我有一个如下所示的查询:
select
id
, int1
, int2
, (select count(*) from big_table_with_millions_of_rows
where id between t.int1 and t.int2)
from myTable t
where
....
此选择只返回一行。内联选择中使用的id是索引列(主键)。如果我将t.int1
和t.int2
替换为此单行返回的int1 / int2的值,则查询以毫秒为单位完成。如果我执行上面的查询 - 即引用int1 / int2,大约需要10分钟。当我运行探查器并查看实际发生的情况时,我发现99%的时间引擎忙于从内联查询返回数据。看起来MySql实际上正在运行
select ... from big_table_with_millions_of_rows
在应用之前,一次内联查询
where id between t.int1 and t.int2
指向结果。这可能是真的吗?如果没有,那么发生了什么?我一直认为内联SELECT
具有潜在的危险性,因为它们作为查询的最后一个元素逐行执行,但对于这样的情况,初始SELECT
确实是高度选择性的,它可以非常有效。任何人都可以对此有所了解吗?
编辑:感谢您的反馈。我关心的不是内联查询的逐行性质,而是面对变量而不是(相同的)硬编码值时似乎无法使用主键索引的事实。我的猜测是,如果最近没有运行ANALYZE,那么优化器会假设它必须进行表扫描,因为它不知道数据分布。但是不应该在主键上完成范围查找这一事实不能弥补这一点吗?
答案 0 :(得分:1)
如果可以,请尝试使用JOIN来避免相关子查询。
在youtube上观看有关MySQL性能的精彩视频。转到31:00分钟。演讲者Jay Pipes谈论避免相关的子查询。
答案 1 :(得分:1)
如果相关子查询未得到很好的优化,请尝试以下查询:
select
t.id
, t.int1
, t.int2
, count(*)
from myTable t
left outer join big_table_with_millions_of_rows b
on (b.id between t.int1 and t.int2)
where
....
group by t.id
这应该更好地优化。
重新提出更新的问题:对,MySQL在优化方面不是市场上最复杂的RDBMS。当MySQL无法优化像这样的角落情况时,不要感到惊讶。
我是MySQL的粉丝,因为它的易用性和开源以及所有这些好东西,但事实是它的竞争对手在技术方面远远领先于MySQL。每个RDBMS都有一些“盲点”,但MySQL看起来更大。
还要确保您使用的是最新版本的MySQL。他们在每个版本中都改进了优化器,因此使用较新版本可能会获得更好的结果。
答案 2 :(得分:0)
如果子查询引用其包含查询的字段,则必须根据包含查询中的每一行重新运行子查询,因为每行中引用的字段可能不同。如果它完全是自包含的,则可以在外部查询开始处理之前运行一次。