繁体   English   中英

在MySQL5.6中优化查询

[英]Optimizing query in MySQL5.6

我有一个INNODB表levels

+--------------------+--------------+------+-----+---------+-------+
| Field              | Type         | Null | Key | Default | Extra |
+--------------------+--------------+------+-----+---------+-------+
| id                 | int(9)       | NO   | PRI | NULL    |       |
| level_name         | varchar(20)  | NO   |     | NULL    |       |
| user_id            | int(10)      | NO   |     | NULL    |       |
| user_name          | varchar(45)  | NO   |     | NULL    |       |
| rating             | decimal(5,4) | NO   |     | 0.0000  |       |
| votes              | int(5)       | NO   |     | 0       |       |
| plays              | int(5)       | NO   |     | 0       |       |
| date_published     | date         | NO   | MUL | NULL    |       |
| user_comment       | varchar(255) | NO   |     | NULL    |       |
| playable_character | int(2)       | NO   |     | 1       |       |
| is_featured        | tinyint(1)   | NO   | MUL | 0       |       |
+--------------------+--------------+------+-----+---------+-------+

有大约400万行。 由于具有前端功能,因此我需要使用各种过滤器和排序查询该表。 它们在playable_characterratingplaysdate_published 可以过滤date_published以在最后一天,一周,一个月或任何时间(过去3年)显示。 还有分页。 因此,根据用户的选择,查询可能看起来像其中之一:

SELECT * FROM levels
WHERE playable_character = 0 AND
    date_published BETWEEN date_sub(now(), INTERVAL 3 YEAR) AND now()
ORDER BY date_published DESC
LIMIT 0, 1000;

SELECT * FROM levels
WHERE playable_character = 4 AND
    date_published BETWEEN date_sub(now(), INTERVAL 1 WEEK) AND now()
ORDER BY rating DESC
LIMIT 4000, 1000;

SELECT * FROM levels
WHERE playable_character = 5 AND
    date_published BETWEEN date_sub(now(), INTERVAL 1 MONTH) AND now()
ORDER BY plays DESC
LIMIT 1000, 1000;

我从索引idx_date_char(date_published, playable_character)开始,该索引在此处的第一个示例查询中效果很好 -基本上是按date_published排序的date_published 使用EXPLAIN,我得到“使用索引条件”,这很好。 我想我理解索引为什么起作用的原因,因为WHERE和ORDER BY子句中存在相同的两个索引列。

我的问题是按playsrating ORDER的查询。 我知道我要介绍第三列,但是就我的一生而言,尽管尝试了我可能想到的几乎所有变体,但我仍然无法获得运行良好的索引:每个顺序中所有三个或四个的复合索引,并且以此类推。 也许查询的书写方式可能不同?

我应该添加该rating并且plays总是以DESC查询。 只有date_published可以是DESCASC

任何建议,不胜感激。 TIA。

where子句AND order by中使用的列应该是索引的一部分。 我会有一个索引

( playable_character, date_published DESC, rating DESC, plays DESC )

我将可玩角色设置为FIRST的原因是,您希望该ID为主要ID,然后是所有这些日期在问题之内。 评分和比赛就可以帮助ORDER BY子句。

这样考虑一下索引。 如果按Date_Published排序,然后按Playable_Character排序,则考虑一下盒子的空间。 每个框都有一个日期。在给定日期的框内,按字符顺序排列它们。 因此,您有3年的数据需要经过,您必须打开最近3年的所有框并找到所需的字符。

现在,这样想。 每个方框均按字符排列,其中所有日期均已预先排序。 因此,您转到一个框,将其打开...移动到有问题的日期,并从所需的XY范围中获取记录。 现在,您可以通过这些记录应用简单的订单。

看来您将充分利用以这种方式对每个查询排序的数据:

  1. playable_character,date_published
  2. playable_character,date_published,等级
  3. playable_character,date_published,播放

请记住,您在第一个查询中排序的数据恰好是第二个和第三个查询所需数据的子集,因此我们可以摆脱它。

还要注意,将DESCASC添加到索引在语法上是正确的,但实际上并不会更改任何内容,因为当前不支持该功能(预计将来会支持该功能,因此就是该功能所在)。 所有索引均以升序存储。 更多信息在这里

因此,这些是您应该创建的索引:

ALTER TABLE levels ADD INDEX (playable_character, date_published, rating)
ALTER TABLE levels ADD INDEX (playable_character, date_published, plays)

那应该使那里的3个查询比Forrest Gump运行得更快。

当查询包含像BETWEEN这样的范围谓词时,索引中列的顺序很重要。

  • 首先,包括由相等谓词引用的一个或多个列。
  • 接下来,包括由范围谓词引用的一列。
  • 范围谓词引用的列之后的索引中任何其他列均不能用于其他范围谓词或排序。
  • 如果没有范围谓词,则可以为排序顺序添加一列。

因此,您的第一个查询可以从(playable_character, date_published)上的索引中受益。 排序应为空,因为优化器只会按索引顺序获取行。

第二个查询和第三个查询必然要进行文件排序,因为您有一个范围谓词,然后要按不同的列进行排序。 如果仅具有相等谓词,则可以使用第三列来避免文件排序,但是当您具有范围谓词时,这将不起作用。

您所希望的最好的结果是,条件会减小结果集的大小,以使结果集可以在内存中进行排序,而无需进行过多的排序合并遍历 您可以通过增加sort_buffer_size来帮助解决此问题,但请注意不要增加太多,因为它是按线程分配的。

索引定义中的ASC / DESC关键字在MySQL中没有区别。
参见http://dev.mysql.com/doc/refman/5.6/en/create-index.html

这些关键字允许将来用于指定升序或降序索引值存储的扩展。 目前,它们已被解析但被忽略; 索引值始终按升序存储。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM