我正在尝试优化我们用于生成报告的查询。 我认为我做了很好的优化到一些扩展。 以下是原始查询:
select trat.asset_name as group_name,trat.name as sub_group_name,
trat.asset_id as group_id,
if(trat.cause_task_type='AccessRequest',true,false) as is_request_task,
'' as grouped_on,
concat(trat.asset_name,' - {0} (',count(*),')') as table_heading
from t_remote_agent_tasks trat
where trat.status in ('completed','failedredundant')
and trat.name not in ('collect-data','update-conn-params')
group by trat.asset_name, trat.name
order by field(trat.name,'create-account','change-attr',
'add-member-to-group',
'grant-access','disable-account','revoke-access',
'remove-member-from-group','update-license')
当我在Extra列中看到执行情况时,它说使用where,Using Temporary,filesort。
所以我像这样优化查询
select trat.asset_name as group_name,trat.name as sub_group_name,
trat.asset_id as group_id,
if(trat.cause_task_type='AccessRequest',true,false) as is_request_task,
'' as grouped_on,
concat(trat.asset_name,' - {0} (',count(*),')') as table_heading
from t_remote_agent_tasks trat
where trat.status in ('completed','failedredundant')
and trat.name not in ('collect-data','update-conn-params')
group by trat.asset_name,trat.name
order by null
这给了我执行计划,使用where,使用临时。所以filesort不再使用,并且没有额外的开销,因为优化器不需要排序,这将在分组期间处理。
我再次前进并按照组中提到的相同顺序创建索引(这很重要或优化不会发生),即创建索引(trat.asset_name,trat.name)。 现在这个优化让我只在额外的列中使用。此外,查询执行时间推断了近一半(早先是0.568秒,现在是0.345秒,虽然每次都变化但在这个范围内或多或少都不一样)。
现在我想优化范围查询,在查询的一部分下面
trat.status in ('completed','failedredundant')
and trat.name not in ('collect-data','update-conn-params')
我正在阅读mysl reference guide to optimize range query,其中说不在范围查询中,所以我在这样的查询中进行了修改
trat.status in ('completed','failedredundant')
and trat.name in ('add-member-to-group','change-attr','create-account',
'disable-account','grant-access', 'remove-member-from-group',
'update-license')
但它没有显示Extra的任何改进(我的意思是使用索引应该在那里,它仍然显示使用where)。 我还尝试将两个范围部分拆分为联合(这将改变查询结果,但仍然没有改进执行计划)
我想要更多关于如何优化此查询的帮助,主要是范围部分(部分)。 如果我需要进行任何其他优化?
感谢您的时间,提前致谢
答案 0 :(得分:0)
几乎在所有情况下,SELECT
中只使用一个索引。所以,一个人必须拥有最好的。
前两个查询的可能从同一个'复合'索引中受益最多:
INDEX(asset_name, name)
通常,人们会尝试处理索引中的WHERE
条件,但它们看起来不适合索引。 (更多讨论如下。)第二个选择是GROUP BY
,我推荐。但是,由于(在第一种情况下)ORDER BY
和GROUP BY
不同,因此必须为GROUP BY
的输出创建一个tmp表,以便可以根据到ORDER BY
。 (GROUP BY
也可能有tmp和排序;我无法分辨。)
“使用索引”表示使用“覆盖”索引。 “覆盖”索引是一个复合索引,其中包含SELECT
中任何地方使用的所有列。那将是大约5列,并且尝试可能不明智。 (更多信息如下。)
另外需要注意的是,即便是这样的事情:
WHERE x IN (11,22)
GROUP BY y
无法使用任何索引同时处理WHERE
和GROUP BY
。因此,您的查询无法同时使用它们(除了“覆盖”)。
覆盖指数在使用时仅部分有用。它说所有工作都是在索引的BTree中完成的。但这可能包括完整的索引扫描 - 这并不比全表扫描快得多。这是反对推荐“覆盖”的另一个论点。
在某些情况下,IN
或OR
可以通过将其变为UNION
来加速:
( SELECT ... WHERE status in ('completed') )
UNION ALL
( SELECT ... WHERE status in ('failedredundant') )
但这只会让你偶然发现NOT IN(...)
条款,这比IN
更糟糕。
找到最佳索引的目的是找到一个连续坐在BTree中的行(在索引和/或表中)。
要对此查询进行任何进一步改进,可能需要重新考虑架构 - 它似乎强迫您拥有IN
,NOT IN
,FIELD
等其他难题优化结构。