如何识别缺少索引的慢查询?

Posted

技术标签:

【中文标题】如何识别缺少索引的慢查询?【英文标题】:How do I identify slow queries missing an index? 【发布时间】:2019-09-24 16:57:59 【问题描述】:

在慢日志上使用SET GLOBAL log_slow_verbosity='query_plan,explain';,我得到很多输出,但我很难理解解释。

# User@Host: root[root] @  [10.0.1.5]
# Thread_id: 31  Schema: enterprise  QC_hit: No
# Query_time: 0.654855  Lock_time: 0.000245  Rows_sent: 50  Rows_examined: 279419
# Rows_affected: 0
# Full_scan: Yes  Full_join: Yes  Tmp_table: Yes  Tmp_table_on_disk: Yes
# Filesort: Yes  Filesort_on_disk: No  Merge_passes: 0  Priority_queue: Yes
#
# explain: id   select_type     table   type    possible_keys   key     key_len ref     rows    r_rows  filtered        r_filtered      Extra
# explain: 1    SIMPLE  external_property_groups_areas  ALL     unique_id_area,search_id_area,search_country    NULL    NULL    NULL    20      20.00   100.00  100.00  Using temporary; Using filesort
# explain: 1    SIMPLE  external_property_level_1_buildings     ref     unique_id_building,building_id_area_id  building_id_area_id     5       enterprise.external_property_groups_areas.id_area        3  6.00     100.00  100.00
# explain: 1    SIMPLE  external_property_level_2_units ref     unit_building_id,property_level_2_created_by    unit_building_id        4       enterprise.external_property_level_1_buildings.id_building  25.13    100.00  100.00  Using index condition
# explain: 1    SIMPLE  ut_unit_types   eq_ref  unique_property_type,query_optimization_designation      unique_property_type     1022    enterprise.external_property_level_2_units.unit_type  1       1.00    100.00  100.00  Using where; Using index
# explain: 1    SIMPLE  property_level_2_units  eq_ref  PRIMARY,property_level_2_organization_id        PRIMARY 1530    enterprise.external_property_level_2_units.external_id,enterprise.external_property_level_2_units.external_system_id,enterprise.external_property_level_2_units.external_table,const   1       0.98    100.00  100.00
# explain: 1    SIMPLE  a       eq_ref  unique_id_unit,unit_building_id unique_id_unit  4       enterprise.property_level_2_units.system_id_unit 1       0.98    100.00  100.00  Using where
# explain: 1    SIMPLE  c       eq_ref  unique_id_building      unique_id_building      4       enterprise.a.building_system_id  1       1.00    100.00  100.00  Using index
# explain: 1    SIMPLE  b       ref     property_property_type  property_property_type  4       const   142     458.00  100.00  0.17    Using where
# explain: 1    SIMPLE  property_groups_countries       ALL     country_names,coutnry_codes     NULL    NULL    NULL    245     245.00  100.00  0.31    Using where; Using join buffer (flat, BNL join)
#
如何识别他们查询的慢部分? 有快速识别缺失索引的快捷方式吗?

还有一个screencast of my session

如果您能指出一些资源来帮助我弄清楚如何提高这些 SQL 查询的性能,那就太好了。

【问题讨论】:

compound indexes, query optimization。要查找的内容、未使用键的表 (ALL)、使用的索引量 (key_len)。 filesort(真的是任何类型)如果有很多行可能很重要。 【参考方案1】:

你的问题很笼统,所以我会回答你的具体问题,然后发送给你可以找到更多信息的地方。

日志上的解释是好的,但你并不是唯一一个无法阅读它们的人。使用日志来识别您的慢查询。稍后使用EXPLAIN(和其他工具)来调试正在发生的事情。很高兴将其记录在日志中,但请像这样在您的数据库中实时格式化它以提高可读性:

回答您的问题:

我如何知道索引是否未被使用?

type(和key)列会告诉你。键入ALL 表示正在使用全表扫描,可能的键/键将是NULL。那是为了扫描。键入constrefrange 通常是首选(还有更多策略)。对于排序(和其他问题),您将在Extra: 上找到字符串Using filesort。这意味着需要对结果进行第二次排序,在某些情况下,索引将有助于自动按顺序获取结果。

这是另一个查询的示例,这次使用索引:

这是一种简化,因为有很多方法可以使用索引来加速结果(ICP、覆盖索引、max()、...)。

这里没有足够的篇幅来讨论JOINs 和子查询,在这里可以通过排序和重写来获得更好的策略。

我如何识别他们查询的慢部分?

