[翻译]——How the MySQL Optimizer Calculates the Cost of a Query (Doc ID 1327497.1)

这篇具有很好参考价值的文章主要介绍了[翻译]——How the MySQL Optimizer Calculates the Cost of a Query (Doc ID 1327497.1)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文是对这篇文章How the MySQL Optimizer Calculates the Cost of a Query (Doc ID 1327497.1)[1]的翻译,翻译如有不当的地方,敬请谅解,请尊重原创和翻译劳动成果,转载的时候请注明出处。谢谢!

适用于:

MySQL 4.0 及后续更高的版本

本文档中的内容适用于任何平台。

目标

了解 MySQL 优化器如何计算SQL语句的查询成本/代价以及如何分析EXPLAIN 语句的输出。

解决方案

MySQL优化器使用成本模型(cost model),其中查询计划的总体成本由各种操作(operation)的成本总体决定。确定成本的主要方法是使用存储提供的统计数据并使用所谓的成本常量(另请参阅下面的“对数据库成本模型进行更改”部分)。例如,这些统计数据是索引基数值(即索引中值的唯一性的度量)和每个表中的总行数。由于统计数据的不精确性,因为统计数据可能已经过时,或者它是使用近似方法来计算获取的统计数据(对于InnoDB数据库尤其如此,见下文),并且值的分布未知,那么优化器只能执行查询时提供查询结果集的行数的估计值。该预估值在某些情况下非常准确,但在某些情况下则不太准确。 实际的实现方式比上面的描述更复杂,确切的细节也可能取决于查询的类型。另请参阅参考手册中的优化器成本模型,了解 MySQL 5.7 及更高版本中优化器成本模型的讨论。 在 MySQL 5.6 及后续更高版本中,当我们在评估优化器如何执行查询语句时,优化器跟踪功能(optimizer trace feature)可用于深入了解优化器的决策过程。更多详细信息,请参阅注释 2241524.1[2]

更改数据库的成本模型

在 MySQL 5.7 以及后续版本中,优化器模型中使用的成本常量(cost constants)由数据库用来进行成本估算。如果需要的话,可以更改此数据库的配置。

警告:更改数据库的成本模型被认为是高级数据库管理。如果您进行更改以验证其行为是否符合预期时,请务必小心,并在部署到生产环境之前进行完全彻底充分的测试。

从 MySQL 5.7.17 开始,数据库成本模型中有两个可以调整的变量。数据存储在mysql.engine_cost表中,默认值为:

mysql> SELECT * FROM mysql.engine_cost;
+-------------+-------------+------------------------+------------+---------------------+---------+
| engine_name | device_type | cost_name              | cost_value | last_update         | comment |
+-------------+-------------+------------------------+------------+---------------------+---------+
default     |           0 | io_block_read_cost     |       NULL | 2017-01-13 15:21:46 | NULL    |
default     |           0 | memory_block_read_cost |       NULL | 2017-01-13 15:21:46 | NULL    |
+-------------+-------------+------------------------+------------+---------------------+---------+
2 rows in set (0.00 sec)

io_block_read_cost和memory_block_read_cost参数分别指定从磁盘和内存读取数据的相对成本。将 io_block_read_cost 参数的cost_value值设置为高于 memory_block_read_cost 的值,这会使优化器生成的查询计划更喜欢读取内存中数据,而不是从磁盘读取数据。 还可以通过将engine_name设置为要生效的存储引擎的名称来指定每个存储引擎的成本值。 当所有变更生效后,使用 FLUSH OPTIMIZER_COSTS 命令触发优化器重新读取成本模型数据。 每个会话的优化器成本都会被缓存。只有在 FLUSH OPTIMIZER_COSTS 语句执行之后启动的会话才会受到更改的影响。   例如,通过使用以下步骤将io_block_read_cost默认值设置为 2.0,将 InnoDB 存储引擎的默认值设置为 3.0:

1.将io_block_read_cost的默认值更新为 2.0:

mysql> UPDATE mysql.engine_cost
          SET cost_value = 2.0
        WHERE cost_name = 'io_block_read_cost';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0

2.为InnoDB存储引擎添加新的成本规则,将io_block_read_cost设置为3.0:

mysql> INSERT INTO mysql.engine_cost (engine_name, device_type, cost_name, cost_value, comment)
       VALUES ('InnoDB'0'io_block_read_cost'3.0'Using a slower disk for InnoDB');
Query OK, 1 row affected (0.01 sec)

3.刷新新的成本值:

mysql> FLUSH OPTIMIZER_COSTS;
Query OK, 0 rows affected (0.00 sec)

4.验证新的成本值是否在查询计划中给出了预期结果。

5.根据需要部署到生产。

InnoDB

