MySQL优化请求

时间:2016-02-17 14:08:41

标签: mysql sql optimization query-optimization

我有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秒或更长时间。

我做过的优化:

  • 禁止SQL_CALC_FOUND_ROWS并使用2个请求执行此操作。
  • 字段权利和利用是TINYINT(4)UNSIGNED,现在他们是ENUM
  • 我添加了这两部分索引权利,avail,del_date & id_b,rights,avail,del_date 优化ORDER BY子句(非常好的收益)

但现在,我注意到( 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 ,请求非常快。

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:1)

第一个SELECT,只有一个COUNT(*),由于多种原因而很奇怪......

  • ORDER BY没用,可能会降低查询速度。
  • AB之间的映射是什么?如果是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)有一个索引。