我正在尝试学习如何优化SQL语句,我想知道是否可以通过查看执行计划来估计可能使我的查询变慢的原因。
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table: <derived2>
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 382856
Extra: Using where; Using temporary; Using filesort
*************************** 2. row ***************************
id: 1
select_type: PRIMARY
table: rf
type: ref
possible_keys: rec_id
key: rec_id
key_len: 4
ref: rs.id
rows: 7
Extra: Using index condition
*************************** 3. row ***************************
id: 2
select_type: DERIVED
table: f
type: range
possible_keys: facet_name_and_value,rec_id
key: facet_name_and_value
key_len: 309
ref: NULL
rows: 382856
Extra: Using index condition; Using where; Using temporary; Using filesort
*************************** 4. row ***************************
id: 2
select_type: DERIVED
table: r
type: ref
possible_keys: record_id
key: record_id
key_len: 9
ref: sqlse_test_crescentbconflate.f.rec_id
rows: 1
Extra: Using where; Using index
通过查看执行计划,我可以看到我使用了太多的连接而且数据太大,因为SQL使用的是文件排序,但我可能错了。
答案 0 :(得分:1)
我会查看执行计划中的extra
字段,然后检查您的查询和数据库架构,以找到提高性能的方法。
using temporary
表示使用了临时表,这可能会降低查询速度。此外,临时表可能最终被写入磁盘(如果可能的话,不会存储在RAM中,服务器通常会尝试这样做),如果它们太大。
根据MySQL 5.5 documentation,有以下几个原因 创建临时表:
- 评估UNION声明。
- 评估某些视图,例如使用TEMPTABLE算法,UNION或聚合的视图。
- 评估包含ORDER BY子句和不同GROUP BY子句或ORDER BY或GROUP BY的语句 包含连接中第一个表以外的表中的列 队列中。
- 评估DISTINCT与ORDER BY结合可能需要临时表格。
- 对于使用SQL_SMALL_RESULT选项的查询,MySQL使用内存临时表,除非查询还包含元素 (稍后描述)需要磁盘存储。
- 评估多表UPDATE语句。
- 评估GROUP_CONCAT()或COUNT(DISTINCT)表达式。
然后是using filesort
,这意味着执行了无法使用现有索引执行的排序。这可能没什么大不了的,但你应该检查一下哪些字段正在排序以及你的索引在哪里,并确保你没有给MySQL太多的工作要做。
答案 1 :(得分:1)
您可以使用执行计划来查看查询运行缓慢的原因,因为您知道架构的工作原理(您拥有的列和索引)。但是,我们这里的Stack Overflow可能只能使用执行计划来帮助你。
filesort.
它本身没有任何错误。它碰巧有一个不幸的名字;它只是意味着满足查询需要对子查询的结果进行排序。它并不一定意味着子查询的结果已被放置在文件系统的实际文件中。
尝试阅读这篇精美的教程。 http://use-the-index-luke.com/
如果您需要特定查询方面的帮助,请提出其他问题。包括以下信息:
EXPLAIN
专业提示:SELECT *
对具有大量联接的大型查询的性能有害。特别是,
SELECT *
FROM gigantic_table
ORDER BY column
LIMIT 1
是一个反模式,因为它会篡改大量数据,对其进行排序,然后丢弃排序结果中除了一行之外的所有数据。很多数据在您的服务器中晃荡,以获得较小的结果。这是浪费,即使它是正确的。你可以用
更有效地做这件事 SELECT *
FROM gigantic_table
WHERE column =
(SELECT MAX(column) FROM gigantic_table)
如果column
被编入索引,那么效率最高。
我之所以提到这一点,是因为explain
的第一行让您看起来像是在漫步很多行以寻找内容。
答案 2 :(得分:1)
不,仅仅从EXPLAIN输出诊断性能问题是不可能的。
但输出确实显示有一个视图查询返回(估计)384,000行。我们无法判断这是存储的视图还是内联视图。但我们可以看到,该查询的结果被实现为一个表(MySQL称之为“派生表”),然后外部查询正在运行。这可能是相当大的开销。
我们无法判断是否可以在没有视图的情况下获得相同的结果,以平整查询。如果这不可能,那么外部查询是否有任何谓词可以推送到视图中。
“使用filesort”不一定是件坏事。但是对于非常大的设备来说,这种操作会变得昂贵所以我们确实希望避免不必要的排序操作。 (我们无法从EXPLAIN输出中判断出是否可以避免这些排序操作。)
如果查询使用“覆盖索引”,则从索引页面满足查询,而无需查找/访问基础表中的页面,这意味着需要做的工作量更少。
此外,请确保谓词采用能够有效使用索引的形式。这意味着在裸列上具有条件,而不是将列包装在函数中。 e.g。
我们希望避免写出这样的条件:
where DATE_FORMAT(t.dt,'%Y-%m') = '2016-01'
同样的事情可以这样表达:
where t.dt >= '2016-01-01' and t.dt < '2016-02-01'
对于前者,MySQL必须为表中的每一行评估DATE_FORMAT函数,并比较函数的返回值。对于后一种形式,MySQL可以对以dt
为前导列的索引使用“范围扫描”操作。范围扫描操作有可能非常有效地消除大量行,而无需实际检查行。
总而言之,最大的性能改进可能来自