├── .gitignore ├── README.md ├── SUMMARY.md ├── book.json ├── 介绍.md ├── 关于作者.md ├── 关于技术审查员.md ├── 第1部分-入门 ├── Chapter1.md ├── Chapter2.md ├── Chapter3.md └── Chapter4.md ├── 第2部分-信息来源 ├── Chapter5.md ├── Chapter6.md ├── Chapter7.md ├── Chapter8.md └── Chapter9.md ├── 第3部分-工具 ├── Chapter10.md ├── Chapter11.md └── Chapter12.md ├── 第4部分-模式注意事项和查询优化器 ├── Chapter13.md ├── Chapter14.md ├── Chapter15.md ├── Chapter16.md ├── Chapter17.md └── Chapter18.md ├── 第5部分-查询分析 ├── Chapter19.md ├── Chapter20.md ├── Chapter21.md └── Chapter22.md ├── 第6部分-改善查询 ├── Chapter23.md ├── Chapter24.md ├── Chapter25.md ├── Chapter26.md └── Chapter27.md ├── 致谢.md └── 附图 ├── 484666_1_En_23_Chapter_TeX_IEq1.png ├── 484666_1_En_23_Chapter_TeX_IEq2.png ├── Figure 1-1.png ├── Figure 1-2.png ├── Figure 10-1.png ├── Figure 10-10.png ├── Figure 10-11.png ├── Figure 10-12.png ├── Figure 10-13.png ├── Figure 10-14.png ├── Figure 10-15.png ├── Figure 10-16.png ├── Figure 10-17.png ├── Figure 10-18.png ├── Figure 10-19.png ├── Figure 10-2.png ├── Figure 10-20.png ├── Figure 10-21.png ├── Figure 10-22.png ├── Figure 10-3.png ├── Figure 10-4.png ├── Figure 10-5.png ├── Figure 10-6.png ├── Figure 10-7.png ├── Figure 10-8.png ├── Figure 10-9.png ├── Figure 11-1.png ├── Figure 11-10.png ├── Figure 11-11.png ├── Figure 11-12.png ├── Figure 11-13.png ├── Figure 11-14.png ├── Figure 11-15.png ├── Figure 11-16.png ├── Figure 11-17.png ├── Figure 11-18.png ├── Figure 11-19.png ├── Figure 11-2.png ├── Figure 11-20.png ├── Figure 11-21.png ├── Figure 11-3.png ├── Figure 11-4.png ├── Figure 11-5.png ├── Figure 11-6.png ├── Figure 11-7.png ├── Figure 11-8.png ├── Figure 11-9.png ├── Figure 12-1.png ├── Figure 12-2.png ├── Figure 12-3.png ├── Figure 14-1.png ├── Figure 16-1.png ├── Figure 16-2.png ├── Figure 16-3.png ├── Figure 16-4.png ├── Figure 16-5.png ├── Figure 17-1.png ├── Figure 17-2.png ├── Figure 17-3.png ├── Figure 17-4.png ├── Figure 18-1.png ├── Figure 18-2.png ├── Figure 19-1.png ├── Figure 19-10.png ├── Figure 19-11.png ├── Figure 19-2.png ├── Figure 19-3.png ├── Figure 19-4.png ├── Figure 19-5.png ├── Figure 19-6.png ├── Figure 19-7.png ├── Figure 19-8.png ├── Figure 19-9.png ├── Figure 2-1.png ├── Figure 2-2.png ├── Figure 2-3.png ├── Figure 20-1.png ├── Figure 20-10.png ├── Figure 20-11.png ├── Figure 20-12.png ├── Figure 20-13.png ├── Figure 20-2.png ├── Figure 20-3.png ├── Figure 20-4.png ├── Figure 20-5.png ├── Figure 20-6.png ├── Figure 20-7.png ├── Figure 20-8.png ├── Figure 20-9.png ├── Figure 22-1.png ├── Figure 22-2.png ├── Figure 22-3.png ├── Figure 22-4.png ├── Figure 22-5.png ├── Figure 23-1.png ├── Figure 23-2.png ├── Figure 23-3.png ├── Figure 23-4.png ├── Figure 24-1.png ├── Figure 24-2.png ├── Figure 24-3.png ├── Figure 24-4.png ├── Figure 24-5.png ├── Figure 24-6.png ├── Figure 24-7.png ├── Figure 24-8.png ├── Figure 25-1.png ├── Figure 25-2.png ├── Figure 25-3.png ├── Figure 25-4.png ├── Figure 25-5.png ├── Figure 25-6.png ├── Figure 25-7.png ├── Figure 26-1.png ├── Figure 26-2.png ├── Figure 26-3.png ├── Figure 27-1.jpg ├── Figure 3-1.png ├── Figure 3-2.png ├── Figure 4-1.png ├── Figure 4-10.jpg ├── Figure 4-11.jpg ├── Figure 4-2.jpg ├── Figure 4-3.png ├── Figure 4-4.jpg ├── Figure 4-5.png ├── Figure 4-6.png ├── Figure 4-7.png ├── Figure 4-8.png ├── Figure 4-9.png ├── Figure 5-1.png ├── Figure 5-2.png ├── Figure 5-3.png ├── Figure 7-1.jpg ├── Figure 9-1.png ├── author.png ├── cover.jpg ├── press.png └── reviewer.png /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | _book -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 《MySQL8查询性能调优》 2 | *一种提高执行速度的系统方法* 3 | 4 | ## 介绍 5 | 该书是翻译自*MySQL 8 Query Performance Tuning*, 翻译过程持续进行中, 欢迎对mysql技术感兴趣的小伙伴加入其中。你可以是译者、审校或者提一些意见 我们一概欢迎。期待该书翻译工作完工! 6 | 7 | ## 目录 8 | - [关于作者](关于作者.md) 9 | - [关于技术审查员](关于技术审查员.md) 10 | - [致谢](致谢.md) 11 | - [介绍](介绍.md) 12 | 13 | ### 第1部分 入门 14 | - [第1章-MySQL性能调优](./第1部分-入门/Chapter1.md) 15 | - [第2章-查询调优方法](./第1部分-入门/Chapter2.md) 16 | - [第3章-使用Sysbench进行基准测试](./第1部分-入门/Chapter3.md) 17 | - [第4章-测试数据](./第1部分-入门/Chapter4.md) 18 | 19 | ### 第2部分 信息来源 20 | - [第5章-Performance数据库](./第2部分-信息来源/Chapter5.md) 21 | - [第6章-sys数据库](./第2部分-信息来源/Chapter6.md) 22 | - [第7章-information数据库](./第2部分-信息来源/Chapter7.md) 23 | - [第8章-show语句](./第2部分-信息来源/Chapter8.md) 24 | - [第9章-慢查询日志](./第2部分-信息来源/Chapter9.md) 25 | 26 | ### 第3部分 工具 27 | - [第10章-MySQL企业监控器](./第3部分-工具/Chapter10.md) 28 | - [第11章-MySQL Workbench](./第3部分-工具/Chapter11.md) 29 | - [第12章-MySQL Shell](./第3部分-工具/Chapter12.md) 30 | 31 | ### 第4部分 模式注意事项和查询优化器 32 | - [第13章-数据类型](./第4部分-模式注意事项和查询优化器/Chapter13.md) 33 | - [第14章-索引](./第4部分-模式注意事项和查询优化器/Chapter14.md) 34 | - [第15章-索引统计](./第4部分-模式注意事项和查询优化器/Chapter15.md) 35 | - [第16章-直方图](./第4部分-模式注意事项和查询优化器/Chapter16.md) 36 | - [第17章-查询优化器](./第4部分-模式注意事项和查询优化器/Chapter17.md) 37 | - [第18章-锁原理与监控](./第4部分-模式注意事项和查询优化器/Chapter18.md) 38 | 39 | ### 第5部分 查询分析 40 | - [第19章-查找候选查询以进行优化](./第5部分-查询分析/Chapter19.md) 41 | - [第20章-分析查询](./第5部分-查询分析/Chapter20.md) 42 | - [第21章-事务](./第5部分-查询分析/Chapter21.md) 43 | - [第22章-诊断锁争用](./第5部分-查询分析/Chapter22.md) 44 | 45 | ### 第6部分 改善查询 46 | - [第23章-配置](./第6部分-改善查询/Chapter23.md) 47 | - [第24章-更改查询计划](./第6部分-改善查询/Chapter24.md) 48 | - [第25章-DDL 和批量数据负载](./第6部分-改善查询/Chapter25.md) 49 | - [第26章-复制](./第6部分-改善查询/Chapter26.md) 50 | - [第27章-缓存](./第6部分-改善查询/Chapter27.md) 51 | 52 | ## 资源 53 | - [美国亚马逊购买链接](https://www.amazon.com/-/zh/MySQL-Query-Performance-Tuning-Systematic/dp/1484255836) 54 | - [源代码下载](https://github.com/Apress/mysql-8-query-perf-tuning) 55 | 56 | 57 | ## gitbook支持 58 | [GitBook](https://www.gitbook.com/) 是一个基于`Node.js`的命令行工具,支持 Markdown 和 AsciiDoc 两种语法格式,可以输出 HTML、PDF、epub 等格式的电子书. 59 | 如有必要, 请参考[这篇教程](https://tonydeng.github.io/gitbook-zh/gitbook-howtouse/index.html). 60 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # 目录 2 | - [关于作者](关于作者.md) 3 | - [关于技术审查员](关于技术审查员.md) 4 | - [致谢](致谢.md) 5 | - [介绍](介绍.md) 6 | 7 | ## 第1部分 入门 8 | - [第1章-MySQL性能调优](./第1部分-入门/Chapter1.md) 9 | - [第2章-查询调优方法](./第1部分-入门/Chapter2.md) 10 | - [第3章-使用Sysbench进行基准测试](./第1部分-入门/Chapter3.md) 11 | - [第4章-测试数据](./第1部分-入门/Chapter4.md) 12 | 13 | ## 第2部分 信息来源 14 | - [第5章-Performance数据库](./第2部分-信息来源/Chapter5.md) 15 | - [第6章-sys数据库](./第2部分-信息来源/Chapter6.md) 16 | - [第7章-information数据库](./第2部分-信息来源/Chapter7.md) 17 | - [第8章-show语句](./第2部分-信息来源/Chapter8.md) 18 | - [第9章-慢查询日志](./第2部分-信息来源/Chapter9.md) 19 | 20 | ## 第3部分 工具 21 | - [第10章-MySQL企业监控器](./第3部分-工具/Chapter10.md) 22 | - [第11章-MySQL Workbench](./第3部分-工具/Chapter11.md) 23 | - [第12章-MySQL Shell](./第3部分-工具/Chapter12.md) 24 | 25 | ## 第4部分 模式注意事项和查询优化器 26 | - [第13章-数据类型](./第4部分-模式注意事项和查询优化器/Chapter13.md) 27 | - [第14章-索引](./第4部分-模式注意事项和查询优化器/Chapter14.md) 28 | - [第15章-索引统计](./第4部分-模式注意事项和查询优化器/Chapter15.md) 29 | - [第16章-直方图](./第4部分-模式注意事项和查询优化器/Chapter16.md) 30 | - [第17章-查询优化器](./第4部分-模式注意事项和查询优化器/Chapter17.md) 31 | - [第18章-锁原理与监控](./第4部分-模式注意事项和查询优化器/Chapter18.md) 32 | 33 | ## 第5部分 查询分析 34 | - [第19章-查找候选查询以进行优化](./第5部分-查询分析/Chapter19.md) 35 | - [第20章-分析查询](./第5部分-查询分析/Chapter20.md) 36 | - [第21章-事务](./第5部分-查询分析/Chapter21.md) 37 | - [第22章-诊断锁争用](./第5部分-查询分析/Chapter22.md) 38 | 39 | ## 第6部分 改善查询 40 | - [第23章-配置](./第6部分-改善查询/Chapter23.md) 41 | - [第24章-更改查询计划](./第6部分-改善查询/Chapter24.md) 42 | - [第25章-DDL 和批量数据负载](./第6部分-改善查询/Chapter25.md) 43 | - [第26章-复制](./第6部分-改善查询/Chapter26.md) 44 | - [第27章-缓存](./第6部分-改善查询/Chapter27.md) -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "MySQL8查询性能调优", 3 | "description": "一种提高执行速度的系统方法", 4 | "language": "zh-hans", 5 | "plugins": [ 6 | "github", 7 | "back-to-top-button" 8 | ], 9 | "pluginsConfig": { 10 | "github": { 11 | "url": "https://github.com/zxyle" 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /介绍.md: -------------------------------------------------------------------------------- 1 | MySQL 性能调优是一个非常大的主题,需要数年时间才能掌握。这本书的篇幅证明了这一点,即使范围缩小,专注于查询相关的主题。没有简单的提高性能的配方,通常需要了解不同部分之间的关系,不仅在MySQL内部,而且对于堆栈的其他部分。如果你觉得这是压倒性的开始,你远不是第一个,但不要绝望,因为它的性能调整一样与其他技能,练习使完美。 2 | 3 | 本书的目的是帮助您在提高 MySQL 实例上执行查询的性能方面获得良好的开端。正如所称,没有简单的配方,所以最好的方法就是了解性能调优所涉及的各种组件是如何工作的。这就是本书的大部分工作,以及给出寻找什么和如何执行共同任务的例子。另一方面,范围仅限于 MySQL 本身,因此对操作系统、文件系统和硬件级别的讨论非常有限。 4 | 5 | MySQL 以其对存储引擎的支持而著名。但是,本书专门包含 InnoDB 存储引擎,但讨论内部临时表除外。对于 MySQL 版本,仅考虑 MySQL 8。也就是说,大多数讨论也适用于旧版本的 MySQL,一般来说,当 MySQL 8 中的功能是新功能或 MySQL 8 与旧版本相比,其行为不同时,也会提到该讨论。 6 | 7 | ## 目标读者 8 | 9 | 这本书是为开发人员和数据库管理员编写的,他们拥有使用 MySQL 的经验,希望将他们的知识扩展到性能优化领域。无需事先体验性能调优。 10 | 11 | ## 示例和该书GitHub仓库 12 | 13 | 我已尝试添加尽可能多的示例和输出示例。有些例子很短,有些则相当长。在这两种情况下,我希望你能够跟随他们,并重现效果或结果证明。同时,请牢记,从自然性质上来说,往往涉及随机性(有时甚至与索引统计一样,示例的确切结果可能取决于在示例之前如何使用表和数据。换句话说,即使你做的每件事都是正确的,你也可能得到不同的结果。这尤其适用于与索引统计信息、计时等相关的数字。 14 | 15 | 长或产生的长或宽的输出的 IExamp 已加到本书的 GitHub 存储库中。这包括一些可能硬是使用页面格式允许的图像大小读取的数字。指向存储库的链接可从位于此位置的www.apress.com/gp/book/9781484255834 16 | 17 | 一旦创建,GitHub 存储库也将是该书的勘误表的家。当 MySQL 8 中的 Bug 修复和新功能导致图书内容更改时,我不仅将使用勘误表来传达书中的错误,还将使用 toprovide 更新。如有必要,我还将更新存储库中的示例,以反映较新版本中行为。出于这些原因,我建议你留意存储库。 18 | 19 | ## 该书结构 20 | 21 | 待翻译 22 | 23 | -------------------------------------------------------------------------------- /关于作者.md: -------------------------------------------------------------------------------- 1 | **Jesper Wisborg Krogh** 自 2006 年作为 SQL 开发人员和数据库管理员与 MySQL 数据库合作,并在 8 年多一直是 TheOracle MySQL 支持团队的一员。他曾多次在 MySQLConnect 和 Oracle OpenWorld 上发言,除了他的著作外,他还经常撰写有关 MySQL 主题的博客,并在 Oracle 知识库中撰写了大约 800 份文档。他为 MySQL 5.6+8 的 sys 架构和四次 Oracle 认证专业 (OCP) 考试做出了贡献,在 2006 年与 MySQL 和其他软件开发合作之前,他获得了计算化学博士学位。Jesper 住在澳大利亚悉尼,喜欢在户外散步、旅行和阅读。他的专业领域包括 MySQL 群集、MySQL 企业备份 (MEB)、性能调优以及性能和系统架构。 -------------------------------------------------------------------------------- /关于技术审查员.md: -------------------------------------------------------------------------------- 1 | **查尔斯·贝尔**从事新兴技术的研究。他是 Oracle MySQL 开发团队的成员,也是 MySQL 企业备份团队的高级软件开发人员。他和爱的妻子住在维吉尼亚州农村的一个小镇上。他于2005年从弗吉尼亚联邦大学获得工程学博士学位,查尔斯是数据库领域的专家,在软件开发和系统工程方面拥有丰富的知识和经验。他的研究兴趣包括三维打印机/打印、微控制器、数据库系统、软件工程、高可用性系统、云和传感器网络。作为一名练习者,他利用有限的空闲时间,专注于微控制器项目和三维打印机的改进。 -------------------------------------------------------------------------------- /第1部分-入门/Chapter1.md: -------------------------------------------------------------------------------- 1 | # MySQL性能调优 2 | 3 | 欢迎来到MySQL性能调优领域。 这个世界有时看起来似乎被黑魔法和运气所支配,但是希望这本书可以帮助您以结构化的方式去工作,并有条不紊地以更好的方式去工作。 4 | 5 | 本章通过讨论整个堆栈以及监视和基于数据执行操作的重要性,向您介绍MySQL性能调优。 由于本书主要是关于查询的,因此在结束本章之前,先回顾一下查询的生命周期。 6 | 7 | ------ 8 | 9 | **技巧** 如果您需要一个测试实例,无论是阅读本书时,还是为了处理工作中的问题,云都可以是你的朋友。它允许您快速启动测试实例。如果您只需要一个小实例,例如,在本书中探索示例,您甚至可以使用免费实例,例如通过 Oracle 云的免费套餐(仍然需要注册和信用卡):https://mysql.wisborg.dk/oracle_cloude_free_tier. 10 | 11 | ------ 12 | 13 | 14 | 15 | ## 考虑整个堆栈 16 | 17 | 调查性能问题时,必须考虑系统的所有部分,从最终用户到应用程序再到 MySQL。当有人报告应用程序速度很慢,并且您知道 MySQL 是应用程序的核心部分时,很容易得出"MySQL 速度慢"的结论。但是,这将排除造成性能不佳的许多潜在原因。 18 | 19 | 当应用程序需要查询结果或需要在 MySQL 中存储数据时,它会通过网络将请求发送到 MySQL,为了执行请求,MySQL 与操作系统交互并使用主机资源(如内存和磁盘)。一旦请求的结果准备就绪,它将通过网络将通信回应用程序。图 1-1 说明了这一点。 20 | 21 | 请求的结果准备就绪后,通过网络将其传递回应用程序。 如图1-1所示。 22 | ![](../附图/Figure%201-1.png) 23 | 24 | 这个金字塔是一个非常简化的图片,它把应用程序以外的一切都删除了,而应用程序又可能与用户通信并使用自己的资源。 网络通信还涉及主机和操作系统。 25 | 26 | 为了说明图层如何交互,请考虑一个实际示例。一个MySQL用户报告了MySQL遇到临时停顿的问题。在Linux上使用 perf 工具的一项调查显示,之所以出现停滞,是因为内存非常分散,主要是由 I/O 缓存引起的。当您通过网络提交数据时,Linux 会请求连续的内存部分(使用 kmalloc),但由于内存严重碎片化,Linux 必须先对内存进行碎片整理(压缩)。在进行这种压缩的同时,包括MySQL在内的所有内容都停滞了,并且在最坏的情况下,它长达一分钟(服务器具有大量可用于I/O缓存的内存),因此造成了严重的影响。 在这种情况下,更改MySQL配置以使用直接I/O可以解决此问题。尽管这是一个极端的情况,但值得注意的是,交互会导致令人惊讶的拥塞点。 27 | 28 | 一个更直接的实际示例是使用框架来生成查询的应用程序。框架中存在一个错误,这意味着对大型表的查询省略了WHERE子句。这意味着一系列的问题,包括应用程序重试查询,并在几秒钟内完成50个查询副本(由于数据最终已被读入缓冲池,使得最后一个查询的执行速度比第一个查询快得多),最终导致一系列问题的解决; 将大量数据发送回应用程序,导致网络过载,并且应用程序内存不足。 29 | 30 | 本书重点介绍 MySQL 和影响查询的各个方面,但不要忘记系统的其余部分。这包括您监视系统的时间。 31 | 32 | ## 监控方式 33 | 34 | 如果你只从阅读这本书中拿出一件事,那么让监控对于维持一个健康的系统至关重要。你所做的一切都应该围绕着监控。在某些情况下,通过专用的监视解决方案进行监视可提供您需要的所有数据,在其他情况下,您需要进行临时观察。 35 | 36 | 您的监视应使用多种信息来源。 这些包括但不限于 37 | 38 | - Performance Schema,包括从低级互斥量到查询和事务度量的信息。这是用于查询性能调优的最重要的信息源。 sys schema 提供了一个方便的界面,特别是用于即席查询。 39 | - Information Schema,其中包括模式信息,InnoDB统计信息等。 40 | - SHOW语句,例如,包含来自InnoDB的信息以及详细的引擎统计信息。 41 | - 慢查询日志,可以记录符合某些条件的查询,例如花费比预定义阈值更长的时间的查询。 42 | - EXPLAIN语句返回查询执行计划。这是一个无价的工具,用于调查为什么由于缺少索引,查询以次优方式编写或MySQL选择次优方式执行查询而导致查询无法正常运行的原因。 EXPLAIN语句在调查特定查询时通常以临时方式使用。 43 | - 操作系统指标,例如磁盘利用率,内存利用率和网络利用率。不要忘记简单的指标(例如可用存储量),因为存储空间不足会导致中断。 44 | 45 | 这些信息来源在本书中都有讨论和使用。 46 | 47 | 在整个性能调优过程中使用监视时,您可以验证问题是什么,找到原因,并证明您已经解决了问题。在处理解决方案时,了解查询的生命周期也很有用。 48 | 49 | ## 查询的生命周期 50 | 51 | 执行查询时,它会在查询结果回到应用程序或客户端之前执行几个步骤。每个步骤都需要时间,而且本身可能是由多个子部分组成的复杂操作。 52 | 53 | 查询生命周期的简化概述见图 1-2。在实践中,涉及更多的步骤,如果您安装了诸如查询重写器之类的插件,它将添加它们自己的步骤。但是,该图确实涵盖了基本步骤,稍后将更详细地介绍几个步骤 54 | 55 | ![](../附图/Figure%201-2.png) 56 | 57 | MySQL 服务器可分为两层。例如,SQL 层处理连接并准备语句以执行。实际数据由存储引擎存储,这些引擎作为插件实现,因此相对容易实现处理数据的不同方法。本书中考虑的主要存储引擎是 InnoDB,它是完全事务性的,并且对高并发工作负载具有很好的支持。另一个存储引擎的示例是 NDBCluster,它也是事务性的,用作MySQL NDB集群的一部分。 58 | 59 | 当应用程序需要执行查询时,第一件事是创建连接(这不包括在图中,因为连接可以重复使用以执行更多查询)。当查询到达时,MySQL 将分析它。这包括将查询拆分为token,因此查询类型是已知的,并且有查询所需的表和列的列表。在下一步中,需要此列表,检查用户是否具有执行查询所需的权限。 60 | 61 | 此时,查询已达到确定如何执行查询的重要步骤。这是优化器的工作,涉及重写查询以及确定访问表的顺序以及要使用的索引。 62 | 63 | 实际执行步骤包括从存储引擎层请求数据。存储引擎本身可能很复杂。对于 InnoDB,它包括用于缓存数据和索引的缓冲池、重做和撤销日志、其他缓冲区以及表空间文件。如果查询返回行,则这些行通过 SQL层 从存储引擎发送回应用程序。 64 | 65 | 在查询调优中,最重要的步骤是优化器和执行步骤,包括存储引擎。本书中大部分信息直接或间接地与这三部分有关。 66 | 67 | ## 总结 68 | 69 | 本章触及了性能调优的表面,并让你为本书的其余部分的旅程做好准备。关键要点是,您需要考虑从最终用户到主机和操作系统的低级详细信息,监视在性能调优中是绝对必须的。执行查询包括每个步骤,其中优化器和执行步骤是您将在本书中学到的最多步骤。 70 | 71 | 下一章将仔细研究一种有助于解决性能问题的方法。 -------------------------------------------------------------------------------- /第1部分-入门/Chapter2.md: -------------------------------------------------------------------------------- 1 | # 查询调优方法 2 | 3 | 有几种解决问题的方法。 在极端情况下,您可以先潜水,然后尝试进行一些更改。尽管这似乎可以节省时间,但通常会造成挫败感,即使所做的更改似乎奏效,您也无法确定自己是否真正解决了根本问题,或者只是暂时性地改善了问题。 4 | 5 | 相反,建议是通过进行分析并使用监视来确认更改的效果,从而在方法上进行工作。 本章将向您介绍一种方法,该方法在解决MySQL问题时会很有用,重点是性能调优。 首先介绍该方法中的步骤。 然后,本章的其余部分将更详细地讨论每个步骤,以及为什么花尽可能多的时间主动地进行工作很重要。 6 | 7 | ------ 8 | 9 | **注意**:此处描述的方法基于Oracle支持中用于解决客户报告的问题的方法。 10 | 11 | ------ 12 | 13 | 14 | 15 | ## 总览 16 | 17 | MySQL性能调优可以看作是一个永无止境的过程,在此过程中,使用迭代方法逐步改善性能。 显然,有时会出现诸如查询之类的特定问题,需要花费半小时才能完成,但是请记住性能不是二进制状态,这一点很重要,因此有必要知道足够好的性能。 否则,您将永远无法完成单个任务。 18 | 19 | 图2-1显示了如何描述性能调优生命周期的示例。 该循环从左上角开始,包括四个阶段,其中第一个阶段是验证问题。 20 | 21 | ![](../附图/Figure%202-1.png) 22 | 23 | 当您遇到性能问题时,第一步是验证问题所在,包括收集问题证据并定义考虑解决问题的要求。 24 | 25 | 第二阶段涉及确定性能问题的原因,而第三阶段则确定解决方案。 最后,在第四阶段中实施解决方案。 解决方案的实施应包括验证更改后的效果。 26 | 27 | ------ 28 | 29 | **提示**:在危机期间进行救火和主动工作时,此循环均有效。 30 | 31 | ------ 32 | 33 | 然后,您就可以从头做起,要么进行第二次迭代,以进一步提高刚刚关注的问题的运行性能,要么可能需要解决第二个问题。也可能在周期之间会有一段很长的时间。 34 | 35 | 然后,您可以准备从头开始,或者进行第二次迭代以进一步改善刚遇到性能的问题,或者您可能需要处理第二个问题。 周期之间也可能会有很长的一段时间。 36 | 37 | ## 验证问题 38 | 39 | 在尝试确定导致问题的原因和解决方案之前,必须清楚您试图解决什么问题。 仅仅说“ MySQL慢”是不够的–这意味着什么? 一个具体的问题可能是“前网页第二部分中使用的查询需要五秒钟”或“ MySQL每秒只能维持5000个事务”。 您越具体,解决问题的机会就越大。 40 | 41 | 问题的定义还应该包括验证问题所在。 最初看起来是什么问题与真正的问题之间可能会有区别。 验证问题可能很简单,例如执行查询并观察查询是否真的花了那么长的时间,或者可能涉及查看监视。 42 | 43 | 准备工作还应包括从监视中收集基准或运行说明问题的数据集。 没有基准,您可能无法在故障排除结束时证明已解决了该问题。 44 | 45 | 最后,您需要确定性能调优的目标是什么。引用斯蒂芬 · 科维的《高效人士的习惯》 46 | 47 | *开始就要考虑如何结束。* 48 | 49 | 慢查询的运行速度的最低可接受目标是什么?或者所需的最小事务吞吐量是多少?这将确保您知道在进行更改时是否达到了目标。 50 | 51 | 问题已明确定义和验证后,可以开始分析问题并确定原因。 52 | 53 | ## 确定原因 54 | 55 | 第二阶段是确定性能不佳的原因。确保你思路开放,并考虑整个堆栈,所以你最终不会盯着自己的盲目的一个方面,事实证明,没有任何与问题有关。 56 | 57 | 第二阶段是确定性能低下的原因。 确保心胸开阔,并考虑整个堆栈,以免最终看不到与问题无关的一个方面。 58 | 59 | 当你认为你知道原因时,你还需要争辩为什么这就是原因。EXPLAIN 语句的输出清楚地显示查询执行完整表扫描,因此这可能是原因,或者您可能有一个图形显示 InnoDB 重做日志已满 75%,因此您可能会出现异步刷新导致临时性能问题。 60 | 61 | 当您认为自己知道原因时,还需要争论为什么这就是原因。 您可能具有EXPLAIN语句的输出,清楚地表明查询执行了全表扫描,因此这可能是原因,或者您可能有一个图显示InnoDB重做日志已满75%,因此您可能具有异步 刷新会导致临时性能问题。 62 | 63 | 找出原因往往是调查最难的部分。一旦知道原因,您就可以决定解决方案。 64 | 65 | ## 确定解决方案 66 | 67 | 确定要调查的问题的解决方案需要两个步骤。 第一步是寻找可能的解决方案; 其次,您必须选择实施哪一个。 68 | 69 | 当你寻找可能的解决方案时,进行头脑风暴会很有用,你写下所有你能够想到的想法。重要的是,不要将自己限制在根本原因所在的狭窄区域,因为在尽可能多的地方可能找到其他区域的解决方案。例如,由于上一章中提到的内存碎片而导致的停滞,其中解决方案是更改 MySQL 的配置,以使用直接 I/O 来减少操作系统 I/O 缓存的使用。您还应同时考虑短期解决方法和长期解决方案,因为如果需要重新启动或升级 MySQL、更改硬件或类似解决方案,则可能并不总是能够立即实施完整解决方案。 70 | 71 | 当您寻找可能的解决方案时,进行头脑风暴,写下所有可以想到的想法,可能会很有用。 重要的是,不要将自己限制在根本原因所在的狭窄区域,因为在尽可能多的地方可能找到其他区域的解决方案。 上一章提到的由于内存碎片化导致的停顿就是一个例子,解决方案是更改MySQL的配置以使用直接I/O以减少对操作系统I/O缓存的使用。 您还应该牢记短期解决方法和长期解决方案,因为如果需要重新启动或升级MySQL,更改硬件或类似功能,则不一定总是可以立即实施完整的解决方案。 72 | 73 | ------ 74 | 75 | **提示** 有时被低估的解决方案是升级 MySQL 或操作系统以使用新功能。但是,当然,您需要进行小心测试,以验证您的应用程序是否与新版本兼容,并特别小心优化器是否有任何更改会导致查询性能不佳。 76 | 77 | ------ 78 | 79 | 确定解决方案的第二部分是选择最适合的候选解决方案。为了做到这一点,你必须争论每个解决方案为什么它的工作原理,什么是利弊。在这一步中,重要的是要对自己诚实,并小心地考虑可能的副作用。 80 | 81 | 一旦您充分了解所有可能的解决方案,您可以选择继续使用哪种解决方案。您还可以选择一个解决方案作为临时缓解措施,同时使用更可靠的解决方案。在这两种情况下,下一阶段是实现解决方案。 82 | 83 | ## 实施解决方案 84 | 85 | 您可以通过一系列步骤来实现该解决方案,其中定义了行动计划,测试行动计划,优化行动计划等,直到最终将该解决方案应用于生产系统。 重要的是不要急于执行此过程,因为这是发现解决方案问题的最后机会。 在某些情况下,测试还可能表明您将需要放弃该解决方案,然后返回上一个阶段并选择其他解决方案。 图2-2说明了实施解决方案的工作流程。 86 | 87 | ![](../附图/Figure%202-2.png) 88 | 89 | 您采用选择的解决方案,并为其创建一个行动计划。 在这里,非常具体很重要,这样可以确保测试的行动计划也是最终在生产系统上应用的行动计划。 写下将要使用的确切命令和语句很有用,这样您就可以复制和粘贴它们,或者将它们收集在脚本中,以便可以自动应用它们。 90 | 91 | 然后,您需要在测试系统上测试操作计划。 重要的是要尽可能地反映生产环境。 您在测试系统上拥有的数据必须代表您的生产环境数据。 实现此目的的一种方法是复制生产环境数据,可以选择使用数据屏蔽来避免将敏感信息(例如个人详细信息和信用卡信息)复制到生产系统之外。 92 | 93 | ------ 94 | 95 | **提示** MySQL企业版订阅(收费订阅)包括数据屏蔽功能:www.mysql.com/products/enterprise/masking.html。 96 | 97 | ------ 98 | 99 | 测试应验证该解决方案已解决问题,并且没有意外的副作用。 要求什么测试取决于您要解决的问题和建议的解决方案。 如果查询速度慢,则需要在实施解决方案后测试查询的性能。 如果修改一个或多个表上的索引,则还必须验证它如何影响其他查询。 实施解决方案后,您可能还需要对系统进行基准测试。 在所有情况下,您都需要与问题验证期间收集的基准进行比较。 100 | 101 | 第一次尝试可能无法按预期进行。 通常,仅需要对行动计划进行一些细化,有时您可能不得不完全放弃提议的解决方案,然后返回上一个阶段并选择另一个解决方案。 如果建议的解决方案部分解决了问题,则您也可以选择将其应用于生产系统,然后重新开始并评估如何继续改善性能。 102 | 103 | 如果您对测试显示解决方案有效感到满意,则可以将其应用于暂存系统,如果一切仍在工作,则可以将其应用于生产系统。 完成此操作后,您再次需要验证它是否有效。 无论您多么谨慎地设置代表生产系统的测试系统,由于某种原因,该解决方案都可能无法按预期在生产中完全正常工作。 本书作者遇到的一种可能性是,本质上随机的索引统计信息是不同的,因此在将解决方案应用于生产系统时,必须使用ANALYZE TABLE语句来更新索引统计信息。 104 | 105 | 如果该解决方案有效,则应收集新的基准,以用于将来的监视和优化。 如果该解决方案不起作用,则需要通过回滚更改并寻找新的解决方案或进行新一轮的故障排除并确定为什么该解决方案不起作用并应用第二个解决方案来决定如何继续。 106 | 107 | ## 积极工作 108 | 109 | 性能调优是一个永无止境的过程。 如果您的系统从根本上来说是健康的,那么大部分工作都将在预防紧急情况和紧急程度相对较低的地方积极开展。 这不会给您的工作带来太多关注,但是它将使您的日常生活压力减轻,并且用户会更快乐。 110 | 111 | ------ 112 | 113 | **注意**:这一讨论在某种程度上基于斯蒂芬·科维的《高效人士7个习惯》中的习惯3"*把第一件事放在第一位*"。 114 | 115 | ------ 116 | 117 | 图2-3显示了如何将任务分类为紧急程度和重要性。 紧急任务通常会引起其他人的注意,而其他任务可能很重要,但是只有在未及时完成的情况下它们才会变得可见,因此它们突然变得紧急。 118 | 119 | ![](../附图/Figure%202-3.png) 120 | 121 | 最容易归类的任务是与危机相关的任务,例如生产系统故障和公司损失收入,因为客户无法使用产品或进行购买。 这些任务既紧急又重要。 在这些任务上花费大量时间可能会让您感到很重要,但这也是一种非常紧张的工作方式。 122 | 123 | 解决性能问题的最有效方法是处理重要但不是紧迫的问题。 这是预防危机发生的前瞻性工作,它包括监视,在问题变得明显之前进行改进等等。 此类别中的一项重要任务也是准备,因此您已准备好应对危机。 例如,这可能是为了建立一个备用系统,以备您在发生危机时进行故障转移或快速启动替换实例的过程。 这可以帮助减少危机的持续时间,并使危机重新回到重要但并非紧急的类别。 您花费在此类任务上的时间越多,通常您就越成功。 124 | 125 | 最后两类包括不太重要的任务。 紧急但不重要的任务包括无法重新安排的会议,其他人推动的任务以及可感知的(但不是真实的)危机。 非紧急和不重要的任务包括管理任务和检查电子邮件。 当然,其中一些任务可能对于保持您的工作是必需的并且很重要,但是对于保持MySQL的良好性能并不重要。 尽管总是必须处理这些类别中的任务,但重要的是要尽量减少在此花费的时间。 126 | 127 | 避免处理不重要的任务的一部分包括您了解任务的重要性,例如,通过定义性能何时足够好,这样就不会最终对查询或吞吐量进行过度优化。 在实践中,如果非重要任务吸引了组织中其他人的注意力,这些任务当然会很困难(这些任务通常是紧急任务),但是重要的是,您应尽可能多地尝试 可以将工作转移到重要但非紧急的任务上,以避免危机任务在以后的时间接管。 128 | 129 | ## 总结 130 | 131 | 本章讨论了可用于解决MySQL性能问题(以及其他类型的问题)的方法,以及主动工作的重要性。 132 | 133 | 报告问题后,您便可以开始验证问题所在并确定已解决的问题。 对于天生具有开放性的绩效问题,重要的是要知道什么是足够好的,否则您将冒着永不停止执行危机管理并回到主动工作的风险。 134 | 135 | 一旦有了清晰的问题描述,就可以确定原因。 原因明确之后,您可以确定要解决的问题。 最后一个阶段是实施解决方案,如果事实证明您首先选择的解决方案不起作用或具有不可接受的副作用,则可能需要您重新考虑潜在的解决方案。 在这种情况下,重要的是要尽可能实际地测试解决方案。 136 | 137 | 本章的最后部分讨论了花尽可能多的时间进行积极主动的工作的重要性,这些工作可以防止发生危机,并在危机发生时帮助您做好准备。 这将帮助您减轻工作压力,并以更好的状态管理数据库。 138 | 139 | 正如本章所讨论的,在将解决方案部署到生产系统之前测试其影响非常重要。 下一章将介绍基准测试,重点是Sysbench基准测试。 -------------------------------------------------------------------------------- /第1部分-入门/Chapter4.md: -------------------------------------------------------------------------------- 1 | # 测试数据 2 | 3 | 测试是性能调优工作中非常重要的一部分,因为在将更改应用到生产系统之前,请确保已确认所做的更改很重要,这一点很重要。 验证变更的最佳数据与生产数据密切相关; 但是,为了探索MySQL的工作方式,最好使用一些通用的测试数据。 本章介绍了四个带有安装说明的标准数据集,以及一些可用的其他数据集。 4 | 5 | ------ 6 | 7 | **提示** 本书的其余部分将使用world数据库,world_x数据库和sakila数据库作为测试数据。 8 | 9 | ------ 10 | 11 | 但是,首先,您需要知道如何下载数据库。 12 | 13 | ## 下载示例数据库 14 | 15 | 本章将详细讨论的示例数据库的共同点是可以从https://dev.mysql.com/doc/index-other.html下载它们,或者有指向可以从中下载它们的链接。 对于其中的一些数据库,此页面还链接了联机文档和PDF文件。 该页面的相关部分如图4-1所示。 16 | 17 | ![](../附图/Figure%204-1.png) 18 | 19 | 员工数据(员工数据库)是从Giuseppe Maxia的GitHub存储库下载的,而其他数据库是从Oracle MySQL站点下载的。 包含员工数据的下载内容还包括sakila数据库的副本。 对于员工数据,world数据库和sakila数据库,还有可用的文档。 20 | 21 | ------ 22 | 23 | **注意** 如果您没有使用最新版本的数据,则在安装测试数据库时,可能会看到有关不推荐使用的功能的警告。 您可以忽略这些警告,但是建议获取最新版本的数据。 24 | 25 | ------ 26 | 27 | menagerie数据库是一个很小的两表数据库,总共少于20行,这是针对MySQL手册中的tutorials部分创建的。 不再赘述。 28 | 29 | ## world数据库 30 | 31 | world样本数据库是用于简单测试的最常用数据库之一。 它由具有几百到几千行的三个表组成。 这使其成为一个小的数据集,这意味着即使在小型测试实例上也可以轻松使用它。 32 | 33 | ### 模式 34 | 35 | 该数据库由city,country和countrylanguage组成。 表之间的关系如图4-2所示。 36 | 37 | ![](../附图/Figure%204-2.jpg) 38 | 39 | 国家地区表包括有关 239 个国家/地区的信息,并在城市和国家表。数据库中共有4079个城市,国家语言组合有984。 40 | 41 | country表包含有关239个国家/地区的信息,并用作来自city表和countrylanguage表的外键中的父表。 数据库中共有4079个城市,并且984个国家和语言组合。 42 | 43 | ### 安装 44 | 45 | 下载的文件包含一个名为world.sql.gz或world.sql.zip的文件,具体取决于您选择的是Gzip还是Zip链接。 无论哪种情况,下载的归档文件都包含一个文件world.sql。 数据的安装非常简单,因为只需执行脚本即可。 46 | 47 | 如果您在2020年1月左右或之前将MySQL Shell与world数据库的副本一起使用,则需要使用传统协议,因为X协议(默认)需要UTF-8,而world数据库则使用Latin 1。 \source命令从MySQL Shell加载数据: 48 | 49 | ``` 50 | MySQL [localhost ssl] SQL> \source world.sql 51 | ``` 52 | 53 | 如果使用旧版命令行客户端,请改为命令: 54 | 55 | ``` 56 | mysql> SOURCE world.sql 57 | ``` 58 | 59 | 在这两种情况下,如果位于启动 MySQL Shell 或 mysql 的目录中,请将其添加到。 60 | 61 | 在任何一种情况下,如果该路径都不位于启动MySQL Shell或mysql的目录中,则将其添加到world.sql文件。 62 | 63 | 另一个相关的数据库是world_x,它包含与world相同的数据,但是组织方式不同 64 | 65 | ## world_x数据库 66 | 67 | MySQL 8增加了对MySQL文档存储的支持,该文档存储支持以JavaScript对象符号(JSON)文档的形式存储和检索数据。 world_x数据库将一些数据存储在JSON文档中,从而为您提供一个测试数据库,该数据库可以轻松用于包含JSON使用的测试。 68 | 69 | ### 模式 70 | 71 | 包含与世界数据库相同的表,尽管列略有不同,例如具有人口(而不是人口的 JSON"信息省略了几列。相反,有一表,它是一个纯文档存储 - 类型表,否则信息将从国家/中删除。图。 72 | 73 | world_x数据库包含与world数据库相同的三个表,尽管各列略有不同,例如,city表包含JSON列Info而不是人口列,而People列包含Country列,而country表则省略了几列。 取而代之的是,有一个countryinfo表,它是一个纯文档存储类型的表,其中的信息否则已从country表中删除。 该架构图如图4-3所示。 74 | 75 | ![](../附图/Figure%204-3.png) 76 | 77 | 尽管没有来自city和countryinfo表的外键,但是可以分别使用CountryCode列和doc->>'$.Code'值将它们连接到country表。 countryinfo表的_id列是存储的生成列的示例,其中该值是从doc列中的JSON文档中提取的。 78 | 79 | ### 安装 80 | 81 | world_x数据库的安装与world数据库非常相似。 您可以下载world_x-db.tar.gz或world_x-db.zip文件并将其解压缩。 提取的文件包括一个名为world_x.sql的文件以及一个README文件。 world_x.sql文件包含创建模式所需的所有语句。 82 | 83 | 由于world_x模式使用UTF-8,因此您可以使用任何一种MySQL协议进行安装。 例如,使用MySQL Shell: 84 | 85 | ``` 86 | MySQL [localhost+ ssl] SQL> \source world_x.sql 87 | ``` 88 | 89 | 如果该路径不在当前目录中,则将其添加到world_x.sql文件。 90 | 91 | world和world_x数据库非常简单,因此易于使用。 但是,有时您会需要sakila数据库可以提供的更复杂的功能。 92 | 93 | ## sakila数据库 94 | 95 | sakila数据库是一个现实的数据库,其中包含电影租赁业务的架构,其中包含有关电影,库存,商店,员工和客户的信息。 它添加了全文索引,空间索引,视图和存储的程序,以提供使用MySQL功能的更完整示例。 数据库大小仍然非常适中,使其适合小型实例。 96 | 97 | ### 模式 98 | 99 | sakila数据库包含16个表,七个视图,三个存储过程,三个存储函数和六个触发器。 这些表可以分为三组:客户数据,业务和库存。 为简便起见,图中未包含所有列,并且未显示大多数索引。 图4-4显示了表,视图和存储例程的完整概述。 100 | 101 | ![](../附图/Figure%204-4.jpg) 102 | 103 | 带有客户相关数据的表(加上工作人员和商店的地址)在左上角的区域中。 左下方的区域包含与业务相关的数据,右上方的区域包含有关胶片和库存的信息。 右下角用于视图和存储的例程(stored routines)。 104 | 105 | ------ 106 | 107 | **提示** 您可以通过打开MySQL Workbench中的安装随附的sakila.mwb文件来查看整个图(尽管格式不同)。 这也是一个很好的例子,说明了如何在MySQL Workbench中使用增强的实体关系(EER)图来记录架构。 108 | 109 | ------ 110 | 111 | 由于存在相对大量的对象,因此在讨论架构时,它们将分为五个组(每个表组,视图和存储的例程)。 第一组是与客户相关的数据,其表如图4-5所示。 112 | 113 | ![](../附图/Figure%204-5.png) 114 | 115 | 有四个表,其中包含与客户相关的数据。 客户表是主表,地址信息存储在address表,city表和country表中。 116 | 117 | 客户和业务组之间有外键,外键从customer表到业务组中的store表。 从业务组表到地址表和客户表,还有四个外键。 业务组如图4-6所示。 118 | 119 | ![](../附图/Figure%204-6.png) 120 | 121 | 业务表包含有关商店、员工、租金和付款的信息。商店和两个方向都有外键,员工属于一家商店,商店有一名经理,是员工的一部分。租金和付款由工作人员处理,因此与商店间接挂钩,付款用于租赁。 122 | 123 | 业务表包含有关商店,员工,租金和付款的信息。 store表和staff表在两个方向上都具有外键,其中职员属于商店,并且商店具有作为职员一部分的经理。 租金和付款由工作人员处理,因此间接链接到商店,付款是针对租金的。 124 | 125 | ![](../附图/Figure%204-7.png) 126 | 127 | 库存组中的主表是电影表,其中包含有关商店提供的电影的元数据。 此外,还有带有标题和描述以及带有全文索引的film_text表。 128 | 129 | 电影与类别表和演员表之间存在多对多关系。 最后,从库存表到业务组中的商店表有一个外键。 130 | 131 | 它涵盖了sakila数据库中的所有表,但也有一些视图,如图4-8所示。 132 | 133 | ![](../附图/Figure%204-8.png) 134 | 135 | 这些视图可以像报表一样使用,并且可以分为两类。 film_list,nice_but_slower_film_list和actor_info视图与存储在数据库中的电影有关。 第二类包含与sales_by_store,sales_by_film_category,staff_list和customer_list视图中的商店有关的信息。 136 | 137 | 为了完成数据库,还有存储的功能和过程,如图4-9所示。 138 | 139 | ![](../附图/Figure%204-9.png) 140 | 141 | film_in_stock( )和film_not_in_stock( )过程根据胶片是否有存货,返回一个结果集,该结果集包含给定电影和商店的库存ID。 找到的库存条目总数作为out参数返回。 rewards_report( )过程根据上个月的最低支出生成报告。 142 | 143 | get_customer_balance( )函数返回给定客户在给定数据上的余额。 剩下的两个函数使用库存清单状态来检查库存清单ID的状态,该方法返回当前正在租借该项目的客户的客户编码(如果没有客户在租用,则返回NULL),以及是否要检查给定的库存清单是否有库存 ,您可以使用ventory_in_stock( )函数。 144 | 145 | ### 安装 146 | 147 | 下载的文件扩展到包含三个文件的目录中,其中两个创建模式和数据,最后一个文件包含MySQL Workbench使用的格式的ETL图。 148 | 149 | ------ 150 | 151 | **注意** 本节和本书后面的示例使用从MySQL主页下载的sakila数据库的副本。 152 | 153 | ------ 154 | 155 | 文件是 156 | 157 | - **sakila-data.sql**:填充表和触发器定义所需的INSERT语句。 158 | - **sakila-schema.sql**:模式定义语句 159 | - **sakila.mwb**:MySQL Workbench ETL图。 这类似于图4-4所示的内容,图4-5至4-9对此进行了详细说明。 160 | 161 | 通过先采购sakila-schema.sql文件,然后再采购sakila-data.sql文件,来安装sakila数据库。 例如,以下使用MySQL Shell: 162 | 163 | ``` 164 | MySQL [localhost+ ssl] SQL> \source sakila-schema.sql 165 | MySQL [localhost+ ssl] SQL> \source sakila-data.sql 166 | ``` 167 | 168 | 如果文件不在当前目录中,则将其添加到文件中。 169 | 170 | 到目前为止,这三个数据集的共同点是它们包含的数据很少。 尽管在许多情况下这是一个不错的功能,因为它使使用起来更容易,但在某些情况下,您需要更多的数据来探索查询计划的差异。 employees数据库是具有更多数据的选项。 171 | 172 | ## employees数据库 173 | 174 | employees数据库(在MySQL文档下载页面上称为员工数据; GitHub存储库的名称为test_db)最初是由Fusheng Wang和Carlo Zaniolo创建的,并且是MySQL主页中链接的最大的测试数据集。 对于非分区版本,数据文件的总大小约为180 MiB,对于分区版本,数据文件的总大小约为440 MiB。 175 | 176 | ### 模式 177 | 178 | employees数据库由六个表和两个视图组成。 您可以选择另外安装两个视图,五个存储函数和两个存储过程。 这些表如图4-10所示。 179 | 180 | ![](../附图/Figure%204-10.jpg) 181 | 182 | 可以选择按from_date列的年份对薪金和职称表进行分区,如清单4-1所示。 183 | 184 | ``` 185 | Listing 4-1. The optional partitioning of the salaries and titles tables 186 | PARTITION BY RANGE COLUMNS(from_date) 187 | (PARTITION p01 VALUES LESS THAN ('1985-12-31') ENGINE = InnoDB, 188 | PARTITION p02 VALUES LESS THAN ('1986-12-31') ENGINE = InnoDB, 189 | PARTITION p03 VALUES LESS THAN ('1987-12-31') ENGINE = InnoDB, 190 | PARTITION p04 VALUES LESS THAN ('1988-12-31') ENGINE = InnoDB, 191 | PARTITION p05 VALUES LESS THAN ('1989-12-31') ENGINE = InnoDB, 192 | PARTITION p06 VALUES LESS THAN ('1990-12-31') ENGINE = InnoDB, 193 | PARTITION p07 VALUES LESS THAN ('1991-12-31') ENGINE = InnoDB, 194 | PARTITION p08 VALUES LESS THAN ('1992-12-31') ENGINE = InnoDB, 195 | PARTITION p09 VALUES LESS THAN ('1993-12-31') ENGINE = InnoDB, 196 | PARTITION p10 VALUES LESS THAN ('1994-12-31') ENGINE = InnoDB, 197 | PARTITION p11 VALUES LESS THAN ('1995-12-31') ENGINE = InnoDB, 198 | PARTITION p12 VALUES LESS THAN ('1996-12-31') ENGINE = InnoDB, 199 | PARTITION p13 VALUES LESS THAN ('1997-12-31') ENGINE = InnoDB, 200 | PARTITION p14 VALUES LESS THAN ('1998-12-31') ENGINE = InnoDB, 201 | PARTITION p15 VALUES LESS THAN ('1999-12-31') ENGINE = InnoDB, 202 | PARTITION p16 VALUES LESS THAN ('2000-12-31') ENGINE = InnoDB, 203 | PARTITION p17 VALUES LESS THAN ('2001-12-31') ENGINE = InnoDB, 204 | PARTITION p18 VALUES LESS THAN ('2002-12-31') ENGINE = InnoDB, 205 | PARTITION p19 VALUES LESS THAN (MAXVALUE) ENGINE = InnoDB) 206 | ``` 207 | 208 | 表4-1显示了employees数据库中表的行数和表空间文件的大小(请注意,加载数据时大小可能会有所不同)。 该大小假定您加载了未分区的数据。 分区表有些大。 209 | 210 | | 表名 | 行数 | 表空间大小 | 211 | | :----------- | ------: | ---------: | 212 | | departments | 9 | 128 kiB | 213 | | dept_emp | 331603 | 25600 kiB | 214 | | dept_manager | 24 | 128 kiB | 215 | | employees | 300024 | 22528 kiB | 216 | | salaries | 2844047 | 106496 kiB | 217 | | titles | 443308 | 27648 kiB | 218 | 219 | 按照今天的标准,它仍然是相对少量的数据,但是它足够大,您可以开始看到不同查询计划的一些性能差异。 220 | 221 | 图4-11总结了视图和例程。 222 | 223 | ![](../附图/Figure%204-11.jpg) 224 | 225 | dept_emp_latest_date和current_dept_emp视图与表一起安装,而其余对象则分别安装在objects.sql文件中。 存储的例程带有它们自己的内置帮助,您可以通过使用employee_usage( )函数或employees_help( )过程获得该帮助。 清单4-2中显示了后者。 226 | 227 | ``` 228 | mysql> CALL employees_help()\G 229 | *************************** 1. row *************************** 230 | info: 231 | == USAGE == 232 | ==================== 233 | PROCEDURE show_departments() 234 | shows the departments with the manager and 235 | number of employees per department 236 | FUNCTION current_manager (dept_id) 237 | Shows who is the manager of a given departmennt 238 | FUNCTION emp_name (emp_id) 239 | Shows name and surname of a given employee 240 | 241 | FUNCTION emp_dept_id (emp_id) 242 | Shows the current department of given employee 243 | 1 row in set (0.00 sec) 244 | Query OK, 0 rows affected (0.02 sec) 245 | ``` 246 | 247 | ### 安装 248 | 249 | 您可以下载包含安装所需文件的ZIP文件,也可以在https://github.com/datacharmer/test_db克隆GitHub存储库。 在撰写本文时,只有一个分支称为master。 如果您已经下载了ZIP文件,它将解压缩到名为test_db-master的目录中。 250 | 251 | 有几个文件。 与在MySQL 8中安装employee数据库有关的两个是employee.sql和employee_partitioned.sql。 区别在于薪金和职称表是否已分区。 (也有employees_ partitioned_5.1.sql,它用于MySQL 5.1,其中不支持employees_partitioned.sql中使用的分区方案。) 252 | 253 | 通过使用SOURCE命令获取.dump文件来加载数据。 在撰写本文时,MySQL Shell不支持SOURCE命令,因此您将需要使用旧版mysql命令行客户端来导入数据。 转到包含源文件的目录,然后根据是否要使用分区来选择employees.sql或employees_partitioned.sql文件,例如: 254 | 255 | ``` 256 | mysql> SOURCE employees.sql 257 | ``` 258 | 259 | 导入需要一点时间,并通过显示花费了多长时间来完成: 260 | 261 | ``` 262 | +---------------------+ 263 | | data_load_time_diff | 264 | +---------------------+ 265 | | 00:01:51 | 266 | +---------------------+ 267 | 1 row in set (0.44 sec) 268 | ``` 269 | 270 | (可选)您可以通过采购objects.sql文件来加载一些额外的视图和存储的例程: 271 | 272 | ``` 273 | mysql> SOURCE objects.sql 274 | ``` 275 | 276 | 除了此处讨论的数据集之外,还有其他一些选择来获取要使用的示例数据。 277 | 278 | ## 其他数据库 279 | 280 | 可能发生的情况是,您需要执行需要数据的测试,而这些数据的某些要求是到目前为止讨论的标准示例数据库无法满足的。 幸运的是,还有其他选择。 281 | 282 | ------ 283 | 284 | **提示** 不要低估创建自己的自定义示例数据库的可能性,例如,通过在生产数据上使用数据屏蔽。 285 | 286 | ------ 287 | 288 | 如果您要查找一个非常大的真实示例,则可以按照https://en.wikipedia.org/wiki/ Wikipedia:Database_download中的说明下载Wikipedia数据库。 自2019年9月20日起,英语Wikipedia转储为bzip2压缩XML格式的16.3 GiB。 289 | 290 | 如果要查找JSON数据,则可以选择以美国地质调查局(USGS)的地震信息提供,该信息以GeoJSON格式提供,并可以选择下载过去一小时,一天,一周或一个月的地震信息(可选) 受地震的影响。 格式说明和提要的链接可以在https://earthquake.usgs.gov/earthquakes/feed/v1.0/geojson.php中找到。 由于数据包含GeoJSON格式的地理信息,因此对于需要空间索引的测试很有用。 291 | 292 | 上一章中介绍的基准测试工具还包括测试数据或支持创建测试数据。 此数据也可能对您自己的测试有用。 293 | 294 | 如果您搜索Internet,则还有其他可用的示例数据库。 最后,需要考虑的重要事项是数据是否适合测试,以及是否使用了所需的功能。 295 | 296 | ## 总结 297 | 298 | 本章介绍了四个标准示例数据库和一些其他测试数据示例。 讨论的四个标准数据库是world,world_x,sakila和employee。 这些都可以通过MySQL手册(https://dev.mysql.com/doc/index-other.html)找到。 除employee外,除非另有说明,否则这些数据库均用于本书中的示例。 299 | 300 | world和world_x数据库是最简单的数据库,不同之处在于world_x使用JSON来存储一些信息,而world数据库是纯粹的关系数据库。 这些数据库包含的数据不多,但是由于它们的大小和简单性,它们对于简单的测试和示例很有用。 特别是本书中世界数据库被广泛使用。 301 | 302 | sakila数据库具有更为复杂的架构,其中包括不同的索引类型,视图和存储的例程。 这使其更现实,并允许进行更复杂的测试。 但是,数据的大小仍然足够小,甚至可以在小型MySQL实例上使用。 本书也广泛使用它。 303 | 304 | employee数据库的架构复杂度介于world数据库和sakila数据库之间,但是拥有大量数据,因此更适合测试各种查询计划之间的差异。 如果您需要在实例上产生一些负载,例如使用表扫描,它也很有用。 employee数据库在本书中并未直接使用,但是如果您要重现一些需要一定负载的示例,那么这是使用四个标准测试数据库中最好的一个。 305 | 306 | 您不应该局限于考虑标准测试数据库。 您可能可以创建自己的数据库,使用基准测试工具创建数据库,或者查找Internet上可用的数据。 维基百科的数据库和来自美国地质调查局(USGS)的地震数据就是可以下载的数据示例。 307 | 308 | 这样就完成了MySQL查询性能调优的介绍。 第二部分从Performance Schema开始,介绍了与诊断性能问题有关的常见信息源。 -------------------------------------------------------------------------------- /第2部分-信息来源/Chapter5.md: -------------------------------------------------------------------------------- 1 | # Performance Schema 2 | 3 | Performance Schema是与MySQL性能相关的诊断信息的主要来源。它最初是在MySQL 5.5版中引入的,然后在5.6版中对其当前结构进行了重大修改,此后在5.7和8中逐渐得到了改进。 4 | 5 | 本章介绍并概述了Performance Schema,因此,在本书剩余部分使用Performance Schema时,它的工作方式非常清晰。Performance Schema的近亲是下一章将讨论的 sys schema, Information Schema是第 7 章的主题。 6 | 7 | 本章讨论了Performance Schema特有的概念,特别关注 threads, instruments, consumers, events, digests和动态配置。 但是,首先,必须熟悉Performance Schema中使用的术语。 8 | 9 | ## 术语 10 | 11 | 在研究新学科时,可能很难的事情之一是术语,Performance Schema也不例外。由于术语之间几乎存在循环关系,因此没有明确的顺序来描述它们。相反,本节将简要概述本章中使用的最重要的术语,因此您可以了解这些术语的含义。在本章结束时,您应该更好地理解这些概念的含义以及它们之间的关系。 12 | 13 | 表5-1总结了Performance Schema中最重要的术语 14 | 15 | | 术语 | 描述信息 | 16 | | :-------------------- | ------------------------------------------------------------ | 17 | | Actor | 用户名和主机名(帐户)的组合。 | 18 | | Consumer | 收集仪器生成的数据的过程 | 19 | | Digest | 标准化查询的校验和。摘要用于汇总类似查询的统计信息。 | 20 | | Dynamic configuration | 可以在运行时配置Performance Schema,这称为动态配置。 这是通过设置表而不是通过更改系统变量来完成的。 | 21 | | Event | 一个事件是消费者从仪器中收集数据的结果。 因此,事件包含度量标准以及有关何时何地收集度量标准的信息。 | 22 | | Instrument | 代码指向进行测量的地方。 | 23 | | Object | 表,事件,函数,过程或触发器。 | 24 | | Setup table | Performance Schema有几个用于动态配置的表。 这些称为设置表,表名以setup_开头。 | 25 | | Summary table | 具有汇总数据的表。 表名包含单词summary,名称的其余部分指示数据的类型及其分组依据。 | 26 | | Thread | 线程对应于连接或后台线程。 Performance Schema线程和操作系统线程之间存在一一对应的关系。 | 27 | 28 | 在阅读本章时,如果遇到不确定其含义的术语,请参考该表。 29 | 30 | ## 线程 31 | 32 | 线程是 Performance Schema中的基本概念。当 MySQL 中执行任何操作时,无论是处理连接还是执行后台工作,工作都是由线程完成的。MySQL 在任何给定时间都有多个线程,因为它允许 MySQL 并行执行工作。对于一个连接,就有一个线程。 33 | 34 | ------ 35 | 36 | **注意**:对 InnoDB 中群集索引和分区执行并行读取的支持引入,使一个线程的一个连接的图片变得有些混乱。但是,由于执行并行扫描的线程被视为后台线程,因此对于本讨论,您可以考虑连接单线程。 37 | 38 | ------ 39 | 40 | 每个线程都有一个 ID,该 ID 是唯一标识线程的 ID,在Performance Schema表中存储此 ID 的列称为THREAD_ID。检查线程的主表是包含清单 5-1 的线程表,该表显示了 MySQL 8 中存在的线程类型的典型示例。线程数和确切的线程类型可用取决于在查询线程表时实例的配置和使用情况。 41 | 42 | ```sql 43 | Listing 5-1. Threads in MySQL 8 44 | mysql> SELECT THREAD_ID AS TID, 45 | SUBSTRING_INDEX(NAME, '/', -2) AS THREAD_NAME, 46 | IF(TYPE = 'BACKGROUND', '*', '') AS B, 47 | IFNULL(PROCESSLIST_ID, '') AS PID 48 | FROM performance_schema.threads; 49 | +-----+--------------------------------------+---+-----+ 50 | | TID | THREAD_NAME | B | PID | 51 | +-----+--------------------------------------+---+-----+ 52 | | 1 | sql/main | * | | 53 | | 2 | mysys/thread_timer_notifier | * | | 54 | | 4 | innodb/io_ibuf_thread | * | | 55 | | 5 | innodb/io_log_thread | * | | 56 | | 6 | innodb/io_read_thread | * | | 57 | | 7 | innodb/io_read_thread | * | | 58 | | 8 | innodb/io_read_thread | * | | 59 | | 9 | innodb/io_read_thread | * | | 60 | | 10 | innodb/io_write_thread | * | | 61 | | 11 | innodb/io_write_thread | * | | 62 | | 12 | innodb/io_write_thread | * | | 63 | | 13 | innodb/io_write_thread | * | | 64 | | 14 | innodb/page_flush_coordinator_thread | * | | 65 | | 15 | innodb/log_checkpointer_thread | * | | 66 | | 16 | innodb/log_closer_thread | * | | 67 | | 17 | innodb/log_flush_notifier_thread | * | | 68 | | 18 | innodb/log_flusher_thread | * | | 69 | | 19 | innodb/log_write_notifier_thread | * | | 70 | | 20 | innodb/log_writer_thread | * | | 71 | | 21 | innodb/srv_lock_timeout_thread | * | | 72 | | 22 | innodb/srv_error_monitor_thread | * | | 73 | | 23 | innodb/srv_monitor_thread | * | | 74 | | 24 | innodb/buf_resize_thread | * | | 75 | | 25 | innodb/srv_master_thread | * | | 76 | | 26 | innodb/dict_stats_thread | * | | 77 | | 27 | innodb/fts_optimize_thread | * | | 78 | | 28 | mysqlx/worker | | 9 | 79 | | 29 | mysqlx/acceptor_network | * | | 80 | | 30 | mysqlx/acceptor_network | * | | 81 | | 31 | mysqlx/worker | * | | 82 | | 34 | innodb/buf_dump_thread | * | | 83 | | 35 | innodb/clone_gtid_thread | * | | 84 | | 36 | innodb/srv_purge_thread | * | | 85 | | 37 | innodb/srv_purge_thread | * | | 86 | | 38 | innodb/srv_worker_thread | * | | 87 | | 39 | innodb/srv_worker_thread | * | | 88 | | 40 | innodb/srv_worker_thread | * | | 89 | | 41 | innodb/srv_worker_thread | * | | 90 | | 42 | innodb/srv_worker_thread | * | | 91 | | 43 | innodb/srv_worker_thread | * | | 92 | | 44 | sql/event_scheduler | | 4 | 93 | | 45 | sql/compress_gtid_table | | 6 | 94 | | 46 | sql/con_sockets | * | | 95 | | 47 | sql/one_connection | | 7 | 96 | | 48 | mysqlx/acceptor_network | * | | 97 | | 49 | innodb/parallel_read_thread | * | | 98 | | 50 | innodb/parallel_read_thread | * | | 99 | | 51 | innodb/parallel_read_thread | * | | 100 | | 52 | innodb/parallel_read_thread | * | | 101 | +-----+--------------------------------------+---+-----+ 102 | 49 rows in set (0.0615 sec) 103 | ``` 104 | 105 | TID 列是每个线程的 THREAD_ID,THREAD_NAME 列包括线程名称的最后两个组件(第一个组件是所有线程的线程),B 列具有后台线程的星号,PID 列具有前台线程的进程列表 ID。 106 | 107 | ------ 108 | 109 | **注意** 遗憾的是,术语“线程”在MySQL中超载,在某些地方用作连接的同义词。在本书中,连接是指用户连接,线程引用Performance Schema线程,即它可以是背景或前景(包括连接)线程。例外是讨论一个明显违反该约定的表时。 110 | 111 | ------ 112 | 113 | 线程列表显示了线程的几个重要概念。进程列表 ID 和线程 ID 不相关。事实上,线程 ID = 28 的线程具有比线程 ID 44 (4) 的线程更高的进程列表 ID (9)。因此,它甚至不保证顺序是相同的(虽然对于非 mysqlx 线程,它一般情况下)。 114 | 115 | 对于 mysqlx/工作线程,一个是前景线程,另一个是背景线程。这反映了 MySQL 如何使用 X 协议处理连接,这与处理经典连接的方式大不相同。 116 | 117 | 也有"混合"线程不是完全的背景,也不是完全的前景线程。例如,sql/compress_gtid_table压缩表的mysql.gtid_executed线程。它是一个前景线程,但如果执行 SHOWPROCESSLIST,则它将被不包括。 118 | 119 | ------ 120 | 121 | **提示** performance_schema.threads 表非常有用,还包括 SHOW 流程列表显示的所有信息。由于与执行 SHOW 进程列表或查询查询表相比,查询此表的开销theinformation_schema。ProcessLIST 表,使用线程表以及 sys.processlist 和 sys.session 视图是获取连接列表的推荐方法。 122 | 123 | ------ 124 | 125 | 有时获得连接的线程ID可能很有用。 为此,有两个功能: 126 | 127 | - **PS_THREAD_ID()**: 获取作为参数提供的连接ID的性能架构线程ID。 128 | - **PS_CURRENT_THREAD_ID()**: 获取当前连接的性能架构线程ID。 129 | 130 | 在MySQL 8.0.15和更早版本中,请改用sys.ps_thread_id()并提供NULL参数以获取当前连接的线程ID。 使用功能的一个例子是 131 | 132 | ``` 133 | mysql> SELECT CONNECTION_ID(), 134 | PS_THREAD_ID(13), 135 | PS_CURRENT_THREAD_ID()\G 136 | *************************** 1. row *************************** 137 | CONNECTION_ID(): 13 138 | PS_THREAD_ID(13): 54 139 | PS_CURRENT_THREAD_ID(): 54 140 | 1 row in set (0.0003 sec) 141 | ``` 142 | 143 | 使用这些函数等效于查询 PROCESSLIST_ID.THREAD_IDcolumns表中的performance_schema和查询,以将连接 ID 与线程 ID 链接。清单 5-2 显示了使用 PS_CURRENT_THREAD_ID( )函数来查询当前连接的线程表的示例。 144 | 145 | ``` 146 | Listing 5-2. Querying the threads table for the current connection 147 | mysql> SELECT * 148 | FROM performance_schema.threads 149 | WHERE THREAD_ID = PS_CURRENT_THREAD_ID()\G 150 | *************************** 1. row *************************** 151 | THREAD_ID: 54 152 | NAME: thread/mysqlx/worker 153 | TYPE: FOREGROUND 154 | PROCESSLIST_ID: 13 155 | PROCESSLIST_USER: root 156 | PROCESSLIST_HOST: localhost 157 | PROCESSLIST_DB: performance_schema 158 | PROCESSLIST_COMMAND: Query 159 | PROCESSLIST_TIME: 0 160 | PROCESSLIST_STATE: statistics 161 | PROCESSLIST_INFO: SELECT * 162 | FROM threads 163 | WHERE THREAD_ID = PS_CURRENT_THREAD_ID() 164 | PARENT_THREAD_ID: 1 165 | ROLE: NULL 166 | INSTRUMENTED: YES 167 | HISTORY: YES 168 | CONNECTION_TYPE: SSL/TLS 169 | THREAD_OS_ID: 31516 170 | RESOURCE_GROUP: SYS_default 171 | 1 row in set (0.0005 sec) 172 | ``` 173 | 174 | 有几个列在性能调优的上下文中提供有用的信息,将在后几章中使用。值得注意的是,这里是他们的名字以PROCESSLIST_。这些等效于 SHOW ProcessLIST 返回的信息,但查询线程表对连接的影响较小。"仪器"和"历史记录"列指定是否为线程收集检测数据,以及是否为线程保留事件历史记录。您可以更新这两列以更改线程的行为,也可以根据 setup_threadstable 中的线程类型或使用 setup_actors 表定义线程的默认行为。这就引出了一个问题,什么是工具和事件。接下来的三节将讨论这一点,以及如何消耗这些仪器。 175 | 176 | ## 仪器 177 | 178 | 仪器是测量的代码点。有两种类型的仪器:可以定时的工具和不能定时的工具。时位仪器包括事件和空闲仪器(测量螺纹空闲时),而不时分仪器则计算错误和内存使用情况。 179 | 180 | 仪器按其名称分组,这些名称形成层次结构,组件以 / 分隔。对于名称有多少个组件没有规则,有些组件只有一个组件,而其他组件最多有五个组件。 181 | 182 | 仪器名称的示例是语句/sql/select,它表示直接执行的 aSELECT 语句(即,不是从存储过程中执行)。另一个仪器是语句/sp/stmt,它是在存储过程中执行的语句。 183 | 184 | 随着新功能的添加,仪器的数量不断增加,并且更多的仪器点入到现有代码中。在 MySQL 8.0.18 中,当没有安装额外的插件或组件时,有 1229 个仪器(仪器的确切数量也取决于平台)。这些仪器在表5-2中列出的顶级组件之间拆分。"定时"列显示仪器是否可以定时,Count 列显示该顶级组件的仪器总数,以及默认情况下在 8.0.18 中启用的仪器数量。 185 | 186 | 补充表5-2 187 | 188 | | Component | Timed | Count | Description | 189 | | ----------- | ----- | ----- | ----------- | 190 | | error | No | | | 191 | | idle | Yes | | | 192 | | memory | No | | | 193 | | stage | Yes | | | 194 | | statement | Yes | | | 195 | | transaction | Yes | | | 196 | | wait | Yes | | | 197 | 198 | 命名方案使得确定仪器测量方法相对容易。您可以在"计算机"表中找到所有setup_instruments,这些仪器还允许您配置仪器是否启用和时间。对于一些仪器,还有一个简短的文档,说明仪器收集的数据。 199 | 200 | 如果要在 MySQL 启动时启用或禁用仪器,可以使用性能架构仪器选项。它的工作方式与大多数选项不同,因为您可以多次指定它来更改多个工具的设置,并且您可以使用 % 通配符来匹配模式。如何使用该选项的示例包括 201 | 202 | ``` 203 | [mysqld] 204 | performance-schema-instrument = "stage/sql/altering table=ON" 205 | performance-schema-instrument = "memory/%=COUNTED" 206 | ``` 207 | 208 | 第一个选项允许对舞台/sql/更改表图进行计数和计时,而第二个选项允许计数所有内存仪器(这也是默认值)。 209 | 210 | 谨慎 启用所有工具(以及接下来讨论的消费者)可能看起来很诱人。但是,检测和消耗的量越大,开销越大。启用所有内容都可能导致中断(本书的作者已经看到这种情况发生)。特别是,等待/同步/% 的仪器andevents_waits_%的使用者增加了开销。根据经验,监视的粒度越细,它增加的开销也越高。在大多数情况下,MySQL 8 中的默认设置在可观察性和开销之间提供了很好的折衷。 211 | 212 | 必须使用仪器生成的数据,才能在性能架构表中使用数据。这是由消费者完成的。 213 | 214 | ## 消费者 215 | 216 | 消费者是处理仪器生成的数据并在性能架构表中提供的数据。消费者在一个thesetup_consumers中定义,除了消费者名称之外,该表还具有一列来指定是否启用了消费者。 217 | 218 | 消费者形成层次结构,如图 5-1 所示。该图分为两部分,高级使用者位于虚线上方,事件使用者位于虚线以下。默认情况下启用绿色(浅色)使用者,默认情况下禁用红色(深色)。 219 | 220 | ![](../附图/Figure%205-1.png) 221 | 222 | 使用者形成层次结构意味着,只有在启用了层次结构中本身和层次结构中较高位置的所有使用者时,使用者才使用事件。因此,禁用global_instrumentation使用者会有效地禁用所有使用者。 223 | 224 | 可以使用 sys 架构函数 ps_is_consumer_enabled() 来确定是否启用了消费者及其依赖的使用者,例如: 225 | 226 | ``` 227 | mysql> SELECT sys.ps_is_consumer_enabled( 228 | 'events_statements_history' 229 | ) AS IsEnabled; 230 | +-----------+ 231 | | IsEnabled | 232 | +-----------+ 233 | | YES | 234 | +-----------+ 235 | 1 row in set (0.0005 sec) 236 | ``` 237 | 238 | 消费者statements_digest是负责收集按语句摘要分组的数据的人,例如,这些数据通过报表表events_statements_summary_by_digest提供。对于查询性能调优,这可能是最重要的使用者。这仅取决于全球消费者。使用者thread_instrumentation确定线程是否正在收集特定于线程的仪器数据。它还控制任何事件使用者是否收集数据。 239 | 240 | 对于使用者,每个使用者有一个配置选项,选项名由性能架构使用者前缀组成,后跟使用者名,例如: 241 | 242 | ``` 243 | [mysqld] 244 | performance-schema-consumer-events-statements-history-long = ON 245 | ``` 246 | 247 | 这将启用events_statements_history_long使用者 248 | 249 | 您很少需要考虑禁用三个高级使用者中的任何一个。事件使用者更经常被具体配置,并将与事件概念讨论。 250 | 251 | ## Events 252 | 253 | 事件是使用者记录仪器收集的数据的结果,也是可用于观察 MySQL 中所发生内容的结果。有几种事件类型,并且事件是链接的,因此通常事件同时具有父级事件和一个或多个子事件。本节介绍事件的工作方式。 254 | 255 | ### 事件类型 256 | 257 | 有四种事件类型,涵盖从事务到等待的各种详细级别。事件类型还对类似类型的事件进行组,为事件收集的信息取决于其类型。例如,表示语句执行的事件包括查询和检查的行数,而事务事件具有请求的事务隔离级别等信息。图 5-2 显示了事件类型。 258 | 259 | ![](../附图/Figure%205-2.png) 260 | 261 | 事件对应于不同级别的详细信息,事务级别最高(最低详细信息),等待事件级别最低(最高详细信息): 262 | 263 | - 事务:事件描述事务并包括尾部,如请求的事务隔离级别(但不必要地使用)、事务状态等。默认情况下,收集每个线程的当前和最后 10 个事务 264 | - 语句:这是最常用的事件类型,用于执行的查询。它还包括有关在存储过程中执行的语句的信息。这包括检查的行数、返回的行数、是否使用索引和执行时间等信息。默认情况下,将收集每个线程的当前和最后 10 个语句。 265 | - 阶段:这大致对应于 SHOWPROCESSLIST 报告状态。默认情况下未启用这些功能(InnoDB 进步信息部分为异常)。 266 | - 等待:这些是低级事件,包括 I/O 和等待静音。这些都是非常具体和非常有用的低级性能调优,但他们也是最昂贵的。默认情况下,未启用任何等待事件使用者。 267 | 268 | 还有一个问题,就是要保留记录的事件多长时间。 269 | 270 | ## 事件范围 271 | 272 | 对于每种事件类型,有三个使用者指定所用事件的生存期。作用域为 273 | 274 | - 当前:当前正在执行的事件和空闲线程的最后一个完成的事件。在某些情况下,可能同时发生多个同一级别的事件。例如,当一个存储过程在过程本身和当前在过程中执行的语句时执行。 275 | - 历史记录:每个线程的最后十个(默认情况下)事件。当线程关闭时,将丢弃事件。 276 | - history_long:最后 10,000 个事件(默认情况下),与生成事件的线程无关。即使在线程关闭后,事件也保留。 277 | 278 | 事件类型和范围组合在一起,形成 12 个事件使用者。有一个与每个事件使用者对应的"性能架构"表,表名与使用者名称相同,如清单 5-3 所示。 279 | 280 | ``` 281 | Listing 5-3. The correspondence between consumer and table names 282 | mysql> SELECT TABLE_NAME 283 | FROM performance_schema.setup_consumers c 284 | INNER JOIN information_schema.TABLES t 285 | ON t.TABLE_NAME = c.NAME 286 | WHERE t.TABLE_SCHEMA = 'performance_schema' 287 | AND c.NAME LIKE 'events%' 288 | ORDER BY c.NAME; 289 | +----------------------------------+ 290 | | TABLE_NAME | 291 | +----------------------------------+ 292 | | events_stages_current | 293 | | events_stages_history | 294 | | events_stages_history_long | 295 | | events_statements_current | 296 | | events_statements_history | 297 | | events_statements_history_long | 298 | | events_transactions_current | 299 | | events_transactions_history | 300 | | events_transactions_history_long | 301 | | events_waits_current | 302 | | events_waits_history | 303 | | events_waits_history_long | 304 | +----------------------------------+ 305 | 12 rows in set (0.0323 sec) 306 | ``` 307 | 308 | 如图 5-2 暗示了事件类型之间的箭头,类型之间存在超出它们表示的详细信息级别的关系。这种关系不是阿赫拉奇,而是由事件嵌套组成。 309 | 310 | ### 事件嵌套 311 | 312 | 通常,事件由其他事件生成,因此事件形成一个树,每个事件都有一个父事件,并且可能有许多子事件。虽然事件类型似乎形成层次结构,例如,事务是声明的元级,但关系比这更复杂,而且是双向的。以开始事务的START TRANSACTION 语句来说,该语句将成为事务的父级,而该语句又成为其他语句的父级。另一个例如调用调用存储过程的 CALL 语句,该语句将成为过程中执行的语句的父级。 313 | 314 | 嵌套可能会变得相当复杂。图 5-3 显示了包括所有四种事件类型在内的事件链的示例。 315 | 316 | ![](../附图/Figure%205-3.png) 317 | 318 | 对于语句事件,将显示实际查询,而对于其他事件类型,将显示事件名称或事件名称的一部分。该链从启动事务的 STARTTRANSACTION 语句开始。在事务中,调用 myproc() 过程,该过程使它成为 SELECT 语句的父级,该语句将执行多个阶段,包括阶段/sql/统计,而阶段又包括请求 InnoDB 中的 trx_mutex。 319 | 320 | 事件表有两列来跟踪事件之间的关系: 321 | 322 | - **NESTING_EVENT_ID**:父事件ID 323 | - **NESTING_EVENT_TYPE**:父事件的事件类型(TRANSACTION,STATEMENT,STAGE或WAIT) 324 | 325 | 语句事件表还有一些与嵌套语句事件相关的列: 326 | 327 | - **OBJECT_TYPE**:父语句事件的对象类型。 328 | - **OBJECT_SCHEMA**:父语句对象存储在的架构。 329 | - **OBJECT_NAME**:父语句对象的名称。 330 | - **NESTING_EVENT_LEVEL**:语句嵌套有多深。最顶层的语句具有级别 0,并且每次创建子级别时,NESTING_EVENT_LEVEL一个级别。 331 | 332 | sys.ps_trace_thread() 过程是一个极好的示例,说明如何自动生成事件的树。第 20 章中ps_trace_thread() 示例。 333 | 334 | ### 事件属性 335 | 336 | 所有事件之间共享的事件有一些属性,而不考虑它们的类型。这些属性包括主键、事件 ID 以及事件的计时工作。 337 | 338 | 事件的当前和历史(但不是长历史)表的主要键与THREAD_IDEVENT_ID。当EVENT_ID创建更多事件时,列将递增,因此,如果要按顺序排列事件,则必须按EVENT_ID。每个线程都有自己的事件 ID 序列。每个事件表中有两个事件 idcolum: 339 | 340 | - **EVENT_ID**:这是事件的主要事件 ID,并在事件开始时设置。 341 | - **END_EVENT_ID**:此 ID 在事件结束时设置。这意味着您可以通过检查该列是否为 NULL 来确定END_EVENT_ID是否正在进行中。 342 | 343 | 此外,EVENT_NAME列具有负责事件的仪器的名称,语句、阶段和等待的源列具有触发仪器的源代码中的文件名和行号。 344 | 345 | 有三列与记录事件的开始、结束和迁移的事件的时间有关: 346 | 347 | - **TIMER_START**:当 MySQL 启动时,内部计时器计数器设置为 0,并每秒递增一次。事件开始时,计数器的值将被取并分配给TIMER_START。 348 | 349 | 但是,由于单位为 pico 秒,计数器可能会达到支持的值最大(大约 30.5 周后发生),在这种情况下,计数器将再次从 0 开始。 350 | 351 | - **TIMER_END**:对于当前事件,这是当前时间,对于已完成的事件,它是事件完成的时间。 352 | 353 | - **TIMER_WAIT**:这是事件的持续时间。对于仍在进行中的事件,它是自事件开始以来的时间量。 354 | 355 | 一个例外是不包含时间安排的交易。 356 | 357 | ------ 358 | 359 | **注意** 不同的事件类型使用不同的计时器,因此不能使用TIMER_STARTTIMER_END列来订购不同类型的事件。 360 | 361 | ------ 362 | 363 | 计时以皮秒(10^-12 秒)为单位完成。该单元的选择是性能原因,因为它允许 MySQL 在尽可能多的情况下使用乘法(最便宜的数学运算和加法)。计时列是 64 位无符号整数,这意味着它们将在大约 30.5 周后溢出,此时值将再次从 0 开始。 364 | 365 | 虽然从计算角度使用皮秒是件好事,但对人类来说,它不太实用。因此,存在函数FORMAT_PICO_TIME() 将秒转换为人类可读格式,例如: 366 | 367 | ``` 368 | SELECT FORMAT_PICO_TIME(111577500000); 369 | +--------------------------------+ 370 | | FORMAT_PICO_TIME(111577500000) | 371 | +--------------------------------+ 372 | | 111.58 ms | 373 | +--------------------------------+ 374 | 1 row in set (0.0004 sec) 375 | ``` 376 | 377 | 该函数已添加到 MySQL 8.0.16 中。在较早的版本中,您需要使用thesys.format_time( ) 函数。 378 | 379 | ## 演员和对象 380 | 381 | 性能架构允许您配置默认情况下应检测的用户帐户和架构对象。这些帐户通过表thesetup_actors通过表配置,对象通过setup_objects配置。默认情况下,将检测除 mysql、information_schema、andperformance_schema中的对象之外的所有帐户和所有架构对象。 382 | 383 | ## Digests 384 | 385 | 性能架构为基于语句摘要执行的语句生成统计信息。这是基于规范化查询的 SHA-256 哈希。具有相同摘要的语句被视为相同的查询。 386 | 387 | 规范化包括删除注释(但不是优化器提示)、将空格替换为单空格字符、将 WHERE 子句中的值替换为问号等。可以使用函数 STATEMENT_DIGEST_TEXT( ) 来访问规范化查询,例如: 388 | 389 | ``` 390 | mysql> SELECT STATEMENT_DIGEST_TEXT( 391 | 'SELECT * 392 | FROM city 393 | WHERE ID = 130' 394 | ) AS DigestText\G 395 | *************************** 1. row *************************** 396 | DigestText: SELECT * FROM `city` WHERE `ID` = ? 397 | 1 row in set (0.0004 sec) 398 | ``` 399 | 400 | 同样,您可以使用STATEMENT_DIGEST( ) 函数来获取查询的SHA-256哈希值: 401 | 402 | ``` 403 | mysql> SELECT STATEMENT_DIGEST( 404 | 'SELECT * 405 | FROM city 406 | WHERE ID = 130' 407 | ) AS Digest\G 408 | 409 | *************************** 1. row *************************** 410 | Digest: 26b06a0b2f651e04e61751c55f84d0d721d31041ea57cef5998bc475ab9ef773 411 | 1 row in set (0.0004 sec) 412 | ``` 413 | 414 | 例如,STATEMENT_DIGEST 如果要查询语句事件表(events_statements_histogram_by_digest 表或 events_statements_summary_by_digest 表)的一个events_statements_summary_by_digest,则函数非常有用,以查找有关具有相同摘要的查询的信息。 415 | 416 | ------ 417 | 418 | **注意**:在升级 MySQL 时,不能保证给定查询的摘要保持不变。这意味着您不应比较不同 MySQL 版本摘要。 419 | 420 | ------ 421 | 422 | 当 MySQL 计算摘要时,查询是令牌化的,为了避免过度使用内存,此进程允许的每个连接的内存量是上限的。这意味着,如果您有大型查询(在查询文本方面),规范化查询(称为摘要文本)将被截断。您可以使用 max_digest_length 变量(默认值为 1024,需要重新启动 MySQL)配置在规范化期间允许连接用于令牌的内存。如果您有大型查询,则可能需要增加此避免查询之间的冲突,这些冲突时间超过max_digest_length字节。如果增加max_digest_length您可能还希望增加"performance_schema_max_digest_length选项,该选项指定存储在性能架构中的摘要文本的最大长度。但是,请注意,因为它会增加性能信息中存储的所有摘要文本值的大小,并且由于性能架构表存储在内存中,因此会导致内存使用量显著增加。作者看到几个支持票证,其中MySQL未能启动,因为摘要长度设置太高,所以MySQL用完了内存。 423 | 424 | 注意 不要盲目增加摘要长度选项,因为您可能会耗尽内存。 425 | 426 | ## Table Types 427 | 428 | 您已经遇到性能架构中提供一些表。表 5-3 总结了截至 MySQL 8.0.18 的可用表类型。 429 | 430 | 最常用的表是摘要表,因为它们提供了对数据的轻松访问,这些数据本身可以用作报告,类似于在sys模式视图的下一章中将看到的内容。 431 | 432 | ## Dynamic Configuration 433 | 434 | 除了可以使用SETPERSIST_ONLY或在配置文件中设置的传统MySQL配置选项外,性能模式还通过设置表提供了自己独特的动态配置。 本节说明动态配置的工作方式。 435 | 436 | 表5-4列出了MySQL 8中可用的设置表。对于允许插入和删除的表,可以更改所有列,但是仅将非关键列列出为可忘记列。 437 | 438 | 对于带有“历史记录”列的表,只有在还启用了仪器的情况下才能记录历史记录。 以与TIMED列相同的方式,仅在启用仪器或对象时才相关。 对于setup_instruments,请注意,并非所有仪器都支持计时,在这种情况下,TIMED列始终为NULL。 439 | 440 | setup_actors和setup_objects表在设置表中是特殊的,因为您可以为其插入和删除行。 这包括使用TRUNCATE TABLE语句删除所有行。 由于表存储在内存中,因此您不能随意插入任意多的行。 相反,最大行数由performance_schema_setup_actors_size和performance_schema_setup_objects_size配置选项定义。 这两个选项默认情况下都是自动调整大小的。 它需要重新启动MySQL才能更改表大小才能生效。 441 | 442 | 您使用常规的UPDATE语句来操纵配置。 对于setup_actors和setup_objects表,还可以使用INSERT,DELETE和TRUNCATETABLE。 启用events_statements_history_long使用者的示例是 443 | 444 | ``` 445 | mysql> UPDATE performance_schema.setup_consumers 446 | SET ENABLED = 'YES' 447 | WHERE NAME = 'events_statements_history_long'; 448 | Query OK, 1 row affected (0.2674 sec) 449 | 450 | Rows matched: 1 Changed: 1 Warnings: 0 451 | ``` 452 | 453 | 重新启动MySQL时,此配置不是永久性的,因此,如果在没有配置选项的情况下要更改这些表的配置,请将所需的SQL语句添加到初始化文件中,并通过init_file选项执行它。 454 | 455 | 以上是对性能模式的介绍,但是在本书的其余部分中,您将看到许多使用表的示例。 456 | 457 | ## 总结 458 | 459 | 本章介绍了性能模式的最重要概念。 MySQL是一个多线程进程,性能模式包含有关所有线程的信息,包括前台线程(连接)和后台线程。 460 | 461 | 这些工具与源代码中的已检测代码点相对应,从而确定要收集哪些数据。启用仪器后,除存储器和错误仪器外,还可以选择对其计时。 462 | 463 | 使用者使用仪器收集的数据并对其进行处理,并通过Performance Schema表使其可用。十二个使用者表示四种事件类型,每种类型具有三个范围。 464 | 465 | 四种事件类型是事务,语句,阶段和等待,它们涵盖了不同的详细程度。这三个事件作用域是当前或最后完成的事件的当前作用域,每个仍然存在的线程的十个最后事件的历史记录以及最后10,000个事件,而与生成它们的线程无关。事件可以触发其他事件,因此它们形成一棵树。 466 | 467 | 一个重要的概念也是摘要,它允许MySQL通过归一化的查询聚合数据分组。当您要寻找查询调整的候选者时,此功能将特别有用。 468 | 469 | 最后,总结了性能模式中的各种类型的表。最常用的表组是摘要表,它们本质上是报告,可以轻松地\从“性能模式”中访问汇总数据。基于性能模式(在某些情况下是汇总表)的报告的另一个示例是sys模式中可用的信息,这是下一章的主题。 470 | -------------------------------------------------------------------------------- /第2部分-信息来源/Chapter6.md: -------------------------------------------------------------------------------- 1 | # sys schema 2 | 3 | sys schema是马克·莱思的创意,他长期以来一直是开发 MySQL 企业监视器的团队的一员。他开始了ps_helper项目,以监控理念进行实验,并展示sys schema可以做什么,同时使sys schema更简单。该项目后来重命名为 thesys 架构并移动到 MySQL 中。此后,包括这本书的作者在内的其他几个人也做出了贡献。 4 | 5 | sys schema适用于 MySQL Server 5.6 及更晚版本。在 MySQL 5.7 中,它成为标准安装的一部分,因此您无需执行任何操作来安装系统或升级系统。截至 MySQL 8.0.18,系统架构源代码是 MySQL 服务器源的一部分。 6 | 7 | 系统架构在整本书中用于分析查询、锁等。本章将介绍 sys 架构的高级别概述,包括如何配置它、格式化函数、视图如何工作以及各种帮助程序例程。 8 | 9 | ------ 10 | 11 | **提示** sys 架构源代码 (https://github.com/mysql/mysqlserver/tree/8.0/scripts/sys_schema 和较旧的 MySQL versionshttps://github.com/mysql/mysql-sys/) 也是了解如何根据性能架构编写查询的有用资源。 12 | 13 | ------ 14 | 15 | ## sys Schema配置 16 | 17 | sys 架构使用自己的配置系统,因为它最初是独立于 MySQL 服务器实现的。有两种方法可以更改配置,取决于是永久更改设置还是只更改会话设置。 18 | 19 | 持久保留的配置存储在sys_config表中,其中包括变量名、其值以及上次设置值和由哪个用户使用。清单 6-1 显示了默认内容(set_time取决于上次安装或升级系统学。 20 | 21 | ``` 22 | Listing 6-1. The sys schema persisted configuration 23 | mysql> SELECT * FROM sys.sys_config\G 24 | *************************** 1. row *************************** 25 | variable: diagnostics.allow_i_s_tables 26 | value: OFF 27 | set_time: 2019-07-13 19:19:29 28 | set_by: NULL 29 | *************************** 2. row *************************** 30 | variable: diagnostics.include_raw 31 | value: OFF 32 | set_time: 2019-07-13 19:19:29 33 | set_by: NULL 34 | *************************** 3. row *************************** 35 | variable: ps_thread_trx_info.max_length 36 | value: 65535 37 | set_time: 2019-07-13 19:19:29 38 | set_by: NULL 39 | *************************** 4. row *************************** 40 | variable: statement_performance_analyzer.limit 41 | value: 100 42 | set_time: 2019-07-13 19:19:29 43 | set_by: NULL 44 | *************************** 5. row *************************** 45 | variable: statement_performance_analyzer.view 46 | value: NULL 47 | set_time: 2019-07-13 19:19:29 48 | set_by: NULL 49 | *************************** 6. row *************************** 50 | variable: statement_truncate_len 51 | value: 64 52 | set_time: 2019-07-13 19:19:29 53 | set_by: NULL 54 | 6 rows in set (0.0005 sec) 55 | ``` 56 | 57 | 目前,set_by始终为 NULL,除非 @sys.ignore_sys_config_触发器用户变量设置为计算为 FALSE 但不是 NULL 的值。 58 | 59 | 您最有可能更改的选项是 statement_truncate_len 它指定 sys 架构用于格式化视图中语句的最大长度(稍后将详细说明这些)。选择默认值 64 可增加查询视图适合控制台宽度的概率;但是,有时获取有关该语句的有用信息太少。 60 | 61 | 您可以通过更新配置设置来更新sys_config。这将保留更改并立即应用于所有连接,除非它们已设置自己的会话值(当使用设置语句的 sysschema 中的东西时,将隐式地发生)。由于sys_config是一个正常的 InnoDB 表,因此在重新启动 MySQL 后,更改也将保留。 62 | 63 | 或者,您可以只更改会话的设置。这是通过使用配置变量的名称和预用系统完成的。并把它变成一个用户可变。清单 6-2 显示了使用 sys_config 表和用户变量来更改statement_truncate_len。结果使用 format_statement( )函数进行测试,该函数是 sys 架构用于截断声明的函数。 64 | 65 | ``` 66 | Listing 6-2. Changing the sys schema configuration 67 | mysql> SET @query = 'SELECT * FROM world.city INNER JOIN world.city ON 68 | country.Code = city.CountryCode'; 69 | Query OK, 0 rows affected (0.0003 sec) 70 | mysql> SELECT sys.sys_get_config( 71 | 'statement_truncate_len', 72 | NULL 73 | ) AS TruncateLen\G 74 | 75 | *************************** 1. row *************************** 76 | TruncateLen: 64 77 | 1 row in set (0.0007 sec) 78 | mysql> SELECT sys.format_statement(@query) AS Statement\G 79 | *************************** 1. row *************************** 80 | Statement: SELECT * FROM world.city INNER ... ountry.Code = city.CountryCode 81 | 1 row in set (0.0019 sec) 82 | mysql> UPDATE sys.sys_config SET value = 48 WHERE variable = 'statement_ 83 | truncate_len'; 84 | Query OK, 1 row affected (0.4966 sec) 85 | mysql> SET @sys.statement_truncate_len = NULL; 86 | Query OK, 0 rows affected (0.0004 sec) 87 | mysql> SELECT sys.format_statement(@query) AS Statement\G 88 | *************************** 1. row *************************** 89 | Statement: SELECT * FROM world.ci ... ode = city.CountryCode 90 | 1 row in set (0.0009 sec) 91 | mysql> SET @sys.statement_truncate_len = 96; 92 | Query OK, 0 rows affected (0.0003 sec) 93 | mysql> SELECT sys.format_statement(@query) AS Statement\G 94 | *************************** 1. row *************************** 95 | Statement: SELECT * FROM world.city INNER JOIN world.city ON country.Code = 96 | city.CountryCode 97 | 1 row in set (0.0266 sec) 98 | ``` 99 | 100 | 首先,在用户变量的@query查询。这纯粹是为了方便起见,所以很容易继续引用相同的查询。sys_get_configt( ) 函数用于获取当前配置值statement_truncate_len选项。这会说明是否设置了@sys.语句_trauncate_len 用户变量。如果提供的选项不存在,则第二个保证提供要返回的值。 101 | 102 | format_statementt( ) 函数用于演示 @query 中的语句格式,首先默认值为 statement_truncate_len 的默认值 64,然后 updatingsys_config 的值为 48,最后将会话的值设置为 96。 请注意,在更新 sys_config 表后,@sys.语句_truncate_len 用户变量如何设置为 NULL,以使 MySQL 应用更新到会话的设置。 103 | 104 | 注意 默认情况下,某些 sysschema 功能支持一些配置选项,这些sys_config在 sys_config 表中,例如调试选项。sys 架构对象(https://dev.mysql.com/doc/refman/en/sys-schema-reference.html)的文档包括支持哪些配置选项的信息。 105 | 106 | format_statement( ) 函数并不是 sysschema 中的唯一格式函数,因此让我们来看看所有这些格式。 107 | 108 | ## Formatting Functions 109 | 110 | sys 架构包含四个函数,可帮助您格式化与性能架构不同的查询输出,使结果更易于阅读或占用更少的空间。由于添加了本机性能学函数以替换它们,因此在 MySQL 8.0.16 中已弃用其中两个函数。 111 | 112 | 表6-1总结了这四个函数以及在format_time( )和format_bytes( )情况下将替换它们的新本机函数。 113 | 114 | | sys Schema Function | Native Function | 描述信息 | 115 | | -------------------- | ------------------- | -------------------------------------------- | 116 | | format_bytes( ) | FORMAT_BYTES( ) | | 117 | | format_path( ) | | | 118 | | format_ statement( ) | | | 119 | | format_time( ) | FORMAT_PICO_TIME( ) | 将以皮秒为单位的时间转换为人类可读的字符串。 | 120 | 121 | 清单 6-3 显示了使用格式化函数的示例,对于 format_bytes( )和 format_time( ),结果将比较本地性能学函数。 122 | 123 | ``` 124 | Listing 6-3. Using the formatting functions 125 | mysql> SELECT sys.format_bytes(5000) AS SysBytes, 126 | FORMAT_BYTES(5000) AS P_SBytes\G 127 | *************************** 1. row *************************** 128 | SysBytes: 4.88 KiB 129 | P_SBytes: 4.88 KiB 130 | 1 row in set, 1 warning (0.0015 sec) 131 | Note (code 1585): This function 'format_bytes' has the same name as a 132 | native function 133 | mysql> SELECT @@global.datadir AS DataDir, 134 | sys.format_path( 135 | 'D:\\MySQL\\Data_8.0.18\\ib_logfile0' 136 | ) AS LogFile0\G 137 | *************************** 1. row *************************** 138 | DataDir: D:\MySQL\Data_8.0.18\ 139 | LogFile0: @@datadir\ib_logfile0 140 | 1 row in set (0.0027 sec) 141 | mysql> SELECT sys.format_statement( 142 | 'SELECT * FROM world.city INNER JOIN world.city ON 143 | country.Code = city.CountryCode' 144 | ) AS Statement\G 145 | *************************** 1. row *************************** 146 | Statement: SELECT * FROM world.city INNER ... ountry.Code = city.CountryCode 147 | 1 row in set (0.0016 sec) 148 | mysql> SELECT sys.format_time(123456789012) AS SysTime, 149 | FORMAT_PICO_TIME(123456789012) AS P_STime\G 150 | *************************** 1. row *************************** 151 | SysTime: 123.46 ms 152 | P_STime: 123.46 ms 153 | 1 row in set (0.0006 sec) 154 | ``` 155 | 156 | 请注意,使用 sys.format_bytes( )会触发警告(但只有第一次连接使用它),因为 sys 架构函数名与本机函数名称相同。"format_path)"函数希望在MicrosoftWindows上对路径名称进行反斜杠,在其他平台上向前斜杠。format_statement( ) 函数的结果假定statement_truncate_len选项的值已重置为默认值 64。 157 | 158 | ------ 159 | 160 | **提示** 虽然 format_time() 和 format_bytes() 的 sys 架构实现仍然存在,但最好使用新的本机函数,因为系统架构实现可能会在将来的版本中被删除,并且本机函数的速度要快得多。 161 | 162 | ------ 163 | 164 | 165 | 166 | ## The Views 167 | 168 | sys 架构提供了许多作为预定义报表工作的视图。这些视图通常使用性能架构表,但也有少数视图使用"信息架构"。 169 | 170 | 由于视图是现成的报表,您可以使用这些报表作为数据库管理员或开发人员,因此它们使用默认顺序进行定义。这意味着使用视图的典型方式是使用纯选择 * 从 [视图名称],例如: 171 | 172 | ``` 173 | mysql> SELECT * 174 | FROM sys.schema_tables_with_full_table_scans\G 175 | *************************** 1. row *************************** 176 | object_schema: world 177 | object_name: city 178 | rows_full_scanned: 4079 179 | latency: 269.13 ms 180 | 181 | *************************** 2. row *************************** 182 | object_schema: sys 183 | object_name: sys_config 184 | rows_full_scanned: 18 185 | latency: 328.80 ms 186 | 2 rows in set (0.0021 sec) 187 | ``` 188 | 189 | 结果取决于已使用完整的表扫描的表。请注意,延迟的格式与 FORMAT_PICO_TIME( )或 sys.format_time( )函数一样。 190 | 191 | 大多数系统架构视图以两种形式存在,其中一种具有语句、路径、字节值和设置格式的计时,另一种形式返回原始数据。如果在控制台上查询视图并自己查看数据,格式化视图非常有用,而未格式化的视图在需要处理程序或想要更改默认排序时会更好地工作。MySQL 工作台中的性能报告使用未格式化的视图,因此您可以在用户界面内更改顺序。 192 | 193 | 您可以区分格式化视图和未格式化视图和名称。如果视图包含格式,则也会有一个同名的未格式化视图,但 x$ 已预加到名称中。例如,对于schema_tables_with_full_table_scans中使用的视图,未格式化的视图schema_tables_with_full_table_scans: 194 | 195 | ``` 196 | mysql> SELECT * 197 | FROM sys.x$schema_tables_with_full_table_scans\G 198 | *************************** 1. row *************************** 199 | object_schema: world 200 | object_name: city 201 | rows_full_scanned: 4079 202 | latency: 269131954854 203 | *************************** 2. row *************************** 204 | object_schema: sys 205 | object_name: sys_config 206 | rows_full_scanned: 18 207 | latency: 328804286013 208 | 2 rows in set (0.0017 sec) 209 | ``` 210 | 211 | sys模式的最后一个主题是提供的帮助程序功能和过程。 212 | 213 | 214 | 215 | ## Helper Functions and Procedures 216 | 217 | sys 架构提供了多种实用程序,可帮助您使用MySQL时。其中包括执行动态创建的查询、操作列表等功能。表 6-2 中总结了最重要的帮助程序功能和程序。 218 | 219 | 补充表6-2 220 | 221 | | Routine Name | Routine Type | Description | 222 | | ------------------------------ | ------------ | ------------------------------------------------------------ | 223 | | extract_schema_ from_file_name | Function | 从每个表的InnoDB表空间文件的路径中提取模式名称。 | 224 | | extract_table_ from_file_name | Function | 从每个表的InnoDB表空间文件的路径中提取表名。 | 225 | | list_add | Function | 除非列表中已经存在元素,否则将其添加到列表中。 例如,这在需要更改SQL模式时很有用。 | 226 | | list_drop | Function | 从列表中删除一个元素 | 227 | | quote_ identifier | Function | 用反引号(`)引用标识符(例如表名)。 | 228 | | version_major | Function | 返回您要查询的实例的主版本。 例如,对于8.0.18,它返回8。 | 229 | | version_minor | Function | 返回您要查询的实例的次要版本。 例如,对于8.0.18,它返回0。 | 230 | | version_patch | Function | 返回您要查询的实例的补丁程序发行版本。 例如,对于8.0.18,它返回18。 | 231 | | execute_ prepared_stmt | Procedure | 执行以字符串形式给出的查询。 使用准备好的语句执行查询,执行完成后,该过程将取消分配准备好的语句。 | 232 | | table_exists | Procedure | 返回一个表是否存在,如果存在,则返回是基表,临时表还是视图。 | 233 | 234 | 其中一些实用程序也在系统架构中内部使用。例程的最常规用途是存储的程序中,您需要动态处理数据和问题。 235 | 236 | ------ 237 | 238 | **提示** sys模式功能和过程带有常规注释形式的内置帮助。 您可以通过查询information_schema.ROUTINES视图的ROUTINE_COMMENT列来获取帮助。 239 | 240 | ------ 241 | 242 | 243 | 244 | ## 总结 245 | 246 | 本章简要介绍了系统架构,因此,当您在后几章中看到示例时,您知道它是什么以及如何使用它。sys 架构是一个有用的附加工具,它提供现成的报告和实用程序,可以简化您的日常任务和调查。sys 架构是 MySQL 5.7 及以后的系统架构,因此需要您方执行任何操作才能开始使用它。 247 | 248 | 首先,讨论了系统架构配置。全局配置存储在可更新sys.sys_config的表中,如果您喜欢与安装 MySQL 时提供的默认值不同的默认值, 则可以更新该表。还可以通过使用 sys 设置用户变量来更改会话的配置选项。前缀到配置选项的名称。 249 | 250 | 然后,在介绍系统架构格式函数时,提到了已添加本机性能架构函数作为系统架构函数替换的情况。格式函数也用于几个视图,以帮助使数据更易于人类读取。对于使用格式设置功能的视图,还有一个相应的未格式化视图,名称前缀为 x$。 251 | 252 | 最后,讨论了几种帮助程序的功能和程序。当您尝试动态地执行工作时,例如执行在存储程序中生成的查询,这些操作可以帮助您。 253 | 254 | 下一章是关于信息模式的 -------------------------------------------------------------------------------- /第2部分-信息来源/Chapter7.md: -------------------------------------------------------------------------------- 1 | # Information Schema 2 | 3 | 当您需要优化查询时,通常需要有关查询、索引等的信息。在这种情况下,信息架构是数据的好资源。本章介绍信息架构以及它包含的视图概述。在书的其余部分中,信息架构多次使用。 4 | 5 | ## Information Schema是什么? 6 | 7 | information数据库是几个关系数据库(包括 MySQL)的通用架构,它添加到 MySQL 5.0 中。MySQL 主要遵循 *F021 基本信息架构*的 SQL:2003 标准,并进行了必要的更改,以反映 MySQL 的附加功能,以及非标准一部分的其他视图。 8 | 9 | ------ 10 | 11 | **注意** 在没有数据存储的意义上,information schema是虚拟的。 因此,即使SHOW CREATE TABLE将其显示为常规表,本章也将所有视图和表都称为视图。 这也与对所有对象将表类型设置为SYSTEM VIEW的information_schema.TABLES视图一致 12 | 13 | ------ 14 | 15 | 在 MySQL 5.5 中引入 Performance Schema 后,目标是使相对静态数据(如通过信息信息和属于性能架构的更易失数据)提供。也就是说,索引统计信息相对不稳定,但也是架构信息的一部分,这并不总是很清楚的。还有一些信息,如InnoDB指标,由于历史原因,这些指标仍然存在于信息架构中。 16 | 17 | 因此,您可以将信息架构视为描述 MySQL 实例的数据集合。在具有关系数据字典的 MySQL 8 中,一些视图是基础数据字典表上的简单 SQL 视图。这意味着 MySQL 8 中许多信息架构查询的性能将远远优于旧版本中可能体验到的性能。当查询不需要从存储引擎检索信息的架构数据时,尤其如此。 18 | 19 | ------ 20 | 21 | **注意** 如果您仍在使用 MySQL 5.7 或更早版本,请小心查询,例如信息架构中的表和列列视图。MySQL 服务器团队在博客中讨论的 MySQL 5.7 和 8 之间的信息架构性能差异示例:https://mysqlserverteam.com/mysql-8-0-scaling-and-performance-of-information_schema/。 22 | 23 | ------ 24 | 25 | 26 | 27 | ## 特权 28 | 29 | Information Schema是一个虚拟数据库,对视图的访问与其他表的工作方式有点不同。所有用户将看到架构information_schema,并且将看到所有视图。但是,查询视图的结果取决于分配给帐户的级别。例如,没有比全局使用权限具有其他权限的帐户只会在查询"信息架构"information_schema。表视图。 30 | 31 | 某些视图需要其他权限,在这种情况下,ER_SPECIFIC_ACCESS_DENIED_ERROR(错误编号 1227)错误,并说明缺少哪个权限。例如,INNODB_METRICS需要 Process 权限,因此,如果没有 Process 权限的一个用户查询该视图,则发生以下错误: 32 | 33 | ``` 34 | mysql> SELECT * 35 | FROM information_schema.INNODB_METRICS; 36 | ERROR: 1227: Access denied; you need (at least one of) the PROCESS 37 | privilege(s) for this operation 38 | ``` 39 | 40 | 现在,是时候看看您可以在Information Schema视图中找到什么样的信息了。 41 | 42 | ## Views 43 | 44 | Information Schema中提供的数据范围从有关系统高级信息到低级 InnoDB 指标。本节概述了视图,但不会详细讨论,因为从性能调优角度讨论最重要的视图,请稍后各章的相关部分讨论这些视图。 45 | 46 | ------ 47 | 48 | **注意** 某些插件会向 Information Schema添加自己的视图。此处不考虑外页视图。 49 | 50 | ------ 51 | 52 | ### 系统信息 53 | 54 | Information Schema中提供的最高级别信息与整个 MySQL 实例有关。这包括哪些字符集可用以及安装了哪些插件等信息。 55 | 56 | 表 7-1 总结了包含系统信息的视图 57 | 58 | | 视图名 | 描述信息 | 59 | | -------------------------------------- | ------------------------------------------------------------ | 60 | | CHARACTER_SETS | 可用的字符集。 | 61 | | COLLATIONS | 每个字符集可用的排序规则。 这包括排序规则的ID,在某些情况下(例如,在二进制日志中),该ID用于唯一指定排序规则和字符集。 | 62 | | COLLATION_CHARACTER_ SET_APPLICABILITY | 归类到字符集的映射(与COLLATIONS的前两列相同)。 | 63 | | ENGINES | 已知的存储引擎以及是否已加载。 | 64 | | INNODB_FT_DEFAULT_ STOPWORD | 在InnoDB表上创建全文索引时使用的默认停用词的列表。 | 65 | | KEYWORDS | MySQL中关键字的列表以及是否保留关键字 | 66 | | PLUGINS | MySQL已知的插件,包括状态 | 67 | | RESOURCE_GROUPS | 线程用于执行工作的资源组。 资源组指定线程的优先级以及它可以使用的CPU。 | 68 | | ST_SPATIAL_REFERENCE_ SYSTEMS | 空间参考系统列表,包括SRS_ID列,该列包含用于指定空间列参考系统的ID。 | 69 | 70 | 与系统相关的视图主要用作参考视图,而RESOURCE_GROUPS表则有所不同,因为可以添加资源组,这将在第17章中进行讨论。 71 | 72 | 例如,在测试升级时,KEYWORDS 视图很有用,因为您可以使用它来验证任何架构、表、列、例程或参数名称是否与新版本中的关键字匹配。如果是这种情况,则需要更新应用程序以引用标识符,如果情况不是这样。要查找与关键字匹配的所有列名: 73 | 74 | ```sql 75 | SELECT TABLE_SCHEMA, TABLE_NAME, 76 | COLUMN_NAME, RESERVED 77 | FROM information_schema.COLUMNS 78 | INNER JOIN information_schema.KEYWORDS 79 | ON KEYWORDS.WORD = COLUMNS.COLUMN_NAME 80 | WHERE TABLE_SCHEMA NOT IN ('mysql', 81 | 'information_schema', 82 | 'performance_schema', 83 | 'sys' 84 | )sql 85 | ORDER BY TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME; 86 | ``` 87 | 88 | 该查询使用COLUMNS视图查找除系统模式以外的所有列名(如果您在应用程序或脚本中使用了它们,则可以选择包括这些列名)。 COLUMNS视图是描述模式对象的几个视图之一。 89 | 90 | 91 | 92 | ### Schema Information 93 | 94 | 包含有关架构对象的信息的视图是信息架构中最有用的视图之一。这些也是几个 SHOW 语句的来源。您可以使用视图查找从存储例程的参数到数据库名称的所有内容的信息。包含架构信息的视图在表 7-2 中汇总。 95 | 96 | | 视图名 | 描述信息 | 97 | | ------------------------ | -------- | 98 | | CHECK_CONSTRAINTS | | 99 | | COLUMN_STATISTICS | | 100 | | COLUMNS | | 101 | | EVENTS | | 102 | | FILES | | 103 | | INNODB_COLUMNS | | 104 | | INNODB_DATAFILES | | 105 | | INNODB_FIELDS | | 106 | | INNODB_FOREIGN | | 107 | | INNODB_FOREIGN_COLS | | 108 | | INNODB_FT_BEING_DELETED | | 109 | | INNODB_FT_CONFIG | | 110 | | INNODB_FT_DELETED | | 111 | | INNODB_FT_INDEX_CACHE | | 112 | | INNODB_FT_INDEX_TABLE | | 113 | | INNODB_INDEXES | | 114 | | INNODB_TABLES | | 115 | | INNODB_TABLESPACES | | 116 | | INNODB_TABLESPACES_BRIEF | | 117 | | INNODB_TABLESTATS | | 118 | | INNODB_TEMP_TABLE_INFO | | 119 | | INNODB_VIRTUAL | | 120 | | KEY_COLUMN_USAGE | | 121 | | PARAMETERS | | 122 | | PARTITIONS | | 123 | | REFERENTIAL_CONSTRAINTS | | 124 | | ROUTINES | | 125 | | SCHEMATA | | 126 | | ST_GEOMETRY_COLUMNS | | 127 | | STATISTICS | | 128 | | TABLE_CONSTRAINTS | | 129 | | TABLES | | 130 | | TABLESPACES | | 131 | | TRIGGERS | | 132 | | VIEW_ROUTINE_USAGE | | 133 | | VIEW_TABLE_USAGE | | 134 | | VIEWS | | 135 | 136 | 几个视图密切相关,例如,列在表中,在架构中,约束引用表和列。这意味着一些列名存在于几个视图中。与这些视图相关的最常用的列名是 137 | 138 | - **TABLE_NAME**:在非特定于InnoDB的视图中用于表名。 139 | - **TABLE_SCHEMA**:用于非特定于InnoDB的视图中的架构名称。 140 | - **COLUMN_NAME**:在非特定于InnoDB的视图中用于列名。 141 | - **SPACE**:在特定于InnoDB的视图中用于表空间ID。 142 | - **TABLE_ID**:在特定于InnoDB的视图中用于唯一标识表。 这也在InnoDB内部使用。 143 | - **Name**:InnoDB特定的视图使用名为NAME的列来提供对象名称,而与对象类型无关。 144 | 145 | 除了使用此列表中的名称外,还有一些示例,这些列名称被稍微修改,就像在视图 KEY_COLUMN_USAGE 中一样,其中您查找了用于外键描述的列 REFERENCED_TABLE_SCHEMA、REFERENCED_TABLE_NAME、andREFERENCED_COLUMN_NAME。例如,如果要使用 KEY_COLUMN_USAGE 视图查找引用 sakila.film 表的带其他键的表,可以使用如下查询: 146 | 147 | ```sql 148 | mysql> SELECT TABLE_SCHEMA, TABLE_NAME 149 | FROM information_schema.KEY_COLUMN_USAGE 150 | WHERE REFERENCED_TABLE_SCHEMA = 'sakila' 151 | AND REFERENCED_TABLE_NAME = 'film'; 152 | +--------------+---------------+ 153 | | TABLE_SCHEMA | TABLE_NAME | 154 | +--------------+---------------+ 155 | | sakila | film_actor | 156 | | sakila | film_category | 157 | | sakila | inventory | 158 | +--------------+---------------+ 159 | 3 rows in set (0.0078 sec) 160 | ``` 161 | 162 | 这表明,所有film_actorfilm_category和库存表都有作为父表的外键。例如,如果查看表定义,请film_actor: 163 | 164 | ```sql 165 | mysql> SHOW CREATE TABLE sakila.film_actor\G 166 | *************************** 1. row *************************** 167 | Table: film_actor 168 | Create Table: CREATE TABLE `film_actor` ( 169 | `actor_id` smallint(5) unsigned NOT NULL, 170 | `film_id` smallint(5) unsigned NOT NULL, 171 | `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE 172 | CURRENT_TIMESTAMP, 173 | PRIMARY KEY (`actor_id`,`film_id`), 174 | KEY `idx_fk_film_id` (`film_id`), 175 | CONSTRAINT `fk_film_actor_actor` FOREIGN KEY (`actor_id`) REFERENCES 176 | `actor` (`actor_id`) ON DELETE RESTRICT ON UPDATE CASCADE, 177 | CONSTRAINT `fk_film_actor_film` FOREIGN KEY (`film_id`) REFERENCES `film` 178 | (`film_id`) ON DELETE RESTRICT ON UPDATE CASCADE 179 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 180 | 1 row in set (0.0097 sec) 181 | ``` 182 | 183 | 约束fk_film_actor_film在胶片表中film_id列。您可以通过手动执行查询中针对 theKEY_COLUMN_USAGE 视图返回的每个表的查询或创建递归公共表表达式 (CTE) 来将其用作查找外键器的完整链的起点。这是留给读者的练习。 184 | 185 | ------ 186 | 187 | **提示** 对于一个示例KEY_COLUMN_USAGE递归共性表表达式中使用该视图来查找外键依赖项的seehttps://mysql.wisborg.dk/tracking-foreign-keys。 188 | 189 | ------ 190 | 191 | 为了完整,图 7-1 中提供了根据胶片表通过外键显示表的可视化表示形式。 192 | 193 | ![](../附图/Figure%207-1.jpg) 194 | 195 | 该图是使用 MySQL 工作台的反向工程功能创建的。 196 | 197 | 具有特定于 InnoDB 的信息的视图使用 SPACE 和TABLE_IDto标识表空间和表。每个表空间都有一个唯一的 ID,其范围为不同的表空间类型保留。例如,数据字典表空间文件 (/mysql.ibd) 的空间 ID 4294967294,临时表空间有 id 4294967293,撤消日志表空间从 4294967279 开始,并声明,用户空间从 1 开始。 198 | 199 | 包含 InnoDB 全文索引信息的视图很特别,因为它们要求您使用要获取信息的表的名称设置 innodb_ft_aux_table 全局变量。例如,要获取表的全文sakila.film_text配置: 200 | 201 | ```sql 202 | mysql> SET GLOBAL innodb_ft_aux_table = 'sakila/film_text'; 203 | Query OK, 0 rows affected (0.0685 sec) 204 | mysql> SELECT * 205 | FROM information_schema.INNODB_FT_CONFIG; 206 | +---------------------------+-------+ 207 | | KEY | VALUE | 208 | +---------------------------+-------+ 209 | | optimize_checkpoint_limit | 180 | 210 | | synced_doc_id | 1002 | 211 | | stopword_table_name | | 212 | | use_stopword | 1 | 213 | +---------------------------+-------+ 214 | 4 rows in set (0.0009 sec) 215 | ``` 216 | 217 | INNODB_FT_CONFIG视图中的值可能与您有所不同。 218 | InnoDB还包括带有与性能有关的信息的视图。 这些将与其他一些与性能相关的表一起讨论。 219 | 220 | ### Performance Information 221 | 222 | 与性能相关的视图组是性能调优中可能使用最多的视图组,与上一组视图的 COLUMN_STATISTICS 和"统计"视图一起使用。表 7-3 中列出了包含性能相关信息的视图。 223 | 224 | | 视图名 | 描述信息 | 225 | | -------------------------------- | -------- | 226 | | INNODB_BUFFER_PAGE | | 227 | | INNODB_BUFFER_PAGE_LRU | | 228 | | INNODB_BUFFER_POOL_STATS | | 229 | | INNODB_CACHED_INDEXES | | 230 | | INNODB_CMP | | 231 | | INNODB_CMP_RESET | | 232 | | INNODB_CMP_PER_INDEX | | 233 | | INNODB_CMP_PER_INDEX_RESET | | 234 | | INNODB_CMPMEM | | 235 | | INNODB_CMPMEM_RESET | | 236 | | INNODB_METRICS | | 237 | | INNODB_SESSION_TEMP_ TABLESPACES | | 238 | | INNODB_TRX | | 239 | | OPTIMIZER_TRACE | | 240 | | PROCESSLIST | | 241 | | PROFILING | | 242 | 243 | 对于包含 InnoDB 压缩表信息的视图,具有 _RESET 作为后缀的表自上次查询视图以来,将操作和计时统计信息作为增量返回。 244 | 245 | 该INNODB_METRICS包括类似于全局状态变量但具体到 InnoDB 的指标。指标被分组到子系统(SUBSYSTEM 列),对于每个指标,在 COMMENTcolum 中都有指标的说明。您可以使用全局系统变量启用、禁用和重置指标: 246 | 247 | - **innodb_monitor_disable**:禁用一个或多个指标。 248 | - **innodb_monitor_enable**:启用一个或多个指标。 249 | - **innodb_monitor_reset**:为一个或多个指标重置计数器。 250 | - **innodb_monitor_reset_all**:重置所有统计信息,包括一个或多个指标的计数器,最小值和最大值。 251 | 252 | 可以使用在"统计"列中的当前状态根据需要打开和关闭指标。将指标的名称指定为变量或innodb_monitor_enable变量innodb_monitor_disable,可以使用 % 作为通配符。值都用作影响所有指标的特殊值。清单 7-1 显示了使用匹配 %cpu% 的所有指标(恰好是 cpu 子系统中的指标)的示例。计数器值取决于查询时的工作负荷。 253 | 254 | ```sql 255 | Listing 7-1. Using the INNODB_METRICS view 256 | mysql> SET GLOBAL innodb_monitor_enable = '%cpu%'; 257 | Query OK, 0 rows affected (0.0005 sec) 258 | mysql> SELECT NAME, COUNT, MIN_COUNT, 259 | MAX_COUNT, AVG_COUNT, 260 | STATUS, COMMENT 261 | FROM information_schema.INNODB_METRICS 262 | WHERE NAME LIKE '%cpu%'\G 263 | *************************** 1. row *************************** 264 | NAME: module_cpu 265 | COUNT: 0 266 | MIN_COUNT: NULL 267 | MAX_COUNT: NULL 268 | AVG_COUNT: 0 269 | STATUS: enabled 270 | COMMENT: CPU counters reflecting current usage of CPU 271 | *************************** 2. row *************************** 272 | NAME: cpu_utime_abs 273 | COUNT: 51 274 | MIN_COUNT: 0 275 | MAX_COUNT: 51 276 | AVG_COUNT: 0.4358974358974359 277 | STATUS: enabled 278 | COMMENT: Total CPU user time spent 279 | *************************** 3. row *************************** 280 | NAME: cpu_stime_abs 281 | COUNT: 7 282 | MIN_COUNT: 0 283 | MAX_COUNT: 7 284 | AVG_COUNT: 0.05982905982905983 285 | STATUS: enabled 286 | COMMENT: Total CPU system time spent 287 | *************************** 4. row *************************** 288 | NAME: cpu_utime_pct 289 | COUNT: 6 290 | MIN_COUNT: 0 291 | MAX_COUNT: 6 292 | AVG_COUNT: 0.05128205128205128 293 | STATUS: enabled 294 | COMMENT: Relative CPU user time spent 295 | *************************** 5. row *************************** 296 | NAME: cpu_stime_pct 297 | COUNT: 0 298 | MIN_COUNT: 0 299 | MAX_COUNT: 0 300 | AVG_COUNT: 0 301 | STATUS: enabled 302 | COMMENT: Relative CPU system time spent 303 | *************************** 6. row *************************** 304 | NAME: cpu_n 305 | COUNT: 8 306 | MIN_COUNT: 8 307 | MAX_COUNT: 8 308 | AVG_COUNT: 0.06837606837606838 309 | STATUS: enabled 310 | COMMENT: Number of cpus 311 | 6 rows in set (0.0011 sec) 312 | mysql> SET GLOBAL innodb_monitor_disable = '%cpu%'; 313 | Query OK, 0 rows affected (0.0004 sec) 314 | ``` 315 | 316 | 首先,使用变量的innodb_monitor_enable指标;然后检索值。除了显示的值外,还有一组列与 _RESET 后缀,当您设置 innodb_monitor_reset(仅计数器)或innodb_monitor_reset_all系统变量时重置。最后,指标再次被确定。 317 | 318 | ------ 319 | 320 | **注意** 指标的开销各不相同,因此建议您在生产中启用指标之前使用工作负载进行测试。 321 | 322 | ------ 323 | 324 | InnoDB度量标准还与全局状态变量和一些其他度量标准以及何时检索这些度量标准一起包含在sys.metrics视图中。 325 | 其余的Information Schema视图包含有关特权的信息。 326 | 327 | ### Privilege Information 328 | 329 | MySQL 使用分配给帐户的权限来确定哪些帐户可以访问哪些架构、表和列。确定给定帐户权限的常见方式是使用 SHOW GRANTS 语句,但信息架构还包括允许您查询权限的视图。 330 | 331 | 信息架构特权视图汇总在表 7-4 中。视图从全局权限排序到列特权。 332 | 333 | | 表名 | 描述信息 | 334 | | ----------------- | -------- | 335 | | USER_PRIVILEGES | | 336 | | SCHEMA_PRIVILEGES | | 337 | | TABLE_PRIVILEGES | | 338 | | COLUMN_PRIVILEGES | | 339 | 340 | 在所有视图中,帐户称为 GRANTEE,并且格式为"用户名"@hostname,报价始终存在。清单7-2显示了一个示例,用于检索mysql.sys@localhost帐户的权限并将其与 SHOWGRANTS 语句的输出进行比较。 341 | 342 | ```sql 343 | Listing 7-2. Using the Information Schema privilege views 344 | mysql> SHOW GRANTS FOR 'mysql.sys'@'localhost'\G 345 | *************************** 1. row *************************** 346 | Grants for mysql.sys@localhost: GRANT USAGE ON *.* TO `mysql. 347 | sys`@`localhost` 348 | *************************** 2. row *************************** 349 | Grants for mysql.sys@localhost: GRANT TRIGGER ON `sys`.* TO `mysql. 350 | sys`@`localhost` 351 | *************************** 3. row *************************** 352 | Grants for mysql.sys@localhost: GRANT SELECT ON `sys`.`sys_config` TO 353 | `mysql.sys`@`localhost` 354 | 3 rows in set (0.2837 sec) 355 | mysql> SELECT * 356 | FROM information_schema.USER_PRIVILEGES 357 | WHERE GRANTEE = '''mysql.sys''@''localhost'''\G 358 | *************************** 1. row *************************** 359 | GRANTEE: 'mysql.sys'@'localhost' 360 | TABLE_CATALOG: def 361 | PRIVILEGE_TYPE: USAGE 362 | IS_GRANTABLE: NO 363 | 1 row in set (0.0006 sec) 364 | mysql> SELECT * 365 | FROM information_schema.SCHEMA_PRIVILEGES 366 | WHERE GRANTEE = '''mysql.sys''@''localhost'''\G 367 | *************************** 1. row *************************** 368 | GRANTEE: 'mysql.sys'@'localhost' 369 | TABLE_CATALOG: def 370 | TABLE_SCHEMA: sys 371 | PRIVILEGE_TYPE: TRIGGER 372 | IS_GRANTABLE: NO 373 | 1 row in set (0.0005 sec) 374 | mysql> SELECT * 375 | FROM information_schema.TABLE_PRIVILEGES 376 | WHERE GRANTEE = '''mysql.sys''@''localhost'''\G 377 | *************************** 1. row *************************** 378 | GRANTEE: 'mysql.sys'@'localhost' 379 | TABLE_CATALOG: def 380 | TABLE_SCHEMA: sys 381 | TABLE_NAME: sys_config 382 | PRIVILEGE_TYPE: SELECT 383 | IS_GRANTABLE: NO 384 | 1 row in set (0.0005 sec) 385 | mysql> SELECT * 386 | FROM information_schema.COLUMN_PRIVILEGES 387 | WHERE GRANTEE = '''mysql.sys''@''localhost'''\G 388 | Empty set (0.0005 sec) 389 | ``` 390 | 391 | 请注意,用户名和主机名周围的单引号是如何通过将引号加乘来转义的。 392 | 393 | 虽然具有特权信息的视图不能直接用于性能调优,但它们对于维护一个稳定的系统非常有用,因为您可以使用它们来轻松识别是否有任何帐户具有它们不需要的权限。 394 | 395 | ------ 396 | 397 | **提示** 最佳做法是限制帐户只具有所需的权限,而不需要更多权限。这是确保系统安全的步骤之一。 398 | 399 | ------ 400 | 401 | 关于信息架构的最后一个主题是如何缓存与索引统计相关的数据。 402 | 403 | ## Caching of Index Statistics Data 404 | 405 | 需要了解的一件事是索引统计相关视图(和等效的 SHOW 语句)中的信息的来源。大部分数据来自 MySQL 数据字典。在 MySQL 8 中,数据字典存储在 InnoDB 表中,因此视图只是数据字典顶部的正常 SQL 视图。(例如,您可以尝试执行"显示创建视图"information_schema。获取统计信息视图定义的统计信息。 406 | 407 | 但是,索引统计信息本身仍然来自存储引擎层,因此查询这些统计信息的成本相对较高。为了提高性能,统计数据字典中缓存了统计数据。您可以控制在 MySQL 刷新缓存之前,统计信息的显示时间。这是用默认为 information_schema_stats_expiry86400 秒(一天)的默认变量完成的。如果将 值设置为 0,则始终从存储引擎获取可用的最新值;如果将值设置为 0,则始终从存储引擎获取可用值。这相当于 MySQL 5.7 行为。可以在全局和会话作用域中同时设置变量,因此,如果您正在调查查看当前统计信息很重要的问题(例如,如果优化器未使用预期索引),则变量可以设置为会话的 0。 408 | 409 | ------ 410 | 411 | **提示** 使用information_schema_stats_expiry变量控制索引统计信息在数据字典中缓存的长。这仅适用于显示目的 - 优化器始终使用最新的统计信息。例如information_schema_stats_expiry将 0 设置为 0 来禁用缓存,在调查优化器使用的错误索引的问题时可能很有用。您可以根据需要在全局和会话作用域中更改该值。 412 | 413 | ------ 414 | 415 | 缓存会影响表 7-5 中列出的列。显示相同数据的 SHOW 语句也会受到影响。 416 | 417 | | 视图名 | 列名 | 描述信息 | 418 | | ---------- | ---------------- | -------- | 419 | | STATISTICS | CARDINALITY | | 420 | | TABLES | AUTO_INCREMENT | | 421 | | | AVG_ROW_LENGTH | | 422 | | | CHECKSUM | | 423 | | | CHECK_TIME | | 424 | | | CREATE_TIME | | 425 | | | DATA_FREE | | 426 | | | DATA_LENGTH | | 427 | | | INDEX_LENGTH | | 428 | | | MAX_DATA_ LENGTH | | 429 | | | TABLE_ROWS | | 430 | | | UPDATE_TIME | | 431 | 432 | 您可以通过为表执行 ANALYZE 表来强制更新给定表的此数据。 433 | 434 | 有时查询数据不会更新缓存的数据: 435 | 436 | - 当缓存的数据尚未过期时,即刷新时间少于几秒钟前的information_schema_stats_expiry 437 | - 当information_schema_stats_expiry设置为0时 438 | - 当MySQL或InnoDB以只读模式运行时,即启用了其中一种模式read_only,super_read_only,transaction_ read_only或innodb_read_only。 439 | - 当查询还包含来自性能架构的数据时 440 | 441 | ## 总结 442 | 443 | 本章首先讨论什么是信息架构以及用户权限的工作方式,来介绍信息架构。本章的其余部分将介绍标准视图和缓存的工作原理。信息架构视图可以按其包含的信息类型进行分组:系统、架构、性能和权限信息。 444 | 445 | 系统信息包括字符集和排序规则、资源组、关键字和与空间数据相关的信息。这可用于使用参考手册的替代方案。 446 | 447 | 架构信息是最大的视图组,包括从架构数据到列、索引和约束的所有可用信息。这些视图以及具有指标和 InnoDB 缓冲池统计信息等信息的性能视图是性能调整中最常用的视图。与特权相关的视图并不常用于性能调整,但它们对于帮助维护一个稳定的系统非常有用。 448 | 449 | 从信息架构视图获取信息的常见快捷方式是使用 SHOW 语句。下一章将讨论这些内容。 -------------------------------------------------------------------------------- /第2部分-信息来源/Chapter8.md: -------------------------------------------------------------------------------- 1 | # show语句 2 | 3 | SHOW 语句是 MySQL 中用于数据库管理员获取有关架构对象和系统上发生的情况的信息的好老主力。虽然今天大部分信息都可以在信息架构或性能信息中找到,但由于其短裤,SHOW 命令仍然非常流行,适合交互式使用。 4 | 5 | ------ 6 | 7 | **提示** 建议查询基础信息架构视图和性能架构表。这尤其适用于对数据的非交互式访问。查询基础源也更强大,因为它允许您联接到其他视图和表。 8 | 9 | ------ 10 | 11 | 本章首先概述 SHOW 语句如何与信息架构视图和性能架构表匹配。课程的其余部分包括信息信息学和性能架构中没有视图或表的 SHOW 语句,包括通过 SHOW ENGINEINNODB 状态语句提供的 InnoDB 监视器输出的更深入的视图获取引擎状态信息,以及获取复制和二进制日志信息。 12 | 13 | ## Relationship to the Information Schema 14 | 15 | 对于返回有关架构对象或特权的信息的 SHOW 语句,可以在信息架构中找到相同的信息。表 8-1 列出了从信息架构视图中获取信息的SHOW语句,以及可以在其中找到哪些视图。 16 | 17 | 在 SHOW 语句和应答信息架构视图之间,信息并不总是相同的。在某些情况下,使用视图可以获得更多信息,并且一般情况下视图更灵活。 18 | 19 | 还有几个 SHOW 语句,其中的基础数据可以在性能架构中找到。 20 | 21 | ## Relationship to the Performance Schema 22 | 23 | 引入性能架构后,信息架构中原始放置的一些信息已移动到性能架构,而性能架构在逻辑上属于该架构。这也反映在与 SHOW 声明的关系中,其中现在有多个表,如表 8-2 所示,这些表从性能架构表中获取数据。 24 | 25 | SHOW 主状态包括有关在将事件编写到二进制日志时启用筛选的信息。此信息无法从性能信息中获得,因此,如果您使用的是 binlog-do-db 或 binlog-ignore-db 选项(因为它们可以防止时间点恢复),则仍然需要使用SHOW MASTER 状态。 26 | 27 | 在"显示从属状态"输出中,在性能架构表中找不到几列。其中一些可以在 mysql 架构slave_master_infoand slave_relay_log_info的表(如果master_info_repository andrelay_log_info_repository已设置为默认的 TABLE)。 28 | 29 | 对于"显示状态"和"显示变量",一个区别是,如果没有会话值,SHOW 语句返回会话范围值将包括全局值。查询session_statussession_variables时,仅返回属于请求范围的值。此外,SHOW STATUS 语句包括 Com_% 计数器,而直接查询性能架构时,这些计数器对应于 events_statements_summary_global_by_event_name 和 events_statements_summary_by_thread_by_event_name 表中的事件(取决于是否查询全局或会话范围)。 30 | 31 | 还有一些 SHOW 语句没有任何相应的表。将讨论的第一组是引擎状态。 32 | 33 | 34 | 35 | ## Engine Status 36 | 37 | SHOW ENGINE 语句可用于获取存储引擎的特定信息。它目前为 InnoDB、Performance_Schema和 NDBCluster 引擎实现。对于所有三个引擎,可以请求状态,对于 InnoDB 引擎,也有可能获取互斥信息。 38 | 39 | SHOW ENGINE PERFORMANCE_SCHEMA状态语句可用于获取有关性能架构的一些状态信息,包括表的大小及其内存使用情况。(内存使用情况也可以从内存图获得。 40 | 41 | 到目前为止,使用最多的引擎状态声明是 SHOW 引擎 INNODB 状态,它提供了一份称为 InnoDB 监视器报告的全面报告,其中包括无法从其他来源获取的一些信息。本节的其余部分将介绍 InnoDB 监视器报告。 42 | 43 | ------ 44 | 45 | **提示** 还可以通过启用系统变量,使 InnoDB 以定期间隔将监视器报告innodb_status_output日志。设置innodb_status_output_locks时,InnoDB 监视器(无论是由于 innodb_status_output = ON 或使用 SHOW ENGINEINNODB 状态)都包含其他锁信息。 46 | 47 | ------ 48 | 49 | InnoDB 监视器报告以标题开头,并注释显示平均值涵盖的时间长: 50 | 51 | ```sql 52 | mysql> SHOW ENGINE INNODB STATUS\G 53 | *************************** 1. row *************************** 54 | Type: InnoDB 55 | Name: 56 | Status: 57 | ===================================== 58 | 2019-09-14 19:52:40 0x6480 INNODB MONITOR OUTPUT 59 | ===================================== 60 | Per second averages calculated from the last 59 seconds 61 | ``` 62 | 63 | 报告本身分为几个部分,包括 64 | 65 | - 背景线程:由主后台线程完成的工作。 66 | - 信号量:信号量统计。在争用导致长信号量等待的情况下,该节是最重要的,在这种情况下,该节可用于获取有关锁和谁持有锁的信息。 67 | - 最新外键错误:如果已对外键错误进行计数,本节将包含该错误的详细信息。否则,将省略这些词。 68 | - 最新检测到的死锁:如果发生死锁,本节将包含导致死锁的两个事务和锁的详细信息。否则,将省略该节。 69 | - 事务:有关 InnoDB 事务的信息。仅包含已修改 InnoDB 表的交易。如果theinnodb_status_output_locks,则列出每个事务的锁;如果启用了"theinnodb_status_output_locks,则列出每个事务的锁。如果启用了该选项,则列出每个事务的锁。否则, 它只是锁涉及锁等待。一般来说,最好使用information_schema。INNODB_TRX查询事务信息和用于锁定信息以使用performance_schema。DATA_LOCKS andperformance_schema.DATA_LOCK_WAITS表。 70 | - 文件 I/O:有关 InnoDBind 使用的 I/O 线程的信息,包括插入缓冲区线程、日志线程、读取线程和写入线程。 71 | - 插入缓冲区和自适应哈希索引:有关更改缓冲区(这以前称为插入缓冲区)和适应哈希索引的信息。 72 | - 日志:有关重做日志的信息。 73 | - 缓冲区池和内存:有关 InnoDB 缓冲池的信息。此信息最好从information_schema。INNODB_BUFFER_POOL_STATS视图。 74 | - 个人缓冲池信息:innodb_buffer_pool_instancesis大于 1,本节包含有关个人缓冲池实例的信息,其信息与上一节中的全球摘要的信息相同。否则,将包含该部分。此信息最好从information_schema。INNODB_BUFFER_POOL_STATS视图。 75 | - 行操作:本节显示有关InnoDB的各种信息,包括当前活动、主线程正在做什么以及插入、更新、删除和读取的行活动。 76 | 77 | 当几个部分的内容用于分析性能或锁定问题时,将在后几章中使用。 78 | 79 | 80 | ## Replication and Binary Logs 81 | 82 | 在使用复制时,SHOW 语句始终很重要。虽然性能架构复制表现在基本上取代了 SHOW SLAVESTATUS 和 SHOW 主状态语句,但如果您想要查看连接哪些副本并检查来自 MySQL 内部的二进制日志或中继日志中的事件,则仍然需要使用 SHOW 语句。 83 | 84 | ### Listing Binary Logs 85 | 86 | SHOW BINARY LOGS 语句可用于检查存在哪些二进制日志。如果您想知道二进制日志占用的空间、它们是否加密,以及基于位置的复制副本是否仍然存在,这可能非常用。 87 | 88 | 输出看起来像一个例子 89 | 90 | ```sql 91 | mysql> SHOW BINARY LOGS; 92 | +---------------+-----------+-----------+ 93 | | Log_name | File_size | Encrypted | 94 | +---------------+-----------+-----------+ 95 | | binlog.000044 | 2616 | No | 96 | | binlog.000045 | 886 | No | 97 | | binlog.000046 | 218 | No | 98 | | binlog.000047 | 218 | No | 99 | | binlog.000048 | 218 | No | 100 | | binlog.000049 | 575 | No | 101 | +---------------+-----------+-----------+ 102 | 6 rows in set (0.0018 sec) 103 | ``` 104 | 105 | MySQL 8.0.14中添加了Encrypted列,并支持加密的二进制日志。 106 | 107 | 通常,文件大小将大于示例中,因为在编写事务后,当大小超过 max_binlog_size(默认为 1 GiB)时,将自动修改二年日志文件。由于事务不会在文件之间拆分,因此如果您有大型事务,则文件可能会变得比文件max_binlog_size。 108 | 109 | 110 | 111 | ### Viewing Log Events 112 | 113 | 显示 BINLOG 事件和显示 RELAYLOG 事件语句分别读取二进制 logand 中继日志,并返回与参数匹配的事件。有四个限制,其中一个仅适用于中继日志事件: 114 | 115 | - IN:要从中读取事件的二进制日志或中继日志文件的名称。 116 | - FROM:以字节为单位开始读取的位置。 117 | - LIMIT(事件):要包括的事件数,带有可选的偏移量。 语法与SELECT语句相同:[offset],row_count。 118 | - FOR CHANNEL:对于中继日志,是要为其读取事件的复制通道。 119 | 120 | 所有参数都是可选的。如果未给出 IN 参数,则返回第一个日志中的事件。使用 SHOW BINLOG 事件的示例列在清单 8-1 中。如果您希望尝试该示例,则需要替换二进制日志文件名、位置和限制。 121 | 122 | ```sql 123 | Listing 8-1. Using SHOW BINLOG EVENTS 124 | mysql> SHOW BINLOG EVENTS IN 'binlog.000049' FROM 195 LIMIT 5\G 125 | *************************** 1. row *************************** 126 | Log_name: binlog.000049 127 | Pos: 195 128 | Event_type: Gtid 129 | Server_id: 1 130 | End_log_pos: 274 131 | Info: SET @@SESSION.GTID_NEXT= '4d22b3e5-a54f-11e9-8bdb-ace2d35785be:603' 132 | *************************** 2. row *************************** 133 | Log_name: binlog.000049 134 | Pos: 274 135 | Event_type: Query 136 | Server_id: 1 137 | End_log_pos: 372 138 | Info: BEGIN 139 | *************************** 3. row *************************** 140 | Log_name: binlog.000049 141 | Pos: 372 142 | Event_type: Table_map 143 | Server_id: 1 144 | End_log_pos: 436 145 | Info: table_id: 89 (world.city) 146 | *************************** 4. row *************************** 147 | Log_name: binlog.000049 148 | Pos: 436 149 | Event_type: Update_rows 150 | Server_id: 1 151 | End_log_pos: 544 152 | Info: table_id: 89 flags: STMT_END_F 153 | *************************** 5. row *************************** 154 | Log_name: binlog.000049 155 | Pos: 544 156 | Event_type: Xid 157 | Server_id: 1 158 | End_log_pos: 575 159 | Info: COMMIT /* xid=44 */ 160 | 5 rows in set (0.0632 sec) 161 | ``` 162 | 163 | 该示例说明了使用 SHOW 语句检查二次日志和中继日志的一些限制。结果是来自查询的正常结果集,并且由于文件大小通常约为 1 GiB,这意味着结果可以同样大。您可以在示例中执行仅选择特定事件,但了解有趣的事件从该开始位置并不总是微不足道的,并且无法按事件类型或它们影响哪些表进行筛选。最后,默认事件格式(binlog_format 选项)是row格式,从结果中的第三行和第四行可以看到,从 SHOW BINGOG 事件中,您只能看到事务更新了 world.city 表。您无法查看更新了哪些行以及值是什么。 164 | 165 | 实际上,如果您有权访问文件系统,在大多数情况下最好使用 MySQL 附带的 mysqlbinlog 实用程序。(在受控测试或复制停止时,显示 BINLOG 事件和 SHOWRELAYLOG 事件语句仍然很有用,您快速想要检查导致错误的事件。使用 mysqlbinlog 实用程序到上一个 SHOW BINLOG 事件语句的等效命令显示在清单 8-2 中。该示例还使用详细标志显示更新 world.city 表的基于行的事件的之前和之后的图像。 166 | 167 | ```sql 168 | Listing 8-2. Inspecting the binary log using the mysqlbinlog utility 169 | shell> mysqlbinlog -v --base64-output=decode-rows --start-position=195 170 | --stop-position=575 binlog.000049 171 | /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; 172 | /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; 173 | DELIMITER /*!*/; 174 | # at 124 175 | #190914 20:38:43 server id 1 end_log_pos 124 CRC32 0x751322a6 Start: 176 | binlog v 4, server v 8.0.18 created 190914 20:38:43 at startup 177 | # Warning: this binlog is either in use or was not closed properly. 178 | ROLLBACK/*!*/; 179 | # at 195 180 | #190915 10:18:45 server id 1 end_log_pos 274 CRC32 181 | 0xe1b8b9a1 GTID last_committed=0 sequence_number=1 182 | rbr_only=yes original_committed_timestamp=1568506725779031 183 | immediate_commit_timestamp=1568506725779031 transaction_length=380 184 | /*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/; 185 | # original_commit_timestamp=1568506725779031 (2019-09-15 10:18:45.779031 186 | AUS Eastern Standard Time) 187 | # immediate_commit_timestamp=1568506725779031 (2019-09-15 10:18:45.779031 188 | AUS Eastern Standard Time) 189 | /*!80001 SET @@session.original_commit_timestamp=1568506725779031*//*!*/; 190 | /*!80014 SET @@session.original_server_version=80018*//*!*/; 191 | /*!80014 SET @@session.immediate_server_version=80018*//*!*/; 192 | SET @@SESSION.GTID_NEXT= '4d22b3e5-a54f-11e9-8bdb-ace2d35785be:603'/*!*/; 193 | # at 274 194 | #190915 10:18:45 server id 1 end_log_pos 372 CRC32 0x2d716bd5 Query 195 | thread_id=8 exec_time=0 error_code=0 196 | SET TIMESTAMP=1568506725/*!*/; 197 | SET @@session.pseudo_thread_id=8/*!*/; 198 | SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, 199 | @@session.unique_checks=1, @@session.autocommit=1/*!*/; 200 | SET @@session.sql_mode=1168113696/*!*/; 201 | SET @@session.auto_increment_increment=1, @@session.auto_increment_ 202 | offset=1/*!*/; 203 | /*!\C utf8mb4 *//*!*/; 204 | SET @@session.character_set_client=45,@@session.collation_connection=45, 205 | @@session.collation_server=255/*!*/; 206 | SET @@session.lc_time_names=0/*!*/; 207 | SET @@session.collation_database=DEFAULT/*!*/; 208 | /*!80011 SET @@session.default_collation_for_utf8mb4=255*//*!*/; 209 | BEGIN 210 | /*!*/; 211 | # at 372 212 | #190915 10:18:45 server id 1 end_log_pos 436 CRC32 0xb62c64d7 Table_map: 213 | `world`.`city` mapped to number 89 214 | # at 436 215 | #190915 10:18:45 server id 1 end_log_pos 544 CRC32 0x62687b0b 216 | Update_rows: table id 89 flags: STMT_END_F 217 | ### UPDATE `world`.`city` 218 | ### WHERE 219 | ### @1=130 220 | ### @2='Sydney' 221 | ### @3='AUS' 222 | ### @4='New South Wales' 223 | ### @5=3276207 224 | ### SET 225 | ### @1=130 226 | ### @2='Sydney' 227 | ### @3='AUS' 228 | ### @4='New South Wales' 229 | ### @5=3276208 230 | # at 544 231 | #190915 10:18:45 server id 1 end_log_pos 575 CRC32 0x149e2b5c Xid = 44 232 | COMMIT/*!*/; 233 | SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/; 234 | DELIMITER ; 235 | # End of log file 236 | /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_ 237 | ``` 238 | 239 | -v 参数请求详细模式,并可最多提供两次以增加包含的信息量。单 -v 是从位置 436 开始的事件中使用伪查询生成注释的函数。--base64 输出=解码行参数告诉 mysqlbinlog 不要以行格式包含事件的 base64 编码版本。--开始位置和 --停止位置参数指定以字节为单位的开始和停止偏移。 240 | 241 | 事务中最有趣的事件是从注释# 436 开始的事件,这意味着事件从偏移量 436(以字节为单位)开始。它编写为伪更新语句,其中 WHERE 部分显示更改前的值,更新后 SET 部分显示值。这也称为图像之前和之后。 242 | 243 | ------ 244 | 245 | **注意** 如果您使用加密的二进制日志,则不能直接使用 mysqlbinlog 来读取文件。一个选项是使 mysqlbinlog 连接到服务器并读取返回未加密的日志的日志。如果使用加密插件存储keyring_file的另一个选项是使用 Python 或标准 Linux 工具来加密文件。这些方法在https://mysql.wisborg.dk/decrypt-binary-logshttps://mysqlhighavailability.com/howto-manually-decrypt-an-encrypted-binary-log-file/。 246 | 247 | ------ 248 | 249 | 250 | 251 | ### Show Connected Replicas 252 | 253 | 另一个有用的命令是请求复制源列出连接到它的所有副本。这可用于在监视工具中自动发现复制拓扑。 254 | 255 | 列出连接的副本的命令是SHOW SLAVE HOSTS,例如: 256 | 257 | ```sql 258 | mysql> SHOW SLAVE HOSTS\G 259 | *************************** 1. row *************************** 260 | Server_id: 2 261 | Host: replica.example.com 262 | Port: 3308 263 | Master_id: 1 264 | Slave_UUID: 0b072c80-d759-11e9-8423-ace2d35785be 265 | 1 row in set (0.0003 sec) 266 | ``` 267 | 268 | 如果在执行语句时未连接任何副本,则结果将为空。Server_idMaster_id列是副本和源server_id的可用系统的值。主机是使用"使用"report_host副本的主机名。同样,Port 列是副本的sreport_port值。最后,Slave_UUID列是副本上的 @@global.server_uuid 的值。 269 | 270 | 剩下的唯一一组 SHOW 语句由各种语句组成,用于获取有关权限、用户、打开的表、警告和错误的信息。 271 | 272 | 273 | 274 | ## Miscellaneous Statements 275 | 276 | 有几个 SHOW 语句很有用,但不适合到目前为止讨论过的任何组。它们可用于列出可用权限、返回帐户的 CREATE USER 语句、列出打开的表以及在执行语句后列出警告 orerors。这些语句总结于表8-3。 277 | 278 | 杂项 SHOW 语句中最常用的三个语句是"显示创建用户"、"显示授权"和"显示警告"。 279 | 280 | "显示创建用户"语句可用于检索帐户的创建用户语句。这对于检查帐户的元数据而不直接查询基础 mysql.user 表非常有用。允许所有用户为当前用户执行语句。例如: 281 | 282 | ```sql 283 | mysql> SET print_identified_with_as_hex = ON; 284 | Query OK, 0 rows affected (0.0200 sec) 285 | Table 8-3. Miscellaneous SHOW statements 286 | SHOW Statement Description 287 | PRIVILEGES Lists the available privileges, which context they apply to, and for some 288 | privileges a description of what the privilege controls. 289 | CREATE USER Returns the CREATE USER statement for an account. 290 | GRANTS Lists the assigned privileges for the current account or another account. 291 | OPEN TABLES Lists the tables in the table cache, the number of table locks or lock requests, 292 | and whether the name of the table is locked (happens during DROP TABLE or 293 | RENAME TABLE). 294 | WARNINGS Lists the warnings and errors and if sql_notes is enabled (the default) notes 295 | for the last executed statement. 296 | ERRORS Lists the errors for the last executed statement. 297 | mysql> SHOW CREATE USER CURRENT_USER()\G 298 | *************************** 1. row *************************** 299 | CREATE USER for root@localhost: CREATE USER 'root'@'localhost' IDENTIFIED 300 | WITH 'caching_sha2_password' AS 0x24412430303524377B743F5E176E1A77494F574 301 | D216C41563934064E58364E385372734B77314E43587745314F506F59502E747079664957 302 | 776F4948346B526B59467A642F30 REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT 303 | UNLOCK PASSWORD HISTORY DEFAULT PASSWORD REUSE INTERVAL DEFAULT PASSWORD 304 | REQUIRE CURRENT DEFAULT 305 | 1 row in set (0.0003 sec) 306 | ``` 307 | 308 | print_identified_with_as_hex(在 8.0.17 及更晚版本中可用)可以返回十六进制表示法中的密码摘要。这是将值返回到控制台时的首选,因为摘要可能包含不可打印字符。SHOW CREATE 用户输出等效于用户创建的方式,可用于创建具有相同设置(包括密码)的新用户。 309 | 310 | ------ 311 | 312 | **注意**:仅在 MySQL 8.0.17 及更晚一些中支持在创建用户时指定十六进制表示法中的身份验证摘要。 313 | 314 | ------ 315 | 316 | SHOW GRANTS 语句通过返回分配给帐户的"显示创建用户"来补充"显示创建用户"。默认值是返回当前用户,但如果您具有 mysql 系统数据库的 SELECT 权限,您还可以获取分配给其他帐户的特权。例如,要列出该帐户root@localhost: 317 | 318 | ```sql 319 | mysql> SHOW GRANTS FOR root@localhost\G 320 | *************************** 1. row *************************** 321 | Grants for root@localhost: GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, 322 | DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW 323 | DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, 324 | REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE 325 | ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, 326 | CREATE ROLE, DROP ROLE ON *.* TO `root`@`localhost` WITH GRANT OPTION 327 | *************************** 2. row *************************** 328 | Grants for root@localhost: GRANT APPLICATION_PASSWORD_ADMIN,AUDIT_ 329 | ADMIN,BACKUP_ADMIN,BINLOG_ADMIN,BINLOG_ENCRYPTION_ADMIN,CLONE_ 330 | ADMIN,CONNECTION_ADMIN,ENCRYPTION_KEY_ADMIN,GROUP_REPLICATION_ 331 | ADMIN,INNODB_REDO_LOG_ARCHIVE,PERSIST_RO_VARIABLES_ADMIN,REPLICATION_ 332 | APPLIER,REPLICATION_SLAVE_ADMIN,RESOURCE_GROUP_ADMIN,RESOURCE_GROUP_ 333 | USER,ROLE_ADMIN,SERVICE_CONNECTION_ADMIN,SESSION_VARIABLES_ADMIN,SET_USER_ 334 | ID,SYSTEM_USER,SYSTEM_VARIABLES_ADMIN,TABLE_ENCRYPTION_ADMIN,XA_RECOVER_ 335 | ADMIN ON *.* TO `root`@`localhost` WITH GRANT OPTION 336 | *************************** 3. row *************************** 337 | Grants for root@localhost: GRANT PROXY ON “@” TO 'root'@'localhost' WITH 338 | GRANT OPTION 339 | 3 rows in set (0.0129 sec) 340 | ``` 341 | 342 | SHOW 警告语句是 MySQL 中使用最未充分利用的语句之一。如果MySQL遇到问题,但能够继续,它将生成一个警告,但另一方面完成语句的执行。虽然语句完成时没有错误,但警告可能是更大问题的迹象,最佳做法是始终检查警告,并力求在应用程序执行的查询中永远不会发出警告。 343 | 344 | ------ 345 | 346 | **注意** MySQL Shell 不支持 SHOW 警告语句,因为如果启用了 \W 模式(默认值),并且不使警告可用,它将自动获取警告。但是,该语句在旧版 mysql 命令行客户端和某些连接器(如 MySQLConnector/Python)中仍然很有用。 347 | 348 | ------ 349 | 350 | 清单 8-3 显示了一个示例,其中 SHOW 警告与旧版 mysqlcommand 线路客户端一起使用,以标识架构定义和数据不匹配。 351 | 352 | ```sql 353 | Listing 8-3. Using SHOW WARNINGS to identify problems 354 | mysql> SELECT @@sql_mode\G 355 | *************************** 1. row *************************** 356 | @@sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE, 357 | NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION 358 | 1 row in set (0.0004 sec) 359 | mysql> SET sql_mode = sys.list_drop( 360 | @@sql_mode, 361 | 'STRICT_TRANS_TABLES' 362 | ); 363 | Query OK, 0 rows affected, 1 warning (0.00 sec) 364 | mysql> SHOW WARNINGS\G 365 | *************************** 1. row *************************** 366 | Level: Warning 367 | Code: 3135 368 | Message: 'NO_ZERO_DATE', 'NO_ZERO_IN_DATE' and 'ERROR_FOR_DIVISION_BY_ZERO' 369 | sql modes should be used with strict mode. They will be merged with strict 370 | mode in a future release. 371 | 1 row in set (0.00 sec) 372 | mysql> UPDATE world.city 373 | SET Population = Population/0 374 | WHERE ID = 130; 375 | Query OK, 0 rows affected, 2 warnings (0.00 sec) 376 | Rows matched: 1 Changed: 0 Warnings: 2 377 | mysql> SHOW WARNINGS\G 378 | *************************** 1. row *************************** 379 | Level: Warning 380 | Code: 1365 381 | Message: Division by 0 382 | *************************** 2. row *************************** 383 | Level: Warning 384 | Code: 1048 385 | Message: Column 'Population' cannot be null 386 | 2 rows in set (0.00 sec) 387 | mysql> SELECT * 388 | FROM world.city 389 | WHERE ID = 130\G 390 | *************************** 1. row *************************** 391 | ID: 130 392 | Name: Sydney 393 | CountryCode: AUS 394 | District: New South Wales 395 | Population: 0 396 | 1 row in set (0.03 sec) 397 | ``` 398 | 399 | 该示例从将 SQL 模式设置为 MySQL 8 中的默认值开始。首先,使用 sys.list_drop() 函数更改 SQLmode 以删除触发警告的 STRICT_TRANS_TABLES 模式,因为禁用严格模式应与其他模式一起完成,因为它们将在以后合并在一起。然后更新世界上一个城市的人口.城市表,但计算结束除以0,这将触发两个警告。一个警告是按 0 划分,未定义,因此 MySQL 使用 NULL 值,该值会导致第二个警告,因为"总体"列是非 NULL 列。结果是,0 的人口与城市是分配的,这可能不是应用程序中的预期。这也解释了为什么启用严格的 SQL 模式很重要,因为这将使分区为零错误并阻止更新。 400 | 401 | ------ 402 | 403 | **注意 不要禁用 STRICT_TRANS_TABLES SQL 模式,因为它使表中的数据更有可能最终出现无效数据。** 404 | 405 | ------ 406 | 407 | 408 | 409 | ## 总结 410 | 411 | 本章介绍了可追溯到信息信息和性能架构实施前的 SHOW 语句。如今,最好在信息架构和性能架构中使用基础数据源。 412 | 413 | 还有一些 SHOW 语句返回无法通过其他源访问的数据。常用的功能是 InnoDB 监视器报告,该报告来自 INNODBobo 与 SHOW 引擎 INNODB 状态语句一起包含。报告分为几个部分,其中一些将在调查性能和锁定问题时使用。 414 | 415 | 还有一些用于复制的语句和有用的二进制日志。其中最常用的语句是 SHOW BINARY LOGS,它列出了 MySQL 为该实例知道的二进制日志。该信息包括日志的大小以及日志是否加密。您还可以在二进制日志或中继日志中列出事件,但在实践中,mysqlbinlog 实用程序通常是更好的选项。 416 | 417 | 最后,介绍了一组杂项的 SHOW 语句。其中三个使用最多的是"显示创建用户"来显示可用于重新创建用户的语句,返回分配给用户的权限的 SHOW GRANTS 和显示警告,它们列出了错误、警告以及上次执行查询时发生的默认注释。检查警告是执行查询时经常忽略的一个方面,因为警告可能表明查询的结果不是您所期望的。值得称赞的是,始终检查警告并启用STRICT_TRANS_TABLESSQL模式。 418 | 419 | 关于信息源的最后一章是关于慢查询日志的信息 -------------------------------------------------------------------------------- /第2部分-信息来源/Chapter9.md: -------------------------------------------------------------------------------- 1 | # 慢查询日志 2 | 3 | 在从Performance Schema获取查询统计信息之前的日子里,慢查询日志是查找最适合优化查询的主要信息来源。即使在今天,慢查询日志也不应该被完全消除。 4 | 5 | 与Performance Schema中的语句摘要信息相比,慢查询日志具有三个主要优点。记录的查询将保持不变,因此您可以在MySQL重新启动,使用时间戳记录查询以及记录实际查询后查看信息。 由于这些原因,慢查询日志通常与Performance Schema一起使用。 6 | 7 | ------ 8 | 9 | **提示** 像 MySQL 企业监视器 (https://dev.mysql.com/doc/mysql-monitor/en/mem-qanal-using.html) 这样的监视解决方案可以克服Performance Schema的这些限制,因此,如果您有包含详细查询信息的监控解决方案,则不太可能调低查询日志的速度。 10 | 11 | ------ 12 | 13 | 慢查询日志也有缺点。开销高于Performance Schema,因为查询写入纯文本文件,并且编写事件时没有并发支持。查询日志的支持也有限(您可以将慢查询日志存储在表中,但这有其自身的缺点),这使得在调查期间使用它不太实用。 14 | 15 | 本章将介绍如何配置慢查询日志、原始日志事件的外观,以及如何使用 mysqldumpslow (mysqldumpslow.pl 在 Microsoft Windows) 脚本来聚合日志 16 | 17 | ## 配置 18 | 19 | 有几个选项可用于配置慢查询日志和记录哪些查询。启用日志的开销随着您日志的查询数而增加,配置良好的慢速查询日志非常重要。对查询进行"正确"的日志记录也便于识别感兴趣的查询。 20 | 21 | 默认情况下,不会启用慢查询日志,并且启用日志时,默认只是记录直接在本地实例上执行的非管理查询,并且查询需要 10 秒以上才能执行。表 9-1 总结了用于微调此行为的配置选项。该信息包括默认值以及该选项是否在全局范围或会话范围中使用,或者两者同时使用。选项按字母顺序列出。 22 | 23 | | 选项/默认值/范围 | 描述 | 24 | | ------------------------------------------------------------ | ------------------------------------------------------------ | 25 | | min_examined_row_limit Default: 0 Scope: Global, Session | 启用后,会有更多信息,例如查询的Handler_%状态变量的值。 仅在登录文件时以及在MySQL 8.0.14和更高版本中才支持 | 26 | | log_output Default: FILE Scope: Global | | 27 | | log_queries_not_using_ indexes Default: OFF Scope: Global | | 28 | | log_short_format Default: OFF Scope: Global | | 29 | | log_slow_admin_statements Default: OFF Scope: Global | | 30 | | log_slow_extra Default: OFF Scope: Global | | 31 | | log_slow_slave_statements Default: OFF Scope: Global | | 32 | | log_throttle_queries_not_ using_indexes Default: 0 Scope: Global | | 33 | | log_timestamps Default: UTC Scope: Global | | 34 | | long_query_time Default: 10 Scope: Global, Session | | 35 | | slow_query_log Default: OFF Scope: Global | | 36 | | slow_query_log_file Default: -slow.log Scope: Global | | 37 | 38 | 建议将事件log_output默认值,然后按"slow_query_log_file"将事件slow_query_log_file。将慢速查询日志作为表获取可能看起来很有吸引力;但是,在这种情况下,数据被保存为逗号分隔值 (CSV),并且与表相对应的查询无法使用索引。还有一些功能,如log_slow_extra,不支持log_output + 表。 39 | 40 | 这些选项意味着您可以对记录哪些查询进行细粒度的控制。除其他log_short_format所有选项都可以动态更改,因此您可以根据情况进行更改。如果您觉得很难确定选项如何中断,则图 9-1 显示了确定是否应记录查询的决策过程的流程图。(流程图仅说明性 – 实际代码路径不同。 41 | 42 | ![](../附图/Figure%209-1.png) 43 | 44 | 流从查询类型开始。对于管理语句和复制语句,它们仅在启用相应选项时才继续。常规查询首先检查它们是否有资格不使用索引,然后回退检查查询执行时间(延迟)。如果满足任一条件,则检查是否检查了足够的行。一些更精细的细节,如不使用索引的语句的节限制,将不从图中算出。 45 | 46 | 有了所需的查询设置后,您需要查看日志中的事件以确定是否需要关注任何查询。 47 | 48 | ## Log Events 49 | 50 | 慢查询日志以纯文本形式构建事件。这意味着您可以使用任何喜欢检查该文件的文本查看器。在 Linux 和 Unix 上,较少的命令是一个很好的选项,因为它对处理大型文件具有很好的支持。在 Microsoft Windows 上,记事本® 是一种常见的选择,但对大型文件的支持并不相同。Windows 上的另一个建议是安装 Linux (WSL) 的 Windows 子系统,它允许您安装 Linux 发行版,并这样,可以访问命令,就像更少。 51 | 52 | 件的格式取决于设置。清单 9-1 显示了一个默认格式的 aevent 示例,long_query_time = 0 来记录所有查询。请注意,由于页面宽度有限,某些行已换行。 53 | 54 | ``` 55 | Listing 9-1. A slow query log event in the default format 56 | # Time: 2019-09-17T09:37:53.269881Z 57 | # User@Host: root[root] @ localhost [::1] Id: 22 58 | # Query_time: 0.032531 Lock_time: 0.000221 Rows_sent: 10 Rows_examined: 4089 59 | SET timestamp=1568713073; 60 | SELECT CountryCode, COUNT(*) FROM world.city GROUP BY CountryCode ORDER BY 61 | COUNT(*) DESC LIMIT 10; 62 | ``` 63 | 64 | 第一行显示执行查询时。这是您可以控制 UTC 或系统时间是否与"系统"选项一起log_timestamp戳。第二行显示哪个帐户执行了查询和连接 ID。第三行包括查询的一些基本统计信息:查询执行时间、等待锁所花费的时间、返回客户端的行数以及检查的行数。 65 | 66 | SET 时间戳查询设置自纪元以来的秒数(1970年1月1日 00:00:00 UTC)测量的查询的时间戳,最后慢速查询位于最后一行。 67 | 68 | 在统计信息中,查询时间和检查行数与发送行数之间的比率特别令人感兴趣。与返回的行数相比,检查的行数越小,通常有效的索引就越小。但是,您应始终查看查询上下文中的信息。在这种情况下,查询查找了包含最多城市的十个国家/地区代码。如果无法执行完整表或索引扫描,则无法找到任何方法,因此在这种情况下,检查的行与发送行数的比率差是有充分理由的。 69 | 70 | 如果在版本 log_slow_extra 8.0.14 及更晚版本中启用了此项,则获得查询的其他信息,如清单 9-2 所示。 71 | 72 | ``` 73 | Listing 9-2. Using log_slow_extra with the slow query log 74 | # Time: 2019-09-17T10:09:50.054970Z 75 | # User@Host: root[root] @ localhost [::1] Id: 22 76 | # Query_time: 0.166589 Lock_time: 0.099952 Rows_sent: 10 Rows_examined: 77 | 4089 Thread_id: 22 Errno: 2336802955 Killed: 0 Bytes_received: 0 Bytes_ 78 | sent: 0 Read_first: 1 Read_last: 0 Read_key: 1 Read_next: 4079 Read_ 79 | prev: 0 Read_rnd: 0 Read_rnd_next: 0 Sort_merge_passes: 0 Sort_range_ 80 | count: 0 Sort_rows: 10 Sort_scan_count: 1 Created_tmp_disk_tables: 81 | 0 Created_tmp_tables: 0 Start: 2019-09-17T10:09:49.888381Z End: 82 | 2019-09-17T10:09:50.054970Z 83 | SET timestamp=1568714989; 84 | SELECT CountryCode, COUNT(*) FROM world.city GROUP BY CountryCode ORDER BY 85 | COUNT(*) DESC LIMIT 10; 86 | ``` 87 | 88 | 从性能角度看,主要兴趣的统计数据是一项从Bytes_received开始,以Created_tmp_tables。其中一些统计信息相当于查询Handler_% 的状态变量。在这种情况下,您可以看到,Read_next计数器是大量检查行的主要原因。Read_next用于扫描索引以查找行,因此可以确定查询执行索引扫描。 89 | 90 | 如果您需要知道在给定时间执行的内容,查看原始事件可能非常有用。如果您更感兴趣的是了解哪些查询一般对系统负载贡献最大,则需要聚合数据。 91 | 92 | 93 | 94 | ## 聚合 95 | 96 | 可以使用 mysqldumpslow(微软 Windows 上的 mysqldumpslow.pl)脚本聚合慢查询日志中的数据。该脚本包含在 MySQL安装。mysqldumpslow 是一个 Perl 脚本,默认情况下,它通过将数值替换为 N 和字符串值替换为"S"来规范化日志中的查询。这允许脚本以类似于性能架构中"events_statements_summary_by_digest中操作的方式聚合查询。 97 | 98 | ------ 99 | 100 | **注意** 脚本要求将 Perl 安装在您的系统上。这不是 Linux 和 Unix 的问题, Perl 始终存在, 但在 Microsoft Windows 上, 您需要自己安装 Perl。一种选择是安装草莓从http://strawberryperl.com/。 101 | 102 | ------ 103 | 104 | 有几个选项来控制 mysqldumpslow 的行为。这些在表 9-2 中已实现。此外,慢查询日志文件可以作为无选项名称的参数给出。 105 | 106 | | Option | 默认值 | 描述 | 107 | | :------ | ------ | ---- | 108 | | -a | | | 109 | | --debug | | | 110 | | -g | | | 111 | | -h | | | 112 | | --help | | | 113 | | -i | | | 114 | | | | | 115 | | | | | 116 | | | | | 117 | | | | | 118 | | | | | 119 | | | | | 120 | 121 | -s、-t 和 -r 选项是最常用的选项。虽然 mysqldumpslow 可以在默认路径和主机名中使用 MySQL 配置文件搜索慢速查询日志,但更常见的是将慢速查询日志文件的路径指定为命令行上的参数。 122 | 123 | -s选项用于指定如何对结果中包含的查询进行排序。 对于某些排序选项,可以在使用总计和平均值之间进行选择。 排序选项在表9-3中列出,也可以从mysqldumpslow --help输出中获得。 “总计”列指定用于按总数排序的选项,而“平均值”列显示用于按平均值排序的选项。 124 | 125 | | Total | Average | 描述信息 | 126 | | ----- | ------- | -------- | 127 | | c | | | 128 | | l | al | | 129 | | r | ar | | 130 | | t | at | | 131 | 132 | 有时,使用不同的排序选项生成多个报表,以便更好地了解实例上执行的查询情况可能很有用。 133 | 134 | 作为案例研究,请考虑从空慢速查询日志文件开始的实例;然后执行清单 9-3 中的查询。这些查询执行long_query_time设置为 0,会话用于记录所有查询,这对于避免长时间执行查询非常有用。 135 | 136 | ``` 137 | Listing 9-3. The queries used to create slow query log events for a case study 138 | SET GLOBAL slow_query_log = ON; 139 | SET long_query_time = 0; 140 | SELECT * FROM world.city WHERE ID = 130; 141 | SELECT * FROM world.city WHERE ID = 131; 142 | SELECT * FROM world.city WHERE ID = 201; 143 | SELECT * FROM world.city WHERE ID = 2010; 144 | SELECT * FROM world.city WHERE ID = 1; 145 | SELECT * FROM world.city WHERE ID = 828; 146 | SELECT * FROM world.city WHERE ID = 131; 147 | SELECT * FROM world.city WHERE CountryCode = 'AUS'; 148 | SELECT * FROM world.city WHERE CountryCode = 'CHN'; 149 | SELECT * FROM world.city WHERE CountryCode = 'IND'; 150 | SELECT * FROM world.city WHERE CountryCode = 'GBR'; 151 | SELECT * FROM world.city WHERE CountryCode = 'USA'; 152 | SELECT * FROM world.city WHERE CountryCode = 'NZL'; 153 | SELECT * FROM world.city WHERE CountryCode = 'BRA'; 154 | SELECT * FROM world.city WHERE CountryCode = 'AUS'; 155 | SELECT * FROM world.city WHERE CountryCode = 'DNK'; 156 | SELECT * FROM world.city ORDER BY Population DESC LIMIT 10; 157 | SELECT * FROM world.city ORDER BY Population DESC LIMIT 4; 158 | SELECT * FROM world.city ORDER BY Population DESC LIMIT 9; 159 | ``` 160 | 161 | 对于WHERE子句或LIMIT子句,存在三个具有不同值的基本查询。首先,城市由主键找到,主键将搜索一行,以便返回一行。其次,城市由作为次要索引的国家代码找到,因此找到几行,但仍检查与返回的行数相同。第三,所有城市都经过检查,以返回人口最多的城市。 162 | 163 | 假设慢速查询日志文件名为 mysql 慢速.log,并且您正在从文件位于的同一目录执行mysqldumpslow,那么您可以对查询进行分组,并按查询的执行时间进行排列,如清单 9-4 所示。-t 选项用于将报表限制为包含三个(规范化)查询。 164 | 165 | ``` 166 | Listing 9-4. Using mysqldumpslow to sort the queries by count 167 | shell$ mysqldumpslow -s c -t 3 mysql-slow.log 168 | Reading mysql slow query log from mysql-slow.log 169 | Count: 9 Time=0.00s (0s) Lock=0.00s (0s) Rows=150.1 (1351), root[root] 170 | @localhost 171 | SELECT * FROM world.city WHERE CountryCode = 'S' 172 | Count: 7 Time=0.02s (0s) Lock=0.00s (0s) Rows=1.0 (7), root[root] 173 | @localhost 174 | SELECT * FROM world.city WHERE ID = N 175 | Count: 3 Time=0.00s (0s) Lock=0.00s (0s) Rows=7.7 (23), root[root] 176 | @localhost 177 | SELECT * FROM world.city ORDER BY Population DESC LIMIT N 178 | ``` 179 | 180 | 请注意,如何修改 WHERE 和限制子句以使用 N 和"S"。查询时间列为 Time=0.00s (0s),其中具有平均查询时间(0.00s)和括号中的总时间。与锁和行统计信息类似。 181 | 182 | 由于 mysqldumpslow 脚本是用 Perl 编写的,因此如果您想要包含对新排序选项的支持或更改输出,则修改脚本相对容易。例如,如果您想要在平均执行时间中包含更多的小数,可以在使用子例程(包含 MySQL 8.0.18 的脚本中的第 168-169 行)之前修改 printf 语句,例如 183 | 184 | ```perl 185 | printf "Count: %d Time=%.6fs (%ds) Lock=%.2fs (%ds) Rows=%.1f (%d), 186 | $user\@$host\n%s\n\n", 187 | $c, $at,$t, $al,$l, $ar,$r, $_; 188 | ``` 189 | 190 | 更改位于第一行的时间=%.6fs 部分。这将用微秒打印平均执行时间。 191 | 192 | ## 总结 193 | 194 | 本章展示了如何使用慢速查询日志来收集有关在 MySQL 实例上执行的查询的信息。慢速查询日志侧重于根据执行时间和是否使用索引(在实践中是执行完整表还是索引扫描)捕获查询。慢速查询日志与性能架构的主要优点是,日志包括执行的确切语句,并且该语句是保留的。缺点是开销,并且很难获得报告返回您感兴趣的查询。 195 | 196 | 首先,讨论了用于配置慢速查询日志的配置选项。有控制最小执行时间的选项,无论是否使用索引的查询应记录,而不考虑要记录的查询类型等。在 MySQL 8.0.14 及更晚log_slow_extra,您可以使用该版本来包含有关慢速查询的更详细了解信息。 197 | 198 | 其次,讨论了慢查询日志事件的两个示例。 有一个示例使用默认信息,而一个示例启用了log_slow_extra。 如果您要查找在给定时间点执行的查询的信息,则原始事件可能会很有用。 对于更一般的查询,使用mysqldumpslow脚本聚合数据更为有用。 上一节讨论了mysqldumpslow的用法。 199 | 200 | 下一部分介绍一些在性能调优中有用的工具,从使用 MySQL 企业监视器作为示例讨论监视开始。 -------------------------------------------------------------------------------- /第3部分-工具/Chapter10.md: -------------------------------------------------------------------------------- 1 | # MySQL企业监控器 2 | 3 | 监视是性能调优的基石之一,无论您是在系统还是查询级别查看性能。本章将介绍 MySQL、MySQL 企业监视器(也称为MEM)可用的监视解决方案之一。 4 | 5 | 本章首先概述MySQL企业监视器的体系结构和原则。然后有一个部分与安装说明,如果你想尝试 MySQL 企业监视器,然后讨论启动和停止服务管理器以及如何将 MySQL 实例添加到受监视的实例列表中。最后,还有用户界面的游览。 6 | 7 | 本书的其余部分使用 MySQL 企业监视器的图形和报告来分析监视工具的使用,但您也可以使用其他监视解决方案。如果您对 MySQL 企业监视器不感兴趣,可以跳过本章。 8 | 9 | ## Overview 10 | 11 | MySQL 企业监视器是 Oracle 的监控解决方案,专用于 MySQL。它可作为 MySQL 服务器的配套提供给客户,由 MySQL 开发团队开发。 12 | 13 | ------ 14 | 15 | **注意** MySQL 企业监视器要求 MySQL 企业版或 MySQLCluster CGE(运营商级版)订阅在 30 天试用期之后使用(另请参阅下一节中的下载说明)。您可以在一个数据库查看MySQLwww.mysql.com/products/enterprise/。 16 | 17 | ------ 18 | 19 | MySQL 企业监视器由组件组成,每个组件都在其整个监控解决方案中发挥作用。在版本 8 中,有两个主要组件: 20 | 21 | - 服务管理器:此组件存储收集的指标,并提供前端界面来查看数据和管理配置。服务管理器由两部分组成,即 aTomcat 服务器,它是服务管理器的应用程序端,而存储库是存储数据的 MySQL 数据库。 22 | - 代理:MySQL 企业监视器使用代理连接到受监视的 MySQL 实例。服务管理器包括一个内置代理,默认情况下,该代理监视存储库。代理可以监视本地操作系统以及本地和远程MySQL实例。 23 | 24 | ------ 25 | 26 | **注意**:本书遵循 MySQL 企业监视器 (https://dev.mysql.com/doc/mysql-monitor/en/) https://dev.mysql.com/doc/mysql-monitor/en/编写服务管理器和代理的约定。 27 | 28 | ------ 29 | 30 | 由于代理只能监视它运行的操作系统(如 CPU 和内存使用情况、磁盘容量等指标),因此最好在监视 MySQL 实例的每个主机上安装 Agent。这将允许您将主机指标与 MySQL 活动关联。例如,如果您无法在本地安装 Agent,例如,如果您使用的云解决方案不允许您访问操作系统,可以使用安装在另一个主机上的代理来监视 MySQL 指标。在这种情况下,一个选项是使用服务管理器中的内置代理。图 10-1 显示了一个具有三个主机的设置示例,其中一个用于 ServiceManager,两个主机安装了受监视的 MySQL 实例。 31 | 32 | ![](../附图/Figure%2010-1.png) 33 | 34 | 顶部的主机是安装 MySQL 企业监视器服务管理器的主机。它由前端(此处用带图表的网页描述)以及内置的代理和存储库组成。内置代理监视存储库,并监视其他 MySQL 实例(图中未显示),如果您无法访问主机(某些云产品的情况),或者如果您正在测试并想要监视与安装服务管理器相同的主机上的第二个 MySQL 实例,则这些实例非常有用。 35 | 36 | 主机 1 和主机 2 是安装了 MySQL 服务器的两台主机。每个主机上都安装了 MySQL 企业监视器代理。代理查询 MySQL 实例的指标,然后将指标发送到服务管理器,服务管理器将指标存储到数据中。服务管理器还可以向代理发送请求,例如,运行临时报告或更改代理收集指标的频率。 37 | 38 | 对于服务管理器和代理以及 usesa 客户安装程序,安装过程类似。下一节介绍如何安装服务管理器。如果要尝试,该练习将留给读者安装 Agent。 39 | 40 | ## 安装 41 | 42 | MySQL 企业监视器的安装非常简单,尽管与其他 MySQL 产品不同。如果您使用 MySQL 的社区版本,则下载软件与可能习惯的软件不同,并且安装始终通过专用安装程序完成。本节将指导您完成 MySQL 企业监视器的下载、安装过程和设置。 43 | 44 | ### 下载 45 | 46 | 安装的第一步是下载 MySQL 企业监视器。有两个地方可以下载 MySQL 企业监视器。现有 MySQL 客户可以从"我的 Oracle 支持 (MOS)"中的"修补程序和更新"选项卡下载它。这是客户推荐的位置,因为修补程序和更新会更新得更频繁,并且包括自 2011 年以来的所有版本。另一个位置是位于此位置的 Oracle 软件交付云https://edelivery.oracle.com/它还允许注册用户下载 30 天的试用版。这些说明涵盖 Oracle 软件交付云。 47 | 48 | ------ 49 | 50 | **注意** 有一段时间未使用的新帐户和帐户可能需要经过导出验证,可能需要几天时间。 51 | 52 | ------ 53 | 54 | 您从“主页”开始,如图10-2所示。 55 | 56 | ![](../附图/Figure%2010-2.png) 57 | 58 | 59 | 60 | 如果没有登录名,则需要使用"新用户"创建新用户?注册这里图标。登录后,您将进入搜索页面。图 10-3 显示了搜索表单的一部分。 61 | 62 | ![](../附图/Figure%2010-3.png) 63 | 64 | 选择文本字段左侧的拖放框中的"释放"。如果您也有兴趣使用其他产品,请将它留在包含软件包的所有类别的默认值上。在文本字段中,输入 MySQL 企业监视器,然后单击显示的搜索列表中的 MySQL 企业监视器,或单击文本字段右侧的"搜索"按钮(图中既不显示列表也不显示按钮)。然后单击 MySQL 企业监视器结果旁边的"添加到购物车"。 65 | 66 | 将产品添加到购物车后,可以单击页面右上右侧附近的结帐链接(图中未显示)。下一个屏幕显示在图10-4中,并允许您选择要下载的平台。 67 | 68 | ![](../附图/Figure%2010-4.png) 69 | 70 | 选择您感兴趣的平台。如果您计划在一个平台上使用 Agent 来监视另一个平台上安装的实例时,将 ServiceManager 放在一个平台上,则需要选择这两个平台。当您决定要下载哪些平台时,请单击"继续"。 71 | 72 | 下一步是接受许可协议。接受前请仔细阅读。Oracle 试用许可协议位于文档末尾。接受条款和条件后,单击"继续"。 73 | 74 | ------ 75 | 76 | **注意**:您可能会被要求完成有关 Oracle 软件交付云可用性的调查,作为步骤之一。 77 | 78 | ------ 79 | 80 | 最后一步是选择要下载的 MySQL 企业监视器的哪些部分。如图 10-5 所示。 81 | 82 | ![](../附图/Figure%2010-5.png) 83 | 84 | 每个平台有两个包,服务管理器有一个包,代理有一个包。可选(推荐),您可以单击屏幕截图中心底部的"查看摘要详细信息"链接,以显示每个文件的 SHA-1 和 SHA-256 校验和。您可以使用这些来验证下载成功完成。 85 | 86 | 您可以通过两种方式下载文件。如果单击文件名,则一个下载文件。或者,检查所需的文件,然后单击下载按钮,使用下载管理器开始下载。如果您没有安装下载管理器,将在下载开始前完成安装。 87 | 88 | ------ 89 | 90 | **提示** Oracle 软件交付云使用通用文件名,如 V982880-01.zip。将文件重命名为包含有关您下载的产品、平台和版本的信息的名称非常有用。 91 | 92 | ------ 93 | 94 | 95 | 96 | ### 安装过程 97 | 98 | MySQL 企业监视器使用自己的安装程序,该安装程序在所有平台上都工作相同。有人支持通过图形用户界面或文本模式使用向导模式执行安装,或者您可以在命令行上提供所有参数并使用无人值守模式。 99 | 100 | 下载的文件的名称取决于您下载的平台和 MySQL 企业监视器的版本。例如,Microsoft Windows 的服务管理器版本 8.0.17 被命名为 V982881-01.zip。其他文件的名称类似。如果解压缩 ZIP 文件,将找到多个文件: 101 | 102 | ``` 103 | PS> ls | select Length,Name 104 | Length Name 105 | ------ ---- 106 | 6367299 monitor.a4.pdf 107 | 6375459 monitor.pdf 108 | 5275639 mysql-monitor-html.tar.gz 109 | 5300438 mysql-monitor-html.zip 110 | 281846252 mysqlmonitor-8.0.17.1195-windows64-installer.exe 111 | 281866739 mysqlmonitor-8.0.17.1195-windows64-update-installer.exe 112 | 975 README_en.txt 113 | 975 READ_ME_ja.txt 114 | ``` 115 | 116 | 确切的文件名和大小取决于平台和 MySQL 企业监视器版本。请注意,有两个可执行文件,在此例中为 mysqlmonitor8.0.17.1195-windows64-安装程序.exe 和 mysqlmonitor-8.0.17.1195-windows64-更新安装程序.exe。前者用于从刮刮安装 MySQL 企业监视器,而另一个(有时也称为更新安装程序)用于执行现有安装的升级。PDF 和 HTML 文件是手册,但您通常最好在 https://dev.mysql.com/doc/mysqlmonitor/en/ 使用在线手册,因为定期更新。 117 | 118 | ------ 119 | 120 | **提示** 如果要使用基于文本的向导或无人参与模式,请使用 --help 参数调用安装器以获取受支持的参数列表。 121 | 122 | ------ 123 | 124 | 此讨论将继续使用图形用户界面进行安装。通过执行安装程序以没有任何参数来启动安装。第一步是选择语言(提供英语、日语和简体中文)。然后,您被告知,您需要确保将安装过程中输入的用户名和密码保留在安全位置。 125 | 126 | 通过欢迎屏幕后,配置将按正确的方式开始,通过指定安装位置。在 Microsoft Windows 上,默认位置是 C:\Program FilesMySQL[企业]监视器,在 Linux 上,当作为根用户安装时,默认位置是 /opt/mysql/企业/监视器,当安装为非特权用户时,它是相对于主目录的 mysql/企业/监视器。 127 | 128 | 图 10-6 中显示的下一个屏幕要求您选择要监视的系统大小。 129 | 130 | ![](../附图/Figure%2010-6.png) 131 | 132 | 系统大小确定服务管理器内存配置等的默认设置。安装完成后,您可以手动调整内存设置,但选择正确的系统大小意味着您最初不必担心这些设置。除非只想尝试 MySQL 企业监视器与几个实例,选择中型或大型系统。 133 | 134 | 接下来,您需要指定要使用的端口号。MySQL 企业监视器使用前端的Tomcat服务器,端口18080作为默认未加密端口,18443作为默认SSL端口。您将始终使用 SSL 端口。(出于遗留原因,非 SSL 端口无法用于前端。 135 | 136 | 此时,如果您使用根帐户在 Linux 上安装,系统会询问要在哪个用户帐户下运行 Tomcat 进程(MySQL 服务器存储进程将使用 mysql 用户)。默认值为 mysqlmem。如果您使用非根帐户在 Linux 上安装,系统将通知您安装者无法设置自动启动。 137 | 138 | 服务管理器使用 MySQL 实例来存储数据,包括收集的计量。在使用与安装程序捆绑的 MySQL 实例和使用现有的 MySQL 实例之间,您有一个选择(参见图 10-7)。 139 | 140 | ![](../附图/Figure%2010-7.png) 141 | 142 | 除非您有充分的理由选择其他方法,否则建议使用捆绑的 MySQL 数据库。这不仅允许安装程序使用已知与服务管理器很好地工作的基本配置,还简化了升级。 143 | 144 | ------ 145 | 146 | **注意** 不要想使用要监视的 MySQL 实例作为服务管理器的存储库。MySQL 企业监视器确实会导致大量数据库活动,如果您使用生产数据库,如果该数据库应该监视关闭,则监视将停止工作。 147 | 148 | ------ 149 | 150 | 现在,您可以选择 ServiceManager 使用到 MySQL 实例的连接的用户名和密码以及端口号和架构名称。如图 10-8 所示。 151 | 152 | ![](../附图/Figure%2010-8.png) 153 | 154 | ## 启动和停止服务管理器 155 | 156 | 服务管理器设计为作为服务启动和停止。在 Microsoft Windows 上,当您使用 Linux上的根帐户安装服务管理器时,安装程序将始终为你安装服务。如果在 Linux 上将其安装为非根用户,可以手动执行服务脚本以启动和停止服务管理器。 157 | 158 | ### 微软视窗 159 | 160 | 在上,安装程序始终要求管理员权限运行,这意味着它也可以将服务管理器进程安装为服务。默认情况下,服务设置为在启动和关闭计算机时自动启动和停止。 161 | 162 | 您可以通过打开服务应用程序来编辑服务的设置。在 Windows 10 上,最简单的方法是使用键盘上的 Windows 键(或者通过单击左下角的 Windows 图标打开"开始"菜单服务,如图。 163 | 164 | ![](../附图/Figure%2010-12.png) 165 | 166 | 与屏幕截图相比,搜索结果可能看起来会有所不同。单击""下的"服务这将打开您可以控制服务的应用程序。在服务应用程序中,您可以通过启动、停止、暂停或重新启动服务来控制服务。存储库服务名为服务名为如图。 167 | 168 | ![](../附图/Figure%2010-13.png) 169 | 170 | 单击服务时,获取服务列表左侧窗格中的基本控件操作。您还可以右键单击服务以获取操作以及编辑服务属性的选项。这些包括是否自动启动和停止服务。 171 | 172 | ### Linux 173 | 174 | 在上启动和停止 MySQL 企业监视器的方式取决于您是否使用根执行了安装。如果使用根用户使用服务启动和停止进程(没有对的本机支持);否则,mysqlmonitorctl.sh底部的脚本。无论哪种方式,都可以添加或参数,以更改其中一个进程的状态。 175 | 176 | 清单显示了如何使用启动、重新启动和停止 MySQL 企业监视器。 177 | 178 | ``` 179 | Listing 10-1. Changing the status of the services with the service command 180 | shell$ sudo service mysql-monitor-server start 181 | Starting mysql service [ OK ] 182 | 2019-08-24T06:45:43.062790Z mysqld_safe Logging to '/opt/mysql/enterprise/ 183 | monitor/mysql/data/ol7.err'. 184 | 2019-08-24T06:45:43.168359Z mysqld_safe Starting mysqld daemon with 185 | databases from /opt/mysql/enterprise/monitor/mysql/data 186 | Starting tomcat service [ OK ] 187 | shell$ sudo service mysql-monitor-server restart 188 | Stopping tomcat service . [ OK ] 189 | Stopping mysql service 2019-08-24T06:47:57.907854Z mysqld_safe mysqld from 190 | pid file /opt/mysql/enterprise/monitor/mysql/runtime/mysqld.pid ended 191 | . [ OK ] 192 | Starting mysql service [ OK ] 193 | 2019-08-24T06:48:04.441201Z mysqld_safe Logging to '/opt/mysql/enterprise/ 194 | monitor/mysql/data/ol7.err'. 195 | 2019-08-24T06:48:04.544643Z mysqld_safe Starting mysqld daemon with 196 | databases from /opt/mysql/enterprise/monitor/mysql/data 197 | Starting tomcat service [ OK ] 198 | shell$ sudo service mysql-monitor-server stop tomcat 199 | Stopping tomcat service . [ OK ] 200 | shell$ sudo service mysql-monitor-server stop mysql 201 | Stopping mysql service 2019-08-24T06:48:54.707288Z mysqld_safe mysqld from 202 | pid file /opt/mysql/enterprise/monitor/mysql/runtime/mysqld.pid ended 203 | . [ OK ] 204 | ``` 205 | 206 | 首先,启动两个服务,然后重新启动,最后一个停止服务。无需一个多个停止服务,但如果需要对存储库进行维护,则它非常有用。 207 | 208 | 清单显示了使用。 209 | 210 | ``` 211 | Listing 10-2. Changing the status of the services with mysqlmonitorctl.sh 212 | shell $ ./mysqlmonitorctl.sh start 213 | Starting mysql service [ OK ] 214 | 2019-08-24T06:52:34.245379Z mysqld_safe Logging to '/home/myuser/mysql/ 215 | enterprise/monitor/mysql/data/ol7.err'. 216 | 2019-08-24T06:52:34.326811Z mysqld_safe Starting mysqld daemon with 217 | databases from /home/myuser/mysql/enterprise/monitor/mysql/data 218 | Starting tomcat service [ OK ] 219 | shell$ ./mysqlmonitorctl.sh restart 220 | Stopping tomcat service . [ OK ] 221 | Stopping mysql service 2019-08-24T06:53:08.292547Z mysqld_safe mysqld from 222 | pid file /home/myuser/mysql/enterprise/monitor/mysql/runtime/mysqld.pid 223 | ended 224 | . [ OK ] 225 | Starting mysql service [ OK ] 226 | 2019-08-24T06:53:15.310640Z mysqld_safe Logging to '/home/myuser/mysql/ 227 | enterprise/monitor/mysql/data/ol7.err'. 228 | 2019-08-24T06:53:15.397898Z mysqld_safe Starting mysqld daemon with 229 | databases from /home/myuser/mysql/enterprise/monitor/mysql/data 230 | Starting tomcat service [ OK ] 231 | shell$ ./mysqlmonitorctl.sh stop tomcat 232 | Stopping tomcat service . [ OK ] 233 | shell$ ./mysqlmonitorctl.sh stop mysql 234 | Stopping mysql service 2019-08-24T06:54:39.592847Z mysqld_safe mysqld from 235 | pid file /home/myuser/mysql/enterprise/monitor/mysql/runtime/mysqld.pid 236 | ended 237 | . [ OK ] 238 | ``` 239 | 240 | 241 | 242 | 步骤与 Service 命令的上一个。实际上,服务命令调用的脚本与 mysqlmonitorctl.sh 脚本,只是其中的路径和用户名取决于用于安装服务管理器和安装路径的操作用户。 243 | 244 | ## 添加 MySQL 实例 245 | 246 | 如果您只想使用 MySQL 企业监视器,则无需执行任何比现在更多的工作。服务管理器的内置代理将自动监视存储库实例,因此当您第一次登录到用户界面时,已经有可用的监视数据。如果您安装了代理,代理还将注册它自动监视的实例。本节将讨论的最后一个选项是从用户界面添加实例。 247 | 248 | 如果要添加监视的 MySQL 实例与服务管理器或现有代理安装在同一主机,则会自动检测到该实例,并且页面右上角的带有海豚和问号的图标将突出显示,如图。 249 | 250 | ![](../附图/Figure%2010-14.png) 251 | 252 | 请注意,它如何表示海豚的右侧有一个(黄色)圆圈中的问号。这是已找到但未受监视的 MySQL 实例数。将鼠标悬停在图标上时,将显示一个实例数。如果您单击海豚或数字,它将带您到 MySQL 实例配置屏幕,您也可以通过左侧窗格中的菜单访问该屏幕。 253 | 254 | ------ 255 | 256 | **注意**: 通过用户界面添加的实例将受到现有代理(如果您自己未安装任何代理的内置代理)的监视。 只有安装了代理的那些系统才会监视其操作系统。 257 | 258 | ------ 259 | 260 | 实例配置屏幕都包括添加新实例的选项,由MySQL Enterprise Monitor找到的不受监视的实例的列表以及受监视的实例的列表。 图[10 15](#Fig15)显示了与开始监视新实例和不受监视实例有关的页面部分。 261 | 262 | ![](../附图/Figure%2010-15.png) 263 | 264 | 您可以使用页面顶部的"添加实例"或 来添加对任何 MySQL 实例的监视。如果要监视的实例列在"未监视的 MySQL 实例"列表中,您也可以选择该实例并单击"监视器实例该按钮将带您到与,其区别在于已知连接设置已预填充。该窗体有几个选项卡,其中""选项卡如图。 265 | 266 | ![](../附图/Figure%2010-16.png) 267 | 268 | 关于连接设置,需要注意的主要操作是,您可以选择让 MySQL 企业监视器自动创建具有比用于设置监视的管理员用户更少的权限的用户。建议允许创建这些用户,因为它允许代理使用具有尽可能少权限的用户执行其任务。 269 | 270 | 如果您有加密要求,您可以在"加密设置"选项卡中要求。很少需要"高级设置"选项卡。如果要设置多个实例的监视,则可能需要在"组设置"选项卡中为实例指定一个组。这些设置也可以在添加实例后更改。 271 | 272 | 添加实例需要一点时间。准备就绪后,您可以开始探索用户界面的其余部分。 273 | 274 | ## 图形用户界面 275 | 276 | 服务管理器的是您将花费大部分时间使用 MySQL 企业监视器的地方。如您已经看到,它可用于添加新实例。本节将进一步深入探讨用户界面,并讨论一般导航、顾问、时间序列图和查询分析器。 277 | 278 | ### 一般导航 279 | 280 | MySQL 企业用户界面将功能划分为逻辑组,支持按组、主机、代理或实例进行筛选。本节将简要介绍界面,目的是在本书的稍后部分提及图形或报表时,如果您想要更仔细地探索图形或报表,可以在界面中找到它们。 281 | 282 | 图显示了用户界面中页面的左上角部分。这是选择要访问的功能以及要显示数据的目标。 283 | 284 | ![](../附图/Figure%2010-17.png) 285 | 286 | 要素的导航位于左侧窗格中,筛选器应用于页面顶部的两个搜索字段中。屏幕截图中标有"的搜索字段允许您选择一组实例。可以手动创建组,也可以为彼此之间复制的实例自动创建组。一个包含所有实例的特殊组。右侧搜索字段允许您限制组中包含的实例、代理或主机。 287 | 288 | 包括仪表板、图形、报表等。可用功能列表取决于您应用的筛选器。菜单项是 289 | 290 | - 这是一个高级仪表板。 291 | - 此选项仅在选择复制组时可用。它带您到显示组拓扑的图表,该图的状态为每个实例的复制。 292 | - 返回实例的监视事件的报告。当满足顾问(更不久)设定的某些条件时,将引发事件。事件的严重程度从通知到紧急情况不等。 293 | - 这将带您访问显示代理收集的指标的报表。无论筛选器如何,时间序列图始终可用(但哪些图表取决于筛选器)。对于单个实例,还有用于表统计信息、用户统计信息、内存使用情况、数据库文件 I/O、InnoDB 缓冲池、进程和锁定等待的报告。其中一些报告将在后几章中使用。 294 | - 这是 MySQL 查询分析器,它允许您调查在实例上执行哪些查询。时间序列图链接到查询分析器,因此可以从检查图表到查看在所调查期间执行哪些查询。 295 | - 复制仪表板和其他与复制相关的报表。 296 | - 有关由 MySQL 企业备份 (MEB) 创建的备份的信息。 297 | - 配置 MySQL 企业监视器的各个方面,包括实例和顾问。 298 | - 文档包括您已查看的"更新"和下载可用于解决问题的诊断报告。如果您有 MySQL 支持合同,并且需要在支持票证中提供诊断,因此主要使用诊断报告。 299 | 300 | 一个需要进一步解释的术语是顾问。 301 | 302 | ### 顾问 303 | 304 | 是 MySQL 企业监视器用于定义收集数据的频率、哪些条件触发事件以及事件的严重性的规则的名称。这是一个重要的概念,您应该花一些时间来理解和配置。 305 | 306 | 获得有用的监视解决方案最重要的步骤之一是确保您及时获得正确的事件(警报),但避免不必要的事件。这包括确保将每个警报设置为适当的严重性。你一开始可能会认为事件越好越好,这样你就知道发生的一切。但是,这不是您最好使用监控系统的一种方式。如果您检查事件时有许多误报,或者在凌晨 3:00 被不必要地唤醒,因为问题很容易等到早上,那么您就开始忽略事件,这肯定是迟早会错过重要事件的秘诀。简言之,您与顾问的工作应该持续不断,以不断改进,以在"正确"的时间触发"正确的"事件。 307 | 308 | 可以在左侧窗格中的"项下配置顾问。顾问按组组织,如图。 309 | 310 | ![](../附图/Figure%2010-18.png) 311 | 312 | 每个组类似类型的顾问,例如,有 22 个顾问的绩效组,例如锁定进程数量过多和索引未得到有效使用。 313 | 314 | 默认情况下,所有顾问都启用了将严重性级别设置为在许多情况下工作良好的值的阈值。但是,由于没有两个系统是相同的,因此您需要通过展开组并单击顾问名称左侧的菜单图标来微调设置,如图。 315 | 316 | ![](../附图/Figure%2010-19.png) 317 | 318 | 您还可以使用顾问左侧的 + 图标展开顾问,该图标允许您编辑特定实例组或单个实例的顾问。?"信息列中的图标提供了其他信息,如评估的表达式或顾问的数据源。图中未显示其他可用信息。 319 | 320 | ### 时间序列图 321 | 322 | 是显示一段时间指标的图表。这是所有监控解决方案的标准功能。您可以筛选要显示的图形,并更改绘图的时间范围以及绘图样式。 323 | 324 | 图显示了时间序列图页面的一部分,该页面侧重于访问筛选和绘图样式的控件。 325 | 326 | ![](../附图/Figure%2010-20.png) 327 | 328 | 图表上方是选择要显示的图形和图形的时间范围的选项。屏幕截图中左侧的搜索字段允许您在保存的时间序列组之间进行选择。默认情况下,有一个名为组(名称建议)包括适合实例筛选的所有时间序列图形。 329 | 330 | 通过使用屏幕截图右上角图标,可以访问时间序列图形的选项。这将打开一个框架,允许您选择要显示的图形和覆盖的时间范围。 331 | 332 | 每个图形下方的两个小按钮允许您在使用线条和堆叠绘图模式之间切换。屏幕截图显示了最顶层图形中的堆叠模式和下图中的线模式的示例。行模式为默认模式。您还可以使用字段左侧的滑块(不包括在屏幕截图中)更改图形的高度,以在保存的图形组之间进行选择。 333 | 334 | 当您将鼠标悬停在图形上方时,图形上方的三个图标将变为可见,并允许您以 CSV 格式导出图形的数据,以 PNG 图像形式打开图形,或移动图形,以便您按最适合您的方式重新排列图形。在这种情况下,有两个图形分组在一起,这些控件适用于这两个图形。 335 | 336 | 更改图形的时间范围的另一种方法是突出显示感兴趣的图形部分并放大该部分。这还允许您转到查询以检查在此期间执行的查询。图显示了在图形中突出显示时间范围的示例。 337 | 338 | ![](../附图/Figure%2010-21.png) 339 | 340 | 请注意,在突出显示区域的右上角,有三个图标对所选内容的处理。框中的 X 将放弃所选内容,数据库圆柱体打开查询分析器中所选时间帧的图形,放大镜缩放时间序列图形以使用所选时间范围。 341 | 342 | ### 查询分析器 343 | 344 | 查询是使 MySQL 企业监视器脱颖而出的其他监视解决方案的功能。它允许您查看在给定期间中对实例执行哪些查询,这在调查性能问题时非常宝贵。 345 | 346 | 查询分析器页面分为三个方面。在顶部可以访问筛选选项,然后可选地有一个或多个图形,页面的其余部分是语句列表。图显示了这方面的示例。 347 | 348 | ![](../附图/Figure%2010-22.png) 349 | 350 | 在顶部的拖放框语句"显示屏幕截图中允许您选择要显示语句的类型。默认值是包括所有语句。右侧是"配置按钮,该按钮将带您到页面,您可以在其中配置如何配置查询分析器页面。这包括要覆盖的时间范围、要显示的图形、筛选选项以及每个语句要包含哪些信息。 351 | 352 | 默认情况下,查询分析器包括查询响应时间索引 (QRTi) 的图形。当查询分析器用于查找优化候选项时,查询响应时间索引的定义以及如何使用它将在章中介绍。 353 | 354 | MySQL 企业监视器之旅结束。我们鼓励您自己进一步探索用户界面。 355 | 356 | ## 总结 357 | 358 | 本章简要介绍了 MySQL 企业监视器,旨在允许您安装和监视 MySQL 实例。首先,讨论了体系结构和原则的概述。MySQL 企业监视器由一个服务管理器组成,其中聚合了数据,您可以通过用户界面访问监控系统。主机和实例的监视由代理完成。服务管理器中有一个内置代理,您可以在 MySQL 实例的主机上安装其他代理。 359 | 360 | 概述后是下载和安装说明。由于 MySQL 企业监视器是仅商用产品,因此您可以从 Oracle 软件交付云或我的 Oracle 支持下载它。安装使用安装程序完成。本章展示了如何使用服务管理器安装程序中的图形用户界面。 361 | 362 | 启动和停止服务管理器基于将服务管理器安装为服务。在 Linux 和 Unix 上,还可以将服务管理器安装为非根用户,在这种情况下,调用服务命令使用的相同脚本。 363 | 364 | 有两种主要方法可以添加要监视的实例。如果安装代理来监视实例,则代理将注册实例。您还可以从服务管理器的用户界面添加实例。 365 | 366 | 最后,快速浏览了服务管理器的图形用户界面。重点是筛选您看到的数据的实例以及要素列表、时间序列图和查询分析器。其中一些功能将用于演示本书剩余部分的监视。 367 | 368 | 下一章将介绍后几章中使用的另一个有用工具:MySQL Workbench。 -------------------------------------------------------------------------------- /第3部分-工具/Chapter11.md: -------------------------------------------------------------------------------- 1 | # MySQL Workbench 2 | 3 | 是 Oracle 用于查询和管理 MySQL 服务器的图形用户界面。它可以被看做是使用 MySQL 的两把瑞士军刀之一,另一把是 MySQL Shell下一章将讨论。 4 | 5 | MySQL Workbench的主要功能是可以执行查询的查询模式。 但是,还有其他一些功能,如性能报告、可视化解释、管理配置和检查架构的能力等。 6 | 7 | 如果将 MySQL Workbench与 MySQL 企业监视器进行比较,则 MySQL 企业监视器专用于监视,是一个服务器解决方案,而 MySQL Workbench是桌面解决方案,主要是用于使用 MySQL 服务器的客户端。同样,MySQL Workbench中包含的监视都是临时监视,而 MySQL 企业监视器作为服务器解决方案包含对存储历史数据的支持。 8 | 9 | 本章将介绍 MySQL Workbench,并介绍安装、基本用法以及如何创建 EER 关系图。性能报告和可视化解释将在后几章中介绍。 10 | 11 | ------ 12 | 13 | 如果您已经熟悉MySQL Workbench,则可以考虑跳过本章或略过本章。 14 | 15 | ------ 16 | 17 | 18 | 19 | ## 安装 20 | 21 | 安装 MySQL Workbench的方式与其他 MySQL 程序相同,只是仅支持使用包管理器(因此没有独立安装)。MySQL Workbench版本号遵循 MySQL 服务器版本,因此 MySQL Workbench 8.0.18 与 MySQL 服务器 8.0.18 同时发布。MySQL Workbench版本支持发布时仍在维护的 MySQL 服务器版本,因此 MySQL Workbench8.0.18 支持连接到 MySQL 服务器 5.6、5.7 和 8。 22 | 23 | 本节将介绍如何在 Microsoft Windows、"企业 Linux 7"(Oracle Linux、红帽企业 Linux 和 CentOS)和 Ubuntu 19.10 上安装 MySQL 工作台的示例。其他 Linux 平台在概念上与两个 Linux 示例类似。 24 | 25 | ### 微软视窗 26 | 27 | 在 Microsoft Windows 上,安装 MySQL Workbench的首选方式是将Windows。如果您安装了其他 MySQL 产品,您可能已经安装了 MySQL 安装程序,在这种情况下,您可以跳过这些说明的第一步,然后单击",该屏幕将您带至图的点。 28 | 29 | 你可以从 。图显示了下载部分。 30 | 31 | ![](../附图/Figure%2011-1.png) 32 | 33 | 安装程序有两种选择。第一个称为Web安装程序只是 MySQL安装程序,还包括 MySQL 服务器。如果您也计划安装 MySQL Server,则选择包含 MySQL 安装程序和 MySQL 服务器的下载是有意义的,因为您避免等待安装程序稍后下载 MySQL 服务器安装文件。此示例假定您选择 Web 安装程序。 34 | 35 | 单击"下载按钮访问下载。如果您尚未登录,它将带您到"开始下载"页面,您可以在登录和立即开始下载进行选择。如图。 36 | 37 | ![](../附图/Figure%2011-2.png) 38 | 39 | 如果您已经拥有帐户,可以登录。否则,您可以选择注册 Oracle 帐户。您也可以选择下载安装程序,而无需登录通过点击"链接。 40 | 41 | 下载完成后,启动下载的文件。除了确认您将允许安装程序和 MySQL 安装程序修改已安装的程序外,无需执行任何操作来安装 MySQL 安装程序。安装完成后,MySQL 安装程序将自动启动安装程序安装的 MySQL 程序,如图。 42 | 43 | ![](../附图/Figure%2011-3.png) 44 | 45 | 如果您没有安装任何 MySQL 程序,您将被带到一个屏幕,要求您确认您同意许可条款。请仔细阅读许可条款,然后再继续。如果您可以接受许可证,请勾选",然后单击标有"下一继续。 46 | 47 | 下一步是选择要安装什么。设置屏幕如图。 48 | 49 | ![](../附图/Figure%2011-4.png) 50 | 51 | You can choose between several bundles such as the developer bundle (called *Developer Default*) which installs the products typically used in a development environment. When you choose a setup type, the description in the right of the screen includes a list of the products that will be installed. For this example, the custom installation type will be used. 52 | 53 | The next step is to choose which products to install. That uses the selector shown in Figure [11-5](#Fig5). 54 | 55 | ![](../附图/Figure%2011-5.png) 56 | 57 | 您可以在"应用程序"下的可用产品列表中找到 MySQL 工作台。单击右侧箭头,将 MySQL 工作台添加到要安装的产品和功能列表中。随意选择其他产品;对于本书,建议也包括 MySQL 雪壳。添加所有需要的产品后,单击"下一步继续。 58 | 59 | 以下屏幕提供了要安装的产品的摘要。单击执行"以启动安装。如果 MySQL 安装程序尚未具有本地副本,安装过程包括下载产品。安装可能需要一点时间才能完成。完成后,单击"下一继续。最终屏幕列出了已安装的程序,并提供了启动 MySQL 工作台和 MySQL 外壳的选项。单击"以关闭 MySQL 安装程序。 60 | 61 | 如果您以后想要安装更多产品或执行升级或删除产品,程序,这将带您到主 MySQL 安装程序屏幕,如图。 62 | 63 | ![](../附图/Figure%2011-6.png) 64 | 65 | 选择要屏幕最右侧执行的操作。操作是 66 | 67 | - 安装产品和功能。 68 | - 更改现有产品的安装。这主要适用于 MySQL 服务器。 69 | - 升级已安装的产品。 70 | - 卸载产品。 71 | - 更新 MySQL 安装程序可用的 MySQL 产品列表。 72 | 73 | 这五个操作允许您执行 MySQL 产品生命周期内所需的所有步骤。 74 | 75 | ### 企业 Linux 7 76 | 77 | 如果使用 Linux,则使用包管理器安装 MySQL 工作台。在 Oracle Linux、红帽企业 Linux 和 CentOS 7 上,首选的软件包管理器是因为它有助于解决您安装或升级的软件包的依赖关系。MySQL 有一个 yum 存储库,用于其社区产品。此示例将演示如何安装它,并使用它来安装 MySQL 工作台。 78 | 79 | 您可以在下一个位置找到存储库 也有 APT 和 SUSE 的存储库。选择与 Linux 发行版对应的文件,然后单击"下载图显示了企业 Linux 7 的文件。 80 | 81 | ![](../附图/Figure%2011-7.png) 82 | 83 | 如果您没有登录,它会将您带至第二个屏幕,例如在 Microsoft Windows 上安装 MySQL 工作台的示例。这将允许您登录到您的 Oracle Web 帐户、创建帐户或下载而无需登录。下载 RPM 文件并保存在要从目录中安装的目录中,或者右键单击"下载"按钮(如果您已登录),或者"否"感谢我的下载链接并复制 URL,如图。 84 | 85 | ![](../附图/Figure%2011-8.png) 86 | 87 | 现在,您可以安装,如清单。 88 | 89 | ``` 90 | Listing 11-1. Installing the MySQL community repository 91 | shell$ wget https://dev.mysql.com/get/mysql80-community-release-el7-3. 92 | noarch.rpm 93 | ... 94 | HTTP request sent, awaiting response... 200 OK 95 | Length: 26024 (25K) [application/x-redhat-package-manager] 96 | Saving to: 'mysql80-community-release-el7-3.noarch.rpm' 97 | 100%[=========================>] 26,024 --.-K/s in 0.001s 98 | 2019-08-18 12:13:47 (20.6 MB/s) - 'mysql80-community-release-el7-3.noarch.rpm' 99 | saved [26024/26024] 100 | Figure 11-8. Copying the link to the repository installation file 101 | shell$ sudo yum install mysql80-community-release-el7-3.noarch.rpm 102 | Loaded plugins: langpacks, ulninfo 103 | Examining mysql80-community-release-el7-3.noarch.rpm: mysql80-communityrelease-el7-3.noarch 104 | Marking mysql80-community-release-el7-3.noarch.rpm to be installed 105 | Resolving Dependencies 106 | --> Running transaction check 107 | ---> Package mysql80-community-release.noarch 0:el7-3 will be installed 108 | --> Finished Dependency Resolution 109 | Dependencies Resolved 110 | ================================================================= 111 | Package 112 | Arch Version 113 | Repository Size 114 | ================================================================= 115 | Installing: 116 | mysql80-community-release 117 | noarch el7-3 /mysql80-community-release-el7-3.noarch 31 k 118 | Transaction Summary 119 | ================================================================= 120 | Install 1 Package 121 | Total size: 31 k 122 | Installed size: 31 k 123 | Is this ok [y/d/N]: y 124 | Downloading packages: 125 | Running transaction check 126 | Running transaction test 127 | Transaction test succeeded 128 | Running transaction 129 | Installing : mysql80-community-release-el7-3.noarch 1/1 130 | Verifying : mysql80-community-release-el7-3.noarch 1/1 131 | Installed: 132 | mysql80-community-release.noarch 0:el7-3 133 | Complete! 134 | ``` 135 | 136 | MySQL Workbench 需要来自 EPEL 存储库的一些包。在 Oracle Linux 7 上,您可以启用它,如 137 | 138 | ``` 139 | sudo yum install oracle-epel-release-el7 140 | ``` 141 | 142 | 143 | 144 | 在红帽企业 Linux 和 CentOS 上,您需要从 Fedora 下载存储库定义: 145 | 146 | ``` 147 | wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm 148 | sudo yum install epel-release-latest-7.noarch.rpm 149 | ``` 150 | 151 | 现在,您可以安装 MySQL Workbench如清单。 152 | 153 | ``` 154 | shell$ sudo yum install mysql-workbench 155 | ... 156 | Dependencies Resolved 157 | ================================================================ 158 | Package Arch Version Repository Size 159 | ================================================================ 160 | Installing: 161 | mysql-workbench-community 162 | x86_64 8.0.18-1.el7 mysql-tools-community 26 M 163 | Transaction Summary 164 | ================================================================ 165 | Install 1 Package 166 | Total download size: 26 M 167 | Installed size: 116 M 168 | Is this ok [y/d/N]: y 169 | Downloading packages: 170 | warning: /var/cache/yum/x86_64/7Server/mysql-tools-community/packages/ 171 | mysql-workbench-community-8.0.18-1.el7.x86_64.rpm: Header V3 DSA/SHA1 172 | Signature, key ID 5072e1f5: NOKEY 173 | Public key for mysql-workbench-community-8.0.18-1.el7.x86_64.rpm is not 174 | installed 175 | mysql-workbench-community-8.0.18-1. | 31 MB 00:14 176 | Retrieving key from file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql 177 | Importing GPG key 0x5072E1F5: 178 | Userid : "MySQL Release Engineering " 179 | Fingerprint: a4a9 4068 76fc bd3c 4567 70c8 8c71 8d3b 5072 e1f5 180 | Package : mysql80-community-release-el7-3.noarch (@/mysql80-communityrelease-el7-3.noarch) 181 | From : /etc/pki/rpm-gpg/RPM-GPG-KEY-mysql 182 | Is this ok [y/N]: y 183 | Running transaction check 184 | Running transaction test 185 | Transaction test succeeded 186 | Running transaction 187 | Installing : mysql-workbench-community-8.0.18-1.el7.x86 1/1 188 | Verifying : mysql-workbench-community-8.0.18-1.el7.x86 1/1 189 | Installed: 190 | mysql-workbench-community.x86_64 0:8.0.17-1.el7 191 | Complete! 192 | ``` 193 | 194 | 例如,您的输出可能看起来不同,具体取决于已安装的包,可能会拉扯依赖项。首次从 MySQL 存储库安装包时,系统将要求您接受用于验证下载的包的 GPG 密钥。如果您从 Fedora 安装了 EPEL 存储库,则还需要接受该存储库中的 GPG 密钥。 195 | 196 | ### Debian和Ubuntu 197 | 198 | 在 Debian 和 Ubuntu 上安装 MySQL 工作台遵循与上一示例相同的原则。对于此处演示的步骤,将使用 Ubuntu 19.10。 199 | 200 | 对于 Debian 和 Ubuntu,您需要安装可以从定义文件下载的 MySQL https://dev.mysql.com/downloads/repo/apt/ 。在编写本文时,只有一个文件可用(参见它独立于体系结构,适用于所有支持的 Debian 和 Ubuntu 版本。 201 | 202 | ![](../附图/Figure%2011-9.png) 203 | 204 | 如果您未登录,您将被带到屏幕上,您可以在登录和立即开始下载之间进行选择。下载 DEB 包或右键单击下载(如果您已登录)或启动我的下载链接并复制 URL,如图。 205 | 206 | ![](../附图/Figure%2011-10.png) 207 | 208 | 现在,您可以安装 MySQL如清单。 209 | 210 | ``` 211 | shell$ wget https://dev.mysql.com/get/mysql-apt-config_0.8.14-1_all.deb 212 | ... 213 | Connecting to repo.mysql.com (repo.mysql.com)|23.202.169.138|:443... connected. 214 | HTTP request sent, awaiting response... 200 OK 215 | Length: 35564 (35K) [application/x-debian-package] 216 | Saving to: 'mysql-apt-config_0.8.14-1_all.deb' 217 | mysql-apt-config_0. 100%[==================>] 34.73K --.-KB/s in 0.02s 218 | 2019-10-26 17:16:46 (1.39 MB/s) - 'mysql-apt-config_0.8.14-1_all.deb' saved 219 | [35564/35564] 220 | Figure 11-10. Copying the link to the repository installation file 221 | shell$ sudo dpkg -i mysql-apt-config_0.8.14-1_all.deb 222 | Selecting previously unselected package mysql-apt-config. 223 | (Reading database ... 161301 files and directories currently installed.) 224 | Preparing to unpack mysql-apt-config_0.8.14-1_all.deb ... 225 | Unpacking mysql-apt-config (0.8.14-1) ... 226 | Setting up mysql-apt-config (0.8.14-1) ... 227 | Warning: apt-key should not be used in scripts (called from postinst 228 | maintainerscript of the package mysql-apt-config) 229 | OK 230 | ``` 231 | 232 | 233 | 234 | 在第二步命令)中,您可以选择哪些 MySQL 产品应该通过存储库提供。图。 235 | 236 | ![](../附图/Figure%2011-11.png) 237 | 238 | 默认值是启用 MySQL 服务器和群集以及工具和连接器。对于 MySQL 服务器和群集,您还可以选择要使用的版本,默认为 8。为了安装 MySQL 外壳,您需要设置为启用。在后,选择"确定"。 239 | 240 | 在开始使用存储库之前,需要执行: 241 | 242 | ``` 243 | shell$ sudo apt-get update 244 | Hit:1 http://repo.mysql.com/apt/ubuntu eoan InRelease 245 | Hit:2 http://au.archive.ubuntu.com/ubuntu eoan InRelease 246 | Hit:3 http://au.archive.ubuntu.com/ubuntu eoan-updates InRelease 247 | Hit:4 http://au.archive.ubuntu.com/ubuntu eoan-backports InRelease 248 | Hit:5 http://security.ubuntu.com/ubuntu eoan-security InRelease 249 | Reading package lists... Done 250 | ``` 251 | 252 | 现在,您可以使用 apt-get 的安装命令安装 MySQL 产品。清单显示了安装(请注意,包名称为末尾的"-社区"很重要)。 253 | 254 | ``` 255 | Listing 11-4. Installing MySQL Workbench from the APT repository 256 | shell$ sudo apt-get install mysql-workbench-community 257 | Reading package lists... Done 258 | Building dependency tree 259 | Reading state information... Done 260 | ... 261 | Setting up mysql-workbench-community (8.0.18-1ubuntu19.10) ... 262 | Setting up libgail-common:amd64 (2.24.32-4ubuntu1) ... 263 | Processing triggers for libc-bin (2.30-0ubuntu2) ... 264 | Processing triggers for man-db (2.8.7-3) ... 265 | Processing triggers for shared-mime-info (1.10-1) ... 266 | Processing triggers for desktop-file-utils (0.24-1ubuntu1) ... 267 | Processing triggers for mime-support (3.63ubuntu1) ... 268 | Processing triggers for hicolor-icon-theme (0.17-2) ... 269 | Processing triggers for gnome-menus (3.32.0-1ubuntu1) ... 270 | ``` 271 | 272 | 输出相当详细,包括安装 MySQL Workbench 所需的其他包的更改列表。包列表取决于您已经安装过什么。 273 | 274 | 您现在可以开始使用 MySQL Workbench了。 275 | 276 | ## 创建连接 277 | 278 | 首次启动时,您需要定义与 MySQL 服务器实例的连接。如果您安装了 MySQL 通知工作台将自动为根用户创建与 MySQL 通知器监视的每个实例的连接。 279 | 280 | 您还可以根据需要创建连接。一个选项是从 MySQL 工作台连接屏幕执行此操作,如图。 281 | 282 | ![](../附图/Figure%2011-12.png) 283 | 284 | 通过单击左上角的图标显示海豚数据库,即可访问连接屏幕。下面通过行连接的表格的图标将带您到数据库建模功能,三个图标中的最后一个将打开数据迁移功能的选项卡。 285 | 286 | 屏幕截图显示连接包含欢迎消息,并且已有一个连接。您可以右键单击连接以访问连接的选项 - 这些选项包括打开连接(创建到 MySQL 实例的连接)、编辑连接、将连接添加到组等。 287 | 288 | 单击 MySQL 连接右侧的 +。图。用于创建新连接和编辑现有连接的对话框非常相似。 289 | 290 | ![](../附图/Figure%2011-13.png) 291 | 292 | 您可以使用您选择的名称来命名连接。它是一个自由格式的字符串,仅用于更轻松地标识连接的用途。其余的选项是通常的连接选项。 293 | 294 | 连接后可以从连接屏幕双击它以创建连接。 295 | 296 | ## 使用 MySQL Workbench 297 | 298 | MySQL 工作台中使用最多的功能是执行查询的能力。这是从查询选项卡完成的,该选项卡除了执行查询的功能外,还包括多个功能。这些功能包括显示结果集、获取名为 Visual Explain 的查询计划的可视化表示、获取上下文帮助、重新格式化查询等。本节将介绍一些从概述开始的功能。 299 | 300 | ### 概述 301 | 302 | 查询选项卡由两个方面组成,其中一个是编写查询的编辑器,另一个是查询结果。还支持显示上下文帮助和查询统计信息。这两个附加区域在技术上不是查询选项卡的一部分,但由于它们大多与查询选项卡一起使用,因此此处还将讨论它们。 303 | 304 | 图显示了具有查询选项卡的 MySQL台,并且最重要的功能已编号。 305 | 306 | ![](../附图/Figure%2011-14.png) 307 | 308 | 标记为 (1) 的区域是您编写查询的地方。您可以保留多个查询,MySQL 工作台将保存它们,因此当您再次打开连接时,这些查询将被还原。这样可以方便地作为暂存板来存储最常用的查询。 309 | 310 | 使用标记为 (2) 的三个闪电图标之一执行查询或查询。左图标是一个普通的闪电符号,执行查询编辑器部分中选择的查询或查询。这与使用键盘快捷键 Ctrl+Shift+Enter 相同。带有闪电符号的中间图标和光标执行光标所在的查询。使用此图标与在编辑器中使用快捷方式 Ctrl+Enter 相同。第三个图标在闪电符号前面有一个放大镜,并在窗体中为当前放置光标的查询创建查询计划。显示查询计划的默认方式是作为可视化解释关系图。还可以使用键盘快捷方式 Ctrl+Alt+X 获取查询计划。 311 | 312 | 结果显示在查询编辑器 (3) 的下方,您可以通过使用查询结果右侧的项在几种格式之间进行选择。最后一项是(4),如果您直接从查询编辑器请求查询计划,它将以相同方式启动查询计划。 313 | 314 | 查询选项卡输出帧 (5),默认情况下,该框架显示上次执行查询的统计信息。这包括执行查询的时间、查询、找到的行数以及执行查询所用的时间。右侧有一个框架,其中有 SQL 添加 (6),默认情况下显示上下文帮助。您可以启用自动上下文帮助或使用帮助文本上方的图标手动请求它。 315 | 316 | ### 配置 317 | 318 | MySQL可以更改多个设置,范围从颜色到行为和路径到 MySql 工作台所依赖的程序(如 319 | 320 | 有几种方法可以到达设置,如图。图显示了 MySQL 工作台窗口的左上角和右上角。 321 | 322 | ![](../附图/Figure%2011-15.png) 323 | 324 | 在左侧,您可以使用"编辑"从菜单中然后转到首选项项。或者,您可以单击窗口右侧的齿轮图标。无论使用哪种方式,您都访问图。 325 | 326 | ![](../附图/Figure%2011-16.png) 327 | 328 | "设置包括用于语法检查器的 SQL 模式以及是否使用空格或选项卡进行缩进等设置。设置包括是否使用安全设置、是否保存编辑器以及编辑器和查询选项卡的一般行为。如果您使用捆绑二进制文件,管理设置指定要使用的路径,包括用于的路径。建模用于数据库建模功能。"设置允许您更改 MySQL 工作台的可视外观。当您使用需要连接到远程主机的 SSH 连接的功能时,将使用设置。最后,""设置包括一些不适合其他类别的设置,例如是否应使用连接在开始屏幕上显示欢迎消息。 329 | 330 | 这些包括安全设置。那是什么? 331 | 332 | ### 安全设置 333 | 334 | MySQL 工作台默认两个安全设置,以帮助防止更改或删除表中的所有行,并避免提取太多行。安全设置意味着和语句没有子句,并且语句添加了可以配置最大行数),则"更新"和"删除"语句将被阻止。更新WHERE句不能是微不足道的。 335 | 336 | 通常最好保持这些设置处于启用状态,但对于某些查询,您需要更改设置,以使它们正常工作。选择可以在设置中更改,如前所述。限制在 SQL 编辑器下的子menu。或者,更简单的方法是使用编辑器上方的拖放框,如图。 337 | 338 | ![](../附图/Figure%2011-17.png) 339 | 340 | 这样更改限制会更新与浏览首选项相同的设置。 341 | 342 | 更新安全设置可以在最远的设置中更改。建议保持该状态,除非您确实需要更新或删除表中的所有行。请注意,禁用设置需要重新连接。 343 | 344 | ### 重新格式化查询 345 | 346 | 不太注意的一个很好的功能是查询美化工具。这对于查询调优也很有用,因为格式良好的查询可以更容易地理解查询正在做什么。 347 | 348 | 查询美化器采用查询,并将选择列表、表和筛选器拆分为单独的行并添加缩进。图。 349 | 350 | ![](../附图/Figure%2011-18.png) 351 | 352 | 第一查询是原始查询,整个查询位于一行中。第二个查询是重新格式化的查询。对于像本示例中这样的简单查询来说,美化没有什么价值,但对于更复杂的查询,它可以使查询更易于阅读。 353 | 354 | 默认情况下,美化包括将 SQL 关键字更改为大写。您可以更改是否应在首选项中的 SQL设置的菜单中发生这种情况。 355 | 356 | ## EER 图 357 | 358 | 将探讨的最后一个功能是支持反向工程架构和创建增强的实体关系 (EER) 关系图。这是获取您正在使用架构的概述的有用方法。如果已定义外键,MySQL 工作台将使用定义将表链接在一起。 359 | 360 | 可以从数据库菜单选项启动反向,然后选择反向。,Ctrl+R 键盘组合也会带您去那里。如图。 361 | 362 | ![](../附图/Figure%2011-19.png) 363 | 364 | 该向导将带您完成导入架构的步骤,从选择要使用或可选手动配置连接的存储连接开始。下一步将连接并导入第三步中显示的可用架构列表。在这里,您可以选择一个或多个逆向工程,如图。 365 | 366 | ![](../附图/Figure%2011-20.png) 367 | 368 | 在此示例中,选择了架构。接下来的步骤获取架构对象,并允许您筛选要包括的对象。最后,将对象导入并放置在关系图中,并显示确认。生成的 EER如图。 369 | 370 | ![](../附图/Figure%2011-21.png) 371 | 372 | 该图显示了世界数据库中的表。将鼠标悬停在表上时,子表与其他表的关系将突出显示为绿色,父表以蓝色突出显示。这允许您快速浏览表之间的关系,以便为您提供在需要调整查询时至关重要的知识。 373 | 374 | ## 总结 375 | 376 | 本章介绍了 MySQL 工作台,这是 MySQL 的图形用户界面解决方案。展示了如何安装 MySQL 工作台和创建连接。然后概述了主查询视图,并展示了如何配置 MySQL 工作台。默认情况下,如果没有实际无法执行和语句查询限制为 1000 行。 377 | 378 | 所讨论的两个功能是查询美化和 EER 图。这些并不是唯一的功能,以后的章节将显示性能报告和可视化解释查询计划图的示例。 379 | 380 | 下一章将讨论 MySQL Shell,这是 MySQL 提供的两把"瑞士军刀"中的第二把。 381 | -------------------------------------------------------------------------------- /第4部分-模式注意事项和查询优化器/Chapter13.md: -------------------------------------------------------------------------------- 1 | # 数据类型 2 | 3 | 在 MySQL(和其他关系数据库)中创建表时,您为每一列指定数据类型。为什么不把所有东西都存储为字符串呢?毕竟,当这本书使用"42"时,它表示为字符串,那么,为什么不只对所有内容都使用字符串,而对每一列都使用各种值呢?这一点有其优点。这部分是NoSQL数据库工作的方式(尽管功能更多),并且本书的作者看到了表,其中所有列均定义为varchar(255)字符串。为什么要费心使用整数、decimals、浮点数、日期、字符串等?有几个原因,这是本章的主题。 4 | 5 | 首先,将讨论对不同类型的值使用不同的数据类型的好处。然后,将概述 MySQL 中支持的数据类型。最后,将讨论数据类型如何影响查询性能以及如何选择列的数据类型。 6 | 7 | ## 为什么是数据类型? 8 | 9 | 列的数据类型定义可以存储哪种类型的值以及如何存储值。 另外,可能存在与数据类型相关的元属性,例如大小(例如,用于数字的字节数和字符串中最大字符数)以及用于字符串的字符集和排序规则。 尽管数据类型属性似乎是不必要的限制,但它们也有好处。 这些好处包括 10 | 11 | - 数据验证 12 | - 文档 13 | - 优化的存储 14 | - 性能 15 | - 正确排序 16 | 17 | 本节的其余部分将讨论这些好处。 18 | 19 | ### 数据验证 20 | 21 | 数据类型的核心是定义允许的值类型。定义为整数数据类型的列只能存储整数值。这也是一种保障。如果您犯了一个错误,并尝试将值存储到与定义的数据类型不同的列中,则可以拒绝该值或转换该值。 22 | 23 | ------ 24 | 25 | **提示** 将错误的数据类型的值分配给列是导致错误还是要转换的数据类型取决于是否启用了STRICT_TRANS_TABLES(对于事务性存储引擎)和STRICT_ALL_TABLES(对于所有存储引擎)SQL模式以及是否启用了SQL模式。 被认为可以安全地转换数据类型。 始终允许某些被认为是安全的转换,例如,将“ 42”转换为42,反之亦然。 建议始终启用严格模式,这种模式会使DML查询在尝试进行不安全的转换或数据截断时失败。 26 | 27 | ------ 28 | 29 | 当您可以确保存储在表中的数据始终具有预期的数据类型时,它会让你的生活更轻松。如果查询具有整数的列,您知道对返回的值执行算术操作是安全的。同样,如果您知道该值是字符串,可以安全地执行字符串操作。它需要进行一些前期的计划,但是一旦完成,您将学会了解自己知道数据的数据类型。 30 | 31 | 关于数据类型和数据验证,还有一个注意事项。通常,存在与数据类型关联的属性。在最简单的情况下,您具有最大大小。例如,整数的大小可以是 1、2、3、4 或 8 字节。这会影响可存储的值范围。此外,整数可以有符号或无符号。更复杂的示例是字符串,它不仅限制它们存储的文本量,还需要一个字符集来定义数据的编码方式,以及一个排序规则来定义数据的排序方式。 32 | 33 | 清单13-1给出了一个MySQL如何根据数据类型验证数据的示例。 34 | 35 | ```sql 36 | Listing 13-1. Data validation based on data type 37 | mysql> SELECT @@sql_mode\G 38 | *************************** 1. row *************************** 39 | @@sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE, 40 | NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION 41 | 1 row in set (0.0003 sec) 42 | mysql> SHOW CREATE TABLE t1\G 43 | *************************** 1. row *************************** 44 | Table: t1 45 | Create Table: CREATE TABLE `t1` ( 46 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 47 | `val1` int(10) unsigned DEFAULT NULL, 48 | `val2` varchar(5) DEFAULT NULL, 49 | PRIMARY KEY (`id`) 50 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 51 | 1 row in set (0.0011 sec) 52 | mysql> INSERT INTO t1 (val1) VALUES ('abc'); 53 | ERROR: 1366: Incorrect integer value: 'abc' for column 'val1' at row 1 54 | mysql> INSERT INTO t1 (val1) VALUES (-5); 55 | ERROR: 1264: Out of range value for column 'val1' at row 1 56 | mysql> INSERT INTO t1 (val2) VALUES ('abcdef'); 57 | ERROR: 1406: Data too long for column 'val2' at row 1 58 | mysql> INSERT INTO t1 (val1, val2) VALUES ('42', 42); 59 | Query OK, 1 row affected (0.0825 sec) 60 | ``` 61 | 62 | SQL 模式设置为默认值,其中包括STRICT_TRANS_TABLES。除了主键之外,该表还有两列,其中一列是无符号位的整数,另一列是 varchar(5),这意味着它最多可以存储五个字符。当尝试将字符串或负整数插入 val1 列时,将弹出该值,因为它无法安全地转换为无符号位的整数。同样,尝试将包含六个字符的字符串存储到 val2 列中失败。但是,将字符串'42'存储到 val1 中,将整数 42 存储到 val2 中被认为是安全的,因此是允许的。 63 | 64 | 数据验证的副作用是,您还描述了预期的数据 - 这是列的隐式文档。 65 | 66 | ### Documentation 67 | 68 | 设计表时,您知道该表的预期用法是什么。当你或其他人以后使用表时, 这不一定清楚。有各种方法可以记录列:使用描述值的列名称、COMMENT 列子句、CHECK 约束和数据类型。 69 | 70 | 虽然数据类型不是记录列的最详细方式,当然也不应独立进行,但数据类型确实有助于描述您期望的数据类型。如果选择日期列而不是日期时间,则您显然只打算存储日期部分。同样,使用 tinyint 而不是 int 显示您只期望相对小的值。这一切都有助于您自己或他人了解可以预期什么样的数据。对数据了解得越好,在需要优化查询时,成功的变化也越好,这样它就可以间接地帮助查询优化。 71 | 72 | ------ 73 | 74 | **提示** 在表中提供文档的最好方法是使用COMMENT子句和CHECK约束。 但是,这些通常在表格图中是不可见的,在表格图中,数据类型有助于更好地了解预期的数据类型。 75 | 76 | ------ 77 | 78 | 性能主题方面,显式选择数据类型也有其好处。其中之一与值的存储方式有关。 79 | 80 | ### 优化存储 81 | 82 | MySQL 不会以相同方式存储所有数据。选择给定数据类型的存储格式尽可能紧凑以减少所需的存储。例如,考虑值 123456。如果将其存储为字符串,则至少需要 6 个字节加上 1 个字节来存储字符串的长度。如果改为选择整数,则只需要 3 个字节(对于整数,所有值始终使用相同数量的字节,取决于列允许的最大存储空间)。此外,从存储中读取整数不需要对该值进行任何解释,而对于字符串,则必须使用其字符集对值进行解码。 83 | 84 | 选择列的正确最大大小可以减少所需的存储量。如果需要存储整数,并且知道永远不需要超过 4 字节的存储的值,可以使用 int 数据类型,而不是使用 8 字节存储的 bigint。这是列所需的存储量的一半。如果您使用大数据,存储(和内存)节省可能会变得足够大,足以成为重要。但是,请注意不要过度优化。在许多情况下,更改数据类型或列的大小需要重建整个表,如果表很大,则这可能是一项昂贵的操作。 这样,最好现在使用更多的存储空间以节省以后的工作。 85 | 86 | ------ 87 | 88 | **提示** 与其他类型的优化一样,请注意不要过度优化数据类型。现在存储的节省相对较小,以后可能会造成疼痛。 89 | 90 | ------ 91 | 92 | 数据的存储方式也会影响性能。 93 | 94 | ### Performance 95 | 96 | 并非所有数据类型都是平等的。 整数在计算和比较中非常便宜,而必须使用字符集对存储的字节进行解码的字符串则相对昂贵。 通过选择正确的数据类型,可以显著提高查询的性能。 特别是,如果您需要比较两列中的值(可能在不同的表中),请确保它们具有相同的数据类型,包括字符集和字符串排序规则。 否则,必须先转换其中一列中的数据,然后才能将其与另一列进行比较。 97 | 98 | 虽然很容易理解为什么整数比字符串有更好的表现,但是使一种数据类型比另一种更好或更差的确切原因却相对复杂,并且取决于如何实现(存储在磁盘上)数据类型。 因此,对性能的进一步讨论将推迟到下一节对MySQL数据类型进行演练之后。 99 | 100 | 接下来将要讨论的最后一个好处是排序。 101 | 102 | ### 正确排序 103 | 104 | 日期类型对值的排序方式有重大影响。虽然人脑通常能直观地理解数据,但计算机需要一些帮助来了解两个值之间的比较。数据类型和字符串的排序是用于确保正确排序数据的关键属性。 105 | 106 | 日期类型对值的排序方式有重大影响。 尽管人脑通常可以直观地理解数据,但是计算机需要一些帮助来理解两个值之间的比较。 数据类型和字符串归类(collation )是用于确保数据正确排序的关键属性。 107 | 108 | 为什么排序很重要?有几个原因: 109 | 110 | - 正确的排序要求知道两个值是否相等或一个值是否在给定范围内。 这对于使WHERE子句和联接条件按预期工作至关重要。 111 | - 创建索引时,排序用于确保MySQL快速找到具有您要查找的值的行。 下一章将详细介绍索引 112 | 113 | 考虑值 8 和 10。它们如何排序?如果您认为它们为整数,则 8 先于 10。但是,如果您将它们视为字符串,则"10"(ASCII: 0x3130)先于"8"(ASCII: 0x38)。是否期望其中一个或另一个取决于您的应用,但除非也有具有非数值部分的值,否则您很可能期望出现要求数据类型为整数类型的整数行为。 114 | 115 | 考虑值8和10。它们如何排序? 如果您认为它们是整数,则8在10之前。但是,如果您将它们视为字符串,则“ 10”(ASCII:0x3130)在“ 8”(ASCII:0x38)之前。 是否期望一个或另一个取决于您的应用程序,但是除非还有带有非数字部分的值,否则您可能希望整数行为要求数据类型为整数类型。 116 | 117 | 现在,已经讨论了显式数据类型的好处是什么,是时候浏览 MySQL 支持的数据类型了。 118 | 119 | ## MySQL 数据类型 120 | 121 | MySQL 中有 30 多种不同的数据类型。其中几个可以调整的大小,精度,以及它们是否接受符号位的值。乍一看,它似乎很让人不知所措,但是如果将数据类型分组,则可以采用逐步的方法为数据选择正确的数据类型。 122 | 123 | MySQL中的数据类型可以视为以下类别之一的一部分: 124 | 125 | - **数值**:包括整数,固定精度的十进制类型,近似精度的浮点类型和bit类型。 126 | - **时间**:包括year,date,time,datetime和timestamp。 127 | - **字符串**:包括二进制对象和带有字符集的字符串。 128 | - **JSON**:JSON数据类型可以存储JSON文档。 129 | - **空间**:这些类型用于存储描述坐标系统中一个或多个点的值。 130 | - **混合**:MySQL有两种数据类型,都可以用作整数和字符串。 131 | 132 | ------ 133 | 134 | **提示** MySQL参考手册对https://dev.mysql.com/doc/refman/8.0/en/data-types.html 中的数据类型及其引用进行了全面的讨论。 135 | 136 | ------ 137 | 138 | 本节的其余部分将介绍数据类型并讨论其详细信息。 139 | 140 | ### 数值数据类型 141 | 142 | 数值数据类型是 MySQL 支持的最简单数据类型。您可以在整数、固定精度十进制值和近似浮点值之间进行选择。 143 | 144 | 表 13-1 总结了数值数据类型,包括字节中的存储要求和支持的值范围。对于整数,您可以选择值是符号还是无符号,这会影响受支持的值范围。对于支持的值,开始值和结束值都包含在允许的值范围内。 145 | 146 | | 数据类型 | 字节存储 | 范围 | 147 | | ------------- | -------- | ----------------------------------------------------- | 148 | | tinyint | 1 | Signed: -128–127 Unsigned: 0–255 | 149 | | smallint | 2 | Signed: -32768–32767 Unsigned: 0–65535 | 150 | | mediumint | 3 | Signed: -8388608–8388607 Unsigned: 0–16777215 | 151 | | int | 4 | Signed: -2147483648–2147483647 Unsigned: 0–4294967295 | 152 | | bigint | 8 | Signed: -263–263-1 Unsigned: 0–264-1 | 153 | | decimal(M, N) | 1-29 | Depends on M and N | 154 | | float | 4 | Variable | 155 | | double | 8 | Variable | 156 | | bit(M) | 1-8 | | 157 | 158 | 整数数据类型是最简单的,具有固定的存储要求和支持值的固定范围。小图的同义词是布尔(布尔值)。 159 | 160 | 十进制数据类型(数字是同义词)采用两个参数 M 和 N,这两个参数定义值的精度和比例。如果具有小数 (5,2),则值最多为五位数字,其中两位是小数(小数点右侧)。这意味着允许 -999.99 和 999.99 之间的值。最多支持 65 位数字。小数的存储量取决于使用 4 个字节的 9 位数字和使用 0+4 字节的 9 位数字数和剩余数字的数字数。 161 | 162 | 浮点和双数据类型存储近似值。这些类型对于数值计算是有效的,但代价是它们的值存在不确定性。它们分别使用 4 个字节和 8 个字节进行存储。 163 | 164 | ------ 165 | 166 | **提示** 切勿使用浮点数据类型来存储准确的数据,如货币存储。请改为使用精确的十进制数据类型。对于近似浮动点数据类型,绝不应使用相等 (+) 和不相等 (+) 运算符,因为比较两个近似值一般不会返回它们相等,即使它们本来是相等的。 167 | 168 | ------ 169 | 170 | 最终的数字数据类型是位类型。它可以在一个值中存储 1 到 64 位。例如,这可用于位掩码。所需的存储取决于所需的位数(M 值);它可以近似为 FLOOR((M+7)/8 字节。 171 | 172 | 与数字类型相关的数据类型类别是时态数据类型,这是将涵盖的下一个类别。 173 | 174 | ### 时态数据类型 175 | 176 | 时态数据定义时间点。精度范围从一年到一米秒。除年数据类型外,值作为字符串输入,但使用内部优化格式,并且值将根据值表示的时间点正确排序。 177 | 178 | 13-2 显示了 MySQL 支持的时间数据类型、每种类型使用的字节存储量以及支持的值范围。 179 | 180 | | 数据类型 | 字节存储 | 范围 | 181 | | --------- | -------- | ------------------------------------------------------------ | 182 | | year | 1 | 1901–2155 | 183 | | date | 3-6 | '1000-01-01' to '9999-12-31' | 184 | | datetime | 5-8 | '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999' | 185 | | timestamp | 4-7 | '1970-01-01 00:00:01.000000' to '2038-01-19 03:14:07.999999' | 186 | | time | 3-6 | '-838:59:59.000000' to '838:59:59.000000' | 187 | 188 | 日期时间、时间戳和时间类型都支持小数秒到微秒分辨率。分数秒的存储要求为 0~3 字节,取决于位数(每两位数 1 字节)。 189 | 190 | 日期时间和时间戳列以微妙的方式不同。当您在日期时间列中存储值时,MySQL 会像指定时一样存储它。另一方面,对于时间戳列,该值将使用已配置为使用的时区 MySQL 转换为 UTC - @@session.time_zone 变量(默认情况下是系统时区)。同样,检索数据时,日期时间值将按您原始指定的值返回,而时间戳列将转换为 @@session.time_zone 变量中的时区集。 191 | 192 | ------ 193 | 194 | **提示** 使用日期时间列时,将数据存储在 UTC 时区中,并转换到使用数据时所需的时区。通过始终将值存储在 UTC 中,如果操作系统时区或MySQL 服务器时区已更改,或者您与不同时区的用户共享数据,则出现问题的可能性较小 195 | 196 | ------ 197 | 198 | 使用字符串输入和检索日期和时间时,它们以专用格式存储在内部。实际字符串呢?让我们来看看字符串和二元数据类型。 199 | 200 | ### 字符串和二进制数据类型 201 | 202 | 字符串和二进制数据类型是存储任意数据的非常灵活的类型。二进制值和字符串之间的差异是字符串具有与其关联的字符集,因此 MySQL 知道如何解释数据。另一手的二进制值存储原始数据,这意味着您可以将它们用于任何类型的数据,包括图像和自定义数据格式。 203 | 204 | 虽然字符串和二进制数据非常灵活,但它们要同时支付成本。对于字符串,MySQL 需要解释字节以确定它们表示的字符。就所需的计算能力而言,这相对来说非常昂贵。某些字符集(包括 MySQL 8 中的默认字符集的 UTF-8)是可变宽度,即字符使用可变字节数;对于 UTF-8,它的范围为每字符 1 到 4 个字节。这意味着,如果您请求字符串的前四个字符,则可能需要读取 4 到 16 个字节,具体取决于它位于哪些字符,因此 MySQL 将需要分析字节以确定何时找到四个字符。对于二元字符串,数据含义的解释将重新放在应用程序上。 205 | 206 | 表 13-3 显示了 MySQL 中表示字符串和二进制数据的数据类型。该表包括可存储的最大数据量以及存储要求的说明。对于数据类型,(M)是列必须能够存储的最大字符数,在存储的 L 字节中,是需要表示用于编码的字符集中的字符串值的字节数。 207 | 208 | | 数据类型 | 存储字节 | 最大长度 | 209 | | :----------- | ------------ | -------------------------------------------- | 210 | | char(M) | M*char width | 255 chars | 211 | | varchar(M) | L+1 or L+2 | 16383 chars for utf8mb4 and 65532 for latin1 | 212 | | tinytext | L+1 | 255 bytes | 213 | | text | L+2 | 65535 bytes | 214 | | mediumtext | L+3 | 16777216 bytes | 215 | | longtext | L+4 | 4294967296 bytes | 216 | | binary(M) | M | 255 bytes | 217 | | varbinary(M) | L+1 or L+2 | 65532 bytes | 218 | | tinyblob | L+1 | 255 bytes | 219 | | blob | L+2 | 65536 bytes | 220 | | mediumblob | L+3 | 16777216 bytes | 221 | | longblob | L+4 | 4294967296 bytes | 222 | 223 | 字符串和二进制对象的存储要求取决于数据的长度。L 是存储值所需的字节数;对于文本字符串,还必须考虑字符集。对于可变宽度类型,使用 1~4 字节来存储值的长度。对于 char(M) 列,使用 InnoDB 存储格式的紧凑系列,以及使用可变宽度字符集对字符串进行编码时,所需的存储可能小于字符宽度的 M 倍。 224 | 225 | 对于所有字符和 varchar,字符串的最大支持长度以字节为单位指定。这意味着可以存储的字符串类型的字符数取决于字符集。此外,字符、varchar、二进制列和二进制列都计入行宽度,其总宽度必须小于 64 kiB,这意味着实际上很少能够使用理论最大长度创建列。(这也是 varchar 和 varbinary 列在最多可以存储 65532 个字符/字节的原因。对于长文本列和长文本列,应该指出,虽然它们原则上可以存储多达 4 GiB 的数据,但在实践中,存储受 max_allowed_packet 变量限制,最多只能存储 1 GiB。 226 | 227 | 存储字符串的数据类型的另一个注意事项是,您必须为列选择字符集和排序规则。如果未明确选择一个,则将使用该表的默认值。在 MySQL 8 中,使用默认排序规则排序规则,默认字符集为 utf8mb4 utf8mb4_0900_ai_ci。utf8mb4 andutf8mb4_0900_ai_ci是什么意思? 228 | 229 | utf8mb4 字符集是 UTF-8,每个字符最多支持 4 个字节(例如,某些表情符号是必需的)。最初,MySQL 仅支持每个字符最多 3 个字节的UTF-8,后来添加了 utf8mb4 以扩展支持。今天,您不应使用utf8mb3(每个字符最多 3 个字节)或其 utf8 别名(已弃用,因此以后可以将其更改为表示 utf8mb4)。使用 UTF-8 时,始终选择 4 字节变体,因为 3 字节变体的好处不大,并且已被弃用。在 MySQL 5.7 和更早版本中,拉丁文 1 是默认字符集,但随着 MySQL 8 中 UTF-8 的改进,建议使用 utf8mb4,除非您有特定的理由选择另一个字符集。 230 | 231 | utf8mb4_0900_ai_ci排序规则是 utf8mb4 的通用排序规则。排序规则定义排序和比较规则,因此当您比较两个字符串时,它们会正确比较。规则可能相当复杂,包括某些字符序列与其他单个字符比较相等(例如,德语锐化度与某些排序规则的"ss"相同)。排序规则名称由几个部分组成,这些部分 232 | 233 | - **utf8mb4**:归类所属的字符集。 234 | - **0900**:这意味着排序规则是基于Unicode排序算法(UCA)9.0.0的排序规则之一。 这些是MySQL 8中引入的,与旧的UTF-8归类相比,它们提供了显着的性能改进。 235 | - **ai**:归类可以是不区分重音(ai)或不区分重音(as)。 当排序规则对重音不敏感时,将诸如à之类的重音字符视为等于非重音字符a。 在这种情况下,它对重音不敏感。 236 | - **ci**:排序规则可以区分大小写(ci)或区分大小写(cs)。 在这种情况下,不区分大小写。 237 | 238 | 名称也可以包括其他部分,其他字符集具有其他字符组合。特别是,有几个针对具体国家/地区的性格集要考虑当地人的排序和比较规则;对于这些,国家/地区代码将添加到名称中。建议使用 UCA 9.0.0 排序规则之一,因为这些排序规则性能更好,并且比其他排序规则更现代。information_schema。Collations 视图包括 MySQL 支持的所有排序规则,支持按字符集进行筛选。截至 8.0.18,有 75 个排序规则可用于 utf8mb4,其中 49 个是 UCA 9.0.0 排序规则。 239 | 240 | ------ 241 | 242 | **提示** 字符集和排序规则本身是一个庞大而有趣的主题。如果您想进一步深入探讨该主题,一个起点是本书作者的以下博客及其引用:https://mysql.wisborg.dk/mysql-8_charset 。 243 | 244 | ------ 245 | 246 | 一种特殊的字符串是 JSON 文档。MySQL 具有专用数据类型。 247 | 248 | ### JSON数据类型 249 | 250 | 与关系表相比,使用更灵活的存储数据的流行格式是JavaScript对象表示法(JSON)格式。这也是为 MySQL 8 中可用的 MySQL 文档存储选择的格式。MySQL 5.7 中引入了对 json 数据类型的支持。 251 | 252 | JSON 文档是 JSON 对象(键和值)、JSON 数组和 JSON 值的组合。JSON 文档的简单示例可如下所示: 253 | 254 | ```json 255 | { 256 | "name": "Sydney", 257 | "demographics": { 258 | "population": 5500000 259 | }, 260 | "geography": { 261 | "country": "Australia", 262 | "state": "NSW" 263 | }, 264 | "suburbs": [ 265 | "The Rocks", 266 | "Surry Hills", 267 | "Paramatta" 268 | ] 269 | } 270 | ``` 271 | 272 | 由于 JSON 文档也是字符串(或二进制对象),它也可以存储在占星或二进制对象列中。但是,通过具有专用数据类型,可以添加验证,并且存储已针对访问文档中的特定元素进行了优化。 273 | 274 | MySQL 8 中 JSON 文档的一个出色的性能相关功能是支持部分更新。这使得更改不仅减少了更新期间完成的量,而且可能只写入二进制日志的部分更改。有一些要求,部分就地更新是可以的。如下所示: 275 | 276 | - 仅支持JSON_SET( ),JSON_REPLACE( )和JSON_REMOVE( )函数。 277 | - 仅支持列内的更新。 也就是说,不支持将列设置为在另一列上工作的三个JSON函数之一的返回值。 278 | - 它必须是已替换的现有值。 添加新的对象或数组元素将导致整个文档被重写。 279 | - 新值最多必须与替换的值大小相同。 例外情况是可以重用先前部分更新释放的空间。 280 | 281 | 为了将二进制日志的部分更新记录为部分更新,您需要将"binlog_row_value_options"选项PARTIAL_JSON。该选项可以在会话和全局级别动态设置。 282 | 283 | 在内部,文档存储为长二进制对象(longblob),其文本使用 utf8mb4 字符集进行解释。最大存储限制为 1GiB。存储要求与长球要求类似,但有必要将元数据和用于查找的字典的开销考虑在内。 284 | 285 | 到目前为止,已涵盖数字、时态数据、字符串、二进制对象和 JSON 文档。指定空间中点的数据如何?这是要涵盖的下一类数据类型。 286 | 287 | ### 空间数据类型 288 | 289 | 空间数据指定坐标系中的一个或多个点,可能形成对象(如多边形)。这很有用,例如,用于指定地图上项目的位置。 290 | 291 | MySQL 8 添加了用于指定使用哪个参考系统的支持;这称为空间参考系统标识符 (SRID)。支持的参考系统可以在information_schema。ST_SPATIAL_REFERENCE_SYSTEMS视图(SRS_IDcolumn具有用于 SRID 的值);有5000多个可供选择。每个空间值都有一个与其关联的参考系统,以便 MySQL 能够正确识别两个值之间的关系,例如,计算两个点之间的距离。要使用地球作为参考系统,请将SRID设置为 4326。 292 | 293 | 支持八种不同的空间数据类型,其中四种是单值类型,四种是值集合。表 13-4 总结了以字节为单位的已查询存储的空间类型。 294 | 295 | MySQL 使用二进制格式来存储数据。网格学、多线线线线、多多边和几何集合类型的存储要求取决于值中包含的对象的大小。这些对象集合的存储比将对象存储在单个列中稍大一点。您可以使用 LENGTH( ) 函数获取空间对象的大小,然后添加 4 个字节来存储 SRID 以获得数据所需的总存储。 296 | 297 | 这留下了一个要讨论的数据类型类别:数字和字符串数据类型之间的混合。 298 | 299 | ### 混合数据类型 300 | 301 | 有两种特殊数据类型组合了整数和字符串的属性:即"环境"集。两者都可以被视为可能值的集合,其区别在于,即环境数据类型允许您完全选择其中一个可能的值,而集数据类型允许您选择任何可能的值。 302 | 303 | 使项数和集数据类型混合的,是您可以将它们用作集合和字符串。后者是最常见和最用户友好的。在内部,这些值以整数存储,提供紧凑高效的存储,同时仍然允许在设置或查询列时使用字符串。使用查找表实现这两种数据类型可以作为替代方法实现。 304 | 305 | "项"数据类型是两者中最常用的类型。创建列时,可以指定允许的值列表,例如: 306 | 307 | ```sql 308 | CREATE TABLE t1 ( 309 | id int unsigned NOT NULL PRIMARY KEY, 310 | val enum('Sydney', 'Melbourne', 'Brisbane') 311 | ); 312 | ``` 313 | 314 | 数值是列表中以 1 开始的位置。也就是说,悉尼具有整数值 1、墨尔本 2 和布里斯班 3。根据列表中的成员数,总存储要求只有 1 或 2 字节,并且最多支持 65535 个成员。 315 | 316 | 集数据类型的工作方式与"已下"类似,但您可以选择多个选项。若要创建它,请列出要可用的成员,例如: 317 | 318 | ```sql 319 | CREATE TABLE t1 ( 320 | id int unsigned NOT NULL PRIMARY KEY, 321 | val set('Sydney', 'Melbourne', 'Brisbane') 322 | ); 323 | ``` 324 | 325 | 列表中的每个成员根据成员在列表中的位置获取系列 1、2、4、8 等中的数值。在示例中,悉尼的值为 1、墨尔本 2 和布里斯班 4。然后值 3 代表什么?是悉尼和墨尔本。 如果你想包括多个值, 你总结他们的个人值。这样,集数据类型的工作方式与位类型相同。将值指定为占星值时更简单,因为在逗号分隔列表中包括该值的成员。清单 13-2 显示了两个插入集值的示例,每个示例都使用数值和字符串值插入相同的值。 326 | 327 | ``` 328 | Listing 13-2. Working with set values 329 | mysql> INSERT INTO t1 330 | VALUES (1, 4), 331 | (2, 'Brisbane'); 332 | Query OK, 2 rows affected (0.0812 sec) 333 | Records: 2 Duplicates: 0 Warnings: 0 334 | mysql> INSERT INTO t1 335 | VALUES (3, 7), 336 | (4, 'Sydney,Melbourne,Brisbane'); 337 | Query OK, 2 rows affected (0.0919 sec) 338 | Records: 2 Duplicates: 0 Warnings: 0 339 | mysql> SELECT * 340 | FROM t1\G 341 | *************************** 1. row *************************** 342 | id: 1 343 | val: Brisbane 344 | *************************** 2. row *************************** 345 | id: 2 346 | val: Brisbane 347 | *************************** 3. row *************************** 348 | id: 3 349 | val: Brisbane,Melbourne,Sydney 350 | *************************** 4. row *************************** 351 | id: 4 352 | val: Brisbane,Melbourne,Sydney 353 | 4 rows in set (0.0006 sec) 354 | ``` 355 | 356 | 首先,插入"布里斯班"的值。由于它是集中的第三个元素,因此其数值为 4。然后插入悉尼、墨尔本和布里斯班的集。在这里,您需要求和 1、2 和 4。请注意,在 SELECT 查询中,元素的顺序与集合定义中的顺序不相同。 357 | 358 | 设置列使用 1、2、3、4 或 8 字节的存储,具体取决于集中成员的数量。一组最多可以有 64 个成员。 359 | 360 | 讨论可用数据类型到此结束。数据类型如何影响查询的性能?可能相当多, 所以这是值得考虑的。 361 | 362 | ## Performance 363 | 364 | 数据类型的选择不仅在数据完整性和数据类型方面很重要,而且不同的数据类型具有不同的性能表现。本节将讨论比较数据类型时性能的变化。 365 | 366 | 通常,数据类型越好,执行得越好。整数具有最佳性能,浮点(近似值)紧随其后。十进制(精确)值的开销高于近似浮点值。二进制对象比文本字符串更性能,因为二进制对象没有字符集的开销。 367 | 368 | 当涉及到像 JSON 这样的数据类型时,您可能认为它的性能比使用二进制对象更糟糕,因为 JSON 文档具有一些存储开销,如本章前面所述。但是,正是此存储开销意味着 JSON 数据类型比存储与 Blob 相同的数据性能更好。开销由元数据和字典组成,这意味着访问数据的速度更快。此外,JSON 文档支持就地更新,而文本和 Blob 数据类型将替换整个对象,即使仅替换单个字符或字节。 369 | 370 | 在给定的数据类型系列(例如,int 与 bigint)中,较小的数据类型性能优于较大的数据类型;但是,在实践中,硬件寄存器中的对齐也有考虑因素,因此对于内存工作负载,差异可能可以忽略不计,甚至相反。 371 | 372 | 那么您应该使用哪些数据类型? 这是本章的最后主题。 373 | 374 | ## 您应该选择哪种数据类型? 375 | 376 | 本章的开头,讨论了如何将所有数据存储在字符串或二进制对象中以具有最大的灵活性,这看起来是个好主意。在本章的过程中,讨论了使用特定数据类型的好处,并在上一节中讨论了不同数据类型的性能。那么,您应该选择哪种数据类型呢? 377 | 378 | 您可以开始问自己一些需要存储在列中的数据的问题。问题示例如下: 379 | 380 | - 数据的本机格式是什么? 381 | - 最初可以期望多大的价值? 382 | - 值的大小会随着时间增长吗? 如果是这样,多少,多少时间? 383 | - 查询中多久检索一次数据? 384 | - 您期望多少个独特的价值? 385 | - 您需要索引值吗? 特别是它是表的主键吗? 386 | - 您是否需要存储数据,或者是否可以通过其他表中的外键(使用整数引用列)获取数据? 387 | 388 | 应为需要存储的数据选择本机的数据类型。如果需要存储整数,请选择整数数据类型,通常为 int 或 bigint,具体取决于所需的值大小。如果要限制值,可以选择较小的整数类型;如果要限制值,可以选择较小的整数类型。例如,存储父母数据的表的子项数量不一定是大数目,但很小的子数就足够了。同样,如果要存储 JSONocuments,请使用 json 类型而不是长文本或长文本。 389 | 390 | 对于数据类型的大小,您需要同时考虑当前需要和未来需求。如果预计在很长时间内需要较大的值,最好马上选择较大的数据类型。这样可以节省以后更改表定义。但是,如果预期更改是几年后,最好现在使用较小的数据类型,并随着时间的推移重新评估您的需求。对于 varchar 和 varbinary,也可以更改位置的宽度,只要不更改存储字符串长度或字符集的字节数。 391 | 392 | 使用字符串和二进制对象时,还可以考虑将数据存储在单独的表中,并使用整数引用值。当您需要检索值时,这将添加一个联接;但是,如果您很少需要实际的字符串值,则保持主表较小,这或许是整体胜利。此方法的好处还取决于表中的行数以及查询行的方式;检索许多行的大型扫描比单行查找受益更多,使用 SELECT * 即使不需要所有列也比仅选择所需的列受益更多。 393 | 394 | 如果只有几个唯一的字符串值,则也值得考虑使用列名数据类型。它的工作方式类似于查找表,但保存联接,并允许您直接更新字符串值 395 | 396 | 对于非整数数字数据,您可以在精确的十进制数据类型和近似浮点和双数据类型之间进行选择。如果需要存储必须精确的数据(如货币值),应始终选择十进制数据类型。这也是要选择的类型,如果您需要进行相等和非相等比较。如果不需要精确数据,则浮点和双数据类型性能更好。 397 | 398 | 关于字符串值,则字符、varchar、微文本、文本、中文本和长文本数据类型需要字符集和排序规则。通常,使用基于 UCA 9.0.0+ 的排序规则之一(名称中与 _0900_ 的排序)选择 utf8mb4 是值得推荐的。如果您utf8mb4_0900_ai_ci,则默认选项是一个不错的选择。拉丁语 1 的表现会稍好一些, 但很少能保证为不同需要使用不同的字符集的复杂性。UCA 9.0.0 排序规则也提供了比拉丁文 1 可用的排序更现代的排序规则。 399 | 400 | 当您需要决定允许的值大小时,请选择支持现在和近期所需的值的最小数据类型或模型。较小的数据类型还意味着用于行大小限制 (64 kiB) 的空间更少,并且更多的数据可以放入 InnoDB 页面。由于 InnoDB 缓冲池可以存储一定数量的页面,从而根据缓冲池和页面的大小,这反过来又意味着更多的数据可以放入缓冲池中,从而有助于减少磁盘 I/O。同时,请记住,优化也是关于了解何时优化得足够。不要花一些时间去剃掉几个字节,而为了在一年内完成一个昂贵的表重建。 401 | 402 | 最后要考虑的是该值是否包含在索引中。值越大,索引也变得越大。这是主键的特定问题。InnoDB 根据主键(如群集索引)组织数据,因此当您添加辅助索引时,主键将添加到索引末尾,将链接添加到行。此外,此数据组织意味着在一般单调增加的值中对主键执行最佳性能。如果具有主键的列随时间随机变化和/或它很大,则最好添加具有自动增量整数的虚拟列,并使用它作为主键。 403 | 404 | 索引本身就是一个重要而大的主题,将在下一章中讨论。 405 | 406 | ## 总结 407 | 408 | 本章介绍了数据类型的概念。使用数据类型有几个好处:数据验证、文档、优化的存储、性能和更正排序。 409 | 410 | MySQL 支持多种数据类型,从字符串和空间对象的简单整数到复杂的 JSON 文档。讨论了每种数据类型,重点讨论了支持的值、支持的值的大小和所需的存储量。 411 | 412 | 本章的最后一部分讨论了数据类型如何影响性能以及如何确定为列选择哪种数据类型。这包括考虑是否对列编制索引,这也与数据类型之一有关:正确的排序。索引是一个非常重要的主题,事实上,下一章将介绍它们。 413 | 414 | -------------------------------------------------------------------------------- /第4部分-模式注意事项和查询优化器/Chapter16.md: -------------------------------------------------------------------------------- 1 | # 直方图 2 | 3 | 在前几章中,您了解了索引和索引统计信息。索引的目的是减少访问查询所需的行和索引统计信息所需的读取,以帮助优化器确定最佳查询计划。这一切都很棒,但索引不是免费的,而且有些情况下索引不是很有效,而且不保证开销,但您仍然需要优化器来了解数据分布。这就是直方图可能有用的地方。 4 | 5 | 本章开始讨论什么是直方图,以及哪些工作负载直方图很有用。然后介绍使用直方图的更实际的一面,包括添加、维护和检查直方图数据。最后,还有一个查询示例,其中查询计划随着直方图的添加而更改。 6 | 7 | ## 什么是直方图? 8 | 9 | 对直方图的支持是 MySQL 8 中的新功能。它使分析和存储有关数据在表中分布的信息成为可能。虽然直方图与索引有些相似,但它们并不相同,并且您可以为没有任何索引的列具有直方图。 10 | 11 | 创建直方图时,告诉 MySQL 将数据划分为存储桶。这可以通过在每个存储桶中放入一个值或在每个存储桶中具有大致相等的行数的值来实现。有关数据分布的知识可以帮助优化器更准确地估计表中给定 WHERE 子句或联接条件将筛选出多少数据。如果没有这些知识,优化器可能会假定条件返回表的三分之一,而直方图可能显示只有 5% 的行与条件匹配。这些知识对于优化器选择最佳查询计划至关重要。 12 | 13 | 同时,必须认识到直方图与索引不一样。MySQL 不能使用直方图来减少使用直方图检查的表的行数,而对于没有直方图执行的同一查询计划相比。但是,通过了解将筛选多少表,优化器可以更好地确定最佳联接顺序。 14 | 15 | 直方图的一个优点是,它们仅在创建或更新时具有成本。与索引不同,更改数据时直方图没有更改。您可以不时重新创建直方图,以确保统计信息是最新的,但 DML 查询没有开销。通常,直方图应与索引统计信息进行比较,而不是与索引进行比较。 16 | 17 | ------ 18 | 19 | **注意** 了解索引和直方图之间的根本区别非常重要。索引可用于减少访问所需行所需的工作,直方图不能。当用于查询的直方图时,它不会直接减少检查的行数,但它可以帮助优化器选择更优化的查询计划。 20 | 21 | ------ 22 | 23 | 就像索引一样,您应该小心地选择为哪个列添加直方图。因此,让我们讨论哪些列应被视为优秀的候选人。 24 | 25 | ## 何时应添加直方图? 26 | 27 | 添加直方图的好处是将它们添加到正确的列。简而言之,直方图最适用于不是索引中的第一列、具有非统一值分布以及将条件应用于这些列的列。这听起来像是一个非常有限的用例,事实上直方图在 MySQL 中并不像在其他一些数据库中那样有用。这是因为 MySQL 有效地估计索引列范围内的行数,因此直方图不会与同一列上的索引一起使用。另请注意,虽然直方图对于具有不均匀数据分布的列特别有用,但同样可用于统一数据分布,因为不值得添加索引。 28 | 29 | ------ 30 | 31 | **提示** 不要向索引中第一列的列添加直方图。对于稍后在索引中显示的列,直方图对于由于需要使用索引的左前缀而不能用于列的查询仍具有值值。 32 | 33 | ------ 34 | 35 | 也就是说,在某些情况下,直方图可以大大提高查询性能。典型的用例是具有一个或多个联接的查询,以及具有数据未一匀分布的列上的一些次要条件。在这种情况下,直方图可以帮助优化器确定最佳联接顺序,以便尽早筛选出大部分行。 36 | 37 | 具有不一致数据分布的数据的一些示例包括状态值、类别、一天中的时间、工作日和价格。状态列可能具有终端状态的大量行,如"已完成"或"失败",以及处于工作状态的一些值。同样,产品表在某些类别中的产品可能比其他类别中的产品多。一天中的时间和工作日值可能不统一,因为某些事件更有可能发生在某些时间或天数中。例如,平日发生的球类比赛(取决于运动)更有可能在周末发生,而不是平日。对于价格,您可能拥有价格相对较窄的多数产品,但最低和最高价格都超出了此范围。选择性低的列示例包括列,即列的数据类型、布尔值和其他只有几个唯一值的列。 38 | 39 | 与索引相比,直方图的一个好处是直方图比索引潜水便宜,以确定一个范围内的行数,例如,对于长 IN 子句或许多 OR 条件。这样做的原因是,直方图统计信息对于优化器是现成的,而索引潜水以估计一个范围内的行数,在确定查询计划时完成,从而对每个查询重复。 40 | 41 | ------ 42 | 43 | **提示** 对于索引列,优化器将从进行相对昂贵但非常准确的索引潜水切换到在有 eq_range_index_dive_ 限制(默认值为 200)或更多相等范围时,使用索引统计信息来估计匹配行数。 44 | 45 | ------ 46 | 47 | 你可以争辩说,为什么当你可以添加索引时,麻烦直方图,但请记住,它不是没有成本,以维护索引,因为数据的变化。执行 DML 查询时需要维护它们,并且它们增加了表空间文件的大小。此外,在执行查询的优化阶段,对范围(包括相等范围)中值数的统计信息进行远程计算。也就是说,它们是根据需要计算的每个查询。另一方面,直方图只存储统计信息,并且仅在显式请求时更新。直方图统计信息也始终可用于优化器。 48 | 49 | 总之,直方图的最佳候选项是符合以下条件的列: 50 | 51 | - 数据分布不均匀或值太多,以致优化器的粗略估算(在下一章中讨论)并不是对数据选择性的良好估算。 52 | - 选择性差(否则索引可能是更好的选择)。 53 | - 用于在WHERE子句或联接条件中过滤表中的数据。 如果不对列进行过滤,则优化器将无法使用直方图。 54 | - 随时间推移稳定分布数据。 直方图统计信息不会自动更新,因此,如果在数据分布经常变化的列上添加直方图,则直方图统计信息可能不准确。 直方图选择不佳的一个主要示例是存储事件日期和时间的列。 55 | 56 | 这些规则的一个例外是,如果可以使用直方图统计信息来替换昂贵的查询。可以查询直方图统计信息,因为它将显示在"检查直方图数据"部分中,因此,如果您只需要数据分布的近似结果,则可以查询直方图统计信息。 57 | 58 | ------ 59 | 60 | **提示** 如果您有确定给定范围内的值数的查询,并且只需要近似值,则即使您不打算使用直方图来改进查询计划,也可以考虑创建直方图。 61 | 62 | ------ 63 | 64 | 由于直方图存储列中的值,因此不允许向加密表添加直方图。否则,加密数据可能会无意中被写入磁盘。此外,不支持临时表上的直方图。 65 | 66 | 为了以最佳方式应用直方图,您需要了解直方图工作的内部信息,包括支持的直方图类型。 67 | 68 | ## Histogram Internals 69 | 70 | 直方图周围有几个内部图,为了有效地使用它们,必须了解这些内部图。您应该了解的概念是存储桶、累积频率和直方图类型。本节将介绍每个概念。 71 | 72 | ### Buckets 73 | 74 | 创建直方图时,值将分发到存储桶。每个存储桶可以包含一个或多个不同的值,对于每个存储桶,MySQL 计算累积频率。因此,存储桶的概念很重要,因为它与直方图统计的准确性密切相关。 75 | 76 | MySQL 支持多达 1024 个存储桶。存储桶的量桶越多,每个存储桶中的值就更少,因此存储桶越多,对于每个值的统计信息越准确。在最好的情况下,每个存储桶只有一个值,因此您知道该值的行数"精确"(只要统计信息准确)。如果每个存储桶有多个值,则计算值范围的行数。 77 | 78 | 在此上下文中了解何谓独特价值非常重要。对于字符串,在比较值时只考虑前 42 个字符,对于二进制值,则考虑前 42 个字节。如果您有具有相同前缀的长字符串或二进制值,直方图可能不太适合您。 79 | 80 | ------ 81 | 82 | **注意** 仅使用字符串前 42 个字符和二进制对象的前 42 个字节来确定直方图存在的值。 83 | 84 | ------ 85 | 86 | 值按顺序添加,因此,如果您从左到右订购存储桶并检查给定的存储桶,则您知道左侧的所有存储桶的值都较小,而右侧的所有存储桶的值都较大。图 16-1 显示了存储桶的概念。 87 | 88 | ![](../附图/Figure%2016-1.png) 89 | 90 | 在图中,前面的暗列是每个存储桶中值的频率。频率是具有该值的行的百分比。在后台(颜色更亮的列)是累积频率,其值与存储桶 0 的计数列相同,然后逐渐增加,直到存储桶 7 达到 100。什么是累积频率?这是你应该理解的直方图的第二个概念。 91 | 92 | ### 累积频率 93 | 94 | 存储桶的累积频率是当前存储桶和上一个存储桶中的行的百分比。如果您正在查看存储桶编号 3,并且累积频率为 50%,则 50% 的行适合存储桶 0、1、2 和 3。这使得优化器很容易确定具有直方图的列的选择性。 95 | 96 | 计算选择性时需要考虑两种情况:相等条件和范围条件。对于相等条件,优化器确定条件值位于哪个存储桶中,然后采用该存储桶的累积频率,并减去上一个存储桶的累积频率(对于存储桶 0,不减去任何值)。如果存储桶中只有一个值,则这就是所需的全部值。否则,优化器假定存储桶中的每个值以相同的频率发生,因此存储桶的频率与存储桶中的值数进行划分。 97 | 98 | 对于范围条件,它的工作方式非常相似。优化器查找边缘条件位于的铲斗。例如,对于 val = 4,位于值为 4 的存储桶。使用的累积频率取决于存储桶中的值数和条件类型。对于相等条件,对于多值存储桶,累积频率通过假设存储桶中值的相等分布来找到。根据条件类型,累积频率使用如下: 99 | 100 | - 小于:使用前一个值的累积频率。 101 | - 小于或等于:使用条件中值的累积频率。 102 | - 大于或等于:从1减去前一个值的累积频率。 103 | - 大于:从1中减去条件中值的累积频率。 104 | 105 | 这意味着,通过使用累积频率,最多需要考虑两个存储桶,以确定条件对表中的行进行筛选的身体状况。查看示例以更好地了解累积频率的工作方式可能很有用。表 16-1 显示了一个直方图示例,每个存储桶有一个值,每个存储桶的累积频率。 106 | 107 | | Bucket | Value | Cumulative Frequency | 108 | | ------ | ----- | -------------------- | 109 | | 0 | 0 | 0.1 | 110 | | 1 | 1 | 0.25 | 111 | | 2 | 2 | 0.37 | 112 | | 3 | 3 | 0.55 | 113 | | 4 | 4 | 0.63 | 114 | | 5 | 5 | 0.83 | 115 | | 6 | 6 | 0.95 | 116 | | 7 | 7 | 1.0 | 117 | 118 | 在此示例中,这些值与存储桶编号相同,但通常情况并非如此。累积频率从 0.1 (10) 开始并增加每个存储桶中的行百分比,直到最后一个存储桶达到 100%。此分布与图 16-1 中所示的分布相同。 119 | 120 | 如果查看与值 4 相比的五种条件类型,则每种类型估计的行数如下: 121 | 122 | - val = 4:从存储区4的累积频率中减去存储区3的累积频率:估计= 0.63 – 0.55 = 0.08。 因此,估计将包含8%的行。 123 | - val <4:使用存储区3的累积频率,因此估计将包含55%的行。 124 | - val <= 4:使用存储区4的累积频率,因此估计将包含63%的行。 125 | - val> = 4:从1中减去存储区3的累积频率,因此估计将包含45%的行。 126 | - val> 4:从1中减去存储区4的累积频率,因此估计将包含37%的行。 127 | 128 | 当每个存储桶中包含多个值时,它变得有点复杂。表 16-2 显示了相同的表和值分布,但这次直方图只有四个存储桶,因此每个存储桶平均有两个值。 129 | 130 | | Bucket | Values | Cumulative Frequency | 131 | | ------ | ------ | -------------------- | 132 | | 0 | 0-1 | 0.25 | 133 | | 1 | 2-3 | 0.55 | 134 | | 2 | 4-5 | 0.83 | 135 | | 3 | 6-7 | 1.0 | 136 | 137 | 在这种情况下,每个存储桶中正好有两个值,但通常情况并非如此(在讨论直方图类型时将对此进行更多讨论)。现在,评估相同的五个条件时,需要考虑到每个存储桶都包含多个值的行数的估计值: 138 | 139 | - **val = 4**:从存储区2的累积频率中减去存储区1的累积频率;然后将结果除以存储区2中值的数量:估计=(0.83 – 0.55)/ 2 = 0.14。因此,估计将包含14%的行。这比每个桶中有一个值的更准确的估计要高,因为值4和5的频率是一起考虑的。 140 | - **val <4**:存储桶1的累积频率是唯一需要的频率,因为存储桶0和1的所有值都小于4。因此,估计将包含55%的行(这与对于前一个示例,因为在两种情况下,估算都只需要考虑完整的存储桶)。 141 | - **val <= 4**:这更加复杂,因为存储区2中一半的值包含在过滤中,而另一半则不包含。因此,估算值将是存储桶1的累积频率加上存储桶2的频率除以存储桶中值的数量:估算= 0.55 +(0.83 – 0.55)/ 2 = 0.69或69%。这比每个存储桶使用一个值的估计值更高且更不准确。该估计的准确性较差的原因是,假定值4和5具有相同的频率。 142 | - **val> = 4**:此条件要求存储区2和3中的所有值,因此估算值应包括1减去存储区1的累积频率;这是45%–与每个存储桶一个值的情况下的估算值相同。 143 | - **val> 4**:这种情况类似于val <= 4,只是要包含的值相反,因此您可以取0.69并从1中减去,得出0.31或31%。同样,由于涉及两个存储桶,因此估算的准确性不如每个存储桶的单个值准确。 144 | 145 | 如您所见,在将值分发到存储桶中时有两种不同的方案:要么存储桶至少与值一样多,也可以为每个值分配自己的存储桶,或者多个值必须共享一个存储桶。这是两种不同类型的直方图,接下来将讨论这些直方图的具体细节。 146 | 147 | ### Histogram Types 148 | 149 | MySQL 8 中有两种类型的直方图。创建或更新直方图时,根据值是否大于存储桶自动选择直方图类型。两种直方图类型是 150 | 151 | - 单位:对于单位直方图,每个存储桶只有一个值。这些是最精确的直方图,因为创建直方图时存在的每个值都有估计值。 152 | - 等高度:当列的值大于存储桶时,MySQL 将分发这些值,因此每个存储桶的行数大致相同,也就是说,每个存储桶的高度大致相同。由于具有相同值的所有行都分布到同一个存储桶,因此存储桶的高度不会完全相同。对于等高直方图,每个存储桶都表示的值数不同。 153 | 154 | 在探索累积频率时,您已经遇到两种直方图类型。单位直方图是最简单、最准确的,但等高直方图是最灵活的,因为它们可以处理任何数据集。 155 | 156 | 为了演示单层和等高直方图,可以从 world.city 表创建 city_ 直方图表,其中包含基于八个国家/地区代码的城市子集。可以使用以下查询创建表: 157 | 158 | ```sql 159 | use world 160 | CREATE TABLE city_histogram LIKE city; 161 | INSERT INTO city_histogram 162 | SELECT * 163 | FROM city 164 | WHERE CountryCode IN 165 | ('AUS', 'BRA', 'CHN', 'DEU', 166 | 'FRA', 'GBR', 'IND', 'USA'); 167 | ``` 168 | 169 | 图 16-2 显示了"国家代码"列上的单例直方图示例。由于有八个值,因此直方图有八个存储桶。(您将在章节的稍后部分学习如何创建和检索直方图统计信息。 170 | 171 | ![](../附图/Figure%2016-2.png) 172 | 173 | 直方图每个存储桶只有一个值。澳大利亚(澳大利亚)的频率范围从1.0%到24.9%到中国(CHN)。例如,如果"国家代码"列上没有索引,直方图可以极大地帮助提供更准确的筛选估计值。原始 world. city 表有 232 个不同的国家代码值,因此单元直方图效果良好。 174 | 175 | 图 16-3 显示了相同数据的等高直方图,但统计时只有四个存储桶。 176 | 177 | ![](../附图/Figure%2016-3.png) 178 | 179 | 对于等高度直方图,MySQL 的目标是具有每个存储桶的相同频率(高度)。但是,由于列值将完全位于一个存储桶中,并且值按顺序分布,因此通常不可能获得完全相同的高度。本示例中的情况也是,存储桶 0 和 3 的频率比存储桶 1 和 2 稍小。 180 | 181 | 该图还显示了等高直方图的缺点。巴西 (BRA)、中国 (CHN) 和印度 (IND) 城市的高频率被它们共享水桶的国家/地区的低频率所掩盖。因此,等高直方图的精度没有单位直方图高。当值的频率变化很大时,尤其如此。精度降低通常比范围条件更公平,因此等高直方图最适合主要用于范围条件的列。 182 | 183 | 在使用直方图统计信息之前,您需要创建它们,一旦创建,就需要维护统计信息。如何做到这一点是下一节的主题。 184 | 185 | ## Adding and Maintaining Histograms 186 | 187 | 直方图仅作为统计信息存在,与在表空间中具有物理状态的索引不同。因此,使用也用于更新索引统计信息的 ANALYZE TABLE 语句创建、更新和删除直方图并不令人感到意外。语句有两个变体:更新和删除统计信息。创建和更新直方图时,还需要了解采样率。本节将介绍每个主题。 188 | 189 | ### 创建和更新直方图 190 | 191 | 通过将 UPDATE HISTOGRAM 子句添加到 ANALYZE TABLE语句或更新图。如果没有统计信息并发出更新请求,则创建直方图;如果存在统计信息并请求更新,则创建直方图。否则,将替换现有的直方图。您需要指定要将统计信息划分到的存储桶数。 192 | 193 | 若要使用最多 256个存储桶(长度以分钟表示,因此 256 个存储桶应足以确保单例直方图)将直方图添加到表的长度列中,可以使用如下示例所示的语句: 194 | 195 | ``` 196 | mysql> ANALYZE TABLE sakila.film 197 | UPDATE HISTOGRAM ON length 198 | WITH 256 BUCKETS\G 199 | **************************** 1. row ***************************** 200 | Table: sakila.film 201 | Op: histogram 202 | Msg_type: status 203 | Msg_text: Histogram statistics created for column 'length'. 204 | 1 row in set (0.0057 sec) 205 | ``` 206 | 207 | 或者,您可以在 ANALYZE 和关键字将语句写入二进制日志。 这与更新索引统计信息时的工作方式相同。 208 | 209 | 当完成无错误的直方图创建将等于状态显示已创建直方图统计信息以及哪个列。如果发生错误,等于解释问题。 例如,如果尝试为不存在的列创建直方图,则错误将类似于此示例: 210 | 211 | ``` 212 | mysql> ANALYZE TABLE sakila.film 213 | UPDATE HISTOGRAM ON len 214 | WITH 256 BUCKETS\G 215 | **************************** 1. row *************************** 216 | Table: sakila.film 217 | Op: histogram 218 | Msg_type: Error 219 | Msg_text: The column 'len' does not exist. 220 | 1 row in set (0.0004 sec) 221 | ``` 222 | 223 | 还可以使用相同的语句更新同一表中多个列的直方图。例如,如果要更新表的长度评级列上的直方图,可以使用像清单。 224 | 225 | ``` 226 | Listing 16-1. Updating histograms for multiple columns 227 | mysql> ANALYZE TABLE sakila.film 228 | UPDATE HISTOGRAM ON length, rating 229 | WITH 256 BUCKETS\G 230 | *************************** 1. row *************************** 231 | Table: sakila.film 232 | Op: histogram 233 | Msg_type: status 234 | Msg_text: Histogram statistics created for column 'length'. 235 | **************************** 2. row *************************** 236 | Table: sakila.film 237 | Op: histogram 238 | Msg_type: status 239 | Msg_text: Histogram statistics created for column 'rating'. 240 | 2 rows in set (0.0119 sec) 241 | ``` 242 | 243 | 您应该选择多少桶?如果唯一值少于 1024 个,建议有足够的存储桶来创建单位直方图(即,至少与唯一值一样多的存储桶)。如果选择比值更多的存储桶,MySQL 将只使用存储每个值的频率所需的存储桶。从这个意义上说,存储桶的数量应视为要使用的最大存储桶数。 244 | 245 | 如果超过 1024 个不同的值,则需要足够的存储桶来获取数据的不同表示形式。25 到 100 个铲斗通常是一个很好的起点。对于 100 个存储桶,等高度直方图将平均具有每个存储桶中 1% 的行。行的分布越统一,需要的存储桶就更少,分布差异越大,需要的存储桶就越大。目标是在自己的存储桶中具有最常发生的值。例如,对于上一节中使用的表的子集,五个存储桶将中国 (CHN)、印度 (IND) 和美国放在自己的存储桶中。 246 | 247 | 直方图通过对值进行采样创建。如何完成取决于可用的内存量。 248 | 249 | ### 采样 250 | 251 | 当 MySQL 创建时,它需要读取行来确定可能的值及其频率。这是以类似但不同的方式对索引统计信息进行采样。计算索引统计信息时,将确定唯一值的数量,这是一个简单的任务,因为它只需要计数。因此,您需要指定的只是要采样的页面数。 252 | 253 | 对于直方图,MySQL 不仅必须确定不同值的数量,还要确定它们的频率以及如何将值分发到存储桶中。因此,采样值被读取到内存中,然后用于创建存储桶并计算直方图统计信息。这意味着更自然地指定可用于采样的内存量,而不是页数。根据可用内存量,MySQL 将确定可以采样多少页。 254 | 255 | 分析表期间语句使用选项指定。默认值为 20,000,000 字节。检查直方图数据"部分中讨论的视图包括有关结果采样率的信息。如果没有得到筛选的预期准确性,可以检查采样率,如果采样率低,可以增加histogram_generation_max_mem_size 采样的页数随可用内存量线性缩放,而存储桶数对采样速率没有任何影响。 256 | 257 | ### 删除直方图 258 | 259 | 如果您确定不再需要直方图,可以再次删除它。与更新直方图统计信息一样, 统计信息。您可以在一个语句中删除一个或多个直方图。清单中列出了和评级列上删除直方图的示例。 本章中后的示例部分包括一个查询,可用于查找所有现有直方图。 260 | 261 | ``` 262 | Listing 16-2. Dropping histograms 263 | mysql> ANALYZE TABLE sakila.film 264 | DROP HISTOGRAM ON length, rating\G 265 | *************************** 1. row *************************** 266 | Table: sakila.film 267 | Op: histogram 268 | Msg_type: status 269 | Msg_text: Histogram statistics removed for column 'length'. 270 | *************************** 2. row *************************** 271 | Table: sakila.film 272 | Op: histogram 273 | Msg_type: status 274 | Msg_text: Histogram statistics removed for column 'rating'. 275 | 2 rows in set (0.0120 sec) 276 | ``` 277 | 278 | ANALYZE TABLE 语句类似于创建统计信息。您还可以在 ANALYZE 和,以避免将语句写入二进制日志。 279 | 280 | 一旦您拥有直方图,如何检查统计数据及其元数据?您可以使用信息架构,如下文讨论。 281 | 282 | ## 检查直方图数据 283 | 284 | 当查询计划不是您所期望的时,了解优化器可用的信息非常重要。就像索引统计信息具有各种视图一样,信息架构还包含一个视图,因此您可以查看直方图统计信息。数据可通过数据视图。下一节包括使用此视图检索有关直方图的信息的示例。 285 | 286 | COLUMN_STATISTICS是包含直方图信息的数据字典部分的视图。表总结了四列。 287 | 288 | | 列名称 | 数据类型 | 描述 | 289 | | :---------- | :------------- | :----------------------- | 290 | | SCHEMA_NAME | 瓦尔查尔(64) | 表位于的架构。 | 291 | | TABLE_NAME | 瓦尔查尔(64) | 直方图的列位于其中的表。 | 292 | | COLUMN_NAME | 瓦尔查尔(64) | 带直方图的列。 | 293 | | 直方图 | Json | 直方图的详细信息。 | 294 | 295 | 前三列(SCHEMA_NAME、TABLE_NAME、COLUMN_NAME)构成主键,并允许您查询您感兴趣的直方图。列是最有趣的,因为它存储直方图的元数据以及直方图统计信息。 296 | 297 | 直方图信息作为,其中包含多个对象,其中包括创建统计信息时、采样率和统计信息本身等信息。表显示了文档中包含的字段。当您在查询视图时,字段按字母顺序列出,可能与包含 298 | 299 | | 字段名称 | JSON 类型 | 描述 | 300 | | :------------- | :-------- | :----------------------------------------------------------- | 301 | | 桶 | 阵 列 | 每个存储桶包含一个元素的数组。每个存储桶的可用信息取决于直方图类型,稍后将介绍。 | 302 | | 排序规则 ID | 整数 | 数据排序的 ID。这仅与字符串数据类型相关。ID 与"用户"中的 。 | 303 | | 数据类型 | 字符串 | 已创建直方图的列中数据的数据类型。这不是 MySQL 数据类型,而是更通用的类型,如字符串类型的"字符串"。可能的值是 int、uint(无符号整数)、双精度、十进制、日期时间和字符串。 | 304 | | 直方图类型 | 字符串 | 直方图类型,单位或。 | 305 | | 上次更新 | 字符串 | 上次更新统计信息的时间。格式是。 | 306 | | 空值 | 十进制 | 采样值的分数为。该值介于 0.0 和 1.0 之间。 | 307 | | 指定的存储桶数 | 整数 | 请求的存储桶数。对于单位直方图,这可能大于实际的存储桶数。 | 308 | | 采样率 | 十进制 | 表中采样的页面的分数。该值介于 0.0 和 1.0 之间。当值为 1.0 时,读取了整个表,并且统计信息是准确的。 | 309 | 310 | 该视图不仅可用于确定直方图统计信息,还可以使用它来检查元数据,例如,确定统计信息上次更新以来的一段时间,并用它来确保定期更新统计信息。 311 | 312 | 字段应得到更多的关注,因为它存储了统计信息。它是一个数组,每个存储桶有一个元素。每个存储桶元素本身就是 JSON 数组。对于单位直方图,每个存储桶有两个元素,而对于等高度直方图有四个元素。 313 | 314 | 单位直方图包含的元素是 315 | 316 | - 存储桶的列值。 317 | - 累积频率。 318 | 319 | 等高度,但总共有四个元素可以说明每个存储桶可能包含多个列值的信息。元素是 320 | 321 | - 存储桶中包含的列值的下限。 322 | - 存储桶中包含的列值的上限。 323 | - 累积频率。 324 | - 存储桶中包含的值数。 325 | 326 | 如果返回并考虑计算各种条件的预期筛选效果的示例,可以看到存储桶信息包括所有必要的内容,但也不包含任何额外的信息。 327 | 328 | 由于直方图数据存储为 JSON 文档,因此值得查看检索各种信息的一些示例查询。 329 | 330 | ## 直方图报告示例 331 | 332 | 此视图对于查询直方图数据非常有用。由于元数据和统计信息存储在 JSON 文档中,因此考虑一些可用的 JSON 操作函数非常有用,因此可以检索直方图报表。本节将介绍为系统中的直方图生成报表的几个示例。所有示例也可从本书的 GitHub 存储库中获取,例如,清单中的查询可在文件。 333 | 334 | ### 列出所有直方图 335 | 336 | 基本报告是列出中的所有直方图。要包括的一些相关信息是直方图的架构信息、直方图类型、直方图上次更新的时间、采样速率、存储桶数量等。清单显示了一个直方图的查询和输出(您可能会看到不同的直方图列表,具体取决于您创建的直方图)。 337 | 338 | ``` 339 | Listing 16-3. Listing all histograms 340 | mysql> SELECT SCHEMA_NAME, TABLE_NAME, COLUMN_NAME, 341 | HISTOGRAM->>'$."histogram-type"' AS Histogram_Type, 342 | CAST(HISTOGRAM->>'$."last-updated"' 343 | AS DATETIME(6)) AS Last_Updated, 344 | CAST(HISTOGRAM->>'$."sampling-rate"' 345 | AS DECIMAL(4,2)) AS Sampling_Rate, 346 | JSON_LENGTH(HISTOGRAM->'$.buckets') 347 | AS Number_of_Buckets, 348 | CAST(HISTOGRAM->'$."number-of-buckets-specified"'AS UNSIGNED) 349 | AS Number_of_Buckets_Specified 350 | FROM information_schema.COLUMN_STATISTICS\G 351 | **************************** 1. row **************************** 352 | SCHEMA_NAME: sakila 353 | TABLE_NAME: film 354 | COLUMN_NAME: length 355 | Histogram_Type: singleton 356 | Last_Updated: 2019-06-02 08:49:18.261357 357 | Sampling_Rate: 1.00 358 | Number_of_Buckets: 140 359 | Number_of_Buckets_Specified: 256 360 | 1 row in set (0.0006 sec) 361 | ``` 362 | 363 | 该查询提供直方图的高级别视图。运算符从 JSON 文档中提取一个运算符另外取消引用提取的值,这些值在提取字符串时非常有用。例如,从示例输出中,您可以看到表中长度列直方图具有 140 个存储桶,但请求了 256 个存储桶。您还可以看到它是一个单位直这并不奇怪,因为并非所有请求的存储桶都使用。 364 | 365 | ### 列出单个直方图的所有信息 366 | 367 | 查看直方图的整个输出非常有用。例如,请考虑本创建并填充了八个国家/地区的数据的表。您可以在"国家代码"列上创建具有四个存储桶的等,如 368 | 369 | ``` 370 | ANALYZE TABLE world.city_histogram 371 | UPDATE HISTOGRAM ON CountryCode 372 | WITH 4 BUCKETS; 373 | ``` 374 | 375 | 清单查询此直方图的数据。这与图讨论等直方图时使用的直方图相同。 376 | 377 | ``` 378 | Listing 16-4. Retrieving all data for a histogram 379 | mysql> SELECT JSON_PRETTY(HISTOGRAM) AS Histogram 380 | FROM information_schema.COLUMN_STATISTICS 381 | WHERE SCHEMA_NAME = 'world' 382 | AND TABLE_NAME = 'city_histogram' 383 | AND COLUMN_NAME = 'CountryCode'\G 384 | **************************** 1. row **************************** 385 | Histogram: { 386 | "buckets": [ 387 | [ 388 | "base64:type254:QVVT", 389 | "base64:type254:QlJB", 390 | 0.1813186813186813, 391 | 2 392 | ], 393 | [ 394 | "base64:type254:Q0hO", 395 | "base64:type254:REVV", 396 | 0.4945054945054945, 397 | 2 398 | ], 399 | [ 400 | "base64:type254:RlJB", 401 | "base64:type254:SU5E", 402 | 0.8118131868131868, 403 | 3 404 | ], 405 | [ 406 | "base64:type254:VVNB", 407 | "base64:type254:VVNB", 408 | 1.0, 409 | 1 410 | ] 411 | ], 412 | "data-type": "string", 413 | "null-values": 0.0, 414 | "collation-id": 8, 415 | "last-updated": "2019-06-03 10:35:42.102590", 416 | "sampling-rate": 1.0, 417 | "histogram-type": "equi-height", 418 | "number-of-buckets-specified": 4 419 | } 420 | 1 row in set (0.0006 sec) 421 | ``` 422 | 423 | 此查询有几个有趣的事情。函数用于便于读取直方图信息。如果没有函数,整个文档将作为一行返回。 424 | 425 | 另请注意,每个字符串的下上限作为 base64 编码字符串返回。这是为了确保字符串和二进制列中的任何值都可以由直方图处理。其他数据类型直接存储其值。 426 | 427 | ### 列出单位直方图的存储桶信息 428 | 429 | 在上一个示例中,查询直方图的原始数据。通过使用可以更好地处理存储桶信息。该示例中使用的是个国家/地区(用于避免产出过多)的城市表的副本。"国家代码"列上存在单位图: 430 | 431 | ``` 432 | ANALYZE TABLE world.city_histogram 433 | UPDATE HISTOGRAM ON CountryCode 434 | WITH 8 BUCKETS; 435 | ``` 436 | 437 | 这与图中讨论单例直方图时用于示例的直方图相同。清单显示了对单例直方图进行此项工作的示例。 438 | 439 | ``` 440 | Listing 16-5. Listing the bucket information for a singleton histogram 441 | mysql> SELECT (Row_ID - 1) AS Bucket_Number, 442 | SUBSTRING_INDEX(Bucket_Value, ':', -1) AS 443 | Bucket_Value, 444 | ROUND(Cumulative_Frequency * 100, 2) AS 445 | Cumulative_Frequency, 446 | ROUND((Cumulative_Frequency - LAG(Cumulative_Frequency, 1, 0) 447 | OVER()) * 100, 2) AS Frequency 448 | FROM information_schema.COLUMN_STATISTICS 449 | INNER JOIN JSON_TABLE( 450 | histogram->'$.buckets', 451 | '$[*]' COLUMNS( 452 | Row_ID FOR ORDINALITY, 453 | Bucket_Value varchar(42) PATH '$[0]', 454 | Cumulative_Frequency double PATH '$[1]' 455 | ) 456 | ) buckets 457 | WHERE SCHEMA_NAME = 'world' 458 | AND TABLE_NAME = 'city_histogram' 459 | AND COLUMN_NAME = 'CountryCode' 460 | ORDER BY Row_ID\G 461 | **************************** 1. row ***************************** 462 | Bucket_Number: 0 463 | Bucket_Value: AUS 464 | Cumulative_Frequency: 0.96 465 | Frequency: 0.96 466 | **************************** 2. row **************************** 467 | Bucket_Number: 1 468 | Bucket_Value: BRA 469 | Cumulative_Frequency: 18.13 470 | Frequency: 17.17 471 | **************************** 3. row ***************************** 472 | Bucket_Number: 2 473 | Bucket_Value: CHN 474 | Cumulative_Frequency: 43.06 475 | Frequency: 24.93 476 | **************************** 4. row ***************************** 477 | Bucket_Number: 3 478 | Bucket_Value: DEU 479 | Cumulative_Frequency: 49.45 480 | Frequency: 6.39 481 | **************************** 5. row ***************************** 482 | Bucket_Number: 4 483 | Bucket_Value: FRA 484 | Cumulative_Frequency: 52.2 485 | Frequency: 2.75 486 | **************************** 6. row ***************************** 487 | Bucket_Number: 5 488 | Bucket_Value: GBR 489 | Cumulative_Frequency: 57.76 490 | Frequency: 5.56 491 | **************************** 7. row ***************************** 492 | Bucket_Number: 6 493 | Bucket_Value: IND 494 | Cumulative_Frequency: 81.18 495 | Frequency: 23.42 496 | **************************** 8. row ***************************** 497 | Bucket_Number: 7 498 | Bucket_Value: USA 499 | Cumulative_Frequency: 100 500 | Frequency: 18.82 501 | 8 rows in set (0.0008 sec) 502 | ``` 503 | 504 | 查询将 JSON 上的视图,将 JSON 文档转换为 SQL 表。函数采用两个参数,其中第一个参数是 JSON 文档,第二个参数是值的路径,以及生成的表的列定义。列定义包括为每个存储桶创建的三列: 505 | 506 | - 此列具有子句,它使它成为一个基于 1 的自动增量计数器,因此可以通过减去 1 来用于存储桶编号。 507 | - 与存储桶一起使用的列值。请注意,该值在其 base64 编码解码后返回,因此相同的查询适用于字符串和数值。 508 | - 存储桶的累积频率为 0.0 和 1.0 之间的小数。 509 | 510 | 函数的结果可以与派生表相同的方式使用。累积频率位于将查询百分比的 SELECT 部分窗口函数用于计算每个存储桶的频率(也作为百分比)。 511 | 512 | ### 列出等高度直方图的存储桶信息 513 | 514 | 检索等高度直方图的存储桶信息的查询与刚才为单位直方图讨论的查询非常相似。唯一的区别是等高度直方图有两个值(间隔的开始和结束)定义存储桶和存储桶中的值数。 515 | 516 | 例如,您可以在"国家代码"列上创建一个直个存储桶: 517 | 518 | ``` 519 | ANALYZE TABLE world.city_histogram 520 | UPDATE HISTOGRAM ON CountryCode 521 | WITH 4 BUCKETS; 522 | ``` 523 | 524 | 清单显示了在具有四个存储桶的代码存储桶信息的示例。 525 | 526 | ``` 527 | Listing 16-6. Listing the bucket information for an equi-height histogram 528 | mysql> SELECT (Row_ID - 1) AS Bucket_Number, 529 | SUBSTRING_INDEX(Bucket_Value1, ':', -1) AS 530 | Bucket_Lower_Value, 531 | SUBSTRING_INDEX(Bucket_Value2, ':', -1) AS 532 | Bucket_Upper_Value, 533 | ROUND(Cumulative_Frequency * 100, 2) AS 534 | Cumulative_Frequency, 535 | ROUND((Cumulative_Frequency - LAG(Cumulative_Frequency, 1, 0) 536 | OVER()) * 100, 2) AS Frequency, 537 | Number_of_Values 538 | FROM information_schema.COLUMN_STATISTICS 539 | INNER JOIN JSON_TABLE( 540 | histogram->'$.buckets', 541 | '$[*]' COLUMNS( 542 | Row_ID FOR ORDINALITY, 543 | Bucket_Value1 varchar(42) PATH '$[0]', 544 | Bucket_Value2 varchar(42) PATH '$[1]', 545 | Cumulative_Frequency double PATH '$[2]', 546 | Number_of_Values int unsigned PATH '$[3]' 547 | ) 548 | ) buckets 549 | WHERE SCHEMA_NAME = 'world' 550 | AND TABLE_NAME = 'city_histogram' 551 | AND COLUMN_NAME = 'CountryCode' 552 | ORDER BY Row_ID\G 553 | **************************** 1. row ***************************** 554 | Bucket_Number: 0 555 | Bucket_Lower_Value: AUS 556 | Bucket_Upper_Value: BRA 557 | Cumulative_Frequency: 18.13 558 | Frequency: 18.13 559 | Number_of_Values: 2 560 | **************************** 2. row ***************************** 561 | Bucket_Number: 1 562 | Bucket_Lower_Value: CHN 563 | Bucket_Upper_Value: DEU 564 | Cumulative_Frequency: 49.45 565 | Frequency: 31.32 566 | Number_of_Values: 2 567 | **************************** 3. row ***************************** 568 | Bucket_Number: 2 569 | Bucket_Lower_Value: FRA 570 | Bucket_Upper_Value: IND 571 | Cumulative_Frequency: 81.18 572 | Frequency: 31.73 573 | Number_of_Values: 3 574 | **************************** 4. row ***************************** 575 | Bucket_Number: 3 576 | Bucket_Lower_Value: USA 577 | Bucket_Upper_Value: USA 578 | Cumulative_Frequency: 100 579 | Frequency: 18.82 580 | Number_of_Values: 1 581 | 4 rows in set (0.0011 sec) 582 | ``` 583 | 584 | 现在,您有一些工具来检查直方图数据,剩下的就是展示直方图如何更改查询计划的示例。 585 | 586 | ## 查询示例 587 | 588 | 直方图的主要目标是帮助优化器实现执行查询的最佳方法。查看直方图如何影响优化器以更改查询计划的示例非常有用,因此,为了结束本章,将讨论在子句中的列中添加直方图时更改计划的查询。 589 | 590 | 该查询使用 和查询短于 55 分钟的电影,并具有名称为 Elvis 的演员。这似乎是一个精心策划的示例,但类似的查询很常见,例如,为满足某些条件的客户查找订单。此示例查询可以按如下内容编写: 591 | 592 | ```sql 593 | SELECT film_id, title, length, 594 | GROUP_CONCAT( 595 | CONCAT_WS(' ', first_name, last_name) 596 | ) AS Actors 597 | FROM sakila.film 598 | INNER JOIN sakila.film_actor USING (film_id) 599 | INNER JOIN sakila.actor USING (actor_id) 600 | WHERE length < 55 AND first_name = 'Elvis' 601 | GROUP BY film_id; 602 | ``` 603 | 604 | 标题和列来自和 如果GROUP_CONCAT猫王,使用"第三个函数。(此查询的替代方法是使用但这样,查询结果中包含了名称为 Elvis 的演员的全名。 605 | 606 | 在列的长度和first_name没有,因此优化器无法知道这些列的条件筛选得有多好。 默认情况下,它假定长度上的条件表中大约三分之一的行,并且 first_name 上10% 的行。(下一章包括这些默认筛选器值的来自。 607 | 608 | 图显示了不存在直方图时查询计划。查询计划显示为可视化解释第。 609 | 610 | ![](../附图/Figure%2016-4.png) 611 | 612 | 在查询计划中需要注意的重要一点是器已选择从执行组件表上的完整表,最后加入表。 总查询成本(在图的右上角)计算为 467.20(图中的查询成本编号可能与您获得的成本数字不同,因为它们取决于索引和直方图 ( 统计信息)。 613 | 614 | 如前所述,默认情况下,优化器估计大约三分之一的电影长度小于 55 分钟。只是考虑到长度的可能值,它表明这是一个糟糕的估计(但优化器对电影一无所知,所以它看不到)。事实上,只有6.6%的电影有这个范围的长度。这使得长度成为直方图的候选列,您可以添加该柱线,就像前面显示的一样: 615 | 616 | ``` 617 | ANALYZE TABLE sakila.film 618 | UPDATE HISTOGRAM ON length 619 | WITH 256 BUCKETS; 620 | ``` 621 | 622 | 623 | 624 | 现在,查询计划将更改,如图。 625 | 626 | ![](../附图/Figure%2016-5.png) 627 | 628 | 直方图意味着现在优化器确切地知道如果首先扫描胶片表返回多少行。这可将查询的总成本降低至 282.26,这是一个很好的改进。(同样,根据索引统计信息,您可能会看到不同的更改。示例中的重要一点是直方图更改查询计划和估计成本。 629 | 630 | 此示例还有趣的是,如果更改条件以查找时间小于 60 分钟的影片,更改回第一次扫描表。原因是,有了这种情况,将包含足够的电影的基础上的长度,这是更好地开始寻找候选演员。同样,如果在上添加直方图,则优化器将实现名字对于此数据库中的执行组件来说是一个相当不错的筛选器;特别是,只有一个演员叫猫王。读者可以尝试更改 WHERE 子句,并查看查询计划如何更改。 631 | 632 | ## 总结 633 | 634 | 本章展示了在优化器尝试确定最佳查询计划时,如何使用直方图来改进优化器可用的信息。直方图将列值划分为存储桶,每个存储桶一个值称为单位直方图,或者每个存储桶称为等高度直方图的多个值。对于每个存储桶,确定遇到值的频率,并计算每个存储桶的累积频率。 635 | 636 | 直方图主要适用于不具有索引的候选列,但它们仍用于筛选具有联接的查询。在这种情况下,直方图可以帮助优化器确定最佳联接顺序。在章节末尾提供了一个示例,演示直方图如何更改查询的联接顺序。 637 | 638 | 可以在数据中检查直方图的元数据和视图。该信息包括优化器使用的每个存储桶的所有数据以及元数据,例如上次更新直方图的时间、直方图类型以及请求的存储桶数。 639 | 640 | 在查询示例中,有人提到优化器对于各种条件的估计筛选效果有一些默认值。到目前为止,在索引和直方图的讨论中,优化器大多被忽视。是时候改变这一点了:下一章是关于查询优化器的。 641 | -------------------------------------------------------------------------------- /第6部分-改善查询/Chapter26.md: -------------------------------------------------------------------------------- 1 | # 复制 2 | 3 | 多年来帮助 MySQL 如此流行的功能之一是支持复制,它允许您拥有一个 MySQL 实例,该实例会自动接收来自其源的更新并应用它们。使用快速事务和低延迟网络,复制可以接近实时,但请注意,由于除了 NDB 群集之外,MySQL 中没有同步复制,因此仍有可能较大的延迟。数据库管理员的一项经常性任务是提高复制的性能。多年来,MySQL 复制有许多改进,包括一些可帮助您提高复制性能的改进。 4 | 5 | 本章将首先提供复制的高级别概述,以便介绍术语和测试设置,用于复制监视部分。本章的另一半讨论如何提高连接和应用程序线程的性能,以及如何使用复制将工作卸载到副本。 6 | 7 | ## 复制概述 8 | 9 | 在深入了解提高复制性能之前,讨论复制的工作原理非常重要。这将有助于就术语达成一致,并在本章其余部分为讨论提供参考点。 10 | 11 | 的工作原理是记录对复制源所做的更改,然后将其发送到连接线程存储数据并应用数据的一个或多个应用线程的副本。图显示了复制的简化概述,省略了与存储引擎和实现详细信息相关的所有内容。 12 | 13 | ![](../附图/Figure%2026-1.png) 14 | 15 | 当事务提交其更改时,这些更改将写入 InnoDB 特定文件(重做日志和数据文件)和二。二进制日志由一系列文件以及索引文件以及列出二进制日志文件的索引文件组成。将事件写入二进制日志文件后,它们将发送到副本。可能有多个副本,在这种情况下,事件将发送到所有副本。 16 | 17 | 在副本上,连接接收事件并将它们写入中。中继日志的工作方式与二进制日志相同,只是它用作临时存储,直到应用线程可以应用事件。可能有一个或多个应用程序线程。也可能副本从多个源(称为多源复制)复制,在这种情况下,每个复制通道有一组一个连接线程和一个或多个。(也就是说,最常见的是每个副本的单个源。或者,副本将更改写入其自己的二进制日志,使其成为复制副本进一步下游复制链的源。在这种情况下,通常调用它为中。图显示了一个使用副本接收来自两个源的更新的设置示例,其中一个是中继实例。 18 | 19 | ![](../附图/Figure%2026-2.png) 20 | 21 | 此处复制到中继,而中继实例又复制到。也会复制到实例。每个都有一个名称,可以区分它们,在多源复制中,每个通道必须具有唯一的名称。默认通道名称为空字符串。讨论监视时,它将使用像图中的复制设置。 22 | 23 | ## 监测 24 | 25 | 当您遇到复制性能问题时,第一步是确定在上一节中描述的步骤链中引入延迟的地点。如果您在早期版本的 MySQL 中一直在使用复制,可以跳转到以检查复制的运行状况;如果一直在使用复制,可以跳转到"显示从状态"命令,以检查复制的运行状况。但是,在 MySQL 8 中,这是要检查的最后一个监视信息源。 26 | 27 | 在 MySQL 8 中,监视复制信息的主要来源是其中包含多个表,描述复制副本上每个复制步骤的配置和状态。性能架构表的一些优点如下: 28 | 29 | - 状态表包括有关复制延迟的更多详细信息,其形式为复制过程中的每个步骤提供微秒分辨率,并且具有来自原始和直接源的时间戳。 30 | - 您可以使用 SELECT 语句表。这允许您查询您最感兴趣的信息,并可以操作数据。当您有多个复制通道时,这一优势尤其明显,的输出在控制台中检查时会很快变得难以使用。 31 | - 数据被拆分为逻辑组,每个组有一个表。配置和应用程序进程有单独的表,配置和状态有单独的表。 32 | 33 | 首次开始使用性能架构复制表时,可能很难理解这些表之间的关系及其与复制流的关系。图显示了单个复制通道的复制流,并添加了与它们包含的信息对应的复制表。图中的表也可用于组复制,通道用于事务通道。 34 | 35 | ![](../附图/Figure%2026-3.png) 36 | 37 | 事件从直接源到达图形的顶部,由具有两个表的连接线程处理,该连接和。连接线程将事件写入中继日志,并且应用器在应用复制筛选器时从中继日志中读取事件。复制筛选器可以在"复制"和中找到。 可以在"应用程序"和"应用程序"表中应用状态。 38 | 39 | 在并行也称为多线程,协调器然后处理事务,并使其可供工作人员使用。可以通过该表监视如果副本使用单线程复制,则跳过协调器步骤。 40 | 41 | 最后一步是应用程序工作人员。在并行复制的情况下,每个线程,并且每个线程都有一个行,其状态中。 42 | 43 | 本节的其余部分将介绍连接和应用程序的性能架构复制表以及日志状态和组复制表。 44 | 45 | ### 连接表 46 | 47 | 复制事件到达副本时的第一步是将它们写入中继日志。处理此操作的是连接线程。 48 | 49 | 有两表提供与连接相关的信息: 50 | 51 | - 复制通道的配置。 52 | - 的状态。这包括显示最初提交最后一个和当前队列事务的时间戳、在直接源实例上提交的时间以及写入中继日志的时间戳。每个通道有一行。 53 | 54 | 复制连接表包括与连接到直接上游源相关的信息,以及在原始源上提交最新接收事件时的时间戳。在简单的复制设置中,即时源和原始源是相同的,但在链式复制中,两者是不同的。清单显示了上一节中讨论的中两个连接表的内容示例。为了提高本书的可读性,对输出重新格式化。原始格式化的输出(包括复制通道的行)包含在文件。 55 | 56 | ``` 57 | Listing 26-1. The replication connection tables 58 | mysql> SELECT * 59 | FROM performance_schema.replication_connection_configuration 60 | WHERE CHANNEL_NAME = 'relay'\G 61 | *************************** 1. row *************************** 62 | CHANNEL_NAME: relay 63 | HOST: 127.0.0.1 64 | PORT: 3308 65 | USER: root 66 | NETWORK_INTERFACE: 67 | AUTO_POSITION: 1 68 | SSL_ALLOWED: YES 69 | SSL_CA_FILE: 70 | SSL_CA_PATH: 71 | SSL_CERTIFICATE: 72 | SSL_CIPHER: 73 | SSL_KEY: 74 | SSL_VERIFY_SERVER_CERTIFICATE: NO 75 | SSL_CRL_FILE: 76 | SSL_CRL_PATH: 77 | CONNECTION_RETRY_INTERVAL: 60 78 | CONNECTION_RETRY_COUNT: 86400 79 | HEARTBEAT_INTERVAL: 30 80 | TLS_VERSION: 81 | PUBLIC_KEY_PATH: 82 | GET_PUBLIC_KEY: NO 83 | NETWORK_NAMESPACE: 84 | COMPRESSION_ALGORITHM: uncompressed 85 | ZSTD_COMPRESSION_LEVEL: 3 86 | 1 row in set (0.0006 sec) 87 | mysql> SELECT * 88 | FROM performance_schema.replication_connection_status 89 | WHERE CHANNEL_NAME = 'relay'\G 90 | *************************** 1. row *************************** 91 | CHANNEL_NAME: relay 92 | GROUP_NAME: 93 | SOURCE_UUID: cfa645e7-b691-11e9-a051- 94 | ace2d35785be 95 | THREAD_ID: 44 96 | SERVICE_STATE: ON 97 | COUNT_RECEIVED_HEARTBEATS: 26 98 | LAST_HEARTBEAT_TIMESTAMP: 2019-08-11 99 | 10:26:16.076997 100 | RECEIVED_TRANSACTION_SET: 4d22b3e5-a54f-11e9-8bdbace2d35785be:23-44 101 | LAST_ERROR_NUMBER: 0 102 | LAST_ERROR_MESSAGE: 103 | LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00 104 | LAST_QUEUED_TRANSACTION: 4d22b3e5-a54f-11e9-8bdbace2d35785be:44 105 | LAST_QUEUED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 2019-08-11 10:27:09.483703 106 | LAST_QUEUED_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 2019-08-11 10:27:10.158297 107 | LAST_QUEUED_TRANSACTION_START_QUEUE_TIMESTAMP: 2019-08-11 10:27:10.296164 108 | LAST_QUEUED_TRANSACTION_END_QUEUE_TIMESTAMP: 2019-08-11 10:27:10.299833 109 | QUEUEING_TRANSACTION: 110 | QUEUEING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 0000-00-00 00:00:00 111 | QUEUEING_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 0000-00-00 00:00:00 112 | QUEUEING_TRANSACTION_START_QUEUE_TIMESTAMP: 0000-00-00 00:00:00 113 | 1 row in set (0.0006 sec) 114 | ``` 115 | 116 | 117 | 118 | 配置表在很大程度上对应于使用 CHANGE Master TO 语句设置复制时可以提供,并且除非显式更改配置,否则数据是静态的。状态表主要包含随着事件处理而快速变化的可变数据。 119 | 120 | 状态表中的时间戳特别令人感兴趣。有两个组,第一组显示最后一个排队事件的时间戳,第二个组显示当前正在排队的事件的时间戳。正在排队的事件意味着它正在写入中继日志。例如,请考虑事件的时间戳: 121 | 122 | - 事件在原始源上提交的时间(来源 123 | - 事件在直接源上提交的时间(中)。 124 | - 此实例开始排队的事件的时间 , 即接收事件和连接线程开始将事件写入中继日志的时间。 125 | - 连接线程完成将事件写入中继日志的时间。 126 | 127 | 微秒分辨率显示,因此它允许您详细了解事件从原始源到中继日志的进行多长时间。零时间戳 () 表示没有要返回的数据;例如,当连接线程完全保持最新时,当前排队时间戳可能会发生这种情况。applier 表提供了有关事件通过副本的旅途中的更多详细信息。 128 | 129 | ### 应用表 130 | 131 | 应用线程更为复杂,因为它们既处理事件筛选和应用事件,又支持并行应用器。 132 | 133 | 在编写时,存在以下表,包含有关 applier 线程的信息: 134 | 135 | - 此表显示每个复制通道的 applier 线程的配置。目前唯一的设置是配置的复制延迟。每个通道有一行。 136 | - 每个复制通道的复制筛选器。该信息包括筛选器的配置和激活时间。 137 | - 应用于所有复制通道的复制筛选器。该信息包括筛选器的配置和激活时间。 138 | - 应用器的总体状态,包括服务状态、剩余延迟(当配置了所需的延迟时)以及事务已出现的重报数。每个通道有一行。 139 | - 使用并行复制时,协调器线程看到的应用器状态。上次处理的事务和当前处理的事务有时间戳。每个通道有一行。对于单线程复制,此表为空。 140 | - 每个"应用器"状态。上次应用的事务和当前应用的事务有时间戳。配置并行复制时,每个工作线程有一行(每个通道配置的数)。对于单线程复制,每个通道有一行。 141 | 142 | 在高级别上,applier 表遵循与连接表相同的模式,增加了筛选器配置表并支持并行应用器。清单显示了中继表的示例。已对输出进行重新格式化,以提高可读性。在本书的 GitHub 存储库中中的文件中也有输出。 143 | 144 | ``` 145 | Listing 26-2. The replication_applier_status_by_worker table 146 | mysql> SELECT * 147 | FROM performance_schema.replication_applier_status_by_worker 148 | WHERE CHANNEL_NAME = 'relay'\G 149 | *************************** 1. row *************************** 150 | CHANNEL_NAME: relay 151 | WORKER_ID: 1 152 | THREAD_ID: 54 153 | SERVICE_STATE: ON 154 | LAST_ERROR_NUMBER: 0 155 | LAST_ERROR_MESSAGE: 156 | LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00 157 | LAST_APPLIED_TRANSACTION: 158 | LAST_APPLIED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 0000-00-00 00:00:00 159 | LAST_APPLIED_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 0000-00-00 00:00:00 160 | LAST_APPLIED_TRANSACTION_START_APPLY_TIMESTAMP: 0000-00-00 00:00:00 161 | LAST_APPLIED_TRANSACTION_END_APPLY_TIMESTAMP: 0000-00-00 00:00:00 162 | APPLYING_TRANSACTION: 163 | APPLYING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 0000-00-00 00:00:00 164 | APPLYING_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 0000-00-00 00:00:00 165 | APPLYING_TRANSACTION_START_APPLY_TIMESTAMP: 0000-00-00 00:00:00 166 | LAST_APPLIED_TRANSACTION_RETRIES_COUNT: 0 167 | LAST_APPLIED_TRANSACTION_LAST_TRANSIENT_ERROR_NUMBER: 0 168 | LAST_APPLIED_TRANSACTION_LAST_TRANSIENT_ERROR_MESSAGE: 169 | LAST_APPLIED_TRANSACTION_LAST_TRANSIENT_ERROR_TIMESTAMP: 0000-00-00 00:00:00 170 | APPLYING_TRANSACTION_RETRIES_COUNT: 0 171 | APPLYING_TRANSACTION_LAST_TRANSIENT_ERROR_NUMBER: 0 172 | APPLYING_TRANSACTION_LAST_TRANSIENT_ERROR_MESSAGE: 173 | APPLYING_TRANSACTION_LAST_TRANSIENT_ERROR_TIMESTAMP: 0000-00-00 00:00:00 174 | *************************** 2. row *************************** 175 | CHANNEL_NAME: relay 176 | WORKER_ID: 2 177 | THREAD_ID: 55 178 | SERVICE_STATE: ON 179 | LAST_ERROR_NUMBER: 0 180 | LAST_ERROR_MESSAGE: 181 | LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00 182 | LAST_APPLIED_TRANSACTION: 4d22b3e5-a54f11e9-8bdbace2d35785be:213 183 | LAST_APPLIED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 2019-08-11 11:29:36.1076 184 | LAST_APPLIED_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 2019-08-11 11:29:44.822024 185 | LAST_APPLIED_TRANSACTION_START_APPLY_TIMESTAMP: 2019-08-11 11:29:51.910259 186 | LAST_APPLIED_TRANSACTION_END_APPLY_TIMESTAMP: 2019-08-11 11:29:52.403051 187 | APPLYING_TRANSACTION: 4d22b3e5-a54f-11e9-8bdbace2d35785be:214 188 | APPLYING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 2019-08-11 11:29:43.092063 189 | APPLYING_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 2019-08-11 11:29:52.685928 190 | APPLYING_TRANSACTION_START_APPLY_TIMESTAMP: 2019-08-11 11:29:53.141687 191 | LAST_APPLIED_TRANSACTION_RETRIES_COUNT: 0 192 | LAST_APPLIED_TRANSACTION_LAST_TRANSIENT_ERROR_NUMBER: 0 193 | LAST_APPLIED_TRANSACTION_LAST_TRANSIENT_ERROR_MESSAGE: 194 | LAST_APPLIED_TRANSACTION_LAST_TRANSIENT_ERROR_TIMESTAMP: 0000-00-00 00:00:00 195 | APPLYING_TRANSACTION_RETRIES_COUNT: 0 196 | APPLYING_TRANSACTION_LAST_TRANSIENT_ERROR_NUMBER: 0 197 | APPLYING_TRANSACTION_LAST_TRANSIENT_ERROR_MESSAGE: 198 | APPLYING_TRANSACTION_LAST_TRANSIENT_ERROR_TIMESTAMP: 0000-00-00 00:00:00 199 | ``` 200 | 201 | 202 | 203 | 时间与之前看到的相同的模式,该模式包含上次处理的事务和当前事务的信息。请注意,对于第一行,所有时间戳均为零,这表明应用者无法利用并行复制。 204 | 205 | 对于具有全局事务标识符 4d22b3e5-a54f-11e9-8bdb-ace2d35785be:213 的最后一个应用事务,可以看到事务是在 11:29:36.1076 在原始源上提交的, 在 11:29:44.822024 上提交,开始在 11:29:51.910259 执行此实例,并在 11:29:52.403051 完成执行。这表明每个实例都会增加大约 8 秒的延迟,但事务本身只需半秒即可执行。您可以得出结论,复制延迟不是由应用单个大型事务引起的,而是中继和副本实例无法像原始源那样快速处理事务、延迟是由较早运行的长期事件引入的,并且复制尚未赶上,或者延迟是在复制链的其他部分引入的。 206 | 207 | ### 日志状态 208 | 209 | 与复制相关的表是 log_status表它提供有关二进制日志、中继日志和 InnoDB 重做日志的信息,使用日志锁返回对应于同一时间点的数据。引入该表时时时时要牢记查询表需要具有权限。清单显示了使用函数的示例输出,以便更轻松地读取作为 JSON 文档返回的信息。 210 | 211 | ``` 212 | Listing 26-3. The log_status table 213 | mysql> SELECT SERVER_UUID, 214 | JSON_PRETTY(LOCAL) AS LOCAL, 215 | JSON_PRETTY(REPLICATION) AS REPLICATION, 216 | JSON_PRETTY(STORAGE_ENGINES) AS STORAGE_ENGINES 217 | FROM performance_schema.log_status\G 218 | *************************** 1. row *************************** 219 | SERVER_UUID: 4d46199b-bbc9-11e9-8780-ace2d35785be 220 | LOCAL: { 221 | "gtid_executed": "4d22b3e5-a54f-11e9-8bdb-ace2d35785be:1-380,\ncbffdc28- 222 | bbc8-11e9-9aac-ace2d35785be:1-190", 223 | "binary_log_file": "binlog.000003", 224 | "binary_log_position": 199154947 225 | } 226 | REPLICATION: { 227 | "channels": [ 228 | { 229 | "channel_name": "relay", 230 | "relay_log_file": "relay-bin-relay.000006", 231 | "relay_log_position": 66383736 232 | }, 233 | { 234 | "channel_name": "source2", 235 | "relay_log_file": "relay-bin-source2.000009", 236 | "relay_log_position": 447 237 | } 238 | ] 239 | } 240 | STORAGE_ENGINES: { 241 | "InnoDB": { 242 | "LSN": 15688833970, 243 | "LSN_checkpoint": 15688833970 244 | } 245 | } 246 | 1 row in set (0.0005 sec) 247 | ``` 248 | 249 | 250 | 251 | LOCAL包括有关已执行的全局事务标识符以及二进制日志文件和在此实例上的位置的信息。复制显示与复制过程相关的日志数据,每个通道有一个对象。列包含有关 InnoDB 日志序列号的信息。 252 | 253 | ### 组复制表 254 | 255 | 如果使用"",则有两个附加表可用于监视复制。一个表包含有关组成员的高级别信息,另一个表包含成员的各种统计信息。 256 | 257 | 两个表是 258 | 259 | - 成员概述。每个成员有一行,数据包括当前状态以及它是主成员还是辅助成员。 260 | - 较低,如队列中的事务数、对所有成员提交哪些事务、有多少事务在本地或远程发起,等等。 261 | 262 | replication_group_members对于验证成员的状态最有用。replication_group_member_stats可用于查看每个节点如何查看已完成的工作,以及冲突和回滚率是否高。这两个表都包括来自群集中所有节点的信息。 263 | 264 | 现在您已经知道如何监视了,您可以开始优化连接和应用程序线程。 265 | 266 | ## 连接 267 | 268 | 连接线程处理到复制的直接源的出站连接、复制事件的接收以及将事件保存到中继日志。这意味着优化连接过程围绕复制事件、网络、维护有关已收到哪些事件的信息以及写入中继日志。 269 | 270 | ### 复制事件 271 | 272 | 使用(默认值和建议)时,事件包括有关已更改的行和新值(映像之前和之后)的信息。默认情况下,包含更新和删除事件的映像前的完整。这使得副本能够应用事件,即使源和副本的列顺序不同或具有不同的主要键定义。但是,它确实使二进制日志 (因此也中继日志) 更大,这意味着更多的网络流量、内存使用情况和磁盘 I/O。 273 | 274 | 如果不需要显示完整的图像之前,可以将"binlog_row_image最小意味着只有标识行所需的列包含在前图像中,后图像仅包括事件更改的列。使用时,除外的所有列都包含在上图中,图像中包含 Blob 和文本列(如果其值已更改)。 使用值是性能的最佳方法,但在对生产系统进行更改之前,请确保进行彻底测试。 275 | 276 | 也可以设置",因此可以根据需要更改该选项。 277 | 278 | ### 网络 279 | 280 | MySQL 中用于复制的网络的主要调优选项是使用的接口以及是否启用压缩。如果网络过载,它很快就会使复制落后。避免这种情况的选项是使用专用网络接口和路由进行复制流量。另一种选择是启用压缩,可以减少以更高的 CPU 负载代价传输的数据量。这两个解决方案都使用实现。 281 | 282 | 定义如何连接到复制源时,可以使用选项指定要用于连接的接口。例如,如果要使用副本上具有 IP 地址 192.0.2.102 的接口从源复制,则可以使用: 283 | 284 | ``` 285 | CHANGE MASTER TO MASTER_BIND='192.0.2.102', 286 | MASTER_HOST='192.0.2.101', 287 | MASTER_PORT=3306, 288 | MASTER_AUTO_POSITION=1, 289 | MASTER_SSL=1; 290 | ``` 291 | 292 | 293 | 294 | 根据需要替换地址和其他信息。 295 | 296 | 压缩在 MySQL 8.0.18使用采用一组允许的算法的"压缩"选项。支持的算法是 297 | 298 | - 压缩。这是默认值。 299 | - 使用 zlib 压缩算法。 300 | - 使用 ztd 版本 1.3 压缩算法。 301 | 302 | 如果包括算法,则可以使用选项指定压缩级别。支持级别为 1~22(两者包括),默认值为 3。将复制连接配置为使用压缩级别为 5 的或算法的示例是 303 | 304 | ``` 305 | CHANGE MASTER TO MASTER_COMPRESSION_ALGORITHMS='zlib,zstd', 306 | MASTER_ZSTD_COMPRESSION_LEVEL=5; 307 | ``` 308 | 309 | 310 | 311 | 在 MySQL 8.0.18 之前,您可以指定是否将一起使用。如果源和副本支持算法,则将选项设置为 会使复制连接使用 zlib 压缩。 312 | 313 | ### 维护源信息 314 | 315 | 副本需要跟踪从源接收的信息。这是通过表完成的。也可以将信息存储在文件中,但自 8.0.18 起,该信息已被弃用,不鼓励这样做。使用文件还可以降低副本从崩溃中恢复的弹性。 316 | 317 | 关于维护此信息的性能,因此重要的选择这指定信息更新的频率,默认值为每 10000 个事件。您可能认为,与源端类似的数据,在每个事件之后同步数据非常重要;然而,情况并非如此。 318 | 319 | 没有必要非常频繁地更新信息的原因是,通过丢弃中继日志和从应用程序到达点开始获取所有内容,可以从信息丢失中恢复。因此,默认值 10000 是好的,很少有任何理由更改它。 320 | 321 | ### 写入中继日志 322 | 323 | 日志是接收复制事件的连接和应用程序已处理它们之间的复制事件的中间存储。影响中继日志写入速度的因素主要有两个:磁盘性能和中继日志同步到磁盘的速度。 324 | 325 | 您需要确保写入中继日志的磁盘有足够的 I/O 容量来维持写入和读取活动。一个选项是将中继日志存储在单独的存储中,以便其他活动不会干扰中继日志的写入和读取。 326 | 327 | 使用"sync_relay_log"与磁盘默认值是每 10000 个事件同步一次。除非将基于位置的复制(禁用与并行应用线程一恢复中继日志。对于基于位置的并行复制除非在操作系统崩溃时重新生成副本是可以接受的。 328 | 329 | 这意味着,从性能角度来看,建议在执行 CHANGE Master TO并设置"=1。否则,请将与主信息相关的其他设置保留为默认值,并将中继日志保留为默认值。 330 | 331 | ## The Applier 332 | 333 | 应用程序是复制延迟的最。主要问题是,对源所做的更改通常是高度并行工作负载的结果。相反,默认情况下,应用器是单线程的,因此单个线程必须跟上源上潜在的数十或数百个并发查询。这意味着,用于解决应用程序延迟的主要工具是启用并行复制。此外,还将讨论主键的重要性、放宽数据安全设置的可能性以及复制筛选器的使用。 334 | 335 | ### 并行应用器 336 | 337 | 将应用程序配置为使用多个线程并行应用事件是提高复制性能的最有力方法。但是,它不像将 1 的值那样简单。还有其他选项(在源和副本上)需要考虑。 338 | 339 | 表总结了影响并行复制的配置选项,包括是否应在源或副本上设置该选项。 340 | 341 | | 选项名称和配置地点 | 描述 | 342 | | :--------------------------------------------------- | :----------------------------------------------------------- | 343 | | binlog_transaction_dependency_tracking设置在源上 | 要在二进制日志中包含哪些有关事务之间依赖项的信息。 | 344 | | binlog_transaction_dependency_history_size设置在源上 | 上次更新行时保存信息的时间。 | 345 | | transaction_write_set_extraction设置在源上 | 如何提取写入集信息。 | 346 | | binlog_group_commit_sync_delay设置在源上 | 等待更多事务在组提交功能中分组在一起的延迟。 | 347 | | slave_parallel_workers设置在副本上 | 要为每个通道创建多少个应用线程 | 348 | | slave_parallel_type设置在副本上 | 是并行于数据库还是逻辑时钟。 | 349 | | slave_pending_jobs_size_max设置在副本上 | 可用于保存尚未应用的事件的内存量。 | 350 | | slave_preserve_commit_order设置在副本 | 是否确保副本以与源顺序相同的顺序将事务写入其二进制日志。启用此功能需要将设置为。 | 351 | | slave_checkpoint_group设置在副本上 | 要在检查点操作之间处理的最大事务数。 | 352 | | slave_checkpoint_period设置在副本上 | 检查点操作之间的最大时间(毫秒)。 | 353 | 354 | 选项最常用的是和副本上。 355 | 356 | 源上的二进制日志事务依赖项跟踪和写入集提取选项是相关的。选项指定如何提取写入集信息(有关哪些行受事务影响的信息)。写入集也是组复制用于冲突检测的用途。将它设置为这也是组复制所需的值。 357 | 358 | 指定二进制日志中可用的事务依赖项信息。对于并行复制来说,这一点对于能够知道哪些事务可以安全地并行应用非常重要。默认值是使用提交顺序并依赖于提交时间戳。为了改进根据逻辑时钟并行化时并行复制性能,请将 359 | 360 | 指定不断提供上次修改给定行的事务的信息的行哈希数。默认值 25000 通常足够大;但是,如果对不同行的修改率非常高,则值得增加依赖项历史记录大小。 361 | 362 | 在副本上,使用"slave_parallel_workers复制。 这是将每个复制通道创建的应用辅助线程数。设置得足够高,使复制保持,但不是太高,以最终有空闲工作人员或您看到来自过于平行的工作负荷的争用。 363 | 364 | 更新副本通常需要的另一个选项是"slave_parallel_type这指定了如何在应用工作者之间拆分事件。默认值为名称建议根据它们所属的架构拆分更新。另一种选择使用组提交信息或二进制日志中的写入集信息来确定哪些事务可以安全地一起应用。除非在二进制日志中包含多个层的副本通常是最佳选择。 365 | 366 | 如果在未启用使用并行化以在组提交功能中将更多事务组合在一起,但代价是更长的提交延迟。这将使并行复制有更多的事务在工作人员之间分布,从而提高有效性。 367 | 368 | 复制延迟的另一个主要因素是缺少主密钥。 369 | 370 | ### 主键 371 | 372 | 使用基于行的复制时,处理事件的应用人员必须找到必须更改的行。如果有主键则非常简单高效 , 只是一个主键查找。但是,如果没有主键,则必须检查所有行,直到找到所有列的值与复制事件前映像中的值相同的行。 373 | 374 | 如果表很大,这样的搜索是昂贵的。如果事务修改了相对较大的表中的许多行,则在最坏的情况下,复制似乎已经停止。MySQL 8 使用优化,它使用哈希匹配一组行与表;但是,有效性取决于在一个事件中修改的行数,并且它永远不会像主键查找那样有效。 375 | 376 | 强烈建议您向所有表添加显式主键(或非唯一键)。如果您自己不添加主密钥,则 InnoDB 会添加隐藏的主密钥(不能用于复制),因此没有磁盘空间或内存可以节省任何空间或内存。隐藏的主键是一个 6 字节整数,并使用全局计数器,因此,如果有许多具有隐藏主键的表,则计数器可能会成为瓶颈。此外,如果要使用组复制,则严格要求所有表都具有显式主键或非唯一索引。 377 | 378 | 如果无法向某些键,则哈希搜索算法效果更好,每个复制事件中包含的行数更多。通过增加复制的源实例上的 binlog_row_event_max_size 的大小,行数。 379 | 380 | ### 放松数据安全 381 | 382 | 提交事务时,必须在磁盘上保留事务。在 InnoDB 中,通过重做日志和通过二进制日志复制来保证持久性。在某些情况下,在副本上放宽更改已保留的保证是可以接受的。此优化要花费在操作系统崩溃时重建副本的费用。 383 | 384 | InnoDBinnodb_flush_log_at_trx_commit,以确定每次事务提交时是否刷新重做日志。默认(和最安全的设置)是在每次提交后刷新)。冲洗是一项昂贵的操作,甚至某些 SSD 驱动器也遇到无法跟上繁忙系统所需的冲洗问题。如果能够承受丢失最多一秒钟的已提交事务的费用,您可以将innodb_flush_log_at_trx_commit 0 或 2。 如果您愿意进一步推迟刷新,这将设置刷新重做日志之间的最大时间量(以秒为单位)。默认值和最小值为 1 秒。这意味着,如果发生灾难性故障,您可能需要重建副本,但好处是,应用程序线程可以提交比源更便宜的更改,从而更容易跟上。 385 | 386 | 二进制日志同样使用选项,该选项也默认为 1,这意味着每次提交后刷新二进制日志。如果您不需要副本上的二进制日志(请注意,对于组复制,必须在所有注释上启用二进制日志),可以考虑完全禁用它或减少日志的同步频率。通常情况下,最好将 sync_binlog 设置为100 或 1000 而不是 0,因为 0 通常会导致整个二进制日志在旋转时一次刷新。刷新千兆字节可能需要几秒钟;同时,还有一个静音,可以防止提交事务。 387 | 388 | ### 复制筛选器 389 | 390 | 如果不需要副本上的所有数据,可以使用复制筛选器来减少应用线程所需的工作,并减少磁盘和内存要求。这还可以帮助副本保持最新的源。有六个选项来设置。选项可以分为三组,包括 do,如表。 391 | 392 | | 选项名称 | 描述 | 393 | | :--------------------------- | :---------------------------------------------- | 394 | | 复制 - 做 db复制 - 忽略 - db | 是否包括作为值给出的架构(数据库)的更改。 | 395 | | 复制 - 做表复制-忽略表 | 是否包括作为值给出的表的更改。 | 396 | | 复制野生做表复制野生忽略表 | 与和一样,但对 _ 通配符的支持与编写子句时相同。 | 397 | 398 | 指定其中一个选项时,可以选择使用规则应应用于和冒号的通道名称为架构/表添加前缀。例如,忽略源 的世界架构更新 399 | 400 | ``` 401 | [mysqld] 402 | replicate-do-db = source2:world 403 | ``` 404 | 405 | 406 | 407 | 这些选项只能在 MySQL 配置文件,并且需要重新启动 MySQL 才能生效。您可以多次指定每个选项以添加多个规则。如果需要动态更改配置,可以使用"更改复制筛选器"筛选器,例如: 408 | 409 | ``` 410 | mysql> CHANGE REPLICATION FILTER 411 | REPLICATE_IGNORE_DB = (world) 412 | FOR CHANNEL 'source2'; 413 | Query OK, 0 rows affected (0.0003 sec) 414 | ``` 415 | 416 | 417 | 418 | 需要使用世界各地的,因为如果需要包含多个数据库,可以指定列表。如果多次指定同一规则,则应用后者,而忽略前者。 419 | 420 | 复制筛选器最适合基于行的复制,因为可以清楚地了解哪个表受事件影响。当您有一个语句时,该语句可能会影响多个表,因此对于基于语句的复制,并不总是清楚筛选器是否应允许该语句。应特别注意复制复制就像使用基于语句的复制一样,它们使用默认架构来决定是否允许语句。更糟糕的是,使用具有行和语句事件混合的复制筛选器,因为筛选器的效果可能取决于更改复制的格式。 421 | 422 | 结束关于如何提高复制性能。还剩下一个主题,这与目前讨论的内容正好相反 — 如何使用副本提高源的性能。 423 | 424 | ## 将工作卸载到副本 425 | 426 | 如果实例因读取查询而重载时出现问题,则提高性能的常见策略是将某些工作卸载到一个或多个副本。一些常见方案是使用副本进行读取横向扩展,并使用副本进行报告或备份。本节将介绍此内容。 427 | 428 | ### 读取横向扩展 429 | 430 | 复制的最常见用途之一是允许查询使用副本,从而减少复制源上的负载。这是可能的,因为副本具有与其源相同的数据。需要注意的主要事情是,即使在最好的时候,在源上提交事务的小延迟,直到副本发生更改。 431 | 432 | 如果应用程序对读取陈旧数据很敏感,则选择"组复制"或"InnoDB 群集",该群集在版本 8.0.14 及更晚版本中支持一致性级别,因此您可以确保应用程序使用所需的一致性级别。 433 | 434 | 使用副本还可以帮助您使应用程序和 MySQL 更接近最终用户,从而减少往返延迟,从而获得更好的体验。 435 | 436 | ### 任务分离 437 | 438 | 副本的另一个常见用途是对副本执行影响任务,以减少复制源上的负载。两个典型的任务是报告和备份。 439 | 440 | 使用副本报告查询时,配置副本的方式可能与源不同,以针对它用于的特定工作负荷对其进行优化。。也可以使用复制筛选器来避免包括来自源的所有数据和更新。数据越少意味着副本必须应用更少的事务并写入更少的数据,并且您可以将较大比例的数据读取到缓冲池中。 441 | 442 | 使用副本进行备份也很常见。如果副本专用于备份,则无需担心由于磁盘 I/O 或缓冲池污染而导致的锁和性能下降,只要副本在下次备份之前可以赶上。您甚至可以考虑在备份期间关闭副本并执行冷备份。 443 | 444 | ## 总结 445 | 446 | 本章介绍复制的工作原理、如何监视和改进复制过程的性能,以及如何使用复制在多个实例之间分发工作。 447 | 448 | 本章的开始与复制有关,包括介绍术语,并展示了在什么地方可以找到复制的监视信息。在 MySQL 8 中,监视复制的最佳方式是使用一系列性能架构表,这些表根据线程类型以及信息是配置还是状态来拆分信息。还有专用于日志状态和组复制的表。 449 | 450 | 可以通过减少复制事件的大小来优化连接线程,只需包含有关复制事件中更新行之前值的最小信息。不过,这并不能适用于所有应用程序。您还可以更改网络和写入中继日志。建议使用启用自动定位的基于 GTID 的复制,从而放松中继日志的同步。 451 | 452 | 对于 applier 的性能来说,最重要的两点是启用并行复制并确保所有表都有主键。并行复制可以通过更新影响架构或逻辑时钟进行。后者通常是性能最好的,但也有例外,因此您需要验证您的工作负载。 453 | 454 | 最后,讨论了如何使用副本来卸载在复制源上必须执行的工作。您可以使用复制进行读取横向扩展,因为您可以使用副本读取数据,并专用于需要写入数据的任务的源。您还可以将副本用于高度密集的工作,如报告和备份。 455 | 456 | 最后一章将介绍通过使用缓存完成的量。 -------------------------------------------------------------------------------- /致谢.md: -------------------------------------------------------------------------------- 1 | 我要感谢所有使这本书成为可能的人。Apress团队再次帮了大忙,我特别要感谢乔纳森·根尼克、吉尔·巴尔扎诺和劳拉·贝伦德森,他们三位编辑在准备制作这本书时都曾合作过。 2 | 3 | 在技术讨论中,有几个人是宝贵的合作伙伴。感谢查尔斯贝尔提供彻底的审查;他的评论一如既往,非常有用。来自雅库布 ·洛普赞斯基的关于 InnoDB 锁的反馈也是不值的。我与 MySQL 支持团队合作,团队内部进行无数次讨论,以及我伟大的同事的工作,对于本书来说,都是一个很好的灵感和想法来源。此外,非常感谢埃德温·德苏扎的支持。 4 | 5 | 最后,但最不重要的,感谢我的妻子,安玛格丽特,她的耐心和支持,而我写这本书。 -------------------------------------------------------------------------------- /附图/484666_1_En_23_Chapter_TeX_IEq1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/484666_1_En_23_Chapter_TeX_IEq1.png -------------------------------------------------------------------------------- /附图/484666_1_En_23_Chapter_TeX_IEq2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/484666_1_En_23_Chapter_TeX_IEq2.png -------------------------------------------------------------------------------- /附图/Figure 1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 1-1.png -------------------------------------------------------------------------------- /附图/Figure 1-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 1-2.png -------------------------------------------------------------------------------- /附图/Figure 10-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-1.png -------------------------------------------------------------------------------- /附图/Figure 10-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-10.png -------------------------------------------------------------------------------- /附图/Figure 10-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-11.png -------------------------------------------------------------------------------- /附图/Figure 10-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-12.png -------------------------------------------------------------------------------- /附图/Figure 10-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-13.png -------------------------------------------------------------------------------- /附图/Figure 10-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-14.png -------------------------------------------------------------------------------- /附图/Figure 10-15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-15.png -------------------------------------------------------------------------------- /附图/Figure 10-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-16.png -------------------------------------------------------------------------------- /附图/Figure 10-17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-17.png -------------------------------------------------------------------------------- /附图/Figure 10-18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-18.png -------------------------------------------------------------------------------- /附图/Figure 10-19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-19.png -------------------------------------------------------------------------------- /附图/Figure 10-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-2.png -------------------------------------------------------------------------------- /附图/Figure 10-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-20.png -------------------------------------------------------------------------------- /附图/Figure 10-21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-21.png -------------------------------------------------------------------------------- /附图/Figure 10-22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-22.png -------------------------------------------------------------------------------- /附图/Figure 10-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-3.png -------------------------------------------------------------------------------- /附图/Figure 10-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-4.png -------------------------------------------------------------------------------- /附图/Figure 10-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-5.png -------------------------------------------------------------------------------- /附图/Figure 10-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-6.png -------------------------------------------------------------------------------- /附图/Figure 10-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-7.png -------------------------------------------------------------------------------- /附图/Figure 10-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-8.png -------------------------------------------------------------------------------- /附图/Figure 10-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 10-9.png -------------------------------------------------------------------------------- /附图/Figure 11-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-1.png -------------------------------------------------------------------------------- /附图/Figure 11-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-10.png -------------------------------------------------------------------------------- /附图/Figure 11-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-11.png -------------------------------------------------------------------------------- /附图/Figure 11-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-12.png -------------------------------------------------------------------------------- /附图/Figure 11-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-13.png -------------------------------------------------------------------------------- /附图/Figure 11-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-14.png -------------------------------------------------------------------------------- /附图/Figure 11-15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-15.png -------------------------------------------------------------------------------- /附图/Figure 11-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-16.png -------------------------------------------------------------------------------- /附图/Figure 11-17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-17.png -------------------------------------------------------------------------------- /附图/Figure 11-18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-18.png -------------------------------------------------------------------------------- /附图/Figure 11-19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-19.png -------------------------------------------------------------------------------- /附图/Figure 11-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-2.png -------------------------------------------------------------------------------- /附图/Figure 11-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-20.png -------------------------------------------------------------------------------- /附图/Figure 11-21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-21.png -------------------------------------------------------------------------------- /附图/Figure 11-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-3.png -------------------------------------------------------------------------------- /附图/Figure 11-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-4.png -------------------------------------------------------------------------------- /附图/Figure 11-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-5.png -------------------------------------------------------------------------------- /附图/Figure 11-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-6.png -------------------------------------------------------------------------------- /附图/Figure 11-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-7.png -------------------------------------------------------------------------------- /附图/Figure 11-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-8.png -------------------------------------------------------------------------------- /附图/Figure 11-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 11-9.png -------------------------------------------------------------------------------- /附图/Figure 12-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 12-1.png -------------------------------------------------------------------------------- /附图/Figure 12-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 12-2.png -------------------------------------------------------------------------------- /附图/Figure 12-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 12-3.png -------------------------------------------------------------------------------- /附图/Figure 14-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 14-1.png -------------------------------------------------------------------------------- /附图/Figure 16-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 16-1.png -------------------------------------------------------------------------------- /附图/Figure 16-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 16-2.png -------------------------------------------------------------------------------- /附图/Figure 16-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 16-3.png -------------------------------------------------------------------------------- /附图/Figure 16-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 16-4.png -------------------------------------------------------------------------------- /附图/Figure 16-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 16-5.png -------------------------------------------------------------------------------- /附图/Figure 17-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 17-1.png -------------------------------------------------------------------------------- /附图/Figure 17-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 17-2.png -------------------------------------------------------------------------------- /附图/Figure 17-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 17-3.png -------------------------------------------------------------------------------- /附图/Figure 17-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 17-4.png -------------------------------------------------------------------------------- /附图/Figure 18-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 18-1.png -------------------------------------------------------------------------------- /附图/Figure 18-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 18-2.png -------------------------------------------------------------------------------- /附图/Figure 19-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 19-1.png -------------------------------------------------------------------------------- /附图/Figure 19-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 19-10.png -------------------------------------------------------------------------------- /附图/Figure 19-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 19-11.png -------------------------------------------------------------------------------- /附图/Figure 19-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 19-2.png -------------------------------------------------------------------------------- /附图/Figure 19-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 19-3.png -------------------------------------------------------------------------------- /附图/Figure 19-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 19-4.png -------------------------------------------------------------------------------- /附图/Figure 19-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 19-5.png -------------------------------------------------------------------------------- /附图/Figure 19-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 19-6.png -------------------------------------------------------------------------------- /附图/Figure 19-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 19-7.png -------------------------------------------------------------------------------- /附图/Figure 19-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 19-8.png -------------------------------------------------------------------------------- /附图/Figure 19-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 19-9.png -------------------------------------------------------------------------------- /附图/Figure 2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 2-1.png -------------------------------------------------------------------------------- /附图/Figure 2-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 2-2.png -------------------------------------------------------------------------------- /附图/Figure 2-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 2-3.png -------------------------------------------------------------------------------- /附图/Figure 20-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 20-1.png -------------------------------------------------------------------------------- /附图/Figure 20-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 20-10.png -------------------------------------------------------------------------------- /附图/Figure 20-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 20-11.png -------------------------------------------------------------------------------- /附图/Figure 20-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 20-12.png -------------------------------------------------------------------------------- /附图/Figure 20-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 20-13.png -------------------------------------------------------------------------------- /附图/Figure 20-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 20-2.png -------------------------------------------------------------------------------- /附图/Figure 20-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 20-3.png -------------------------------------------------------------------------------- /附图/Figure 20-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 20-4.png -------------------------------------------------------------------------------- /附图/Figure 20-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 20-5.png -------------------------------------------------------------------------------- /附图/Figure 20-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 20-6.png -------------------------------------------------------------------------------- /附图/Figure 20-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 20-7.png -------------------------------------------------------------------------------- /附图/Figure 20-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 20-8.png -------------------------------------------------------------------------------- /附图/Figure 20-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 20-9.png -------------------------------------------------------------------------------- /附图/Figure 22-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 22-1.png -------------------------------------------------------------------------------- /附图/Figure 22-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 22-2.png -------------------------------------------------------------------------------- /附图/Figure 22-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 22-3.png -------------------------------------------------------------------------------- /附图/Figure 22-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 22-4.png -------------------------------------------------------------------------------- /附图/Figure 22-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 22-5.png -------------------------------------------------------------------------------- /附图/Figure 23-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 23-1.png -------------------------------------------------------------------------------- /附图/Figure 23-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 23-2.png -------------------------------------------------------------------------------- /附图/Figure 23-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 23-3.png -------------------------------------------------------------------------------- /附图/Figure 23-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 23-4.png -------------------------------------------------------------------------------- /附图/Figure 24-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 24-1.png -------------------------------------------------------------------------------- /附图/Figure 24-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 24-2.png -------------------------------------------------------------------------------- /附图/Figure 24-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 24-3.png -------------------------------------------------------------------------------- /附图/Figure 24-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 24-4.png -------------------------------------------------------------------------------- /附图/Figure 24-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 24-5.png -------------------------------------------------------------------------------- /附图/Figure 24-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 24-6.png -------------------------------------------------------------------------------- /附图/Figure 24-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 24-7.png -------------------------------------------------------------------------------- /附图/Figure 24-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 24-8.png -------------------------------------------------------------------------------- /附图/Figure 25-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 25-1.png -------------------------------------------------------------------------------- /附图/Figure 25-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 25-2.png -------------------------------------------------------------------------------- /附图/Figure 25-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 25-3.png -------------------------------------------------------------------------------- /附图/Figure 25-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 25-4.png -------------------------------------------------------------------------------- /附图/Figure 25-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 25-5.png -------------------------------------------------------------------------------- /附图/Figure 25-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 25-6.png -------------------------------------------------------------------------------- /附图/Figure 25-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 25-7.png -------------------------------------------------------------------------------- /附图/Figure 26-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 26-1.png -------------------------------------------------------------------------------- /附图/Figure 26-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 26-2.png -------------------------------------------------------------------------------- /附图/Figure 26-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 26-3.png -------------------------------------------------------------------------------- /附图/Figure 27-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 27-1.jpg -------------------------------------------------------------------------------- /附图/Figure 3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 3-1.png -------------------------------------------------------------------------------- /附图/Figure 3-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 3-2.png -------------------------------------------------------------------------------- /附图/Figure 4-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 4-1.png -------------------------------------------------------------------------------- /附图/Figure 4-10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 4-10.jpg -------------------------------------------------------------------------------- /附图/Figure 4-11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 4-11.jpg -------------------------------------------------------------------------------- /附图/Figure 4-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 4-2.jpg -------------------------------------------------------------------------------- /附图/Figure 4-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 4-3.png -------------------------------------------------------------------------------- /附图/Figure 4-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 4-4.jpg -------------------------------------------------------------------------------- /附图/Figure 4-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 4-5.png -------------------------------------------------------------------------------- /附图/Figure 4-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 4-6.png -------------------------------------------------------------------------------- /附图/Figure 4-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 4-7.png -------------------------------------------------------------------------------- /附图/Figure 4-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 4-8.png -------------------------------------------------------------------------------- /附图/Figure 4-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 4-9.png -------------------------------------------------------------------------------- /附图/Figure 5-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 5-1.png -------------------------------------------------------------------------------- /附图/Figure 5-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 5-2.png -------------------------------------------------------------------------------- /附图/Figure 5-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 5-3.png -------------------------------------------------------------------------------- /附图/Figure 7-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 7-1.jpg -------------------------------------------------------------------------------- /附图/Figure 9-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/Figure 9-1.png -------------------------------------------------------------------------------- /附图/author.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/author.png -------------------------------------------------------------------------------- /附图/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/cover.jpg -------------------------------------------------------------------------------- /附图/press.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/press.png -------------------------------------------------------------------------------- /附图/reviewer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxyle/MySQL-8-Query-Performance-Tuning/506b4721b012f6595eb95343825b0326aa67438e/附图/reviewer.png --------------------------------------------------------------------------------