1

我有以下表格(示例)

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

我已经在影响连接(例如 on t1.t2_id)的列上创建了索引,并在必要时创建了外键。查询很慢(600 毫秒),如果我放置 where 子句(例如WHERE t1.column10 = 1wherecolumn10没有索引),查询会变得慢得多。我使用的查询select (*)速度LIMIT很快,但我无法理解计数行为。有什么解决办法吗?

编辑:添加解释 SQL

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 并且速度提高了,特别是如果我放置 where 子句。但是我仍然有时间(100-150 毫秒)我想在我的应用程序中计数的原因是对于正在处理搜索表单的用户,他期望使用 ajax 的结果数。可能有更好的解决方案,例如创建一个临时表,每隔一小时更新一次?

4

3 回答 3

1

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

编辑:另一个重要的事情是,那些是 PK,所以它们是独一无二的。优化器选择对第一个索引执行 INDEX RANGE SCAN,并且只检查后续索引中是否存在键(这就是为什么计划声明只会返回一行)。

EDIT2:感谢 J. Bruni,事实上这是聚集索引,上面不是“全部真相”。可能对第一个表进行了全扫描,并随后进行了三个 INDEX ACCESS 以确认 FK 存在。

于 2012-09-16T12:38:53.703 回答
0

count遍历整个结果集并且不依赖于索引。对查询使用 EXPLAIN ANALYZE 来检查它是如何执行的。

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

于 2012-09-16T12:22:17.563 回答
-1

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

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

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

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
于 2012-09-16T12:22:56.040 回答