Mysql计数查询优化
我有下面的查询要优化Mysql计数查询优化,mysql,sql,query-optimization,Mysql,Sql,Query Optimization,我有下面的查询要优化 SELECT count(*) AS count FROM area INNER JOIN entity ON area.id = entity.id INNER JOIN areacust ON area.id = areacust.id WHERE entity.deleted=0 AND area.id > 0 已删除的表上有索引,所有表上都有ID 现在,当我假设有20个Lac(200万)的记录时,查询会花费很多时间来给出结果。时间在10到20秒之间 我
SELECT count(*) AS count FROM area
INNER JOIN entity ON area.id = entity.id
INNER JOIN areacust ON area.id = areacust.id
WHERE entity.deleted=0
AND area.id > 0
已删除的表上有索引,所有表上都有ID
现在,当我假设有20个Lac(200万)的记录时,查询会花费很多时间来给出结果。时间在10到20秒之间
我怎样才能更优化它。还有什么其他技巧可以让你数一数
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE vtiger_crmentity ref PRIMARY,entity_deleted_idx entity_deleted_idx 4 const 729726 Using where; Using index
1 SIMPLE area eq_ref PRIMARY PRIMARY 4 area.id 1 Using index
1 SIMPLE areacust eq_ref PRIMARY PRIMARY 4 area.id 1 Using where; Using index
复合密钥的新解释
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE entity ref PRIMARY,entity_deleted_idx,comp_index deleted_idx 4 const 928304 Using index
1 SIMPLE area eq_ref PRIMARY PRIMARY 4 entity.id 1 Using index
1 SIMPLE areacust eq_ref PRIMARY PRIMARY 4 entity.idid 1 Using index
你可以试试:
SELECT count(*) AS count
FROM area
JOIN entity
ON entity.id = area.id
AND entity.deleted = 0
JOIN areacust
ON areacust.id = area.id
在可能的情况下,我喜欢在连接中包含条件,并将我要连接的表保持在这些条件中的等式的左边
而且WHERE area.id>0
也很奇怪。。由于其他表中的自动增量ID,大多数外键从1开始,因此这将包括所有行。我已删除此条件
从解释的外观来看,您并不希望最上面一行使用实体\u已删除\u idx
。对于实体
以下是我对此查询的索引:
-(id)这可能已经是主要区域了区域
-(id)这可能已经是主要的areacust
-(id,已删除)应添加并使用该实体实体
实体
中删除除主索引和复合索引之外的所有未启用的索引
如果这不起作用,请运行:
SELECT count(*) AS count
FROM area
JOIN entity USE INDEX (**composite_index_name**)
ON entity.id = area.id
AND entity.deleted = 0
JOIN areacust
ON areacust.id = area.id
根据评论,如果您想继续查询,您必须为您的MySQL实例分配更多资源。我假设您使用InnoDB作为存储引擎,否则这个建议是无用的: 增加
innodb\u buffer\u pool
变量的值。尽你所能。您希望分配尽可能多的RAM
另外,去掉deleted
列上的索引,它是无用的。它的基数太低,无法作为索引
您可以(应该)使用的另一种“技术”是手动处理此计数
创建包含您感兴趣的计数的表。每次更新/插入/删除实体或区域记录时-手动更新计数值(增加、减少)
这样,您所要做的就是查找单个表的单个记录。设置将自动排序的触发器应该很简单。这样,您将在运行时处理计数,而不是浪费I/O和CPU来不断遍历数据集。Post
EXPLAIN
查询计划您是否尝试添加强制索引。。。。。选择?如何在此查询中从区域力索引(area.id)添加力索引。。因此,首先,如果您想计算所有内容,大多数人会将其写成count(*)
。。如果只想计算一个表中的内容,可以执行count(a.id)
甚至(a.*)
。。但是,只有当有左连接导致额外的行时,这才有意义。。。MySQL对COUNT(ID)
或COUNT(*)
的执行几乎相同。。除非存在要计数的null
值。。。如果存在空值,您应该始终使用COUNT(*)
,因为MySQL知道如何更好地处理它。。将执行时间减半。花费相同的时间甚至更多。@RahulTailwal很公平。。您是否在(id,deleted)上尝试了复合索引?大多数优化器将为此查询和原始查询生成相同的计划。这些在语义上是相同的,所以…@Clockwork Muse是的,这可能是真的,但是通过这个查询,更容易看到潜在的索引和速度,因此我的结论是。这需要时间的原因是因为您的数据库是HDD绑定的。它只是使用了硬盘I/O,因为它无法将工作数据集放入内存中。罪魁祸首总是innodb\u buffer\u pool
value,如果您使用innodb(您应该这样做)。将该数字至少增加到服务器内存的70%(是的,70%,您希望内存中有尽可能多的数据,因为这是提高速度的方法)。我喜欢在增加资源之前,尽可能使用索引优化查询。。但这可能是他唯一的选择。就像汇总表的想法一样,超级快速。索引在这里帮不上忙。它们不是一种神奇的药丸,能让一切都像那样快速。这是一个简单的数据结构,在本例中,在已删除的
上设置索引根本没有帮助。无法使用索引进一步优化原始查询。唯一可用的优化是删除已删除的
上的索引,这只会释放一些存储空间。性能将是相同的。真正的答案是增加资源(innodb_buffer_pool的默认值是8MB,这太低了),或者创建一个表来查找计数器号。索引在这里绝对有帮助!我的回答中描述的索引涵盖了查询所需的所有信息,因此可以满足计数(*),而无需引擎进入行中检查实体删除值。。如果实体有很多列,这将节省大量内存。增加内存大小很好,但只能增加一次,而且不断升级服务器的成本很高,因此您希望查询尽可能快。这就是我喜欢汇总表的原因。。可移植的解决方案。另外,如果你看他的解释,看起来优化者在实体主键上使用删除的索引,即cray!我想先解决这个问题。