有两种选择:

分析查询(这将为您提供在每个查询步骤上花费的每个阶段的时间),这可以使用show profile 来完成,或者对于某些查询使用performance_schema 启用它。典型输出:

SHOW PROFILE CPU FOR QUERY 5;
+----------------------+----------+----------+------------+
| Status               | Duration | CPU_user | CPU_system |
+----------------------+----------+----------+------------+
| starting             | 0.000042 | 0.000000 |   0.000000 |
| checking permissions | 0.000044 | 0.000000 |   0.000000 |
| creating table       | 0.244645 | 0.000000 |   0.000000 |
| After create         | 0.000013 | 0.000000 |   0.000000 |
| query end            | 0.000003 | 0.000000 |   0.000000 |
| freeing items        | 0.000016 | 0.000000 |   0.000000 |
| logging slow query   | 0.000003 | 0.000000 |   0.000000 |
| cleaning up          | 0.000003 | 0.000000 |   0.000000 |
+----------------------+----------+----------+------------+

处理程序统计信息,它将为您提供与时间无关的扫描策略指标和每个扫描的行数:

最后一个可能看起来有点不友好,但是一旦你理解了它,你就可以很容易地看到索引使用情况和全扫描,通过知道内部引擎调用是什么。

有快速识别缺失索引的快捷方式吗?

是的,如果您启用了performance_schema 并且可以访问sys 数据库SELECT * FROM sys.statement_analysis; 将为您提供一个名为“full_scan”的列,它将为您提供执行完整扫描的查询(不使用索引的扫描) .然后你可以按rows_examinedrows_examined_avgavg_latency等按重要性排序。

如果您不想或不能使用 performance_schema,请使用日志将这些数字与 pt-query-digest from percona-toolkit 汇总:

如果检查的行与发送的行相比非常大,则可能是索引造成的。

总而言之,日志可用于识别查询 - 使用它们与 performance_schema 或 pt-query-digest 聚合它们。但是,一旦您确定了最严重的违规查询,请使用其他工具进行调试。

我在扩展中详细讨论了如何识别慢查询以及如何在我的幻灯片上进行查询优化的详细信息 "Query Optimization with MySQL 8.0 and MariaDB 10.3"。我这样做是为了谋生,查询优化是我的热情所在,我建议你看看它们(我不是在卖给你一本书,它们是免费的,并且具有知识共享许可)。

【讨论】:

伟大的开始 + 1 但查询优化还有更多。mysql 优化器有时可以重写 SQL 以优化或选择不使用索引,而全扫描更便宜 @Raymond Nijland 我在slideshare.net/jynus/… 谈到了这一点,我无法在这里总结 200 多张幻灯片:-D 跟踪优化器也是dev.mysql.com/doc/internals/en/optimizer-tracing.html 为这些好的资源添加建议的事情。如果它在我没有查看的幻灯片中不存在 没问题,我没有看切片,确实你不能把所有信息都放在这里【参考方案2】:

“不使用索引的慢查询”——谁在乎?您应该关心的是“慢查询”。 那么在尝试找出查询缓慢的原因时,您可能也可能不会发现索引问题。

使用 jynus 描述的摘要并向我们展示“最差”的查询。为它使用的表提供SHOW CREATE TABLEEXPLAIN SELECT ...。然后我们可以通过它来找出索引是否有问题。或者是哪里出了问题。

更多关于消化等:http://mysql.rjweb.org/doc.php/mysql_analysis#slow_queries_and_slowlog

重新视频

唉,EXPLAIN 没有告诉你需要什么索引,甚至没有告诉你哪个表需要更好的索引。

呈现文字时,请使用文字,而不是视频。

当“Rows”和“r_rows”很高时,会提示您该表可能缺少良好的索引。请提供SHOW CREATE TABLE,以便我们查看您已有的索引。

如果可能,请使用短别名;长的会导致很多混乱。

【讨论】:

虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review @TrentonMcKinney - 随便找我。我已经开发了大约 20 篇文章,我反复指出,而不是花时间重复自己。他们已经成立了十年,我并没有打算让他们失望。此外,我偶尔会更新它们以跟上 MySQL/MariaDB 的新版本。 我不是对你的答案投反对票的人。

以上是关于如何识别缺少索引的慢查询?的主要内容,如果未能解决你的问题,请参考以下文章

识别 RDS 上 Postgresql 的慢查询

MonetDB 带索引的慢查询

基于代价的慢查询优化建议

连接表的慢查询

慢查询引发的车祸现场,案例分析!

分区表中的慢查询