【问题标题】:Suggest Plan to Query Optimiser向查询优化器建议计划
【发布时间】:2023-04-03 03:20:01
【问题描述】:

有时我可以使用强制索引选项在查询中使用特定索引来加快查询速度。

然后一段时间后,该表中的数据可能会发生变化。而且我使用的强制索引可能不是该查询的正确索引搜索。

我的问题是

  • 无论如何建议查询优化器在其计划生成期间使用强制索引作为可能的选项。如果使用强制索引的计划很慢,那么它可以使用正常的查询计划。

  • 否则是否无论如何要编辑 MySql/PSQL 的代码以建议优化器在其计划生成期间使用强制索引作为可能的选项。

附加信息:我想将我的计划添加到优化器计划列表中(优化器已经为查询创建了许多计划)。因此,在为查询选择最佳计划时,我希望优化器也考虑我的计划。如果这种方式可行,那么优化器就不需要每次都考虑力指数。它可以保留力索引作为计划生成的可能选项

据我所知,我试图把这个问题弄清楚。如果有人看不懂,请评论您的问题。

【问题讨论】:

标签: mysql database postgresql innodb psql


【解决方案1】:

据我所知

由于缺少某种统计和机制,例如直方图、动态采样等,Mysql 不足以支持您的要求。

因此,如果数据发生变化,尽管及时收集统计信息,但缺少前面描述的必要内容,优化器可能不会像您预期的那样运行。

您的两个问题可能是很好的做法,但对最终用户来说很难。

或者您可以为 oracle 或 maria db 团队提供建议?

