8章优化

目录

8.1优化概述
8.2优化SQL语句
8.2.1优化SELECT语句
8.2.2优化子查询、导出表,查看参考,共同tableexpressions
8.2.3 information_schema查询优化
8.2.4优化性能模式查询
8.2.5优化数据变化报表
8.2.6优化数据库的权限
8.2.7其他优化技巧
8.3优化指标
8.3.1 MySQL如何使用索引
8.3.2主关键字优化
8.3.3空间索引优化
8.3.4外键优化
8.3.5列索引
8.3.6多列索引
8.3.7验证指标的使用
8.3.8 InnoDB和MyISAM索引的统计信息收集
8.3.9比较B树和哈希索引
使用索引扩展第
8.3.11优化器使用生成的列的索引
B hfp无形指标
8.3.13降序索引
8.4优化数据库结构
8.4.1优化数据大小
8.4.2优化MySQL数据类型
8.4.3优化多表
在MySQL中使用8.4.4内部临时表
8.5优化InnoDB表
8.5.1优化InnoDB表的存储布局
8.5.2优化InnoDB事务管理
8.5.3优化InnoDB只读事务
8.5.4优化InnoDB重做日志
8.5.5 InnoDB表加载大量数据
8.5.6 InnoDB查询优化
8.5.7 InnoDB DDL操作优化
8.5.8 InnoDB磁盘I/O优化
8.5.9优化InnoDB配置变量
8.5.10优化InnoDB有很多表系统
8.6优化MyISAM表
8.6.1 MyISAM查询优化
8.6.2数据批量加载对MyISAM表
8.6.3优化检修表报表
8.7优化内存表
8.8了解查询执行计划
8.8.1优化查询详细解释
8.8.2解释输出格式
8.8.3扩展解释输出格式
8.8.4获取执行计划信息为命名的连接
8.8.5估计查询性能
8.9控制查询优化器
8.9.1控制查询计划的评价
8.9.2优化器提示
3切换优化
8.9.4指标提示的
8.9.5优化器成本模型
8.9.6优化器统计
8.10缓冲和缓存
8.10.1 InnoDB缓冲池的优化
8.10.2的myisam Key Cache
8.10.3缓存的准备好的语句和存储的程序
8.11优化锁定操作
8.11.1内部锁定的方法
8.11.2表锁定问题
8.11.3并发插入
8.11.4元数据锁定
8.11.5外锁闭
8.12优化MySQL服务器
4优化磁盘I/O
8.12.2使用符号链接
8.12.3优化内存使用
8.12.4优化网络使用
8.12.5资源组
8.13性能测试(基准)
8.13.1企业测量表达式和函数的速度
8.13.2使用您自己的基准
8.13.3测量性能与performance_schema
8检查线程信息
8.14.1公司螺纹指令值
8.14.2通用线程状态
8.14.3复制主线程状态
8.14.4复制从I/O线程状态
8.14.5 SLAVE端状态
8.14.6复制从连接线程状态
8.14.7事件调度线程的状态

本章介绍了如何优化MySQL的性能和提供的例子。优化包括配置、调整和测量性能,在几个级别。这取决于你的工作角色(开发人员,DBA,或两者的结合),你可以在单个SQL语句的优化,整体应用水平,一个数据库服务器,或多个网络数据库服务器。有时你可以表现的积极推动和计划,有时你可能排除配置或代码出现问题后的问题。优化CPU和内存的使用还可以提高可扩展性,允许数据库没有放慢处理更多的负载。

8.1优化概述

数据库的性能取决于在数据库级别的几个因素,如表、查询和配置设置。这些软件构建了导致CPU和I/O操作在硬件层面,你必须尽量减少,尽可能高效。当你在数据库的性能,你开始学习高级规则和软件方面的指导方针,并测量使用挂钟时间性能。当你成为一个专家,你更了解内部发生了什么,并开始测量的东西,如CPU周期和I/O操作。

典型用户的目的是摆脱他们现有的软件和硬件配置最好的数据库性能。高级用户寻找机会提高MySQL软件本身,或开发自己的存储引擎和硬件设备扩展MySQL的生态系统。

优化在数据库级别

在数据库应用程序中快速的最重要的因素是它的基本设计:

  • 是表结构合理吗?特别是,做列有正确的数据类型,并为每个表的工作类型相应的列?例如,进行频繁的更新,经常有许多表几列的应用程序,而应用程序,分析大量数据往往有几张桌子和许多列。

  • 是正确的指标到位,使查询效率呢?

  • 你使用适当的存储引擎每个表,并利用优势和每个存储引擎使用的功能?特别是,一个事务性存储引擎,如选择InnoDB或非事务性等MyISAM可以对性能和可伸缩性很重要。

    笔记

    InnoDB是新表的默认存储引擎。在实践中,先进的InnoDB性能特点意味着InnoDB表通常比简单的MyISAMTable,especially for a Busy Database .

  • 每台使用适当的格式行吗?这一选择也取决于使用的表的存储引擎。特别是,压缩表使用较少的磁盘空间,因此需要更少的磁盘I/O读写数据。压缩是可用于所有种类的工作InnoDB表为只读MyISAM

  • 应用程序是否使用适当的锁定策略?例如,通过允许共享访问时,可能使数据库操作可以同时运行,并在适当的时候,请求独占访问关键业务得到优先处理。再次,存储引擎的选择是重要的。这个InnoDB存储引擎处理大多数锁定问题没有参与你,允许在数据库中更好的并发性和减少量的实验和代码的优化。

  • 都是用于缓存的内存区域尺寸正确吗?这是大到足以容纳频繁访问的数据,但也不能太大,他们超载物理内存,导致寻呼。主存储区配置是InnoDB缓冲池和MyISAM键缓存

在硬件级别的优化

任何数据库应用程序最终命中的硬件限制的数据库变得越来越忙。DBA必须评估是否可以调整应用程序或配置服务器来避免这些瓶颈,或是否有更多的硬件资源的要求。系统的瓶颈通常是从这些来源:

  • 磁盘寻道。它的磁盘找到一块数据的时间。随着现代磁盘,这意味着时间通常小于10ms,所以我们在理论上可以做大约100寻求二。这一次缓慢地改善,新的磁盘和很难单个表的优化。的方式来优化寻道时间是将数据分发到多个磁盘。

  • 磁盘读写。当磁盘处于正确的位置,我们需要读取或写入数据。随着现代磁盘,一个磁盘提供至少10–Mb/s的吞吐量。这比寻求更优化的因为你可以从多个磁盘并行读取。

  • CPU周期。当数据在内存中的,我们必须处理它得到我们的结果。相比于内存量有大的表是最常见的限制因素。但小桌子,速度通常是没问题的。

  • 内存带宽。当CPU需要更多的数据比可以在CPU缓存,内存带宽成为瓶颈。这是一种罕见的最系统的瓶颈,但是要知道。

平衡便携性和性能

在一个便携式的MySQL程序使用面向性能的SQL扩展,你可以把MySQL特定的关键词在一份声明中/*! */注释符。其他SQL服务器忽略评论关键词。关于写作的评论信息,看9.6节”中,语法”

8.2优化SQL语句

一个数据库应用程序的核心逻辑是通过SQL语句进行发布,是否直接通过翻译或提交幕后通过API。在这段调整的指导方针有助于加快各类MySQL的应用。该指南包括SQL操作,读写数据,后面的开销的场景在一般的SQL操作,并在特定的场景中使用如数据库监控操作。

8.2.1优化SELECT语句

查询的形式SELECT语句在数据库中执行所有的查找操作。调整这些报表是重中之重,能否实现亚秒级的响应时间为动态网页,或把小时休息时间产生巨大的隔夜报告。

除了SELECT报表,查询的优化技术也适用于构造如CREATE TABLE...AS SELECTINSERT INTO...SELECT,和哪里条款DELETE声明.这些陈述有额外的性能考虑,因为他们结合读写操作的查询操作。

主要考虑优化查询:

  • 做一个慢SELECT ... WHERE查询速度快,首先检查是否可以添加一个指数。用于建立索引的列WHERE条款,加快评估,过滤,和最终的检索结果。为了避免浪费磁盘空间,构造一个小的指标,加快了许多相关的问题在应用程序中使用的。

    指标是参考不同表的查询,尤其重要的是,使用等特点加入外键。你可以使用EXPLAIN语句来确定哪些指标是用于SELECT。看到第8.3.1,“MySQL如何使用索引”8.8.1节,“优化查询的解释”

  • 分离和调整查询的任何部分,如一个函数调用,把过多的时间。这取决于如何查询是结构化的,一个函数可以被调用一次,在结果集的每一行,甚至一度在表的每一行,大大放大任何无效。

  • 尽量多的全表扫描在你的查询,特别是对于大表。

  • 保持统计表目前采用ANALYZE TABLE声明周期,那么优化器需要构建一个高效的执行计划的信息。

  • 学习整定技术,索引技术,并为每个表的特定存储引擎配置参数。两InnoDBMyISAM有能够在保持高性能的查询指南集。详情见8.5.6节,“优化InnoDB查询”第8.6.1,“优化MyISAM查询”

  • 你可以优化单查询交易InnoDB表格、使用技术第8.5.3,“优化InnoDB只读事务”

  • 避免转化的方式,让人很难理解的查询,特别是如果优化做了一些相同的自动转换。

  • 如果性能问题不是一个容易解决的基本准则,探讨特定查询的内部细节阅读EXPLAIN计划和调整指标,哪里条款,加入条款,等等。(当你达到一定的专业水平,阅读EXPLAIN可能你的每一个查询计划的第一步。)

  • 调整内存区域,MySQL使用缓存的大小和性质。与使用效率InnoDB缓冲池MyISAM键缓存,和MySQL的查询缓存,重复查询运行得更快,因为结果是从内存中检索第二和随后的时代。

  • 即使对于一个查询,跑得快,使用内存缓存区,你仍可能进一步优化,它们需要较少的内存缓存,使你的应用程序可扩展性。可扩展性意味着你的应用程序可以处理更多的并发用户,更大的要求,而不用经历业绩大降。

  • 锁定问题处理,在您的查询的速度可能会受到其他会话访问表同时影响。

8.2.1.1 WHERE子句的优化

本节讨论的优化,可以处理WHERE条款。考试使用SELECT报表,但相同的优化应用哪里条款DELETEUPDATE声明.

笔记

因为在MySQL优化器的工作正在进行中,并不是所有的优化,MySQL的执行都记录在这里。

你也许会改写你的查询,使运算速度更快,而牺牲可读性。因为MySQL是类似的自动优化,你通常可以避开这项工作,并把查询更容易理解和维护的形式。一些优化由MySQL遵循:

  • 去除不必要的括号:

       ((a AND b) AND c OR (((a AND b) AND (c AND d))))
    -> (a AND b AND c) OR (a AND b AND c AND d)
    
  • 恒一

       (a<b AND b=c) AND a=5
    -> b>5 AND b=c AND a=5
    
  • 不变的情况下(需去除因不断的折叠):

       (B>=5 AND B=5) OR (B=6 AND 5=5) OR (B=7 AND 5=6)
    -> B=5 OR B=6
    
  • 用指标常量表达式的评价只有一次。

  • COUNT(*)没有一个单一的表哪里直接从表中检索信息MyISAM内存表这也是做任何NOT NULL表达只有一个可以

  • 无效的常量表达式的早期检测。MySQL快速检测到一些SELECT报表是不可能的,没有返回的行。

  • HAVING合并哪里如果你不使用GROUP BY或聚合函数(COUNT()MIN(),等等)

  • 每个表中的一个连接,一个简单的WHERE构建得到快速哪里为表评价并跳过行尽快。

  • 所有的常量表在查询其他表中读取第一。一个常数表下列:

    • 一个空的表或一排桌子。

    • 一个表,用WHERE条款上主键UNIQUE指数,在所有指数部分是比较恒定的表情和被定义为不为空

    以下所有表格作为常数表:

    SELECT * FROM t WHERE primary_key=1;
    SELECT * FROM t1,t2
      WHERE t1.primary_key=1 AND t2.primary_key=t1.id;
    
  • 最好加入组合连接表是通过尝试所有可能性的发现。如果所有的列ORDER BY条款都来自同一个表,表是首选加入时。

  • 如果有一个ORDER BY子句和一个不同的条款,或者ORDER BY包含来自其他在加入队列比第一桌柱,临时表的创建。

  • 如果你使用SQL_SMALL_RESULT改性剂,MySQL使用内存中的临时表。

  • 每个表的索引进行查询,和最好的指标是除非优化器认为,更有效的是使用表扫描。同时,扫描是基于是否最好指标跨越表超过30 %,但有固定的百分比不再决定选择使用索引或扫描之间。优化器现在更为复杂和基地估计额外的因素如表大小、行数和I/O块大小。

  • 在一些情况下,MySQL可以读取索引行没有咨询的数据文件。如果从索引使用的所有列是数字,只有索引树被用于解决查询。

  • 在每一行输出,那些不匹配HAVING条款被跳过

一些非常快速查询的例子:

SELECT COUNT(*) FROM tbl_name;

SELECT MIN(key_part1),MAX(key_part1) FROM tbl_name;

SELECT MAX(key_part2) FROM tbl_name
  WHERE key_part1=constant;

SELECT ... FROM tbl_name
  ORDER BY key_part1,key_part2,... LIMIT 10;

SELECT ... FROM tbl_name
  ORDER BY key_part1 DESC, key_part2 DESC, ... LIMIT 10;

MySQL解决以下仅使用索引树的查询,假定索引列的数字:

SELECT key_part1,key_part2 FROM tbl_name WHERE key_part1=val;

SELECT COUNT(*) FROM tbl_name
  WHERE key_part1=val1 AND key_part2=val2;

SELECT key_part2 FROM tbl_name GROUP BY key_part1;

下面的查询使用索引来检索顺序排没有一个单独的分拣:

SELECT ... FROM tbl_name
  ORDER BY key_part1,key_part2,... ;

SELECT ... FROM tbl_name
  ORDER BY key_part1 DESC, key_part2 DESC, ... ;

8.2.1.2范围优化

这个range访问方法使用一个单一的指标来检索,都包含在一个或几个指标值区间表的行的子集。它可以用一个单一的部分或多部分指标。以下各节描述的条件下,优化器使用范围的访问。

单部分指标范围的访问方法

一部分指标,指标值区间可以方便地表示在相应的条件WHERE从句,表示为范围条件而不是间隔.

一部分指标的一系列条件的定义如下:

  • BTREE搞砸指标,一个关键部分是一个恒定值范围比较时使用=<=>IN()IS NULL,或IS NOT NULL运营商

  • 此外,为BTREE指标,一个关键部分是一个恒定值范围比较时使用><>=<=BETWEEN!=,或<>运营商,或LIKE如果参数比较LIKE是一个常量字符串不以通配符。

  • 所有索引类型、多范围的条件结合ORANDform a range条件。

常数值在前面的描述下列之一:

  • 从查询字符串常数

  • 一柱一constsystem从相同的连接表

  • 一个关联子查询的结果

  • 任何表达完全由来自上述类型的子表达式

这里有一些在各种条件查询的例子WHERE条款:

SELECT * FROM T1的地方key_col&#62; 1key_col< 10;SELECT * FROM t1  WHEREkey_col= 1  ORkey_col在(15,18,20);选择*从T1的地方key_col像“AB %”或key_col“酒吧”和“foo”;

一些非恒定的值可以转换为常数的优化器常数传播阶段。

MySQL试图从提取范围条件WHERE为每一个可能的指标条款。在提取过程中,不可用于构建范围条件的下降,产生重叠的范围条件相结合,并产生空范围条件去掉。

考虑下面的语句,其中key1一个索引列,非键是不是索引:

SELECT * FROM t1 WHERE
  (key1 < 'abc' AND (key1 LIKE 'abcde%' OR key1 LIKE '%b')) OR
  (key1 < 'bar' AND nonkey = 4) OR
  (key1 < 'uux' AND key1 > 'z');

关键的提取工艺key1如下:

  1. 从原来的WHERE条款:

    (key1 < 'abc' AND (key1 LIKE 'abcde%' OR key1 LIKE '%b')) OR(key1 < 'bar' AND nonkey = 4) OR(key1 < 'uux' AND key1 > 'z')
  2. 去除nonkey = 4key1是“B”因为他们不能用于范围扫描。除去它们的正确方法是用TRUE,所以我们不会错过任何匹配行做范围扫描。取代他们的真的yields:

    (key1 < 'abc' AND (key1 LIKE 'abcde%' OR TRUE)) OR
    (key1 < 'bar' AND TRUE) OR
    (key1 < 'uux' AND key1 > 'z')
    
  3. 崩溃的条件总是真或假:

    • (key1 LIKE 'abcde%' OR TRUE)永远是真实的

    • (key1 < 'uux' AND key1 > 'z')永远是假的

    与常数产生更换这些条件:

    (key1 < 'abc' AND TRUE) OR (key1 < 'bar' AND TRUE) OR (FALSE)
    

    去除不必要的TRUE错误的yields常数:

    (key1 < 'abc') OR (key1 < 'bar')
    
  4. 结合成一个重叠的区间收益的最终条件是用于扫描范围:

    (key1 < 'bar')
    

一般(和前面的例子证明),用于一系列条件限制较少比扫描WHERE条款.MySQL进行过滤,满足范围条件但不是全行的一个额外的检查哪里条款.

范围条件提取算法可以处理嵌套AND/OR任意深度的结构,其输出不依赖于条件出现的顺序哪里条款.

MySQL不支持合并多个范围的range空间索引存取方法。为了解决这个问题,你可以使用一个UNION具有相同SELECT陈述,除非你把每一个不同的空间谓词SELECT

多部分指标范围的访问方法

在一个多部分指标范围条件一部分指标范围延伸条件。在一个多部分指标一系列制约指数排躺在一个或几个关键元组区间。关键元区间是定义在一组关键的元组,使用从指数排序。

例如,考虑一个定义为多个部分指标key1(key_part1, key_part2, key_part3),和下面的一组元组顺序列出关键的关键:

key_part1key_part2key_part3ABC是空1空1 XYZ Foo是空2 1 1 1 1 XYZ的ABC ABC 1 2 2 1是AAA

条件key_part1 = 1定义了这个区间:

(1,-inf,-inf) <= (key_part1key_part2key_part3) < (1,+inf,+inf)

区间包括第四,第五,和第六元组在前面的数据集,可以通过访问方法使用范围。

相比之下,条件key_part3 = 'abc'没有定义一个区间,不能访问方法使用范围。

以下说明如何范围的条件下工作的多个部分指标更详细。

  • HASH指标,每个区间包含相同的值可以用。这意味着,间隔可以产生只有在以下条件形式:

    key_part1cmpconst1key_part2cmpconst2和…和key_partNcmpconstN

    在这里,const1const2是常数,……cmp是其中的一个=<=>,或IS NULL比较运算符,和条件覆盖所有指标部分。(即有N的条件下,为每一部分N部分指标。)例如,以下是13部分的一系列条件搞砸索引:

    key_part1 = 1 AND key_part2 IS NULL AND key_part3 = 'foo'
    

    对于定义什么是一个常数,看单部分指标范围的访问方法

  • 对于一个BTREE指数区间可能用于条件结合AND,其中每个条件比较关键的一部分与一个恒定值,使用=<=>IS NULL><>=<=!=<>BETWEEN,或LIKE 'pattern'(在哪里&#39;pattern&#39;不从一个通配符)。区间可只要有可能确定一个关键元组包含匹配条件的所有行(或两区间如果<>!=使用)

    优化器尝试使用额外的关键部位来确定区间只要比较运算符=<=>,或IS NULL。If the Operation is><>=<=!=<>BETWEEN,或LIKE优化器使用它,但认为没有更多的关键部件。下列表达式,优化器使用=从最初的比较。它还使用>=从第二比较但认为没有进一步的关键部件和不使用第三比较区间施工:

    key_part1= 'foo' ANDkey_part2>= 10 ANDkey_part3&#62; 10

    单间隔:

    ('foo',10,-inf) < (key_part1,key_part2,key_part3) < ('foo',+inf,+inf)
    

    这是可能的,创造的区间包含的行比初始条件。例如,前间隔包括价值('foo', 11, 0),不满足初始条件

  • 如果条件覆盖包含在区间套行相结合OR,它们形成了一个覆盖条件,包含他们的间隔结合在一组行。如果条件结合AND,它们形成了一个条件,包括包含在其区间相交集。例如,这种情况在两指数:

    key_part1= 1 ANDkey_part2< 2) OR (key_part1&#62; 5)

    间隔:

    (1,-inf) < (key_part1,key_part2) < (1,2)
    (5,-inf) < (key_part1,key_part2)
    

    在这个例子中,在第一行间隔使用的一个关键组成部分为左界和权利约束的两个关键部分。二号线区间仅使用一个密钥的一部分。这个key_len列在EXPLAIN输出指示用的关键前缀的最大长度。

    在某些情况下,key_len可能表明,使用是一个重要的部分,但这可能不是你所期望的。假设key_part1key_part2可以是无效的。然后key_len列显示下列条件下的两个关键部分的长度:

    key_part1>= 1 ANDkey_part2< 2

    但是,事实上,条件转换为本:

    key_part1 >= 1 AND key_part2 IS NOT NULL
    

为了说明如何进行优化,结合或消除区间范围的条件下在一个单一的部分指标,看单部分指标范围的访问方法。类似的步骤是在多个部分指标范围的条件下进行。

多值比较平等范围优化

考虑到这些表达式,其中col_name一个索引列:

col_name在(val1,…,valNcol_name=val1或或col_name=valN

每个表达式为真,如果col_name等于任何数的值。这些比较是平等的范围比较(其中范围是一个单值)。优化器估计阅读资格平等范围比较行如下费用:

  • 如果有一个唯一索引col_name,每个范围的行估计是1因为在一排可以给定值。

  • 否则,他任何指数col_name是唯一的,优化器可以估计的行数为每个范围使用潜入指数或指数统计。

随着指数跳水,优化器会在一个范围内的每一端潜水和使用范围中的行数的估计。例如,表达col_name IN (10, 20, 30)有三个平等的范围和优化使得每个范围两跳水产生行估计。每一对动作产生一个估计的行数,给定值。

指数跳水提供准确的行的估计,但在表达增加的比较值,优化器需要更长的时间来生成一个行估计。利用指数统计比指数跳水但允许更快的排大值列表不准确的估计。

这个eq_range_index_dive_limit系统变量允许您配置的值的数目,优化切换到另一行估计策略。允许比较了指数跳水的使用N平等的范围,设置eq_range_index_dive_limitN1.。禁止利用统计数据和总是使用指数跳水不管N,集eq_range_index_dive_limit这是0

更新的最佳估计表索引统计,使用ANALYZE TABLE

MySQL 5.0之前,没有办法跳过索引使用潜水评价指标的实用性,除了利用eq_range_index_dive_limit系统变量。在MySQL 8中,指数跳水不可能满足所有这些条件的查询:

  • 查询是一个表,而不是在多个表的联接。

  • 一个单一的指标FORCE INDEX指标提示存在。这个想法是,如果指数使用的是被迫的,没有什么可从执行潜入指数的额外开销获得。

  • 索引是唯一的,不FULLTEXT指数

  • 没有子查询是目前

  • DISTINCT,或ORDER BY条款是存在的

EXPLAIN FOR CONNECTION,输出的变化如下如果指数跳水跳过:

  • 传统的输出,rows过滤NULL

  • JSON输出,rows_examined_per_scanrows_produced_per_join不出现,skip_index_dive_due_to_force真正的,和成本计算不准确

没有FOR CONNECTIONEXPLAIN输出不随指数跳水跳过。

一个查询的指数跳水动作跳过执行后,在相应的行INFORMATION_SCHEMA.OPTIMIZER_TRACE表包含一个index_dives_for_range_access价值skipped_due_to_force_index

跳跃扫描范围的访问方法

考虑下面的情况:

CREATE TABLE t1 (f1 INT NOT NULL, f2 INT NOT NULL, PRIMARY KEY(f1, f2));
INSERT INTO t1 VALUES
  (1,1), (1,2), (1,3), (1,4), (1,5),
  (2,1), (2,2), (2,3), (2,4), (2,5);
INSERT INTO t1 SELECT f1, f2 + 5 FROM t1;
INSERT INTO t1 SELECT f1, f2 + 10 FROM t1;
INSERT INTO t1 SELECT f1, f2 + 20 FROM t1;
INSERT INTO t1 SELECT f1, f2 + 40 FROM t1;
ANALYZE TABLE t1;

EXPLAIN SELECT f1, f2 FROM t1 WHERE f2 > 40;

执行此查询,MySQL可以选择索引扫描获取的所有行(该指数包含所有列被选中),然后应用f2 > 40条件的哪里条款产生最终的结果集。

一系列的扫描比索引扫描更有效,但不能使用,在这种情况下,因为没有条件f1第一个索引列。然而,在MySQL 8.0.13,优化器可以使用松散索引扫描(见第8.2.1.15,“优化”组)要做的工作的一部分:

  1. 执行一个松散的扫描的第一指标部分不同的值,f1(前缀的指标)

  2. 执行子对每个不同的前缀值扫描f2 > 40在剩余的部分指标的情况。

对于数据集证明,这样的算法:

  1. 获得第一个关键部分的第一个不同值(f1 = 1

  2. 基于第一和第二关键部件构造范围(f1 = 1 AND f2 > 40

  3. 执行范围扫描

  4. 获得第一个关键部分的第一个不同值(f1 = 2

  5. 基于第一和第二关键部件构造范围(f1 = 2 AND f2 > 40

  6. 执行范围扫描

采用这种策略减少了访问的行数因为MySQL跳过不符合每个构造范围的行。这种访问方式称为跳跃扫描,适用于以下情况:

  • 桌上有至少一个与形式的关键部件的复合指数([ a_1,…,a_kb_1,b_,],…m(1 _,C,D,…,D _n])。关键部件A和D可能是空的,但B和C不能是空的。

  • “query references只有一个表。

  • 查询不使用GROUP BY不同的

  • 在索引的查询仅列

  • 在a_1谓词,…,a_k必须是平等的,他们必须是常数的谓词。这包括IN()算子

  • 查询必须是一个合取查询;AND属于条件(cond1(key_part1) OR cond2(key_part1)) AND (cond1(key_part2) OR ...) AND ...

  • 必须有在C.一系列条件

  • 在条件允许的情况下D柱。条件对D必须在C.范围内条件连词

使用跳跃扫描显示EXPLAIN输出如下:

  • Using index for skip scan额外柱表明松散索引跳跃扫描访问方法。

  • 如果指数可用于跳过扫描,指数应该在可见的possible_keys专栏

使用跳跃扫描显示跟踪输出的优化"skip scan"这种形式的元素:

“跳过扫描“{”:“跳跃式”_扫描”,“指标”:index_used_for_skip_scan,“key_parts_used_for_access”:[key_parts_used_for_access],”前缀范围”:[prefix_ranges“范围”:[ ],range] }

使用跳跃扫描是本课题的价值skip_scan旗的optimizer_switch系统变量。见第3,“开关的优化”。默认情况下,此标志on。要禁用它,集skip_scanoff

除了使用optimizer_switch系统变量控制优化器使用跳跃扫描会话范围的,MySQL支持优化器提示优化器对每个语句基础的影响。看到第8.9.2,“优化器提示”

行构造函数的表达范围优化

优化器能够适用范围扫描访问方法,这种形式的查询:

SELECT ... FROM t1 WHERE ( col_1, col_2 ) IN (( 'a', 'b' ), ( 'c', 'd' ));

此前,为范围扫描被使用,有必要写的查询:

SELECT ... FROM t1 WHERE ( col_1 = 'a' AND col_2 = 'b' )
OR ( col_1 = 'c' AND col_2 = 'd' );

对于优化器使用范围扫描,查询必须满足这些条件:

  • 只有IN()使用谓词,不NOT IN()

  • 在左边IN()谓词,行构造函数只包含列引用。

  • 在右侧的IN()谓词,行构造函数只包含运行时常量,这是文字或局部,势必在执行列引用常量。

  • 在右侧的IN()谓,有一行以上的构造函数。

为更多的信息关于优化器和行构造函数,看第8.2.1.20,“行构造函数表达式优化”

限制范围优化内存使用

控制可用的范围优化内存使用range_optimizer_max_mem_size系统变量:

  • 值为0表示没有限制

  • 一个大于0的值,优化器跟踪消耗考虑范围的内存访问方法。如果指定的限制即将突破,范围的访问方法是放弃和其他方法,包括一个全表扫描,是不是。这可能是最佳的。如果发生这种情况,以下警告出现(在N是当前range_optimizer_max_mem_size值):

    警告3170内存容量N“range_optimizer_max_mem_size字节的突破。范围不该查询做了优化。

单个查询超过了可用范围优化内存,优化落回不到最佳方案,提高range_optimizer_max_mem_size值可能会提高性能

估计需要处理一系列表达的内存量,使用这些指南:

  • 一个简单的查询,如下面的,那里是一个候选键范围的访问方法,每个谓词结合OR大约使用230个字节:

    SELECT COUNT(*) FROM tWHERE a=1 OR a=2 OR a=3 OR .. . a=N
  • 同样一个查询等,每个谓词结合AND使用大约125字节:

    SELECT COUNT(*) FROM tWHERE a=1 AND b=1 AND c=1 ...N
  • 对于一个查询IN()谓词:

    select count(*)从那里有一个在(1,2,…,M和B)和(1,2,…,N);

    在每一个文本值IN()列表作为一个谓词结合OR。如果有两IN()列表谓词结合数OR为列表中的每个值数量的产品。因此,谓词结合数OR在前面的案例M×N

8.2.1.3索引合并优化

这个索引进行合并访问方法检索行多range扫描和合并成一个。这种访问方法将索引扫描只从一个单一的表扫描,不能跨多个表。合并产生的工会,工会的路口,或其基本扫描的十字路口。

示例查询的索引合并可以使用:

SELECT * FROM tbl_name WHERE key1 = 10 OR key2 = 20;

SELECT * FROM tbl_name
  WHERE (key1 = 10 OR key2 = 20) AND non_key = 30;

SELECT * FROM t1, t2
  WHERE (t1.key1 IN (1,2) OR t1.key2 LIKE 'value%')
  AND t2.key1 = t1.some_col;

SELECT * FROM t1, t2
  WHERE t1.key1 = 1
  AND (t2.key1 = t1.some_col OR t2.key2 = t1.some_col2);
笔记

索引合并优化算法有以下限制:

  • 如果你的查询有一个复杂的WHERE条款与深AND/OR嵌套和MySQL不选择最优方案,尝试使用以下身份转换项分布:

    xy)或z=> (xz)和(yz)(xy)和z=> (xz)或(yz
  • 索引合并不适用于全文索引。

进入EXPLAIN输出指标的合并方法的出现index_merge类型专栏在这种情况下,的key列包含一系列指标,并该_懒惰contains a list of the最长密钥份额for those指标。

索引合并访问方法有几种算法,这是显示在ExtraEXPLAIN输出:

  • Using intersect(...)

  • Using union(...)

  • Using sort_union(...)

下面的部分更详细地描述这些算法。优化器选择不同指标之间可能的合并基于可用的各种选项的成本估计算法和其他接入方式。

索引合并交叉存取算法

当这个存取算法是适用的WHERE条款转化为几个范围条件对不同的键结合AND,和每一个条件是下列之一:

  • 一个N-这种形式的表达,在指数已经完全N部分(即所有索引部分覆盖):

    key_part1=const1key_part2=const2…和key_partN=constN
  • 在一个主键的任何范围的条件InnoDB

实例:

SELECT * FROM innodb_table
  WHERE primary_key < 10 AND key_col1 = 20;

SELECT * FROM tbl_name
  WHERE key1_part1 = 1 AND key1_part2 = 2 AND key2 = 2;

索引合并交叉算法同时进行扫描所有使用的指标和生产排序列的交叉口,它接收从合并索引扫描。

如果查询中使用的列所用指标,全表行不检索(EXPLAIN输出包含使用索引进入Extra在这种情况下场)。这里是一个查询的一个例子:

SELECT COUNT(*) FROM t1 WHERE key1 = 1 AND key2 = 1;

如果用指标不包括查询中使用的列,全行仅检索时所有用密钥范围条件。

如果一个合并的条件是在一个关键的条件InnoDB表,它不用于行检索,而是用来过滤掉行检索使用的其他条件。

索引合并联盟接入算法

该算法的标准是类似于那些用于索引合并交叉算法。该算法适用于表WHERE条款转化为几个范围条件对不同的键结合OR,和每一个条件是下列之一:

  • 一个N-这种形式的表达,在指数已经完全N部分(即所有索引部分覆盖):

    key_part1=const1key_part2=const2…和key_partN=constN
  • 在一个主键的任何范围的条件InnoDB

  • 此时的索引合并交叉算法的适用性。

实例:

SELECT * FROM t1
  WHERE key1 = 1 OR key2 = 2 OR key3 = 3;

SELECT * FROM innodb_table
  WHERE (key1 = 1 AND key2 = 2)
     OR (key3 = 'foo' AND key4 = 'bar') AND key5 = 5;
指标归并排序联盟接入算法

这种访问算法适用于WHERE条款转化为几个范围条件结合OR,但索引合并的合并算法不适用。

实例:

SELECT * FROM tbl_name
  WHERE key_col1 < 10 OR key_col2 < 20;

SELECT * FROM tbl_name
  WHERE (key_col1 > 10 OR key_col2 = 20) AND nonkey_col = 30;

这种结合算法和合并算法之间的区别是,排序合并算法必须先获取所有行行ID和排序,然后返回任何行。

影响索引合并优化

使用索引合并主体的价值index_merge_合并_交叉索引index_merge_union,和index_merge_sort_union旗帜的optimizer_switch系统变量。见第3,“开关的优化”。默认情况下,所有的旗帜on。使某些算法,集索引off,使只有这样的人应该被允许。

除了使用optimizer_switch系统变量控制优化器使用索引合并算法的会话范围的,MySQL支持优化器提示优化器对每个语句基础的影响。看到第8.9.2,“优化器提示”

8.2.1.4引擎优化条件下推

这种优化提高非索引列和一个常数之间的直接比较效率。在这种情况下,条件是推下在存储引擎的评价。这只能通过使用优化NDB存储引擎

笔记

这个NDB存储引擎是目前不可用在MySQL 8。如果你在使用MySQL集群感兴趣,看7.5、MySQL NDB Cluster NDB簇7.6,这提供了有关MySQLCluster NDB 7.5(基于MySQL 5.7但含有最新的改进和修正的NDBCLUSTER存储引擎)

MySQL集群,这种优化可以消除需要发送的数据不匹配的行在集群节点发出查询MySQL服务器之间的网络,可以加快查询速度,它是由五因子用于十倍的情况下,条件下推可以但不使用。

假设一个MySQL簇表的定义如下:

CREATE TABLE t1 (
    a INT,
    b INT,
    KEY(a)
) ENGINE=NDB;

条件下推可用于查询,如上图所示,其中包括非索引列和一个常数之间的比较:

SELECT a, b FROM t1 WHERE b = 10;

条件下推的使用可以在输出中看到EXPLAIN

MySQL的&#62;EXPLAIN SELECT a,b FROM t1 WHERE b = 10\G*************************** 1。行***************************编号:1 select_type:简单表:T1型:allpossible_keys:空键:空key_len:零号:空10行:额外的:使用与推条件

但是,在条件许可的不能被用在这两个查询:

SELECT a,b FROM t1 WHERE a = 10;
SELECT a,b FROM t1 WHERE b + 1 = 10;

条件下不适用于第一个查询因为索引列a。(索引存取方法会更有效,所以会优先条件下推。选择)条件下推不能用于第二查询由于涉及非索引列的比较B是间接的。(然而,条件下推可以如果你减少应用b + 1 = 10b = 9WHERE条款。)

条件下推也可以当一个索引列与恒定的使用><运营商:

mysql> EXPLAIN SELECT a, b FROM t1 WHERE a < 2\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
         type: range
possible_keys: a
          key: a
      key_len: 5
          ref: NULL
         rows: 2
        Extra: Using where with pushed condition

其他支持的比较条件下推包括以下:

  • column [NOT] LIKE pattern

    pattern必须包含匹配模式的字符串;语法,看第12.5.1”字符串比较函数

  • column IS [NOT] NULL

  • column IN (value_list)

    在每一个项目value_list必须是一个常量,常量值。

  • column BETWEEN constant1 AND constant2

    constant1constant2每个文字必须是常数,值。

在所有的情况下,上述列表中,可以转换成一个或多个列和一个常数之间的直接比较是可能的形成条件。

发动机状态下默认是启用。禁用它在服务器启动时,设置optimizer_switch可变系统。For example,in amy.cnf文件,使用这些线:

[mysqld]
optimizer_switch=engine_condition_pushdown=off

在运行时,禁止条件下推这样:

SET optimizer_switch='engine_condition_pushdown=off';

局限性发动机状态下推是受以下限制:

  • 只有支持条件下推NDB存储引擎

  • 列可以与常数而已;然而,这包括表达式评估为恒定值。

  • 在比较中使用的列不能有任何的BLOBTEXT类型

  • 是一列比较字符串值,必须使用相同的排序的列。

  • 加入不直接支持;涉及多个表的条件下尽可能被分开。使用扩展EXPLAIN输出确定哪些条件实际上是推下。看到第8.8.3,“扩展解释输出格式”

8.2.1.5指数条件下推优化

指数条件下推(ICP)是一种优化的情况下,MySQL检索行从表使用索引。没有ICP,存储引擎遍历索引查找列在基表中返回到MySQL服务器的评估WHERE行条件。用ICP启用,如果部分的哪里条件可以通过指数仅列评估,MySQL服务器将这部分的WHERE条件下的存储引擎。存储引擎进行推指数条件下利用索引项,如果这是满意的是从表中读取的行。ICP可以减少次存储引擎的数量必须访问基表和时代的MySQL服务器必须访问存储引擎数。

该指数的条件下推优化的适用性是受这些条件:

  • ICP是用于rangerefeq_ref,和ref_or_null访问方法时需要访问表中的行。

  • ICP可用于InnoDBMyISAM表,包括partitionedInnoDBMyISAM

  • InnoDB表格、ICP仅用于辅助索引。ICP的目标是降低全行读取数,从而减少I/O操作。为InnoDB聚簇索引,完整的记录已经读到InnoDB缓冲区。采用ICP在这种情况下,不降低我/ O.

  • ICP是不是次要指标虚拟生成的列创建的支持。InnoDB支持二级指标虚拟生成的列。

  • 条件,指的是子查询不能推下。

  • 条件是指存储函数不能被推下。存储引擎无法调用存储函数。

  • 触发条件不能推下。(关于触发条件,信息见第8.2.2.4,优化子查询与存在战略”。)

要了解如何优化,首先考虑的是如何索引扫描时的所得指标条件下推是没有用的:

  1. 到下一行,通过读取索引数组,然后利用索引数组查找和阅读完整的表行。

  2. 测试的部分WHERE本表适用的条件。接受或拒绝基于试验结果的行。

使用索引扫描所得的条件下推,这样反而:

  1. 到下一行的索引数组(而不是全表行)。

  2. 测试的部分WHERE条件适用于这台可以只使用索引列的检查。如果条件不满足,继续为下一行的索引数组。

  3. 如果满足条件,使用索引数组查找和阅读完整的表行。

  4. 试验的剩余部分WHERE本表适用的条件。接受或拒绝基于试验结果的行。

EXPLAIN输出显示索引的使用条件Extra当指数条件下推用柱。它不显示使用索引因为这并不适用于当全表的行必须读。

假设一个表包含关于人和他们的地址信息,表定义的索引INDEX (zipcode, lastname, firstname)。如果我们知道一个人的邮政编码价值但不确定的名字,我们可以搜索这样的:

SELECT * FROM people
  WHERE zipcode='95054'
  AND lastname LIKE '%etrunia%'
  AND address LIKE '%Main Street%';

MySQL可以使用索引扫描的人zipcode='95054'. 第二部分(姓是“etrunia %)不能用于限行必须扫描的数量,所以没有索引的条件下推,这个查询要检索所有人有充分的表行zipcode='95054'

指数条件下推,MySQL检查lastname LIKE '%etrunia%'在阅读完整的表行。这避免了阅读整行对应元组匹配指数邮政编码条件但不是lastname条件

指数条件下推是默认启用。它可以控制的optimizer_switch系统变量的设置_ _ pushdown条件指数国旗:

SET optimizer_switch = 'index_condition_pushdown=off';
SET optimizer_switch = 'index_condition_pushdown=on';

看到第3,“开关的优化”

8.2.1.6嵌套循环连接算法

MySQL执行连接上使用嵌套循环算法或变化表之间。

嵌套循环连接算法

一个简单的嵌套循环连接(NLJ)算法读取行从第一个表中的一个循环一次,路过的每一行,一个嵌套循环,在加入过程下表。这个过程是反复多次仍表被加入。

假设3个表联接t1T2,和t3可以使用下面的连接类型执行:

表连接typet1 ranget2 reft3所有

如果使用一个简单的NLJ算法,加入是这样进行:

for each row in t1 matching range {
  for each row in t2 matching reference key {
    for each row in t3 {
      if row satisfies join conditions, send to client
    }
  }
}

因为行在NLJ算法通过外循环时间内循环,它通常是在内部循环多次处理表。

块嵌套循环连接算法

一块嵌套循环(BNL)加入算法使用读取的行在外环以减少倍,内环表必须读一些缓冲。例如,如果10行读入缓冲区和缓冲区传递给下一个内环,内环的读每一行可以对缓冲区中的所有10行比较。这降低了级的时代内表号订单必须读。

MySQL加入缓冲具有这些特点:

  • 加入缓冲时可以使用的连接类型ALLindex(换句话说,当不可能的密钥可以使用,和全扫描完成,无论是数据或索引行,分别),或range。使用缓冲也适用于外部联接,所述第8.2.1.11,“块嵌套循环和批量密钥访问连接”

  • 加入缓冲不分配给第一数台,即使它会类型ALLindex

  • 只有列感兴趣的一个连接存储在其加入缓冲液,不全行。

  • 这个join_buffer_size系统变量确定用于处理一个查询的每个连接的缓冲区的大小。

  • 一个缓冲区分配给每个连接可以缓冲,所以一个给定的查询可能会使用多个连接的缓冲区处理。

  • 加入缓冲区分配给执行加入前和释放后的查询进行了。

例如加入先前描述的NLJ算法(无缓冲),加入如下使用连接缓冲:

for each row in t1 matching range {
  for each row in t2 matching reference key {
    store used columns from t1, t2 in join buffer
    if buffer is full {
      for each row in t3 {
        for each t1, t2 combination in join buffer {
          if row satisfies join conditions, send to client
        }
      }
      empty join buffer
    }
  }
}

if buffer is not empty {
  for each row in t3 {
    for each t1, t2 combination in join buffer {
      if row satisfies join conditions, send to client
    }
  }
}

如果S是存储每个大小T1t2在加入缓冲组合C缓冲区中的组合数,次数表T3是扫描:

(S * C)/join_buffer_size + 1

t3扫描随价值join_buffer_size增加了点时join_buffer_size足以容纳所有以前的排组合。在这一点上,没有速度是通过使它更大了。

8.2.1.7嵌套连接优化

表达和语法允许嵌套连接。下面的讨论是指在加入语法描述第13.2.10.2,加入“语法”

语法table_factor在SQL标准比较扩展。后者只接受table_reference,没有他们的列表放在圆括号内。这是一个保守的延伸,如果我们考虑在一个列表中的每一个逗号table_reference项目相当于一个内部联接。例如:

SELECT * FROM t1 LEFT JOIN (t2, t3, t4)                 ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)

就相当于:

SELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)
                 ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)

在MySQL,CROSS JOIN在语法上是等价的内部联接他们可以相互替换。在标准的SQL,他们是不等价的。INNER JOIN使用一个打开(放)Clause;CROSS JOIN否则使用

总的来说,括号可以忽略加入只包含内在表达的连接操作。考虑加入表达:

t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.b=t3.b OR t2.b IS NULL)
   ON t1.a=t2.a

删除括号和左操作分组后,加入表达转变成这样的表达:

(t1 LEFT JOIN t2 ON t1.a=t2.a) LEFT JOIN t3
    ON t2.b=t3.b OR t2.b IS NULL

然而,这两个表达式是不等价的。看到这,假设表t1T2,和t3有以下状态:

  • t1包含的行(1)(2)

  • t2包含行(1101)

  • t3包含行(101)

在这种情况下,第一个表达式返回的结果集的行(1,1,101,101)(2,零,零,零),而第二表达式返回的行(1,1,101,101)(2,零,零,101)

mysql> SELECT *
       FROM t1
            LEFT JOIN
            (t2 LEFT JOIN t3 ON t2.b=t3.b OR t2.b IS NULL)
            ON t1.a=t2.a;
+------+------+------+------+
| a    | a    | b    | b    |
+------+------+------+------+
|    1 |    1 |  101 |  101 |
|    2 | NULL | NULL | NULL |
+------+------+------+------+

mysql> SELECT *
       FROM (t1 LEFT JOIN t2 ON t1.a=t2.a)
            LEFT JOIN t3
            ON t2.b=t3.b OR t2.b IS NULL;
+------+------+------+------+
| a    | a    | b    | b    |
+------+------+------+------+
|    1 |    1 |  101 |  101 |
|    2 | NULL | NULL |  101 |
+------+------+------+------+

在下面的例子中,一个外连接操作是通过内部联接操作一起使用:

t1 LEFT JOIN (t2, t3) ON t1.a=t2.a

表达不能转化为下面的表达式:

t1 LEFT JOIN t2 ON t1.a=t2.a, t3

对于给定的表态,两个表达式返回不同的行:

mysql> SELECT *
       FROM t1 LEFT JOIN (t2, t3) ON t1.a=t2.a;
+------+------+------+------+
| a    | a    | b    | b    |
+------+------+------+------+
|    1 |    1 |  101 |  101 |
|    2 | NULL | NULL | NULL |
+------+------+------+------+

mysql> SELECT *
       FROM t1 LEFT JOIN t2 ON t1.a=t2.a, t3;
+------+------+------+------+
| a    | a    | b    | b    |
+------+------+------+------+
|    1 |    1 |  101 |  101 |
|    2 | NULL | NULL |  101 |
+------+------+------+------+

因此,如果我们忽略圆括号中加入外部联接运算符的表达式,我们可能改变为原来的表达式的结果。

更确切地说,我们不能忽视在左外右操作数的括号连接操作在一个正确的连接操作的左操作数。换句话说,我们不能忽略外部连接操作的内表表达式的括号。对于另一个操作数的括号(对外部表数)可以忽略。

下面的表达式:

(t1,t2) LEFT JOIN t3 ON P(t2.b,t3.b)

是任何表这个表达式等效t1,t2,t3和任何条件P在属性t2.bt3.b

t1, t2 LEFT JOIN t3 ON P(t2.b,t3.b)

当执行命令的连接操作在连接表达式(join_table)不是从左到右,我们谈论嵌套连接。考虑以下查询:

SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.b=t3.b) ON t1.a=t2.a  WHERE t1.a > 1SELECT * FROM t1 LEFT JOIN (t2, t3) ON t1.a=t2.a  WHERE (t2.b=t3.b OR t2.b IS NULL) AND t1.a > 1

这些查询被认为含有这些嵌套连接:

t2 LEFT JOIN t3 ON t2.b=t3.b
t2, t3

在第一个查询,嵌套连接形成连接操作左。第二查询,它形成一个内在的连接操作。

在第一个查询,可以省略括号:的连接表达式的语法结构将决定加入操作的执行顺序。第二查询、圆括号不能省略,虽然加入表达这里可以解释明确没有他们。在我们的扩展语法,括号中(t2, t3)第二查询是必要的,虽然理论上查询可以解析没有他们:我们仍会有明确的语法结构的查询,因为左连接ON对表达的左和右的分隔符的作用(T2,T3)

前面的例子说明这一点:

  • 加入只涉及内部联接表达式(而不是外部联接),括号可以去掉,加入从左向右计算。事实上,表可以在任何顺序评估。

  • 同样是在一般的不真实,,外连接或外连接和内连接。去除括号可以改变结果。

嵌套的外连接查询的执行在同一管道内连接的查询方式。更确切地说,一种变异的嵌套循环连接算法开发。记得算法的嵌套循环连接执行查询(见第8.2.1.6,“嵌套循环连接算法)。假设一个加入3多表查询T1,T2,T3这种形式:

SELECT * FROM T1内P1(T1、T2和T2)内加入T3(T2,T3),P2 P(T1,T2,T3)

在这里,P1(T1,T2)P2(T3,T3)一些加入条件(表达式),而P(T1,T2,T3)在列表的条件T1,T2,T3

嵌套循环连接算法将在以下的方式执行此查询:

FOR each row t1 in T1 {
  FOR each row t2 in T2 such that P1(t1,t2) {
    FOR each row t3 in T3 such that P2(t2,t3) {
      IF P(t1,t2,t3) {
         t:=t1||t2||t3; OUTPUT t;
      }
    }
  }
}

符号t1||t2||t3显示一行行柱连接构造T1t2,和T3。在some examples of the following,NULL其中一个表的名字出现在这一行无效的用于每个列的表。例如,t1||t2||NULL显示一行行柱连接构造T1t2,和无效的每一列t3。这一行是无效的-是的

现在考虑一个嵌套的外连接查询:

SELECT * FROM T1 LEFT JOIN
              (T2 LEFT JOIN T3 ON P2(T2,T3))
              ON P1(T1,T2)
  WHERE P(T1,T2,T3)

此查询,修改嵌套循环模式获得:

FOR each row t1 in T1 {
  BOOL f1:=FALSE;
  FOR each row t2 in T2 such that P1(t1,t2) {
    BOOL f2:=FALSE;
    FOR each row t3 in T3 such that P2(t2,t3) {
      IF P(t1,t2,t3) {
        t:=t1||t2||t3; OUTPUT t;
      }
      f2=TRUE;
      f1=TRUE;
    }
    IF (!f2) {
      IF P(t1,t2,NULL) {
        t:=t1||t2||NULL; OUTPUT t;
      }
      f1=TRUE;
    }
  }
  IF (!f1) {
    IF P(t1,NULL,NULL) {
      t:=t1||NULL||NULL; OUTPUT t;
    }
  }
}

一般来说,任何嵌套循环的第一内表外连接操作,介绍了一种标志,关闭前环和后环检查。国旗被打开时,当前行的从外表与表内的操作数被发现。如果在循环周期的结束标志仍然是关闭的,没有匹配的已发现的外表中的当前行。在这种情况下,该行的补充NULL为内表的列的值。结果行传递到输出或进入下一个循环嵌套的最终检查,但如果行满足连接条件的所有嵌入的外部联接。

在这个例子中,外部联接表由以下表达式表示嵌入:

(T2 LEFT JOIN T3 ON P2(T2,T3))

与内部联接的查询,优化器可以选择不同的顺序嵌套循环,例如这一个:

FOR each row t3 in T3 {
  FOR each row t2 in T2 such that P2(t2,t3) {
    FOR each row t1 in T1 such that P1(t1,t2) {
      IF P(t1,t2,t3) {
         t:=t1||t2||t3; OUTPUT t;
      }
    }
  }
}

与外部联接的查询,优化器只能选择这样一个顺序在表外环内表圈之前。因此,我们与外连接查询,只有一个嵌套顺序是可能的。以下查询优化器计算两个不同的嵌套。在嵌套,T1必须处理,外环是用的外连接。T2T3用于内连接,所以连接必须在内部循环处理。然而,由于连接是内部联接,T2T3可在订单处理

SELECT * T1(T2、T3)左连接在P1(T1,T2)和P2(T1,T3),P(T1,T2,T3)

一个嵌套的评价T2,然后T3

FOR each row t1 in T1 {
  BOOL f1:=FALSE;
  FOR each row t2 in T2 such that P1(t1,t2) {
    FOR each row t3 in T3 such that P2(t1,t3) {
      IF P(t1,t2,t3) {
        t:=t1||t2||t3; OUTPUT t;
      }
      f1:=TRUE
    }
  }
  IF (!f1) {
    IF P(t1,NULL,NULL) {
      t:=t1||NULL||NULL; OUTPUT t;
    }
  }
}

其他嵌套的评价T3,然后T2

FOR each row t1 in T1 {
  BOOL f1:=FALSE;
  FOR each row t3 in T3 such that P2(t1,t3) {
    FOR each row t2 in T2 such that P1(t1,t2) {
      IF P(t1,t2,t3) {
        t:=t1||t2||t3; OUTPUT t;
      }
      f1:=TRUE
    }
  }
  IF (!f1) {
    IF P(t1,NULL,NULL) {
      t:=t1||NULL||NULL; OUTPUT t;
    }
  }
}

当讨论嵌套循环算法的内部联接,我们省略了一些细节的查询执行性能的影响可能是巨大的。我们没有提及所谓的推下的条件。假设我们的WHERE条件P(T1,T2,T3)可以通过一个合取式表示:

P(T1,T2,T2) = C1(T1) AND C2(T2) AND C3(T3).

在这种情况下,MySQL实际上使用下面的嵌套的内部联接的查询执行循环算法:

FOR each row t1 in T1 such that C1(t1) {
  FOR each row t2 in T2 such that P1(t1,t2) AND C2(t2)  {
    FOR each row t3 in T3 such that P2(t2,t3) AND C3(t3) {
      IF P(t1,t2,t3) {
         t:=t1||t2||t3; OUTPUT t;
      }
    }
  }
}

你看,每个并列C1(T1)C2(T2)C3(T3)推出来的最内层循环的最外环,它可以评估。如果C1(T1)是一个非常严格的条件,此条件下可以大大减少从表的行数T1通过内循环。因此,对于查询的执行时间可能会得到极大的改善。

因为有一个很漂亮的小丑WHERE条件是只有在已发现从外表行目前已经在内部表的匹配检查。因此,推进条件出内循环嵌套优化不能直接应用与外部联接的查询。在这里,我们要介绍的条件下推谓词把守旗帜,打开时,比赛已经遇到。

记得这个例子与外部联接:

P(T1,T2,T3)=C1(T1) AND C(T2) AND C3(T3)

为例,嵌套循环算法使用守卫推倒条件看起来像这样:

FOR each row t1 in T1 such that C1(t1) {
  BOOL f1:=FALSE;
  FOR each row t2 in T2
      such that P1(t1,t2) AND (f1?C2(t2):TRUE) {
    BOOL f2:=FALSE;
    FOR each row t3 in T3
        such that P2(t2,t3) AND (f1&&f2?C3(t3):TRUE) {
      IF (f1&&f2?TRUE:(C2(t2) AND C3(t3))) {
        t:=t1||t2||t3; OUTPUT t;
      }
      f2=TRUE;
      f1=TRUE;
    }
    IF (!f2) {
      IF (f1?TRUE:C2(t2) && P(t1,t2,NULL)) {
        t:=t1||t2||NULL; OUTPUT t;
      }
      f1=TRUE;
    }
  }
  IF (!f1 && P(t1,NULL,NULL)) {
      t:=t1||NULL||NULL; OUTPUT t;
  }
}

在一般情况下,推下谓词可以提取加入条件如P1(T1,T2)P(T2,T3)。在这种情况下,一个推下谓守卫也由一个标志,防止检查的谓词NULL通过相应的外连接操作产生补排。

访问的关键从一个内表到另一个在相同的嵌套连接是由一个谓词诱导禁止WHERE条件

8.2.1.8外部连接优化

外部连接:LEFT JOIN右连接

MySQL实现A LEFT JOIN B join_condition如下:

  • B将取决于表A在在线和表whichA取决于

  • A将取决于所有的表(除B),用于左连接条件

  • 这个LEFT JOIN条件来决定如何从表中检索行B。(换句话说,在任何情况下哪里条款是没有用的。)

  • 所有标准的连接进行优化,除一表总是读它所依赖的所有表。如果有一个循环依赖,发生了一个错误。

  • 所有的标准WHERE进行优化

  • 如果有一个排A匹配哪里的条款,但没有行B匹配打开(放)的条件下,一个额外的B行设置所有列生成无效的

  • 如果你使用LEFT JOIN发现排不一定存在的表和你有以下的测试:col_name是空的哪里的一部分,在那里col_name是一个被声明为柱不为空,MySQL停止寻找更多的行(一个特定的组合键)后,发现了一行匹配LEFT JOIN条件

这个RIGHT JOIN实现是类似的左连接与表的角色逆转。正确的连接转换为等效的左连接,所述第8.2.1.9,“外连接简化”

对于一个LEFT JOIN,如果哪里条件总是错误的产生NULL行的左连接改为内连接。例如,在WHERE条款将在以下查询,如果是假的t2.column1NULL

SELECT * FROM t1 LEFT JOIN t2 ON (column1) WHERE t2.column2=5;

因此,可以将查询到的内部联接:

SELECT * FROM t1, t2 WHERE t2.column2=5 AND t1.column1=t2.column1;

现在,优化器可以使用表t2在表T1如果这样做会导致一个更好的查询计划。提供一个关于表提示连接顺序,使用优化器提示;看第8.9.2,“优化器提示”。另外,使用STRAIGHT_JOIN它;第13.2.10,选择“语法”。然而,STRAIGHT_JOIN可以防止指标被使用因为它禁用半连接的转换;看第8.2.2.1,优化子查询、派生表、视图的引用,和公用表表达式和半连接的转变”

8.2.1.9外连接的简化

表中的表达FROM一个查询子句在许多情况下的简化。

在解析阶段,右外部联接操作查询转换为等效的查询只包含左连接操作。在一般情况下,转换是这样进行的,这对加入:

(T1, ...) RIGHT JOIN (T2, ...) ON P(T1, ..., T2, ...)

成为这个等效左连接:

(T2, ...) LEFT JOIN (T1, ...) ON P(T1, ..., T2, ...)

表格的所有内部连接表达式T1 INNER JOIN T2 ON P(T1,T2)由表替代T1,T2P(T1,T2)作为一个连接的连接哪里条件(或连接条件的嵌入连接,如果有的话)。

当优化器评估外加入行动计划,它只考虑计划里,对于每一次这样的操作,外表内表访问之前。优化器的选择是因为只有这样的计划,使外部连接是使用嵌套循环算法执行有限公司。

考虑一个查询这个形式,在R(T2)大大缩小了从表匹配的行数T2

SELECT * T1 LEFT JOIN T2 ON P1(T1,T2)
  WHERE P(T1,T2) AND R(T2)

如果执行查询的书面,优化器没有选择只能访问限制较少的表T1在更严格的表T2,这可能会产生一个非常低效的执行计划。

相反,MySQL将查询到没有外连接操作查询如果WHERE条件是零拒绝。(即,将外部连接到内部联接。)的条件是零拒绝外部联接操作,如果它对错误的UNKNOWN对于任何无效的补行生成操作

因此,此外连接:

T1 LEFT JOIN T2 ON T1.A=T2.A

如这些空拒绝了因为他们不能为任何真实情况NULL补排(带T2栏目设置NULL):

T2.B IS NOT NULLT2.B > 3T2.C <= T1.CT2.B < 2 OR T2.C > 1

如这些都不是零拒绝,因为他们可以为真的条件NULL补排:

T2.B IS NULLT1.B < 3 OR T2.B IS NOT NULLT1.B < 3 OR T2.B > 3

一般规则检查是否为null拒绝外部联接操作简单:

  • 它的形式是A IS NOT NULL,在那里是任何的内表的属性

  • 这是一个谓词包含一个对内表UNKNOWN它的一个参数时无效的

  • 这是一个结合含有无效拒绝条件为合

  • 这是一个分离的零拒绝的条件

一个条件可以是零拒绝一个外连接操作查询中不空拒绝另一个。在这个查询的WHERE条件是零拒绝第二外部联接操作但不空拒绝第一个:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A                 LEFT JOIN T3 ON T3.B=T1.B  WHERE T3.C > 0

如果WHERE条件是零拒绝在查询外连接操作,外连接操作是通过内部联接操作代替。

例如,在前面的查询,第二外部连接是无效的拒绝,可以通过内部联接取代:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A
                 INNER JOIN T3 ON T3.B=T1.B
  WHERE T3.C > 0

对原始查询,优化器评估计划与单表访问兼容T1,T2,T3。对于重写查询,另外还考虑存取顺序T3、T1,T2

转换一个外连接操作会触发转换的另一个。因此,查询:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A
                 LEFT JOIN T3 ON T3.B=T2.B
  WHERE T3.C > 0

首先被转化为查询:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A
                 INNER JOIN T3 ON T3.B=T2.B
  WHERE T3.C > 0

这相当于查询:

SELECT * FROM (T1 LEFT JOIN T2 ON T2.A=T1.A), T3
  WHERE T3.C > 0 AND T3.B=T2.B

其余的外连接操作也可以因为条件的内部联接取代T3.B=T2.B是零拒绝。这样的结果是没有在所有的外连接查询:

SELECT * FROM (T1 INNER JOIN T2 ON T2.A=T1.A), T3  WHERE T3.C > 0 AND T3.B=T2.B

有时候优化器成功取代嵌入式外连接操作,但无法将嵌入外连接。以下查询:

SELECT * FROM T1 LEFT JOIN
              (T2 LEFT JOIN T3 ON T3.B=T2.B)
              ON T2.A=T1.A
  WHERE T3.C > 0

转换为:

SELECT * FROM T1 LEFT JOIN
              (T2 INNER JOIN T3 ON T3.B=T2.B)
              ON T2.A=T1.A
  WHERE T3.C > 0

可以重写只还含有嵌入外连接操作的形式:

SELECT * FROM T1 LEFT JOIN
              (T2,T3)
              ON (T2.A=T1.A AND T3.B=T2.B)
  WHERE T3.C > 0

任何企图将查询中嵌入的外连接操作必须考虑加入条件嵌入外部联接在一起WHERE条件在这个查询的哪里条件不是零拒绝嵌入式外加入,但加入嵌入外部联接条件T2.A=T1.A AND T3.C=T1.C是零拒绝:

SELECT * FROM T1 LEFT JOIN              (T2 LEFT JOIN T3 ON T3.B=T2.B)              ON T2.A=T1.A AND T3.C=T1.C  WHERE T3.D > 0 OR T1.D > 0

因此,查询可以被转换为:

SELECT * FROM T1 LEFT JOIN
              (T2, T3)
              ON T2.A=T1.A AND T3.C=T1.C AND T3.B=T2.B
  WHERE T3.D > 0 OR T1.D > 0

8.2.1.10多阅读范围优化

通过一系列阅读排在第二索引扫描可以导致许多随机磁盘访问基表当表大而不存储在存储引擎的缓存。与磁盘扫描多方位阅读(MRR)优化,MySQL试图减少范围扫描首先通过扫描指数仅收集钥匙相关行的随机磁盘访问次数。然后按键排序,最后行用主键顺序从基表中检索。磁盘扫描MRR的动机是为了减少随机磁盘访问次数而实现对基表中的数据,更连续扫描。

多方位阅读优化提供这些好处:

  • MRR使数据行被访问的顺序而不是以随机顺序,基于索引的元组。服务器获得一套指标元组满足查询条件的数据行进行排序,根据ID,并使用排序元组来检索数据行。这使得数据访问更有效和更昂贵的。

  • MRR能够为需要访问数据行通过索引元组操作的关键访问请求的批处理,如范围索引扫描等加入,使用索引的连接属性。MRR遍历序列的指数范围获得合格指标元组。作为这些结果的积累,它们被用来访问相应的数据行。这是没有必要在开始读取数据行获得的所有索引的元组。

MRR优化不次要指标对虚拟生成的列创建的支持。InnoDB支持二级指标虚拟生成的列。

以下情况说明当MRR优化是有利的:

场景一:材料可用于InnoDBMyISAM表索引范围扫描和等值连接操作。

  1. 该指数的一部分,是在一个缓冲区数据积累。

  2. 在缓存中的元组的数据行ID排序。

  3. 数据行根据排序的索引访问元组序列。

方案B:MRR可用于NDB多方位索引表扫描或表演等时的属性连接。

  1. 一部分的范围,可能单一的键范围,积累在一个缓冲区的中心节点,提交的查询。

  2. 范围发送到执行节点访问数据行。

  3. 访问的行被包装成包发送回中心节点。

  4. 接收到的包的数据行被放置在一个缓冲区。

  5. 从缓冲区读取数据行

当使用的材料,ExtraEXPLAIN输出显示使用MRR

InnoDBMyISAM如果不充分的表行不需要访问生成查询结果使用MRR。这种情况如果结果可以产生完全基于信息索引中的元组(通过覆盖指标MRR)提供任何好处。

optimizer_switch系统变量标志提供了一个接口,MRR的优化使用。这个MRR控制是否启用MRR是旗帜。如果mrr启用(打开(放)页:1mrr_cost_based标志控制是否优化器尝试基于成本的选择使用和不使用MRR(打开(放)(b)无论是否有可能(或)off页:1By default,MRRonmrr_cost_basedon。看到第3,“开关的优化”

MRR,存储引擎使用的价值read_rnd_buffer_size系统变量作为一个指南,它能为缓冲区分配多少内存。该发动机采用了read_rnd_buffer_size字节数和确定范围,通过在一个单一的过程。

8.2.1.11块嵌套循环和批量密钥访问加入

在MySQL中,一批重点访问(BKA)加入算法可使用索引访问表的加入和加入缓冲。米酵菌酸算法支持内连接,外连接、半连接操作,包括嵌套的外部联接。的好处包括改善连接性能BKA由于更高效的表扫描。同时,该块嵌套循环连接算法(BNL)以前仅用于内部联接扩展可用于外部连接和半连接操作,包括嵌套的外部联接。

以下各节讨论了加入缓冲管理基础原BNL算法的扩展,扩展的BNL算法,与BKA算法。关于半连接策略,看第8.2.2.1,优化子查询、派生表、视图的引用,和公用表表达式和半连接的转变”

加入缓冲管理块嵌套循环和批量化的关键accessalgorithms

MySQL可以采用加入缓冲区执行不仅内部联接没有内部表索引访问,而且外部连接和半连接的查询出现后压扁。此外,加入缓冲液可以有效地使用,当有内表的一个索引访问。

加入缓冲管理代码更有效地利用存储时加入缓冲空间的有趣的排列的值:没有额外的字节分配缓存行列如果它的值是NULL,和字节最小值分配任何值的VARCHAR类型

代码支持两种类型的缓冲区,定期和增量。想加入缓冲B1用于联接表T1t2与此操作的结果是与表T3使用连接缓冲B2

  • 定期加入缓冲区包含从每个加入操作柱。如果B2是一个普通的连接缓冲区,每一行r投入B2是由一排柱子r1B1和一个匹配行的有趣的列r2从表T3

  • 增量加入缓冲区只包含列的第二连接操作产生的表行。就是说,它是从第一个操作数增量缓冲行。如果B2是一个渐进的加入缓冲区,它包含的排列的有趣r2一个连结在一起的行r1B1

增量加入缓冲区总是增量相对于加入从早期的连接操作的缓冲区,所以从第一个连接操作的缓冲区始终是一个普通的缓冲区。在这个例子,缓冲B1用于联接表T1t2必须有一个规则的缓冲。

每排用于连接操作的增量缓冲区只包含有趣的列一列从表中要加入。这些列是增强由第一次加入操作产生的表匹配的行列的有趣的参考。在增量缓冲几行可以参考相同的行r它的列存储在前加入缓冲区因为这些行匹配的行r

从增量缓冲器可以使用以前的连接操作的缓冲柱不频繁的复制。这提供了一个节省的缓冲空间,因为在一般情况下,一个排第一加入操作数产生可通过第二连接操作产生的几行匹配。这是不必要的,从第一个操作数进行连续几份。增量缓冲区也提供了一个节省处理时间,由于在复制时间的减少。

这个block_nested_loopbatched_key_access旗帜的optimizer_switch系统变量控制优化器如何使用块嵌套循环和批量密钥访问的连接算法。默认情况下,block_nested_looponbatched_key_accessoff。看到第3,“开关的优化”。优化器提示也可应用;看优化器提示块嵌套循环和批量密钥访问算法

关于半连接策略,看第8.2.2.1,优化子查询、派生表、视图的引用,和公用表表达式和半连接的转变”

块嵌套循环算法的外部连接和半连接

原来的MySQL BNL算法实现扩展支持外连接和半连接操作。

当这些操作执行的连接缓冲区,每排放入缓冲区提供一个匹配的旗帜。

如果一个外连接操作是使用连接缓冲区执行,每行的第二个操作数产生的表检查比赛中加入缓冲区的每一行。当找到一个匹配,形成一个新的扩展行(原行+列第二个操作数)将进一步扩展剩余的连接操作。此外,在缓冲区中的行匹配匹配标志启用。在表的所有行被加入了,加入缓冲区扫描。每一行从缓冲区没有比赛的标志启用扩展NULL补充(无效的在第二操作数的每个列的值)将进一步扩展剩余的连接操作。

这个block_nested_loop旗的optimizer_switch系统变量控制优化器如何使用块嵌套循环算法。默认情况下,block_nested_loopon。看到第3,“开关的优化”。优化器提示也可应用;看优化器提示块嵌套循环和批量密钥访问算法

进入EXPLAIN输出,一桌的使用是指在BNL额外值包含Using join buffer (Block Nested Loop)类型ALLindex,或range

关于半连接策略,看第8.2.2.1,优化子查询、派生表、视图的引用,和公用表表达式和半连接的转变”

批量密钥访问joins

MySQL实现方法联接表称为批量密钥访问(BKA)连接算法。米酵菌酸可以应用在通过第二连接操作产生的表的一个索引访问。像BNL连接算法,该算法采用BKA加入加入缓冲积累的连接操作的第一个操作数产生的排列的有趣。然后BKA算法建立键访问表中要加入缓冲区中的所有行并提交这些键在一个批处理的数据库引擎索引查找。关键是通过多方位向机读(MRR)接口(见第8.2.1.10,“多阅读范围优化”)。钥匙的提交后,MRR引擎功能进行查找索引中以最优的方式,获取连接表中的行发现这些钥匙,并开始喂米酵菌酸加入算法和匹配的行。每个匹配行是加上一个参考在加入缓冲行。

当BKA使用价值join_buffer_size定义键批量多大,在每一个请求的存储引擎。较大的缓冲区,更多的顺序访问将是一个连接操作的右手表,可以显着提高性能。

对米酵菌酸被用的batched_key_access旗的optimizer_switch系统变量必须设置为打开(放)。BKA采用MRR,所以mrr标记也必须打开(放)。目前,对MRR的成本估计太悲观。因此,它是必要的mrr_cost_based成为远离的用于对米酵菌酸。下面的设置启用BKA:

mysql> SET optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';

还有,MRR函数执行两种情况:

  • 第一种方案是使用传统的基于磁盘的存储引擎等InnoDBMyISAM。这些发动机,通常从加入缓冲区的所有行的键提交立即向MRR接口。发动机特定的MRR函数执行的提交键索引查找,得到行ID(或主键)从他们身上,然后把这些选定的行ID逐一BKA算法要求的行。每一行返回一个关联的参考,使进入匹配的行中加入缓冲。行取MRR功能以最佳的方式:他们在排ID(主键),取。这提高了性能,因为读磁盘顺序而不是随机的顺序。

  • 另一种是用于远程存储引擎等NDB。一套钥匙从加入缓冲行的一部分,连同他们的协会,是由一个MySQL服务器发送(SQL节点)到MySQL集群节点的数据。作为回报,SQL节点接收到一个包(或几个包)加上相应的关联匹配行。米酵菌酸加入算法将这些行和建立新加入行。然后,一组新的密钥发送到数据节点和从返回的包行是用来建立新加入行。这个过程一直持续到从加入缓冲最后密钥发送到数据节点和SQL节点接收到了所有匹配行这些钥匙。这提高了性能,因为少了关键轴承包由SQL节点发送到数据节点意味着更少的往返和数据节点之间执行连接操作。

在第一个场景中,在加入缓冲区的一部分被保留用于存储行标识(主键)通过查找索引选择和作为参数传递的MRR功能。

没有特殊的缓冲区来存储了从加入缓冲行键。相反,一个函数,建立缓冲区中的下一行的关键是作为参数传递的MRR功能。

进入EXPLAIN输出,一桌的使用是指当米酵菌酸额外值包含Using join buffer (Batched Key Access)类型refeq_ref

优化器提示块嵌套循环和批量密钥访问算法

除了使用optimizer_switch系统变量控制优化器使用的BNL和BKA算法广泛支持会话,MySQL优化器提示优化器对每个语句基础的影响。看到第8.9.2,“优化器提示”

使用BNL或者BKA暗示使加入任何内表外连接的缓冲,加入缓冲必须为外部联接内启用的表。

8.2.1.12条件过滤

在加入处理,前缀行那些行通过从一个表中的一个连接到下一个。在一般情况下,优化器会尝试把桌子低前缀计数早在加入以保持排组合数量迅速增加。在某种程度上,优化器可以使用条件的信息,选择从一个表中的行并传递给下一个,更准确的可计算行估计和选择最佳的执行计划。

无状态过滤,为表前缀行计数的基础上选定的行数的估计WHERE根据两者的访问方法优化选择条款。条件过滤使优化器在使用其他相关条件哪里条款没有考虑到访问的方法,从而提高其前缀的行数的估计。例如,虽然有可能是一个基于索引的访问方法,可以用来选择一个加入从电流表的行,也可能是在表的附加条件WHERE可过滤条款(限制)的排位赛传递给下一个表行的估计。

条件有利于滤波估计只有:

  • 它是指电流表

  • 这取决于一个恒定值或值的加入顺序前面的表。

  • 它是不是已经被访问的方法考虑。

进入EXPLAIN输出的列指示所选择的接入方法行估计,和filtered柱反映状态的滤波作用。过滤值表示为百分比。最大值是100,这意味着没有过滤的行发生。减少100值表明越来越多的过滤。

前缀的行数(行估计是通过电流表连接到下一个数)的产品rows过滤价值观。即前缀行数的行数,以估计的滤波效果降低。例如,如果rows1000,过滤is 20%, condition filtering reduces the estimated row count of 1000 to a prefix row count of 1000 × 20% = 1000 × .2 = 200.

考虑以下查询:

SELECT *
  FROM employee JOIN department ON employee.dept_no = department.dept_no
  WHERE employee.first_name = 'John'
  AND employee.hire_date BETWEEN '2018-01-01' AND '2018-06-01';

假设数据集具有这些特点:

  • 这个employee表有1024行

  • 这个department表有12行

  • 两表索引dept_no

  • 这个employee表的索引第一_ name

  • 八行满足这个条件employee.first_name

    employee.first_name = 'John'
  • 150行满足这个条件employee.hire_date

    employee.hire_date之间的2018-01-01 &#39;和&#39; 2018-06-01”
  • 1行满足条件:

    employee.first_name = 'John'
    AND employee.hire_date BETWEEN '2018-01-01' AND '2018-06-01'
    

无状态过滤,EXPLAIN这样产生的输出:

---- ------------ -------- ------------------ --------- --------- ------ ---------- | ID |表|型| possible_keys |关键| REF |行|过滤| ---- ------------ -------- ------------------ --------- --------- ------ ---------- | 1 |员工| REF |名字,h_date,系|名字| const | 8 | 100 | | 1 |部| eq_ref |初级|小学| dept_no | 1 | 100 | ---- ------------ -------- ------------------ --------- --------- ------ ----------

employee,在访问方法姓名指数回升8行名称匹配'John'。没有过滤了(过滤100%),所以所有的行的下一行:表前缀前缀的行数rows×过滤= 8 × 100% = 8.

有条件的过滤,优化器还考虑到条件从WHERE条款不考虑访问方法。在这种情况下,优化器使用启发式方法的16.31%个滤波效果评价BETWEEN条件employee.hire_date。因此,EXPLAIN这样产生的输出:

---- ------------ -------- ------------------ --------- --------- ------ ---------- | ID |表|型| possible_keys |关键| REF |行|过滤| ---- ------------ -------- ------------------ --------- --------- ------ ---------- | 1 |员工| REF |名字,h_date,系|名字| const | 8 | 16.31 | | 1 |部| eq_ref |初级|小学| dept_no | 1 | 100 | ---- ------------ -------- ------------------ --------- --------- ------ ----------

现在的前缀行计数rows×过滤= 8 × 16.31% = 1.3, which more closely reflects actual data set.

通常情况下,优化器不算条件过滤效果(前缀的行数减少)的最后加入表因为没有通过下表行。一个异常的发生EXPLAIN:提供更多的信息,滤波效果计算所有连接表,包括最后一个。

控制是否优化器考虑额外的过滤条件,使用condition_fanout_filter旗的optimizer_switch系统变量(参见第3,“开关的优化”)。这个标志是默认启用,但可以禁用抑制条件过滤(例如,如果一个特定的查询发现,产生更好的性能没有)。

如果优化器高估状态滤波的效果,性能可能比如果条件过滤不差。在这种情况下,这些技术可以帮助:

  • 如果列没有索引,索引,优化器的一些列值分布信息,可以提高其行估计。

  • 同样,如果没有列直方图信息,生成直方图(见第8.9.6,“优化统计”

  • 改变连接顺序。的方式来完成这包括连接顺序优化的提示(见第8.9.2,“优化器提示”),STRAIGHT_JOIN紧随选择,和STRAIGHT_JOIN连接操作

  • 禁用会话过滤条件:

    SET optimizer_switch = 'condition_fanout_filter=off';
    

    或者,对于一个给定的查询,使用优化器提示:

    SELECT /*+ SET_VAR(optimizer_switch = 'condition_fanout_filter=off') */ ...
    

8.2.1.13是无效的优化

MySQL可以执行相同的优化col_nameIS NULL它可以使用col_name=constant_value。例如,MySQL可以使用指标和范围搜索无效的IS NULL

实例:

SELECT * FROM tbl_name WHERE key_col IS NULL;

SELECT * FROM tbl_name WHERE key_col <=> NULL;

SELECT * FROM tbl_name
  WHERE key_col=const1 OR key_col=const2 OR key_col IS NULL;

如果一个WHERE条款包括col_nameIS NULL一个声明为柱条件不为空,表现为优化掉。这种优化不发生案件时可能产生的柱NULL无论如何;例如,如果是一对一的右侧表左连接

MySQL也可以优化组合col_name = expr OR col_name IS NULL,一是解决子查询的常见形式。EXPLAIN演出ref_or_null当这种优化方法

这种优化处理IS NULL对其中的关键部分

有些是优化查询的例子,假设有一个索引列aBt2

SELECT * FROM t1 WHERE t1.a=exprOR t1.a IS NULL;SELECT * FROM t1, t2 WHERE t1.a=t2.a OR t2.a IS NULL;SELECT * FROM t1, t2  WHERE (t1.a=t2.a OR t2.a IS NULL) AND t2.b=t1.b;SELECT * FROM t1, t2  WHERE t1.a=t2.a AND (t2.b=t1.b OR t2.b IS NULL);SELECT * FROM t1, t2  WHERE (t1.a=t2.a AND t2.a IS NULL AND ...)  OR (t1.a=t2.a AND t2.a IS NULL AND ...);

ref_or_null首先对参考答案一读的作品,然后用一个单独的搜索排无效的关键值

优化只能处理一IS NULL水平。在下面的查询,MySQL使用键查询仅在表达(t1.a=t2.a AND t2.a IS NULL)和无法使用的关键部分b

SELECT * FROM t1, t2  WHERE (t1.a=t2.a AND t2.a IS NULL)  OR (t1.b=t2.b AND t2.b IS NULL);

8.2.1.14顺序优化

本节描述了当MySQL可以使用索引来满足ORDER BY的条款,filesort使用索引时,不能使用,和执行计划的信息可以从优化器ORDER BY

一个ORDER BY与无极限可以将不同的命令行,讨论第8.2.1.17,“限制查询优化”

利用指标来满足订单

在一些情况下,MySQL可能会使用索引来满足ORDER BY条款和避免额外的排序与执行filesort运营

指数也可以使用,即使ORDER BY不匹配的指数到底,只要指数和所有额外的未使用的部分顺序列中的常数WHERE条款.如果索引不包含所有列的查询访问,指数只有索引访问比其他接入方式更便宜的使用。

假设有一个指数(key_part1, key_part2),以下查询可以使用索引来解决顺序部分。是否真的取决于优化器读取索引比表扫描,如果列不在索引也必须读更有效。

  • 在这个查询的索引(key_part1, key_part2)使优化器来避免排序:

    SELECT * FROM T1秩序key_part1key_part2

    然而,查询使用SELECT *,可选择的列多于key_part1key_part2。在这种情况下,扫描整个索引和查找表的行,列在索引中找到不可能比扫描表更贵的结果和排序。如果是这样的话,优化器可能不会使用索引。如果选择*只选择索引的列,索引可以避免和排序。

    如果t1是一个InnoDB表,表的主键是隐式的指标,该指标可用于解决ORDER BY此查询:

    选择pkkey_part1key_part2从T1秩序key_part1key_part2
  • 在这个查询,key_part1是恒定的,所以所有的行通过指数是key_part2顺序和索引key_part1key_part2如果避免了排序哪里条款是选择性足以使索引范围扫描比表扫描:

    SELECT * FROM t1
      WHERE key_part1 = constant
      ORDER BY key_part2;
    
  • 在接下来的两个查询,是否使用索引与查询不相同DESC先前所示:

    SELECT * FROM T1秩序key_part1desc,key_part2desc;SELECT * FROM T1的地方key_part1=constant顺序key_part2desc;
  • 在一个两列ORDER BY可以在同一个方向(两类ASC,或两者DESC(一)或在相反的方向ASC,一个DESC)。索引使用的条件是,指数必须有相同的均匀性,但不需要有相同的实际方向。

    如果一个查询的混合ASCdesc,优化器可以使用索引的列如果指数也采用相应的混合升降柱:

    SELECT * FROM t1
      ORDER BY key_part1 DESC, key_part2 ASC;
    

    优化器可以使用索引(key_part1key_part2)如果key_part1下降key_part2是上升的。它也可以使用索引的列(一个向后扫描)如果key_part1是升key_part2正在下降。看到第8.3.13,“降指标”

  • 在接下来的两个查询,key_part1与君士特比较【中文解释】:索引哪里条款是选择性足以使索引范围扫描比表扫描:

    SELECT * FROM t1
      WHERE key_part1 > constant
      ORDER BY key_part1 ASC;
    
    SELECT * FROM t1
      WHERE key_part1 < constant
      ORDER BY key_part1 DESC;
    
  • 在接下来的查询,ORDER BY没有名字key_part1但所有的行,选择有一个恒定的key_part1值,所以指数仍然可以使用:

    SELECT * FROM T1的地方key_part1=constant1key_part2&#62;constant2顺序key_part2

在一些情况下,MySQL不能使用索引来解决ORDER BY,尽管它可能仍然使用索引查找匹配的行的哪里条款.实例:

  • 该查询使用ORDER BY对不同的指标:

    SELECT * FROM T1秩序key1key2
  • 该查询使用ORDER BYOn no Consecutive parts of an index :

    SELECT * FROM T1的地方key2=constant顺序key1_part1key1_part3
  • 该指标用来提取行不同于一个用于ORDER BY

    SELECT * FROM T1的地方key2=constant顺序key1
  • 该查询使用ORDER BY一个表达式,包括比其他索引列名称:

    选择从T1秩序*(ABSkey);选择*从T1秩序—key
  • 查询和多表,在列ORDER BY是不是所有的从第一个数的表是用来检索行。(这是第一个表中EXPLAIN输出没有const连接类型。)

  • 查询有不同ORDER BY表达.

  • 有一个唯一的前缀索引中的列命名ORDER BY条款.在这种情况下,该指标不能充分解决排序。例如,如果只有前10个字节的CHAR(20)列的索引,索引值不能区分过去十字节和filesort是必要的

  • 索引不存储的行为。例如,这是一个真实的HASH指数在内存

一种指数的排序的有效性可以通过列别名的使用影响。假定柱t1.a索引。在这份声明中,选择列表中的列的名称是。它指的是t1.a作为参考,不ORDER BY,所以指数一个T1可以使用:

SELECT a FROM t1 ORDER BY a;

在这份声明中,选择列表中的列的名称也a恩,but is the name的别名。en to”是指ABS(A)作为参考,不a顺序,所以指数t1.a不能使用:

选择ABS(一)作为一个从T1的命令;

在随后的声明中,该ORDER BY指的是一个名字,是不是在选择列表中的列的名称。但有一个列T1命名a,所以顺序是指t1.a和指数一个T1可以使用。(由此产生的排序顺序可能是完全不同的,ABS(a),当然。)

选择ABS(一)B从T1的命令;

以前(MySQL 5.7下),GROUP BY在一定条件下进行隐式。在MySQL 8中,不再发生,因此指定以空最后以抑制隐式排序(以前就是这样做的)不再是必要的。然而,查询的结果可能不同于以前的MySQL版本。产生一个给定的排序顺序,提供ORDER BY条款.

使用filesort满足订单

如果一个指标不能用来满足ORDER BY子句,MySQL执行filesort操作:表格行和排序。一filesort构成了一个额外的排序相在查询执行。

获得的记忆filesort操作,如MySQL 8.0.12,优化分配的内存缓冲区递增的需要,达到尺寸表示的sort_buffer_size系统变量,而不是分配固定数量的sort_buffer_size字节的前面,如MySQL 8.0.12之前完成。这使用户设置sort_buffer_size值越大,加快大类小类,没有过多的内存使用问题。(这个好处可能不会出现在Windows中,多个并发的类具有弱的多线程malloc。)

filesort手术采用临时磁盘文件是必要的如果结果集太大,内存放。某些类型的查询特别适合完全在内存中filesort运营例如,优化器可以使用filesort内存中的有效处理,没有临时文件的顺序操作(和子查询)查询下列形式:

SELECT ... FROM single_table ... ORDER BY non_index_column [DESC] LIMIT [M,]N;

这样的查询是常见的Web应用程序,只显示几行从一个更大的结果集。实例:

SELECT col1, ... FROM t1 ... ORDER BY name LIMIT 10;
SELECT col1, ... FROM t1 ... ORDER BY RAND() LIMIT 15;
通过优化影响

ORDER BY查询的filesort不使用,尽量降低max_length_for_sort_data系统变量的值是适当的触发filesort。(设定值这一变量太高是一种高磁盘活动和较低的CPU活动。症状)

增加ORDER BY速度,检查您是否可以得到MySQL使用索引而不是一个额外的排序阶段。如果这是不可能的,试试以下的策略:

  • 增加sort_buffer_size变量的值。理想的情况下,该值应足够大,将适合在排序缓冲整个结果(避免写到磁盘合并通过)。

    考虑到存储在排序缓冲区的列值的大小是受max_sort_length系统变量的值。例如,如果元组的长字符串列存储值和增加你的价值max_sort_length,排序缓冲区大小增加元组以及需要你增加sort_buffer_size

    监测数量的合并(合并时的临时文件),检查Sort_merge_passes状态变量

  • 增加read_rnd_buffer_size变量的值使更多的行读一次。

  • 改变tmpdir系统变量来指向一个专用的文件系统与大量的自由空间。变量的值可以列出几条常用的循环方式;您可以使用此功能将负载分散在几个目录。由冒号分隔的路径()在UNIX和分号(;)在Windows。的路径应该在文件系统位于不同的目录名称身体的盘,同一磁盘上的不同分区。

通过执行计划信息秩序

EXPLAIN(见8.8.1节,“优化查询的解释”),您可以检查是否MySQL可以使用索引来解决ORDER BY条款:

  • 如果ExtraEXPLAIN输出不包含使用filesort,用指数和filesort不执行

  • 如果ExtraEXPLAIN输出包含使用filesort,指数是没有用的,filesort执行

此外,如果一个filesort进行优化的跟踪输出包括filesort_summary块。例如:

"filesort_summary": {
  "rows": 100,
  "examined_rows": 100,
  "number_of_tmp_files": 0,
  "peak_memory_used": 25192,
  "sort_mode": "<sort_key, packed_additional_fields>"
}

peak_memory_used表明在任何时间使用的最大内存中排序。这是一个价值高达但不一定一样大的价值sort_buffer_size系统变量。MySQL 8.0.12之前,输出显示sort_buffer_size相反,指示值sort_buffer_size。(MySQL的优化器8.0.12,总是分配之前sort_buffer_size对于排序缓冲区字节。作为8.0.12排序缓冲区内存分配,优化增量,开始少量添加更多的必要了sort_buffer_size字节)

这个sort_mode价值提供了关于在排序缓冲元组的内容信息:

  • <sort_key, rowid>:这表明排序缓冲元组包含排序关键字值和原始表的列ID对。元组排序键值的行ID排序是用来从表中读取的行。

  • <sort_key, additional_fields>:这表明排序缓冲元组包含排序关键字值和列的查询中引用。元组排序键值和列值的排序是从元组直接读取。

  • <sort_key, packed_additional_fields>:像以前的变种,但额外的列被紧紧地挤在一起而不是使用一个固定长度编码。

EXPLAIN不区分是否优化是否执行filesort在记忆中。使用一个内存filesort可以在跟踪输出中看到的优化器。寻找filesort_priority_queue_optimization。关于优化跟踪信息,看MySQL内核:追踪优化器

8.2.1.15集团通过优化

为了满足一个最普通的方式GROUP BY条款是扫描整个表,创建一个新的临时表,从每一组中的所有行是连续的,然后使用这个临时表发现组和应用聚合函数(如有)。在一些情况下,MySQL能够做的更好,通过使用索引访问避免创建临时表。

使用指标的最重要的前提GROUP BY是所有列参考属性相同的指数,而指数存储键为(是真实的,例如,一个BTREE指数,但不一搞砸指数)。是否使用临时表可以通过索引访问取代也取决于这一指标的部分是在查询中使用的,这部分规定的条件,并选择聚合函数。

有两种方法来执行GROUP BY通过索引访问查询,在下面的章节中详细。第一种方法适用于所有的分组操作范围谓词(如果有的话)。第二方法首先执行范围扫描,然后组产生的元组。

松散索引扫描也可以用来在没有GROUP BY在一定的条件下。看到跳跃扫描范围的访问方法

松散索引扫描

处理的最有效的方法GROUP BY当一个指数是用来直接检索分组列。这种访问方法,MySQL使用一些指数型的关键是有序的属性(例如,B树)。这个属性可以使用查找组指标没有考虑所有的索引键都满足WHERE条件这种访问方法考虑索引中只有一小部分的钥匙,所以它被称为松散索引扫描。当没有WHERE条款,松散索引扫描读取多键组的数目,这可能是一个比所有的按键数量小得多。如果哪里包含谓词(见条款范围的讨论range加入型8.8.1节,“优化查询的解释”),一个松散的索引扫描查找第一个关键的每一组满足条件的范围内,并再次读取按键的数量最少。这可能是在下列条件下:

  • 在单表查询

  • 这个GROUP BY只有名字列,形成一个索引,没有其他栏目最左前缀。(如果不是,查询有DISTINCT条款,所有不同的属性所引用的列形成一个索引的最左前缀。)例如,如果表T1有一个指标(c1,c2,c3)松散索引扫描,如果查询是适用的集团通过C1、C2。它不适用于如果查询GROUP BY c2, c3(列是不是最左前缀)或由C1,C2,C4c4是不是在指数)

  • 唯一的聚合函数用于选择列表(如果有的话)是MIN()MAX(),它们都是指同一列。列必须在索引中的列必须马上走

  • 其他部分的指数比那些从GROUP BY在查询中引用必须是常数(也就是说,他们必须在平等与常量引用),除了论证MIN()MAX()功能.

  • 列在索引中,全列的值必须被索引,而不只是一个前缀。例如,用c1 VARCHAR(20), INDEX (c1(10)),该指数仅使用一个前缀C1值,不能用于松散索引扫描。

如果松散索引扫描是一个适用于查询的EXPLAIN输出显示利用指数组Extra专栏

假设有一个指数idx(c1,c2,c3)在表T1(C1,C2,C3,C4)。松散索引扫描访问方法可以使用以下查询:

SELECT c1, c2 FROM t1 GROUP BY c1, c2;
SELECT DISTINCT c1, c2 FROM t1;
SELECT c1, MIN(c2) FROM t1 GROUP BY c1;
SELECT c1, c2 FROM t1 WHERE c1 < const GROUP BY c1, c2;
SELECT MAX(c3), MIN(c3), c1, c2 FROM t1 WHERE c2 > const GROUP BY c1, c2;
SELECT c2 FROM t1 WHERE c1 < const GROUP BY c1, c2;
SELECT c1, c2 FROM t1 WHERE c3 = const GROUP BY c1, c2;

下面的查询无法执行这个快速选择方法的原因:

  • 有聚合函数以外MIN()MAX()

    选择C1,和(C2)从T1组C1;
  • 在列GROUP BY条款不构成索引的最左前缀:

    选择C1、C2从T1组C2、C3;
  • 查询是指的一个关键是一部分后GROUP BY的一部分,并有一个恒定的不平等:

    选择C1,C1从T1组C3、C2;

    包含了查询WHERE c3 = const松散索引扫描,可以使用。

松散索引扫描访问方法可以适用于其他形式的选择列表中的聚合函数的引用,另外的MIN()MAX()引用已经支持:

假设有一个指数idx(c1,c2,c3)在表T1(C1,C2,C3,C4)。松散索引扫描访问方法可以使用以下查询:

SELECT COUNT(DISTINCT c1), SUM(DISTINCT c1) FROM t1;

SELECT COUNT(DISTINCT c1, c2), COUNT(DISTINCT c2, c1) FROM t1;
紧索引扫描

紧张的索引扫描可以全索引扫描或范围索引扫描,根据不同的查询条件。

当一个松散的指数条件扫描不满足,它仍有可能避免创建临时表GROUP BY查询。如果有条件的范围哪里条款,此方法只读取按键,满足这些条件。否则,它执行索引扫描。因为此方法读取每个范围内定义的所有钥匙WHERE条款,或扫描整个索引,如果没有范围的条件下,它被称为紧索引扫描。与紧张的索引扫描,分组操作只有在满足条件的范围内已发现的所有按键进行。

使用这个方法,它是足够的,有一个恒定的等式条件的所有列在查询中涉及的部分关键到来之前或在部分之间GROUP BY钥匙从平等条件的常数填写任何空白在搜索键,从而可以形成完整的前缀索引。这些指数的前缀,然后可用于查找索引。如果GROUP BY结果需要排序,并可能形成是索引前缀搜索键,MySQL也避免了额外的排序操作,因为在一个有序的索引已经检索所有的钥匙为前缀搜索。

假设有一个指数idx(c1,c2,c3)在表T1(C1,C2,C3,C4)。下面的查询不使用松散索引扫描访问方法,但跟紧指数仍然工作扫描访问方法。

  • 在有一个缺口GROUP BY,但它是由条件c2 = 'a'

    SELECT c1, c2, c3 FROM t1 WHERE c2 = 'a' GROUP BY c1, c3;
    
  • 这个GROUP BY没有开始的关键的一部分,但有一个条件,提供了一个恒定的那一部分:

    SELECT c1, c2, c3 FROM t1 WHERE c1 = 'a' GROUP BY c2, c3;

8.2.1.16明显优化

DISTINCT结合顺序需要在许多情况下,一个临时表。

因为DISTINCT可以使用,学会工作列在MySQLORDER BY条款不属于所选列的一部分。看到第12.19.3,MySQL处理组”

在大多数情况下,一个DISTINCT条款可以被视为一种特殊情况。例如,下面的两个查询是等效的:

SELECT DISTINCT c1, c2, c3 FROM t1
WHERE c1 > const;

SELECT c1, c2, c3 FROM t1
WHERE c1 > const GROUP BY c1, c2, c3;

由于这种等价性,适用于优化GROUP BY查询也可用于查询和不同的条款.因此,在优化的可能性的更多细节DISTINCT查询,看第8.2.1.15,“优化”组

当结合LIMIT row_count不同的MySQL停止,尽快找到row_count独特的行

如果你不使用所有的表在查询中指定的列,MySQL停止扫描任何未使用的表,只要它找到第一个匹配。在下列情况下,假设t1之前使用T2(你可以检查EXPLAINMySQL),从阅读。T2(对于任何特定的行t1)当它发现第一排T2

SELECT DISTINCT t1.a FROM t1, t2 where t1.a=t2.a;

8.2.1.17限制查询优化

如果你需要从结果集只有一个指定的行数,使用LIMIT查询中的条款,而不是取整个结果集和扔掉的额外数据。

MySQL查询优化,有时有LIMIT row_count条款和无条款:

  • 如果你只选择几行LIMITMySQL的使用指标,在某些情况下,通常宁愿做全表扫描。

  • 如果你把LIMIT row_count顺序MySQL停止排序,只要它发现了第一row_count一排排的排序结果,而不是对整个结果。如果用一个指标进行排序,这是非常快的。如果一个filesort必须做,查询匹配,无所有行极限条款的选择,大多数或所有的排序,在第一row_count被发现。在最初的行被发现,MySQL不排序任何剩余的结果集。

    这种行为的一种表现形式是:ORDER BY查询有无极限可将不同的命令行,在本节后面介绍。

  • 如果你把LIMIT row_count不同的MySQL停止,尽快找到row_count独特的行

  • 在某些情况下,一个GROUP BY可以通过在命令读取索引解决(或者做一个排序的指标),然后计算总结直到指数值的变化。在这种情况下,极限row_count不计算任何不必要的价值观

  • 当MySQL发送到客户端所需的行数,在中止查询,除非你使用的是SQL_CALC_FOUND_ROWS。在这种情况下,行数可以获得选择found_rows()。看到12.14节,“信息功能”

  • LIMIT 0快速返回一个空集合。这可以检查一个查询的有效性是有用的。它也可以用来获得在使用MySQL的API,使结果集元数据应用的结果列的类型。与MySQL客户端程序,您可以使用--column-type-info选项显示结果的列类型。

  • 如果服务器使用临时表来解决一个查询,它使用LIMIT row_count条款来计算需要多少空间。

  • 如果一个指标是没有用的ORDER BY但一个极限条款也在场,优化器可以避免使用文件的合并和排序行内存使用内存中filesort运营

如果多个列中具有相同值的ORDER BY列,服务器是免费的任何命令返回的行,并可以根据不同的整体执行计划。换句话说,这些行的排序顺序是不确定的关于nonordered柱。

其中一个因素,影响执行计划LIMIT,所以顺序查询有无LIMIT可以将不同的命令行。考虑这个查询,这是排序的多类别但不确定柱相对于id评级专栏

mysql> SELECT * FROM ratings ORDER BY category;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
|  1 |        1 |    4.5 |
|  5 |        1 |    3.2 |
|  3 |        2 |    3.7 |
|  4 |        2 |    3.5 |
|  6 |        2 |    3.5 |
|  2 |        3 |    5.0 |
|  7 |        3 |    2.7 |
+----+----------+--------+

包括LIMIT可能会影响在每个命令行多类别价值。例如,这是一个有效的查询结果:

mysql> SELECT * FROM ratings ORDER BY category LIMIT 5;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
|  1 |        1 |    4.5 |
|  5 |        1 |    3.2 |
|  4 |        2 |    3.5 |
|  3 |        2 |    3.7 |
|  6 |        2 |    3.5 |
+----+----------+--------+

在每一种情况下,行进行排序的ORDER BY柱,这是由SQL标准要求。

如果它是保证同一排,重要的不LIMIT,包括额外的列顺序条款使阶确定性。例如,如果id价值观是独特的,你可以为一个给定的成行多类别值出现在id这样的顺序进行排序:

MySQL的&#62;SELECT * FROM ratings ORDER BY category, id;---- ---------- -------- | ID |范畴|评级| ---- ---------- -------- | 1 | 1 | 4.5 | | 5 | 1 | 3.2 | | 3 | 2 | 3.7 | | 4 | 2 | 3.5 | | 6 | 2 | 3.5 | | 2 | 3 | 5 | | 7 | 3 | 2.7 | ---- ---------- -------- MySQL &#62;SELECT * FROM ratings ORDER BY category, id LIMIT 5;---- ---------- -------- | ID |范畴|评级| ---- ---------- -------- | 1 | 1 | 4.5 | | 5 | 1 | 3.2 | | 3 | 2 | 3.7 | | 4 | 2 | 3.5 | | 6 | 2 | 3.5 | ---- ---------- --------

8.2.1.18函数调用优化

MySQL的功能标记内部确定的或不确定的。一个函数是不确定的如果,给出其参数固定的值,它可以返回不同的调用不同的结果。非确定性函数的例子:RAND()UUID()

如果一个函数被标记具有不确定性,在一个对它的引用WHERE条款对每行(当选择一个表中的行)或组合(当选择从多个表的连接)。

MySQL也决定当评估基于类型的参数的功能,无论是参数表列或常量值。一个确定性的函数,以表列作为参数必须进行评估时,柱的变化值。

不确定性函数可能会影响查询性能。例如,一些优化可能不可用,或者可能需要更多的锁定。以下的讨论使用RAND()但适用于其他不确定性函数以及。

假设一个表t这个定义:

创建表(ID int不空主键,col_a varchar(100));

考虑到这两个查询:

SELECT * FROM t WHERE id = POW(1,2);
SELECT * FROM t WHERE id = FLOOR(1 + RAND() * 49);

查询出现使用主键查找因为平等比较关键,但这是真的只是其中的第一:

  • 第一个查询总是产生最大一行因为POW()随着不断的争论是一个恒定值,用于索引查找。

  • 第二查询包含一个表达式,采用非确定性函数RAND(),这是不恒定的查询但实际上已经为表的每行一个新值T。因此,查询读表的每一行,每一行的预测评估,并输出所有行的主键值的随机匹配。这可能是零,一个或多个行,取决于id列的值在值RAND()序列

不确定性的影响不仅限于SELECT声明.这UPDATE语句使用非确定性函数,选择要修改的行:

UPDATE t SET col_a =some_exprWHERE id = FLOOR(1 + RAND() * 49);

大概意图是更新在一个单一的行的主键相匹配的表达。然而,它可能会更新为零,一个,或多个行,取决于id列的值在值RAND()序列

在所描述的行为对性能和复制的影响:

  • 因为一个不确定的功能不会产生一个恒定值,优化器不能使用策略,否则可能适用,如查找索引。结果可能是一个表扫描。

  • InnoDB可能升级的一系列关键锁而不是以单排锁一个匹配行。

  • 更新不确定性不执行复制。

困难在于RAND()函数求值一次表的每一行。避免多功能评估,使用这些技术:

  • 移动包含不确定性函数的另一份声明中表达,在变量中保存的值。在最初的声明,与参考的变量替换的表达,而优化器可以视为一个恒定值:

    SET @keyval = FLOOR(1 + RAND() * 49);
    UPDATE t SET col_a = some_expr WHERE id = @keyval;
    
  • 分配随机值在派生表变量。这项技术使变量被赋值一次,之前,在比较其使用WHERE条款:

    UPDATE /*+ NO_MERGE(dt) */ t, (SELECT FLOOR(1 + RAND() * 49) AS r) AS dtSET col_a =some_exprWHERE id = dt.r;

如前所述,在一个不确定的表达WHERE条款可能防止优化和结果在表扫描。然而,它可能会部分优化哪里如果其他的表达是确定的条款。例如:

SELECT * FROM t WHERE partial_key=5 AND some_column=RAND();

如果优化器可以使用partial_key为了减少行选择设定,RAND()被执行的次数减少,从而减少不确定性对优化的影响。

8.2.1.19窗函数优化

窗函数的影响策略的优化研究:

  • 如果子查询有窗函数导出表为子查询合并被禁用。子查询总是物化。

  • 半连接不适用于窗函数优化因为半连接适用于在子查询中的WHERE加入打开(放),其中不能包含窗口函数。

  • 优化过程的多个窗口,序列有相同的订货要求,因此排序可以跳过Windows下面的第一个。

  • 优化器不会尝试合并窗口,可以在一个单一的步骤进行;例如,当多个OVER条款包含相同的窗口定义。解决方法是在定义窗口窗口在条款并参照窗口名称OVER条款.

聚合函数不作为窗口的功能是聚集在最可能的查询。例如,在这个查询,MySQL看到COUNT(t1.b)是不存在于外部查询由于其位置哪里条款:

SELECT * FROM t1 WHERE t1.a = (SELECT COUNT(t1.b) FROM t2);

因此,MySQL的聚集体内部的子查询的处理t1.b作为一个常数和返回的行数T2

更换WHERE在一个错误的结果:

mysql> SELECT * FROM t1 HAVING t1.a = (SELECT COUNT(t1.b) FROM t2);
ERROR 1140 (42000): In aggregated query without GROUP BY, expression #1
of SELECT list contains nonaggregated column 'test.t1.a'; this is
incompatible with sql_mode=only_full_group_by

错误发生的原因COUNT(t1.b)可以存在于因此,外部查询汇总

窗函数(包括骨料作为窗口函数)没有前面的复杂性。他们总是聚集在子查询的地方都写,从不在外查询。

窗函数的评价可以通过值的影响windowing_use_high_precision系统变量,它决定着计算窗口操作而不损失精度。默认情况下,windowing_use_high_precision启用

对于一些移动框架的聚集体,逆聚合函数可以应用于从集合删除值。这可以提高性能,但可能会以损失精度。例如,添加一个非常小的浮点值的一个非常大的价值使很小的值是隐藏通过大量的价值。当反相大的价值后,对小值的效果了。

由于逆聚集的精度损失是浮点只有操作因素(近似值)的数据类型。对于其他类型,反聚集是安全的;这包括DECIMAL它允许一个小数部分,但一个确切的值类型。

执行速度更快,MySQL总是用反聚集时它是安全的:

对于方差的功能评价STDDEV_POP()STDDEV_SAMP()VAR_POP()VAR_SAMP(),和它们的同义词,评价可以发生在优化模式或默认模式。优化模式可能会在最后一位有效数字产生稍微不同的结果。如果这种差异是允许的,windowing_use_high_precision可以禁用允许优化模式。

EXPLAIN,窗口执行计划信息太大,传统的输出格式显示。看到窗口的信息,使用EXPLAIN FORMAT=JSON寻找开窗元素

8.2.1.20行构造函数的表达式优化

行构造函数允许多个值同时比较。例如,这两个语句在语义上是等价的:

SELECT * FROM t1 WHERE (column1,column2) = (1,1);
SELECT * FROM t1 WHERE column1 = 1 AND column2 = 1;

此外,优化器处理表达式相同的方式。

优化器是不太可能如果行构造函数列不包括索引的前缀使用索引。考虑下面的表格,其中有一个主键(c1, c2, c3)

create table T1(int,int,C1,C2,C3,C4 int,char(100),primary key(C1,C2,C3));

在这个查询的WHERE子句中索引使用的所有列。然而,行构造函数本身不包括索引,优化器使用前缀,只有结果C1key_len=4,大小C1):

mysql> EXPLAIN SELECT * FROM t1
       WHERE c1=1 AND (c2,c3) > (1,1)\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 3
     filtered: 100.00
        Extra: Using where

在这种情况下,重写构造函数表达行采用等效nonconstructor表达可能会导致更完整的索引使用。对于给定的查询,该行构造函数和等效nonconstructor表达式:

(c2,c3) > (1,1)
c2 > 1 OR ((c2 = 1) AND (c3 > 1))

重写查询优化器使用所有三列在索引中使用nonconstructor表达结果(key_len=12):

MySQL的&#62;EXPLAIN SELECT * FROM t1WHERE c1 = 1 AND (c2 > 1 OR ((c2 = 1) AND (c3 > 1)))\G*************************** 1。行***************************编号:1 select_type:简单表:T1分区:null类型:rangepossible_keys:主键:主要key_len:12编号:零排:3:100:使用额外的过滤

因此,为了更好的效果,避免混行构造函数AND/OR表达.使用一个或另一个。

在一定的条件下,优化器可以适用范围的访问方法IN()有行构造函数的参数表达式。看到行构造函数的表达范围优化

8.2.1.21避免全表扫描

从输出EXPLAIN演出ALL类型柱时,MySQL的使用全表扫描解决一个查询。这通常发生在下列条件下:

  • 桌子太小,可以更快地执行表扫描比管一个键查找。这对于少于10行的表和一个短的行长度是常见的。

  • 在没有可用的限制ON哪里索引列条款

  • 你是比较恒定的价值观和MySQL索引列有计算(基于索引树),常数覆盖太大的表的一部分,表扫描的速度会更快。看到第8.2.1.1,“WHERE子句优化”

  • 您使用的是一个关键的低基数(多行匹配的关键值)通过另一列。在这种情况下,MySQL假定使用钥匙可能会做许多关键的查找和表扫描的速度会更快。

小表,表扫描通常是适当的,对性能的影响可以忽略不计。对于大型的表,试试下面的方法来避免错误的优化器选择一个表扫描:

8.2.2优化子查询、导出表,查看参考,共同tableexpressions

MySQL查询优化器有不同的策略可以用来评价子查询。为IN(或=ANY)子查询优化器选择:

  • 半连接

  • 物化

  • EXISTS策略

NOT IN(或<>ALL)子查询优化器选择:

  • 物化

  • EXISTS策略

派生表,优化器选择:

  • 合并派生表进入外层查询块

  • 实现派生表内部临时表

视图引用和公用表表达式,优化器有相同的选择为派生表。

下面的讨论提供了上述优化策略的更多信息。

笔记

限制UPDATEDELETE语句中使用子查询来修改一个表是优化器不使用半连接或物化查询优化。作为一种变通方法,尝试重写为多个表UPDATEDELETE语句使用连接而不是子查询。

8.2.2.1优化子查询、导出表、视图的引用,和半公共tableexpressions联接转换

优化器使用半连接策略来提高查询的执行,如本节所述。

两表内连接,连接返回一行从一个表多次有在其他表中匹配。但对于一些问题,唯一一个重要的信息是否匹配,不匹配的数目。假设有个名为class花名册单班在课程和班级花名册(登记每个班的学生,分别)。列出有学生就读的课程,你可以使用这个连接:

SELECT class.class_num, class.class_name
FROM class INNER JOIN roster
WHERE class.class_num = roster.class_num;

然而,结果列出每个类每一次招收的学生。被问的问题,这是不必要的重复信息。

假设class_num在一个主键表,通过使用重复的抑制是可能的SELECT DISTINCT,但它是产生所有匹配行的第一只消除重复后无效。

同样的复制自由的结果可以通过使用子查询获得:

SELECT class_num, class_name
FROM class
WHERE class_num IN (SELECT class_num FROM roster);

在这里,优化器可以承认IN条款要求的子查询的返回唯一的每一类数的实例花名册表在这种情况下,查询可以使用半连接;即返回的每一行中只有一个实例运行class这是由行匹配花名册

外部连接和内部连接语法是在外部查询规范允许,和表可参考基表,导出表、视图的引用,或公用表表达式。

在MySQL数据库中,查询必须满足这些标准作为半办理加入:

  • 它必须是一个IN(或=ANY)查询,出现在顶部的水平WHERE打开(放)条款,可能是短期的AND的表达。例如:

    选择…OT1,…,(OE1,…)在(选择IE1,…从IT1,…在…);

    在这里,ot_i它_i代表在查询外部和内部零件表,和oe_iie_i代表表达,指列在外和内表。

  • 它必须是一个单一的SELECT没有UNION构建

  • 它必须不包含GROUP BY条款.

  • 它不能被隐式组合(它必须包含聚合函数)。

  • 它不能有ORDER BY极限

  • 语句不能使用STRAIGHT_JOIN连接类型在外部查询

  • 这个STRAIGHT_JOIN改性剂必须不

  • 内部和外部表的数量必须小于允许在连接表的最大数目。

子查询可能相关或不相关。DISTINCT是允许的,如极限除非ORDER BY也用了

如果子查询满足以上要求,MySQL将其转换为半连接,使得基于成本的选择,这些策略:

  • 将子查询的连接,或使用表拔出和运行查询子查询的表和表之间的内部和外部。表拔拉一桌从查询到外部查询。

  • 重复weedout:运行半连接好像加入和使用临时表中删除重复记录。

  • firstmatch:当扫描内表的行的组合,有一个给定的值组的多个实例,选择一个而不是返回他们。这种“捷径”扫描和消除不必要的排产。

  • loosescan:使用索引,使一个单一的价值可以从每个子查询的值组选择一个子查询表扫描。

  • 为实现子查询索引临时表进行联接,其中指数是用来删除重复项。该指数可能以后还可以用查找时加入临时表和表外;如果不是,表扫描。关于物化的更多信息,参见第8.2.2.2,“物化”优化子查询

这些策略可以启用或禁用使用以下optimizer_switch系统变量的旗帜:

  • 这个semijoin标志控制是否使用半连接。

  • 如果semijoin启用的firstmatchloosescanduplicateweedout,和materialization旗帜使更精细的控制允许的半连接策略。

  • 如果duplicateweedout半连接策略被禁用,则除非所有其他适用的策略也禁止使用。

  • 如果duplicateweedout是残疾人,有时候优化器可以生成查询计划远非最佳。这发生在贪婪搜索由于启发式剪枝,可通过设置optimizer_prune_level=0

这些旗子是默认启用。看到第3,“开关的优化”

优化器将处理意见分歧和派生表。这会影响查询使用STRAIGHT_JOIN改性剂和与进入子查询可以转换为半连接。下面的查询说明因为在处理变化导致的转型中的变化,因而不同的执行策略:

CREATE VIEW v AS
SELECT *
FROM t1
WHERE a IN (SELECT b
           FROM t2);

SELECT STRAIGHT_JOIN *
FROM t3 JOIN v ON t3.x = v.a;

优化器首先查看和转换IN子查询的半连接,然后检查是否合并视图到外部查询。因为straight_join外部查询中的改性剂防止半连接,优化器不合并,导致派生表评价使用物化表。

EXPLAIN输出指示使用的半连接策略如下:

  • 扩展EXPLAIN输出,由下面显示的文本SHOW WARNINGS显示重写查询,显示半连接结构。(见第8.8.3,“扩展解释输出格式”。)从这你就可以知道哪些表被拉出来的半连接。如果子查询转换为一个半连接,你会看到,子查询谓词消失了,其表WHERE条款合并为外查询加入列表哪里条款.

  • 重复weedout临时表的使用表明Start temporary端临时Extra专栏表未拔出,在范围内EXPLAIN输出行覆盖启动临时End temporary有他们的rowid在临时表

  • FirstMatch(tbl_name)额外加入快捷栏的显示

  • LooseScan(m..n)额外列指示使用的loosescan策略。mn关键零件号

  • 为实现临时表的使用是由行与显示select_type价值物化排一个table价值<subqueryN&#62;

8.2.2.2优化子查询物化

优化器使用物化以实现更高效的查询处理。物化加快查询执行生成查询结果作为一个临时表,通常在内存中。MySQL需要子查询结果的第一次,它体现了,结果到一个临时表。以后的任何时间的结果是必要的,MySQL又指临时表。优化器可能指数与哈希索引进行查找,快速和廉价的桌子。索引是唯一的,从而消除了重复,使表更小。

子查询物化使用内存中的临时表,如果可能的话,回落到磁盘上的存储如果表变得太大。看到第8.4.4,“MySQL”使用内部临时表

如果物化是不使用优化器有时改写相关子查询作为一个相关子查询。例如,下面的INsubquery是noncorrelated(where_condition只涉及列T2而不是t1):

SELECT * FROM t1where T1,T2在(选择B从T2的地方。where_condition);

优化器可能会改写这一EXISTS相关子查询:

SELECT * FROM t1where存在(选择B从T2,T2。where_conditionAND t1.a=t2.b);

使用临时表避免了这样的重写查询物化,使得它可以执行查询只有一次,而不是每行外查询一次。

子查询物化为可用于MySQL的optimizer_switch系统变量物化国旗必须启用。(见第3,“开关的优化”用。)materialization标志启用,实现适用于子查询谓词出现在选择列表中的任何地方(,哪里ONHAVING,或顺序),谓词,落入任何这些用例:

  • 谓语具有这种形式,当没有外部的表达oe_i或是内心的表达ie_i可为空N是一个金子

    oe_1oe_2,…,oe_N[不]在(选择)ie_1i_2,…,ie_N…)
  • 谓语具有这种形式,当有一个单一的外在表现oe和内心的表达ie。表达式可以是空

    oe[不]在(选择ie…)
  • 谓语是IN不在和结果UNKNOWN无效的)已经由于相同的意义FALSE

下面的示例说明如何为对等的要求UNKNOWN错误的谓词评估是否可以使用子查询物化的影响。假设where_condition仅从涉及列T2而不是t1我知道that is the noncorrelated子查询。

这是受物化查询:

SELECT * FROM t1
WHERE t1.a IN (SELECT t2.b FROM t2 WHERE where_condition);

在这里,不管的IN谓词返回未知FALSE。无论哪种方式,该行从T1不包括在查询结果

一个例子,查询物化是不是使用以下查询,在那里t2.b是一个空列:

SELECT * FROM t1where(T1,T1,T2(B)没有选择,B从T2,T2。where_condition);

以下限制适用于使用子查询的实现:

  • 的内部和外部的表达式的类型必须匹配。例如,优化器可以当两个表达式都是整数或小数都是使用物化,但如果不能一个表达式是整数及小数。

  • 内表达不能BLOB

使用EXPLAIN一个查询提供了一些指示优化器使用子查询是否实现。相比不使用物化查询执行,select_type可以改变DEPENDENT SUBQUERY子查询。这表明,为子查询,将每行执行一次外,物化使子查询被执行一次。此外,扩展EXPLAIN输出,由下面显示的文本SHOW WARNINGS包括实现materialized-subquery

8.2.2.3优化派生表、视图的引用,和公用表表达式

优化器可以使用派生表的参考策略:

  • 合并派生表进入外层查询块

  • 实现派生表内部临时表

优化器使用相同的策略来处理查看参考和公用表表达式。

例1:

SELECT * FROM (SELECT * FROM t1) AS derived_t1;

合并,查询执行类似:

SELECT * FROM t1;

例2:

SELECT *
  FROM t1 JOIN (SELECT t2.f1 FROM t2) AS derived_t2 ON t1.f2=derived_t2.f1
  WHERE t1.f1 > 0;

合并,查询执行类似:

SELECT t1.*, t2.f1
  FROM t1 JOIN t2 ON t1.f2=t2.f1
  WHERE t1.f1 > 0;

与物化,derived_t1derived_t2作为在各自的查询一个单独的表。

优化器处理源表和视图引用了相同的方式:尽可能避免不必要的物化条件,使压下从外部查询派生表和生产更高效的执行计划。(例如,见第8.2.2.2,“物化”优化子查询。)

如果合并会导致外部查询块引用61多个基表,优化器选择物化代替。

优化传播ORDER BY条款在派生表或视图外查询块参考如果这些条件都是真的:

  • 外部查询不分组或聚合。

  • 外部查询不指定DISTINCT,或ORDER BY

  • 外部查询此派生表或视图作为参考在的唯一来源FROM条款.

否则,优化器ignores the theORDER BY条款.

以下可用的手段是否影响优化器尝试合并源表和视图引用到外查询块:

  • 这个MERGEno_merge优化器提示可以使用。他们运用假设没有其他规则防止合并。看到第8.9.2,“优化器提示”

  • 同样,你可以使用derived_merge旗的optimizer_switch系统变量。See第3,“开关的优化”。默认情况下,国旗启用允许合并。禁止标志禁止合并,避免了ER_UPDATE_TABLE_USED错误.

    这个derived_merge国旗也适用于视图不包含算法条款.因此,如果一个ER_UPDATE_TABLE_USED发生错误观点参考,使用一个表达式等价的查询,添加ALGORITHM=TEMPTABLE为视图定义防止合并和接管derived_merge价值

  • 它可以禁用合并的子查询任何结构,防止合并使用,虽然这些都没有明确其对物化。结构,防止合并是相同的派生表、公用表表达式,并查看参考:

    • 聚合函数和窗口函数(SUM()MIN()MAX()COUNT()我知道,和四)

    • DISTINCT

    • GROUP BY

    • HAVING

    • LIMIT

    • UNIONUNION ALL

    • 选择列表中的子查询

    • 用户变量赋值

    • refererences只有文字值(在这种情况下,有没有相关的表格)

如果优化器选择物化策略而不是派生表的合并,它处理查询如下:

  • 优化器将派生表的物化到它的内容是在查询执行过程中所需要的。这提高了性能,因为延迟物化可能导致没有做到这一点。考虑加入一个派生表查询结果到另一张表:如果优化过程,其他表首先发现它没有返回行,加入不需要进一步开展,优化器可以完全跳过实现派生表。

  • 在执行查询,优化器可以添加索引派生表加快检索的行。

考虑以下EXPLAIN声明,为子查询中出现的条款一SELECT查询:

解释查询(SELECT * FROM T1)作为derived_t1;

物化查询优化器可以通过延迟直至结果需要在SELECT执行.在这种情况下,查询不执行(因为它发生在一个EXPLAIN声明),因此不需要

即使是对执行的查询,查询物化延迟可能使优化器实现完全避免。当这一切发生的时候,查询的执行需要进行物化的时间更快。考虑下面的查询,将在子查询的结果FROM条款的另一个表:

SELECT *  FROM t1 JOIN (SELECT t2.f1 FROM t2) AS derived_t2          ON t1.f2=derived_t2.f1  WHERE t1.f1 > 0;

如果优化过程t1第一、哪里条款产生一个空的结果,加入一定是空的,不需要物化查询。

的情况下,派生表的要求具体化,优化器可以添加索引化表来加快访问它。如果这样的索引使ref访问表,可以大大减少查询执行过程中读取的数据量。考虑以下查询:

SELECT * FROM t1 JOIN (SELECT DISTINCT f1 FROM t2) AS derived_t2         ON t1.f1=derived_t2.f1;

优化器在列建立索引f1derived_t2如果这样做会使使用ref以最低的成本获取执行计划。添加索引后,优化器可以把物化的派生表作为一个指标的常规表一样,它的好处同样从生成的索引。索引创建的开销相比,没有索引的查询执行成本可以忽略不计。如果ref访问会导致比其他接入方式成本较高,优化器创建没有索引和失去什么。

优化的跟踪输出,合并的源表或视图引用不显示为一个节点。只有底层表出现在顶部的查询计划。

为派生表化什么是同样适用于公用表表达式(CTE)。此外,以下专属于CTEs。

如果一个CTE的查询物化,它是物化的一次查询,即使查询引用了好几次。

递归CTE总是物化

如果一个CTE是实,优化器会自动添加相关的指标,如果估计的索引将加快对CTE的顶级声明访问。这是类似于派生表的自动标引,但如果CTE引用多次,优化器可能会创建多个索引,加快以最适当的方式由各参考访问。

这个MERGEno_merge优化器提示可以应用CTEs。每个CTE参考在顶层声明可以有它自己的暗示,允许热膨胀系数参考被选择性合并或实。下面的语句使用的暗示表明cte1应合并cte2应物化:

WITH
  cte1 AS (SELECT a, b FROM table1),
  cte2 AS (SELECT c, d FROM table2)
SELECT /*+ MERGE(cte1) NO_MERGE(cte2) */ cte1.b, cte2.d
FROM cte1 JOIN cte2
WHERE cte1.a = cte2.c;

这个ALGORITHM条款CREATE VIEW不影响任何物化WITH前面的条款SELECT在视图的定义语句。考虑这一说法:

CREATE ALGORITHM={TEMPTABLE|MERGE} VIEW v1 AS WITH ... SELECT ...

这个ALGORITHM价值实现的影响SELECT,不WITH条款.

CTEs,存储引擎用于磁盘内部临时表不能MyISAM。如果internal_tmp_disk_storage_engine=MYISAM一个错误发生时,任何试图实现一个CTE使用磁盘上的临时表。

如前所述,CTE,如果物化,物化一次,即使多次引用。表示一次性的物化,优化跟踪输出中包含一个发生creating_tmp_table加上一个或多个事件reusing_tmp_table

热膨胀系数与派生表的materialized_from_subquery结如下参考。这对于一个CTE是多次引用的是真实的,所以不会有重复materialized_from_subquery节点(这会给人的印象是,子查询被执行多次,并产生不必要的冗长的输出)。只有一个引用CTE拥有完整materialized_from_subquery随着它的查询计划的说明结。其他参考资料了materialized_from_subquery结。同样的想法适用于EXPLAIN输出传统格式:其他参考子查询不显示。

8.2.2.4优化子查询与存在的策略

某些优化适用于比较使用IN(或=ANY)运算符测试子查询结果。本节讨论这些问题,特别是面临的挑战NULL价值观现状。讨论的最后一部分提出如何可以帮助优化器。

考虑下面的子查询比较:

outer_expr IN (SELECT inner_expr FROM ... WHERE subquery_where)

MySQL评估查询从外到内即,首先得到外部的表达式的值outer_expr,然后运行查询并捕捉它产生的行。

一个非常有用的优化是通知子查询,唯一感兴趣的是那些表达内在的行inner_expr等于outer_expr。这是被推下一个适当的平等为子查询的完成哪里条款更严格。转换比较看起来像这样:

EXISTS (SELECT 1 FROM ... WHERE subquery_where AND outer_expr=inner_expr)

转换后,MySQL可以使用推下平等的限行必须要检查评估查询的数量。

更一般的,比较N子查询返回的值N值行是受同样的转换。如果oe_iie_i代表相应的外在和内在的表达值,该子查询比较:

oe_1,…,oe_N在(选择)ie_1,…,ie_N从…哪里subquery_where

成为:

EXISTS (SELECT 1 FROM ... WHERE subquery_where
                          AND oe_1 = ie_1
                          AND ...
                          AND oe_N = ie_N)

为简单起见,以下的讨论假定一个单一的对外部和内部的表达式的值。

刚才描述的转换有其局限性。如果我们无视可能是有效的NULL价值观。那是的下推战略工程,只要这些条件都是真实的:

  • outer_exprinner_expr不能无效的

  • 你不需要区分NULL错误的子查询的结果。如果子查询的一部分ORAND中的表达哪里子句,MySQL假设你不在乎。另一个例子,优化器发现NULL错误的子查询的结果不需要区分这是构建:

    ... WHERE outer_expr IN (subquery)
    

    在这种情况下,的WHERE条款拒绝行是否subquery退货无效的FALSE

当这些条件或不持有,优化更为复杂。

假设outer_expr被称为是一个非—无效的价值但查询不产生排成一排,outer_expr=inner_expr。然后outer_expr(选择)评价如下:

  • NULL,如果SELECT产生的任何行inner_expr无效的

  • FALSE,如果SELECT只产生非—无效的值或不生产

在这种情况下,寻找行的方法outer_expr = inner_expr不再有效。要寻找这样的行,但如果没有被发现,也找行inner_expr无效的。大致说来,子查询可以被转换成这样的:

EXISTS (SELECT 1 FROM ... WHERE subquery_where AND
        (outer_expr=inner_expr OR inner_expr IS NULL))

需要进行额外的IS NULL条件就是为什么MySQL的ref_or_null存取方法:

MySQL的&#62;EXPLAINSELECT outer_expr IN (SELECT t2.maybe_null_keyFROM t2, t3 WHERE ...)FROM t1;*************************** 1。行*************************** ID:1 select_type:主表:T1…*************************** 2。行***************************编号:2 select_type:相关子查询表:T2型:ref_or_nullpossible_keys:maybe_null_key关键:maybe_null_key key_len:5号:功能:2行:使用额外使用指数…

这个unique_subqueryindex_subquery子查询具体的接入方式也有NULL变种

额外的OR ... IS NULL条件使查询执行更复杂的(和在子查询优化成为不适用),但通常这是可以容忍的。

情况更糟的时候outer_expr可以是无效的。根据SQL的解释NULL作为未知的价值,NULL IN (SELECT inner_expr ...)这样的评价:

  • NULL,如果SELECT产生的任何行

  • FALSE,如果SELECT无行

适当的评价是必要的,它能够检查是否SELECT产生了所有的行,所以outer_expr=inner_expr不能下推到子查询。这是一个问题,因为许多现实世界的子查询变得很慢,除非平等可以推下去。

从本质上讲,必须有不同的方法来执行子查询取决于价值outer_expr

优化器选择SQL符合以上的速度,所以它占的可能性outer_expr可能是无效的

  • 如果outer_expr无效的,对下面的表达式,它是必要的执行SELECT以确定它是否产生任何行:

    空(选择inner_expr从…哪里subquery_where

    要执行原SELECT在这里,没有任何推下等式的上述以前。

  • 另一方面,当outer_expr是不是无效的,这是绝对必要的,这种比较:

    outer_expr IN (SELECT inner_expr FROM ... WHERE subquery_where)
    

    将这个表达式使用推下:

    EXISTS (SELECT 1 FROM ... WHERE subquery_where AND outer_expr=inner_expr)
    

    没有这种转换,查询将是缓慢的。

为了解决是否下推到子查询条件的困境,条件是包裹在触发功能.因此,该形式的表达:

outer_expr IN (SELECT inner_expr FROM ... WHERE subquery_where)

转换成:

EXISTS (SELECT 1 FROM ... WHERE subquery_where
                          AND trigcond(outer_expr=inner_expr))

更一般地,如果子查询的比较是基于内部和外部表情几双,转换需要比较:

(oe_1, ..., oe_N) IN (SELECT ie_1, ..., ie_N FROM ... WHERE subquery_where)

并将其转换为这种表达:

EXISTS (SELECT 1 FROM ... WHERE subquery_where
                          AND trigcond(oe_1=ie_1)
                          AND ...
                          AND trigcond(oe_N=ie_N)
       )

每个trigcond(X)是一种特殊的函数值为下列值:

  • X链接外部的表达oe_i是不是无效的

  • TRUE链接外部的表达oe_i无效的

笔记

触发功能对那种你创建触发器CREATE TRIGGER

平等,是包裹在trigcond()功能并非第一类谓词的查询优化器。大多数优化不能谓词,可以打开和关闭的查询执行时间的交易,所以他们承担任何trigcond(X是一个未知函数,忽略它。触发的等式可以通过这些优化的应用:

  • 参考的优化:trigcond(X=Y [OR Y IS NULL])可以用来构造refeq_ref,或ref_or_null表访问

  • 通过子查询执行引擎索引查找:trigcond(X=Y)可以用来构造unique_subqueryindex_subquery访问

  • 表条件生成器:如果子查询是一个多个表的连接,触发条件是尽快检查。

当优化器使用触发条件来创建基于访问索引查找一些种(如上述列表中的前两个项目),它必须对案件回退策略时关闭。此回退策略都是一样的:做一个全表扫描。进入EXPLAIN输出回退显示为对空键全扫描Extra专栏

MySQL的&#62;EXPLAIN SELECT t1.col1,t1.col1 IN (SELECT t2.key1 FROM t2 WHERE t2.col2=t1.col2) FROM t1\G*************************** 1。行***************************编号:1 select_type:主表:2 *************************** T1。行***************************编号:2 select_type:相关子查询表:T2型:index_subquerypossible_keys:KEY1键:key1 key_len:5号:功能:2行:使用额外的地方;在空键全扫描

如果你运行EXPLAIN然后SHOW WARNINGS,你可以看到触发条件:

*************************** 1. row ***************************  Level: Note   Code: 1003Message: select `test`.`t1`.`col1` AS `col1`,         <in_optimizer>(`test`.`t1`.`col1`,         <exists>(<index_lookup>(<cache>(`test`.`t1`.`col1`) in t2         on key1 checking NULL         where (`test`.`t2`.`col2` = `test`.`t1`.`col2`) having         trigcond(<is_not_null_test>(`test`.`t2`.`key1`))))) AS         `t1.col1 IN (select t2.key1 from t2 where t2.col2=t1.col2)`         from `test`.`t1`

触发条件的使用对性能的影响。一NULL IN (SELECT ...)表达现在可能会导致全表扫描(这是慢)当它以前没有。这是正确的结果付出的代价(的触发条件,战略的目标是提高依从性,而不是速度)。

多表查询,执行NULL IN (SELECT ...)特别慢因为加入优化器不会的情况下,外在表现为优化无效的。它假定查询的评价NULL左边是非常罕见的,即使有统计表明,否则。另一方面,如果外表达可能无效的不过,没有性能损失

帮助查询优化器更好地执行你的查询,使用这些建议:

  • 声明一个列NOT NULL如果真的是。这也有助于优化等方面简化列条件测试。

  • 如果你不需要区分NULL错误的子查询的结果,你可以很容易地避免缓慢的执行路径。更换一个比较看起来像这样:

    outer_expr IN (SELECT inner_expr FROM ...)
    

    这个表达:

    (outer_expr IS NOT NULL) AND (outer_expr IN (SELECT inner_expr FROM ...))
    

    然后NULL IN (SELECT ...)绝不是因为MySQL停止评价评价AND部分只要表达式的结果是明确的。

    另一个可能的重写:

    EXISTS (SELECT inner_expr FROM ...
            WHERE inner_expr=outer_expr)
    

    这也适用于当你不需要区分NULL错误的子查询的结果,在这种情况下,你可能真的要EXISTS

这个subquery_materialization_cost_based旗的optimizer_switch系统变量可以在子查询的物化和之间的选择控制进入-EXISTS辅助转换见第3,“开关的优化”

8.2.3 information_schema查询优化

应用程序监控数据库可能经常使用INFORMATION_SCHEMA表写这些表最有效的查询,使用以下的一般准则:

  • 试着只查询INFORMATION_SCHEMA表,数据字典表的视图。

  • 试图查询仅适用于静态元数据。选择列或使用检索条件的动态元数据随着静态元数据增加了开销处理动态元数据。

笔记

在数据库和表的名称比较行为INFORMATION_SCHEMA查询可能不同于你所期望的。详情见第10.8.7,“使用排序规则在information_schema搜索”

这些INFORMATION_SCHEMA表是数据字典表的视图来实现的,所以他们的查询检索信息从数据字典:

character_setscollationscollation_character_set_applicabilitycolumnseventsfilesinnodb_columnsinnodb_datafilesinnodb_fieldsinnodb_foreigninnodb_foreign_colsinnodb_indexesinnodb_tablesinnodb_tablespacesinnodb_tablespaces_briefinnodb_tablestatskey_column_usageparameterspartitionsreferential_constraintsresource_groupsroutinesschematastatisticstablestable_constraintstriggersviewsview_routine_usageview_table_usage

某些类型的值,即使是非观INFORMATION_SCHEMA表,检索查找的数据字典。这包括诸如数据库和表名,表类型和存储引擎。

一些INFORMATION_SCHEMA表包含列提供统计表:

statistics.cardinalitytables.auto_incrementtables.avg_row_lengthtables.checksumtables.check_timetables.create_timetables.data_freetables.data_lengthtables.index_lengthtables.max_data_lengthtables.table_rowstables.update_time

这些柱子代表动态表元数据;即信息表内容的变化而变化。

默认情况下,MySQL检索缓存值的列的mysql.index_stats台词字典表的列时,查询检索统计,这比直接从存储引擎更高效。如果缓存数据不可用或已经过期,MySQL检索最新的统计数据从存储引擎缓存中mysql.index_stats台词字典表。随后的查询检索缓存到缓存的数据过期统计。

这个information_schema_stats_expiry会话变量定义的时间到期之前缓存统计。默认值是86400秒(24小时),但时间期限可以延长为一年。

更新缓存值在任何时间对于一个给定的表,使用ANALYZE TABLE

查询统计的列不存储或更新统计在mysql.index_stats台词在这种情况下,数据字典表:

information_schema_stats_expiry是一个会话变量,每个客户端会话可以定义自己的到期价值。统计是从存储引擎检索和一个会话缓存可以被其他会话。

笔记

如果innodb_read_only系统变量是启用,ANALYZE TABLE可能会失败,因为它不能在数据字典更新统计表,并使用InnoDB。为ANALYZE TABLE操作更新密钥分配,即使操作更新表本身可能出现故障(例如,如果它是一个MyISAM表)。为了获得更新的统计分布,集information_schema_stats_expiry=0

INFORMATION_SCHEMA表实现对数据字典表的看法,对基础数据字典表索引允许优化器构建高效的查询执行计划。看到选择的优化,使用EXPLAIN。也看到服务器用来执行查询information_schema查询、使用SHOW WARNINGS后立即EXPLAIN

consider this statement,which确定小吃for theutf8mb4字符集:

MySQL的&#62;SELECT COLLATION_NAMEFROM INFORMATION_SCHEMA.COLLATION_CHARACTER_SET_APPLICABILITYWHERE CHARACTER_SET_NAME = 'utf8mb4';| ---------------------------- collation _ name | ---------------------------- | utf8mb4 _通用_我们| | utf8mb4 _仓| | utf8mb4 _ Unicode版本_我们| | utf8mb4 _ _我们| | utf8mb4 _ latvian _我们| | utf8mb4 _罗马尼亚_我们| | utf8mb4 _ slovenian _ |我们……

如何声明服务器进程吗?找出来,用EXPLAIN

MySQL的&#62;EXPLAIN SELECT COLLATION_NAMEFROM INFORMATION_SCHEMA.COLLATION_CHARACTER_SET_APPLICABILITYWHERE CHARACTER_SET_NAME = 'utf8mb4'\G*************************** 1。行***************************编号:1 select_type:简单表:CS分区:null类型:constpossible_keys:小学,名字:名字key_len:194编号:const行:1过滤:额外100:使用索引*************************** 2。行***************************编号:1 select_type:简单表:西分区:null类型:refpossible_keys:character_set_id关键:character_set_id key_len:8编号:const行:68过滤:100个额外的:null2行集,1报警(0.01秒)

看到用来满足语句的查询,使用SHOW WARNINGS

MySQL的&#62;SHOW WARNINGS\G*************************** 1. row ***************************  Level: Note   Code: 1003Message: /* select#1 */ select `mysql`.`col`.`name` AS `COLLATION_NAME`         from `mysql`.`character_sets` `cs`         join `mysql`.`collations` `col`         where ((`mysql`.`col`.`character_set_id` = '45')         and ('utf8mb4' = 'utf8mb4'))

SHOW WARNINGS,服务器处理查询COLLATION_CHARACTER_SET_APPLICABILITY在一个查询character_setscollations数据表格MySQL系统数据库

8.2.4优化性能模式查询

应用程序监控数据库可以使绩效模式表频繁使用。写这些表最有效的查询,利用他们的指标。例如,包括WHERE条款限制检索的基础上,在一个特定的行索引列值的比较。

大多数的性能模式表索引。表不是那些通常包含几行或不太可能经常查询。性能模式指标给优化器访问其他比全表扫描的执行计划。这些指标也提高性能相关的对象,如sys架构视图,使用这些表。

是否一个给定的性能架构表指标和它们是什么,用SHOW INDEXSHOW CREATE TABLE

MySQL的&#62;SHOW INDEX FROM performance_schema.accounts\G*************************** 1。行***************************表:账户:账户:0 non_unique key_name seq_in_index:1 column_name:用户整理:零基数:空sub_part:空包装:零:是的index_type:哈希评论:index_comment:可见:是的*************************** 2。行***************************表:账户:账户:0 non_unique key_name seq_in_index:2 column_name:主机整理:零基数:空sub_part:空包装:零:是的index_type:哈希评论:index_comment:可见:yesmysql &#62;SHOW CREATE TABLE performance_schema.rwlock_instances\G*************************** 1. row ***************************       Table: rwlock_instancesCreate Table: CREATE TABLE `rwlock_instances` (  `NAME` varchar(128) NOT NULL,  `OBJECT_INSTANCE_BEGIN` bigint(20) unsigned NOT NULL,  `WRITE_LOCKED_BY_THREAD_ID` bigint(20) unsigned DEFAULT NULL,  `READ_LOCKED_BY_COUNT` int(10) unsigned NOT NULL,  PRIMARY KEY (`OBJECT_INSTANCE_BEGIN`),  KEY `NAME` (`NAME`),  KEY `WRITE_LOCKED_BY_THREAD_ID` (`WRITE_LOCKED_BY_THREAD_ID`)) ENGINE=PERFORMANCE_SCHEMA DEFAULT CHARSET=utf8

看到一个性能模式查询的执行计划,不论使用任何指标,用EXPLAIN

MySQL的&#62;EXPLAIN SELECT * FROM performance_schema.accountsWHERE (USER,HOST) = ('root','localhost')\G*************************** 1。行***************************编号:1 select_type:简单表:账户分区:零式:constpossible_keys:账号:账号:278 key_len编号:const常量行:1过滤:100个额外的:空

这个EXPLAIN输出指示优化器使用accounts账户包括其中的索引USER主机专栏

性能指标:他们是虚拟架构构建性能架构存储引擎不使用内存或磁盘空间。性能架构报告索引信息优化从而构建高效的执行计划。反过来,绩效架构使用优化器的信息寻找什么(例如,一个特定的键值),从而没有建立实际索引结构进行有效的查找。这种实现提供了两个重要的好处:

  • 它完全避免了表进行频繁的更新,通常所产生的维修费用。

  • 它减少了在查询执行数据检索量的早期阶段。条件索引列,性能架构有效地只返回符合查询条件的数据行。如果没有索引,性能架构将返回表中的所有行,要求优化后评估的条件对每一行产生的最终结果。

性能指标是预定义的模式并不能下降,增加,或改变。

性能模式指标类似于哈希索引。例如:

  • 他们仅用于平等的比较,使用=<=>运营商

  • 他们是无序的。如果一个查询的结果必须有具体的行排序的特点,包括ORDER BY条款.

关于哈希索引的更多信息,参见第8.3.9,比较B树和哈希索引”

8.2.5优化数据变化报表

本节说明如何加快数据变动表:INSERTUPDATE,和DELETE。传统的OLTP应用和现代Web应用程序通常做许多小的数据更改操作,其中并发是至关重要的。数据分析和报告应用程序通常运行数据变化影响多行一次操作,这里主要考虑的是I/O写入大量数据和保持最新的指标。插入和更新数据量大(在业内被称为ETL,为抽取、转换和加载),有时你使用其他的SQL语句或外部命令,模仿效应INSERTUPDATE,和DELETE声明.

8.2.5.1优化插入语句

优化插入速度,结合许多小的业务合并成一个单一的大手术。理想的情况是,你做一个连接,数据发送一次新的行,和延迟所有的索引更新和一致性检查直到最后。

插入一行是由以下因素决定所需的时间,其中的数字表示的近似比例:

  • (3)连接:

  • 发送查询服务器:(2)

  • 解析查询:(2)

  • 插入行:(1行×大小)

  • 插入指标:(指标1×号)

  • (1):关门

这没有考虑到打开的表的初始开销,这是一次为每个并发运行的查询做了。

表的大小降低指标的插入日志NB树索引,假设

你可以使用下面的方法来加快插入:

8.2.5.2优化更新报表

UPDATE语句的优化如SELECT随着写的额外开销的查询。的写入速度取决于数据被更新,更新索引的数量。不改变指标没有得到更新。

另一种方式来获得快速更新是延迟更新,然后做很多更新在一排后。执行多个更新更快比做一次如果你锁定表。

对于一个MyISAM表格使用动态行格式,更新一行较长的总长度可能分裂的行。如果你这样做的时候,它的使用是很重要的OPTIMIZE TABLE偶尔地.看到第13.7.3.4,“优化表语法”

8.2.5.3优化删除语句

需要删除一个人行的时间MyISAM表格是指标数量正比例。要删除行的越快,你可以增加密钥的缓存大小增加key_buffer_size系统变量。See第5.1.1条,“配置服务器”

从删除所有行MyISAM表,TRUNCATETABLEtbl_name速度比删除tbl_name。截断操作不安全交易;发生错误时一个在一个活跃的交易或活动表锁的过程。看到第13.1.34”truncate table语法”

8.2.6优化数据库的权限

更复杂的权限设置,更多的开销,适用于所有的SQL语句。简化了的特权GRANT语句使MySQL减少权限检查的开销时,客户端执行语句。例如,如果你不给予任何表级或列级权限,服务器并不需要检查的内容_前缀号码表columns_priv表同样,如果你在任何帐户没有资源限制,服务器不具备完成资源计数。如果你有一个非常高的语句处理负荷,考虑使用一个简化的格兰特结构减少权限检查的开销。

8.2.7其他优化技巧

本节列出了提高查询处理速度的一些其他技巧:

  • 如果你的应用程序有几个数据库请求执行相关的更新,结合报表为存储程序可以帮助性能。同样,如果你的应用程序的基础上计算的一些列的值或数据量大的单一结果,结合成一个UDF(用户定义函数计算)可以帮助性能。由此产生的快速的数据库操作就可以被其他的查询,应用重复使用,甚至不同的编程语言编写的代码。看到第23,“使用存储子程序(过程和函数)”28.4节,“MySQL”添加新的功能更多信息

  • 解决任何问题的发生与压缩ARCHIVE表格的使用OPTIMIZE TABLE。看到16.5节,“ARCHIVE存储引擎”

  • 如果可能的话,分类报告直播或为统计的,在统计报表所需的数据仅是从是从生活资料定期生成汇总表创建。

  • 如果你有数据,不符合一个行和列的表结构,你可以包和存储数据到一个BLOB专栏在这种情况下,你必须在你的应用程序打包和解包信息提供的代码,但这可能节省I/O操作读写相关的值集。

  • Web服务器,存储图像和其他二进制资产文件,用路径名称存储在数据库而不是文件本身。大多数Web服务器更好的缓存文件不是数据库的内容,所以使用文件通常更快。(虽然你必须处理备份和存储的问题,自己在这种情况下。)

  • 如果你真的需要高速,看低级的MySQL的接口。例如,通过访问MySQLInnoDBMyISAM存储引擎,你可以得到一个很大的速度增加,而使用的SQL接口。

  • 复制可以提供一些操作的性能优势。您可以分发客户端检索服务器之间复制分裂负荷。为了避免减缓大师而制作备份,你可以使用一个从属服务器进行备份。看到17章,复制

8.3优化指标

为了提高性能的最佳途径SELECT操作是在一个或多个测试,查询中的列创建索引。索引条目像指针表行,允许查询快速确定哪些行匹配的条件哪里条款,并检索这些行的列值。所有的MySQL数据类型可以被索引。

虽然很容易为每一个可能的列在查询中使用的创建一个索引,不必要浪费空间浪费的指标来确定哪些指标对MySQL的使用时间。指标也增加了插入、更新和删除操作的成本,因为每个索引必须更新。你必须找到能够实现快速的查询使用索引的优化设定正确的平衡。

8.3.1 MySQL如何使用索引

使用索引快速查找特定列值的行。如果没有索引,MySQL必须从第一行,然后通过读取整个表中找到相关的行。表面积较大,更多的成本。如果表有问题的列的索引,MySQL可以快速确定位置,寻求在数据文件中而不用看所有的数据。这比阅读每行依次快得多。

现在mysql indexes(PRIMARY KEY独特INDEX,和全文)存储在B树。例外:在空间数据类型使用R树索引;MEMORY表还支持使用散列索引InnoDB采用倒排列表全文指标

一般来说,指标的使用,如下面的讨论。以哈希索引的具体特征(如用在MEMORY表)进行了第8.3.9,比较B树和哈希索引”

MySQL使用这些运营指标:

  • 找到匹配的行WHERE条款很快

  • 消除行的思考。如果有多个指标之间选择,MySQL通常使用指数,发现行的最小的数(最选择性索引)

  • 如果表中有多个列的索引,索引的最左前缀,任何可以通过优化用于查找的行。例如,如果你有13列的索引(col1, col2, col3),你有索引搜索的能力(2)(col1, col2),和(COL1,COL2,col3)。有关更多信息,参见第8.3.6,“多列索引”

  • 检索其他表中的行时加入。MySQL可以利用索引列,如果他们被声明为相同的类型和尺寸更有效。在这样的背景下,VARCHARCHAR如果它们被声明为相同的大小是相同的。例如,VARCHAR(10)CHAR(10)都是一样的大小,但VARCHAR(10)CHAR(15)是不是

    非二进制字符串列之间的比较,两列应使用相同的字符集。例如,比较utf8柱形latin1不允许使用索引列

    不同的列的比较(比较字符串列,例如时间或数字列)可能如果值不能直接比较,无需转换防止使用指标。对于一个给定的值,如1在数字列,它可能比等于字符串列如任何数量的值“1”' 1'&#39;为&#39;,或'01.e1'。这一规则的字符串列的任何指标的使用。

  • 找到MIN()MAX()对于一个特定的索引列的值key_col。这是优化的预处理,检查你是否使用哪里key_part_N=constant在那发生之前,所有关键部件key_col在指数。在这种情况下,MySQL做为每个单一的键查找MIN()MAX()表达和取代它与一个恒定的。如果所有的表达式替换成常数,在一次查询返回。例如:

    选择最小(key_part2)、马克斯(key_part2from)tbl_name哪里key_part1=10;
  • 要排序或分组表如果排序或分组在一个可用的索引的最左前缀(例如做,ORDER BY key_part1, key_part2)。如果关键部件由desc,关键是以相反的顺序读。(或者,如果该指数下降的指标,关键是看了秩序。读)第8.2.1.14,“优化”命令第8.2.1.15,“优化”组,和第8.3.13,“降指标”

  • 在某些情况下,一个查询可以优化检索值没有咨询数据行。(一个指数,提供了一个查询所需的所有结果称为覆盖指标如果一个查询使用。)从一个表只列中所包含的一些指标,选定的值可从索引树的速度:

    SELECT key_part3 FROM tbl_name
      WHERE key_part1=1
    

指标是对小表查询不重要或大表,报表查询过程中的大部分或全部的行。当一个查询需要访问大多数行,阅读顺序是不通过索引更快。连续读取减少磁盘寻道,即使不是所有的行的查询需要。看到第8.2.1.21,避免全表扫描”详情

8.3.2主关键字优化

主键为表的列或一组,你用你最重要的查询的列。它有一个相关的指标,用于快速查询性能。查询性能得益于NOT NULL优化,因为它不包括任何无效的值。与InnoDB存储引擎的表数据的物理组织做快速查找和排序基于主键的列或列。

如果你的表是重要的,但没有明显的列或一组列作为主键,你可以创建一个单独的列自动增量值作为主键。这些独特的ID可以作为其他表中的相应行的指针,当你加入使用外键表。

8.3.3空间索引优化

MySQL允许创作SPATIAL指标不为空几何值列(见部分11.5.10,创建空间索引”)。优化器检查SRID索引列来确定哪些空间参考系统的属性(SRS)用于比较,以计算适当的SRS。(MySQL 8,优化器进行比较之前空间利用直角坐标计算指标值;如果该列包含非笛卡尔srids值这种运算的结果是未定义的。)

比较正常的工作,在每一列SPATIAL索引必须扩散限制。即列定义必须包括一个明确的SRID属性,所有列的值必须具有相同的扩散。

优化器考虑SPATIAL只有SRID限制列的索引:

  • 柱上的限制在一个直角SRID使直角包围盒的计算指标。

  • 柱上的限制在一个地理网格使地理边界框计算指标。

优化器将忽略SPATIAL在没有索引的列SRID属性(因而不扩散限制)。MySQL仍保持这样的指标,如下:

  • 他们是更新表的修改(INSERTUPDATEDELETE,等等)。更新出现虽然指数为直角,即使列可能包含混合的直角坐标系和地理价值。

  • 他们的存在只是为了向后兼容;例如,在MySQL 5.7进行转储和MySQL 8的恢复能力。因为SPATIAL上未列的索引限制的SRID优化器没有用,每个这样的栏目应该修改:

    • 验证列中的所有值都有相同的扩散。确定包含在几何柱sridscol_name,使用以下查询:

      选择不同的st_srid(col_name从)tbl_name

      如果查询返回多个行,该列包含一个混合的srids。在这种情况下,修改其内容,所有的值都有相同的扩散。

    • 定义列有明确的SRID属性

    • 重现SPATIAL指数

8.3.4外键优化

如果一个表有很多列,和你查询的列的许多不同的组合,可以有效的将不常用的数据到单独的表有几列,并与他们的主表被复制的数字ID列主表。这样,每个小表可以对其数据的快速查找主键,你可以查询只是列,使用连接操作的需要。根据数据分布、查询可能会执行I / O和占用更少的内存缓存由于相关栏目一起装盘。(以最大化性能,查询尝试读一些数据块可能从磁盘;只有几列的表可以容纳更多的行中的每个数据块。)

8.3.5列索引

指标中最常见的类型包括单柱、存储副本的值从一种数据结构,柱,允许与相应的列值的行进行快速查找。B树的数据结构,让指数迅速找到一个特定的值,值的集合,或一个范围值,对应的运营商如=&#62;之间IN,等等,在哪里条款.

指标表的最大数量和最大索引长度是指每个存储引擎。看到15章,InnoDB存储引擎,和16章,选择存储引擎。所有的存储引擎支持每台至少16项指标,共有至少256个字节的索引长度。大多数存储引擎有较高的限制。

有关列索引的更多信息,参见第13.1.14,“创建索引的语法”

前缀索引

col_name(N)在一个字符串列的索引规范的语法,你可以创建一个索引,只使用第一N列的字符。索引只是一个前缀的列值,这样可以使索引文件小得多。当你的指标BLOBTEXT柱,你必须指定索引的前缀长度。例如:

CREATE TABLE test (blob_col BLOB, INDEX(blob_col(10)));

前缀可以多达767个字节长InnoDB表使用冗余COMPACT行格式。前缀长度限制为3072字节InnoDB表使用DYNAMIC压缩的行格式。对于MyISAM表,前缀长度限制为1000字节。

笔记

前缀限制以字节为单位,而前缀长度CREATE TABLEALTER TABLE,和CREATE INDEX语句被解释为非二进制字符串类型的字符数(CHARVARCHARTEXT)和二进制字符串类型的字节数(BINARYVARBINARYBLOB)。考虑到这一点时指定前缀长度为非二进制字符串列使用多字节字符集。

关于前缀索引的更多信息,参见第13.1.14,“创建索引的语法”

全文索引

FULLTEXT指标用于全文搜索。只有InnoDBMyISAM存储引擎支持全文指标与only forCHARVARCHAR,和TEXT专栏索引总是发生在整个列和列前缀索引不支持。详情见12.9节,“全文搜索功能”

优化适用于某些种类的FULLTEXT查询单InnoDB表具有这些特征的查询是特别有效的:

  • FULLTEXT那只返回文档ID查询,或文档ID和搜索排名。

  • FULLTEXT查询排序匹配行的得分降序和应用极限条款取前N匹配的行。这个优化的申请,必须没有WHERE条款和只有一个顺序降序条款

  • FULLTEXT查询只检索计数(*)匹配搜索条件的行的值,没有额外的WHERE条款.代码哪里条款WHERE MATCH(text) AGAINST ('other_text'),没有任何&#62; 0比较操作

对于包含全文表达式的查询,MySQL对表达式执行查询的优化阶段。优化器不看全文的表达和说明,它实际上对他们在执行计划的过程中发展。

这种行为的一个含义是,EXPLAIN全文查询通常是低于非全文查询的优化阶段中出现不表达评价。

EXPLAIN全文查询可以显示选择表优化掉Extra由于匹配发生在优化柱;在这种情况下,不需要在以后的执行发生表访问。

空间索引

你可以创建空间数据类型指标。MyISAMInnoDBR树索引的空间类型的支持。其他存储引擎使用B树索引的空间类型(除ARCHIVE,不支持空间类型索引)。

在内存中的存储引擎的索引

这个MEMORY存储引擎使用搞砸指标的默认,但也支持BTREE指标

8.3.6多列索引

MySQL可以创建复合索引(即指标对多个列)。一个指标可以由16列。对于某些数据类型,你可以索引前缀的列(见第8.3.5,“列索引”

MySQL可以使用多列索引的查询,测试中所有列的索引,或查询测试只是第一列,第一两列,前三列,等等。如果您指定的列中的正确顺序索引定义中,一个单一的复合索引可以加快在同一个表中的几种查询。

多列索引可以被认为是一个已排序的数组,其中包含的行,将索引列的值创造的价值。

笔记

作为一个综合指数,你可以介绍一列是散列基于其他列中的信息。如果该列是短的,相当独特,和索引,它可能比一个快在许多列的索引。在MySQL数据库中,这是很容易使用这个额外的列:

SELECT * FROM tbl_name
  WHERE hash_col=MD5(CONCAT(val1,val2))
  AND col1=val1 AND col2=val2;

假设一个表有以下规格:

CREATE TABLE test (
    id         INT NOT NULL,
    last_name  CHAR(30) NOT NULL,
    first_name CHAR(30) NOT NULL,
    PRIMARY KEY (id),
    INDEX name (last_name,first_name)
);

这个name指数在一个指数_ last namefirst_name专栏该指标可用于查询指定值在已知范围内组合查询_ last namefirst_name价值观。它也可以用于查询指定一个_ last name价值因为柱是一种索引的最左前缀(在本节后面介绍)。因此,该name指数是用于下列查询中查找:

SELECT * FROM test WHERE last_name='Widenius';SELECT * FROM test  WHERE last_name='Widenius' AND first_name='Michael';SELECT * FROM test  WHERE last_name='Widenius'  AND (first_name='Michael' OR first_name='Monty');SELECT * FROM test  WHERE last_name='Widenius'  AND first_name >='M' AND first_name < 'N';

然而,这name指数使用下列查询中查找:

SELECT * FROM test WHERE first_name='Michael';

SELECT * FROM test
  WHERE last_name='Widenius' OR first_name='Michael';

假设你的问题如下SELECT声明:

SELECT * FROMtbl_nameWHERE col1=val1AND col2=val2

如果多个列的索引存在col1COL2,适当的排可以拿来直接。如果分开单列索引存在col1COL2,优化器尝试使用索引合并优化(见部分8.2.1.3,“索引合并优化”),或试图找到最严格的指标决定哪个指标排除更多的行,使用指数取行。

如果表中有多个列的索引,索引的最左前缀,任何可以通过优化用于查找的行。例如,如果你有13列的索引(col1, col2, col3),你有索引搜索的能力(2)(col1, col2),和(COL1,COL2,col3)

MySQL无法使用索引的列,如果不形成一个索引的最左前缀进行查找。假设你有SELECT报表显示在这里:

SELECT * FROMtbl_nameWHERE col1=val1选择*;tbl_nameWHERE col1=val1AND col2=val2选择*;tbl_nameWHERE col2=val2选择*;tbl_nameWHERE col2=val2AND col3=val3

如果一个指标存在(col1, col2, col3),只有前两个查询使用索引。三、四查询包含索引列,但不使用索引进行查找,因为(COL2)(col2, col3)是不是左边的前缀(COL1,COL2,col3)

8.3.7验证指标的使用

经常检查你的查询真的使用指标,你必须在创建表。使用EXPLAIN语句,如8.8.1节,“优化查询的解释”

8.3.8 InnoDB和MyISAM索引的统计信息收集

存储引擎收集统计表使用的优化器。统计表是基于价值的群体,其中值组是一组具有相同键的前缀值的行。优化的目的,一个重要的统计平均值组的大小。

MySQL采用平均值组的大小在以下方面:

  • 估计有可能必须阅读每一行ref访问

  • 估计部分连接会产生多少行;即是这种形式的一个操作会产生的行数:

    (...) JOIN tbl_name ON tbl_name.key = expr
    

作为一个指数增加的平均值组的大小,指数这两个目的是有用的因为每次查找增加平均行数:为优化目标的好的指标,它是最好的,每一个索引值的目标很小数量的表中的行。当一个给定索引值产生一个大的行数,指标是有用的,MySQL是不太可能使用它。

平均值组的大小是表基数相关,这是值的组数。这个SHOW INDEX声明显示一个基数的基础上的价值N/S,在那里N为表中的行数和S是平均值组的大小。这比收益表中的值组的近似数。

一个加入的基础上<=>比较运算符,无效的是不是不同于任何其他值处理:NULL <=> NULL,正如N<=>N任何其他N

然而,对于一个加入的基础上=算子,无效的不同于非—NULL价值观:expr1=expr2是不是真的当expr1expr2(或两者)是无效的。这会影响ref用于访问形式的比较tbl_name.key=expr:MySQL不会如果当前值的访问表expr无效的,因为比较不可能是真的。

=比较,不管多少无效的值在表。为优化目标,相关的价值是非的平均大小—NULL值组。然而,MySQL目前不使平均大小为收集或使用。

InnoDBMyISAM表,可以通过表格数据的采集控制innodb_stats_methodmyisam_stats_method系统变量,分别。这些变量的三个可能的值,区别如下:

  • 当变量被设置为nulls_equal,所有的无效的值被视为相同的(即,它们都形成一个单值组)。

    如果NULL值组的大小是比一般的非高多了—无效的值组的大小,该方法将平均值组的大小上。这使得指数出现优化要比真的是加入寻找非那么有用—NULL值。因此,《nulls_equal方法可能会导致优化器不使用索引ref访问时,应

  • 当变量被设置为nulls_unequal无效的价值观是不一样的。相反,每个NULL价值形成单独的一组值的大小。

    如果你有很多NULL值,该方法将平均值组规模下降。如果平均非—无效的值组规模大,计数NULL是一组大小1使优化器高估的加入,寻找非索引值的每个值—无效的值。因此,《nulls_unequal方法可能会导致优化器使用该指标ref查找时,其他方法可能会更好。

  • 当变量被设置为nulls_ignored无效的值将被忽略

如果你倾向于使用许多连接使用<=>而不是=NULL值的比较和一个不是特别无效的等于另一个。在这种情况下,nulls_equal是适当的统计方法

这个innodb_stats_method系统变量有一个全球性的价值;myisam_stats_method系统变量具有全局和会话的值。设定全球价值影响统计数据收集从相应的存储引擎的表。设置会话值影响统计仅为当前客户端连接。这意味着你可以强制表的统计是再生与给定的方法没有设置会话值影响其他客户myisam_stats_method

再生MyISAM统计表,您可以使用下列方法之一:

对于使用的一些注意事项innodb_stats_methodmyisam_stats_method

  • 你可以强制表统计数据被收集明确,如刚才所描述的。然而,MySQL也可以收集自动统计。例如,如果一个table语句执行过程中,有些语句修改表,MySQL可能会收集统计。(这可能会出现批量插入或删除,或一些ALTER TABLE报表,例如。)如果发生这种情况,统计数据是使用何种价值收集innodb_stats_methodmyisam_stats_method在有时间。因此,如果你收集的统计数据使用的一种方法,但系统变量设置为其他方法当一个表的数据自动采集后,将使用另一个方法。

  • 有没有办法告诉它的方法被用来生成一个给定的统计表。

  • 这些变量only to applyInnoDBMyISAM表其他存储引擎收集统计表只有一个方法。它通常是更接近nulls_equal方法

8.3.9比较B树和哈希索引

了解B-树和哈希数据结构可以帮助预测不同的查询执行不同的存储引擎使用这些数据结构的指标,特别是对MEMORY存储引擎,让你选择B树和哈希索引。

B树索引的特点

B-树索引可以用于柱比较表达式的使用=>>=<<=,或BETWEEN操作员。索引也可以使用。LIKE如果参数比较LIKE是一个常量字符串不以通配符。例如,下面的SELECT语句中使用的指标:

SELECT * FROMtbl_name哪里key_col像“帕特里克%;select * fromtbl_name哪里key_col像Pat _ck % %;

在第一个声明,只有行'Patrick' <= key_col < 'Patricl'被认为是。在第二句,才行'Pat' <=key_col< 'Pau'被认为是

以下SELECT声明不使用索引:

SELECT * FROMtbl_name哪里key_col像“%帕特里克%;select * fromtbl_name哪里key_col喜欢other_col

在第一个声明的LIKE价值从一个通配符。第二声明的LIKE值不是一个常数

如果你使用... LIKE '%string%'string超过3个字,MySQL的使用Turbo Boyer Moore算法初始化字符串的模式,然后使用此模式来执行搜索更迅速。

搜索使用col_name IS NULL如果使用指标col_name索引

任何指标,不能跨越所有AND水平在哪里条款不用于优化查询。换句话说,能够使用一个索引,一个前缀的索引必须在每AND群组

以下WHERE子句使用索引:

…哪里index_part1=1 ANDindex_part2=2 ANDother_column=3    /*index= 1 ORindex= 2 */... WHEREindex=1 OR A=10 ANDindex=2    /* optimized like "index_part1='hello'" */... WHEREindex_part1='hello' ANDindex_part3=5    /* Can use index onindex1但不在index2index3* /……whereindex1=1 ANDindex2=2 ORindex1=3 ANDindex3=3;

这些WHERE条款做使用索引:

    /* index_part1 is not used */
... WHERE index_part2=1 AND index_part3=2

    /*  Index is not used in both parts of the WHERE clause  */
... WHERE index=1 OR A=10

    /* No index spans all rows  */
... WHERE index_part1=1 OR index_part2=10

有时,MySQL不使用索引,即使是可用的。一种情况下,发生这种情况是当优化器估计使用索引需要MySQL访问一个非常大的比例的表中的行。(在这种情况下,一个表扫描可能会更快,因为它需要更少的寻求。)但是,如果这样的查询使用LIMIT检索部分的行索引,MySQL使用无论如何,因为它可以更快速地找到结果返回几行。

哈希索引的特点

哈希索引有所不同的特点只是讨论:

  • 他们仅用于平等的比较,使用=<=>运营商(但非常快)。他们不使用比较运算符如<找到一个值的范围。依靠这种单值查询系统称为该密钥值;使用MySQL等应用程序,尽可能使用哈希索引。

  • 优化器不能使用哈希索引加快ORDER BY运营(这种类型的索引不能用于搜索的顺序。下一项)

  • MySQL不能确定有两值之间大约有多少行(这是由范围优化器来决定使用哪个索引使用)。这可能如果改变影响某些查询MyISAMInnoDB表散列索引MEMORY

  • 只有整个键可以用来寻找一排。(与B树索引的最左前缀的关键,任何可以找到的行。)

使用索引扩展第

InnoDB自动扩展每个二级指标通过添加主键列,它。考虑这个表定义:

CREATE TABLE t1 (  i1 INT NOT NULL DEFAULT 0,  i2 INT NOT NULL DEFAULT 0,  d DATE DEFAULT NULL,  PRIMARY KEY (i1, i2),  INDEX k_d (d)) ENGINE = InnoDB;

该表定义了主键列(i1, i2)。它还定义了一个二级指标_ d k柱上(d),但内部InnoDB将这个指标并将其作为列(d, i1, i2)

优化器考虑主键列的扩展二指标在确定是否以及如何使用索引。这可能会导致更有效的查询执行计划和更好的性能。

优化器可以使用扩展的次要指标ref范围,和index_merge索引访问,松散索引扫描访问,加入和排序优化,并MIN()/MAX()优化.

下面的示例演示如何执行计划受到无论优化器使用扩展的次要指标。假设t1填充了这些行:

INSERT INTO t1 VALUES(1, 1, &#39;1998-01-01&#39;), (1, 2, &#39;1999-01-01&#39;),(1, 3, &#39;2000-01-01&#39;), (1, 4, &#39;2001-01-01&#39;),(1, 5, &#39;2002-01-01&#39;), (2, 1, &#39;1998-01-01&#39;),(2, 2, &#39;1999-01-01&#39;), (2, 3, &#39;2000-01-01&#39;),(2, 4, &#39;2001-01-01&#39;), (2, 5, &#39;2002-01-01&#39;),(3, 1, &#39;1998-01-01&#39;), (3, 2, &#39;1999-01-01&#39;),(3, 3, &#39;2000-01-01&#39;), (3, 4, &#39;2001-01-01&#39;),(3, 5, &#39;2002-01-01&#39;), (4, 1, &#39;1998-01-01&#39;),(4, 2, &#39;1999-01-01&#39;), (4, 3, &#39;2000-01-01&#39;),(4, 4, &#39;2001-01-01&#39;), (4, 5, &#39;2002-01-01&#39;),(5, 1, &#39;1998-01-01&#39;), (5, 2, &#39;1999-01-01&#39;),(5, 3, &#39;2000-01-01&#39;), (5, 4, &#39;2001-01-01&#39;),(5, 5, &#39;2002-01-01&#39;);

现在考虑这个查询:

EXPLAIN SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01'

优化器不能使用主键,在这种情况下,包括立柱(i1, i2)而查询不指。相反,优化器可以使用辅助索引k_d打开(放)(D),和执行的计划取决于扩展指标应用。

当优化器不会考虑指标的扩展,它将指数k_d因为只有(D)EXPLAIN产生这一结果的查询:

MySQL的&#62;EXPLAIN SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01'\G*************************** 1。行***************************编号:1 select_type:简单表:T1型:refpossible_keys:小学、k_d关键:k_d key_len:4编号:const行:额外5:使用;使用索引

当优化器需要索引扩展的考虑,它把k_d作为(d,I1,I2)。在这种情况下,可以使用左边的索引前缀(d, i1)为了创造一个更好的执行计划:

MySQL的&#62;EXPLAIN SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01'\G*************************** 1。行***************************编号:1 select_type:简单表:T1型:refpossible_keys:小学、k_d关键:k_d key_len:8编号:const常量行:额外1:使用索引

在这两种情况下,key表明,优化器将使用辅助索引_ d kEXPLAIN输出显示了使用扩展指数的改进:

  • key_len从4字节到8字节,表明键查询使用列Di1,不只是D

  • 这个ref值的变化constconst,const因为钥匙查找使用的关键部分,而不是一个。

  • 这个rows从5:1数减少,说明InnoDB需要检查较少的行产生的结果。

  • 这个Extra值的变化使用;使用索引Using index。这意味着排可以只使用索引读取,数据行中没有咨询栏目。

使用扩展指标的优化行为的差异也可以看到SHOW STATUS

FLUSH TABLE t1;FLUSH STATUS;SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01';SHOW STATUS LIKE 'handler_read%'

上面的语句:FLUSH TABLESFLUSH STATUS冲表缓存和清除状态计数器。

没有索引扩展,SHOW STATUS产生这一结果:

----------------------- ------- | variable_name |价值| ----------------------- ------- | handler_read_first | 0 | | handler_read_key | 1 | | handler_read_last | 0 | | handler_read_next | 5 | | handler_read_prev | 0 | | handler_read_rnd | 0 | | handler_read_rnd_next | 0 | ----------------------- -------

与索引扩展,SHOW STATUS产生这一结果的。《Handler_read_next价值从5:1下降,指示更有效的使用索引:

----------------------- ------- | variable_name |价值| ----------------------- ------- | handler_read_first | 0 | | handler_read_key | 1 | | handler_read_last | 0 | | handler_read_next | 1 | | handler_read_prev | 0 | | handler_read_rnd | 0 | | handler_read_rnd_next | 0 | ----------------------- -------

这个use_index_extensions旗的optimizer_switch系统变量控制是否允许优化器将主键列的考虑在决定如何使用InnoDB表的辅助索引。默认情况下,use_index_extensions启用。检查是否禁用索引的使用扩展将提高性能,使用此语句:

SET optimizer_switch = 'use_index_extensions=off';

由优化器使用索引扩展是对索引中的关键部件的数量通常的限制(16)和最大长度(3072字节)。

8.3.11优化器使用生成的列的索引

MySQL支持生成的列的索引。例如:

CREATE TABLE t1 (f1 INT, gc INT AS (f1 + 1) STORED, INDEX (gc));

生成的列,gc,是指表达F1 1。列也索引,优化器可以指数考虑执行计划建设中。在下面的查询,WHERE条款是指气相色谱法而优化器考虑是否在列的指数产生一个更有效的计划:

SELECT * FROM t1 WHERE gc > 9;

优化器可以使用生成的列的索引生成执行计划,甚至直接引用查询中的列名称的情况下。如果发生这种情况的WHERE顺序,或GROUP BY条款指的是一个表达式匹配一些索引生成的列的定义。下面的查询没有直接提及气相色谱法但不使用表达式相匹配的定义gc

SELECT * FROM T1在F1的9 1.;

优化器认为表达f1 + 1匹配的定义气相色谱法gc建立索引,所以它认为执行计划施工指标。你可以看到使用EXPLAIN

MySQL的&#62;EXPLAIN SELECT * FROM t1 WHERE f1 + 1 > 9\G*************************** 1。行***************************编号:1 select_type:简单表:T1分区:null类型:rangepossible_keys:GC关键:GC key_len:5编号:零排:1过滤:额外100:使用索引条件

实际上,优化器已经取代表达f1 + 1随着生成的列相匹配的表达式的名称。在重写查询可用的扩展也很明显,EXPLAIN信息显示SHOW WARNINGS

MySQL的&#62;SHOW WARNINGS\G*************************** 1。行***************************水平:注意代码:1003message:/ *选择# 1 * /选择`测试`。` T1 `。` F1 `作为` F1 `,`测试`。` T1 `。` GC `作为` GC `从`测试`。` T1 `哪里(`测试` ` T1。` ` GC ` &#62; 9)。

以下限制和条件适用于优化器使用生成的列的索引:

  • 一个查询表达式生成的列定义匹配,表达式必须是相同的,它必须有相同的结果类型。例如,如果生成的列的表达式f1 + 1,优化器将不如果查询使用识别匹配1 F1,或者如果f1 + 1(一个整数表达式)是一个字符串比较。

  • 优化应用于这些运营商:=<<=>>=BETWEEN,和IN()

    对于运营商以外的BETWEENIN(),一个操作数可以由一个匹配替换生成的列。为BETWEENIN(),只有第一个参数可以通过匹配替换生成的列,和其他的参数必须具有相同的结果类型。BETWEENIN()尚未涉及支持JSON值的比较。

  • 生成的列必须定义为一个表达式,包含至少一个函数调用或一个前项算子。表达式不能包含另一个列一个简单的参考。例如,gc INT AS (f1) STORED仅由一列引用,所以指标气相色谱法不考虑

  • 比较字符串的索引生成的列值,计算从一个函数返回一个json字符串,JSON_UNQUOTE()在列定义需要从功能价值删除多余的报价。(为一个字符串,函数结果,直接比较JSON比较器处理去除引号,但这不发生索引查找。)例如,而不是写一个列定义这样的:

    doc_name文本(json_extract(JDoc,“美元。名字))存储

    这样写:

    doc_name TEXT AS (JSON_UNQUOTE(JSON_EXTRACT(jdoc, '$.name'))) STORED
    

    后者的定义,优化器可以检测到匹配这两方面的比较:

    ... WHERE JSON_EXTRACT(jdoc, '$.name') = 'some_string' ...
    ... WHERE JSON_UNQUOTE(JSON_EXTRACT(jdoc, '$.name')) = 'some_string' ...
    

    没有JSON_UNQUOTE()在列定义中,优化器检测只为那些比较第一次比赛。

  • 如果优化器选择了错误的索引,索引提示可用于禁用它,强制优化器做出不同的选择。

B hfp无形指标

MySQL支持无形的指标;即是查询优化器使用索引。该功能适用于非主键索引(无论是明确的或隐含的)。

指标是可见的默认。控制指标能见度明确一个新的索引,使用VISIBLE看不见的关键词作为索引定义部分CREATE TABLECREATE INDEX,或ALTER TABLE

CREATE TABLE t1 (  i INT,  j INT,  k INT,  INDEX i_idx (i) INVISIBLE) ENGINE = InnoDB;CREATE INDEX j_idx ON t1 (j) INVISIBLE;ALTER TABLE t1 ADD INDEX k_idx (k) INVISIBLE;

改变现有索引的可见性,使用VISIBLE看不见的关键词与ALTER TABLE ... ALTER INDEX操作:

修改表T1改变指数i_idx无形;改变表T1改变指数i_idx可见;

对于一个指标是有形的或无形的信息可从INFORMATION_SCHEMA.STATISTICS表或SHOW INDEX输出。例如:

MySQL的&#62;SELECT INDEX_NAME, IS_VISIBLEFROM INFORMATION_SCHEMA.STATISTICSWHERE TABLE_SCHEMA = 'db1' AND TABLE_NAME = 't1';有一个是一个隐形的,可见的,可见的的。

看不见的指标可以测试除对查询性能指标的影响,没有进行破坏性的变化,必须完成的指标应该成为必需。删除并重新添加索引可以是昂贵的大表,而使其不可见和可见的速度快,到位的操作。

如果一个指数实际上是看不见的需要或查询优化器使用,有注意到没有对该表的查询效果的几种途径:

  • 发生错误的查询,包括索引提示,指的是看不见的指标。

  • 性能模式数据显示受影响的查询工作量的增加。

  • 查询有不同EXPLAIN执行计划

  • 查询出现在慢查询日志,并没有出现之前。

这个use_invisible_indexes旗的optimizer_switch系统的控制变量是否使用索引迷情无形查询执行计划为建设。if the flag is远离的(默认),优化器将忽略看不见的指标(行为作为该旗出台之前一样)。如果国旗on看不见的指标,仍然看不见,但优化器需要考虑执行计划建设。

指标能见度不影响索引维护。例如,一个指数继续更新每变化表行,和唯一索引可以防止插入复制为一列,无论是有形的或无形的指标。

主键表可能仍然没有明确是否有有一个有效的隐式主键UNIQUE指标不为空专栏在这种情况下,第一个这样的指数相同的地方约束表行明确作为主键和索引不能看不见。考虑下面的表定义:

CREATE TABLE t2 (
  i INT NOT NULL,
  j INT NOT NULL,
  UNIQUE j_idx (j)
) ENGINE = InnoDB;

该定义包括主键没有明确,但指数NOT NULL专栏J地方上的行相同的约束作为主键,不能看不见:

mysql> ALTER TABLE t2 ALTER INDEX j_idx INVISIBLE;
ERROR 3522 (HY000): A primary key index cannot be invisible.

现在假设一个明确的主键表中添加:

ALTER TABLE t2 ADD PRIMARY KEY (i);

明确的主键不能看不见。此外,独特的指标j不再作为一个隐含的主键,因此可以使看不见的:

MySQL的&#62;ALTER TABLE t2 ALTER INDEX j_idx INVISIBLE;查询行,0行受影响(0.03秒)

8.3.13降序索引

MySQL支持降序索引:DESC在索引定义不再被忽视而导致关键值存储在降序。此前,指标可按相反的顺序但在性能损失扫描。降序索引可以在向前的顺序扫描,这是更有效的。降序索引也有可能使优化器使用多列索引时最有效的扫描顺序将升为其他一些列降序顺序。

考虑下面的表的定义,它包含两列和42为升序和降序索引的列上的索引定义的各种组合柱:

CREATE TABLE t (
  c1 INT, c2 INT,
  INDEX idx1 (c1 ASC, c2 ASC),
  INDEX idx2 (c1 ASC, c2 DESC),
  INDEX idx3 (c1 DESC, c2 ASC),
  INDEX idx4 (c1 DESC, c2 DESC)
);

在四个不同的指标表定义的结果。优化器可以执行一个向前的索引扫描的每ORDER BY条款和不需要使用filesort操作:

ORDER BY c1 ASC, c2 ASC    -- optimizer can use idx1
ORDER BY c1 DESC, c2 DESC  -- optimizer can use idx4
ORDER BY c1 ASC, c2 DESC   -- optimizer can use idx2
ORDER BY c1 DESC, c2 ASC   -- optimizer can use idx3

利用下降指标是受这些条件:

  • 降序索引是唯一的支持InnoDB存储引擎,这些限制:

    • 改变缓冲不支持一次索引如果索引包含一个降序索引键列或主键包括降序索引列。

    • 这个InnoDBSQL解析器不使用降序索引。为InnoDB全文搜索,这意味着需要在指数FTS_DOC_ID该索引的表不列被定义为一个递减指数。有关更多信息,参见第15.8.2.4,“InnoDB全文索引”

  • 降序索引都支持所有的数据类型都可以提升指标。

  • 降序索引支持普通(无再生中继)和生成的列(包括VIRTUAL存储

  • DISTINCT可以使用任何含有匹配列的索引,包括下行的关键部分。

  • 有降的关键部分指标不能用于MIN()/MAX()使用聚合函数,但没有一个查询优化条款.

  • 降序索引支持BTREE但不搞砸指标。降序索引不支持FULLTEXT空间指标

    明确规定ASCdesc指示器HASH全文,和SPATIAL结果在一个错误的指标。

8.4优化数据库结构

你作为一个数据库设计者的角色,找来组织你的模式,最有效的方式表和列。当调整应用程序代码,你减少I/O,把相关的物品放在一起,并计划前,业绩保持高数据量的增加。从一个高效的数据库设计使得团队成员编写高性能的应用程序更容易,并使数据库可能随着应用的发展和承受改写。

8.4.1优化数据大小

设计你的表来减少对磁盘空间。这可能会导致巨大的改进,通过减少数据的写入量和从磁盘读取。小表通常需要较少的内存,其内容正在积极处理在执行查询。任何空间减少为较小的索引表的数据也表明,可以更快地处理。

MySQL支持许多不同的存储引擎(表类型)和行格式。对于每个表,你可以决定哪些存储和索引的使用方法。选择适当的表格式的应用程序会给你一个大的性能增益。看到15章,InnoDB存储引擎,和16章,选择存储引擎

你可以得到更好的性能表,利用这里列出的技术减少存储空间:

表列

  • 使用最有效的(最小的)可能的数据类型。MySQL有许多特殊类型,节省磁盘空间和内存。例如,如果能够得到更小的表使用较小的整数类型。MEDIUMINT往往是一个比较好的选择INT因为一个MEDIUMINT柱采用25%更少的空间。

  • 申报列为NOT NULL如果可能的话。它使SQL操作的速度更快,能够更好地利用指标消除开销测试是否每个值无效的。你也节省了存储空间,每栏一点。如果你真的需要NULL表中的值,使用它们。只是避免默认设置允许无效的在每一列的值

行格式

  • InnoDB在创建表使用动态行格式默认。使用行以外的格式DYNAMIC,配置innodb_default_row_format,或指定row_format选项中明确CREATE TABLEALTER TABLE声明

    行格式紧凑的家庭,其中包括COMPACT动态,和COMPRESSED行,减少存储空间增加一些操作CPU的使用成本。如果你的工作量是一个典型的一个有限的缓存命中率和磁盘的速度可能会更快。如果它是一个罕见的情况下,由CPU速度有限,可能会慢一些。

    行格式紧凑型家庭也优化CHAR列存储使用可变长度的字符,如utf8mb3utf8mb4。与ROW_FORMAT=REDUNDANTCHAR(N)占有N×最大字节长度的字符集。许多语言可以写主要使用单字节UTF8字符,所以固定的存储长度通常会浪费空间。行格式紧凑型家庭,InnoDB分配一个存储变量的范围NN×最大字节长度设置这些栏目通过剥离尾随空格字符。最小存储长度N字节在典型情况下帮助更新。有关更多信息,参见第15.8.1.2,“物理行结构的InnoDB表”

  • 为了最大限度地减少空间进一步压缩形式存储表数据,指定ROW_FORMAT=COMPRESSED当创建InnoDB表,或运行MyISAMPack在现有的命令MyISAM表。(InnoDB压缩表是可读写的,而MyISAM压缩表是只读的。)

  • MyISAM表,如果你没有任何可变长度列(VARCHARTEXT,或BLOB列),使用固定尺寸的记录格式。这是更快,但可能会浪费一些空间。看到第16.2.3,“MyISAM表的存储格式”。你可以暗示你想有固定长度的行,即使你已经VARCHAR的列CREATE TABLE选项ROW_FORMAT=FIXED

索引

  • 一个表的主索引应该尽可能短。这使得每一行的简单而有效的识别。为InnoDB表的主键列在每个二级指标条目复制,所以短主键可以节省相当多的空间,如果你有许多次要指标。

  • 创建唯一的指标,你需要提高查询性能。索引是很好的检索,但减慢了插入和更新操作。如果你访问一个表主要是通过搜索列的组合,创建一个单一的综合指标,而不是为每个列一个单独的索引。该指数的第一部分应该是最常用的色谱柱。如果你总是使用许多列从表中选择时,索引中的第一列应该是最多的一个副本,以获得更好的索引压缩。

  • 如果它很可能是一长串柱对人物的第一号唯一的前缀,它是更好的指标只有这个前缀,以创建一个列的左边部分指标MySQL的支持(见第13.1.14,“创建索引的语法”)。更短的索引会更快,不仅因为他们需要更少的磁盘空间,因为他们将在索引缓存中提供更多的点击,从而减少磁盘寻道。看到第5.1.1条,“配置服务器”

加入

  • 在某些情况下,可以分成21个表扫描通常。如果它是一个动态格式表,它可以使用一个较小的静态格式表可以用来找出相关行的扫描表时,这是真实的。

  • 申报列不同表中具有相同的数据类型相同的信息,加快加入基于相应的列。

  • 将列名称简单,让你可以在不同的表使用相同的名称和简化连接查询。例如,表中的命名customer,使用列名称姓名而不是customer_name。让你的名字移植到其他SQL服务器,考虑让他们短于18字符。

归一化

  • 通常情况下,尽量保持所有的数据冗余(观察什么是指在数据库理论第三范式)。而不是重复冗长的值,如姓名和地址,给他们分配唯一的ID,根据需要重复多个更小的表这些ID,并加入表中查询的JOIN子句引用ID。

  • 如果速度比磁盘空间和保持数据的多个副本的维护成本,更重要的,例如在商业智能的情况下,你对全部数据进行分析,从大的表,你可以放松的规范化规则,重复的信息或创建汇总表以获得更快的速度。

8.4.2优化MySQL数据类型

8.4.2.1优化数值数据

  • 独特的ID或其他值可以表示为字符串或数字,喜欢数字列弦柱。由于大量的数值可存储的字节数比相应的字符串,它速度快、占用内存少的转移和比较。

  • 如果您使用的是数字数据,很快在许多情况下,从数据库中获取信息(使用实时连接)比访问文本文件。数据库中的信息会被存储在一个更紧凑的格式的文本文件,所以访问需要更少的磁盘访问。你也把你的应用程序,你可以避免解析文本文件找到的行和列的边界。

8.4.2.2优化字符和字符串类型

字符和字符串的列,遵循这些指导方针:

  • 使用二进制排序顺序快速比较和排序操作,当你不需要特定的语言整理的特点。你可以使用BINARY运营商在一个特定的查询使用二进制排序规则。

  • 当比较值的不同列,声明这些列具有相同的字符集和整理,尽可能避免在运行查询字符串转换。

  • 列值小于8 kb的大小,使用二进制VARCHAR而不是斑点。这个GROUP BY顺序条款可以生成临时表和临时表可以使用这些MEMORY存储引擎如果原表不包含任何斑点专栏

  • 如果一个表包含字符串列如姓名和地址,但许多查询不找回那些列,考虑拆分字符串列为一个单独的表中,使用联接查询一个外键,必要时。当MySQL检索任何值从行,它读取一个数据块包含该行的所有列(和可能的其他相邻的行)。保持每行小,只有最常用的栏目,让更多的行放在每个数据块。这种紧凑的表减少磁盘I/O和内存使用通用查询。

  • 当你使用一个随机生成的值作为主键InnoDB表前缀与提升价值,如当前的日期和时间,如果可能的话。当连续的主要价值是物理存储彼此靠近,InnoDB可以插入和检索速度

  • 看到第8.4.2.1,优化数值数据”为什么一个数字列通常比等效的字符串列。

8.4.2.3 BLOB类型的优化

  • 当存储一个大水滴包含文本数据,首先考虑压缩。不使用这种技术时,整个表压缩InnoDBMyISAM

  • 具有多个列的表中,以减少查询不使用BLOB列存储的要求,考虑将BLOB列为一个单独的表和参考用的连接查询时所需要的。

  • 自从来检索并显示一个BLOB值的性能要求,可以从其他数据类型的不同,你可以把BLOB特定表在不同的存储设备,甚至是一个单独的数据库实例。例如,检索一个BLOB可能需要大量的磁盘顺序读,更适合于传统的硬盘驱动器要比SSD装置

  • 看到第8.4.2.2,“优化字符和字符串类型”为什麼?VARCHAR柱有时是最好一个等效的BLOB列。

  • 而不是平等对抗很长的文本字符串测试,您可以存储的哈希值的列在一个单独的列,索引列,和测试的散列值查询。(使用MD5()CRC32()函数产生的散列值。)由于哈希函数可以产生不同的输入重复的结果,还包括一个条款AND blob_column = long_string_value在查询防伪火柴;履行利益来自较小,容易扫描的散列值指数。

8.4.3优化多表

保持个人查询快速涉及到将数据在许多表格的一些技巧。当表的数量达到几千甚至几百万,处理所有这些表的开销成为一个新的性能考虑。

8.4.3.1 MySQL如何打开和关闭表

当你执行一个并发数命令,你应该看到这样的事情:

Uptime: 426 Running threads: 1 Questions: 11082
Reloads: 1 Open tables: 12

这个Open tables12值可有点令人费解,如果你只有六张桌子。

MySQL是多线程的,所以可能会有很多客户查询给定表的同时。减少在同一个表中有不同国家的多个客户端会话的问题,该表是由每个并发会话独立开。使用额外的内存,但通常会增加性能。与MyISAM表,一个额外的文件描述符是数据文件为每一个客户,有打开表的要求。(相比之下,索引文件描述符之间的所有会话。共享)

这个table_open_cachemax_connections系统变量的影响的文件的最大数量的服务器保持开放。如果你增加一个或两个这些值,你可能会碰到你的操作系统在每个打开的文件描述符的数量施加限制的过程。许多操作系统允许你增加打开文件的限制,虽然该方法从系统的广泛变化。咨询你的操作系统文档以确定是否有可能增加限制和如何做。

table_open_cache有关max_connections。例如,200的并发连接,指定至少表缓存200 *N,在那里N是最大数量的表每参加任何你所执行的查询。你还必须为临时表和文件保留一些额外的文件描述符。

确保你的操作系统可以处理打开的文件描述符的数量暗示table_open_cache设置如果table_open_cache定得太高,MySQL可能运行的文件描述符和拒绝连接,无法执行查询,并且很不可靠。

你也应该考虑这样的事实:MyISAM存储引擎需要为每一个独特的打开表的两个文件描述符。对于分区MyISAM表2文件描述符是每个分区的打开表的要求。(请注意当MyISAM打开一个分区表,它打开了这个表的每个分区,是否一个给定分区实际使用。看到MyISAM和分区的文件描述符的使用。)你可以增加文件描述符可用MySQL的使用--open-files-limit启动选项mysqld。看到第b.5.2.17,“找不到文件和类似的错误”

开桌的缓存保持在一个水平table_open_cache条目.服务器启动时autosizes缓存大小。设置的大小明确,设置table_open_cache在启动系统变量。注意,MySQL可能暂时开放更多的表比这个要执行查询。

MySQL关闭未使用的表和删除它在下列情况下表缓存:

当表缓存已满,服务器使用以下过程确定缓存项的使用:

  • 表目前没有在使用中被释放,开始与表最近最少使用。

  • 如果一个新表需要被打开,但缓存已满,没有桌子可以被释放,缓存暂时扩展是必要的。当缓存是一个暂时的扩展状态和表从一个用来闲置状态,桌上是封闭的,从缓存中释放。

MyISAM表打开每个并发访问。这意味着表需要打开两次,如果两个线程访问同一个表或者一个线程访问表两次相同的查询(例如,通过加入表本身)。每个并发开放需要在表缓存条目。任何第一次开放MyISAM表格需要两个文件描述符:一个数据文件和一个索引文件。表中的每一个额外的使用只有一个文件描述符的数据文件。索引文件描述符中的所有线程共享。

如果你是开一桌HANDLER tbl_name OPEN声明,一个专门的表格对象分配给线程。这个表对象不会被其他线程共享和不封闭,直到线程调用处理程序tbl_name关闭或线程终止。当这一切发生的时候,桌子是放在表缓存(如果缓存不全)。看到第13.2.4,“HANDLER Syntax”

你可以判断你的表缓存太小的检查mysqld状态变量Opened_tables,这表明表开启操作数从服务器开始:

MySQL的&#62;SHOW GLOBAL STATUS LIKE 'Opened_tables';变量名称和值_ ------- | | | ---------------打开表| ------- | _ 2741 | --------------- -------

如果值是非常大的或迅速增加,即使你没有发出许多FLUSH TABLES报表,增加表的缓存大小。看到第5.1.7,服务器“系统变量”,和第5.1.9,“服务器状态变量”

建立在同一个数据库多表8.4.3.2缺点

如果你有很多MyISAM表在同一数据库目录,打开,关闭,并创建操作速度慢。如果你执行SELECT在许多不同的表格报表,有一个小的开销,当表缓存已满,因为每台已被打开,另一个必须关闭。你可以通过增加数量的条目在表缓存可以减少这种开销。

在MySQL中使用8.4.4内部临时表

在某些情况下,服务器创建内部临时表而处理报表。用户没有直接的控制权,当这种情况发生时。

服务器创建临时表如下条件下:

判断一个语句需要一个临时表,使用EXPLAIN检查额外柱是否说Using temporary(见8.8.1节,“优化查询的解释”EXPLAIN不一定会说使用临时派生或物化的临时表

当服务器创建一个内部的临时表(在内存或磁盘上),它的增量Created_tmp_tables状态变量。如果服务器磁盘上创建表(开始或将内存中的表)它的增量Created_tmp_disk_tables状态变量

一些查询条件,防止内存中的临时表的使用,在这种情况下,服务器使用一个磁盘上的表而不是:

  • 存在一个BLOBTEXT柱过程中的所有表

  • 任何字符串列的最大长度大于512的存在(对于二进制字符串,字节字符的二进制字符串)在SELECT列表,如果UNIONUNION ALL使用

  • 这个SHOW COLUMNSDESCRIBE语句中使用斑点对于一些列的类型,因此临时表用于结果是磁盘上的表。

服务器不使用临时表UNION报表,满足一定的条件。相反,它保留了从临时表创建唯一的数据结构进行必要的结果列的类型转换。桌子上没有完全实例化并没有行被写入或读取它;行直接发送到客户端。其结果是减少了内存和磁盘要求,和较小的延迟第一行之前发送到客户端,因为服务器不需要等到最后一个查询语句块执行。EXPLAIN和优化器跟踪输出反映了这一策略的执行结合的结果查询块不存在因为那块对应的部分,读取临时表。

符合条件的论文AUNION评价没有一个临时表:

  • 工会UNION ALL,不联盟UNION DISTINCT

  • 没有全球ORDER BY条款.

  • 欧盟不是一个顶级的查询块{INSERT | REPLACE} ... SELECT ...声明

内部临时表的存储引擎

内部临时表可以保存在内存中处理的TempTable内存存储引擎,或存储在磁盘上的InnoDBMyISAM存储引擎

在内存内部临时表的存储引擎

这个internal_tmp_mem_storage_engine会话变量定义的存储引擎在内存内部临时表。允许值诱人的(默认的),MEMORY

这个TempTable存储引擎提供了高效的存储VARCHARVARBINARY专栏这个temptable_max_ram配置选项定义的随机存取存储器(RAM),最多可占用诱人的存储引擎,它从临时文件映射到内存的磁盘空间分配之前。默认的temptable_max_ram设置1gib。通过使用临时文件诱人的存储引擎的溢出机制在内存中的临时表是由这些规则:

  • 临时文件中定义的目录中创建tmpdir配置选项

  • 临时文件在创建后,打开立即删除,因此不在保持可见tmpdir目录的临时文件占用的空间是由操作系统打开文件而临时召开。空间再生时的临时文件是关闭的诱人的存储引擎,或是当的mysqld进程关闭

  • 数据是不动的RAM和临时文件,在内存之间或临时文件。

  • 新的数据,如果空间变得可用在由极限定义存储在RAM中temptable_max_ram。。。。。。。此外,新的数据存储在一个临时文件。

  • 如果空间可用内存在一些对于一个表的数据写入临时文件,对于剩余的表的数据存储在RAM是可能的。

这个memory/temptable/physical_ram记忆/诱人/ physical_disk性能模式的仪器是用来监测TempTable从内存和磁盘空间的分配。记忆/诱人/ physical_ram报告的数量分配的内存。memory/temptable/physical_disk报告的数量分配磁盘空间。如果physical_disk仪器介绍0以外的值,temptable_max_ram从某种意义上说是达到阈值。数据可以查询性能模式记忆汇总表等memory_summary_global_by_event_name。看到第25.11.15.10,“记忆汇总表”

当使用MEMORY在内存中的临时表的存储引擎,MySQL会自动将内存中的临时表的一个磁盘表如果它变得太大。最大尺寸为内存中的临时表是从哪一个确定的值tmp_table_sizemax_heap_table_size是小。differs from this内存显式创建表CREATE TABLE:这样的表,只有max_heap_table_size系统变量决定了大表是允许的增长并没有转化为对磁盘格式。

在磁盘内部临时表的存储引擎

这个internal_tmp_disk_storage_engine系统变量确定的存储引擎的服务器使用的磁盘内部临时表管理。允许值InnoDB(默认的),MYISAM

公用表表达式(CTE),存储引擎用于磁盘内部临时表不能MyISAM。如果internal_tmp_disk_storage_engine=MYISAM一个错误发生时,任何试图实现一个CTE使用磁盘上的临时表。

笔记

当使用internal_tmp_disk_storage_engine=INNODB,查询,生成磁盘内部临时表,超过InnoDB行或列的极限退货行尺寸太大太多的列错误.解决方法是设置internal_tmp_disk_storage_engineMyISAM

内部临时表的存储格式

当内存内部临时表的管理TempTable存储引擎,行包括varcharVARBINARY列为代表的内存单元阵列,每个单元包含一个空标志,数据长度和数据指针。列的值放在连续的顺序后的数组,在内存的一个区域,无填充。数组中的每个单元用16字节的存储。同样的存储格式,适用于诱人的存储引擎超过temptable_max_ram极限,从临时文件映射到内存的磁盘空间分配。

当内存内部临时表的管理MEMORY存储引擎,使用固定长度的行格式。varcharVARBINARY列的值填充到列的最大长度,实际上它们存储为烧焦BINARY专栏

在磁盘管理的内部临时表InnoDBMyISAM存储引擎(取决于internal_tmp_disk_storage_engine设置)。发动机内部临时表存储采用动态宽行格式。列只需要尽可能多的存储需要,从而减少磁盘I/O和空间的要求,并与磁盘上的数据表,使用固定长度列的处理时间。

当使用MEMORY存储引擎,报表可以初步创建一个内存内部临时表并将它转换为一个磁盘上的表,如果表变得太大。在这种情况下,更好的性能可能会跳过转换和创建磁盘内部临时表开始了。这个big_tables系统变量可用于强制内部临时表存储。

8.5优化InnoDB表

InnoDB是存储引擎,在可靠性和并发性是重要的生产数据库通常使用MySQL客户。InnoDB是MySQL的默认存储引擎。本节说明如何优化数据库操作InnoDB

8.5.1优化InnoDB表的存储布局

  • 一旦你的数据达到一个稳定的大小,或增长的表增加了几十或几百兆,考虑使用OPTIMIZE TABLE报表重组表和紧凑的任何浪费的空间。重组后的表需要更少的磁盘I/O执行全表扫描。这是一个简单的技术,可以提高性能,当其他技术如提高索引的使用或调整应用程序代码是不实际的。

    OPTIMIZE TABLE本表中的数据部分和重建索引。效益来自内部数据指标改进包装,减少碎片的内表空间和磁盘。效益取决于每个表中的数据。你可能会发现一些不为别人有显着的收益,或在收益减少的时间直到你下一个优化表。此操作可以慢如果索引被重建不适合进入缓冲池的桌子是大或。第一次运行后加入大量的数据表通常是远低于后运行。

  • 进入InnoDB,有长primary key(无论是单柱或多柱的长期价值,形成一个长的复合价值)浪费了大量的磁盘空间。一行的主键值是所有辅助索引记录指向同一行重复。(见第15.8.2.1,“聚集和二级指标”创建一个。)AUTO_INCREMENT如果你列作为主键主键或索引前缀长,长varchar而不是整个柱

  • 使用VARCHAR数据类型代替CHAR存储可变长度的字符串或列多无效的价值观。一CHAR(N)柱总是N字符存储数据,即使字符串短或它的价值无效的。小桌子放在缓冲池和减少磁盘I / O.

    当使用COMPACT行格式(默认InnoDB格式)和可变长度的字符集,如utf8SJISCHAR(N)柱占据空间变量的数量,但至少N字节

  • 表大,或包含重复的文字或数字的大量数据,可以考虑使用COMPRESSED行格式。更少的磁盘I/O要求把数据放入缓冲池,或执行全表扫描。在永久的决定,测量可以实现利用压缩量压缩的对比COMPACT行格式

8.5.2优化InnoDB事务管理

优化InnoDB事务处理,发现交易特征的性能开销,你的服务器的工作负载之间的理想平衡。例如,一个应用程序可能要有每秒数千次遇到性能问题,和不同的性能问题,如果它有每2-3小时。

  • 默认的MySQL设置AUTOCOMMIT=1可以在一个繁忙的数据库服务器对性能的局限性。在可行的情况下,将几个相关的数据更改操作成一个单一的交易,通过发行SET AUTOCOMMIT=0START TRANSACTION声明,随后承诺在所有的变化表

    InnoDB必须刷新日志到磁盘在每个事务提交如果事务修改的数据库。当每个变化之后的承诺(如默认autoCommit设置),I/O吞吐量的存储设备,把帽子上的潜在操作每秒数。

  • 另外,对于交易,只有一个SELECT声明,将我们自动提交有助于InnoDB认识到只读事务和优化。看到第8.5.3,“优化InnoDB只读事务”安魂曲

  • 避免进行回滚后插入,更新,或删除大量的行。如果一个大交易放缓服务器的性能,它的滚动可以使问题变得更糟,可能以几倍作为原始数据更改操作。造成数据库的过程中并没有帮助,因为回滚再次开始在服务器启动时。

    为了尽可能的减少这个问题的发生:

    • 增加的大小缓冲池这样所有的数据变化可以缓存而不是立即写入磁盘。

    • 配置innodb_change_buffering=all因此,更新和删除操作的缓冲除了插入。

    • 考虑发行COMMIT报表周期大数据改变的操作过程中,很可能打破单一的删除或更新操作较小数量的行的多个报表。

    才能一旦发生摆脱失控的回滚,增加缓冲池,回滚成为CPU绑定的,跑得快,或者杀死服务器并重启innodb_force_recovery=3,解释第15.17.2,“InnoDB恢复”

    这个问题将是罕见的默认设置innodb_change_buffering=all,它允许更新和删除操作将被缓存在内存中,使他们更快地在第一个地方表演,也快滚回来如果需要。要使用此参数设置对服务器的长期交易过程与许多插入,更新或删除。

  • 如果你能提供一些最新的承诺的交易损失如果发生崩溃时,可以设置innodb_flush_log_at_trx_commit参数为InnoDB试图刷新日志每秒一次吧,虽然不能保证冲洗。

  • 行时,修改或删除,行和相关UNDO日志身体不立即删除,甚至后立即提交事务。旧的数据保留到事务开始前或同时完成,使这些交易可以访问以前状态,修改或删除行。因此,长期运行的事务可以防止InnoDB从清洗,是由不同的交易数据的变化。

  • 修改或删除行时,在长期运行的事务,其他交易使用READ COMMITTEDREPEATABLE READ隔离级别必须做更多的工作来重建旧的数据,如果他们读到那些相同的行。

  • 当一个长期运行的事务修改一个表,从其他交易与表查询不使用的覆盖指标技法查询通常可以从一次索引检索所有结果列,而是找到相应的值从表中的数据。

    如果次级索引页被发现有PAGE_MAX_TRX_ID这是太新,或者如果在辅助索引记录的删除标记,InnoDB可能需要使用聚集索引查找记录。

8.5.3优化InnoDB只读事务

InnoDB可以避免的开销与设置事务IDTRX_ID场),被称为是只读事务。事务ID是一个唯一的需要交易可能执行写操作或锁定读SELECT ... FOR UPDATE。消除不必要的事务ID减少内部数据结构,请教每次查询或数据更改语句构造尺寸阅读视图

InnoDB当检测到只读事务:

  • 交易开始的START TRANSACTION READ ONLY声明。在这种情况下,试图对数据库进行修改(为InnoDBMyISAM,或其他类型的表)引起的误差,以及交易继续在只读状态:

    错误1792(25006):无法执行语句在只读事务。

    你还可以更改在只读事务的特定会话的临时表,或发行锁定查询他们,因为这些变化和锁的任何其他事务是不可见的。

  • 这个autocommit设置是打开的,这样的交易是保证是一个语句,和单表弥补交易是非锁定SELECT声明。that is,a选择不使用FOR UPDATE在共享模式锁条款.

  • 交易开始没有READ ONLY选项,但没有更新或陈述,明确锁定行被执行呢。直到更新或显式锁是必需的,一个事务处于只读模式。

因此,为读密集型应用,如报表生成器,您可以调整顺序InnoDB这里面查询START TRANSACTION READ ONLYCOMMIT,或打开autocommit设置运行前选择报表,或者干脆避免任何数据更改语句穿插查询。

有关START TRANSACTIONautocommit,看到第13.3.1条,“开始事务,提交和回滚语法”

笔记

交易称为自动提交,非锁定,和只读(ac-nl-ro)保持了一定的内部InnoDB数据结构,因此不上市SHOW ENGINE INNODB STATUS输出

8.5.4优化InnoDB重做日志

考虑以下优化重做日志:

  • 让你重做日志文件大,为更大缓冲池。什么时候InnoDB已写入重做日志文件,它必须写缓冲池的修改内容到磁盘中检查点。小的重做日志文件,造成许多不必要的磁盘写入。虽然历史上大的重做日志文件引起的漫长的恢复时间,恢复现在的速度快得多,你可以放心地使用大的重做日志文件。

    的大小和数量的重做日志文件配置使用innodb_log_file_sizeinnodb_log_files_in_group配置选项。有关修改一个现有的重做日志文件的配置信息,看第15.7.2,变化的数量或大小的InnoDB重做日志文件”

  • 考虑增加的大小日志缓冲区。一个大的日志缓冲区使大交易运行而不需要在事务日志写入磁盘犯罪。因此,如果你有交易,更新、插入或删除行,很多,使得日志缓冲区更大的节省了磁盘I / O的日志缓冲区大小的配置使用innodb_log_buffer_size配置选项,可以配置为dynamically在MySQL数据库。

  • 配置innodb_log_write_ahead_size配置选项来避免读写。该选项定义先写块大小为重做日志。配置innodb_log_write_ahead_size匹配的操作系统或文件系统缓存块大小。读写时,重做日志块不完全缓存的操作系统或文件系统由于不匹配之间提前写块大小为重做日志和操作系统或文件系统缓存块大小。

    有效值为innodb_log_write_ahead_size是的倍数InnoDB日志文件的块大小(2N)。最小值是InnoDB日志文件的块大小(512)。向前写时不会出现最小值是指定的。最大值是相等的innodb_page_size价值。如果你指定一个值innodb_log_write_ahead_size是大于innodb_page_size的价值,innodb_log_write_ahead_size设置截断的innodb_page_size价值

    设置innodb_log_write_ahead_size太低的值与操作系统或文件系统的高速缓存块大小的结果,在读写。设置的值太高,可能会有轻微的影响fsync对日志文件的写入性能由于被写在一块。

  • 优化旋转延迟的用户线程等待使用刷新重做。旋转延迟有助于减少延迟。在低并发的时期,减少延迟,可能没那么重要,在这期间可以减少能源消耗,避免使用旋转延迟。在高并发的时期,你可能想避免扩大处理能力对自旋延迟可用于其他工作。下面的系统变量允许设置高、低值的水印信息,定义旋转延迟的使用界限。

    • innodb_log_wait_for_flush_spin_hwm:定义最大平均日志刷新时间超过该用户线程不再自旋等待刷新重做。默认值是400微秒。

    • innodb_log_spin_cpu_abs_lwm:定义了最小的CPU使用率低于该用户线程不再自旋等待刷新重做。该值表示为和CPU核心的使用。例如,80的默认值是80%的单CPU核心。在一个多核处理器系统,一个价值150代表一个CPU核心加上第二CPU核心的一半使用百分百的用法。

    • innodb_log_spin_cpu_pct_hwm:定义的最大数量的CPU使用率,用户线程不再自旋等待刷新重做。该值表示为所有CPU核心处理能力的百分比总和。默认值是50。例如,两个CPU内核100 % 50 %的结合使用是CPU处理能力的服务器上有四个CPU核心。

      这个innodb_log_spin_cpu_pct_hwm配置选项方面处理器亲和。例如,如果一个服务器有48个内核,但mysqld过程是在只有四个CPU核心,其他44个CPU核心被忽略。

8.5.5 InnoDB表加载大量数据

这些表现提示补充快速插入通用指南第8.2.5.1,“优化INSERT语句”

  • 当将数据导入到InnoDB,关闭自动提交模式,因为它执行日志刷新到磁盘的每一个插入。你的导入操作中禁用自动提交,环绕它SET autocommitCOMMIT声明:

    SET autocommit=0;... SQL import statements ...承诺;

    这个mysqldump选项--opt创建快速导入一个转储文件InnoDB表,即使没有包装的SET autocommitCOMMIT声明.

  • 如果你有UNIQUE二键约束,可以加速表进口暂时关闭的唯一性检查进口会议期间:

    SET unique_checks=0;... SQL import statements ...SET unique_checks=1;

    对于大表,这样可以节省大量的磁盘I/O,因为InnoDB可以利用其改变缓冲区到一批写辅助索引记录。可以肯定,数据不包含重复的键。

  • 如果你有FOREIGN KEY你的表的约束,可以加速表进口关闭的进口会话持续时间外键检查:

    SET foreign_key_checks=0;... SQL import statements ...SET foreign_key_checks=1;

    对于大表,这样可以节省大量的磁盘I / O.

  • 使用多行INSERT语法来减少客户端和服务器之间的通信开销,如果需要插入多行:

    插入的热情yourtable值(1,2),(5)…………………;

    这个技巧是有效的插入任何表,不只是InnoDB

  • 在做批量插入自动递增列表,集innodb_autoinc_lock_mode2(交错)而不是1(连续)。看到第15.8.1.5,”auto_increment InnoDB”处理详情

  • 执行批量插入的时候,它是快速插入行PRIMARY KEY排序InnoDB表使用聚集索引,这使得它相对快速的顺序使用数据PRIMARY KEY。执行批量插入主键为表,完全不配合的缓冲池中尤为重要。

  • 为获得最佳性能,将数据加载到一个时InnoDB全文指数,按照这套步骤:

    1. 定义列FTS_DOC_ID在创建表时,类型bigint符号不空,与一个命名的唯一索引FTS_DOC_ID_INDEX。。。。。。。例如:

      CREATE TABLE t1 (FTS_DOC_ID BIGINT unsigned NOT NULL AUTO_INCREMENT,title varchar(255) NOT NULL DEFAULT '',text mediumtext NOT NULL,PRIMARY KEY (`FTS_DOC_ID`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE UNIQUE INDEX FTS_DOC_ID_INDEX on t1(FTS_DOC_ID);
    2. 加载数据到表

    3. 创建FULLTEXT在数据索引加载

    笔记

    当添加FTS_DOC_ID在创建表时柱,确保_ FTS _ doc ID列被更新的时候FULLTEXT索引列的更新,为_ FTS _ doc ID必须与每个单调增加INSERTUPDATE。如果你选择不加入_ FTS _ doc ID在创建表时,InnoDB为您管理文档标识,InnoDB将添加FTS_DOC_ID作为一个隐藏的柱下CREATE FULLTEXT INDEX呼叫。然而这种方法,需要一个表的重建将对性能的影响。

8.5.6 InnoDB查询优化

调查询InnoDB表,每个表的索引创建一套合适。看到第8.3.1,“MySQL如何使用索引”详情。遵循这些指南InnoDB反射

  • 因为每个InnoDB桌上有一个主键(你是否要求或不),指定每个表的主键列中所使用的最重要的时间关键查询的列。

  • 没有指定主键中的列太多或太长,因为这些列的值在每一次指数复制。当索引包含不必要的数据,I/O读取这个数据和内存缓存降低服务器的性能和可扩展性。

  • 不要创建一个单独的次要指标每一列,因为每个查询只能使用一个索引。在很少的测试栏目或栏目只有几个不同的价值指标可能不利于任何查询。如果你有相同的多表查询,试验柱的不同组合,尝试创建一个小的数目连接索引而不是大量的单柱指标。如果索引包含了所有需要的列的结果集(称为覆盖指标),查询可以避免一切的读表数据。

  • 如果一个索引的列不能包含任何NULL值,它的状态不为空当你创建表。优化器可以更好地确定哪些指标是最有效的使用一个查询,当知道每一列包含NULL价值观

  • 你可以优化单查询交易InnoDB表格、使用技术第8.5.3,“优化InnoDB只读事务”

8.5.7 InnoDB DDL操作优化

  • 在表和索引DDL操作(CREATE改变,和DROP最重要的方面InnoDB表是创建和删除次要指标是在MySQL 5.5和更高的速度更快,比以前的版本。看到第15.12.1,“在线DDL操作”详情

  • 快速创建索引很快在某些情况下,删除索引在数据加载到表,然后重新创建索引后加载数据。

  • 使用TRUNCATE TABLE空表,不删除tbl_name。外键约束可以使截断语句的工作像一个普通的DELETE声明,在这种情况下,一系列的命令一样DROP TABLECREATE TABLE可能是最快的

  • 因为主键是每个存储布局积分InnoDB表,以及改变主键的定义涉及到重组整个表,总是设置主键的一部分CREATE TABLE声明,并计划前,你不需要改变DROP主键之后

8.5.8 InnoDB磁盘I/O优化

如果你遵循数据库设计和SQL操作技术优化的最佳实践,但你的数据库仍然缓慢由于繁重的磁盘I/O活动,考虑这些磁盘I/O优化。如果Unixtop工具或Windows任务管理器显示你的工作量的CPU使用率不到七成,你的工作量可能是磁盘绑定。

  • 增加缓冲池大小

    当表中的数据缓存在InnoDB缓冲池,它可以通过查询多次访问不需要任何磁盘I/O与指定的缓冲池的大小innodb_buffer_pool_size选项这个内存区是很重要的,这是典型的建议innodb_buffer_pool_size配置为50到75%的系统内存。更多信息见,第8.12.3.1,“MySQL如何使用内存”

  • 调整冲洗方法

    在GNU / Linux和Unix的一些版本中,冲洗与UNIX磁盘文件fsync()电话(这InnoDB使用默认的)和类似的方法是出奇的慢。如果数据库的写性能是一个问题,以作为基准innodb_flush_method参数设置为o_dsync

  • 用一个空或期限I/O调度器与本地AIO在Linux

    InnoDB采用异步I/O子系统(本地AIO)上进行提前读写数据文件的页面请求Linux。这种行为是由innodb_use_native_aio配置选项,这是默认启用。与本地的AIO,类型的I/O调度程序对I/O性能的影响更大。一般来说,建议空和期限的I / O调度。进行基准测试来确定I/O调度程序提供了最好的结果,你的工作量和环境。有关更多信息,参见第15.6.7,使用异步I/O的Linux”

  • 使用直接I/O在Solaris 10 x86_64架构

    当使用InnoDB对于x86_64架构在Solaris 10存储引擎(AMD Opteron),使用直接I/OInnoDB相关的文件,以避免降解InnoDB性能为整个文件系统用于存储直接I/O的使用InnoDB相关的文件,安装它的forcedirectio看到选项;mount_ufs(1M)。(在Solaris 10 / x86_64默认使用此选项。)采用直接I/O只InnoDB文件操作而不是整个文件系统,集innodb_flush_method = O_DIRECT。这样设置,InnoDB电话directio()而不是fcntl()对I/O数据文件(不是I / O的日志文件)。

  • 数据和日志文件使用Solaris 2.6或更高版本的原始存储

    当使用InnoDB有一个大的存储引擎innodb_buffer_pool_size在任何版本的Solaris 2.6和任何平台价值(SPARC / x86/x64 / AMD64),进行基准InnoDB数据文件和在原始设备上或在一个单独的直接I/O UFS文件系统的日志文件,使用forcedirectio挂载选项如前所述。(需要安装选项而不是设置innodb_flush_method如果你想直接I / O的日志文件。)的Veritas VxFS用户应使用convosync=direct挂载选项

    不要把其他的MySQL数据文件,例如MyISAM表,在直接I/O文件系统。可执行文件或库不能被放置在一个直接I/O文件系统。

  • 使用额外的存储设备

    额外的存储设备可用于建立一个RAID配置。相关的信息,看第4,“优化磁盘I/O

    另外,InnoDB表空间的数据文件和日志文件可以放置在不同的物理磁盘。有关更多信息,请参阅以下部分:

  • 考虑非旋转存储

    非旋转存储通常提供更好的性能的随机I/O操作;和顺序I/O操作旋转存储。当分布数据和日志文件在旋转和非旋转的存储设备,认为主要是对每个文件执行I/O操作的类型。

    随机I / O-面向文件通常包括文件表烟草公司数据文件,撤销表空间文件,并临时表空间文件顺序I / O-面向文件包括InnoDB系统片文件(由于doublewrite缓冲变化的缓冲)和日志文件等二进制日志文件和重做日志文件文件

    以下配置选项设置使用非旋转存储时回顾:

    • innodb_checksum_algorithm

      这个crc32选择使用更快的校验算法,推荐用于快速存储系统。

    • innodb_flush_neighbors

      此选项优化I/O旋转存储设备。禁用它非旋转存储或混合旋转和非旋转存储。这是默认情况下禁用。

    • innodb_io_capacity

      默认设置200一般是足够的下端非旋转存储装置。高端、总线连接的设备,考虑如1000更高的设置。

    • innodb_io_capacity_max

      默认值2000是用于工作负载,使用非旋转存储。一个高端、总线连接的非旋转的存储设备,如2500更高的设置考虑。

    • innodb_log_compressed_pages

      如果重做日志是非旋转存储,考虑禁用此选项以减少测井。看到禁用压缩页面登录

    • innodb_log_file_size

      如果重做日志是非旋转存储,配置此选项来最大化缓存和写结合。

    • innodb_page_size

      考虑使用一个页面大小相匹配的内部磁盘扇区大小。早代SSD设备通常有一个4K扇区大小。一些较新的设备有一个16K的扇区大小。默认的InnoDB页面大小为16K。保持页面大小接近存储设备的块大小不变,减少数据改写磁盘。

    • binlog_row_image

      如果二进制日志是非旋转存储所有表的主键,考虑设置此选项minimal为了减少测井

    确保装饰的支持是你的操作系统启用。它通常是默认启用。

  • 提高I/O能力,避免积压

    如果由于吞吐量下降周期InnoDB检查点操作,考虑增加的价值innodb_io_capacity配置选项。较高的值导致更频繁冲洗,避免积压的工作会导致蘸吞吐量。

  • 如果冲洗不落下的I/O能力

    如果系统不落后InnoDB冲洗操作,考虑降低的价值innodb_io_capacity配置选项。通常情况下,你把这个选项的值低的现实,但不能太低,这导致吞吐量下降周期前款子弹提到。在一个典型的场景,你可以下的期权价值,你可能会看到这样的组合的输出SHOW ENGINE INNODB STATUS

    • 历史列表长度低,低于几千。

    • 插入缓冲合并近排插

    • 修改页面缓冲池始终低于innodb_max_dirty_pages_pct该缓冲池。(测量时,服务器不做批量插入;它是正常的在大容量插入修改页面的比例显著上升。)

    • Log sequence number - Last checkpoint在小于7/8或小于6/8的总规模InnoDB日志文件

  • 存储系统表空间文件IO设备上的融合

    你可以利用一个doublewrite缓冲相关的I/O优化存储系统表空间文件(ibdata文件)对Fusion-io的设备支持原子写道。在这种情况下,doublewrite缓冲(innodb_doublewrite)自动禁用,Fusion-io原子将用于所有数据文件。此功能仅在Fusion-io的硬件支持,仅仅在Fusion-io nvmfs Linux。要充分利用这一特点,innodb_flush_method设置直接_ O推荐

    笔记

    因为doublewrite缓冲的设置是全局的,doublewrite缓冲也是数据文件驻留在非融合IO硬件禁用。

  • 禁用压缩页面登录

    当使用InnoDB压缩特征,重新压缩图像网页写入重做日志文件当更改压缩数据。这种行为是由innodb_log_compressed_pages,这是默认启用,防止腐败,如果能出现一个不同版本的zlib压缩算法应用在恢复。如果你是肯定的zlib版本将不会改变,禁用innodb_log_compressed_pages为了减少工作量,修改压缩数据重做日志生成。

8.5.9优化InnoDB配置变量

不同的设置最适合的服务器,可预测的负荷,与正在满负荷运转的服务器,或者体验尖峰高活性。

因为InnoDB存储引擎执行它的许多优化自动,许多性能调优任务涉及监测以确保数据库表现良好,和改变配置选项时,性能下降。看到15.15节,“InnoDB集成MySQL性能模式”有关详细信息InnoDB性能监测

主要的配置步骤可以执行包括:

  • 控制的数据更改操作类型InnoDB缓冲区的变化数据,以避免频繁的小磁盘写入。看到第15.6.4配置变化,InnoDB缓冲”。因为默认的是缓冲区的所有数据类型的更改操作,如果你需要减少缓冲只更改此设置。

  • 将自适应哈希索引的功能和使用innodb_adaptive_hash_index选项看到第15.4.3,“自适应哈希索引”更多信息。你可能会在特别活动期间这个设置改变,那么它恢复到原来的设置。

  • 设置并发线程数的限制,InnoDB过程中,如果上下文切换是一个瓶颈。看到第15.6.5,“配置InnoDB线程并发

  • 预取控制the amount of thatInnoDB它提前读操作。当系统中有未使用的I/O能力,多读可以提高查询性能。太多的阅读可以在重负载系统导致业绩周期性下降。看到第15.6.3.5”配置,InnoDB缓冲池预取(预读)”

  • 越来越多的读或写操作后台线程的数量,如果你有一个高端的I/O子系统不是由默认值的充分利用。看到第15.6.6,“配置一些背景InnoDB I/O线程”

  • 多少I/O控制InnoDB在后台执行。看到第15.6.8,“配置InnoDB主线程I/O率”。你可能会缩减这个设置如果你观察在绩效周期下降。

  • 控制determines when that the algorithmInnoDB执行某些类型的写作背景。看到第15.6.3.6,“配置InnoDB缓冲池冲洗”。该算法对某些类型的工作负载而不是其他的,所以可能会关闭此设置如果你观察在绩效周期下降。

  • 利用多核处理器和缓存的内存配置,减少上下文切换的延迟。看到第15.6.9”配置,自旋锁投票”

  • 防止一次性操作如表扫描干扰频繁访问的数据存储在InnoDB缓冲区高速缓存。看到第15.6.3.4,“缓冲池扫描耐”

  • 调整日志文件的大小,使可靠性和故障恢复的意义。InnoDB日志文件通常是保持小避免启动时间过长之后崩溃。优化了MySQL 5.5的加速崩溃的某些步骤恢复的过程。特别是,扫描the重做日志文件应用重做日志是由于内存管理的改进算法快。如果你让你的日志文件,以避免人为小长的启动时间,你现在可以考虑增加日志文件的大小减少I/O发生因回收重做日志记录。

  • 对于配置的大小和数量的情况下InnoDB对于多字节的缓冲池,缓冲池系统尤其重要。看到第15.6.3.3,“配置多个缓冲池的实例”

  • 增加并发事务的最大数目,大大提高了可扩展性,为繁忙的数据库。看到第15.4.7,“UNDO日志”

  • 移动清洗操作(一种垃圾收集)为后台线程。看到第15.6.10,“配置InnoDB净化调度”。有效地衡量这个设定的结果,调整其他I/O相关的线程相关的配置设置的第一。

  • 减少开关InnoDB之间的并发线程,以便在一个繁忙的服务器的SQL操作不排队,形成一个交通堵塞。设置为一个值innodb_thread_concurrency选项,高达约32为高性能的现代系统。增加的价值innodb_concurrency_tickets选择,通常在5000左右。本文结合选项设置线程数的帽子,InnoDB在任何一个时间过程,并允许每个线程被换出前做大量的工作,让多少等待的线程保持低和操作可以完全没有过多的上下文切换。

8.5.10优化InnoDB有很多表系统

  • 如果你已经配置非持久性优化统计(非错误配置)InnoDB计算指数基数对于一个表,表的访问,启动后第一时间的价值,而不是在表中存储这些值。这一步可以在系统分区的数据分成许多表重要的时间。由于这种开销仅适用于初始打开表的操作,以热身为以后使用表,访问它发布了一项声明如后立即启动SELECT 1 FROM tbl_name LIMIT 1

    优化器统计信息都保存在磁盘上的默认情况下,启用了innodb_stats_persistent配置选项。关于持续优化统计信息,看第15.6.11.1”配置,持续优化统计参数

8.6优化MyISAM表

这个MyISAM存储引擎执行最低并发读取操作是数据或表锁,因为限制同时进行更新的能力。在MySQL,InnoDB是默认的存储引擎,而不是MyISAM

8.6.1 MyISAM查询优化

为加快查询的一些提示MyISAM

  • 为了帮助MySQL更好地优化查询,使用ANALYZE TABLE或运行myisamchk -分析在表后已加载数据。这个更新的值为每个索引部分表明具有相同值的行数的平均值。(独特的指标,这都是1。)MySQL使用这个来决定哪些指标选择当你加入基于恒定表达两表。你可以检查结果从表的分析利用SHOW INDEX FROM tbl_name和检查基数价值myisamchk——描述——噜显示指数分布信息

  • 排序的索引和数据按照索引,使用myisamchk --sort-index --sort-records=1(假如你想在指数排序)。这是一个很好的方式使查询更快,如果你有一个独特的指标,要根据指数依次读取所有行。你第一次排序的大表这种方式,它可能需要很长的时间。

  • 尽量避免复杂SELECT查询MyISAM表,经常更新,以避免与表锁定的发生是由于读者和作者之间的争用问题。

  • MyISAM支持并发插入:如果一个表中的数据文件中没有空闲块,你可以INSERT进入新的行在同一时间,其他线程读取表。如果是能够做这个重要的,考虑使用的方式,避免删除行的表。另一种可能性是跑OPTIMIZE TABLE整理后的表,你已经删除了很多行的。这种行为是改变设置concurrent_insert变量。你可以强迫新行被添加(因此允许并发插入),甚至在已经删除的行的表。看到第8.11.3,并发插入”

  • MyISAM表变化频繁,尽量避免可变长度列(VARCHARBLOB,和TEXT)。该表使用的动态行格式,如果它甚至包括一个可变长度列。看到16章,选择存储引擎

  • 它通常是不可分割的表分表只是因为行变大。在访问一个排,最大的性能损失是磁盘寻道需要找到这一行的第一个字节。经过查找资料,大多数现代硬盘可以读取整行的速度不够快,对于大多数应用程序。在拆分表使一个明显的区别是如果它是一个唯一的情况MyISAM使用动态行格式,你可以改变一个固定大小的表行,或者如果你经常需要扫描表但不需要的列。看到16章,选择存储引擎

  • 使用ALTER TABLE ... ORDER BY expr1, expr2, ...如果你经常检索行expr1expr2,…排序通过后的表广泛的变化使用此选项,您可以获得更高的性能。

  • 如果你经常需要计算的结果,如基于从多行信息的数量,它可能比引入一个新的表和实时更新计数器。该形式的更新是非常快的:

    UPDATE tbl_name SET count_col=count_col+1 WHERE key_col=constant;
    

    这是非常重要的当你使用MySQL存储引擎等MyISAM那只表级锁(多单作家读者)。这也提供了更好的性能,与大多数的数据库系统,因为该行锁定经理在这种情况下,少做。

  • 使用OPTIMIZE TABLE定期以避免动态格式的碎片MyISAM表看到第16.2.3,“MyISAM表的存储格式”

  • 声明一个MyISAM表与DELAY_KEY_WRITE=1表选项使索引更新快是因为他们没有刷新到磁盘,直到表关闭。缺点是,如果杀死服务器时,这种表是开放的,你必须确保表与运行服务器好--myisam-recover-options选项,或通过运行myisamchk在重新启动服务器。(然而,即使在这种情况下,你不应该用失去什么DELAY_KEY_WRITE,因为关键信息可以从数据行中产生的。)

  • 字符串自动前缀和端部空间压缩MyISAM指标。看到第13.1.14,“创建索引的语法”

  • 你可以提高性能,通过在应用程序缓存的查询或答案,然后执行插入或更新多在一起。在该操作中锁定表确保索引缓存只刷新后所有的更新。

8.6.2数据批量加载对MyISAM表

这些表现提示补充快速插入通用指南第8.2.5.1,“优化INSERT语句”

  • 对于一个MyISAM表格,你可以使用并行插入要添加行的同时,SELECT语句正在运行,如果没有删除的行在数据文件中。看到第8.11.3,并发插入”

  • 一些额外的工作,就有可能使LOAD DATA INFILE跑得更快了MyISAM表当表有很多指标。使用以下过程:

    1. 执行FLUSH TABLES声明或mysqladmin flush-tables命令

    2. 使用myisamchk --keys-used=0 -rq/path/to/db/tbl_name删除表中的所有使用的指标。

    3. 数据插入表LOAD DATA INFILE。这不更新任何指标,因此很快。

    4. 如果你只打算读表将来,使用MyISAMPack压缩。看到第16.2.3.3,压缩特性表”

    5. 重新创建索引myisamchk - RQ/path/to/db/tbl_name。这将创建在内存中的索引树写到磁盘之前,这比更新索引时要快得多LOAD DATA INFILE因为它避免了大量的磁盘寻道。由此产生的索引树也是完美的平衡。

    6. 执行FLUSH TABLES声明或mysqladmin flush-tables命令

    LOAD DATA INFILE如果执行前自动优化MyISAM表格的插入数据是空的。主要的区别自动优化和利用程序之间可以让你明确myisamchk分配更多的临时内存创建索引可能比你希望服务器分配指标再创造执行时LOAD DATA INFILE声明

    你还可以禁用或启用一个非唯一索引MyISAM通过使用以下语句而不是表myisamchk。如果你使用这些语句,你可以跳过FLUSH TABLES运营

    修改表tbl_name禁用按键;修改表tbl_name使钥匙;
  • 加快INSERT这与非事务表多个语句执行的操作,锁定你的表:

    锁定表写;插入一个值(1,23),(2,34),(4,33);插入一个值(8,26),(6,29);解锁表;

    这种好处表现因为索引缓冲区被刷新到磁盘上只有一次,毕竟INSERT语句完成。通常情况下,会有很多索引缓冲区刷新有INSERT声明.如果你能把所有行单不需要显式锁定报表INSERT

    锁也降低了多个连接测试的总时间,虽然最大等待时间个体连接可能会因为他们等待锁。假设五个客户尝试执行插入同时如下:

    • 1: 1000刀片连接

    • 连接2,3,和4做1插入

    • 5.一千插入连接

    如果你不使用锁定,连接2、3、1、5和4完成之前。如果你使用锁,连接二、三、四可能不一或之前完成,但总的时间应该是大约百分之四十更快。

    INSERTUPDATE,和DELETE操作是在MySQL的速度非常快,但是你可以通过添加任何不能超过五个连续的插入或更新锁获得更好的整体性能。如果你做了很多连续的插入,你可以做一个LOCK TABLES其次是一个UNLOCK TABLES偶尔一次(每1000排左右)允许其他线程访问表。这会导致一个好的性能增益。

    INSERT仍然是非常慢的数据加载到LOAD DATA INFILE,即使使用策略只是概述。

  • 提高性能MyISAM表,为LOAD DATA INFILEINSERT,扩大了密钥缓存增加key_buffer_size系统变量。见第5.1.1条,“配置服务器”

8.6.3优化检修表报表

REPAIR TABLEMyISAM表类似使用myisamchk修复操作,和一些相同的性能优化应用:

  • myisamchk有变量控制内存分配。你可以通过设置这些变量的提高性能,如部分4.6.4.6,“myisamchk内存使用”

  • REPAIR TABLE,同样的原则也适用,但因为修复是由服务器完成的,你设置服务器系统变量代替myisamchk变量.另外,除了设置内存分配变量,增加myisam_max_sort_file_size系统变量的增加,维修将使用更快的filesort方法避免修复缓慢的关键缓存方法的可能性。设置变量的最大文件大小为你的系统,检查后要确保有足够的可用空间,保持一份表格文件。自由空间必须是可用的文件系统中的文件包含原始表。

假设一个myisamchk表修复术是使用下面的选项来设置其内存分配变量:

--key_buffer_size=128M --myisam_sort_buffer_size=256M
--read_buffer_size=64M --write_buffer_size=64M

一些人myisamchk变量对应于服务器的系统变量:

myisamchk变量系统变量
key_buffer_sizekey_buffer_size
myisam_sort_buffer_sizemyisam_sort_buffer_size
read_buffer_sizeread_buffer_size
write_buffer_size

每个服务器的系统变量可以在运行时设置的,他们中的一些人(myisam_sort_buffer_sizeread_buffer_size)除了全球价值环节的价值。设置会话值限制的更改您的当前会话的效果,不影响其他用户。只改变一个全局变量(key_buffer_sizemyisam_max_sort_file_size)影响其他用户以及。为key_buffer_size,你必须考虑到缓冲与用户共享。例如,如果你设置myisamchkkey_buffer_size变为128MB,你可以设置相应的key_buffer_size系统变量大于(如果尚未设置较大),允许其他会话活动的关键缓冲区使用。然而,改变全球关键缓冲区大小无效的缓冲,增加磁盘I/O和放缓的其他会议。避免这个问题的另一种方法是使用一个单独的密钥缓存,给它从桌子需要修理的指标,并释放它时,修复完成。看到第8.10.2.2,“多键缓存”

基于前面的话,一个REPAIR TABLE操作可以进行如下设置类似于myisamchk命令。在这里,一个单独的128mb关键缓冲区分配和文件系统假设允许至少100GB文件大小。

SET SESSION myisam_sort_buffer_size = 256*1024*1024;
SET SESSION read_buffer_size = 64*1024*1024;
SET GLOBAL myisam_max_sort_file_size = 100*1024*1024*1024;
SET GLOBAL repair_cache.key_buffer_size = 128*1024*1024;
CACHE INDEX tbl_name IN repair_cache;
LOAD INDEX INTO CACHE tbl_name;
REPAIR TABLE tbl_name ;
SET GLOBAL repair_cache.key_buffer_size = 0;

如果你想改变一个全局变量,但想只为一个时间这么做REPAIR TABLE手术微创影响其他用户,在用户变量保存其价值和恢复之后。例如:

SET @old_myisam_sort_buffer_size = @@global.myisam_max_sort_file_size;SET GLOBAL myisam_max_sort_file_size = 100*1024*1024*1024;REPAIR TABLE tbl_name ;SET GLOBAL myisam_max_sort_file_size = @old_myisam_max_sort_file_size;

影响系统的变量REPAIR TABLE可设置在服务器启动时如果你想要的值默认生效。例如,增加这些线路的服务器my.cnf文件:

[mysqld]
myisam_sort_buffer_size=256M
key_buffer_size=1G
myisam_max_sort_file_size=100G

这些设置不包括read_buffer_size。设置read_buffer_size在全球范围内的较大值做为所有会话可以导致性能会因为许多并发会话的服务器内存过度分配。

8.7优化内存表

考虑使用MEMORY对于非关键数据的访问通常是只读的表,或很少更新。在您的应用程序相当于基准InnoDBMyISAM一个现实的工作量下表,确认任何额外的表现值得数据丢失的风险,或在应用程序启动一个基于磁盘的表复制数据的开销。

最佳性能MEMORY检查表,对每个表查询的类型,并指定要使用的类型为每个相关的指标,无论是B-树索引和哈希索引。上CREATE INDEX声明、使用条款使用B树USING HASH。B树索引快速查询,大于或小于比较通过运营商如&#62;BETWEEN。索引是唯一的快速查询,查单值通过=算子,或限制设置的值通过IN算子。为什么使用B树往往比默认的一个更好的选择USING HASH,看到第8.2.1.21,避免全表扫描”。对于不同类型的实现细节MEMORY指标,看第8.3.9,比较B树和哈希索引”

8.8了解查询执行计划

根据你的表,详细列,指标,和你的条件WHERE子句,MySQL的优化器考虑许多技术来有效地执行一个SQL查询的查询中。在一个巨大的表的查询可以在没有阅读所有的行;参与涉及几个表可以进行无行的每个组合的比较。一组操作,优化器选择执行最高效的查询称为查询执行计划,也被称为EXPLAIN计划你的目标是识别的方面EXPLAIN计划表明,查询优化,并学习SQL语法和索引技术提高的计划,如果你看到一些低效运营。

8.8.1优化查询详细解释

这个EXPLAIN声明提供了关于MySQL执行语句的信息:

借助EXPLAIN,你可以看到你应该添加索引表使语句执行利用指标行更快找到。你也可以使用EXPLAIN检查是否优化连接表的最佳顺序。给一点提示,优化器使用联接的表中指定的顺序对应的订单SELECT首先声明,声明选择straight_join而不是仅仅SELECT。。。。。。。(这第13.2.10,选择“语法”然而。),STRAIGHT_JOIN可以防止指标被使用因为它禁用半连接的转换。看到第8.2.2.1,优化子查询、派生表、视图的引用,和公用表表达式和半连接的转变”

优化痕迹有时可能提供的信息是互补的EXPLAIN。然而,优化器跟踪的格式和内容有不同版本之间的变化。详情见MySQL内核:追踪优化器

如果你有一个问题,指标不被使用当你认为他们应该跑ANALYZE TABLE更新表的统计,如基数的钥匙,可以影响优化器作出的选择。看到第13.7.3.1,“语法分析表”

笔记

EXPLAIN也可用于获取有关表中的列信息。EXPLAIN tbl_name是同义词描述tbl_name显示列tbl_name。有关更多信息,参见第13.8.1“describe语法”,和第13.7.6.5,“显示列的语法”

8.8.2解释输出格式

这个EXPLAIN声明提供了关于MySQL执行语句的信息。EXPLAIN作品SELECTDELETEINSERTREPLACE,和UPDATE声明.

EXPLAIN每个表中一行信息返回SELECT声明。它列出了表中的顺序输出,MySQL会读他们在处理语句。MySQL解决所有连接使用嵌套循环连接方法。这意味着MySQL读取第一个表中的一行,然后找到一个匹配的排在第二台、三台,等等。当所有的表都被处理,MySQL输出所选择的列和回溯通过表到表是发现其中有更匹配的行。下一行是从表中读取的过程中继续与下表。

笔记

MySQL Workbench具有直观解释的能力,提供了一个可视化表示EXPLAIN输出。看到教程:用解释来提高查询性能

解释输出列

本节描述由输出列EXPLAIN。后面的章节提供的额外信息typeExtra专栏

每个输出行EXPLAIN提供关于一个表的信息。每一行包含了价值观表8.1,“解释输出列”,和更详细的描述如下表。列名在表的第一列显示;第二列提供了等效的属性名称,在输出时显示FORMAT=JSON使用

表8.1解释输出列

专栏JSON的名字意义
idselect_id这个SELECT标识符
select_type这个SELECT类型
tabletable_name对于输出行的表
partitionspartitions匹配的分区
typeaccess_type连接类型
possible_keyspossible_keys选择可能的指标
keykey其实选择指数
key_lenkey_length所选择的密钥长度
refref列指标相比
rowsrows要检查行估计
filteredfiltered由表条件筛选行的百分比
Extra附加信息

笔记

JSON的属性是NULL是不是在JSON格式的显示解释输出

  • id(JSON的名称:select_id

    这个SELECT标识符。这是的顺序数SELECT在查询。该值可以是无效的如果行指的是其他行的结合的结果。在这种情况下,的table列中显示的值一样<unionMN&#62;表明该行指行联盟身份证件MN

  • select_type(JSON的名字:无)

    类型SELECT,可那些如下表所示。一个JSON格式解释暴露SELECT作为一个属性类型_查询块,除非是SIMPLE首要。JSON的名称(如适用)也在表中显示。

    select_type价值JSON的名字意义
    SIMPLE简约SELECT(不使用UNION或子查询)
    PRIMARY最外层的SELECT
    UNION二或后SELECT声明一个UNION
    DEPENDENT UNIONdependent真正的二或后SELECT声明一个UNION外,相关的在线查询
    UNION RESULTunion_result结果一UNION
    SUBQUERY第一SELECT在子查询
    DEPENDENT SUBQUERYdependent真正的第一SELECT在相关子查询的查询,在线外
    DERIVED派生表
    MATERIALIZEDmaterialized_from_subquery物化查询
    UNCACHEABLE SUBQUERYcacheable子查询的结果不能被缓存,必须重新评估每个排外部查询
    UNCACHEABLE UNIONcacheable第二或后选择在UNION属于一个不可缓存的查询(见不可隐藏的

    DEPENDENT通常是一个相关子查询的使用。看到第13.2.11.7,“相关子查询”

    DEPENDENT SUBQUERY评价不同不可隐藏的评价.为DEPENDENT SUBQUERY,子查询是重新评估,只有一次,每一组变量的不同值从外部语境。为不可隐藏的,子查询是重新评估每行外语境。

    当你指定FORMAT=JSON解释,输出没有单一的财产直接等同于select_type;的_查询块属性对应于一个给定的SELECT。性能相当于大多数的选择子查询类型只显示可用(例如materialized_from_subquery物化),并显示在适当的时候。没有JSON的等价物SIMPLE首要

    这个select_type对非的价值SELECT报表显示受影响的表的表类型。例如,select_typeDELETEDELETE声明.

  • table(JSON的名称:

    表的名称,指的是输出的行。这也可以是下列值之一:

    • <unionM,N>:行是指行联盟身份证件MN

    • <derivedN>:行指导出表结果与行身份证件价值N。派生表的可能结果,例如,在子查询条款.

    • <subqueryN>:行是指一个物化查询与行的结果身份证件价值N。看到第8.2.2.2,“物化”优化子查询

  • partitions(JSON的名称:分区

    分区的记录将被查询匹配。的价值NULL为已分区表。欧洲经济区第22.3.5,“获得信息的分区”

  • type(JSON的名称:access_type

    连接类型。对于不同类型的描述,参见EXPLAIN连接类型

  • possible_keys(JSON的名称:possible_keys

    这个possible_keys列指示指标,MySQL可以找到此表中的行。注意,本栏是完全独立的表的顺序显示在输出EXPLAIN。这意味着,一些在钥匙possible_keys可能无法使用在实践中生成的表的顺序。

    如果该列是NULL(或未定义JSON格式输出),有没有相关的指标。在这种情况下,你可以通过检查提高查询性能哪里条款来检查它是否指的是一些列适合索引。如果是这样的话,创造一个合适的索引和查询与检查EXPLAIN再一次.看到第13.1.8,“ALTER TABLE语法”

    看什么指标表,使用SHOW INDEX FROM tbl_name

  • key(JSON的名称:钥匙

    这个key列指示的关键(指数),MySQL实际上决定使用。如果MySQL决定使用其中的possible_keys索引查找行,指标列为核心价值。

    这是可能的,key将名称的索引是不存在的possible_keys价值。这可能没有发生possible_keys指标适用于查找行,但所有列的查询选择其它索引列。这是命名的指数覆盖选定的列,所以虽然它不是用来确定哪些行检索,索引扫描是更有效的比数据行扫描。

    InnoDB,辅助索引可能覆盖选定的列即使查询选择主键因为InnoDB商店的主键值与各次指数。如果key无效的没有发现使用的索引,MySQL查询的执行效率更高。

    强制MySQL使用或忽略索引列在possible_keys柱,使用力量指数USE INDEX,或忽略指数在你的查询。看到第8.9.4,”指标提示”

    MyISAM表,运行ANALYZE TABLE有助于优化选择更好的指标。为MyISAM桌子,myisamchk -分析不一样的。看到第13.7.3.1,“语法分析表”,和7.6节,“MyISAM表的维护和故障恢复”

  • key_len(JSON的名称:key_length

    这个key_len列指示密钥的长度,使用MySQL的决定。价值该_懒惰使您能够确定有多少部分关键的MySQL多部分的实际使用。如果key柱说无效的,的len_len柱也说无效的

    由于关键的存储格式、密钥长度是一个更大的一个栏目,可以NULL比一个不为空专栏

  • ref(JSON的名称:裁判

    这个ref列显示哪些列或常数进行比较的指标中的命名钥匙列选择与表中的行

    如果该值为func,使用的值是一些函数的结果。看到它的功能,使用SHOW WARNINGS以下EXPLAIN看扩展EXPLAIN输出。功能实际上可能是操作者如算术运算符。

  • rows(JSON的名称:

    这个rows列指示行MySQL数认为它必须检查执行查询。

    InnoDB表,这个数字只是一个估计,并不能总是精确的。

  • filtered(JSON的名称:过滤

    这个filtered列指示估计百分比的表行,将由表条件过滤。最大值是100,这意味着没有过滤的行发生。减少100值表明越来越多的过滤。显示行的数目估计和检验rows×过滤显示的行,将下列表格加入数。例如,如果rows1000,过滤is 50.00 (50%), the number of rows to be joined with the following table is 1000 × 50% = 500.

  • Extra(JSON的名字:无)

    此列包含关于MySQL如何解决查询更多信息。对不同的价值观的描述,参见EXPLAIN额外的信息

    有没有一个JSON属性对应Extra柱;然而,值可以在柱发生暴露作为JSON属性,或者该文本消息财产

解释的连接类型

这个typeEXPLAIN输出描述表的连接。JSON格式化输出,这些被发现的价值access_type财产下面的列表描述了连接类型,下令从最好到最坏的类型:

  • system

    The table has only one row (= system table). This is a special case of theconst连接类型

  • const

    表中最多有一个匹配行,这是在查询开始阅读。因为只有一行,从该行该列的值是由优化器其余常数。const表很快因为他们只读取一次。

    const是当你比较一个所有部件主键UNIQUE恒值指数。在下面的查询,tbl_name可以作为一个const

    SELECT * FROMtbl_name哪里primary_key=1;SELECT * FROMtbl_name哪里primary_key_part1=1 ANDprimary_key_part2=2;
  • eq_ref

    一行行读这个表的每个组合从上表。比其他的systemconst类型,这可能是最好的连接类型。它是用来当一个索引的所有部分都使用的连接和索引是主键UNIQUE NOT NULL指数

    eq_ref可用于索引的列进行比较=算子。比较值可以是常量或表达式,使用表,表中读取列前。在下面的例子中,MySQL可以使用eq_ref加入过程ref_table

    SELECT * FROMref_tableother_table哪里ref_tablekey_column=other_tablecolumn选择*;ref_tableother_table哪里ref_tablekey_column_part1=other_tablecolumnref_tablekey_column_part2=1;
  • ref

    所有的行匹配索引值的读取该表行的每个组合从上表。ref如果是用于连接只使用一个最左前缀的关键或如果钥匙不主键UNIQUE指数(换句话说,如果加入不能选择基于核心价值的单排)。如果关键是用来比赛只有几行,这是一个很好的连接类型。

    ref可用于索引的列进行比较=<=>算子。在下面的例子中,MySQL可以使用ref加入过程ref_table

    SELECT * FROMref_table哪里key_column=expr选择*;ref_tableother_table哪里ref_tablekey_column=other_tablecolumn选择*;ref_tableother_table哪里ref_tablekey_column_part1=other_tablecolumnref_tablekey_column_part2=1;
  • fulltext

    连接是通过使用FULLTEXT指数

  • ref_or_null

    这种连接类型是ref,但加上MySQL做为行,包含一个额外的搜索无效的价值观。此连接类型的优化是最常用的解决子查询。在下面的例子中,MySQL可以使用ref_or_null加入过程ref_table

    SELECT * FROMref_table哪里key_column=exprkey_column是空的;

    看到第8.2.1.13,“空”的优化

  • index_merge

    此连接类型表明索引合并优化方法。在这种情况下,的key在输出行的列包含一系列指标,并该_懒惰包含一系列的指标最关键零部件采用。有关更多信息,参见部分8.2.1.3,“索引合并优化”

  • unique_subquery

    这种类型的替代eq_ref对于一些进入下列形式:

    value IN (SELECT primary_key FROM single_table WHERE some_expr)
    

    unique_subquery只是一个索引查找函数代替子查询完全更好的效率。

  • index_subquery

    这种连接类型是相似的unique_subquery。它replaces进入子查询,但它工作在以下形式:非唯一索引:

    value IN (SELECT key_column FROM single_table WHERE some_expr)
    
  • range

    只检索,在一定范围内的行,使用索引选择行。这个key在输出行列指示使用索引。这个该_懒惰集装箱中的最长的部分是曾经使用的。的ref无效的对于这类

    range可当一个键列进行比较,使用任何的一个常数=<>>>=<<=IS NULL<=>BETWEENLIKE,或IN()运营商:

    SELECT * FROMtbl_name哪里key_column= 10;SELECT * FROMtbl_name哪里key_column之间的10和20;select * fromtbl_name哪里key_column在(30);选择*tbl_name哪里key_part1= 10 ANDkey_part2(10,20,30);
  • index

    这个index连接类型是一样的ALL,除了那树索引扫描。这是两种方式:

    • 如果指数是一个覆盖索引的查询,可以用来满足表所需的所有数据,只有树索引扫描。在这种情况下,的Extra柱说使用索引。一个唯一索引扫描通常比ALL因为索引通常尺寸小于表数据。

    • 全表扫描是利用索引查找索引顺序读取数据行进行。Uses index没有出现在额外专栏

    MySQL可以使用此连接类型的查询时,使用的是一个单一的指数部分只列。

  • ALL

    全表扫描了行的每个组合从上表。如果表是第一个表没有标明这通常是不好的const通常,和非常在所有其他情况下坏。通常情况下,你可以避免ALL通过添加索引,使基于恒定值或列值,从前面的表的表行检索。

解释的额外信息

这个ExtraEXPLAIN输出包含MySQL如何解决查询更多信息。下面的列表说明了可以出现在这列的值。每个项目还表明JSON格式的输出,性能表现额外价值。对于这些,有一个特定的属性。其他显示的文本message财产

如果你想使你的查询速度尽可能快,看出来的Extra列值使用filesortUsing temporary,或者,在JSON格式解释输出为using_filesortusing_temporary_table性质相同true

  • const row not found(JSON属性:const_row_not_found

    一个查询等SELECT ... FROM tbl_name,桌子是空的

  • Deleting all rows(JSON属性:消息

    DELETE,一些存储引擎(如MyISAM)支持的处理方法,去除一个简单而快速的方式表的所有行。这额外值,如果引擎使用此优化显示。

  • Distinct(JSON属性:不同的

    MySQL是寻找不同的值,所以它停止寻找当前行的组合更行后,发现第一个匹配的行。

  • FirstMatch(tbl_name)(JSON属性:first_match

    半连接firstmatch加入快捷策略用于tbl_name

  • Full scan on NULL key(JSON属性:消息

    出现这种情况的查询优化回退策略优化程序无法使用索引查找访问方法。

  • Impossible HAVING(JSON属性:消息

    这个HAVING条款总是虚假和不能选择任何行。

  • Impossible WHERE(JSON属性:消息

    这个WHERE条款总是虚假和不能选择任何行。

  • Impossible WHERE noticed after reading const tables(JSON属性:消息

    MySQL读了const(和system)表和注意哪里条款始终是假的

  • LooseScan(m..n)(JSON属性:消息

    半连接loosescan策略应用。mn关键零件号

  • No matching min/max row(JSON属性:消息

    没有行满足查询条件等SELECT MIN(...) FROM ... WHERE condition

  • no matching row in const table(JSON属性:消息

    一个连接查询,有一张空桌子或没有行满足独特的指数情况表。

  • No matching rows after partition pruning(JSON属性:消息

    DELETEUPDATE,优化器没有发现删除或更新后的分区修剪。它在意义上是相似的不可能在那里SELECT声明.

  • No tables used(JSON属性:消息

    查询没有FROM条款,或有从双条款.

    INSERTREPLACE声明,EXPLAIN显示此值时没有SELECT部分。例如,它的出现为解释插入T值(10)因为这相当于EXPLAIN INSERT INTO t SELECT 10 FROM DUAL

  • Not exists(JSON属性:消息

    MySQL也可以做LEFT JOIN优化的查询和不检查更多的行表中的一行一行组合后发现匹配左连接标准.这里是查询的类型,可以优化这种方式的一个例子:

    SELECT * FROM t1 LEFT JOIN t2 ON t1.id=t2.id
      WHERE t2.id IS NULL;
    

    假设t2.id被定义为不为空。在这种情况下,MySQL扫描t1看了一排排T2使用价值t1.id。如果MySQL找到一个匹配的行T2,它知道t2.id不可无效的,而不通过扫描行的休息t2具有相同身份证件价值。换句话说,中的每一行t1,MySQL需要做的只有一个单一的查找T2实际上,不管有多少行匹配t2

  • Plan isn't ready yet(JSON属性:无)

    这个值是EXPLAIN FOR CONNECTION当优化器没有完成创建表的命名连接执行的执行计划。如果执行计划输出包含多行,任何或所有这些能有这额外价值,取决于在确定执行计划的优化过程。

  • Range checked for each record (index map: N)(JSON属性:消息

    MySQL没有发现良好的指标使用,但发现一些指标可以用后从前面表列的值是已知的。每行的组合在前面的表,MySQL检查是否可能使用rangeindex_merge检索行的访问方法。这是不是很快,但比没有在所有的指标执行联接更快。适用标准中所描述的第8.2.1.2”范围,优化”,和部分8.2.1.3,“索引合并优化”,除上述表中的所有列的值是已知的,被认为是常数。

    索引是从1开始计数,以相同的顺序显示SHOW INDEXfor the table。the index map值N是一位掩码值,指示哪些指标是候选人。例如,一个价值0x19(二11001)意味着索引1, 4和5将被视为。

  • Recursive(JSON属性:递归

    这表明该行适用于递归SELECT一个递归公用表表达式的一部分。看到第13.2.13,“语法(公用表表达式)”

  • Scanned N databases(JSON属性:消息

    这表明许多目录扫描服务器执行查询时的处理INFORMATION_SCHEMA表中所描述的8.2.3章节,“优化information_schema查询”。价值N可以是0, 1,或全部

  • Select tables optimized away(JSON属性:消息

    优化器确定1),最多一行应该退还,2),产生这一排,一个确定性的行集必须读。当排读可以在优化阶段阅读(例如,通过读取索引行),不需要在查询执行过程中读取任何表。

    第一个条件是满足查询时隐式分组(包含聚合函数但没有GROUP BY条款)。第二个条件被满足时,一行进行查找的每个索引的使用。数量指标读决定读取的行数。

    考虑下面的隐式分组查询:

    SELECT MIN(c1), MIN(c2) FROM t1;
    

    假设MIN(c1)可以通过阅读和检索的索引行min(C2)可以通过从不同的指标中读取一行检索。就是说,每一列c1C2,存在索引的列是索引的第一列。在这种情况下,一行返回,通过阅读两确定性产生的行。

    Extra价值如果不读行不确定性的发生。考虑此查询:

    SELECT MIN(c2) FROM t1 WHERE c1 <= 10;

    假设(c1, c2)是一个覆盖指数。使用这个指标,所有行c1 <= 10必须经过扫描找到最小c2价值。通过对比,认为该查询:

    SELECT MIN(c2) FROM t1 WHERE c1 = 10;

    在这种情况下,第一个索引列c1 = 10包含最小C2价值。只有一行必须阅读产生返回的行。

    存储引擎,保持精确的行计数表(如MyISAM,但不InnoDB),这Extra价值可能会发生的计数(*)查询的WHERE条款缺失或总是真的没有条款.(这是一个隐含的分组查询,存储引擎的影响是否有确定的行数可以读。一个实例)

  • Skip_open_tableopen_frm_onlyOpen_full_table(JSON属性:消息

    这些值表示打开文件的优化,适用于查询INFORMATION_SCHEMA

    • Skip_open_table:表文件,不需要打开。该信息已经可以从数据字典。

    • Open_frm_only:只需要读取数据字典表的信息。

    • Open_full_table:未经优化的信息查找。表的信息必须从数据字典和读表文件的读取。

  • Start temporary端临时(JSON属性:message

    这表明,半临时表的使用weedout加入复制策略。

  • unique row not found(JSON属性:消息

    一个查询等SELECT ... FROM tbl_name不满足条件的行为独特指数或PRIMARY KEY在桌子上

  • Using filesort(JSON属性:using_filesort

    MySQL必须做额外的传球找到了如何检索顺序排。排序完成通过所有行根据连接类型和存储排序关键字和指针的行匹配的行的所有WHERE条款.钥匙然后进行排序和排的排列顺序检索。看到第8.2.1.14,“优化”命令

  • Using index(JSON属性:using_index

    的列信息检索表中的索引树只使用信息而不需额外的寻求阅读的实际行。这种策略可以用来查询时使用的是一个单一的指数部分只列。

    InnoDB有一个用户定义聚集索引表,索引时都可以使用使用索引缺席Extra专栏这种情况如果类型index钥匙PRIMARY

  • Using index condition(JSON属性:使用标准索引

    通过访问索引表的元组和测试,首先要确定是否读全表行读取。这样,指数的信息是用来延迟(下推)阅读全表的行,除非它是必要的。看到第8.2.1.5,“指标条件下推优化”

  • Using index for group-by(JSON属性:using_index_for_group_by

    类似于Using index表访问方法,利用指数组发现表明MySQL索引,可以用来检索所有列的GROUP BY不同的没有任何额外的磁盘访问的实际表查询。此外,该指数是用以最有效的方式使每一组中,只有少数的索引是读。详情见第8.2.1.15,“优化”组

  • Using index for skip scan(JSON属性:using_index_for_skip_scan

    表明跳跃扫描访问方法。看到跳跃扫描范围的访问方法

  • Using join buffer (Block Nested Loop)使用连接缓冲(批量密钥访问)(JSON属性:using_join_buffer

    从早期的连接表阅读部分将加入缓冲液,然后行用于从缓冲与电流表进行连接。(Block Nested Loop)表明使用该块嵌套循环算法(批量密钥访问)表示使用批量密钥访问算法。那就是,钥匙从桌上的上一行EXPLAIN将输出缓冲,和匹配的行会牵强在批次的线表使用连接缓冲出现.

    JSON格式化输出值using_join_buffer要么是一个环算法Batched Key Access

  • Using MRR(JSON属性:消息

    表阅读使用多阅读范围的优化策略。看到第8.2.1.10,“多阅读范围优化”

  • Using sort_union(...)使用UNION(…)Using intersect(...)(JSON属性:消息

    这表明特定的算法如何合并的索引扫描index_merge连接类型。看到部分8.2.1.3,“索引合并优化”

  • Using temporary(JSON属性:using_temporary_table

    解决查询,MySQL需要创建一个临时表来保存结果。如果查询包含GROUP BY顺序条款清单列不同

  • Using where(JSON属性:_附加条件

    WHERE子句用于限制哪些行与下表或发送到客户端。除非你想卖或检查表中所有的行,你可能在你查询一些错误如果额外价值是不Using where和表连接类型ALLindex

    Using where没有直接对应的JSON格式的输出;_附加条件属性包含任何WHERE条件下的应用

  • Using where with pushed condition(JSON属性:消息

    本产品适用于NDB只有。这意味着MySQL集群使用条件下推优化提高非索引列和一个常数之间的直接比较的效率。在这种情况下,条件是推下对集群节点的数据和评估所有的数据节点同时。这消除了需要在网络上发送不匹配的行,可以加快查询的5倍到10倍的情况下,条件下推可以但不使用。有关更多信息,参见第8.2.1.4,“发动机状态下推优化”

  • Zero limit(JSON属性:消息

    查询了LIMIT 0条款和不能选择任何行。

解释输出的解释

你可以通过在产品的价值得到一个很好的迹象,一个连接是多么的好rows列的EXPLAIN输出。这应该告诉你大约多少行MySQL必须检查执行查询。如果你限制查询的max_join_size系统变量,该行的产品也被用于确定多个表SELECT报表执行和终止。看到第5.1.1条,“配置服务器”

下面的示例显示了如何多表连接可以逐步根据提供的信息优化EXPLAIN

假设你有SELECT声明在这里和你打算检查它使用EXPLAIN

EXPLAIN SELECT tt.TicketNumber, tt.TimeIn,               tt.ProjectReference, tt.EstimatedShipDate,               tt.ActualShipDate, tt.ClientID,               tt.ServiceCodes, tt.RepetitiveID,               tt.CurrentProcess, tt.CurrentDPPerson,               tt.RecordVolume, tt.DPPrinted, et.COUNTRY,               et_1.COUNTRY, do.CUSTNAME        FROM tt, et, et AS et_1, do        WHERE tt.SubmitTime IS NULL          AND tt.ActualPC = et.EMPLOYID          AND tt.AssignedPC = et_1.EMPLOYID          AND tt.ClientID = do.CUSTNMBR;

在这个例子中,做出如下假设:

  • 列相比已声明如下

    专栏数据类型
    ttActualPCCHAR(10)
    ttAssignedPCCHAR(10)
    ttClientIDCHAR(10)
    etEMPLOYIDCHAR(15)
    doCUSTNMBRCHAR(15)
  • 表有以下指标

    指数
    ttActualPC
    ttAssignedPC
    ttClientID
    etEMPLOYID(主键)
    doCUSTNMBR(主键)
  • 这个tt.ActualPC值的分布是不均匀的

最初,之前已经进行了优化,其EXPLAIN语句产生以下信息:

桌上型possible_keys关键key_len参考行提取所有主要零零零74do所有原零空2135et_1所有原零零零74tt所有assignedpc,零零零3872 clientId,actualpc范围检查每个记录(指数图:0x23)

因为typeALLfor each table, this output indicates that MySQL is generating a Cartesian product of all the tables; that is, every combination of rows. This takes quite a long time, because the product of the number of rows in each table must be examined. For the case at hand, this product is 74 × 2135 × 74 × 3872 = 45,268,558,720 rows. If the tables were bigger, you can only imagine how long it would take.

一个问题是,MySQL可以利用索引列,如果他们被声明为相同的类型和尺寸更有效。在这样的背景下,VARCHARCHAR如果它们被声明为相同的大小是相同的。tt.actualpc声明为CHAR(10)et.employidCHAR(15),所以有一个长度不匹配。

固定柱长度之间的这个差距,使用ALTER TABLE延长actualpc从10字至15字:

mysql> ALTER TABLE tt MODIFY ActualPC VARCHAR(15);

现在tt.ActualPCet.employid都是VARCHAR(15)。执行EXPLAIN声明再次产生这样的结果:

桌上型possible_keys关键key_len参考行extratt所有assignedpc,零零零3872使用clientId,哪里actualpcdo所有原零零零2135范围检查每个记录(指数图:0x1)et_1所有原零零零74范围检查每个记录(指数图:0x1)等eq_ref小学15 tt.actualpc 1

这是不完美的,但更好的产品:rows价值是由74因素少。这个版本在几秒钟之内执行。

二变更可以消除对列的长度不匹配tt.AssignedPC = et_1.EMPLOYIDtt.ClientID = do.CUSTNMBR比较:

mysql> ALTER TABLE tt MODIFY AssignedPC VARCHAR(15),
                      MODIFY ClientID   VARCHAR(15);

之后的修改,EXPLAIN这里显示的输出产生:

桌上型possible_keys关键key_len参考行提取所有主要零零零74tt REF assignedpc,actualpc 15 et.employid 52使用clientId,哪里actualpcet_1 eq_ref小学15 tt.assignedpc 1do eq_ref小学15 tt.clientid 1

在这一点上,查询优化,几乎尽可能。剩下的问题是,默认情况下,MySQL的假定值在tt.ActualPC柱是均匀分布的,而不是为个案TT表幸运的是,很容易告诉MySQL进行密钥分配:

mysql> ANALYZE TABLE tt;

与其他索引信息,加入完美EXPLAIN产生这一结果:

桌上型possible_keys关键key_len参考行extratt所有assignedpc零零零3872使用clientId,哪里actualpcet eq_ref小学15 tt.actualpc 1et_1 eq_ref小学15 tt.assignedpc 1do eq_ref小学15 tt.clientid 1

这个rows列在输出EXPLAIN是一个受过教育的猜测从MySQL的连接优化。检查数据是否真的比较与该查询返回的行的实际数量的产品。如果数字是完全不同的,你可能会以获得更好的性能STRAIGHT_JOIN在你的SELECT声明并试图列出表按不同的顺序的条款。(然而,STRAIGHT_JOIN可以防止指标被使用因为它禁用半连接的转换。看到第8.2.2.1,优化子查询、派生表、视图的引用,和公用表表达式和半连接的转变”。)

有可能在某些情况下,执行语句修改数据时EXPLAIN SELECT使用子查询;有关更多信息,参见第13.2.11.8,“派生表”

8.8.3扩展解释输出格式

这个EXPLAIN语句产生额外的(扩展),不是部分信息EXPLAIN输出也可以通过发布一个视SHOW WARNINGS声明如下EXPLAIN。在MySQL 8.0.12,扩展信息是可用的SELECTDELETEINSERTREPLACE,和UPDATE声明.之前8.0.12,扩展信息只提供给SELECT声明.

这个Message价值SHOW WARNINGS输出显示优化器如何限定的表名和列名的SELECT声明,什么SELECT像重写和优化规则的应用后,可能还有其他笔记优化过程。

扩展信息显示与SHOW WARNINGS声明如下EXPLAIN是只为SELECT声明.SHOW WARNINGS显示其他解释的语句的结果为空(DELETEINSERTREPLACE,和UPDATE

这里是扩展的一个例子EXPLAIN输出:

MySQL的&#62;EXPLAINSELECT t1.a, t1.a IN (SELECT t2.a FROM t2) FROM t1\G*************************** 1。行*************************** ID:1 select_type:主表:T1型:indexpossible_keys:空键:主要key_len:四号:空的行数:4过滤:壹佰额外:使用索引*************************** 2。行*************************** ID:2 select_type:子查询表:T2型:indexpossible_keys:关键:一key_len:五号:空的行数:3过滤:壹佰额外:在使用指数排,1警告(0.001秒)MySQL &#62;SHOW WARNINGS\G*************************** 1. row ***************************  Level: Note   Code: 1003Message: /* select#1 */ select `test`.`t1`.`a` AS `a`,         <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in         ( <materialize> (/* select#2 */ select `test`.`t2`.`a`         from `test`.`t2` where 1 having 1 ),         <primary_index_lookup>(`test`.`t1`.`a` in         <temporary table> on <auto_key>         where ((`test`.`t1`.`a` = `materialized-subquery`.`a`))))) AS `t1.a         IN (SELECT t2.a FROM t2)` from `test`.`t1`1 row in set (0.00 sec)

因为显示的声明SHOW WARNINGS可能包含特殊标记提供了查询重写和优化操作的信息,声明不一定是有效的SQL和不打算执行。输出也可能包括行消息值,提供额外的非SQL注释关于优化器所采取的行动。

下面的列表描述了特殊的标记,可以出现在扩展输出显示SHOW WARNINGS

  • <auto_key>

    一个自动生成的密钥对临时表。

  • <cache>(expr)

    表达(如标量子查询)是执行一次,所得的值保存在存储器中供以后使用。对于由多个值的结果,一个临时表可以创建,你会看到<temporary table>相反

  • <exists>(query fragment)

    子查询谓词转换为EXISTS谓词和子查询转换,它可以与一起使用存在谓语.

  • <in_optimizer>(query fragment)

    这是没有意义的内部优化对象的用户。

  • <index_lookup>(query fragment)

    查询片段使用索引查找到符合条件的行的处理。

  • <if>(condition, expr1, expr2)

    如果条件为真,评价expr1,否则expr2

  • <is_not_null_test>(expr)

    测试验证表达式不评价NULL

  • <materialize>(query fragment)

    使用子查询的实现

  • `materialized-subquery`.col_name

    引用列col_name在一个内部临时表实举行的结果评估查询。

  • <primary_index_lookup>(query fragment)

    查询片段使用主键查找,找到符合条件的行的处理。

  • <ref_null_helper>(expr)

    这是没有意义的内部优化对象的用户。

  • /* select#N */ select_stmt

    这个SELECT是与非的行扩展EXPLAIN输出有一个身份证件价值N

  • outer_tables semi join (inner_tables)

    半连接操作inner_tables表明没有掏出表。看到第8.2.2.1,优化子查询、派生表、视图的引用,和公用表表达式和半连接的转变”

  • <temporary table>

    这是一个内部临时表创建缓存中间结果。

当一些表是constsystem型,涉及从这些表列的表达式求值的算法早不是显示的语句的一部分。然而,随着FORMAT=JSON,一些const表的访问显示为ref访问使用常量的值

8.8.4获取执行计划信息为命名的连接

获得一个解释的语句在一个指定的连接执行的执行计划,使用这条语句:

EXPLAIN [options] FOR CONNECTION connection_id;

EXPLAIN FOR CONNECTION返回EXPLAIN这是目前被用来在一个给定的连接执行查询信息。由于更改数据(和统计数据支持)可以从运行产生不同的结果EXPLAIN在等效查询文本。这种行为差异可以诊断更多的瞬态性能问题是有用的。例如,如果你正在运行一个语句一次,要很长时间才能完成,使用EXPLAIN FOR CONNECTION在另一个会话可能会产生延迟的原因有用的信息。

connection_id是连接标识符,从information_schemaPROCESSLIST表或SHOW PROCESSLIST声明。如果你有PROCESS特权,你可以指定任何连接标识符。否则,你只能指定自己的连接标识符。

如果指定的连接不执行语句,结果是空的。否则,EXPLAIN FOR CONNECTION只适用于如果语句在指定的连接执行的解释。这包括SELECTDELETEINSERTREPLACE,和UPDATE。(然而,解释连接不准备报表工作,甚至准备这些类型的语句。)

如果指定的连接执行一个解释性语句,输出的是什么你会获得通过EXPLAIN在语句本身

如果指定的连接执行语句是不能解释的,发生了一个错误。例如,你不能说出你当前的会话标识符的连接,因为EXPLAIN是不是可以解释:

MySQL的&#62;SELECT CONNECTION_ID();_;| connection ID(373);| | |;1行集(0秒)在MySQL &#62;EXPLAIN FOR CONNECTION 373;错误1889(hy000):连接命令解释是supportedonly选择/更新/插入/删除/替换

这个Com_explain_other状态变量表示的数量的EXPLAIN FOR CONNECTION报表执行

8.8.5估计查询性能

在大多数情况下,你可以通过计数盘寻找估计的查询性能。小桌子,你通常可以在一个磁盘发现行寻求(因为指数可能是缓存)。对于较大的表,可以估计,使用B树索引,你需要这许多寻求一排:log(row_count) / log(index_block_length / 3 * 2 / (index_length + data_pointer_length)) + 1

在MySQL数据库中,索引块通常是1024个字节,数据指针通常是四字节。对于一个三字节的密钥值的长度500000行表(大小MEDIUMINT),公式表示日志(500000)/日志(1024/3 * 2 /(3 4))1=4寻求.

This index would require storage of about 500,000 * 7 * 3/2 = 5.2MB (assuming a typical index buffer fill ratio of 2/3), so you probably have much of the index in memory and so need only one or two calls to read data to find the row.

写的,然而,你需要四寻求要求找到一个新的指标值,通常两寻求更新索引写行。

前面的讨论,并不意味着你的应用程序的性能缓慢退化的日志N。只要一切都是由操作系统或MySQL服务器缓存,事情变得稍微慢表变大。数据太大被缓存后,事情开始变得更慢,直到您的应用程序绑定只有硬盘查找(这增加的日志N)。为了避免这种情况,增加缓存大小为数据增长的关键。为MyISAM表,关键的高速缓存的大小是由key_buffer_size系统变量。见第5.1.1条,“配置服务器”

8.9控制查询优化器

MySQL通过系统变量是如何影响查询计划进行优化,可提供优化控制、优化和索引提示,而优化器成本模型。

服务器维护数据列的值,虽然还没有使用这些信息优化。

8.9.1控制查询计划的评价

查询优化器的任务是寻找执行SQL查询语句的优化方案。由于在性能之间的差异坏的计划可以是数量级(即秒和数小时甚至数天),大多数的查询优化器,包括MySQL,执行所有可能的查询评估计划中最优方案的更多或更少的穷举搜索。对于连接查询,可能计划由MySQL优化器调查数呈指数级增长的查询中引用的表的数量。对于少量的表(通常小于7~10)这不是一个问题。然而,当大的查询提交,在查询优化时容易成为服务器性能的瓶颈。

查询优化更灵活的方法可以让用户控制在最优的查询计划评估其搜索优化器如何详尽。总的想法是,少计划的优化研究,更少的时间花费在编译查询。另一方面,由于优化器跳过一些计划,可能想找到一个最佳的方案。

相对于计划评估数的优化器的行为可以用两个系统变量控制:

  • 这个optimizer_prune_level变量告诉优化器跳过基于对每个表的访问的行数估计某些计划。我们的经验表明,这种受过教育的猜测很少错过最佳方案,可以大大减少查询编译时间。这就是为什么这个选项是对的(optimizer_prune_level=1)默认情况下。然而,如果你相信优化器错过了更好的查询计划,该选项可以关闭(optimizer_prune_level=0),编译查询可能需要更长的时间风险。注意,即使使用这种启发式,优化器还探讨了大致的指数数量的计划。

  • 这个optimizer_search_depth变讲述到期货每个不完整的计划优化器应该对是否应进一步扩大。较小的值optimizer_search_depth可能导致幅度较小的查询的编译时间的订单。例如,12、13查询,或多个表可能需要几个小时甚至几天时间来编译如果optimizer_search_depth接近查询中的表的数量。同时,如果编译optimizer_search_depth等于3或4,优化器可以编制在不到一分钟的查询。如果你不确定一个合理的价值是什么optimizer_search_depth,这个变量可以被设置为0,告诉优化器确定值自动。

8.9.2优化器提示

在优化策略控制的一种手段是设置optimizer_switch系统变量(参见第3,“开关的优化”)。这个变量影响所有后续查询执行的变化;影响一个查询不同于另一个改变是必要的optimizer_switch在每一个

另一种方式来控制优化器利用优化器提示,可在单个语句指定的。因为优化器提示每一个语句的基础上,他们提供更精细的控制语句的执行计划比可以达到使用optimizer_switch。例如,你可以在一份声明中一个表的优化和不同的表禁用优化。在一个声明中暗示优先optimizer_switch旗帜

实例:

SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY, f2_idx) */ f1
  FROM t3 WHERE f1 > 30 AND f1 < 33;
SELECT /*+ BKA(t1) NO_BKA(t2) */ * FROM t1 INNER JOIN t2 WHERE ...;
SELECT /*+ NO_ICP(t1, t2) */ * FROM t1 INNER JOIN t2 WHERE ...;
SELECT /*+ SEMIJOIN(FIRSTMATCH, LOOSESCAN) */ * FROM t1 ...;
EXPLAIN SELECT /*+ NO_ICP(t1) */ * FROM t1 WHERE ...;
SELECT /*+ MERGE(dt) */ * FROM (SELECT * FROM t1) AS dt;
INSERT /*+ SET_VAR(foreign_key_checks=OFF) */ INTO t2 VALUES(2);

这里描述的优化器提示,,不同于索引提示,描述第8.9.4,”指标提示”。优化和索引提示可以单独或一起使用。

优化器提示概述

在不同的应用范围水平优化程序提示:

  • 全球:暗示影响整个语句

  • 查询块:暗示会影响一个特定的查询块内的语句

  • 表级:暗示会影响一个特定的表在查询块

  • 指标层:暗示会影响一个特定的索引表内

下表总结了使用优化器提示,它们影响的优化策略,或者在它们适用的范围的范围。给出更多的细节后。

表格8.2优化器提示

淡淡的名字描述适用范围
BKANO_BKA影响批量密钥访问连接处理查询块,表
BNLNO_BNL影响块嵌套循环连接处理查询块,表
INDEX_MERGENO_INDEX_MERGE影响索引合并优化表,索引
JOIN_FIXED_ORDER使用表中指定的顺序FROM条款的加入顺序查询块
JOIN_ORDER使用表中指定的加入顺序为线索查询块
JOIN_PREFIX使用表顺序在第一表提示指定连接顺序查询块
JOIN_SUFFIX使用表顺序指定在上表的连接顺序的暗示查询块
MAX_EXECUTION_TIME语句的执行时间限制全球
MERGENO_MERGE影响派生表/视图合并到外层查询块
MRRNO_MRR影响多阅读范围优化表,索引
NO_ICP影响指标优化条件下推表,索引
NO_RANGE_OPTIMIZATION影响范围优化表,索引
QB_NAME命名查询块查询块
RESOURCE_GROUP在语句执行资源组全球
SEMIJOINNO_SEMIJOIN影响半连接策略查询块
SKIP_SCANNO_SKIP_SCAN影响跳跃扫描优化表,索引
SET_VAR在语句执行变量集全球
SUBQUERY影响物化,IN-存在子查询技术查询块

禁用优化防止优化使用。使优化优化器是免费的如果它适用于执行语句使用的策略,并不是优化一定会用它。

优化器提示语法

MySQL支持SQL语句中的评论中所描述的9.6节”中,语法”。优化器提示必须指定在/*+ ... */评论那是,优化器提示使用一种/ *…* /C风格的注释语法,以+以下的特点/ *评论的开放顺序。实例:

/*+ BKA(t1) */
/*+ BNL(t1, t2) */
/*+ NO_RANGE_OPTIMIZATION(t4 PRIMARY) */
/*+ QB_NAME(qb2) */

空格后是允许的+人物

解析器识别优化提示评论最初的关键词后SELECTUPDATEINSERTREPLACE,和DELETE声明.提示在这些情况下允许:

  • 在开始查询和报表数据的变化:

    SELECT /*+ ... */ ...
    INSERT /*+ ... */ ...
    REPLACE /*+ ... */ ...
    UPDATE /*+ ... */ ...
    DELETE /*+ ... */ ...
    
  • 在查询块的开始:

    (SELECT /*+ ... */ ... )
    (SELECT ... ) UNION (SELECT /*+ ... */ ... )
    (SELECT /*+ ... */ ... ) UNION (SELECT /*+ ... */ ... )
    UPDATE ... WHERE x IN (SELECT /*+ ... */ ...)
    INSERT ... SELECT /*+ ... */ ...
    
  • 在hintable报表作序EXPLAIN。。。。。。。例如:

    解释选择/ *…*解释更新/…在X(选择/ *…* /…)

    言下之意是,你可以使用EXPLAIN看看优化器提示影响执行计划。使用SHOW WARNINGS后立即EXPLAIN看看如何使用提示。扩展解释通过下面的显示输出SHOW WARNINGS表明使用提示。忽略提示不显示。

淡淡的评论可能包含多个提示,但不能包含多个查询块暗示的评论。这是有效的:

SELECT /*+ BNL(t1) BKA(t2) */ ...

但这是无效的:

SELECT /*+ BNL(t1) */ /* BKA(t2) */ ...

当提示评论包含多个提示,存在重复和冲突的可能性。以下的一般准则的应用。具体的提示类型,额外的规则可以适用,在淡淡的描述表明。

  • 重复提示:如一个暗示/*+ MRR(idx1) MRR(idx1) */第一,MySQL使用提示和问题的重复提示警告。

  • 冲突的提示:关于如/*+ MRR(idx1) NO_MRR(idx1) */第一,MySQL使用提示和问题的一种二冲突提示警告。

查询块名称标识符和遵循什么名字都是有效的,如何引用他们通常的规则(见9.2节,“架构对象名称”

提示名称,查询块的名字,和策略的名称不区分大小写。表和索引名称引用遵循通常的标识符区分规则(见第9.2.2,“标识符大小写敏感”

连接顺序优化提示

加入顺序提示影响秩序,优化联接表。

语法的JOIN_FIXED_ORDER提示:

hint_name([ @query_block_name])

其他的连接顺序提示语法:

hint_name([@query_block_name] tbl_name [, tbl_name] ...)
hint_name(tbl_name[@query_block_name] [, tbl_name[@query_block_name]] ...)

语法是指这些条款:

  • hint_name提示:这些名字都是允许的:

    • JOIN_FIXED_ORDER:强制优化器使用中出现的顺序联接表条款.这是作为指定相同的SELECT STRAIGHT_JOIN

    • JOIN_ORDER:指示优化器使用指定的顺序表的联接表。提示适用于指定的表。优化器将表不点名的顺序连接的任何地方,包括在指定的表。

    • JOIN_PREFIX:指示优化器使用指定表为加入执行计划的第一表连接表。提示适用于指定的表。优化地方所有其他表后命名表。

    • JOIN_SUFFIX:指示优化器使用指定表的命令执行计划最后加入表连接表。提示适用于指定的表。优化器的地方之前,所有其他表命名表。

  • tbl_name:一个在声明中使用的表的名称。暗示的名字表适用于所有的表,它的名字。这个join_fixed_order提示名称不表适用于在所有表FROM在它发生的查询块条款。

    如果一个表有一个别名,暗示必须参阅别名,不表名。

    在提示表名称不能胜任模型的名字。

  • query_block_name:查询块,提示应用。如果暗示不包括领导@query_block_name,提示适用于在它发生的查询块。为tbl_name@query_block_name语法,提示适用于指定的表中的命名查询块。对一个查询块分配一个名字,看命名查询优化器提示块

例子:

SELECT
/*+ JOIN_PREFIX(t2, t5@subq2, t4@subq1)
    JOIN_ORDER(t4@subq1, t3)
    JOIN_SUFFIX(t1) */
COUNT(*) FROM t1 JOIN t2 JOIN t3
           WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
             AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);

提示控制半行为加入表,合并外查询块。如果子查询subq1页:1转换为半连接,表t4@subq1“subq2 T5合并外部查询块。在这种情况下,在外部查询块指定的提示控制行为t4@subq1“subq2 T5

优化器解决连接顺序提示,根据这些原则:

  • 多提示的情况下

    只有一个JOIN_PREFIX我喝了_后缀各类型提示应用。以后的任何提示,相同类型的警告被忽略。JOIN_ORDER可以指定几次

    实例:

    /*+ JOIN_PREFIX(t1) JOIN_PREFIX(t2) */
    

    第二JOIN_PREFIX提示忽略警告

    / * join_prefix(T1)join_suffix(T2)* /

    都提示是适用的。没有警告出现。

    /*+ JOIN_ORDER(t1, t2) JOIN_ORDER(t2, t3) */
    

    都提示是适用的。没有警告出现。

  • 冲突的提示

    在某些情况下,提示冲突,如当JOIN_ORDER首选前缀有订单表是不可能同时申请:

    SELECT /*+ JOIN_ORDER(t1, t2) JOIN_PREFIX(t2, t1) */ ... FROM t1, t2;
    

    在这种情况下,指定的第一个提示是应用和随后的冲突被忽略没有警告提示。一个有效的暗示是不可能的应用被忽略没有警告。

  • 忽略提示

    一个暗示是如果一个表中的提示指定有一个循环依赖忽视。

    例子:

    /*+ JOIN_ORDER(t1, t2) JOIN_PREFIX(t2, t1) */
    

    这个JOIN_ORDER提示设置表T2依赖t1。这个首选前缀提示被忽略,因为表t1我们不能依赖T2。忽略提示不显示在扩展EXPLAIN输出

  • 互动const

    MySQL优化器的地方const在加入顺序表,和一个位置const表不受暗示。引用const表连接顺序提示被忽略,虽然提示仍然适用。例如,这些都是等价的:

    如果您已经注册了,请先登录。const_tbl同时,_阶(T2),T1,T2)

    接受提示显示在扩展EXPLAIN输出包括const表中为他们指定的

  • 同类型的交互连接操作

    MySQL支持几种类型的连接:LEFT正确的INNER十字架STRAIGHT_JOIN。暗示与指定类型的连接冲突被忽略没有警告。

    例子:

    SELECT /*+ JOIN_PREFIX(t1, t2) */FROM t2 LEFT JOIN t1;
    

    在这里发生冲突的要求之间的连接顺序的提示,按订单要求LEFT JOIN。暗示是忽略没有警告。

表级优化器提示

表级提示影响:

这些提示类型适用于特定的表,或在一个查询块表。

表级提示语法:

hint_name([@query_block_name] [tbl_name [, tbl_name] ...])
hint_name([tbl_name@query_block_name [, tbl_name@query_block_name] ...])

语法是指这些条款:

  • hint_name提示:这些名字都是允许的:

    • BKA嗯,_ bka:启用或禁用指定的表米酵菌酸。

    • BNLNO _ BNL:启用或禁用指定的表一。

    • MERGEno_merge:使指定的表合并,查看参考或公用表表达式;或禁用合并使用物化代替。

    笔记

    使用BNL或者BKA暗示使加入任何内表外连接的缓冲,加入缓冲必须为外部联接内启用的表。

  • tbl_name:一个在声明中使用的表的名称。提示适用于所有的表,它的名字。如果提示没有名字的表,它适用于所有的表,在它发生的查询块。

    如果一个表有一个别名,暗示必须参阅别名,不表名。

    在提示表名称不能胜任模型的名字。

  • query_block_name:查询块,提示应用。如果暗示不包括领导@query_block_name,提示适用于在它发生的查询块。为tbl_name@query_block_name语法,提示适用于指定的表中的命名查询块。对一个查询块分配一个名字,看命名查询优化器提示块

实例:

SELECT /*+ NO_BKA(t1, t2) */ t1.* FROM t1 INNER JOIN t2 INNER JOIN t3;
SELECT /*+ NO_BNL() BKA(t1) */ t1.* FROM t1 INNER JOIN t2 INNER JOIN t3;
SELECT /*+ NO_MERGE(dt) */ * FROM (SELECT * FROM t1) AS dt;

表级提示适用于接收记录表前表,不发送表。考虑这一说法:

SELECT /*+ BNL(t2) */ FROM t1, t2;

如果优化器选择过程t1首先,它将一个块嵌套循环连接T2通过缓冲中的行t1在开始阅读T2。如果优化器不是选择过程t2首先,暗示没有影响,因为T2是一个发送者表

对于MERGEno_merge提示,这些优先规则:

  • 提示优先于任何优化启发式,不是技术约束。(如果提供一个提示的建议没有效果,优化器已经忽略它。一个原因)

  • 提示优先于derived_merge旗的optimizer_switch系统变量

  • 视图引用的ALGORITHM={MERGE|TEMPTABLE}在视图定义条款优先于暗示在查询中引用视图指定。

指数级优化器提示

指数水平提示影响指数的处理策略,优化器使用特定的表或索引。这些提示对索引的使用条件下推(ICP),多读(MRR),索引合并,和范围的优化(见第8.2.1,优化选择报表”

指数级别提示语法:

hint_name([@query_block_name] tbl_name [index_name [, index_name] ...])
hint_name(tbl_name@query_block_name [index_name [, index_name] ...])

语法是指这些条款:

  • hint_name提示:这些名字都是允许的:

    • INDEX_MERGE无处索引:启用或禁用索引合并为指定的表或索引存取方法。有关此访问方法的信息,参见部分8.2.1.3,“索引合并优化”。这些提示适用于所有三指数合并算法。

      这个INDEX_MERGE暗示的力量优化器使用索引合并为指定的表使用指定的索引集。如果没有指定索引,优化器考虑所有可能的指标组合,选择最便宜的。提示可能是如果指标组合不适用于给定的语句被忽略。

      这个NO_INDEX_MERGE提示禁用索引合并组合,包括任何指定的指标。如果提示没有指定索引,索引合并是不允许的表。

    • MRR不_ MRR:启用或禁用指定的表或索引的MRR。MRR提示仅适用于InnoDBMyISAM表有关此访问方法的信息,参见第8.2.1.10,“多阅读范围优化”

    • NO_ICP:禁用ICP为指定的表或索引。默认情况下,ICP是一个候选的优化策略,所以没有暗示使它。有关此访问方法的信息,参见第8.2.1.5,“指标条件下推优化”

    • NO_RANGE_OPTIMIZATION:禁用指定的表或索引的索引范围的访问。这提示也禁用索引合并和减少索引扫描的表或索引。默认情况下,Access是一个候选范围的优化策略,所以没有暗示使它。

      这提示可能是有用的当数范围可高范围的优化需要很多资源。

    • SKIP_SCANno_skip_scan:启用或禁用跳过扫描指定的表或索引存取方法。有关此访问方法的信息,参见跳跃扫描范围的访问方法。这些提示可作为MySQL 8.0.13。

      这个SKIP_SCAN暗示的力量优化器使用跳过扫描指定的表使用指定的索引集。如果没有指定索引,优化器考虑所有可能的指标,选择最便宜的。提示可能是如果指标不适用于给定的语句被忽略。

      这个NO_SKIP_SCAN提示禁用指定的索引跳跃扫描。如果提示没有指定索引跳跃扫描是不允许的表。

  • tbl_name:表中的应用`暗示

  • index_name:在指定的表名。提示适用于所有的指标,它的名字。如果提示没有名字的指标,它适用于表中的所有指标。

    指一个主键,名称的使用PRIMARY。看指数名称表,使用SHOW INDEX

  • query_block_name:查询块,提示应用。如果暗示不包括领导@query_block_name,提示适用于在它发生的查询块。为tbl_name@query_block_name语法,提示适用于指定的表中的命名查询块。对一个查询块分配一个名字,看命名查询优化器提示块

实例:

SELECT /*+ INDEX_MERGE(t1 f3, PRIMARY) */ f2 FROM t1
  WHERE f1 = 'o' AND f2 = f3 AND f3 <= 4;
SELECT /*+ MRR(t1) */ * FROM t1 WHERE f2 <= 3 AND 3 <= f3;
SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY, f2_idx) */ f1
  FROM t3 WHERE f1 > 30 AND f1 < 33;
INSERT INTO t3(f1, f2, f3)
  (SELECT /*+ NO_ICP(t2) */ t2.f1, t2.f2, t2.f3 FROM t1,t2
   WHERE t1.f1=t2.f1 AND t2.f2 BETWEEN t1.f1
   AND t1.f2 AND t2.f2 + 1 >= t1.f1 + 1);
SELECT /*+ SKIP_SCAN(t1 PRIMARY) */ f1, f2
  FROM t1 WHERE f2 > 40;

下面的例子使用索引合并的暗示,但其他指标水平提示遵循有关提示忽略与优化器提示优先级相同的原则optimizer_switch系统变量或指标的提示。

假设表t1有柱bC,和d而指标命名;i_ai_b,和C的_存在于aB,和c,分别是:

SELECT /*+ INDEX_MERGE(t1 i_a, i_b, i_c)*/ * FROM t1  WHERE a = 1 AND b = 2 AND c = 3 AND d = 4;

应用索引(i_a, i_b, i_c)在这种情况下

SELECT /*+ INDEX_MERGE(t1 i_a, i_b, i_c)*/ * FROM t1  WHERE b = 1 AND c = 2 AND d = 3;

应用索引(i_b, i_c)在这种情况下

_合并/ *指数(T1 _ I,I _ B)没有_ _合并指数(T1 _ * / I B)

NO_INDEX_MERGE被忽视因为有前面的提示相同的表。

/ *没有_ _合并指数(T1 _ I,I _(b)_合并指数(T1 _ * / I B)

INDEX_MERGE被忽视因为有前面的提示相同的表。

对于INDEX_MERGE无处索引优化器提示,这些优先规则:

  • 如果优化器提示指定是适用的,它优先于索引合并的相关标志optimizer_switch系统变量

    SET optimizer_switch='index_merge_intersection=off';SELECT /*+ INDEX_MERGE(t1 i_b, i_c) */ * FROM t1WHERE b = 1 AND c = 2 AND d = 3;

    提示优先于optimizer_switch。索引合并is used for(我_ _ I B,C)在这种情况下

    SET optimizer_switch='index_merge_intersection=on';
    SELECT /*+ INDEX_MERGE(t1 i_b) */ * FROM t1
    WHERE b = 1 AND c = 2 AND d = 3;
    

    提示仅指定了一个指数,因此它是不适用的,和optimizer_switch旗(打开(放))应用。索引合并是如果优化器评估它是成本有效的使用。

    SET optimizer_switch='index_merge_intersection=off';
    SELECT /*+ INDEX_MERGE(t1 i_b) */ * FROM t1
    WHERE b = 1 AND c = 2 AND d = 3;
    

    提示仅指定了一个指数,因此它是不适用的,和optimizer_switch旗(远离的)应用。不使用索引合并。

  • 这个USE INDEX力指数,和IGNORE INDEX索引提示有更高优先级的索引NO_INDEX_MERGE优化器提示

    /*  INDEX_MERGE(t1 i_a, i_b, i_c) */ ... 不知道索引

    IGNORE INDEX优先于索引,所以指数i_a被排除在可能的范围内为索引合并。

    / * noérère index aramée(t1 ièmeème a,i?b)* /…力量指数

    索引合并被取消i_a, i_b因为力量指数,但优化器是被迫使用i_ai_brangeref访问没有冲突;同时提示适用。

  • 如果一个IGNORE INDEX提示名称多个指标,这些指标是不可用的索引合并。

  • 这个FORCE INDEX利用指数提示只有指定的指标可用于索引合并。

    SELECT /*+ INDEX_MERGE(t1 i_a, i_b, i_c) */ a FROM t1
    FORCE INDEX (i_a, i_b) WHERE c = 'h' AND a = 2 AND b = 'b';
    

    索引合并交叉存取算法(i_a, i_b)。同样是真实的如果力量指数改变USE INDEX

查询优化器提示

子查询提示影响是否使用半连接的变换和半连接策略允许的,和,当半连接不使用,是否使用子查询物化或IN-存在变换。关于这些问题的更多信息,参见第8.2.2条,“优化子查询、派生表、视图的引用,和公用表表达式”

语法提示影响半连接策略:

hint_name([@query_block_name] [strategy [, strategy] ...])

语法是指这些条款:

  • hint_name提示:这些名字都是允许的:

    • SEMIJOINno_semijoin:启用或禁用指定的半连接策略。

  • strategy:半连接是启用或禁用策略。这些策略的名称是允许的:dupsweedoutFIRSTMATCHloosescanMATERIALIZATION

    SEMIJOIN提示,如果没有策略命名,半连接如果基于策略可能使根据使用optimizer_switch系统变量。如果策略命名但不适用的声明,dupsweedout使用

    NO_SEMIJOIN提示,如果没有策略命名,半连接是没有用的。如果策略被命名为排除声明所有适用的策略,dupsweedout使用

如果子查询嵌套在另一个和合并成一个半外部查询,任何规格的半连接的查询策略,忽略内心。SEMIJOINno_semijoin提示仍然可以用来启用或禁用半加入这样的嵌套查询转换。

如果DUPSWEEDOUT是残疾人,有时候优化器可以生成查询计划远非最佳。这发生在贪婪搜索由于启发式剪枝,可通过设置optimizer_prune_level=0

实例:

SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, LOOSESCAN) */ * FROM t2
  WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2
  WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);

这些影响是否使用子查询语法化或提示IN-存在变换:

SUBQUERY([@query_block_name] strategy)

暗示的名字永远是SUBQUERY

SUBQUERY提示,这些strategy值是允许的:intoexistsMATERIALIZATION

实例:

SELECT id, a IN (SELECT /*+ SUBQUERY(MATERIALIZATION) */ a FROM t1) FROM t2;
SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ SUBQUERY(INTOEXISTS) */ a FROM t1);

半连接SUBQUERY提示,领先@query_block_name指定查询块,提示应用。如果暗示不包括领导@query_block_name,提示适用于在它发生的查询块。对一个查询块分配一个名字,看命名查询优化器提示块

如果提示评论包含多个查询提示,第一次使用。如果有其他的类型的暗示,他们产生一个警告。以下提示其他类型被忽略。

语句执行时间优化程序提示

这个MAX_EXECUTION_TIME提示只用于SELECT站住它的位置N(毫秒超时值)多久语句允许执行服务器终止之前:

最高的执行时间N

Example with a timeout of 1 Second(1000 Milliseconds):

SELECT /*+ MAX_EXECUTION_TIME(1000) */ * FROM t1 INNER JOIN t2 WHERE ...

这个MAX_EXECUTION_TIME(N)提示设置一个语句执行超时N千年如果这一选项不在。N0、成立由声明超时max_execution_time系统变量的应用

这个MAX_EXECUTION_TIME提示适用如下:

  • 语句多SELECT关键词,如工会或报表与查询,_ _最大执行时间适用于整个语句,必须在第一次出现SELECT

  • 它适用于只读SELECT声明.声明不是只读那些调用存储函数修改数据的副作用。

  • 它不适用于SELECT在存储的程序语句和被忽略。

变量设置提示语法

这个SET_VAR提示设置系统变量临时会话值(对于单个语句的时间)。实例:

SELECT /*+ SET_VAR(sort_buffer_size = 16M) */ name FROM people ORDER BY name;INSERT /*+ SET_VAR(foreign_key_checks=OFF) */ INTO t2 VALUES(2);SELECT /*+ SET_VAR(optimizer_switch = 'mrr_cost_based=off') */ 1;

语法的SET_VAR提示:

set_var(var_name=value

var_name名称系统变量有一个会话值(尽管不是所有的变量可以被命名的,后来的解释)。value是分配给该变量的值;该值必须是一个标量。

SET_VAR让一个临时变量的变化,通过这些陈述的证明:

MySQL的&#62;SELECT @@unique_checks;----------------- | @ @独特的_ - | ----------------- | 1 | ----------------- mysql &#62;SELECT /*+ SET_VAR(unique_checks=OFF) */ @@unique_checks;----------------- | @ @独特的_ - | ----------------- | 0 | ----------------- mysql &#62;SELECT @@unique_checks;----------------- | @ @ unique_checks | ----------------- | 1 | -----------------

SET_VAR,无需保存和恢复变量值。这使您可以通过一个单一的语句替换多个语句。考虑这个语句序列:

SET @saved_val = @@session.var_name集@ @会议var_name=value;选择设置@ @会议。var_name= @saved_val;

该序列可以通过这一声明取代:

SELECT /*+ SET_VAR(var_name = value) ...

独立SET语句允许任何这些语法命名会话变量:

设置会话var_name=value集@ @会议var_name=value;设置@ @var_name=value

因为SET_VAR提示仅适用于会话变量,会话范围是内隐的,和会话@@session.,和@ @既不需要也不允许。包括明确会议指示语法的结果SET_VAR提示被忽略警告

不是所有的Session变量是允许使用SET_VAR。个人系统变量说明每个变量是否是hintable;看第5.1.7,服务器“系统变量”。您也可以检查系统变量在运行时尝试使用它SET_VAR。如果变量是不hintable警告时:

MySQL的&#62;SELECT /*+ SET_VAR(collation_server = 'utf8') */ 1;--- | 1 | --- | 1 | --- 1行集,1报警(0秒)MySQL &#62;SHOW WARNINGS\G*************************** 1。行***************************水平:报警代码:4537message:变“collation_server”不能使用set_var暗示。

SET_VAR语法允许设置只有一个变量,但多提示可以设置多个变量:

SELECT /*+ SET_VAR(optimizer_switch = 'mrr_cost_based=off')           SET_VAR(max_heap_table_size = 1G) */ 1;

如果用相同的变量名几个提示出现在同一个表,第一个是应用和其他的警告被忽略:

SELECT /*+ SET_VAR(max_heap_table_size = 1G)
           SET_VAR(max_heap_table_size = 3G) */ 1;

在这种情况下,第二提示被忽略的警告,这是矛盾的。

SET_VAR提示忽略警告,如果没有系统变量指定的名称或变量的值是不正确的:

SELECT /*+ SET_VAR(max_size = 1G) */ 1;SELECT /*+ SET_VAR(optimizer_switch = 'mrr_cost_based=yes') */ 1;

首先声明,没有max_size变量。For the second statement,成本_ MRR _旗以价值观on远离的,因此试图将它设置为yes是不正确的。在每一种情况下,提示被忽略的警告。

这个SET_VAR提示只允许在语句层面。如果使用子查询,提示被忽略的警告。

从服务器忽略SET_VAR在复制的语句提示避免安全问题的潜力。

资源组提示语法

这个RESOURCE_GROUP优化器提示是用于资源组管理(见第8.12.5,“资源组”)。这提示分配执行一个语句暂时命名的资源组的线程(用于声明的时间)。它要求RESOURCE_GROUP_ADMINRESOURCE_GROUP_USER特权

实例:

SELECT /*+ RESOURCE_GROUP(USR_default) */ name FROM people ORDER BY name;
INSERT /*+ RESOURCE_GROUP(Batch) */ INTO t2 VALUES(2);

语法的RESOURCE_GROUP提示:

resource_group(group_name

group_name表明资源集团的螺纹应分为语句执行的时间。如果是不存在的,发生了警告和提示被忽略。

这个RESOURCE_GROUP提示必须初始语句关键字后出现(选择INSERT更换UPDATE,或删除

一种替代RESOURCE_GROUP是的SET RESOURCE GROUP声明,这nontemporarily分配线程的资源组。看到第13.7.2.4,“设置资源组句法”

命名查询优化器提示块

表水平,指标水平,和子查询优化器提示允许特定的查询块被命名为他们争论语法部分。创造这些名字,用QB_NAME提示,赋予一个名字,在它发生的查询块:

qb_name(name

QB_NAME提示可以用来做一个清晰明确的方式申请查询块的其他线索。他们还允许所有非查询块的名字显示在一个更容易理解复杂的报表指定单个提示评论。考虑下面的语句:

选择从(选择…从(选择…从…))…

QB_NAME提示查询块语句中指定的名字:

选择/ * * / qb_name(QB1)…从(选择/ * * / qb_name(qb2)…从(选择/ * * / qb_name(QB3)…从…))…

然后其他的提示可以使用这些名称来指相应的查询块:

SELECT /*+ QB_NAME(qb1) MRR(@qb1 t1) BKA(@qb2) NO_MRR(@qb3t1 idx1, id2) */ ...
  FROM (SELECT /*+ QB_NAME(qb2) */ ...
  FROM (SELECT /*+ QB_NAME(qb3) */ ... FROM ...)) ...

产生的效果如下:

  • MRR(@qb1 t1)适用于表T1在查询块qb1

  • BKA(@qb2)适用于查询块qb2

  • NO_MRR(@qb3 t1 idx1, id2)适用于指标IDX1idx2T1在查询块qb3

查询块名称标识符和遵循什么名字都是有效的,如何引用他们通常的规则(见9.2节,“架构对象名称”)。例如,一个查询块名称包含空格必须引用,可以使用引号:

SELECT /*+ BKA(@`my hint name`) */ ...
  FROM (SELECT /*+ QB_NAME(`my hint name`) */ ...) ...

如果ANSI_QUOTESSQL模式是启用的,也可能是引用查询块的名称用双引号:

选择/ * BKA(@”我的暗示的名字”)* /…从(选择/ * qb_name(“我的暗示的名字”)* /…)…

3切换优化

这个optimizer_switch系统变量使优化器的行为控制。它的价值是一组标志,每一种都有价值打开(放)off指示是否启用或禁用相应的优化行为。这个变量具有全局和会话的值可以在运行时改变。全局默认可设置在服务器启动。

看到优化器旗帜当前设置,选择变量的值:

mysql> SELECT @@optimizer_switch\G
*************************** 1. row ***************************
@@optimizer_switch: index_merge=on,index_merge_union=on,
                    index_merge_sort_union=on,
                    index_merge_intersection=on,
                    engine_condition_pushdown=on,
                    index_condition_pushdown=on,
                    mrr=on,mrr_cost_based=on,
                    block_nested_loop=on,batched_key_access=off,
                    materialization=on,semijoin=on,loosescan=on,
                    firstmatch=on,duplicateweedout=on,
                    subquery_materialization_cost_based=on,
                    use_index_extensions=on,
                    condition_fanout_filter=on,derived_merge=on,
                    use_invisible_indexes=off,skip_scan=on

改变价值optimizer_switch,指定一个由逗号分隔的一个或多个命令列表:

SET [GLOBAL|SESSION] optimizer_switch='command【,command]…”;

每个command价值应该有以下形式

命令语法意义
default重置为其默认值的每个优化
opt_name=default为优化设置为默认值
opt_name=off禁用指定的优化
opt_name=on使指定的优化

在价值的命令的顺序并不重要,虽然default如果当前执行命令。设置一个opt_name国旗默认将其设置为任何on远离的它的默认值。指定任何opt_name不止一次的值是不允许的,会导致错误。在价值的任何错误导致任务的失败与错误,离开价值optimizer_switch不变

The following the permissible LIST描述opt_name标志名称,通过优化策略组合:

  • 批量密钥访问旗

    • batched_key_access(默认远离的

      控件使用BKA连接算法。

    batched_key_access有任何影响,当设置为打开(放),的mrr标记也必须打开(放)。目前,对MRR的成本估计太悲观。因此,它是必要的mrr_cost_based成为远离的用于对米酵菌酸

    有关更多信息,参见第8.2.1.11,“块嵌套循环和批量密钥访问连接”

  • 块嵌套循环的旗帜

    • block_nested_loop(默认打开(放)

      控件使用BNL连接算法。

    有关更多信息,参见第8.2.1.11,“块嵌套循环和批量密钥访问连接”

  • 滤波旗weather condition

    • condition_fanout_filter(默认打开(放)

      控件使用条件过滤

    有关更多信息,参见第8.2.1.12,“条件过滤”

  • 派生表合并标志

    • derived_merge(默认打开(放)

      控制合并的源表和视图到外层查询块。

    这个derived_merge标志控制是否优化器尝试合并派生表、视图的引用,和公用表表达式为外层查询块,假设没有其他规则防止合并;例如,一个算法一个视图指令优先于derived_merge设置默认情况下,旗帜打开(放)为了使合并

    有关更多信息,参见第8.2.2.3,“优化派生表、视图的引用,和公用表表达式”

  • 发动机状态下推的旗帜

    • engine_condition_pushdown(默认打开(放)

      控制发动机的条件下推。

    有关更多信息,参见第8.2.1.4,“发动机状态下推优化”

  • 指数条件下推的旗帜

    • index_condition_pushdown(默认打开(放)

      控制指标条件下推

    有关更多信息,参见第8.2.1.5,“指标条件下推优化”

  • 索引箭头

    • use_index_extensions(默认打开(放)

      控件使用的索引扩展

    有关更多信息,参见第节,“使用索引扩展”

  • 索引合并标志

    • index_merge(默认打开(放)

      控制索引合并优化

    • index_merge_intersection(默认打开(放)

      控制索引合并交叉访问优化。

    • index_merge_sort_union(默认打开(放)

      控制指标归并排序联盟访问优化。

    • index_merge_union(默认打开(放)

      控制索引合并工会访问优化。

    有关更多信息,参见部分8.2.1.3,“索引合并优化”

  • 【中文解释】:可行性指数

    • use_invisible_indexes(默认远离的

      控件使用隐形的指标

    有关更多信息,参见第8.3.12节“隐形反射”

  • 多方位阅读标志

    • mrr(默认打开(放)

      控制多范围的阅读策略。

    • mrr_cost_based(默认打开(放)

      控件使用基于成本的MRR如果mrr=on

    有关更多信息,参见第8.2.1.10,“多阅读范围优化”

  • 跳跃扫描标志

    • skip_scan(默认打开(放)

      控件使用跳跃扫描访问方法。

    有关更多信息,参见跳跃扫描范围的访问方法

  • 半连接的旗帜

    • semijoin(默认打开(放)

      控制所有的半连接策略。

    • duplicateweedout(默认打开(放)

      控制半连接的重复weedout策略。

    • firstmatch(默认打开(放)

      控制半连接firstmatch策略。

    • loosescan(默认打开(放)

      控制半连接loosescan策略(不要混淆为松散索引扫描GROUP BY

    这个semijoinfirstmatchloosescan,和duplicateweedout标志可控制半连接策略。这个semijoin标志控制是否使用半连接。如果它被设置为打开(放),的firstmatchloosescan旗帜使更精细的控制允许的半连接策略。

    如果duplicateweedout半连接策略被禁用,则除非所有其他适用的策略也禁止使用。

    如果semijoin物化都是on半连接使用,也体现在适用。这些标志打开(放)默认情况下

    有关更多信息,参见第8.2.2.1,优化子查询、派生表、视图的引用,和公用表表达式和半连接的转变”

  • 子查询的物化标志

    • materialization(默认打开(放)

      对照物化(包括半连接物化)。

    • subquery_materialization_cost_based(默认打开(放)

      基于物化选择使用成本。

    这个materialization标志控制是否使用子查询的实现。如果半连接materialization都是打开(放)半连接使用,也体现在适用。这些标志on默认情况下

    这个subquery_materialization_cost_based国旗能够查询物化和之间的选择控制进入-EXISTS辅助转换If the FlAG is打开(放)(默认),优化器执行基于成本的查询物化之间的选择IN-存在如果子查询转换方法。如果国旗off在子查询,优化器选择物化进入-EXISTSsubquery转变。

    有关更多信息,参见第8.2.2条,“优化子查询、派生表、视图的引用,和公用表表达式”

当你指定一个值optimizer_switch,国旗没有提及,保持它们的当前值。这使得它可以启用或禁用特定的优化器的行为在一个语句中不影响他人的行为。声明不依靠什么其他优化标志的存在和他们的价值观是什么。假设所有索引合并优化功能:

MySQL的&#62;SELECT @@optimizer_switch\G*************************** 1. row ***************************@@optimizer_switch: index_merge=on,index_merge_union=on,                    index_merge_sort_union=on,                    index_merge_intersection=on,                    engine_condition_pushdown=on,                    index_condition_pushdown=on,                    mrr=on,mrr_cost_based=on,                    block_nested_loop=on,batched_key_access=off,                    materialization=on,semijoin=on,loosescan=on,                    firstmatch=on,                    subquery_materialization_cost_based=on,                    use_index_extensions=on,                    condition_fanout_filter=on

如果服务器使用索引合并工会或索引归并排序方法结合访问某些查询你想检查是否优化器将更好的表现没有他们,设置变量值这样:

mysql> SET optimizer_switch='index_merge_union=off,index_merge_sort_union=off';

mysql> SELECT @@optimizer_switch\G
*************************** 1. row ***************************
@@optimizer_switch: index_merge=on,index_merge_union=off,
                    index_merge_sort_union=off,
                    index_merge_intersection=on,
                    engine_condition_pushdown=on,
                    index_condition_pushdown=on,
                    mrr=on,mrr_cost_based=on,
                    block_nested_loop=on,batched_key_access=off,
                    materialization=on,semijoin=on,loosescan=on,
                    firstmatch=on,
                    subquery_materialization_cost_based=on,
                    use_index_extensions=on,
                    condition_fanout_filter=on

8.9.4指标提示的

索引提示给优化器有关如何在查询处理过程中选择指标。这里描述的索引提示,,不同于优化器提示,描述第8.9.2,“优化器提示”。指数和优化器提示可以单独或一起使用。

指标提示仅适用于SELECT声明.(他们是接受由分析器UPDATE陈述而被忽略,没有影响。)

索引提示指定一个表名。(对于一般的语法在一个指定的表SELECT声明,看第13.2.10.2,加入“语法”。)对于引用单个表的语法,包括索引提示,看起来像这样:

tbl_name [[AS] alias] [index_hint_list]

index_hint_list:
    index_hint [index_hint] ...

index_hint:
    USE {INDEX|KEY}
      [FOR {JOIN|ORDER BY|GROUP BY}] ([index_list])
  | IGNORE {INDEX|KEY}
      [FOR {JOIN|ORDER BY|GROUP BY}] (index_list)
  | FORCE {INDEX|KEY}
      [FOR {JOIN|ORDER BY|GROUP BY}] (index_list)

index_list:
    index_name [, index_name] ...

这个USE INDEX (index_list)提示告诉MySQL只使用一个指定的索引查找表中的行。替代语法(不知道索引index_list告诉MySQL不使用某些特定的索引。这些提示是有用的如果EXPLAIN表明,MySQL是使用从可能的索引列表错误的指标。

这个FORCE INDEX提示像利用指数(index_list,与另外一个表扫描被认为是非常昂贵的。换句话说,一个表扫描仅如果没有办法用一个指定的索引查找表中的行用。

每个提示需要索引名称,不列名称。指一个主键,名称的使用PRIMARY。看指数名称表,使用SHOW INDEX声明或INFORMATION_SCHEMA.STATISTICS

一个index_name值可以是不完整的索引名称。它可以是一个明确的前缀索引名称。如果前缀是模糊的,发生了一个错误。

实例:

SELECT * FROM table1 USE INDEX (col1_index,col2_index)
  WHERE col1=1 AND col2=2 AND col3=3;

SELECT * FROM table1 IGNORE INDEX (col3_index)
  WHERE col1=1 AND col2=2 AND col3=3;

索引提示的语法具有以下特点:

  • 这是省略语法有效index_list利用指数,这意味着使用任何指标省略index_list力量指数IGNORE INDEX是一个语法错误

  • 您可以通过添加一个指定索引提示范围FOR条款的提示。这提供了对查询处理的各个阶段的执行计划选择更细粒度的优化。仅仅影响指标时使用MySQL决定如何查找表中的行和如何处理连接,使用加入。影响排序或分组的行索引的使用,使用FOR ORDER BY对于组

  • 您可以指定多个索引提示:

    SELECT * FROM t1 USE INDEX (i1) IGNORE INDEX FOR ORDER BY (i2) ORDER BY a;
    

    这不是名称相同的指标在几个提示错误(即使在同一个提示):

    SELECT * FROM t1 USE INDEX (i1) USE INDEX (i1,i1);
    

    然而,它是将一个错误USE INDEX力量指数对于相同的表:

    SELECT * FROM t1 USE INDEX FOR JOIN (i1) FORCE INDEX FOR JOIN (i2);
    

如果索引提示不包括FOR条款,提示的范围是适用于所有部分的声明。例如,这暗示:

不知道索引(I1)

相当于这个组合的提示:

IGNORE INDEX FOR JOIN (i1)
IGNORE INDEX FOR ORDER BY (i1)
IGNORE INDEX FOR GROUP BY (i1)

在MySQL 5中,没有一丝的范围FOR条款只适用于行检索。使服务器使用这个旧的行为时没有条款的存在,使old在服务器启动系统变量。要使复制设置这个变量的护理。基于二进制日志记录语句,有主人和奴隶不同的模式可能会导致复制错误。

当指标提示进行处理,他们是在一个单一的名单收集型(USEIGNORE)和范围(加入FOR ORDER BY对于组)。例如:

SELECT * FROM t1
  USE INDEX () IGNORE INDEX (i2) USE INDEX (i1) USE INDEX (i2);

就相当于:

SELECT * FROM t1
   USE INDEX (i1,i2) IGNORE INDEX (i2);

然后为每个索引提示应用范围按以下顺序:

  1. {USE|FORCE} INDEX如果目前的应用。(如果没有,优化器确定的指标使用。)

  2. IGNORE INDEX在上一步的结果。例如,下面的两个查询是等效的:

    SELECT * FROM T1使用索引(I1)忽略指数(I2)利用指数(I2);选择*从T1使用索引(I1);

FULLTEXT搜索索引提示如下:

  • 自然语言模式的搜索,索引提示被忽略。例如,IGNORE INDEX(i1)忽略没有预警指数仍使用。

  • 为波利洋模式搜索FOR ORDER BY对于组被忽略。指标提示FOR JOIN或没有改性剂的荣幸。相反,如何提示申请非—FULLTEXT搜索提示是用于查询执行的所有阶段(发现行和检索、分组、排序)。即使暗示了非这是真的—全文指数

    例如,下面的两个查询是等效的:

    SELECT * FROM t
      USE INDEX (index1)
      IGNORE INDEX (index1) FOR ORDER BY
      IGNORE INDEX (index1) FOR GROUP BY
      WHERE ... IN BOOLEAN MODE ... ;
    
    SELECT * FROM t
      USE INDEX (index1)
      WHERE ... IN BOOLEAN MODE ... ;
    

8.9.5优化器成本模型

生成执行计划,优化器使用成本模型是基于成本的查询执行过程中发生的各种操作,估计。它有一套编译默认成本常数可使有关执行计划的决定。

优化器也有一个数据库的成本估计使用执行计划建设中。这些估计是存储在server_costengine_cost表中的mysql系统数据库和配置在任何时间。这些表的目的是使它能够很容易地调整成本估计,优化器使用当它试图到达查询执行计划。

成本模型的一般操作

可配置的优化成本模型是这样的:

  • 服务器读取数据到内存的成本模型在启动和使用内存中的值在运行时。任何非—NULL成本估算表中指定的优先级高于相应的违约成本不变的编制。任何无效的估计指示优化器使用编译的默认。

  • 在运行时,服务器可能会重读成本表。这发生在当一个存储引擎是动态加载或当FLUSH OPTIMIZER_COSTS定位器已执行

  • 成本表使服务器管理员可以很容易地调整成本估算表中的条目的变化。它也很容易恢复到默认设置项的成本NULL。优化器使用内存中的成本值,所以表的变化应遵循FLUSH OPTIMIZER_COSTS生效

  • 记忆中的成本估算,目前当一个客户端会话开始时将整个会议直到结束。特别是,如果服务器重新读取成本表,任何改变的估计只适用于随后开始会话。现有会话不受影响。

  • 成本表是特定于一个给定的服务器实例。服务器不成本表的更改复制到复制的奴隶。

成本模型数据库

优化器成本模型数据库由两个表中mysql系统数据库包含在查询执行过程中发生的运营成本估算信息:

  • server_cost:一般服务器操作优化的成本估算

  • engine_cost:具体到特定的存储引擎的操作优化的成本估算

这个server_cost表包含这些列:

  • cost_name

    一个成本估算使用成本模型。名称不区分大小写。如果服务器不识别成本的名字时,它读取这个表,它写入错误日志警告。

  • cost_value

    成本估算值。如果该值是非—NULL,服务器使用它的成本。否则,它使用默认的估算(编制的价值)。DBA可以通过更新此列更改成本估计。如果服务器发现成本值是无效的(正)当它读这个表,它将写入错误日志警告。

    重写默认的成本估算(一个入口指定NULL),设置一个非成本—无效的价值。恢复到默认值设置为NULL。然后执行FLUSH OPTIMIZER_COSTS告诉服务器读成本表

  • last_update

    最后一行的更新时间

  • comment

    与成本估算相关的描述性评论。DBA可以使用该列提供有关为什么成本估计行存储一个特定的值。

  • default_value

    默认(编译)的成本估计值。本栏目是一个只读的生成的列,保持它的价值甚至改变相关的成本估计。行在运行时添加到表中,该列的值NULL

对于主键server_cost表是成本_ name柱,所以它是不可能为任何成本估算中创建多个条目。

服务器能够识别这些cost_name值为伺服器

  • disk_temptable_create_costdisk_temptable_row_cost

    对于存储在基于磁盘的存储引擎内部创建的临时表(或成本估计InnoDBMyISAM)。增加这些值增加使用内部临时表的成本估算和使优化器选择查询计划与他们使用较少。有关这些表的信息,参见第8.4.4,“MySQL”使用内部临时表

    这些硬盘参数较大的默认值相对于相应的内存参数的默认值(memory_temptable_create_costmemory_temptable_row_cost)反映了更大的成本处理基于磁盘的表。

  • key_compare_cost

    比较成本记录键。增加这个值会导致查询计划比较多钥匙变得更加昂贵。例如,一个查询计划的执行filesort变得相对比较昂贵到查询计划,避免了使用索引排序。

  • memory_temptable_create_costmemory_temptable_row_cost

    存储在内部创建的临时表的成本估计MEMORY存储引擎。增加这些值增加使用内部临时表的成本估算和使优化器选择查询计划与他们使用较少。有关这些表的信息,参见第8.4.4,“MySQL”使用内部临时表

    较小的默认值,这些参数对相应内存相比,硬盘参数的默认值(disk_temptable_create_costdisk_temptable_row_cost)反映了较小的处理成本的基于内存的表。

  • row_evaluate_cost

    评价记录条件的成本。增加这个值会导致查询计划,探讨多排变得更加昂贵比查询计划,探讨较少的行。例如,一个表扫描变得相对比较昂贵到范围扫描读取较少的行。

这个engine_cost表包含这些列:

  • engine_name

    名称的存储引擎,这个成本估计的应用。名称不区分大小写。如果该值为default,它适用于没有为自己进入各种存储引擎。如果服务器不识别引擎的名字时,它读取这个表,它写入错误日志警告。

  • device_type

    设备类型,这个成本估计的应用。列是用于指定不同的存储设备类型不同的成本估计,如硬盘驱动器和固态驱动器。目前,这个信息是没有用的,0是唯一的允许值。

  • cost_name

    一样的server_cost

  • cost_value

    一样的server_cost

  • last_update

    一样的server_cost

  • comment

    一样的server_cost

  • default_value

    默认(编译)的成本估计值。本栏目是一个只读的生成的列,保持它的价值甚至改变相关的成本估计。行在运行时添加到表中,该列的值NULL,与异常,如果行具有相同的成本_ name价值作为一种原始的行,default_value列都有相同的值作为该行。

对于主键engine_cost表是一个元组包括(成本_ nameengine_namedevice_type)柱,所以它是不可能在这些列的任何组合的值创建多个条目。

服务器能够识别这些cost_name值为engine_cost

  • io_block_read_cost

    阅读索引或数据块从磁盘的成本。增加这个值导致的查询计划读很多的磁盘块变得更昂贵的比一个查询计划:更少的磁盘块。例如,一个表扫描变得相对比较昂贵到范围扫描读取较少的块。

  • memory_block_read_cost

    类似io_block_read_cost,但代表阅读索引或数据块从内存中的数据库缓冲区的成本。

如果io_block_read_costmemory_block_read_cost价值观不同,执行计划可能两运行相同的查询之间的变化。假设内存访问的成本小于磁盘访问的成本。在这种情况下,在服务器启动前的数据被读入缓冲池,你可以在查询已经运行,因为该数据将被存储到一个不同的计划比。

变更的成本模型数据库

对DBA希望改变成本模型参数的默认值,尝试加倍或减半的值和测量的影响。

变化的io_block_read_costmemory_block_read_cost参数是最有可能产生有价值的结果。这些参数值,使成本模型的数据访问方法,考虑不同来源的阅读信息的成本;即从磁盘与已经在内存缓冲区中读取信息的阅读信息的成本。例如,所有其他的事情都是平等的,设置io_block_read_cost一个值大于memory_block_read_cost使优化器选择的查询计划,阅读已经保存在内存中的计划,必须从磁盘中读取信息。

这个例子显示了如何更改默认值io_block_read_cost

UPDATE mysql.engine_cost  SET cost_value = 2.0  WHERE cost_name = 'io_block_read_cost';FLUSH OPTIMIZER_COSTS;

这个例子展示了如何变化的价值io_block_read_cost只为InnoDB存储引擎:

INSERT INTO mysql.engine_cost
  VALUES ('InnoDB', 0, 'io_block_read_cost', 3.0,
  CURRENT_TIMESTAMP, 'Using a slower disk for InnoDB');
FLUSH OPTIMIZER_COSTS;

8.9.6优化器统计

这个column_statistics数据字典表存储直方图统计的列值,在构造查询执行计划的优化使用。进行直方图的管理、使用ANALYZE TABLE声明;看第13.7.3.1,“语法分析表”

这个column_statistics表具有这些特点:

  • 表中所有数据类型的列统计除了几何类型(空间数据)和JSON

  • 桌子上是持久的,不需要每次列统计服务器开始创建。

  • 该服务器执行更新的表;用户不。

这个column_statistics表不是由用户直接访问是数据字典部分。直方图信息可使用INFORMATION_SCHEMA.COLUMN_STATISTICS,这是对数据字典表的视图实现。COLUMN_STATISTICS这些列有:

  • SCHEMA_NAMECOLUMN_NAME:的图式,表的名称,和列的统计应用。

  • HISTOGRAMAJSON描述统计之列,存储为一个直方图。

列直方图包含存储在列中的值的范围部分桶。直方图JSON对象允许在列统计表示的灵活性。这里是一个简单的直方图的目标:

{“桶”:[ [ 1,0.3333333333333333 ],[ 2,0.6666666666666666 ],[ 3,1 ] ],“空值”:0,“最近更新”:“2017-03-24 13:32:40. 000000”、“采样率”:1、“直方图”型:“独生子女”、“斗指定”编号:128,“数据类型”:“int”、“整理ID”:8 }

直方图的对象有这些钥匙:

  • buckets:直方图桶。斗结构取决于直方图的类型。

    singleton直方图,桶包含两个值:

    • 价值1:对斗的价值。类型取决于该列的数据类型。

    • 价值2:双代表价值的累积频率。例如,25。75表明,25 %和%的75列的值是小于或等于斗值。

    equi-height直方图,桶包含四个值:

    • 价值1, 2:上下对斗纳值。类型取决于该列的数据类型。

    • 价值3:双代表价值的累积频率。例如,25。75显示在列中的值25%和75%是小于或等于桶上的价值。

    • 价值:从斗下价值的上限值范围的不同值的个数。

  • null-values:0.0和1.0之间的一个数字表示分数,列值的SQL无效的价值观。如果零,列不包含NULL价值观

  • last-updated:当直方图产生作为UTC的价值YYYY-MM-DD HH:MM:SS.hhmmss格式

  • sampling-rate:一为0.0表示采样创建直方图数据的分数之间的数。值为1意味着所有的数据读取(不取样)。

  • histogram-type在直方图的类型:

    • singleton代表:一桶列中的一个单一的价值。这个直方图类型时创建的列中不同值的个数小于或等于指定的桶数ANALYZE TABLE生成直方图的声明

    • equi-height:一桶是一个值的范围。这个直方图类型时创建的列中不同值的个数大于指定的桶数ANALYZE TABLE生成直方图的声明

  • number-of-buckets-specified:指定的桶数ANALYZE TABLE生成直方图的声明

  • data-type:这个数据直方图的类型包括。这是需要阅读和分析直方图从持久性存储到内存时。价值是一个intuint(无符号整数),decimal日期时间,或string(包括字符和二进制字符串)。

  • collation-id3 .《历史记录》。∮It is mostly meaningful when the数据类型string。值对应身份证件列中的值INFORMATION_SCHEMA.COLLATIONS

从直方图对象中提取特定的值,你可以使用JSON操作。例如:

MySQL的&#62;SELECTTABLE_NAME, COLUMN_NAME,HISTOGRAM->>'$."data-type"' AS 'data-type',JSON_LENGTH(HISTOGRAM->>'$."buckets"') AS 'bucket-count'FROM INFORMATION_SCHEMA.COLUMN_STATISTICS;----------------- ------------- ----------- -------------- | table_name | column_name |数据类型|桶数| ----------------- ------------- ----------- -------------- |国|人口| int | 226 | |市|人口| int | 1024 | | countrylanguage |语言|字符串| 457 | ----------------- ------------- ----------- --------------

优化器使用直方图统计,如果适用,对任何数据类型的列的统计数据收集。优化器将直方图统计的基础上确定选择性行估计(滤波效果)列值的比较对常量值。这些形式的谓词符合直方图的使用:

col_name = constant
col_name <> constant
col_name != constant
col_name > constant
col_name < constant
col_name >= constant
col_name <= constant
col_name IS NULL
col_name IS NOT NULL
col_name BETWEEN constant AND constant
col_name NOT BETWEEN constant AND constant
col_name IN (constant[, constant] ...)
col_name NOT IN (constant[, constant] ...)

例如,这些陈述包含谓词符合直方图的使用:

SELECT * FROM orders WHERE amount BETWEEN 100.0 AND 300.0;
SELECT * FROM tbl WHERE col1 = 15 AND col2 > 100;

对一个恒定值比较的要求包括是常数函数,如ABS()FLOOR()

SELECT * FROM tbl WHERE col1 < ABS(-34);

直方图统计主要是有用的非索引列。添加一个索引列的直方图统计的适用也可能帮助优化器使行估计。权衡:

  • 一个索引时必须更新表中的数据被修改。

  • 一个直方图或只在需要更新,所以没有增加开销,当表中的数据被修改。另一方面,统计变得越来越过时,当表的修改发生,直到他们下一次的更新。

优化器选择范围优化排的估计从直方图统计得到的。如果优化器,优化器的应用范围,它不使用直方图统计。

这是索引的列,行估计可以得到平等的比较使用指数跳水(见第8.2.1.2”范围,优化”)。在这种情况下,直方图统计不一定有用,因为指数跳水可以产生更好的估计。

在某些情况下,使用直方图统计可能不会提高查询执行;例如,如果数据是过时的。检查是否是这种情况,使用ANALYZE TABLE再生的直方图统计,然后再次运行查询。

另外,禁用直方图统计,使用ANALYZE TABLE把他们。一个禁用直方图统计不同的方法是关闭的condition_fanout_filter旗的optimizer_switch系统变量(尽管这可能会使其他的优化以及):

SET optimizer_switch='condition_fanout_filter=off';

如果使用直方图统计,由此产生的影响是可见的使用EXPLAIN。考虑下面的查询,在没有索引可用于柱2

SELECT * FROM t1 WHERE col1 < 24;

如果直方图的统计表明,57%的行t1满足col1 < 24谓词过滤甚至可以在一个指数没有发生,和EXPLAIN在57显示过滤专栏

8.10缓冲和缓存

MySQL使用缓存信息的内存中的缓冲区来提高性能的几种策略。

8.10.1 InnoDB缓冲池的优化

InnoDB维护一个存储区域称为缓冲池在内存中缓存数据和索引。知道如何InnoDB缓冲池的作品,而且利用它保持经常访问的数据在内存中,是MySQL优化的一个重要方面。

对内部运作的一种解释InnoDB缓冲池,其LRU替换算法的概述,和一般配置的信息,参见第15.6.3.1,“InnoDB缓冲池”

额外的InnoDB缓冲池的配置和调试信息,看到这些部分:

8.10.2的myisam Key Cache

为了减少磁盘I/O,这MyISAM存储引擎使用的策略,是由多个数据库管理系统使用。它采用了缓存机制来保持最频繁访问的内存中的表块:

  • 索引块,特殊结构称为键缓存(或关键缓冲)保持。该结构包含多个块缓冲区,最常用的索引块放。

  • 数据块,MySQL没有使用特殊的缓存。相反,它依赖于本地操作系统的文件系统缓存。

本部分首先介绍了基本操作MyISAM键缓存。然后讨论了特征,提高缓存性能和关键,使你更好地控制缓存操作:

  • 多个会话可以同时访问高速缓存。

  • 你可以设置多个索引缓存分配表索引到特定的缓存。

控制关键的缓存大小,使用key_buffer_size系统变量。如果这个变量设置为等于零,没有密钥缓存的使用。键缓存也不是用如果key_buffer_size值太小,要分配的块缓冲区的最小数量(8)。

当密钥缓存不可操作,索引文件只使用本地文件系统缓存由操作系统提供的访问。(换句话说,表的索引块都使用相同的策略,用于访问表数据块。)

一个索引块相邻单元的访问MyISAM索引文件。通常一个索引块大小相等的索引B树节点的大小。(指标是使用B树数据结构的磁盘为代表。在树的底部节点是叶节点。上面的叶节点的节点是叶节点。)

在一个关键的缓存结构的所有块缓冲区大小是一样的。这个尺寸可以等于、大于或小于一个表的索引块的大小。通常这两个值是另一个。

当数据从任何表的索引块必须访问,服务器首先检查它是否在一些关键的缓存块缓冲区可用。如果是,服务器访问数据的索引缓存而不是硬盘。那就是,它读取或写入到缓存而不是读写磁盘。否则,服务器选择一个包含不同的表的索引块的缓存块缓冲区(或块)和替代数据有一份需要的表的索引块。一旦新的索引块在高速缓存中,数据可以被访问的索引。

如果选择更换一块已被修改,被认为是块在这种情况下,被替换之前,它的内容刷新到表的索引从它来的。

通常服务器如下LRU(最近最少使用)策略:当选择一块更换,选择最近最少使用的索引块。做这样的选择更容易,关键缓存模块维护所有使用的块在一个特殊的列表(LRU链通过使用时间排序)。当一个块被访问时,它是最常用的,放在列表的结尾。当块需要更换,在列表的开始块最近最少使用成为驱逐的第一人选。

这个InnoDB存储引擎也采用LRU算法,来管理缓冲池。看到第15.6.3.1,“InnoDB缓冲池”

8.10.2.1共享密钥缓存访问

线程可以访问密钥缓存缓冲区的同时,须符合下列条件:

  • 一个不被更新缓冲区可以由多个会话访问。

  • 一个被更新的原因会议,需要用它来等待更新完成缓冲。

  • 多个会话可以发起请求,缓存块置换的结果,只要他们不互相干扰(即,只要他们需要不同的索引块,从而导致不同的缓存块被取代)。

对关键的高速缓存的共享访问服务器可以提高吞吐量。

8.10.2.2多个索引缓存

共享访问密钥缓存提高性能,但不排除在会议完全竞争。他们还在争夺控制结构管理访问密钥缓存缓冲区。为了进一步降低密钥缓存访问竞争,MySQL还提供了多个索引缓存。此功能使您可以指定不同的表索引缓存不同的关键。

在有多个索引缓存,服务器必须知道使用处理查询时对于一个给定的高速缓存MyISAM表。by default,allMyISAM表索引缓存在默认密钥缓存。指定表的索引到一个特定的密钥缓存,使用CACHE INDEX声明(见第13.7.7.2,“缓存索引语法”)。例如,下面的语句将表中的索引t1T2,和t3对密钥缓存命名热门高速缓存

mysql> CACHE INDEX t1, t2, t3 IN hot_cache;
+---------+--------------------+----------+----------+
| Table   | Op                 | Msg_type | Msg_text |
+---------+--------------------+----------+----------+
| test.t1 | assign_to_keycache | status   | OK       |
| test.t2 | assign_to_keycache | status   | OK       |
| test.t3 | assign_to_keycache | status   | OK       |
+---------+--------------------+----------+----------+

键缓存中CACHE INDEX语句可以通过设置它的大小了SET GLOBAL参数设置表或通过使用服务器启动选项。例如:

MySQL的&#62;SET GLOBAL keycache1.key_buffer_size=128*1024;

摧毁一个密钥缓存,设置其大小为零:

mysql> SET GLOBAL keycache1.key_buffer_size=0;

你无法摧毁的默认密钥缓存。任何试图这样做是忽略:

mysql> SET GLOBAL key_buffer_size = 0;

mysql> SHOW VARIABLES LIKE 'key_buffer_size';
+-----------------+---------+
| Variable_name   | Value   |
+-----------------+---------+
| key_buffer_size | 8384512 |
+-----------------+---------+

键缓存变量系统变量有一个名字和组件。为keycache1.key_buffer_sizeKeycachl是缓存变量名称key_buffer_size是缓存组件。看到第5.1.8.2,“系统变量”一个描述,用于指密钥缓存系统变量的语法结构。

默认情况下,表的索引分配给主(默认)缓存在服务器启动时创建的关键。当一个密钥缓存被破坏,所有的指标分配给它分配给默认密钥缓存。

对于繁忙的服务器,您可以使用一个策略,包括三个主要的缓存:

  • 键缓存占用20的空间分配给所有索引缓存。使用此表,被大量用于搜索,但都没有更新。

  • 寒冷的键缓存占用20%的空间分配给所有索引缓存。使用这个缓存中,深入修改表,如临时表。

  • 温暖的键缓存占用的缓存空间的60%个关键。使用该默认密钥缓存,将默认使用的所有其他表。

三关键缓存的使用是有益的原因之一是,使用一个密钥缓存结构不阻止访问的人。语句访问表分配一个缓存不语句表访问分配给另一个缓存竞争。性能的提升,以及其他原因导致:

  • 热缓存只用于检索查询,所以其内容不会被修改。因此,每当一个索引块需要拉在从磁盘,选择更换高速缓存块的内容不需要刷新第一。

  • 对于索引分配到热缓存,如果没有查询需要的索引扫描,有一个高概率的指数对应的索引B树的非叶节点保持在缓存。

  • 更新操作最频繁执行的临时表执行更快更新的节点的缓存不需要从磁盘中读取第一。如果该临时表的索引的大小随着冷关键的缓存大小相当,的概率是非常高的,更新的节点缓存中。

这个CACHE INDEX声明中建立一个表和一个密钥缓存之间的关联,但关联丢失每次重新启动服务器。如果你想学会每次服务器开始生效,做到这一点的方法之一是使用一个选项文件:包括变量设置,配置您的密钥缓存,和初始化文件选择包含文件的名字CACHE INDEX要执行的语句。例如:

key_buffer_size = 4Ghot_cache.key_buffer_size = 2Gcold_cache.key_buffer_size = 2Ginit_file=/path/to/data-directory/ mysqld_init.sql

的陈述mysqld_init.sql每次服务器开始执行。该文件应包含每行一个SQL语句。下面的示例将几个表每热门高速缓存cold_cache

db1.t1索引缓存,在缓存缓存db1.t2,db2.t3 _指数db1.t4 db2.t5热,冷,db2.t6 _缓存

8.10.2.3中点插入策略

默认情况下,密钥缓存管理系统使用一个简单的LRU策略选择密钥缓存块被驱逐,但它也支持一个更复杂的方法称为中点插入策略

采用中点插入策略时,LRU链分为两个部分:热子列表和一个温暖的子列表。两者之间的分界点是不固定的,但关键的缓存管理系统需要照顾,温暖的部分不过短,总是包含至少key_cache_division_limitpercent of the key缓存块。key_cache_division_limit是结构化的关键缓存变量的一个组成部分,所以它的值是一个参数,可以设置每个缓存。

当一个索引块从表中读取到密钥缓存,它被放在温暖的子列表结束。一定数量的点击率(访问后的块),它是推动热点列表。目前,点击次数需要推动一块(3)是所有索引块相同。

一块提升到热子列表放在列表的结尾。块循环在这个列表。如果块保持在一个足够长的时间子列表的开始,它是降级到温暖的子列表。这一次是由价值决定的key_cache_age_threshold高速缓存的关键成分

阈值的规定,一个关键的高速缓存包含N块,在热子没有在去年开始的块N* key_cache_age_threshold / 100点击要搬到温暖的子列表的开始。它便成为拆迁的第一人选,因为块更换总是从温暖的子列表的开始。

中点插入策略可以在缓存中保留更多的值块总是。如果你喜欢使用普通的LRU策略,离开key_cache_division_limit值设置为其默认值100。

中点插入策略有助于提高性能,当执行一个查询,需要一个索引扫描可以有效地将从高速缓存中的所有索引块对应的有价值的高层次的树节点。为了避免这种情况,你必须使用一个中点插入策略与key_cache_division_limit将100少得多。那么重要的经常访问的节点保存在热子在扫描操作以及索引。

8.10.2.4指数预压

如果有把握整个索引块关键足够的缓存块,或至少对应于其非叶节点的块,它是有意义的预紧力的关键缓存索引块在开始使用它。预压使你把表的索引块的最有效的方式的一个关键的高速缓存:通过读取索引块从磁盘顺序。

无预压块仍放入缓存的查询所需的关键。虽然块会留在缓存中,因为有足够的缓冲区的所有人,他们是从随机磁盘牵强,不按顺序。

预紧力的索引缓存,使用LOAD INDEX INTO CACHE声明。例如,下面的语句预加载节点(索引块)的表的索引T1t2

MySQL的&#62;LOAD INDEX INTO CACHE t1, t2 IGNORE LEAVES;--------- -------------- ---------- ---------- |表| OP | msg_type | msg_text | --------- -------------- ---------- ---------- | test.t1 | preload_keys |状态|好| | test.t2 | preload_keys |状态|好| --------- -------------- ---------- ----------

这个IGNORE LEAVES改性剂的指标是非叶节点只造成块预装。因此,表的所有索引块的预紧力T1,但只有块的非叶节点t2

如果索引被使用一个密钥缓存CACHE INDEX声明中,预压的地方,缓存索引块。否则,该指数是加载到默认密钥缓存。

8.10.2.5密钥缓存块大小

这是可以指定的块缓冲区的大小为单个密钥缓存使用key_cache_block_size变量。这允许调谐性能的I / O索引文件的操作。

最佳性能的I/O操作时实现读取缓冲区的大小等于本地操作系统的I/O缓冲区的大小。但是,设置关键节点等于I/O缓冲区的大小并不总是确保最佳的整体性能。阅读大的叶节点时,服务器将在很多不必要的数据,有效地防止了阅读其他叶子节点。

控制块的大小.MYI索引文件MyISAM表,使用--myisam-block-size在服务器启动选项

8.10.2.6转型的关键缓存

一个关键的缓存可以被重组随时更新其参数值。例如:

mysql> SET GLOBAL cold_cache.key_buffer_size=4*1024*1024;

如果你给的key_buffer_sizekey_cache_block_size键缓存组件的值不同于组件的电流值,服务器将缓存的旧结构,创造一种新的基于新的价值观。如果缓存包含任何脏块,服务器将他们在破坏和重新创建缓存磁盘。重组不如果你改变其他关键缓存参数发生。

在转型的关键缓存,服务器先冲任何脏缓冲区的内容到磁盘。在那之后,缓存的内容变得不可用。然而,重组不块,需要使用分配给缓存索引查询。相反,服务器直接访问表的索引使用本地文件系统缓存。文件系统缓存是不使用密钥缓存的效率,所以虽然查询执行放缓可以预期。缓存后进行了调整,变得再次可用缓存索引分配给它,以及文件系统的索引缓存的使用停止。

8.10.3缓存的准备好的语句和存储的程序

某些陈述,客户可能执行多次的会话期间,服务器将语句内部结构和缓存结构来执行期间使用。缓存服务器可以执行更有效,因为它避免了重新恢复的语句的开销需要一次会议期间。转换和缓存发生这些语句:

  • 准备好的语句,那些在SQL级处理(使用PREPARE表)和加工使用二进制的客户端/服务器协议(使用mysql_stmt_prepare()C API函数)。这个max_prepared_stmt_count系统变量控制报表服务器缓存的总数。(对预备语句在所有会话。数之和)

  • 程序存储(存储过程和函数、触发器和事件)。在这种情况下,服务器转换和缓存整个程序体。这个stored_program_cache系统变量指示程序存储每个会话的服务器缓存的近似数。

服务器维护的准备好的语句的缓存,每个会话的基础上存储的程序。报表缓存一次不到其他会话访问。当会话结束时,服务器丢弃任何语句缓存它。

当服务器使用一个缓存内部的语句结构,要注意结构不过时。元数据的变化可以出现一个语句所使用的对象,如内部表结构表示导致当前对象的定义和定义之间的不匹配。元数据的变化发生的DDL语句,如那些创建,降,修改,重命名,或截断表,或分析、优化,或修复表。表格内容的变化(例如,用INSERTUPDATE)不改变的元数据,也不SELECT声明.

这是问题的一个例子。假设一个客户在本声明:

PREPARE s1 FROM 'SELECT * FROM t1';

这个SELECT *扩展的内部结构的表中的列的列表。如果表中的列进行改性修改表,该声明过时。如果服务器没有检测到这一变化的客户在下次执行s1,该声明将返回不正确的结果。

为了避免由元数据更改表或视图所准备的声明引起的问题,服务器检测到这些变化,并自动reprepares声明时,下一个执行。即,服务器工具重新剖析要声明和重建的内部结构。重新也发生后引用的表或视图的表定义隐式刷新缓存,缓存中让新的条目的房间,或明确的原因FLUSH TABLES

同样,如果发生变化,通过储存的程序使用的对象,影响报表服务器工具重新剖析要在程序。

服务器对象的元数据中也检测到表达变化。这些可用于特定于存储的程序语句,如DECLARE CURSOR或如流程控制语句IFCASE,和RETURN

为了避免重新分析整个程序存储和服务器工具重新剖析要影响语句或表达式在程序中只需要。实例:

  • 假设一个表或视图的元数据的改变。重新发生了SELECT *在访问的表或视图的程序,但不支持选择*不能访问的表或视图

  • 当一个语句的影响,仅部分服务器工具重新剖析要尽可能。考虑这个CASE声明:

    案例case_expr什么时候when_expr1…什么时候when_expr2…什么时候when_expr3…最后的案例…

    如果一个元数据的更改只影响WHEN when_expr3,这是重新解析表达case_expr和其他什么时候表达是不解析

重新使用默认的数据库和SQL模式,实际上是在为内部形式的转换。

服务器尝试重新涨三倍。如果努力失败,出现错误。

重新分析是自动的,但在某种程度上,它的发生,减少了事先准备好的声明和程序存储性能。

在准备好的声明,该Com_stmt_reprepare状态变量的跟踪repreparations数。

8.11优化锁定操作

MySQL管理争表内容的使用锁定

  • 内部锁定在MySQL服务器本身的管理表内容由多个线程争用。这种锁的内部是由服务器进行完全不涉及其他程序。看到8.11.1节,“内锁法”

  • 外锁发生时,服务器和其他程序锁MyISAM表文件来协调自己的程序可以访问当时的表。看到8.11.5部分,“外锁”

8.11.1内部锁定的方法

本节讨论内部锁定;即锁定在MySQL服务器本身的管理表内容由多个会话的争夺。这种锁的内部是由服务器进行完全不涉及其他程序。锁定其他程序对MYSQL文件执行,看8.11.5部分,“外锁”

行级锁

MySQL的使用行级锁InnoDB表格支持同时用多个会话的访问,使它们适合于多用户、高并发,和OLTP应用程序。

为了避免死锁当执行多个并发的一个写操作InnoDB表,在通过发行交易的开始获得必要的锁选择更新对于每一组行有望改声明,即使数据更改语句来在交易后。如果事务修改或锁定多个表,问题适用的报表以相同的顺序在每个交易。死锁影响性能而不是一个严重的错误,因为InnoDB自动检测默认情况下,回滚一个受影响的交易产生的条件。

在高并发系统中,死锁检测可以造成经济放缓时多线程等待同一个锁。有时,它可能是更有效地禁用死锁检测和依靠innodb_lock_wait_timeout设置事务回滚时,死锁发生。死锁检测可以禁用使用innodb_deadlock_detect配置选项

优势的行级锁:

  • 更少的锁冲突时不同的会话访问不同的行。

  • 对回滚的变化少

  • 可能很长一段时间的单排锁。

表级锁

MySQL的使用表级锁MyISAM内存,和MERGE表,只允许一个会话更新那些表一次。这使得这些存储引擎的锁定级别更适合只读、读为主,或单用户应用程序。

这些存储引擎,避免死锁总是请求所需的所有锁同时查询的开始总是锁定表中相同的顺序。权衡的是,这种策略降低并发;其他会议,要修改的表必须等待直到当前数据更改语句结束。

表级锁的优点:

  • 相对较少的内存要求(要求每列或行锁定锁定的行组记忆)

  • 快使用时在桌子的很大一部分,因为只有一个单一的锁是。

  • 如果你经常做快GROUP BY在数据的很大一部分业务或必须扫描整个表频繁。

MySQL的授权表写锁如下:

  1. 如果桌子上没有锁,放一个写锁上。

  2. 否则,把锁请求的写锁队列。

MySQL的授权表读锁如下:

  1. 如果没有在桌子上放一个写锁,读锁。

  2. 否则,把锁请求的读锁队列。

表更新了高优先级比表检索。因此,当释放锁,锁是提供给在写锁队列,然后在读锁队列中的请求的请求。这将确保更新一个表不饥饿甚至当有太重SELECT为表活动。但是,如果有一台多更新,SELECT语句等待直到没有更多的更新。

为改变读取优先级信息写,看第8.11.2,“表锁定问题”

你可以分析你的系统表的锁争用的检查Table_locks_immediateTable_locks_waited状态变量,这表明倍,表锁的请求会立即答应,不得不等待数,分别:

MySQL的&#62;SHOW STATUS LIKE 'Table%';----------------------- --------- | variable_name |价值| ----------------------- --------- | table_locks_immediate | 1151552 | | table_locks_waited | 15324 | ----------------------- ---------

性能模式锁表还提供锁定信息。看到第25.11.12,绩效模式锁表”

这个MyISAM存储引擎支持并发插入减少给定表的读者和作者之间的竞争:如果一个MyISAM表中的数据文件中没有空闲块,行总是插在数据文件结束。在这种情况下,你可以自由地混合并行INSERTSELECT声明一个MyISAM桌上没有锁。就是说,你可以将行插入MyISAM同时其他客户阅读它表。孔可以从已删除的行或在表中更新。如果有孔,并发插入,残疾人却再次启用自动当洞已充满了新的数据。为了控制这种行为,使用concurrent_insert系统变量。See第8.11.3,并发插入”

如果你获得一个明确的表锁LOCK TABLES,你可以要求阅读的地方锁而不是READ锁,使其他会议,而你的表执行并发插入锁。

执行了许多INSERTSELECT在一个表的操作T1当并发插入是不可能的,你可以插入到一个临时表temp_t1而从临时表中的行更新房表:

MySQL的&#62;LOCK TABLES t1 WRITE, temp_t1 WRITE;MySQL的&#62;INSERT INTO t1 SELECT * FROM temp_t1;MySQL的&#62;DELETE FROM temp_t1;MySQL的&#62;UNLOCK TABLES;

选择锁的类型

一般来说,表锁比行级锁在下面的例:

  • 大多数报表的表读

  • 表的语句是一个混合的读取和写入,在写入一行,可以通过一个按键读取更新或删除:

    UPDATE tbl_name SET column=value WHERE unique_key_col=key_value;
    DELETE FROM tbl_name WHERE unique_key_col=key_value;
    
  • SELECT结合并行INSERT报表,很少UPDATEDELETE声明.

  • 许多扫描或GROUP BY在整个表的操作没有任何作家。

与更高级别的锁,你可以更容易地调整应用程序,支持不同类型的锁,因为锁的开销小于行级锁。

除行级锁定选项:

  • 版本控制(例如,用于并发插入mysql),可以在同一时间许多读者有一个作家。这意味着数据库或表支持根据不同数据视图的访问开始时。这个一般条款时间旅行,写时拷贝,按需复制

  • 按需复制是在许多情况下优于行级锁。然而,在最坏的情况下,可以使用更多的内存比使用普通锁。

  • 而不是使用行级锁,你可以使用应用程序级别的锁,如所提供的GET_LOCK()RELEASE_LOCK()在MySQL。这是咨询的锁,所以他们只能在应用程序互相配合。看到第12,“多功能”

8.11.2表锁定问题

InnoDB表使用行级锁,多个会话和应用程序可以读写的同时在同一张桌子上,不让对方等待,或产生不一致的结果。这个存储引擎,避免使用LOCK TABLES声明,因为它不提供任何额外的保护,而是减少并发。自动行级锁使这些表适合您繁忙的数据库与您最重要的数据,同时也简化了应用程序的逻辑,既然你不需要锁定和解锁表。因此,该InnoDB存储引擎是MySQL默认。

MySQL使用表锁定(而不是页、行、列或锁定)的所有存储引擎除了InnoDB。锁定操作本身没有太多的开销。但由于只有一个会话可以写一个表在任何一个时间,以获得最佳性能和其他存储引擎,使用它们主要为表,查询往往很少插入或更新。

性能考虑支持InnoDB

当选择是否创建一个表使用InnoDB或不同的存储引擎,请记住以下缺点表锁定:

  • 表锁定,使许多会议,同时从表中读取,但如果一个会话想要写一个表,它必须首先获得独家访问,这意味着它可能要等到其他会话完成表一。在更新过程中,所有其他会议,要访问这个表必须等到更新完成。

  • 表锁定引起的问题时,一个会话等待磁盘已满,和自由空间需要在会话可以成为可。在这种情况下,所有的会话,要访问的问题表也放在一个等待状态直到更多的磁盘空间可用。

  • SELECT声明说,需要很长时间才能运行防止其他会话的同时更新表,使得其他会话出现缓慢或无响应。当一个会话等待更新独家访问表,其他会话的问题SELECT报表将排队背后,即使只读会话减少并发。

锁定性能问题的解决方法

以下描述以避免或减少表锁定,造成竞争的一些方法:

  • 考虑到开关表InnoDB存储引擎,或者使用CREATE TABLE ... ENGINE=INNODB在安装过程中,或使用ALTER TABLE ... ENGINE=INNODB这是我的存存器。See15章,InnoDB存储引擎关于这个存储引擎的更多细节。

  • 优化SELECT报表运行速度更快,所以他们锁表的时间较短。你可能必须创建一些汇总表做这。

  • 开始mysqld--low-priority-updates。存储引擎只使用表级锁(如MyISAMMEMORY,和合并),这使所有语句更新(修改)一个表的优先级低于SELECT声明。在这房子,the secondSELECT在前面的场景的语句将执行之前UPDATE声明,不等待第一SELECT完成

  • 指定所有的更新在一个特定的连接发出应与低优先级,设置low_priority_updates服务器系统变量等于1。

  • 给出一个具体的INSERTUPDATE,或DELETE声明的优先级较低,使用low_priority属性

  • 给出一个具体的SELECT声明更高的优先级,使用high_priority属性。看到第13.2.10,选择“语法”

  • 开始mysqld对于一个较低的值max_write_lock_count系统变量力MySQL暂时提高所有优先SELECT陈述,等待一台特定数量的插入后的表格出现。这允许阅读锁一定数量后WRITE锁具

  • 如果你有问题INSERT结合SELECT,考虑切换到MyISAM表,支持并行SELECTINSERT声明.(见第8.11.3,并发插入”。)

  • 如果你有问题的混合SELECTDELETE报表的极限选项DELETE可以帮助。看到第13.2.2,删除语法”

  • 使用SQL_BUFFER_RESULTSELECT报表可以帮助使表锁短时间。看到第13.2.10,选择“语法”

  • 分表内容为单独的表可能会有帮助,允许查询在一个表中对列运行,而更新是局限于在一个不同的表列。

  • 你可以更改锁定码mysys/thr_lock.c使用一个队列。在这种情况下,锁和读写锁将具有相同的优先级,这可能有助于某些应用。

8.11.3并发插入

这个MyISAM存储引擎支持并发插入减少给定表的读者和作者之间的竞争:如果一个MyISAM表的数据文件中没有孔(中删除的行),一个INSERT语句可以执行到表的末尾添加行的同时,SELECT语句从表读取行。如果有多个INSERT陈述,他们排队和顺序进行的,同时与SELECT声明.一个并行的结果INSERT可能不是立即可见

这个concurrent_insert系统变量可以设置修改并发插入处理。默认情况下,该变量被设置为汽车(1)并发插入,如刚才所描述的处理。如果concurrent_insert是集从未(0),并发插入被禁用。如果变量被设置为ALWAYS(2),并发插入到表的末尾甚至已删除行的表允许。又见的描述concurrent_insert系统变量

如果您使用的是二进制日志,并发插入转换成正常的插入CREATE ... SELECTINSERT ... SELECT声明.这是为了确保你可以重新应用日志备份操作期间创建的表的精确副本。看到5.4.4节,“二进制日志”。此外,对于那些语句读锁放置在选定的表,插入,表被封锁。效果是:并发插入该表必须等。

LOAD DATA INFILE,如果你指定的同时发生的用一个MyISAM表满足并发插入的条件(即,它包含在中间没有空闲块),其他会话可以检索数据从表而LOAD DATA执行。使用的同时发生的选项会影响性能LOAD DATA一点,即使没有其他会话同时使用表。

如果你指定HIGH_PRIORITY,它覆盖的影响--low-priority-updates如果服务器启动选项,选项。这也导致并发插入不能使用。

LOCK TABLE,之间的差异阅读的地方READ是的,阅读的地方允许nonconflictingINSERT报表(并发插入)执行而被锁定。然而,这是不可能的如果你要操纵数据库使用服务器外部过程,而你持有的锁。

8.11.4元数据锁定

MySQL使用元数据锁定管理并发访问数据库对象和保证数据的一致性。元数据锁不仅适用于表,而且架构,存储的程序(程序,函数,触发器,和预定的事件),和表空间。

元数据锁定确实需要一些开销,提高查询量增加。元数据冲突增加多个查询试图访问同一对象的多。

元数据锁不是一个表定义缓存替换,和互斥锁的区别LOCK_open互斥。下面的讨论提供了一些有关如何元数据锁工作。

为了确保事务的可串行化,服务器不允许一个会话执行数据定义语言(DDL)在桌子上,用在一个未完成的显式或隐式事务中开始另一次会议的声明。服务器通过获取元数据锁表使用在交易和延迟释放的锁,直到事务结束。桌上的元数据锁防止表的结构的变化。这种锁定方法已经暗示了一个表,在一次交易中不能使用DDL语句的其他会话使用直到交易结束。

这个原则不仅适用于事务表,也非事务表。假设一个会议开始一个事务使用事务性表t和非事务表NT如下:

START TRANSACTION;
SELECT * FROM t;
SELECT * FROM nt;

服务器保存元数据锁上tNT直到交易结束。如果另一个会话的尝试DDL或表写锁操作,直到它块元数据锁释放在交易结束。例如,第二届块如果尝试任何这些操作:

DROP TABLE t;
ALTER TABLE t ...;
DROP TABLE nt;
ALTER TABLE nt ...;
LOCK TABLE t ... WRITE;

同样的行为负责LOCK TABLES ... READ。这是显式或隐式事务,开始更新任何表(事务性或非事务)将阻止与被阻止锁定表…阅读该表

如果服务器获取元数据锁的声明语法正确但未在执行过程中,它不释放锁的早。锁定释放仍然是递延的交易最终因为失败的语句写入二进制日志的一致性和锁保护。

在自动提交模式下,每个语句实际上是一个完整的交易,所以元数据锁的声明获得只举行到语句的结束。

获取元数据锁在PREPARE声明一次声明已经准备释放,即使准备在多语句事务。

元数据锁扩展,必要时,相关的外键约束来防止冲突的DDL和DML操作同时在相关表执行表。更新父表时,元数据锁在子表的外键的元数据更新时。外键元数据子表拥有的。

在MySQL 8.0.13,XA事务PREPARED状态、元数据锁都保持在客户端断开和重新启动服务器,直到XA COMMITXA RECOVER执行

8.11.5外锁闭

外锁是锁争用文件系统管理的应用MyISAM数据库表的多个进程。外部锁使用的情况下,一个单一的过程如MySQL服务器不能被认为是唯一的过程,需要访问表。这里是一些例子:

  • 如果你运行多个服务器使用相同的数据库目录(不推荐),每个服务器必须有外部锁定功能。

  • 如果你使用myisamchk执行表的维护MyISAM表,您必须确保服务器没有运行,或服务器已启用外部锁,锁表文件作为必要的协调myisamchk访问表。同样使用的是真实的MyISAMPack包装MyISAM

    如果服务器运行外部锁定功能,您可以使用myisamchk在读操作这样的检查表中的任何时间。在这种情况下,如果服务器试图更新一个表,myisamchk是以,服务器将等待myisamchk然后再继续完成

    如果你使用myisamchk写如修复或优化数据表的操作,或者如果你使用MyISAMPack收拾桌子,你必须始终确保mysqld服务器不使用表。如果你不停止mysqld,至少做一个mysqladmin flush-tables在你运行myisamchk。你的表可能会损坏如果服务器和myisamchk访问表

与外部的锁定效应,每个进程需要访问一个表获取表的文件系统锁定之前访问表。如果所有必要的锁无法获取的过程,阻止访问表锁之前可以得到(当前持有的锁的过程释放后)。

外锁影响服务器性能因为服务器有时必须等待其他进程之前,它可以访问表。

外锁是不必要的如果你运行一个服务器访问一个给定的数据目录(这是通常的情况),如果没有如其他程序myisamchk需要修改的表在服务器正在运行。如果你只阅读与其他程序表,外锁是不需要的,虽然myisamchk可能会报告警告如果服务器而变化表myisamchk是阅读

与外部锁定禁用,使用myisamchk,你必须停止服务器,而myisamchk执行否则锁和冲洗表在运行myisamchk。。。。。。。(这制度因素。)为了避免这一要求,使用CHECK TABLEREPAIR TABLE语句来检查和修复MyISAM

mysqld、外部锁定是值的控制skip_external_locking系统变量。当启用此变量,外部锁定功能,反之亦然。外锁默认是禁用的。

使用外部锁定可控制在服务器启动时使用--external-locking--skip-external-locking选项

如果你使用外部锁定选项启用更新MyISAM从许多MySQL进程表,不与启动服务器--delay-key-write=ALL选项或使用DELAY_KEY_WRITE=1任何共享表格选项。否则,指数腐败发生。

为了满足这一条件的最简单的方法是使用--external-locking在一起--delay-key-write=OFF。(这不是默认因为很多设置是有前面的选项。混合有用)

8.12优化MySQL服务器

该部分论述了数据库服务器的优化技术,主要处理系统的配置,而不是调整SQL语句。本节中的信息适用于DBA要确保在服务器管理的性能和可扩展性;开发商建设安装脚本,包括建立数据库;人们使用MySQL自己的开发,测试,和谁想要最大限度地提高自己的生产力。

4优化磁盘I/O

本节描述了配置存储设备的方式时,你可以投入更多和更快的存储硬件到数据库服务器。关于优化InnoDB配置以提高I/O性能,看第8.5.8,“优化InnoDB的磁盘I / O”

  • 磁盘寻道是一个巨大的性能瓶颈。这个问题变得更加明显,当数据量开始增长如此之大,有效的缓存成为可能。对于大型数据库,你或多或少的随机访问数据,你可以肯定,你至少需要一个磁盘寻道读几盘要写的东西。为了解决这个问题,使用磁盘寻道时间和低。

  • 增加可用磁盘锭的数量(从而减少寻求通过symlinking开销)文件到不同的磁盘或磁盘条带:

    • 使用符号链接

      这意味着,对于MyISAM表的链接,你的索引文件和数据文件从他们平常的位置在数据目录到另一个磁盘(也可以是条纹)。这使得寻找和阅读倍,假设磁盘不用于其他目的,以及。看到第8.12.2,“使用符号链接”

      不支持符号链接的使用InnoDB表然而,它是可能的地方InnoDB在不同的物理磁盘上的数据和日志文件。有关更多信息,参见第8.5.8,“优化InnoDB的磁盘I / O”

    • 条纹

      条纹意味着你有很多磁盘并把第一块放在第一盘,第二盘二块,和N这是块上(thN国防部number_of_disks)盘,等等。这意味着如果你的正常数据大小小于条纹尺寸(或完全对齐),你获得更好的性能。条纹是非常依赖于这款操作系统的条带大小,因此不同大小的应用程序基准条纹。看到第8.13.2,“使用你自己的基准”

      对于剥离速度差异非常依赖于参数。这取决于你如何设置带参数和数量的磁盘,你可以得到数量级的测量差异。你要选择随机或顺序访问优化。

  • 可靠性,你可能想使用RAID 0的1(带+镜像),但是在这种情况下,你需要2×N驱动着N硬盘数据。这可能是最好的选择,如果你有钱了。然而,你可能也会投资一些卷管理软件处理效率。

  • 一个好的选择是不同的RAID级别是根据关键的数据类型是。例如,商店半,可以再生一个RAID 0磁盘存储重要数据,但真正重要的数据如RAID 0 1或RAID主机信息和日志N磁盘。RAIDN如果你有很多写的是一个问题,由于需要更新奇偶校验位的时间。

  • 你也可以对数据库使用的文件系统设置参数:

    如果你不需要知道文件的上次访问(这是不是真的有用的数据库服务器),你可以挂载文件系统的-o noatime选项跳过在节点更新上次访问时间的文件系统,从而避免了磁盘的查找。

    在多个操作系统,你可以设置一个文件系统被安装在异步更新-o async选项如果你的电脑是相当稳定的,这应该会给你更好的性能而不会牺牲太多的可靠性。(这面旗帜在默认情况下Linux上。)

使用NFS与MySQL

建议谨慎考虑使用NFS与MySQL。潜在的问题,不同的操作系统和NFS版本,包括:

  • MySQL数据文件和日志文件放在NFS卷成为锁定,无法使用。锁定问题可能发生的情况下,多个实例的MySQL访问相同的数据目录或MySQL是没有正常关机,由于停电,例如。NFS版本4地址标的锁定问题的咨询和租赁介绍基于锁定。然而,在MySQL实例共享数据目录是不推荐。

  • 数据不一致,由于收到了坏消息或丢失的网络流量。要避免此问题,使用TCPhard介绍挂载选项

  • 最大文件大小限制。NFS版本的客户端只能访问一个文件的最低2gb(符号位偏移)。NFS版本3客户支持大文件(64位的偏移量)。所支持的最大文件大小也取决于NFS服务器的本地文件系统。

在一个专业的SAN环境或其他存储系统能够提供比使用NFS这样的环境之外,更高的可靠性,使用NFS。然而,NFS在SAN环境可能比直接连接或总线连接的非旋转存储速度较慢。

如果你选择使用NFS,NFS版本4或更高版本的推荐,如NFS安装测试部署到生产环境之前彻底。

8.12.2使用符号链接

您可以将数据库或表从数据库目录到其他位置,取代他们的新位置的符号链接。你可能会想这样做,例如,将数据库与文件系统或增加更多的自由空间传播你的表不同的磁盘系统的速度。

InnoDB表,使用数据目录的条款CREATE TABLE而不是符号链接声明,解释第15.7.5”创建文件,每个表的表空间在数据目录”。这个新功能是支持的,跨平台的技术。

推荐的方式是整个数据库目录的符号链接到不同的磁盘。符号链接MyISAM表只能作为最后的手段。

确定你的数据目录的位置,用这个语句:

SHOW VARIABLES LIKE 'datadir';

8.12.2.1使用UNIX符号链接数据库

在Unix系统中,对数据库的链接方式是首先创建一些磁盘,你有自由的空间,然后从MySQL数据目录中创建一个软链接到一个目录。

shell> mkdir /dr1/databases/test
shell> ln -s /dr1/databases/test /path/to/datadir

MySQL不支持连接一个目录到多个数据库。一个符号链接的作品,只要你不让数据库之间的链接符号替换数据库目录。假设你有一个数据库db1MySQL数据目录下,然后做一个符号链接db2db1

内核&#62;cd /path/to/datadir内核&#62;ln -s db1 db2

其结果是,任何表tbl_a进入DB1,似乎也有一个表tbl_a进入db2。如果一个客户端更新db1.tbl_a而另一个客户端更新在db2.tbl _,有可能发生的问题

8.12.2.2使用MyISAM表在UNIX符号链接

笔记

符号链接的支持,这里所描述的,随着的--symbolic-links选择控制它,是过时的、将在未来版本的MySQL移除。此外,该选项默认是禁用的。

符号链接的完全支持,只MyISAM表用其他存储引擎的表使用的文件,你可以尝试使用符号链接得到奇怪的问题。为InnoDB表,使用替代技术说明第15.7.5”创建文件,每个表的表空间在数据目录”相反

不链接表上没有一个全面运作的系统realpath()呼叫。(Linux和Solaris支持realpath())。确定你的系统是否支持符号链接,检查的价值have_symlink使用此报表系统变量:

显示变量的have_symlink”;

对于符号链接的处理MyISAM表如下:

  • 在数据目录中,你总是有数据(.MYD)文件和索引(。我)文件。数据文件和索引文件可以通过符号链接的数据目录和其他替代的感动。

  • 你可以使用的数据文件和索引文件独立不同的目录。

  • 指示运行MySQL服务器执行的symlinking,使用DATA DIRECTORY索引目录选项CREATE TABLE。看到第13.1.18,“创建表的语法。另外,如果mysqld没有运行,symlinking可以完成手动使用LN S从命令行

    笔记

    对一方或双方使用的路径DATA DIRECTORY索引目录选项可能不包括MySQLdata目录(错误# 32167)

  • myisamchk不替换的符号与数据文件或索引文件。它可以直接对文件的链接点。任何临时文件的目录中创建的数据文件或索引文件的位置。同样的是真实的ALTER TABLEOPTIMIZE TABLE,和REPAIR TABLE声明.

  • 笔记

    当你把一个表,使用符号链接,无论是符号链接和文件的符号链接点下降。这是一个非常好的理由运行mysqld作为系统root或允许系统用户具有写访问MySQL数据库目录。

  • 如果您重命名的表ALTER TABLE ... RENAMERENAME TABLE你不把桌子移到另一个数据库,在数据库目录的符号链接被重新命名为新的名称和数据文件和索引文件重命名相应。

  • 如果你使用ALTER TABLE ... RENAMERENAME TABLE移动到另一个数据库表,表移动到其他数据库目录。如果表名称的改变,在新的数据库目录的符号链接被重新命名为新的名称和数据文件和索引文件重命名相应。

  • 如果你不使用符号链接,开始mysqld--skip-symbolic-links选项来确保没有人可以使用mysqld可以删除或重命名一个文件的数据目录之外。

不支持这些表的符号链接的操作:

  • ALTER TABLE忽略了数据目录INDEX DIRECTORY表选项

8.12.2.3使用Windows符号链接数据库

在Windows中,符号链接可以用于数据库目录。这使您可以将一个数据库目录在不同的位置(例如,在一个不同的磁盘)通过建立符号链接它。在Windows的数据库链接的使用类似于使用UNIX,虽然设置链接的程序不同。

假设你想把数据库目录数据库命名mydbD:\数据文件。为此,在MySQL数据目录中创建一个符号链接,指向D:\data\mydb。然而,在创建符号链接,确保D:\数据文件通过创建必要的目录是否存在。如果你已经有了一个数据库目录mydb在数据目录,移动到d:\日期。否则,符号链接是无效的。为了避免这些问题,确保服务器没有运行时,您将数据库目录。

在Windows中,您可以创建一个符号链接使用mklink命令。这个命令需要管理员权限。

  1. 改变位置到数据目录:

    C:\> cd \path\to\datadir
    
  2. 在数据目录中,创建一个符号链接名mydb指数据库目录的位置:

    C:\ &#62;mklink /d mydb D:\data\mydb

在这之后,在数据库中创建表mydb被创造出来的D:\数据文件

8.12.3优化内存使用

8.12.3.1 MySQL如何使用内存

MySQL分配缓冲区和缓存来提高数据库操作的性能。默认配置的目的是允许一个MySQL服务器启动一个虚拟机拥有大约512MB的RAM。你可以通过增加一定的缓存和缓冲区相关的系统变量的值提高MySQL的性能。你也可以修改默认的配置运行在有限的内存系统MySQL。

下面的列表描述了一些MySQL的使用内存。在适用的情况下,相关的系统变量的引用。有些项目是存储引擎或特定特征。

  • 这个InnoDB缓冲池是一个内存区域,拥有缓存InnoDB数据表、索引、和其他辅助缓冲区。对于大批量的读操作效率,缓冲池分为网页可以容纳多个行。用于高速缓存管理效率,缓冲池作为一个页面链表实现;是很少使用的数据超过了缓存,使用变化的LRU算法.有关更多信息,参见第15.6.3.1,“InnoDB缓冲池”

    缓冲池的大小,系统的性能是非常重要的:

  • 存储引擎接口使优化器用来扫描,优化器估计会读多行提供有关记录缓冲区大小的信息。缓冲区大小可以根据估计的大小变化。InnoDB使用可变大小的缓冲能力,利用行预取,并减少开销的闭锁和B-树导航。

  • 所有线程共享MyISAM关键缓冲。这个key_buffer_size系统变量决定其大小

    对于每个MyISAM台服务器打开,索引文件打开一次;数据文件打开一次每个并发运行的线程访问表。对于每个并发线程,表结构,每个柱的结构,和缓冲区大小3 *N(我是allocatedN是最大的行长度,不包括BLOBcolumns)。在BLOB列要求五到八字节的长度加上BLOB数据这个MyISAM存储引擎维护内部使用一个额外的行缓冲区。

  • 这个myisam_use_mmap系统变量可以被设置为1,使所有的内存映射MyISAM

  • 如果一个内部内存中的临时表变得太大(确定使用的tmp_table_sizemax_heap_table_size系统变量),MySQL会自动将表从内存到磁盘上的格式。磁盘上的临时表的使用定义的存储引擎internal_tmp_disk_storage_engine系统变量。你可以增加允许临时表的大小如第8.4.4,“MySQL”使用内部临时表

    MEMORY显式创建表CREATE TABLE,only themax_heap_table_size系统变量决定了大表是允许的增长并没有转化为对磁盘格式。

  • 这个MySQL性能模式是一个在一个低水平的MySQL服务器运行监控功能。性能架构动态分配内存的内存使用增量,缩放到实际服务器的负载,而不是分配所需内存在服务器启动。一旦分配内存,它不释放,直到重新启动服务器。有关更多信息,参见25.16节,“性能架构的内存分配模型”

  • 每个线程的服务器用来管理客户端的连接需要一些线程特定的空间。下面的列表显示这些系统变量控制它们的大小:

    连接缓冲区和缓冲区的每一个结果开始的大小等于net_buffer_length字节,但动态放大max_allowed_packet字节的需要。结果缓冲收缩net_buffer_length字节每个SQL语句后。而语句运行时,一份当前语句字符串分配。

    每个连接线程使用内存计算语句消化。服务器配置max_digest_length拜访。见25.9节,“性能架构声明消化和采样”

  • 所有线程共享同一内存。

  • 当一个线程不再需要,分配到它被释放并返回到系统除非线程回到线程缓存内存。在这种情况下,保持内存分配。

  • 每个请求执行的顺序扫描表分配读缓冲区。这个read_buffer_size系统变量确定缓冲区的大小。

  • 阅读中的任意序列行时(例如,以下排序),一个随机读取缓冲区可能是allocated避seeks两盘。《read_rnd_buffer_size系统变量确定缓冲区的大小。

  • 所有的连接是通过在一个单一的执行,和大多数加入甚至可以做到无需使用临时表。大多数的临时表是基于哈希表的内存。临时表与大行长度(计算为所有列的长度的总和)或包含BLOB列存储在磁盘上

  • 大多数要求执行排序分配一个排序缓冲区和零个临时文件根据结果集的大小。看到第b.5.3.5,“MySQL存储临时文件”

  • 几乎所有的分析和计算是在本地线程和可重复使用的内存池了。没有内存开销小,所需要的物品,从而避免了正常慢的内存分配和释放。分配内存,只有出人意料的大串。

  • 每个表有BLOB柱、缓冲放大动态读大BLOB价值观。如果你扫描一个表,缓冲增长作为最大的大BLOB价值

  • MySQL需要表的高速缓存和描述符。在使用表格的所有处理器结构保存在表缓存管理第一,先出(FIFO)。这个table_open_cache系统变量定义了初始表缓存;看第8.4.3.1,“MySQL如何打开和关闭表”

    MySQL也需要为表定义的高速缓冲存储器。这个table_definition_cache系统变量定义表的定义,可以存储在表定义缓存数量。如果你使用了大量的表格,你可以创建一个大表定义缓存加速表的开放。表定义缓存占用空间小和不使用文件描述符,不像表缓存。

  • FLUSH TABLES声明或mysqladmin flush-tables命令关闭了所有的表,在不使用一次,标志着所有在用表被关闭时,当前正在执行的线程完成。这将有效地使用内存最。FLUSH TABLES不直到所有的表都已关闭,返回。

  • 服务器缓存在内存中的结果GRANTCREATE USERCREATE SERVER,和INSTALL PLUGIN声明.这记忆是不是由相应的释放REVOKEDROP USERDROP SERVER,和UNINSTALL PLUGIN报表服务器执行,因此导致缓存报表的例子很多,会有内存使用的增加。这种缓存内存可以释放FLUSH PRIVILEGES

  • 在复制拓扑中,下列设置影响内存的使用情况,并可根据需要进行调整:

    • 这个max_allowed_packet在复制限制最大消息大小,主机发送到处理它的奴隶系统变量。该设置默认到64M。

    • 这个slave_pending_jobs_size_max在一个多线程的奴隶系统变量设置的最大内存量可保持消息等待处理。该设置默认为128M。内存只分配时所需要的,但它可能如果你复制拓扑处理大交易有时。它是一种软限制,和更大的交易可以被处理。

    • 这个rpl_read_size系统变量在一个复制的主从控制的最小数据量的字节读取二进制日志文件和中继日志文件。默认值是8192字节。一个缓冲区的大小是分配给每个线程读取二进制日志和中继日志文件,包括转储线程对奴隶主人和协调线程。

    • 这个binlog_transaction_dependency_history_size系统变量极限排数哈希举行内存中的历史。

    • 这个max_binlog_cache_size系统变量由个人交易指定内存使用上限。

    • 这个max_binlog_stmt_cache_size系统变量的语句缓存指定内存使用上限。

PS和其他系统状态程序会报告mysqld使用大量的内存。这可以通过在不同的内存地址,导致线程栈。例如,Solaris版本PS计数栈之间的未使用的内存用于存储。为了验证这一点,检查可用的交换swap -s。我们的测试mysqld一些内存泄漏探测器(包括商业的和开源的),所以不存在内存泄漏。

监控MySQL内存使用

下面的示例演示如何使用性能模式sys模式监控MySQL内存使用。

大多数的性能模式记忆仪器默认是禁用的。仪器可通过更新ENABLED的性能架构列setup_instruments表记忆工具的形式有名字内存code_area/instrument_name,在那里code_area是一种价值如SQLinnodb,和instrument_name是仪器的细节

  1. 要查看可用的存储工具,查询的性能模式setup_instruments表以下的所有代码的内存区域工具查询返回数百。

    MySQL的&#62;SELECT * FROM performance_schema.setup_instrumentsWHERE NAME LIKE '%memory%';

    你可以通过指定一个代码区域狭窄的结果。例如,您可以限制结果InnoDB通过指定内存工具InnoDB为代码区

    mysql> SELECT * FROM performance_schema.setup_instruments
           WHERE NAME LIKE '%memory/innodb%';
    +-------------------------------------------+---------+-------+
    | NAME                                      | ENABLED | TIMED |
    +-------------------------------------------+---------+-------+
    | memory/innodb/adaptive hash index         | NO      | NO    |
    | memory/innodb/buf_buf_pool                | NO      | NO    |
    | memory/innodb/dict_stats_bg_recalc_pool_t | NO      | NO    |
    | memory/innodb/dict_stats_index_map_t      | NO      | NO    |
    | memory/innodb/dict_stats_n_diff_on_level  | NO      | NO    |
    | memory/innodb/other                       | NO      | NO    |
    | memory/innodb/row_log_buf                 | NO      | NO    |
    | memory/innodb/row_merge_sort              | NO      | NO    |
    | memory/innodb/std                         | NO      | NO    |
    | memory/innodb/trx_sys_t::rw_trx_ids       | NO      | NO    |
    ...
    

    这取决于你的MySQL安装,代码区可以包括performance_schemaSQLclientInnoDBmyisamCSVmemory黑洞archive分区,和其他人

  2. 使记忆工具,添加一个performance-schema-instrument统治你的MySQL的配置文件。例如,为了使所有的记忆工具,添加此规则配置文件并重新启动服务器:

    performance-schema-instrument='memory/%=COUNTED'
    笔记

    启用内存工具启动时确保内存分配发生在启动计数。

    在重新启动服务器后,该ENABLED的性能架构列setup_instruments该报告表记忆的工具,你可以。这个TIMED列在setup_instruments表忽略记忆工具因为内存操作不定时。

    MySQL的&#62;SELECT * FROM performance_schema.setup_instrumentsWHERE NAME LIKE '%memory/innodb%';------------------------------------------- --------- ------- |名字|启用|定时| ------------------------------------------- --------- ------- |记忆/会/自适应哈希索引|没有|没有| |记忆/ InnoDB / buf_buf_pool |没有|没有| |记忆/ InnoDB / dict_stats_bg_recalc_pool_t |没有|没有| |记忆/ InnoDB / dict_stats_index_map_t |没有|没有| |记忆/会/ dict_stats_n_diff_on_level |没有|没有| |记忆/会/其他|没有|没有| |记忆/ InnoDB / row_log_buf |没有|没有| |记忆/ InnoDB / row_merge_sort |没有|没有| |记忆/会/性病|没有|没有| |记忆/会/ trx_sys_t::rw_trx_ids |没有|没有|…
  3. 记忆仪器数据查询。在这个例子中,记忆的仪表数据查询的性能架构memory_summary_global_by_event_name表,总结数据事件_ name。这个EVENT_NAME是仪器的名称

    下面的查询返回的数据的存储器InnoDB缓冲池。列的描述,参见第25.11.15.10,“记忆汇总表”

    mysql> SELECT * FROM performance_schema.memory_summary_global_by_event_name
           WHERE EVENT_NAME LIKE 'memory/innodb/buf_buf_pool'\G
                      EVENT_NAME: memory/innodb/buf_buf_pool
                     COUNT_ALLOC: 1
                      COUNT_FREE: 0
       SUM_NUMBER_OF_BYTES_ALLOC: 137428992
        SUM_NUMBER_OF_BYTES_FREE: 0
                  LOW_COUNT_USED: 0
              CURRENT_COUNT_USED: 1
                 HIGH_COUNT_USED: 1
        LOW_NUMBER_OF_BYTES_USED: 0
    CURRENT_NUMBER_OF_BYTES_USED: 137428992
       HIGH_NUMBER_OF_BYTES_USED: 137428992
    

    相同的基础数据可以查询使用sys图式memory_global_by_current_bytes表,显示当前内存使用的服务器在全球范围内,被分配的类型。

    MySQL的&#62;SELECT * FROM sys.memory_global_by_current_bytesWHERE event_name LIKE 'memory/innodb/buf_buf_pool'\G*************************** 1。行*************************** event_name:记忆/会/ buf_buf_pool current_count:1 current_alloc:131.06 mibcurrent_avg_alloc:131.06 MIB high_count:1 high_alloc:131.06 MIB high_avg_alloc:131.06 MIB

    sys模式查询聚集当前分配的内存(_程序流)的编码区:

    mysql> SELECT SUBSTRING_INDEX(event_name,'/',2) AS
           code_area, sys.format_bytes(SUM(current_alloc))
           AS current_alloc
           FROM sys.x$memory_global_by_current_bytes
           GROUP BY SUBSTRING_INDEX(event_name,'/',2)
           ORDER BY SUM(current_alloc) DESC;
    +---------------------------+---------------+
    | code_area                 | current_alloc |
    +---------------------------+---------------+
    | memory/innodb             | 843.24 MiB    |
    | memory/performance_schema | 81.29 MiB     |
    | memory/mysys              | 8.20 MiB      |
    | memory/sql                | 2.47 MiB      |
    | memory/memory             | 174.01 KiB    |
    | memory/myisam             | 46.53 KiB     |
    | memory/blackhole          | 512 bytes     |
    | memory/federated          | 512 bytes     |
    | memory/csv                | 512 bytes     |
    | memory/vio                | 496 bytes     |
    +---------------------------+---------------+
    

    为更多的信息关于sys图式,看26章,MySQL系统架构

8.12.3.2使大页面支持

一些硬件/操作系统架构,支持内存页面大于默认的(通常是4KB)。这种支持实际的实现依赖于底层的硬件和操作系统。执行大量内存的应用程序的访问可以通过使用大页面由于减少了翻译Lookaside Buffer获得的性能改进(TLB)错过。

在MySQL,大的页面可以使用InnoDB,为缓冲池和额外的内存池分配内存。

在MySQL中尝试使用最大尺寸的支持大页面标准使用,高达4MB。Solaris下,一个超级大页功能使使用页面达到256MB。此功能适用于最近的SPARC平台。它可以启用或禁用使用--super-large-pages--skip-super-large-pages选项

MySQL也支持大页支持Linux的实现(即hugetlb Linux)。

在大的页面可以使用Linux,内核必须能够支持他们,这是必要的配置hugetlb内存池。供参考,这hugetbl API是记录在Documentation/vm/hugetlbpage.txt你的Linux源文件。

最近的一些系统如红帽企业Linux内核似乎大网页功能默认启用。检查这是否你的内核是真实的,使用如下的命令和输出线含看巨大

shell> cat /proc/meminfo | grep -i huge
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       4096 kB

非空命令的输出显示大页面支持是存在的,但零值表明没有页面被配置为使用。

如果你的内核需要重新配置以支持大页面,咨询hugetlbpage.txt文件的说明

假设你的Linux内核的大页面支持,配置它使用MySQL使用下面的命令。通常情况下,你把这些放在一个rc文件或相关的启动文件,系统在启动过程中执行的命令执行,这样每次系统启动。命令执行的顺序,MySQL服务器开始之前。一定要改变分配数和组数的适合您的系统。

# Set the number of pages to be used.# Each page is normally 2MB, so a value of 20 = 40MB.# This command actually allocates memory, so this much# memory must be available.echo 20 > /proc/sys/vm/nr_hugepages# Set the group number that is permitted to access this# memory (102 in this case). The mysql user must be a# member of this group.echo 102 > /proc/sys/vm/hugetlb_shm_group# Increase the amount of shmem permitted per segment# (12G in this case).echo 1560281088 > /proc/sys/kernel/shmmax# Increase total amount of shared memory.  The value# is the number of pages. At 4KB/page, 4194304 = 16GB.echo 4194304 > /proc/sys/kernel/shmall

MySQL的使用,你通常想要的价值shmmax接近值SHMALL

为了验证大页面配置,检查/proc/meminfo又如前所述。现在你应该看到一些非零值:

内核&#62;cat /proc/meminfo | grep -i hugehugepages_total:20hugepages_free:20hugepages_rsvd:0hugepages_surp:0hugepagesize:4096 KB

使用的最后一步hugetlb_shm_group是给MySQL用户无限为memlock限值。这可以通过编辑/etc/security/limits.conf或者通过添加以下命令你_ mysqld safe脚本:

ulimit -l unlimited

添加文件描述符命令_ mysqld safe原因root用户设置memlock限制无限切换到前mysql用户(这个假设_ mysqld safe是开始root。)

在MySQL大页面支持默认是禁用的。要启用,在启动服务器--large-pages选项例如,你可以在服务器上使用下面的代码my.cnf文件:

[mysqld]
large-pages

使用此选项,InnoDB使用大页面自动为其缓冲池和额外的内存池。如果InnoDB做不到这一点,它回到使用传统内存写入错误日志警告:警告:使用常规内存池

验证页面正在被使用,检查/proc/meminfo再一次:

内核&#62;cat /proc/meminfo | grep -i hugehugepages_total:20hugepages_free:20hugepages_rsvd:2hugepages_surp:0hugepagesize:4096 KB

8.12.4优化网络使用

8.12.4.1 MySQL如何使用线程,客户端连接

连接管理器线程处理客户端连接请求的网络接口,服务器监听。在所有平台上,一个管理线程处理TCP/IP连接请求。在Unix上,这个管理线程也处理UNIX套接字文件的连接请求。在Windows中,管理线程处理共享内存连接请求,而另一个命名管道的连接请求的处理。服务器无法创建线程来处理接口,它听不到。例如,一个Windows服务器没有启用命名管道连接不支持创建一个线程来处理他们。

连接管理器线程将每个客户端连接与一个线程专门给它处理身份验证请求处理该连接的。管理线程创建一个新线程需要时可尽量避免这样做咨询的线程缓存首先要看它是否包含一个线程可用于连接。当一个连接端,其线程如果缓存未满返回线程缓存。

在这个连接的线程模型,有许多线程有客户端当前连接,其中有一些缺点,当服务器负载必须扩展以处理大量的连接。例如,线程的创建和处理变得昂贵。另外,每个线程都需要服务器和核心资源,如堆栈空间。为了容纳大量的并发连接,每个线程的堆栈大小必须保持小,导致的情况是,要么太小或服务器消耗大量内存。其他资源枯竭可能发生以及调度开销可以成为重要的。

控制和监视服务器如何管理线程处理客户端连接,几个系统状态变量有关。(见第5.1.7,服务器“系统变量”,和第5.1.9,“服务器状态变量”。)

线程缓存的大小决定了thread_cache_size系统变量。默认值是0(无缓存),使一个线程被设置为每个新的连接处理,当连接终止。配置thread_cache_sizeN为了使N无效的连接线程缓存thread_cache_size可设置在服务器启动或更改在服务器运行。连接线变为无效,当客户端连接与它相关联的终止。

监视缓存的线程数和多少线程创建后,因为一个线程不能从缓存中取出,监控Threads_cachedThreads_created变量

你可以设置max_connections在服务器启动或运行时控制,可以同时连接的客户端的最大数量。

当线程堆栈太小,这限制了复杂的SQL语句,服务器可以处理、存储过程的递归深度,和其他内存消费行为。设置堆栈大小N每个线程字节,启动服务器--thread_stack=N

8.12.4.2 DNS查询优化和缓存

MySQL服务器维护一个主机缓存内存中包含客户信息:IP地址,主机名和错误信息。这个host_cache性能模式表暴露主机缓存的内容可以使用了SELECT声明.这可以帮助您诊断连接问题的原因。看到第25.11.16.1,“host_cache表”

使用主机缓存数目的服务器:

  • 通过缓存IP主机名查找结果,避免了为每个客户端连接服务器做DNS查找。相反,对于一个给定的主机,它只需要从主机的第一个连接中执行一个查找。

  • 缓存包含在连接过程中出现的错误信息。一些被认为是错误的舞台调度.如果太多的连续发生从一个给定的主机没有连接成功,服务器模块进一步连接从主机。这个max_connect_errors系统变量前决定允许阻塞发生的错误数。看到第b.5.2.5,“主机”host_name“受阻”

使用主机缓存为外地的TCP连接的服务器。它不使用缓存的TCP连接的建立使用环回接口地址(例如,127.0.0.1::1),或已建立的连接使用UNIX socket文件、命名管道和共享内存。

每一个新的客户端连接,服务器使用客户端的IP地址是否客户端主机名的主机缓存。如果没有,服务器尝试解析主机名。首先,它解决了IP地址的主机名和主机名解析,返回一个IP地址。然后比较结果的原始IP地址以确保它们是相同的。服务器存储在主机缓存该操作结果信息。如果缓存已满,最近最少使用的条目被丢弃。

服务器处理的条目在主机缓存这样:

  1. 当第一个TCP客户端连接到服务器,从一个给定的IP地址,一个新的缓存条目来记录客户端的IP,主机名和客户端查询验证标志。最初,主机名设置为NULL和国旗是错误的。本条目也可以用于后续的客户端连接从相同的源IP。

  2. 如果客户端的IP输入验证标志是假的,服务器尝试一个IP主机名DNS解析。如果成功的话,主机名与解决主机名和验证标记更新设置为true。如果分辨率是不成功的,采取的行动取决于误差是永久或暂时。对于永久性故障,主机名是NULL和验证标志设置为true。瞬时故障,主机名和验证标志保持不变。(在这种情况下,另一个DNS解析尝试下次出现一个客户端连接的IP。)

  3. 如果错误发生在处理传入的客户端连接从一个给定的IP地址,服务器更新相应的错误计数器在IP入口。一个描述的错误记录,看第25.11.16.1,“host_cache表”

该服务器执行主机名解析使用gethostbyaddr()gethostbyname()系统调用

疏通堵塞的主机,主机通过发行刷新缓存FLUSH HOSTS语句或执行mysqladmin冲洗主机命令

为阻止主机成为畅通的即使不可能FLUSH HOSTS如果从封锁主机上连接的尝试出现了来自其他主机的活动。这可能是因为服务器删除最近最少使用的缓存条目,如果缓存满了从一个不在缓存客户端IP连接时到达为新进入的房间。如果丢弃的条目是阻塞的主机,主机变得畅通。

主机缓存是默认启用。要禁用它,设置host_cache_size系统变量为0,无论是在服务器启动或运行时。

禁用DNS主机名查找和启动服务器--skip-name-resolve选项在这种情况下,服务器只使用IP地址而不是主机名匹配连接主机的MySQL的授权表行。只有账户指定这些表中使用的IP地址可以使用。(一个客户端可能无法如果没有考虑存在指定客户端的IP地址,连接)

如果你有一个非常缓慢的DNS和许多主机,你可能会提高性能可以通过禁用DNS查找能--skip-name-resolve或通过增加价值host_cache_size主机缓存让the空气日期2010年1月17。

不允许TCP/IP连接完全,与启动服务器--skip-networking选项

有些错误是不连接的TCP连接,在连接过程中很早就出现(即使在一个IP地址是已知的),或是不针对任何特定的IP地址(如内存不足的条件下)。关于这些错误信息,检查Connection_errors_xxx状态变量(这第5.1.9,“服务器状态变量”

8.12.5资源组

MySQL支持的资源组的创建和管理,并允许分配的线程运行在服务器上的特定群体,线程执行根据可用的资源组。组属性使其资源控制,启用或限制资源消耗的线程组。DBA可以适合不同的工作负载,修改这些属性。

目前,CPU时间是一个可管理的资源,通过概念的代表虚拟CPU作为一个术语,包括CPU核心,hyperthreads,硬件线程,等等。服务器确定在启动多少个虚拟CPU可用,并拥有适当权限的数据库管理员可以将这些CPU资源组分配的线程组。

例如,管理批作业不需要执行高优先级执行,DBA可以创建一个Batch资源组,并向上或向下取决于服务器有多忙调整优先级。(也许是批量作业分配到组应该运行在低优先级和高优先级的白天在夜间。)DBA还可以调节设定CPU可用的组。组可以启用或禁用控制是否线程分配给他们。

以下各节描述了在MySQL资源组使用方面:

重要

在一些平台或MySQL服务器的配置,资源组是不可用或有局限性。特别是,Linux系统可能需要手动的一些安装方法步骤。详情见资源组的限制

资源组分

这些功能提供MySQL资源组管理SQL接口:

  • SQL语句可以创建,修改,和丢弃的资源组,使分配线程的资源组。一个优化器提示使分配单独的报表资源组。

  • 资源组的权限控制,提供用户可执行的操作的资源组。

  • 这个INFORMATION_SCHEMA.RESOURCE_GROUPS表露出对资源组定义和性能架构信息threads表格显示每个线程的资源组分配。

  • 状态变量提供执行计数每个管理SQL语句。

资源组的属性

资源组的属性定义组。所有的属性可以设置组的创建时间。有些属性是固定在创作时间;其他人可以修改之后的任何时间。

这些属性是定义在资源组的创建时间和不能被修改:

  • 每个组都有一个名字。资源组名称标识如表名和列名,并且不需要在SQL语句中引用除非他们包含特殊字符或是保留字。组名称不区分大小写,最多可以有64个字符长。

  • 每个组有一个类型,这是SYSTEM用户。资源组类型影响范围的优先级值分配给组,为后面介绍。此属性与差异在允许优先使系统线程被确定为保护他们免受CPU资源对用户线程争用。

    系统和用户线程对应于后台和前台线程在性能模式上市threads

这些属性是在资源组创建时间的定义,可以修改之后的任何时间:

  • CPU亲和力是虚拟的CPU资源组可以使用。亲和力可以是任何非空子集可用的CPU。如果一个团体没有亲和力,它可以使用所有可用的CPU。

  • 线程的优先级是分配给资源组线程的执行优先级。优先级值的范围从20(最高优先级)到19(最低优先级)。默认的优先级是0,对系统和用户组。

    系统允许用户组组比一个更高的优先级,确保用户线程不会比系统线程优先级更高:

    • 系统资源组,允许优先级范围是20到0。

    • 用户资源组,允许优先级的范围是0到19。

  • 每个组可以启用或禁用,让管理员在线程分配控制。线程可以分配到启用组。

资源组管理

默认情况下,存在一个系统组和一个用户组,命名为SYS_default失误,分别。这些默认组不能降低,属性不能被修改。每个默认组没有CPU亲和力和优先级0。

新创建的系统和用户线程被分配到SYS_default失误好了

用户定义资源组,所有的属性都在集团创作的时间分配。在一组已经建立,它的属性可以修改,除了名字和类型属性。

创建和管理用户定义的资源组,使用这些SQL语句:

这些陈述的要求RESOURCE_GROUP_ADMIN特权

管理资源组分配,使用这些能力:

这些操作要求RESOURCE_GROUP_ADMINRESOURCE_GROUP_USER特权

资源组定义存储在resource_groups数据字典表使集团坚持在服务器重新启动。因为resource_groups是数据字典的一部分,它不是由用户直接访问。资源组的信息可使用INFORMATION_SCHEMA.RESOURCE_GROUPS,这是对数据字典表的视图实现。看到24.19节,“information_schema resource_groups表”

最初,该RESOURCE_GROUPS这些行描述表的默认组:

MySQL的&#62;SELECT * FROM INFORMATION_SCHEMA.RESOURCE_GROUPS\G*************************** 1。行*************************** resource_group_name:usr_default resource_group_type:userresource_group_enabled:1 vcpu_ids:0-3 thread_priority:0 *************************** 2。行*************************** resource_group_name:sys_default resource_group_type:systemresource_group_enabled:1 vcpu_ids:0-3 thread_priority:0

这个THREAD_PRIORITY值为0,表示默认的优先级。这个vcpu _ IDS值显示的范围包括所有可用的CPU。对于默认组,显示的值取决于系统上的MySQL服务器运行。

早期的讨论中提到的一个场景涉及一个资源组命名Batch管理,不需要执行批处理作业优先执行。要创建这样的一个群体,用类似这样的语句:

CREATE RESOURCE GROUP Batch  TYPE = USER  VCPU = 2-3            -- assumes a system with at least 4 CPUs  THREAD_PRIORITY = 10;

为了验证资源组创建为预期,检查RESOURCE_GROUPS

MySQL的&#62;SELECT * FROM INFORMATION_SCHEMA.RESOURCE_GROUPSWHERE RESOURCE_GROUP_NAME = 'Batch'\G*************************** 1。行*************************** resource_group_name:批resource_group_type:userresource_group_enabled:1 vcpu_ids:2-3 thread_priority:10

如果THREAD_PRIORITY值是0而不是10,检查资源组的限制,看是否你的平台或系统配置限制的资源组的能力。

分配一个线程的Batch组,这样做:

设置资源组批thread_id

此后,在指定的线程执行的语句Batch集团资源

如果一个会话的当前线程应该在Batch组,在会话中执行此语句:

设置资源组批;

此后,在会话语句执行Batch集团资源

执行一个语句使用Batch组,使用resource_group优化提示:

INSERT /*+ RESOURCE_GROUP(Batch) */ INTO t2 VALUES(2);

分配给线程Batch其资源执行组,可以修改为所需的:

  • 有时当系统高负荷,减少CPU分配到组,降低其优先级,或(如图所示)两:

    ALTER RESOURCE GROUP Batch
      VCPU = 3
      THREAD_PRIORITY = 19;
    
  • 有时当系统负载较轻时,增加CPU的数量分配到组,提高它的优先级,或(如图所示)两:

    ALTER RESOURCE GROUP Batch
      VCPU = 0-3
      THREAD_PRIORITY = 0;
    

资源组的复制

资源组管理本地服务器对它发生。资源组SQL语句修改的resource_groups数据字典表不写入二进制日志,则不复制。

资源组的限制

在一些平台或MySQL服务器的配置,资源组是不可用或有局限性:

  • 如果安装了线程池的插件资源组是不可用的。

  • 资源组是不可用在MacOS,没有提供API绑定CPU线程。

  • 在FreeBSD和Solaris,资源组线程优先级被忽略。(有效的,所有的线程运行在优先级0.)试图改变一个警告优先的结果:

    mysql> ALTER RESOURCE GROUP abc THREAD_PRIORITY = 10;
    Query OK, 0 rows affected, 1 warning (0.18 sec)
    
    mysql> SHOW WARNINGS;
    +---------+------+-------------------------------------------------------------+
    | Level   | Code | Message                                                     |
    +---------+------+-------------------------------------------------------------+
    | Warning | 4560 | Attribute thread_priority is ignored (using default value). |
    +---------+------+-------------------------------------------------------------+
    
  • 在Linux中,资源组线程优先级被忽略,除非CAP_SYS_NICE能力集。MySQL软件包安装的Linux系统中应设置此功能。使用压缩的安装焦油文件的二进制分发或从源的CAP_SYS_NICE能力可以手动设置使用setcap命令,指定的路径名mysqld可执行文件(这需要sudo接入)。你可以用check the能力getcap。。。。。。。例如:

    shell> sudo setcap cap_sys_nice+ep ./bin/mysqld
    shell> getcap ./bin/mysqld
    ./bin/mysqld = cap_sys_nice+ep
    
    重要

    如果手动使用setcap是必需的,它必须在每次重新安装完成。

  • 在Windows中,在五个线程优先级的线程运行。资源组线程优先级范围-在下面的表格中显示20到19的地图上那些水平。

    表8.3资源组线程优先级在Windows

    优先权的范围Windows priority level
    - 20 - 10THREAD_PRIORITY_HIGHEST
    - 9 - 1THREAD_PRIORITY_ABOVE_NORMAL
    THREAD_PRIORITY_NORMAL
    1到10THREAD_PRIORITY_BELOW_NORMAL
    11到19THREAD_PRIORITY_LOWEST

8.13性能测试(基准)

测量性能,考虑以下因素:

  • 无论你是在一个安静的测量系统的一个单一的操作速度,或一组操作(一个工作量经过一段时间的作品)。简单的测试,通常测试如何改变一个方面(配置设置,索引表、查询中的SQL语句的集合)性能的影响。基准测试通常是长时间运行的性能测试及精心的结果可能决定高层选择如硬件和存储配置,或如何尽快升级到一个新的MySQL版本。

  • 为标杆,有时你必须模拟一个沉重的工作量,得到一个准确的图片数据库。

  • 性能取决于很多不同的因素,几个百分点的差异可能不是一个决定性的胜利有所不同。结果可能会改变对你的测试在不同的环境。

  • 某些MySQL功能帮助或不帮助性能取决于工作量。为了完整性,总是测试性能与功能的开启和关闭。尝试每个工作量的最重要的特征是自适应哈希索引InnoDB

这一部分的进展从简单直接的测量技术,一个开发人员可以做,到更复杂的问题,需要更多的专业知识来执行和解释结果。

8.13.1企业测量表达式和函数的速度

衡量一个特定的MySQL表达式或函数调用的速度,BENCHMARK()函数的使用MySQL客户端程序。它的语法是BENCHMARK(loop_count,expression)。返回值始终为零,但MySQL打印线显示大约多久了执行语句。例如:

mysql> SELECT BENCHMARK(1000000,1+1);
+------------------------+
| BENCHMARK(1000000,1+1) |
+------------------------+
|                      0 |
+------------------------+
1 row in set (0.32 sec)

在Pentium II 400MHz系统得到了这样的结果。这表明,MySQL可以执行1000000个简单的加法公式,系统在0.32秒。

内置的MySQL函数通常是高度优化的,但是可能会有一些例外。BENCHMARK()是找出如果有些功能是你查询的问题是一个非常好的工具。

8.13.2使用您自己的基准

测试你的应用和数据库找出瓶颈在哪里。固定一个瓶颈之后(或更换一笨蛋模块),你可以找出下一个瓶颈。即使您的应用程序的整体性能,目前是可以接受的,你至少应该让每一个瓶颈的计划并决定如何解决它,如果有一天你真的需要额外的性能。

一个免费的基准测试套件是一个开放源代码的数据库基准测试程序,可在osdb.sourceforge.net http:/ / /

对于一个只有当系统负荷严重,发生问题是很常见的。我们有很多客户与我们联系他们时,(测试)系统在生产遇到的负载问题。在大多数情况下,性能问题是由于基础数据库的设计问题(例如,表扫描的不好,在高负荷下)或问题与操作系统或库。大多数时候,这些问题就会解决容易得多,如果系统已经不在生产。

为了避免这样的问题,你的整个应用程序中可能出现的最坏的基准负载下:

这些程序或软件包能使系统崩溃,所以一定要使用它们只在你的开发系统。

8.13.3测量性能与performance_schema

你可以查询中的表performance_schema数据库查看实时信息关于您的服务器的性能特点和应用运行。看到第25章,MySQL性能模式详情

8检查线程信息

当你试图了解你的MySQL服务器是干什么的,它可以帮助检查进程列表,这是当前正在执行的线程在服务器设置。进程列表信息可从这些来源:

访问threads不需要一个互斥体和对服务器性能的影响最小。INFORMATION_SCHEMA.PROCESSLISTSHOW PROCESSLIST有负面的绩效后果是因为他们需要一个互斥。threads也对后台线程信息,这INFORMATION_SCHEMA.PROCESSLISTSHOW PROCESSLIST不。这意味着,threads可用于监视活动的其他线程的信息来源不。

你可以随时查看自己的线程信息。查看线程执行其他帐户信息,您必须PROCESS特权

每个进程列表条目包含几条信息:

  • Id与线程关联的客户端标识符的连接。

  • User主机表明与线程关联的帐户。

  • db对线程的默认数据库,或无效的如果是没有选择的

  • Command状态说明有哪些线程正在做。

    大多数州对应很快行动。如果一个线程保持在一个给定的数秒的状态,有可能是一个需要研究的问题。

  • Time表明多久线程已在其当前状态。当前时间线的概念,在某些情况下可能会改变:线程可以改变时间SET TIMESTAMP = value。一个线程在一个奴隶,是处理从主事件线程运行,时间设置的时间在事件的发现以及由此反映出当前时间的主人而不是奴隶。

  • Info包含该语句的线程中执行文本,或无效的如果不执行一个。默认情况下,此值只包含第一个字符的声明。查看完整的语句,使用SHOW FULL PROCESSLIST

  • 这个sys图式processlist的观点,提出从信息表现模式threads在一个更方便的格式表:第26.4.3.22,“列表和列表视图X美元”

  • 这个sys图式session的观点,提出了关于用户会话的信息(如系统图式processlist看来,但后台进程过滤掉):第26.4.3.33,“会话和X $ SESSION的看法”

下面列出了可能的Command值,并状态按类别值。一些这些价值的意义是不言而喻的。对于其他人,提供额外的描述。

8.14.1公司螺纹指令值

一个线程可以有下列Command价值观:

  • Binlog Dump

    这是发送二进制日志内容从服务器在主服务器的一个线程。

  • Change user

    线程正在执行一个改变用户操作。

  • Close stmt

    线程是关闭一个事先准备好的声明。

  • Connect

    复制从连接到它的主人。

  • Connect Out

    复制从连接到它的主人。

  • Create DB

    线程正在执行创建数据库的操作。

  • Daemon

    这个线程的服务器内部,不是一个线程服务一个客户端连接。

  • Debug

    线程是生成调试信息

  • Delayed insert

    线程是一个延迟插入处理程序。

  • Drop DB

    线程是执行删除数据库操作。

  • Error

  • Execute

    线程正在执行一个事先准备好的声明。

  • Fetch

    线程正在执行一个事先准备好的声明中取结果。

  • Field List

    线程检索表的列信息

  • Init DB

    线程是选择一个默认的数据库。

  • Kill

    线程是杀害另一个线程。

  • Long Data

    该线程在执行一个事先准备好的声明结果检索长数据。

  • Ping

    该线程正在处理服务器ping请求。

  • Prepare

    线程正在准备一份准备好的声明。

  • Processlist

    线程是生产服务器的线程信息。

  • Query

    线程正在执行一个语句。

  • Quit

    线程终止

  • Refresh

    线程是刷新表,日志,或缓存,或复位状态变量或复制服务器信息。

  • Register Slave

    线程是注册服务器

  • Reset stmt

    线程是将事先准备好的声明。

  • Set option

    线程设置或重置客户端执行语句的选择。

  • Shutdown

    线程关闭服务器

  • Sleep

    线程正在等待客户端发送一个新的声明,它。

  • Statistics

    线程是生产服务器的状态信息。

  • Table Dump

    线程发送表的内容从服务器。

  • Time

    未使用的

8.14.2通用线程状态

下面的列表描述了线程State这与一般的查询处理,而不是更多的专业活动,如复制值。许多这些仅用于在服务器上发现的bug。

  • After create

    这发生在线程创建一个表(包括内部临时表),在创建表,函数结束。这种状态是即使表不可能由于一些错误创建使用。

  • Analyzing

    当计算MyISAM表的主要分布(例如,为ANALYZE TABLE

  • checking permissions

    线检查服务器是否有权限执行该语句。

  • Checking table

    线程正在执行表检查操作。

  • cleaning up

    线程处理一个命令,并准备释放内存和重置某些状态变量。

  • closing tables

    线程是刷新改变表的数据到磁盘并关闭所使用的表。这应该是一个快速的操作。如果没有,证明你没有一个完整的磁盘和磁盘不是很重的使用。

  • converting HEAP to ondisk

    线程是从一个内部临时表MEMORY为磁盘上的表

  • copy to tmp table

    线程正在处理一个ALTER TABLE声明。这种状况发生在新表结构已经建立,但在数据被复制到它。

    在这个国家的一个线程,性能架构可以用来获得对复制操作的进度。看到第25.11.5,“表现图式阶段事件表”

  • Copying to group table

    如果一个语句有不同ORDER BY标准的行进行排序的组和复制到一个临时表。

  • Copying to tmp table

    服务器复制到一个临时表在内存中。

  • altering table

    服务器的过程中,执行到位ALTER TABLE

  • Copying to tmp table on disk

    服务器复制到一个临时表在磁盘上。临时结果集已经变得太大(见第8.4.4,“MySQL”使用内部临时表)。因此,线程正在将临时表从内存到磁盘的格式来保存记忆。

  • Creating index

    线程正在处理ALTER TABLE ... ENABLE KEYS对于一个MyISAM

  • Creating sort index

    线程正在处理SELECT这是解决使用内部临时表。

  • creating table

    线程是创建表。这包括创建临时表。

  • Creating tmp table

    线程被创建在内存或磁盘上的临时表。如果表是建立在内存但后来被转换为一个磁盘上的表,在运行状态将Copying to tmp table on disk

  • committing alter table to storage engine

    服务器已经完成了一个地方ALTER TABLE和正在实施的结果

  • deleting from main table

    服务器正在执行多表删除的第一部分。这是删除只从第一个表,节约列和偏移量用来删除从其他(参考)表。

  • deleting from reference tables

    服务器正在执行多表删除的第二部分,并从其他表中删除匹配的行。

  • discard_or_import_tablespace

    线程正在处理一个ALTER TABLE ... DISCARD TABLESPACE好的进出口图声明

  • end

    这发生在年底之前清理ALTER TABLECREATE VIEWDELETEINSERTSELECT,或UPDATE声明.

  • executing

    线程开始执行语句

  • Execution of init_command

    线程在执行语句的值init_command系统变量

  • freeing items

    线程已执行的命令。这种状况通常是其次cleaning up

  • FULLTEXT initialization

    服务器正在准备进行自然语言全文检索。

  • init

    这之前发生的初始化ALTER TABLEDELETEINSERTSELECT,或UPDATE声明.服务器在这种状态下进行的行动包括冲洗的二进制日志和InnoDB日志

    对于end状态,可能会发生下列操作:

    • 写一个事件的二进制日志

    • 释放内存缓冲区,包括斑点

  • Killed

    有人发出了一个KILL语句的线程和它应该放弃下一次检查kill标志。旗帜在MySQL中各主要回路的检查,但在某些情况下,该线程可能会死的很短的时间。如果线程被其他线程锁定,杀死需尽快生效,其他线程释放锁。

  • Locking system tables

    线程试图锁定一个系统表(例如,一个时区或日志表)。

  • logging slow query

    线程是语句写入慢查询日志。

  • login

    初始状态为一个连接线程直到客户端已经成功验证。

  • manage keys

    服务器启用或禁用索引表。

  • NULL

    this state is used for theSHOW PROCESSLIST状态

  • Opening system tables

    线程正试图打开一个系统表(例如,一个时区或日志表)。

  • Opening tables

    线程正试图打开一个表。这应该是非常快的过程,除非一些防止开放。例如,一个ALTER TABLELOCK TABLE语句可以防止打开表直到语句完成。有必要检查你的table_open_cache值足够大

    for the system表,Opening system tables国家是用来代替

  • optimizing

    服务器执行查询的初步优化。

  • preparing

    这种状况出现在查询优化。

  • Purging old relay logs

    线程是消除不必要的中继日志文件。

  • query end

    这种状态发生后处理查询,但在freeing items状态

  • Receiving from client

    服务器从客户端读取一个数据包。

  • Removing duplicates

    查询是使用SELECT DISTINCT在这样一种方式,MySQL不能优化了独特的运作处于初期阶段。正因为如此,MySQL需要一个额外的阶段,在将结果发送到客户端之前删除所有重复的行。

  • removing tmp table

    螺纹加工后去除内部临时表SELECT声明。这种状态是不是如果没有临时表创建使用。

  • rename

    线程是重命名表

  • rename result table

    线程正在处理一个ALTER TABLE声明中,创建新的表,并且重命名它来代替原有的表。

  • Reopen tables

    线程获得了表锁,但是发现获得锁的表结构修改后。它释放锁,关闭表,并试图重新打开它。

  • Repair by sorting

    修复代码是使用分类来创建索引。

  • preparing for alter table

    服务器正在准备执行到位ALTER TABLE

  • Repair done

    线程已完成修复一个多线程MyISAM

  • Repair with keycache

    修复代码以创建键逐个通过索引缓存。这是远低于Repair by sorting

  • Rolling back

    线程回滚事务

  • Saving state

    MyISAM表操作,如修复或分析,线程保存一个新表的状态的。我文件头。状态信息包括的行数,AUTO_INCREMENT计数器,以及关键的分布。

  • Searching rows for update

    线程正在进行第一阶段找到所有匹配行之前更新。这是必须的如果UPDATE变化的指标,是用来查找相关行。

  • Sending data

    线程正在读取和处理的行为SELECT声明,并发送数据到客户端。因为在这个国家发生的操作会执行大量的磁盘访问(读取),它往往是运行时间最长的国家在一个给定的查询时间。

  • Sending to client

    服务器写数据包到客户端。

  • setup

    线程是开始ALTER TABLE运营

  • Sorting for group

    线程正在执行一种满足GROUP BY

  • Sorting for order

    线程正在执行一种满足ORDER BY

  • Sorting index

    线程排序更有效的访问在一个索引页MyISAM表的优化操作

  • Sorting result

    对于一个SELECT声明,这是类似的创建排序索引nontemporary,but for表。

  • statistics

    服务器计算统计开发一个查询执行计划。如果一个线程在这个国家很长一段时间,服务器的磁盘可能在执行其他工作。

  • System lock

    线程已被称为mysql_lock_tables()和线程状态尚未更新自。这是一个很一般的状态,可以有很多原因。

    例如,线程正在请求或者等待一个内部或外部的系统表锁。这可以发生在InnoDB等待期间执行的表级锁LOCK TABLES。如果这个状态是由外部锁的请求引起的,你用不多mysqld这是访问同一个服务器MyISAM表,您可以禁用与外部系统锁--skip-external-locking选项然而,外部锁定默认是禁用的,所以此选项将不起任何作用。为SHOW PROFILE,这种状态意味着线程正在请求锁(不等待)。

    for the system表,Locking system tables国家是用来代替

  • update

    线程是准备开始更新表。

  • Updating

    线程是寻找行更新,更新。

  • updating main table

    服务器正在执行多表更新的第一部分。这是只从第一个表中更新,节省列和偏移量用来更新其他(参考)表。

  • updating reference tables

    服务器正在执行多表更新的第二部分,并从其他表中更新匹配的行。

  • User lock

    线程正在请求或者等待一个咨询请求锁定一个GET_LOCK()呼叫。为SHOW PROFILE,这种状态意味着线程正在请求锁(不等待)。

  • User sleep

    线程调用SLEEP()呼叫

  • Waiting for commit lock

    FLUSH TABLES WITH READ LOCK是在等待一个承诺锁

  • Waiting for global read lock

    FLUSH TABLES WITH READ LOCK等待一个全局读锁或全球read_only系统变量设置

  • Waiting for tables

    该线程得到通知,底层表结构已经发生变化,需要重新打开数据表来获取新的结构。然而,重新打开表,必须等到所有其他线程关闭这个表。

    这个通知发生,如果另一个线程使用FLUSH TABLES或下列问题上表陈述:冲洗表tbl_nameALTER TABLERENAME TABLEREPAIR TABLEANALYZE TABLE,或OPTIMIZE TABLE

  • Waiting for table flush

    线程正在执行FLUSH TABLES并等待所有线程关闭他们的桌子,或线程得到通知,底层表结构已经发生变化,需要重新打开数据表来获取新的结构。然而,重新打开表,必须等到所有其他线程关闭这个表。

    这个通知发生,如果另一个线程使用FLUSH TABLES或下列问题上表陈述:冲洗表tbl_nameALTER TABLERENAME TABLEREPAIR TABLEANALYZE TABLE,或OPTIMIZE TABLE

  • Waiting for lock_type lock

    服务器正在等待请求THR_LOCK从元数据锁子锁或锁在那里lock_type指示锁的类型

    此状态指示一个等待THR_LOCK

    • Waiting for table level lock

    这些表明一个元数据锁等待:

    • Waiting for event metadata lock

    • Waiting for global read lock

    • Waiting for schema metadata lock

    • Waiting for stored function metadata lock

    • Waiting for stored procedure metadata lock

    • Waiting for table metadata lock

    • Waiting for trigger metadata lock

    有关表锁的指标信息,看8.11.1节,“内锁法”。关于元数据锁定信息,看第8.11.4,“元数据锁定”。看这锁阻塞的锁请求,使用性能模式锁定表描述第25.11.12,绩效模式锁表”

  • Waiting on cond

    一个普通的状态,线程等待一个条件为真。没有特定的状态信息是可用的。

  • Writing to net

    服务器写一个网络数据包。

8.14.3复制主线程状态

下面的列表显示了你可以看到的最常见的状态State对于主人的柱binlog转储线如果你没有看到Binlog Dump在主服务器的线程,这意味着复制不运行;即,没有奴隶当前连接。

  • Finished reading one binlog; switching to next binlog

    线程已读完一个二进制日志文件,打开下一个发送到奴隶。

  • Master has sent all binlog to slave; waiting for more updates

    线程已从二进制日志中读取所有剩余的更新和发送他们的奴隶。线程是现在闲置,等待新的事件出现在从主发生新的更新所产生的二进制日志。

  • Sending binlog event to slave

    Binary Logs Conco of事件,一个事件通常是一个更新,加上一些其他的信息。线程读取二进制日志事件,现在将它发送到奴隶。

  • Waiting to finalize termination

    一个很简单的状态为线程停止时。

8.14.4复制从I/O线程状态

下面的列表显示在看到你最常见的状态State对于一个从服务器I/O线柱。这种状态也出现在slave_io_state列显示SHOW SLAVE STATUS,所以可以利用声明发生的一个很好的观点。

  • Checking master version

    一个国家发生的非常简要,后主建立连接。

  • Connecting to master

    该线程正在尝试连接到主。

  • Queueing master event to the relay log

    线程读取事件并复制到中继日志,SQL线程可以处理它。

  • Reconnecting after a failed binlog dump request

    正尝试重新连接到主

  • Reconnecting after a failed master event read

    正尝试重新连接到主。当连接建立起来,国家成为Waiting for master to send event

  • Registering slave on master

    一个国家发生的非常简要的后主建立连接。

  • Requesting binlog dump

    一个国家发生的非常简要,后主建立连接。线程发送到主为其二进制日志的内容要求,从要求的二进制日志文件的名称和位置。

  • Waiting for its turn to commit

    一个国家时,奴隶的线程正在等待工作线程提交如果老slave_preserve_commit_order启用

  • Waiting for master to send event

    线程已连接到主并等待到二进制日志事件。这会持续很长一段时间如果掌握闲置。如果等待时间slave_net_timeout秒,超时。在这一点上,线程认为连接被打破,尝试重新连接。

  • Waiting for master update

    在初始状态Connecting to master

  • Waiting for slave mutex on exit

    一个国家发生简单的线程停止。

  • Waiting for the slave SQL thread to free enough relay log space

    你使用一个非零的relay_log_space_limit价值,和中继日志已经足够大,他们的总大小超过此值。I/O线程等待直到SQL线程释放足够的空间通过处理中继日志的内容,可以删除一些中继日志文件。

  • Waiting to reconnect after a failed binlog dump request

    如果二进制日志转储请求失败(由于断开),线程进入这种状态而睡,然后试图重新定期。重试之间的间隔可以指定使用的CHANGE MASTER TO声明

  • Waiting to reconnect after a failed master event read

    阅读时出现错误(由于断开)。线程睡眠的数秒CHANGE MASTER TO声明(默认为60)在试图重新连接。

8.14.5 SLAVE端状态

下面的列表显示了你可以看到的最常见的状态State对于一个从服务器,SQL线程列:

  • Killing slave

    线程正在处理STOP SLAVE声明

  • Making temporary file (append) before replaying LOAD DATA INFILE

    线程正在执行一个LOAD DATA INFILE声明并添加数据到一个临时文件包含的数据从奴隶将读取的行。

  • Making temporary file (create) before replaying LOAD DATA INFILE

    线程正在执行一个LOAD DATA INFILE声明并创建一个临时数据文件从奴隶将读取的行。这种状态只能是在最初的遭遇LOAD DATA INFILE语句被记录由主运行MySQL的MySQL 5.0.3版本低于。

  • Reading event from the relay log

    线程读取中继日志事件,事件可以被处理。

  • Slave has read all relay log; waiting for more updates

    线程处理在中继日志文件的所有事件,并正在等待I/O线程写新事件中继日志。

  • Waiting for an event from Coordinator

    使用多线程的奴隶(slave_parallel_workers大于1),其中一个奴隶工作线程正在等待的线程事件协调员。

  • Waiting for slave mutex on exit

    一个很简单的状态为线程停止时。

  • Waiting for Slave Workers to free pending events

    这个等待的动作发生时,事件处理的工人的总大小超过的大小slave_pending_jobs_size_max系统变量。协调恢复调度时的大小低于该限制。只有当这种状态出现slave_parallel_workers设置大于0

  • Waiting for the next event in relay log

    在初始状态Reading event from the relay log

  • Waiting until MASTER_DELAY seconds after master executed event

    SQL线程读取事件不过是等待从延时失效。这种延迟设置的MASTER_DELAY选择CHANGE MASTER TO

这个Info对于SQL线程列可以显示声明全文。这表明线程读取中继日志事件,从中提取的语句,可以执行它。

8.14.6复制从连接线程状态

这些线程状态出现在复制奴隶但连接线程相关联的,不是与I/O或SQL线程。

  • Changing master

    线程正在处理CHANGE MASTER TO声明

  • Killing slave

    线程正在处理STOP SLAVE声明

  • Opening master dump table

    This occurs后进行Creating table from master dump

  • Reading master dump table data

    This occurs后进行Opening master dump table

  • Rebuilding the index on master dump table

    This occurs后进行Reading master dump table data

8.14.7事件调度线程的状态

这些国家发生的事件调度线程,被创建的线程来执行预定的事件,或线程终止程序。

  • Clearing

    调度线程或线程正在执行一个事件终止和即将结束。

  • Initialized

    调度线程或线程会执行一个事件已初始化。

  • Waiting for next activation

    调度程序有一个非空的事件队列,但接下来的活化是未来。

  • Waiting for scheduler to stop

    线程发出SET GLOBAL event_scheduler=OFF是等待调度程序停止

  • Waiting on empty queue

    调度程序的事件队列是空的,它正在睡觉。