如果您的表使用InnoDB 存储引擎,您还应该注意索引统计信息是基于有限数量记录的随机样本/采样的估计。如果您运行ANALYZE TABLE tablename(将tablename替换为实际的表名),然后运行SHOW INDEXES FROM tablename,那么您将看到基数将在后续一系列操作之间波动。表中的总行数也是如此。如果多次执行SHOW TABLE STATUS LIKE 'tablename',即使表上没有发生任何更新,那么您将看到每次执行时行总数的估计值也会有所不同(另一方面,对于MyISAM存储引擎表,表中的行数是精确的,因为其缺乏多版本控制和使用表锁,使得维护精确的统计数据变得更容易)。然而,您也可能不走运,最终对要检查的行数的估计相对较差。这也意味着,如果您运行ANALYZE TABLE tablename,那么行列中的值可能会发生变化,在某些情况下甚至查询计划本身也会发生变化。另请参阅MySQL 参考手册中的InnoDB 表限制。

注意:如果innodb_stats_on_metadata设置为ON(MySQL 5.5 及更早版本中的默认值),InnoDB会在元数据语句(例如SHOW TABLE STATUS或SHOW INDEX )执行期间访问INFORMATION_SCHEMA表TABLES或STATISTICS时更新统计信息。

为了更好地估计 InnoDB 表的索引基数,可以将参数innodb_stats_sample_pages设置为更大的值。但需要注意,较大的值将导致索引更新时间更长,并且每次打开表时都会重新计算统计信息,因此可能会对性能产生影响。另请参阅MySQL 优化器团队的Oystein Grovlen 的博客[3],文中讨论了更改innodb_stats_sample_pages的值如何影响索引基数计算。 innodb_stats_sample_pages选项是随 MySQL 5.1.38 中的 InnoDB 插件一起引入的。在MySQL 5.1和MySQL 5.0及更早版本的内置InnoDB中,该值无法更改,并且默认值为8。在 MySQL 5.6.3 中,innodb_stats_sample_pages已替换为innodb_stats_transient_sample_pages选项。对于 MySQL 5.6.2 及更高版本,另请参阅innodb_stats_persistent_sample_pages。   实际检查行数示例 要更好地估计实际检查的行数,请在查询之前和查询完成之后执行SHOW SESSION STATUS LIKE 'handler%'命令。另一种可能性是确保查询被慢查询日志记录,慢查询日志还提供检查的总行数。

使用会话状态变量查找检查的行数的示例是:

mysql> SHOW SESSION STATUS LIKE 'handler%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Handler_commit             | 0     |
| Handler_delete             | 0     |
| Handler_discover           | 0     |
| Handler_prepare            | 0     |
| Handler_read_first         | 0     |
| Handler_read_key           | 0     |
| Handler_read_last          | 0     |
| Handler_read_next          | 0     |
| Handler_read_prev          | 0     |
| Handler_read_rnd           | 0     |
| Handler_read_rnd_next      | 0     |
| Handler_rollback           | 0     |
| Handler_savepoint          | 0     |
| Handler_savepoint_rollback | 0     |
| Handler_update             | 0     |
| Handler_write              | 0     |
+----------------------------+-------+
16 rows in set (0.00 sec)

mysql> SELECT * FROM (SELECT id FROM t1 WHERE id < 100) t1 INNER JOIN t2 USING (id);
+----+-----+
| id | val |
+----+-----+
|  1 | a   |
|  2 | b   |
|  3 | c   |
...
| 98 | c   |
| 99 | a   |
+----+-----+
76 rows in set (0.00 sec)

mysql> SHOW SESSION STATUS LIKE 'handler%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Handler_commit             | 1     |
| Handler_delete             | 0     |
| Handler_discover           | 0     |
| Handler_prepare            | 0     |
| Handler_read_first         | 1     |
| Handler_read_key           | 100   |
| Handler_read_last          | 0     |
| Handler_read_next          | 99    |
| Handler_read_prev          | 0     |
| Handler_read_rnd           | 0     |
| Handler_read_rnd_next      | 100   |
| Handler_rollback           | 0     |
| Handler_savepoint          | 0     |
| Handler_savepoint_rollback | 0     |
| Handler_update             | 0     |
| Handler_write              | 99    |
+----------------------------+-------+
16 rows in set (0.00 sec)

这表明SQL查询总共读取了 300 行,分布如下:

  • 1 行读取索引中的第一个条目 (Handler_read_first)
  • 99 行按键顺序读取下一行(Handler_read_next)
  • 100 行从索引查找行(Handler_read_key)
  • 100 行进行表扫描 (Handler_read_rnd_next) 此外,由于派生表 (Handler_write),有 99 行被写入内部临时表。

参考资料

[1]

原文: https://support.oracle.com/epmos/faces/DocumentDisplay?id=1327497.1

[2]

1: https://support.oracle.com/epmos/faces/DocumentDisplay?parent=DOCUMENT&sourceId=1327497.1&id=2241524.1

