我有以下情况,我想知道是否可行/可行。如果这被认为是一个过于“宽泛”的问题,我会道歉,但我认为这将是最好的问题。
让我们假设我有一个网站,我想向最终用户显示图表。出于此示例的目的,假设我们要在过去一小时内向他们显示“每个类别的销售额”。数据将显示在图形中,运行查询的SQL可能如下所示:
SELECT SUM(revenue) FROM sales
WHERE timestamp > NOW() - INTERVAL 1 HOUR
GROUP BY category
据我所知,有两种通用方法可以为最终用户更新数据:
我的问题是,当数据太大而无法存储在内存中时,是否可以进行实时数据更新(我在示例2中描述的情况)。我认为答案是“不”,但也许我错过了一些方法来做到这一点。例如,假设我在BigQuery中存储了1TB的数据,并且我正在通过购买新产品来对其进行流式更新 - 有没有办法将更新推送到最终客户端,而不必每次都重新运行查询想得到更新?是否有任何其他技术可用于此方案?
同样,我认为这不可能,但希望看到在查询数据集上尽可能近端实时显示终端客户端的可能性。
由于您对此选项感兴趣,因此我决定将评论扩展为答案。我将采用SQL Server和C#组件 - sqltabledependency。如果它符合您的需求,您可以查看它。
sales
表的任何更改,例如sales_data_watch
(你可以在那里有预先计算聚合,如你的例子)。sales
表中的更改并在sales_data_watch
上执行插入/更新sales_data_watch
的C#sqltabledependency(注意:从示例中获取以适合你的表)
public class SaleData
{
public int revenue{ get; set; }
}
public class Program
{
private static string _con = "data source=.; initial catalog=MyDB; integrated security=True";
public static void Main()
{
// The mapper object is used to map model properties
// that do not have a corresponding table column name.
// In case all properties of your model have same name
// of table columns, you can avoid to use the mapper.
var mapper = new ModelToTableMapper<SaleData>();
mapper.AddMapping(s => s.revenue, "Aggregated revenue");
// Here - as second parameter - we pass table name:
// this is necessary only if the model name is different from table name
// (in our case we have Sale vs Sales).
// If needed, you can also specifiy schema name.
using (var dep = new SqlTableDependency<SaleData>(_con, "sales_data_watch", mapper: mapper));
{
dep.OnChanged += Changed;
dep.Start();
Console.WriteLine("Press a key to exit");
Console.ReadKey();
dep.Stop();
}
}
public static void Changed(object sender, RecordChangedEventArgs<SaleData> e)
{
var changedEntity = e.Entity;
Console.WriteLine("DML operation: " + e.ChangeType);
Console.WriteLine("Revenue: " + changedEntity.Revenue);
}
}
truncate table sales_data_watch
(如果您不希望表格变得太大而最终会减慢整个过程的速度。这只使用sql server和C#组件。还有其他可能更好的选择,例如:Detect record table change with MVC, SignalR, jQuery and SqlTableDependency以不同的方式做到这一点。这取决于您的偏好。
编辑Building real time charts with Angular 5, Google Charts, SignalR Core, .NET Core 2, Entity Framework Core 2 and SqlTable dependency的完整示例链接(此链接是第一页的三个)。在页面顶部,您可以看到实时谷歌的仪表图。所有学分都归anthonygiretti所有。您可以在github下载示例项目。
数据库
使用Visual Studio 2017的Sql Server,localDb是正确的,使它工作
前端技术
Angular 5
Google Charts
Visual Studio Code
SignalR Client
BackEnd技术
.NET Core 2
SignalR Core
EntityFramework Core
EntityFramework Core for Sql Server
SqlTableDependency
首先是安装所需的组件 - 服务代理,SQL表,Angular-CLI,Angular 5项目,SignalR客户端(VS 2017,.Net Core 2 SDK安装) - 链接是相同的qazxsw poi
接下来是后端设置 - part1
为了使它工作,这个项目包含:
最后一部分是设置前端 - part2
我们有 :
在下一步中,您应该测试它以查看在更改数据时数据是否正确投影到图形中。
我认为问题可能源于客户图表及其设计要求的问题。
“最后一小时的销售”图表既缺乏信息又难以更新。
更新需要在“最近一小时”进展(下午1:05转到下午1:06)时扣除销售额,并增加新的销售额。
此外,这些信息可能看起来令人兴奋,但它提供的营销可用于改善销售的信息非常少(即,应该在哪个小时添加更多广告)。
我会考虑24小时图,或12小时图除以实际小时数。
这可以简化更新,并可能提供更有用的指标。
这样,对图形的更新总是相加的,因此不需要内存数据存储(并且信息更具可操作性)。
例如,每个新的销售都可以发布到part3频道。公布的销售数据可能包括它的确切时间。
这将允许订阅的客户端将新的销售额添加到图表中的正确小时,而无需调用额外的数据库调用,也无需内存中的数据存储。
如果您的数据在每个客户端是唯一的,大而实时的更改,那么使用任何数据库或缓存作为交换都没有任何拯救。您必须直接发送数据更新。
如果您无法从执行数据库更新的进程直接将数据推送到客户端,您可能可以将执行更新的进程中的数据传递给执行推送消息代理的进程(我将使用Rabbitmq作为示例)。
此设置的最佳配置是"new_sale"
,其中主题是客户端ID或密钥,并为该主题为每个连接的客户端创建一个侦听器 - 或者,为所有客户端创建一个侦听器,但动态注册/取消注册主题。
让websocket处理程序听取客户端的主题。设置更新数据库的过程以将更新流传输到客户端的主题ID。代理将丢弃所有不会连接到客户端的更新,从而使得负载在侦听器端更易于管理。
没有任何存储或轮询,此解决方案是低延迟。即使有一千个同时发生的客户,我怀疑经纪人会耗尽内存。