sql count结果查询具有连接性能

时间:2012-09-16 12:02:45

标签: mysql sql performance join count

我有以下表格(示例)

t1 (20.000 rows, 60 columns, primary key t1_id)
t2 (40.000 rows, 8 columns, primary key t2_id)
t3 (50.000 rows, 3 columns, primary key t3_id)
t4 (30.000 rows, 4 columns, primary key t4_id)

sql查询:

SELECT COUNT(*) AS count FROM (t1)
JOIN t2 ON t1.t2_id = t2.t2_id
JOIN t3 ON t2.t3_id = t3.t3_id
JOIN t4 ON t3.t4_id = t4.t4_id

我已经在影响连接的列上创建索引(例如t1.t2_id)和必要时的外键。查询很慢(600毫秒),如果我放置where子句(例如WHERE t1.column10 = 1,其中column10没有索引),则查询变得慢得多。我对select (*)LIMIT的查询速度很快,我无法理解计数行为。任何解决方案?

编辑: EXPLAIN SQL ADDED

id  select_type     table   type    possible_keys   key     key_len     ref  rows   Extra
1   SIMPLE          t4      index   PRIMARY     user_id     4           NULL  5259  Using index
1   SIMPLE          t2      ref     PRIMARY,t4_id   t4_id   4        t4.t4_id   1   Using index
1   SIMPLE          t1      ref     t2_id         t2_id     4        t2.t2_id   1   Using index
1   SIMPLE          t3      ref     PRIMARY     PRIMARY     4        t2.t2_id   1   Using index

其中user_id是t4表的列

编辑:我从innodb更改为myisam并且我的速度提升了,特别是如果我放在哪里。但我仍然有时间(100-150毫秒)我想在我的应用程序中计算的原因,是对正在处理搜索表单的用户,他期望与ajax的结果数量。可能有一个更好的解决方案,例如创建一个临时表,每隔一小时更新一次?

3 个答案:

答案 0 :(得分:1)

计数查询只是因为INDEX ONLY SCAN而更快,如查询计划中所述。您提到的查询仅包含索引列,这就是为什么在执行期间不需要触摸物理数据 - 所有查询都在索引上执行。当您放置一些由未编制索引的列组成的附加子句,或以防止索引使用的方式编制索引时,需要通过物理地址访问存储在堆表中的数据 - 这非常慢。

编辑: 另一件重要的事情是,那些是PK,所以它们是独一无二的。优化器选择在第一个索引上执行INDEX RANGE SCAN,并仅检查后续索引中是否存在密钥(这就是计划表明只返回一行的原因)。

EDIT2: 对于J. Bruni来说,实际上这就是聚集指数,而不是“全部真相”。第一张桌子上可能有全扫描,随后有三张INDEX ACCESS来确认FK的存在。

答案 1 :(得分:0)

count遍历整个结果集,并不依赖于索引。使用EXPLAIN ANALYZE查询查询方式。

select + limit不会迭代整个结果集,因此它更快

答案 2 :(得分:-1)

关于COUNT(*)性能缓慢:您使用的是InnoDB引擎吗?参见:

主要信息似乎是:“ InnoDB使用群集主键,因此主键与数据页中的行一起存储,而不是存储在单独的索引页中。

因此,一种可能的解决方案是创建一个单独的索引,并通过SQL查询中的USE INDEX命令强制使用它。请查看此评论以获取示例使用情况报告:

http://www.mysqlperformanceblog.com/2006/12/01/count-for-innodb-tables/comment-page-1/#comment-529049

关于WHERE问题,如果将条件放在JOIN子句中,查询将表现得更好,如下所示:

SELECT COUNT(t1.t1_id) AS count FROM (t1)
JOIN t2 ON (t1.column10 = 1) AND (t1.t2_id = t2.t2_id)
JOIN t3 ON t2.t3_id = t3.t3_id
JOIN t4 ON t3.t4_id = t4.t4_id