注意:原始问题没有实际意义,但扫描到底部是否有相关内容。
我想要优化的查询看起来像这样:
select cols from tbl where col = "some run time value" limit 1;
我想知道正在使用哪些键,但无论我传递什么来解释,它都能够将where子句优化为什么(“Impossible WHERE注意到......”)因为我给它一个常量。
编辑:EXPLAIN
似乎在给我一个由常量值产生的查询计划。由于查询是存储过程的一部分(并且sproc中的IIRC查询计划在调用之前生成),这对我没有好处,因为该值不是常量。我想要的是找出优化器在不知道实际值是什么时将生成什么查询计划。
我错过了什么吗?
Edit2:在其他地方询问,似乎MySQL总是重新生成查询计划,除非你不遗余力地让它重复使用它们。即使在存储过程中。从这看起来我的问题似乎没有实际意义。
然而,这并不是我真正想知道的事情: 如何优化包含任何特定查询中常量的值的查询,但我,程序员,事先不知道将使用什么值? - 例如说我的客户端代码生成一个查询,其中包含where
子句中的数字。有时这个数字会导致不可能where where 其他时候它不会。如何使用explain来检查查询的优化程度?
我正在看到的最好的方法是在其上运行EXPLAIN
以获得存在/不存在情况的完整矩阵。真的,这不是一个非常好的解决方案,因为手工操作既容易又容易出错。
答案 0 :(得分:5)
你得到“不可能注意到”,因为你指定的值不在列中,而不仅仅是因为它是一个常量。您可以1)使用列中存在的值或2)只说col = col
:
explain select cols from tbl where col = col;
答案 1 :(得分:4)
例如,假设我的客户端代码正在生成一个带有数字的查询,其中包含where子句。
有时候,这个数字会导致一个不可能的where子句,有时则不会。
如何使用explain来检查查询的优化程度?
MySQL
为绑定参数的不同值构建不同的查询计划。
在此article中,您可以阅读MySQL
优化程序何时执行以下操作的列表:
Action When Query parse PREPARE Negation elimination PREPARE Subquery re-writes PREPARE Nested JOIN simplification First EXECUTE OUTER->INNER JOIN conversions First EXECUTE Partition pruning Every EXECUTE COUNT/MIN/MAX elimination Every EXECUTE Constant subexpression removal Every EXECUTE Equality propagation Every EXECUTE Constant table detection Every EXECUTE ref access analysis Every EXECUTE range/index_merge analysis and optimization Every EXECUTE Join optimization Every EXECUTE
此列表中还缺少一件事。
MySQL
可以在每JOIN
次迭代上重建一个查询计划:这样称为range checking for each record
。
如果表上有复合索引:
CREATE INDEX ix_table2_col1_col2 ON table2 (col1, col2)
和这样的查询:
SELECT *
FROM table1 t1
JOIN table2 t2
ON t2.col1 = t1.value1
AND t2.col2 BETWEEN t1.value2_lowerbound AND t2.value2_upperbound
,MySQL
不会使用RANGE
到(t1.value1, t1.value2_lowerbound)
的索引(t1.value1, t1.value2_upperbound)
访问权限。相反,它将使用REF
上的索引(t1.value)
访问权限,只过滤掉错误的值。
但是如果你重写这样的查询:
SELECT *
FROM table1 t1
JOIN table2 t2
ON t2.col1 <= t1.value1
AND t2.col1 >= t2.value1
AND t2.col2 BETWEEN t1.value2_lowerbound AND t2.value2_upperbound
,然后MySQL
将重新检查RANGE
中每条记录的索引table1
访问,并决定是否即时使用RANGE
访问权限
您可以在我的博客中阅读这些文章:
SKIP SCAN
中模仿MySQL
访问方法MySQL
N
MySQL
条记录
所有这些都使用RANGE CHECKING FOR EACH RECORD
回到你的问题:无法确定MySQL
将为每个给定常量使用哪个计划,因为在给出常量之前没有计划。
不幸的是,没有办法强制MySQL
对绑定参数的每个值使用一个查询计划。
您可以使用JOIN
和INDEX
条款来控制所选的STRAIGHT_JOIN
订单和FORCE INDEX
,但它们不会强制索引上的某个访问路径或禁止IMPOSSIBLE WHERE
。
另一方面,对于所有JOIN
,MySQL
仅使用NESTED LOOPS
。这意味着,如果您构建正确的JOIN
订单或选择正确的索引,MySQL
可能会受益于所有IMPOSSIBLE WHERE
。
答案 2 :(得分:0)
如何使用仅对查询保持不变的值来优化查询,但是我,程序员,事先不知道将使用哪个值?
通过在特定列上使用索引(如果始终一起查询给定列,甚至可以使用列组合)。如果您有索引,查询计划程序将可能使用它们。
关于“不可能”的值:查询计划程序可以从几个来源推断出给定值不在表中:
PS。通常,创建查询计划并不昂贵,重新创建比重新使用它们更好,因为自生成查询计划以来可能已更改条件并且可能存在更好的查询计划。