我有2个表的加入请求。我做了2次分页请求。我之前做了一个SQL_CALC_FOUND_ROWS请求。
表A包含145000行 表B包含91000行
这些是MyIsam表。
表A是这样的:
id MEDIUMINT(6) UNSIGNED PK
id_b MEDIUMINT(6) UNSIGNED INDEX
rights ENUM ('0', '1', '2', '3', '4', '5', '6', '7', '8') INDEX
avail ENUM ('0', '1', '2', '3') INDEX
del_date DATE INDEX
... and 40 others fields
这些指数:
rights, avail, del_date
id_b, rights, avail, del_date
表B是这样的:
id MEDIUMINT(6) UNSIGNED PK
title VARCHAR(150) INDEX
.. and 47 others fields
以下是请求:
SELECT COUNT(*)
FROM A
INNER JOIN B ON B.id = A.id_b
WHERE
A.rights NOT IN ('7')
AND (A.del_date IS NULL OR A.del_date > '2016-02-17')
AND A.avail NOT IN ('0')
ORDER BY B.title;
SELECT A.*, B.*
FROM A
INNER JOIN B ON B.id = A.id_b
WHERE
A.rights NOT IN ('7')
AND (A.del_date IS NULL OR A.del_date > '2016-02-17')
AND A.avail NOT IN ('0')
ORDER BY B.title
LIMIT 0, 20;
第一个请求实际需要2秒,第二个0.3秒。在尝试优化max之前,SQL_CALC_FOUND_ROWS请求有时需要10秒或更长时间。
我做过的优化:
但现在,我注意到( A.del_date IS NULL或A.del_date>' 2016-02-17' )是造成缓慢的原因。
如果我删除所有这一条( A.del_date IS NULL或A.del_date>' 2016-02-17' )或只是 A.del_date IS NULL ,请求非常快。
非常感谢任何帮助!
答案 0 :(得分:1)
第一个SELECT
,只有一个COUNT(*)
,由于多种原因而很奇怪......
ORDER BY
没用,可能会降低查询速度。A
和B
之间的映射是什么?如果是1:1,那么就不需要包含B
的任何内容。如果每个B
有0或1 A
行,那么您需要JOIN
。如果它是1:多,那么COUNT
将超过A
的行数;那是你要的吗?要解决此问题,请将JOIN
更改为EXISTS
。如果您需要在查询中保留B
,请添加INDEX(rights, del_date, avail, id_b)
(按任意顺序)。
如果您不需要保留B
,请添加INDEX(rights, del_date, avail)
(按任意顺序)
在任何一种情况下,这将是一个“覆盖索引”(EXPLAIN
将说“使用索引”),它将运行得更快。
OR
通常是性能杀手 - 它通常会消除使用索引的可能性。请提供EXPLAIN SELECT
以查看是否属于这种情况。
请不要在句子中提供信息;使用实际输出或模式规范。事情可能会迷失。
你应该考虑转移到InnoDB。
如果有必要,你应该摆脱“out of nnn items”,从而消除COUNT(*)
或SQL_CALC_FOUND_ROWS
。
对于主查询,问题是过滤在一个表上,但ORDER BY
在另一个表上。这使得优化变得困难或不可能。
答案 1 :(得分:0)
我建议您尝试使用符合条件的多个字段的复合索引,而不是在“A”表上添加单个列索引。这样,引擎不需要加载所有实际页面数据以便记录以确认其他部分,但只能通过索引中找到的内容获取。然后,那些符合条件的人会读取剩余记录的实际数据页面。
查看你的WHERE子句,并且因为你使用NOT IN作为你的权限和可用性标志,我会有一个索引(del_date,avail,rights)
你的“B”表,我也会因为类似的原因而对(id,title)有一个索引。