1

注意:原始问题没有实际意义,但请扫描到底部以查找相关内容。

我有一个要优化的查询,看起来像这样:

select cols from tbl where col = "some run time value" limit 1;

我想知道正在使用什么键,但无论我通过什么来解释,它都能够将 where 子句优化为无(“不可能 WHERE 注意到......”),因为我给它提供了一个常数。

  • 有没有办法告诉mysql不要在解释中进行持续优化?
  • 我错过了什么吗?
  • 有没有更好的方法来获取我需要的信息?

编辑:EXPLAIN似乎给了我由常量值产生的查询计划。由于查询是存储过程的一部分(并且 spocs 中的 IIRC 查询计划是在调用它们之前生成的),这对我没有好处,因为值不是恒定的。我想要的是找出优化器在不知道实际值是什么时会生成什么查询计划。

我错过了什么吗?

Edit2:在别处询问,似乎 MySQL 总是重新生成查询计划,除非你不遗余力地让它重新使用它们。即使在存储过程中。由此看来,我的问题似乎没有实际意义。

但是,这并没有使我真正想知道的事情变得毫无意义: 您如何优化包含在任何特定查询中恒定的值的查询,但是我,程序员,事先不知道将使用什么值?-- 例如,假设我的客户端代码正在生成一个在其where子句中带有数字的查询。有时该数字会导致不可能的 where 子句,有时则不会。我如何使用解释来检查查询的优化程度?

我立即看到的最佳方法是EXPLAIN针对存在/不存在案例的完整矩阵运行它。确实,这不是一个很好的解决方案,因为手工操作既困难又容易出错。

4

3 回答 3

5

您收到“不可能在哪里注意到”,因为您指定的值不在列中,而不仅仅是因为它是一个常量。您可以 1) 使用列中存在的值,或者 2) 只说col = col

explain select cols from tbl where col = col;
于 2008-11-22T23:44:30.227 回答
4

例如,假设我的客户端代码正在生成一个在其 where 子句中带有数字的查询。

有时该数字会导致不可能的 where 子句,有时则不会。

我如何使用解释来检查查询的优化程度?

MySQL为不同的绑定参数值构建不同的查询计划。

本文中,您可以阅读MySQL优化器何时执行的列表:

    行动时

    查询解析准备
    否定消除准备
    子查询重写 PREPARE

    嵌套 JOIN 简化首先执行
    OUTER->INNER JOIN 转换首先执行

    分区修剪每次执行
    COUNT/MIN/MAX 消除 每次执行
    常量子表达式删除每个 EXECUTE
    平等传播每次执行
    常数表检测 每次执行
    ref 访问分析 每个 EXECUTE
    range/index_merge 分析和优化 每个 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不会使用从to的索引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访问权限,并决定是否即时使用访问权限。table1RANGE

您可以在我的博客中的这些文章中了解它:

所有这些东西都使用RANGE CHECKING FOR EACH RECORD

回到你的问题:没有办法知道哪个计划将MySQL用于每个给定的常量,因为在给定常量之前没有计划。

不幸的是,没有办法强制MySQL对绑定参数的每个值使用一个查询计划。

您可以使用and子句控制选择的JOIN顺序和'es ,但它们不会强制索引上的某个访问路径或禁止.INDEXSTRAIGHT_JOINFORCE INDEXIMPOSSIBLE WHERE

另一方面,对于所有JOIN的,MySQL仅雇用NESTED LOOPS. 这意味着如果您构建正确的JOIN顺序或选择正确的索引,MySQL可能会从 all IMPOSSIBLE WHERE's 中受益。

于 2009-05-04T20:23:18.900 回答
0

您如何使用仅对查询恒定的值来优化查询,但我,程序员,事先不知道将使用什么值?

通过在特定列上使用索引(如果您总是一起查询给定列,甚至在列组合上)。如果您有索引,查询规划器可能会使用它们。

关于“不可能”值:查询计划器可以从多个来源得出结论,给定值不在表中:

  • 如果特定列上有索引,它可以观察到特定值大于或小于索引中的任何值(最小/最大值需要恒定时间从索引中提取)
  • 如果您传入了错误的类型(如果您要求数字列与文本相等)

PS。通常,查询计划的创建并不昂贵,并且重新创建比重新使用它们更好,因为条件可能在查询计划生成后发生了变化,并且可能存在更好的查询计划。

于 2009-03-05T07:42:51.287 回答