【讨论】:

    【解决方案2】:

    我的问题是,你有没有因为力指数而导致执行缓慢?

    如果没有,
    选择优化器。它在糟糕的情况下跳过力指数
    例如:select last_name from employees force index(idx_last_name) order by last_name;
    在上面的查询中,它跳过了强制索引

    如果是,

    您可以根据您的观察覆盖优化器的计划。

    【讨论】:

    • 我想将我的计划添加到优化器计划列表中(优化器已经为查询创建了许多计划)。因此,在为查询选择最佳计划时,我希望优化器也考虑我的计划。如果这种方式可行,那么优化器就不需要每次都考虑力指数。它可以将力索引作为计划生成的可能选项。
    【解决方案3】:

    您处理的一般概念是“内部数据库统计信息”(不是官方术语)。即,数据库引擎用于制定查询计划的信息。统计信息存储详细信息,例如索引中的键分布、表行大小、计数、空行的百分比、数据的独特性等等。

    出于历史(和相关)性能原因,内部数据库统计信息不会即时更新,但通常会根据 DBA 的要求定期更新。在 Postgres 领域,此信息可通过 pg_statistic 表简洁地获得。不幸的是,MySQL 不会使这些信息随时可用,但您可以查看从 INFORMATION_SCHEMA 和 SHOW INDEXES 中收集到的信息。

    对于您手头的问题——查询计划提示的短暂有用性——是数据库的统计信息不能代表表数据。一般的反应是:更新相关表的数据库统计信息,您不需要在查询中提供优化器提示:

    ANALYZE TABLE <table_name>;
    

    有一些注意事项需要注意:

    • 如果没有额外的措施,数据库引擎的这种分析是短暂的:它不会在数据库重新启动/重新启动后持续存在。选项是在数据库启动时重新分析表,或查看statistics persistence

    • 这会通过采样数据生成统计信息——查看随机表行的子集。从本质上讲,随机抽样意味着在任何特定运行中收集的统计信息可能不能很好地表示实际数据,从而导致查询计划不佳。您可以通过innodb_stats_persistent_sample_pages增加示例页面数量

    • ANALYZE 不是OPTIMIZE,您的表可能还需要优化。 OPTIMIZE 是一项代价高昂的操作,需要锁定表,但在某些情况下可能非常有用。

    • ANALYZE 是特定于表格的,无法弥补糟糕的表格布局。例如,我最近的任务是加速一组运行缓慢的报表查询。罪魁祸首?该架构将时间和日期列存储为字符串,而不是本地数据类型。这具有巨大的影响,因为查询首先必须在比较之前将字符串转换为日期(包括数据中的错误),从而导致多次整个表扫描。非常糟糕。

    • ANALYZE 无法弥补糟糕的查询。例如,与前面的要点一样,WHERE SOME_FUNCTION( col ) &gt; some_value 之类的内容意味着查询计划器可能无法利用索引,因为每行必须首先执行 FUNCTION 才能获得条件结果。并非总是如此,但经常出现在幼稚的 SQL 查询中。

    • ANALYZE 无法弥补不良的标准化。尽管可能存在较大的算法常数,但通过适当的归一化,您将获得更大的 big-O 算法胜利。

    • ANALYZE创建索引。如果查询访问具有高基数但没有索引的列,那就太糟糕了。了解根据已知或预期查询在哪些列上放置索引取决于 DBA。

    在这种情况下,像往常一样,对 StackOverflow 的所有建议持保留态度:您负责数据或程序,并拥有实际运行的产品。你可以测试,你可以测量,你可以四处寻找。我们不能。

    【讨论】:

      【解决方案4】:

      问:无论如何建议查询优化器在其计划生成期间使用强制索引作为可能的选项。如果是使用强制索引的慢计划,那么它可以使用正常的查询计划。

      A:不。优化器会根据给定的内容做它所做的事情。优化器不会忽略提示。 SQL 文本中包含的任何提示都会产生影响。

      这就是为什么提示是“最后的手段”。我们的偏好是让优化器选择一个合适的计划。实现这一目标的最佳方法是仔细编写 SQL 以避免阻止使用适当索引的结构(例如,在函数中包装列),提供适当的索引,并确保统计信息准确且符合日期。

      问:是否可以编辑 MySql/PSQL 的代码以建议优化器在其计划生成期间使用强制索引作为可能的选项?

      A:优化器将考虑所有索引,如果候选访问计划的成本估计最低,则选择使用特定索引。这不需要 FORCE INDEX 提示; MySQL 将考虑索引。


      在 SQL 文本中使用提示是最后的手段。在我们考虑使用提示(FORCE INDEX 或其他)之前,我们应该

      • 使用允许(不阻止)使用适当索引的 SQL 结构。例如,对于 DATETIME 列dt,MySQL 可以对此dt &gt;= '2018-04-22' AND dt &lt; '2018-04-23' 使用范围扫描操作,但不能对此DATE(dt) = '2018-04-22' 使用。有时可以通过对 SQL 文本进行一些简单的调整来解决查询性能问题。有时会进行更广泛的重新设计和重写。

      • 有合适的索引可用(例如,考虑具有适当前导列的复合索引,并删除单列上的冗余索引)

      • 确保统计信息是最新的并且代表表(请注意,InnoDB 使用一小部分页面样本收集统计信息。如果被抽样的页面不代表表,我们可以得到有偏差的统计数据。

      【讨论】:

        【解决方案5】:

        FORCE INDEX 今天可能很好,但明天很糟糕。这是因为数据分布发生变化和/或查询中的常量发生变化。

        有一些模式通常会导致选择“错误”的索引:

        SELECT ...
            WHERE ...
            ORDER BY ...
        

        目前还不清楚是针对WHERE 还是针对ORDER BY 进行优化。

        SELECT ...
            FROM a
            JOIN b ON ...
            WHERE a.x ...
              AND b.y ...
        

        并不清楚是先过滤a.x 还是b.y。 (它不能同时过滤两者。)

        如果您提供特定的查询,我们可能会提供具体的提示。

        有时,可以重新制定查询以诱使优化器选择一条路径而不是另一条路径。 8.0 版有许多“提示”,但不一定比FORCE INDEX 好。 STRAIGHT_JOIN 是另一种暗示。

        重新制定查询可能涉及将其中的一部分转换为子查询。但同样,你冒着“今天好,明天坏”的风险。

        如果您“过度规范化”(例如规范化日期时间,然后使用 BETWEEN),则解决方案可能涉及非规范化。

        您是否使用“复合”索引? WHERE 的“范围”部分是否位于索引的最后? (还有很多其他问题——让我们看看具体的查询。)

        【讨论】:

        • 我没有处理具体的查询。我想了解更多关于查询优化器的信息。我想将我的计划添加到优化器计划列表中(优化器已经为查询创建了许多计划)。因此,在为查询选择最佳计划时,我希望优化器也考虑我的计划。如果这种方式是可能的,优化器就不需要每次都考虑力指数。它可以保留力指数作为计划生成的一个可能选项。注意:(力指数是我要讲的一个例子)
        • @vinieth,很可能优化器已经在考虑您的“最佳”计划,但是根据其成本模型,它决定“最佳”计划的成本比其他计划的成本更差,因此它不使用“最佳”计划。
        • @VladimirBaranov 但在某些情况下它找不到最佳计划。那时,如果我向优化者提出建议计划会很好。有什么办法吗。通过更改代码或其他方式。 (我需要为我执行的每个不同查询添加额外的计划到优化器计划列表中)。
        • 正如我所指出的,优化器并非总能找到“最佳”计划。这通常是由于对表中数据分布的了解有限。
        • @vinieth - 了解更多信息:mysql.rjweb.org/doc.php/index_cookbook_mysql
        【解决方案6】:

        唯一的方法是从查询中删除FORCE INDEX

        您可以覆盖优化器的计划,或者让优化器选择计划。

        优化器无法判断使用索引是否会变慢。它试图做出最好的猜测来选择一个快速的计划。

        优化器更准确的唯一方法是运行两个查询,比较性能差异,然后运行快速查询。这显然是不切实际的,所以优化器的目的是根据一些统计模型来估计查询的成本。大多数情况下,这足够准确,优化器的选择是最好的。

        【讨论】:

        • 问题2有什么办法
        猜你喜欢
        • 2023-04-01
        • 2016-06-08
        • 2020-11-21
        • 2019-10-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多