这里有很多类似的问题,但很多答案都说要强制使用索引,而且似乎并没有为我提速。
我想展示一个" live"我的网站上的计数器显示表格中的行数。有点像一些网站显示注册用户的数量,或者其他一些统计数据,实时" (即经常使用ajax或websockets更新)。
我的表有大约5M行。它的增长相当快,并且有大量的插入和删除。运行
select count(*) from my_table
需要1.367秒,这是不可接受的,因为我需要我的应用程序来获取每秒一次的新行数。
我尝试了这里提出的许多答案并将查询更改为:
select count(*) from my_table use index(my_index)
my_index
Normal
字段上的BTREE
bigint
,stats
。但实际上时间增加到了1.414秒。
为什么不使用索引加快查询速度,因为这里有很多答案会说明会这样做?
一些答案建议的另一个选项是在表上放置一个触发器,使另一个表中的列递增。因此,我可以创建一个my_table
表,并且只要在stats
中插入或删除行,就会在{{1}}表中触发增量或减少一列。这是唯一的其他选择,因为使用索引似乎不起作用吗?
编辑:以下是我尝试完成的事情类型的完美示例:https://www.freelancer.com。滚动到页面底部,您将看到:
这些数字每秒钟更新一次。
答案 0 :(得分:1)
读取500万条记录并计算它们需要时间 - 无论是索引还是原始数据形式。
如果"快速和肮脏"解决方案是可以接受的,您可以使用元数据:
SELECT table_rows
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = <whatever> and TABLE_NAME = <whatever2>;
请注意,这可能会失去同步。
另一种可能性是将表分成更小的块。一个优点是,如果插入和删除往往是一个分区,您可以只计算它并使用其他分区的元数据。
在这种情况下,触发器可能会有所帮助,也可能无效,具体取决于insert
/ delete
负载。如果你每分钟进行多次插入,那么触发器是一个简单的解决方案 - 一个很好的解决方案。如果您每秒进行数十次或数百次更改,则触发器的开销可能会降低服务器的速度。
答案 1 :(得分:1)
如果你的系统太繁忙以至于计数影响太大,那么INSERTing / DELETEing可能也会产生影响。改进INSERT / DELETE的一种方法是在批量生产中进行改进。而不是一次一个。
收集INSERT,最好是在应用中,但也可以选择在“暂存”中。表。然后,每隔一秒(或其他)使用INSERT..SELECT
或(如果需要)INSERT..ON DUPLICATE KEY UPDATE
将它们复制到真实表格中。 DELETE可以进入同一个表(带有标志)或单独的表。
COUNT(*)
可以在批处理结束时完成。或者可以通过知道计数是多少来计算(以低得多的成本),然后通过临时表来改变它来调整。
这对您的应用代码来说是一个重大的动荡,所以除非您每秒有超过100个INSERT / DELETE的峰值,否则不要开始使用它。 (稳定的100 INSERT /秒=每年30亿行。)
有关&#34; staging table&#34;的详细信息,请参阅http://mysql.rjweb.org/doc.php/staging_table请注意,该博客主张在一对临时表之间进行翻转,以便最大限度地减少对它们的锁定,并允许多个客户共存。
答案 2 :(得分:0)
在后台运行一项工作,执行以下操作;然后用它的表来计算:
Loop:
INSERT INTO Counter (ct_my_table)
SELECT COUNT(*) FROM my_table;
sleep 1 second
end loop
最糟糕的是,它会过时几秒钟。另请注意,INSERT和DELETE会干扰(读取:减慢)SELECT COUNT(*),因此&#34; sleep&#34;。
您是否注意到一些用户界面说&#34;大约120,000个东西&#34;?他们甚至使用更粗略的估计。但它对用户来说通常都足够好。
答案 3 :(得分:0)
information_schema
中获取不准确的值SELECT MAX(id) - MIN(id)
my_table_count
,用于存储表my_table
的行数并使用触发器更新在许多情况下,您不需要准确的价值。谁在乎你是否显示36,400个用户而不是准确的36,454?