我有以下表格(示例)
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的结果数量。可能有一个更好的解决方案,例如创建一个临时表,每隔一小时更新一次?
答案 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
命令强制使用它。请查看此评论以获取示例使用情况报告:
关于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