[3]

Oystein Grovlen: http://oysteing.blogspot.com/2011/04/more-stable-query-execution-time-by.html文章来源地址https://www.toymoban.com/news/detail-745912.html

到了这里,关于[翻译]——How the MySQL Optimizer Calculates the Cost of a Query (Doc ID 1327497.1)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • AGI之Agent:《Agent AI: Surveying the Horizons of Multimodal Interaction智能体AI:多模态交互视野的考察》翻译与解读

    AGI之Agent:《Agent AI: Surveying the Horizons of Multimodal Interaction智能体AI:多模态交互视野的考察》翻译与解读 导读 :这篇文章探讨了一种新的 多模态 智能代理 体系结构,该体系结构可 感知视觉 刺激、 语言 输入和其他 环境相关 数据,并产生 有意义的实体动作 。 文章提出,随

    2024年01月22日
    浏览(101)
  • 安装 MySQL 服务时提示 Install/Remove of the Service Denied

    在安装 MySQL-8.0.25-winx64 的 MySQL 服务时遇到了以下提示: 安装 MySQL 服务时提示:、 即, 安装/删除服务被拒绝! ; MySQL 服务没有加载到电脑上时,以下功能都将无法使用: 启动 MySQL 服务是就会提示 服务名无效 ; 无法登录上 MySQL 的账户,无法使用 MySQL; 解决 Install/Remove

    2024年02月04日
    浏览(45)
  • 解决mysql常见错误,安装mysql提示Install/Remove of the service Denied!/显示无法启动/服务名无效

            1.1 在安装mysql中提示 Install/Remove of the service Denied!         1.2 MySQL 服务没有加载到电脑上时,有以下原因:                 1.2.1 端口被占用 ,需要更改端口,也可以卸载重装mysql。                 1.2.2 启动 MySQL 服务是就会提示  服务名无效  或

    2024年02月08日
    浏览(57)
  • How to Use the Git Restore Command

    The git restore command is used to restore files in your working directory to a previous state. It allows you to discard changes made to files or restore files that were deleted. The basic syntax of git restore is as follows: Here are a few common use cases of git restore : Discard Local Changes : To discard the changes made to a specific file and revert it

    2024年01月16日
    浏览(46)
  • How to Use the Git Reset Command

    The git reset command is used to move the current branch to a specific commit, effectively resetting the branch to that commit. It allows you to undo commits, unstage changes, or move the branch pointer to a different commit. The basic syntax of git reset is as follows: Here are three common usages of git reset : Soft Reset : To undo the most recent commit w

    2024年02月02日
    浏览(41)
  • How to find the TLS used for the SQL Server connection

    本文是How to find the TLS used for the SQL Server connection这篇英语文章的翻译,此文出处请见于文章底部链接: 原文出处 [1] 对于客户,我做了一些研究,如何找出SQL Server数据库会话连接使用了哪一种TLS协议。唯一的方式就是创建一个扩展事件,这个扩展事件有一个很大的限制就是只

    2024年02月06日
    浏览(48)
  • How to Write and Publish a Scientific Paper-How to Write the Results

    至此,我们进入了本文的核心- -数据。论文的这一部分称为结果部分。 与流行的信念相反,你不应该通过描述你在材料和方法部分无意中遗漏的方法来开始结果部分。 结果部分通常有两个成分。首先,你应该对实验进行某种整体的描述,提供大概的图景,而不必重复先前在

    2024年02月09日
    浏览(45)
  • 安装mysql服务出现Install/Remove of the Service Denied!问题,即使管理员启动cmd也无效

    在Windows系统下,如果你是以管理员身份运行cmd,但是仍然无法安装MySQL服务,可能是因为系统的用户账户控制(UAC)设置的问题。你可以尝试以管理员权限运行命令提示符(cmd),然后使用以下命令禁用UAC: reg add HKLMSOFTWAREMicrosoftWindowsCurrentVersionPoliciesSystem /v EnableLUA /t REG_DWO

    2024年02月15日
    浏览(44)
  • g) Visa: How Blockchain Can Facilitate the IoT Market

    作者:禅与计算机程序设计艺术 物联网(IoT)正在成为当前世界上最具规模的新兴产业之一。近年来,全球各行各业都涌现了大量的互联网终端设备,它们将物联网技术引入到自己的生活中,并产生了巨大的商业价值。但是,相对于其它传统电信、信息化领域来说,构建可靠

    2024年02月07日
    浏览(40)
  • How to install a specific version of a package in R

    在使用R语言完成数据分析的过程中,很多时候,因为项目实际需要,我们应该指定某些库文件的安装包的版本,这个时候,我们可以基于 devtools 包中的函数 install_version 来完成。 这里,我们以安装库文件 ggplot2 的安装包的版本号为3.3.6为例来说明,即 说明如下: version 版本

    2024年02月21日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包