具有限制的MySQL查询执行计划根据

时间:2016-10-28 17:21:09

标签: mysql sql database

我有一个限制的查询,根据close所在的值提供截然不同的执行时间。我正在使用MySQL 5.1,在我最大的表格中查看大约100,000,000条记录"警报"。

当我看到这个执行计划时,我很高兴,我的查询不到一秒钟:

mysql> EXPLAIN SELECT alert.id, category.severity, category.classification, category.completion, alert.description,
->        alert.detectTime, analyzer.name, analyzer.manufacturer, analyzer.model, analyzer.version,
->        analyzer.class, analyzer.osType, analyzer.osVersion, analyzerNode.hostName,
->        analyzerNode.address, sourceNode.hostName, sourceNode.address, targetNode.hostName,
->        targetNode.address, sourceUser.userName, sourceUser.uid, targetUser.userName, targetUser.uid,
->        alert.filePath, alert.sourceProcessPid, alert.sourceProcessPath, alert.targetProcessPid,
->        alert.targetProcessPath, alert.acknowledgeUserName, alert.acknowledgeTime, reference.url, reference.meaning
-> FROM alerts AS alert
->      LEFT JOIN categories AS category ON category.id = alert.categoryId
->      LEFT JOIN analyzers AS analyzer ON analyzer.id = alert.analyzerId
->      LEFT JOIN nodes AS analyzerNode ON analyzerNode.id = alert.analyzerNodeId
->      LEFT JOIN nodes AS sourceNode ON sourceNode.id = alert.sourceNodeId
->      LEFT JOIN nodes AS targetNode ON targetNode.id = alert.targetNodeId
->      LEFT JOIN users AS sourceUser ON sourceUser.id = alert.sourceUserId
->      LEFT JOIN users AS targetUser ON targetUser.id = alert.targetUserId
->      LEFT JOIN `references` AS reference ON reference.id = alert.referenceId
-> WHERE category.severity = 'info'
-> ORDER BY alert.id DESC
-> LIMIT 40 OFFSET 0;
  • | id | select_type |表|类型| possible_keys |关键| key_len | ref |行|额外|
  • | 1 |简单|警报|指数| categoryIndex |主要| 8 | NULL | 40 | |
  • | 1 |简单|类别| eq_ref | PRIMARY,severityIndex |主要| 8 | am.alert.categoryId | 1 |使用where |
  • | 1 |简单|分析仪| eq_ref |主要|主要| 8 | am.alert.analyzerId | 1 | |
  • | 1 |简单| analyzerNode | eq_ref |主要|主要| 8 | am.alert.analyzerNodeId | 1 | |
  • | 1 |简单| sourceNode | eq_ref |主要|主要| 8 | am.alert.sourceNodeId | 1 | |
  • | 1 |简单| targetNode | eq_ref |主要|主要| 8 | am.alert.targetNodeId | 1 | |
  • | 1 |简单| sourceUser | eq_ref |主要|主要| 8 | am.alert.sourceUserId | 1 | |
  • | 1 |简单| targetUser | eq_ref |主要|主要| 8 | am.alert.targetUserId | 1 | |
  • | 1 |简单|参考| eq_ref |主要|主要| 8 | am.alert.referenceId | 1 | |

但是,当我只是更改where子句的值(在这种情况下是枚举,但我不认为相关)时,我可以得到截然不同的结果,我的查询将永远。< / p>

mysql> EXPLAIN SELECT alert.id, category.severity, category.classification, category.completion, alert.description,
->        alert.detectTime, analyzer.name, analyzer.manufacturer, analyzer.model, analyzer.version,
->        analyzer.class, analyzer.osType, analyzer.osVersion, analyzerNode.hostName,
->        analyzerNode.address, sourceNode.hostName, sourceNode.address, targetNode.hostName,
->        targetNode.address, sourceUser.userName, sourceUser.uid, targetUser.userName, targetUser.uid,
->        alert.filePath, alert.sourceProcessPid, alert.sourceProcessPath, alert.targetProcessPid,
->        alert.targetProcessPath, alert.acknowledgeUserName, alert.acknowledgeTime, reference.url, reference.meaning
-> FROM alerts AS alert
->      LEFT JOIN categories AS category ON category.id = alert.categoryId
->      LEFT JOIN analyzers AS analyzer ON analyzer.id = alert.analyzerId
->      LEFT JOIN nodes AS analyzerNode ON analyzerNode.id = alert.analyzerNodeId
->      LEFT JOIN nodes AS sourceNode ON sourceNode.id = alert.sourceNodeId
->      LEFT JOIN nodes AS targetNode ON targetNode.id = alert.targetNodeId
->      LEFT JOIN users AS sourceUser ON sourceUser.id = alert.sourceUserId
->      LEFT JOIN users AS targetUser ON targetUser.id = alert.targetUserId
->      LEFT JOIN `references` AS reference ON reference.id = alert.referenceId
-> WHERE category.severity = 'high'
-> ORDER BY alert.id DESC
-> LIMIT 40 OFFSET 0;
  • | id | select_type |表|类型| possible_keys |关键| key_len | ref |行|额外|
  • | 1 |简单|类别| ref | PRIMARY,severityIndex | severityIndex | 2 | const | 8 |用在哪里;使用临时;使用filesort |
  • | 1 |简单|警报| ref | categoryIndex | categoryIndex | 8 | am.category.id | 3883428 | |
  • | 1 |简单|分析仪| eq_ref |主要|主要| 8 | am.alert.analyzerId | 1 | |
  • | 1 |简单| analyzerNode | eq_ref |主要|主要| 8 | am.alert.analyzerNodeId | 1 | |
  • | 1 |简单| sourceNode | eq_ref |主要|主要| 8 | am.alert.sourceNodeId | 1 | |
  • | 1 |简单| targetNode | eq_ref |主要|主要| 8 | am.alert.targetNodeId | 1 | |
  • | 1 |简单| sourceUser | eq_ref |主要|主要| 8 | am.alert.sourceUserId | 1 | |
  • | 1 |简单| targetUser | eq_ref |主要|主要| 8 | am.alert.targetUserId | 1 | |
  • | 1 |简单|参考| eq_ref |主要|主要| 8 | am.alert.referenceId | 1 | |

注意一个人有限制作为执行的第一步,另一个没有。无论如何都要强制MySQL查询优化器首先执行限制吗?

1 个答案:

答案 0 :(得分:0)

使用ORDER BY和LIMIT时,重要的是订单依据索引。

如果优化程序决定选择另一个索引,则不会应用限制,因为检索结果并扫描更多记录。

在您的情况下,您可能没有“信息”警报更少的“高”,优化程序更喜欢类别表中的严重性索引。

您可以尝试使用FORCE INDEX强制使用警报表的PK,或尝试忽略类别表的严重性索引。

这个article似乎很有用。