当前位置: 首页 > news >正文

反诈app开发公司asp网站 seo

反诈app开发公司,asp网站 seo,做网站需要公司资料吗,wordpress多个文章页引言 本博客大部分内容翻译自MySQL 官网 Understanding the Query Execution Plan 专题。另外有一些补充#xff0c;则来自于网课以及《高性能MySQL#xff08;第三版#xff09;》。 根据我们的表、字段、索引、以及 where 子句中的条件等信息#xff0c;MySQL 优化器会…引言 本博客大部分内容翻译自MySQL 官网 Understanding the Query Execution Plan 专题。另外有一些补充则来自于网课以及《高性能MySQL第三版》。 根据我们的表、字段、索引、以及 where 子句中的条件等信息MySQL 优化器会考虑各种技术来更高效地执行查找。一个大表中的查找不一定要读取所有记录多表连接也不一定需要比较每条联合记录。优化器选择的执行最优查询的操作集称为“查询执行计划”也可以说是 EXPLAIN 计划。我们的目标就是找到那些可以将查询优化地更好的点然后通过学习 SQL 语法和索引等技术来改善执行计划。 一、EXPLAIN 介绍 EXPLAIN 语句提供了 MySQL 如何执行语句的信息 1、MySQL5.6 之后 EXPLAIN 可以和 SELECT DELETE INSERT REPLACE UPDATE 语句等一起工作 2、当 EXPLAIN 和一个可解释的语句一起使用时MySQL 就会展示来自优化器的关于语句执行计划的信息。即MySQL 会解释它将会怎样执行语句包括表是如何连接的以什么方式排序的等信息。 3、When EXPLAIN is used with FOR CONNECTION connection_id  rather than an explainable statement, it displays the execution plan for the statement executing in the named connection.这句暂不翻译 4、对于 SELECT 语句 EXPLAIN 提供了额外的执行计划信息可以用 SHOW WARNINGS 来查看。参考Section 8.8.3, “Extended EXPLAIN Output Format”. 5、EXPLAIN对于检查涉及分区表的查询非常有用。参考Section 22.3.5, “Obtaining Information About Partitions”. 6、FORMAT 选项可以用于选择输出格式。TRADITIONAL 以表格的形式展示。如果没有指定 FORMAT 选项TRADITIONAL 就是默认的。JSON 格式会以 json 格式展示 EXPLAIN 信息。例如EXPLAIN FORMAT JSON SELECT... 。 在 EXPLAIN 的帮助下你可以清楚的知道为了让查询变得更快该在哪里给表添加索引。你也可以知道优化器是否以最佳的顺序连接各个表。为了让优化器使用 SELECT 语句中表的命名顺序连接各表以 SELECT  STRAIGHT_JOIN(而不是SELECT)开头即可。参考Section 13.2.9, “SELECT Statement”但是STRAIGHT_JOIN 可能会妨碍索引的使用因为它禁用了半连接转换because it disables semijoin transformations. 。参考Section 8.2.2.1, “Optimizing Subqueries, Derived Tables, and View References with Semijoin Transformations”. 优化器跟踪The optimizer trace有时可能提供与 EXPLAIN 互补的信息。但是优化器跟踪的格式和内容会受不同版本的影响。更多细节参考MySQL Internals: Tracing the Optimizer. 如果你对本应该使用索引而没有用到索引的情况感到疑惑执行一下 ANALYZE TABLE 来更新表统计信息。例如列的基数cardinality of keys这会影响优化器做出的选择。参考Section 13.7.2.1, “ANALYZE TABLE Statement”. 注意 EXPLAIN 还可以用来获取表的列的信息。 EXPLAIN  tb1_name  与  DESCRIBE  tb1_name  、 SHOW  COLUMNS  FROM  tb1_name  是等价的。 更多信息参考Section 13.8.1, “DESCRIBE Statement”和  Section 13.7.5.5, “SHOW COLUMNS Statement”。 二、EXPLAIN 的输出格式 EXPLAIN会为 select 语句中的每张表返回一行信息。并会以MySQL处理语句时读取这些表的顺序罗列它们。 MySQL 解决所有 join 的方法是使用一个“嵌套循环关联”的方法。也就是说MySQL会从第一张表中读取一条记录然后找到第二张表中与之匹配的记录然后再找第三张表依此类推。当所有的表处理完毕MySQL会输出查询的列并回溯表列表table list直到找到一个有更多行的表译者注连接表的时候主表查询出的记录往往是最多的从主表开始关联查询再回溯到主表可能官网想表达的是这个意思。下一条记录会从该表中读取并且继续处理下一张表。 EXPLAIN 输出包含了分区信息partitions 列。同样对于 SELECT 语句EXPLAIN 会生成扩展信息只要在 EXPLAIN 执行完成后直接执行 SHOW WARNINGS 即可。参考Section 8.8.3, “Extended EXPLAIN Output Format” 注意 旧的MySQL版本中, 分区和扩展信息使用 EXPLAIN PARTITIONS 和 EXPLAIN EXTENDED 输出。这些语法依然向后兼容但是分区和扩展输出现在默认都是开启的了。所以 PARTITIONS 和 EXTENDED 关键字完全多余。未来版本也会移除的。 不可以在EXPLAIN语句中同时使用 PARTITIONS 和 EXTENDED 关键字。另外哪一个都不能和 FORMAT 选项一起使用。 MySQL Workbench 译者注这是一款由 MySQL 官方出品的类似 Navicat 的数据库管理工具有一个 Visual Explain 功能可以提供可视化的 EXPLAIN 输出信息。参考Tutorial: Using Explain to Improve Query Performance. 2.1 EXPLAIN 输出字段EXPLAIN Output Columns 这一节描述了 EXPLAIN 的输出字段。后面的两节则提供了更多的关于 type 和 Extra 字段的信息。 EXPLAIN输出的每一行都对应一张表。下面的表提供了EXPLAIN的输出字段第一列是字段名称第二列是当 FORMAT JSON 时的输出字段名称 ColumnJSON NameMeaningidselect_idThe SELECT identifier查询idselect_typeNoneThe SELECT type查询类型tabletable_nameThe table for the output row对应的表partitionspartitionsThe matching partitions匹配的分区typeaccess_typeThe join type访问类型possible_keyspossible_keysThe possible indexes to choose可能用到的索引keykeyThe index actually chosen真正被用到的索引key_lenkey_lengthThe length of the chosen key用到的索引长度refrefThe columns compared to the index与索引比较的列rowsrowsEstimate of rows to be examined大约要检索的行数filteredfilteredPercentage of rows filtered by table condition按表条件过滤的行的百分比ExtraNoneAdditional information附加信息 1、idJSON 名select_id SELECT 标识符SELECT identifier。这是一个连续的数字用以标识查询中的 SELECT 。如果引用了其他行的联合结果集union result of other rows那么 id 会为 NULL。这种情况下该行的 table 字段会显示为 union M, N 这样的形式表示该行代表了 id 值为 M 和 N 的行的联合the row refers to the union of the rows with id values of M and N 。 重点id 是一个自然数编号如1、2但有时也可以是NULL。如上所述NULL的时候就是引用了一个 UNION 结果集。 当 id 为数字的时候编号大的会先执行。有时候编号会相同相同编号就从上到下执行。 2、select_typeJSON 名无 查询类型。MySQL将查询分为简单和复杂类型复杂类型可分为三大类简单子查询、FROM子查询以及UNION查询。select_type 就是用于区分这三类复杂查询。可选值如下红色标记为常见值 select_type ValueJSON NameMeaningSIMPLENone简单查询没有任何 UNION 或 子查询。PRIMARYNone主查询如果查询中包含任何复杂的子部分那么最外层查询被标记PRIMARY。UNIONNoneUNION 中的第二个或后面的SELECT语句DEPENDENT UNIONdependent (true)UNION 中的第二个或后面的SELECT语句, 依赖于外部查询UNION RESULTunion_result从UNION 的结果获取数据的SELECT。SUBQUERYNoneSELECT子句或WHERE子句中的子查询DEPENDENT SUBQUERYdependent (true)子查询中的第一个 SELECT, 依赖于外层查询DERIVEDNone派生表。FROM子句中的子查询。MySQL会递归执行这些子查询把结果放在临时表里。MATERIALIZEDmaterialized_from_subqueryMaterialized subquery  物化子查询。参考《MySQL高级 —— 查询性能优化》4.1节UNCACHEABLE SUBQUERYcacheable (false)非缓存子查询结果不能被缓存的子查询必须被外部查询的每一行重新求得UNCACHEABLE UNIONcacheable (false)非缓存子查询uncacheable subquery的 UNION 中的第二个或后面的 SELECT SUBQUERY还可以被标记为DEPENDENT SUBQUERY这一般是指SELECT依赖于外层查询发现的数据很可能是依赖于FROM派生表的外层SELECT。参考Section 13.2.10.7, “Correlated Subqueries” 。 DEPENDENT SUBQUERY 的取值与 UNCACHEABLE SUBQUERY由于用户变量等原因 的取值不同。对于 DEPENDENT SUBQUERY 对于来自其外部查询的变量的每组不同值子查询只重新计算一次。而对于 UNCACHEABLE SUBQUERY 对外部查询的每行记录该子查询都会计算一遍。 子查询缓存与缓存中的查询结果缓存不一样具体描述参考 Section 8.10.3.1, “How the Query Cache Operates”。子查询缓存发生在查询执行过程中而查询结果缓存只在查询执行完毕时才会存储结果。 当你在 EXPLAIN 语句中指定了 FORMAT JSON 输出的结果并没有一个对应 select_type 的单独属性query_block 属性对应给定的 SELECT 。与刚才显示的大多数 SELECT 子查询类型等价的属性都是有的并且在合适的时机就会展示。不过并没有与 SIMPLE 和 PRIMARY 等价的 JSON 值。 select_type 属性值对于非 SELECT 语句会展示影响表的语句类型如 DELETE 语句的 select_type 就是 DELETE。 3、tableJSON 名table_name explain 输出的每一行都对应一个表别名或表名。它可以是下面的值中的一个 union M, N : 这一行引用了 id 值为 M 和 N 的表的联合。 derived N : 这一行引用了 id 值为 N 的表所派生的表。派生的表可能是一个结果集比如FROM 子句中的子查询。 subquery N : 这一行引用了 id 值为 N 的物化子查询的结果。参考Section 8.2.2.2, “Optimizing Subqueries with Materialization”. 4、partitionsJSON 名partitions 查询的记录将会在哪个分区中匹配。NULL 代表没有分区表。参考 Section 22.3.5, “Obtaining Information About Partitions”. 5、typeJSON 名access_type 关联类型但更准确的说法是——访问类型换言之就是MySQL决定如何查找表中的行。参考 2.2 节。 6、possible_keysJSON 名possible_keys 该属性可以表明查询中对应表有哪些索引可以使用。注意这个属性完全不依赖于表在 explain 输出中的显示顺序。也就是说以生成的表顺序 possible_keys 中的有些索引可能实际中并不会用到。 如果该属性是 NULL (或者在 JSON 格式中是 undefined )代表没有相关的索引。这时你可能就应该努力通过调试 WHERE 子句来提升你的查询性能检查是否涉及到了一些字段或者适合索引查询的字段。如果有就创建一个合适的索引然后再次通过 EXPLAIN 进行检验。 查看一个表有哪些索引可以使用 SHOW INDEX FROM tbl_name 语句。 7、keyJSON 名key 这一列表示 MySQL 决定采用哪个索引来优化对该表的访问。如果 MySQL 决定使用 possible_keys 中的一个索引去查找记录那么这个索引就会列在 key 属性中。 key 中也会出现 possible_key 中没有出现的索引。发生这种情况很可能是 possible_keys 没有找到适合查询的索引但是所有查询的字段都在索引中。也就是说查询使用了覆盖索引。因此尽管它不用于决定要查询哪些行但却依然可以用于查询字段因为索引扫描依然比行扫描更高效。换句话说possible_keys 揭示了哪一个索引能有助于高效地行查找而 key 显示的是优化采用哪一个索引可以最小化查询成本。 对于InnoDB 即使查询列表中有主键二级索引也可能覆盖所查询的字段因为InnoDB用每个二级索引存储了主键值。如果列是NULL, MySQL就找不到索引来更有效地执行查询。 要强制MySQL使用或忽略在 possiblele_keys 中列出的索引请在查询中使用 FORCE INDEXUSE INDEX 或 IGNORE INDEX 。参考 Section 8.9.4, “Index Hints”. 对于 MyISAM运行 ANALYZE TABLE 可以帮助优化器选择更好的索引。对于 MyISAM 表来说 myisamchk --analyze 也是一样的。参考 Section 13.7.2.1, “ANALYZE TABLE Statement”, 和 Section 7.6, “MyISAM Table Maintenance and Crash Recovery”. 8、key_lenJSON 名key_length 该字段表示 MySQL 在索引里使用的字节数。 因为key_len是通过查找表的定义而被计算出而不是表中的数据因此它显示了在索引字段中可能的最大长度而不是表中数据使用的实际字节数。key_len 的值可以让你判断 MySQL 究竟用到了复合索引的哪几个索引列。如果 key 属性的值为 NULL , 那么 key_len 肯定也是 NULL 。 由于索引的存储格式那些可以为 NULL 的字段的索引长度要比非空字段的索引长度大一些。 MySQL并不总是显示一个索引真正使用了多少。例如如果对一个前缀模式匹配例如 张%执行LIKE查询它会显示列的完整宽度正在被使用。 计算 key_len 的简易方法 int 类型在MySQL中以4个字节存储key_len 为 4如果列值允许为 NULL那么需要 1即 key_len 为 5. double 类型以8个字节存储key_len 为 8如果允许 NULL那么同样 1 即 key_len 为 9. char(n) 定长字符串首先需要看字符集常见的utf8以3个字节存储每个字符gbk用2个latin用1个。key_len 就等于每个字节长度乘以允许最大字符数n如果允许NULLkey_len 也要 1。例如 char(20) DEFAULT NULL编码为utf8 ,那么 key_len 就是 3 × 20 1 61。如果不允许为 NULL 就是60。 varchar(n)变长字符串每个字符utf8为3字节、gbk为2字节、latin为1字节。由于是变长因此 key_len 要 2如果允许 NULL同样 1。其他和 char计算方式一样。例如varchar(20) DEFAULT NULL编码 utf8那么 key_len 就是 3 × 20 2 1 63如果不允许为 NULL就是62。 上面的说明只是单独计算每种列值类型的方法如果是复合索引那么key_len 就是用到的索引列长度和。 9、refJSON 名ref ref 列显示了常量或哪些列与 key 列中的索引进行了比较。只有 type 列是 ref 的时候ref 列才会有值。 简单的说就是 key 中的索引如果与一个常量比较那么 ref 会显示 const如果是与其他表的某个列进行比较那么就会显示该列名。 如果 ref 属性的值是 func 那么用到的值就是某些函数的结果。想要知道是哪个函数在 EXPLAIN 执行后使用 SHOW WARNINGS 查看EXPLAIN 的扩展信息。 函数实际上可能是一个运算符比如算术运算符。 10、rowsJSON 名rows rows 列表示MySQL认为执行查询必须检查的行数。这个数字是内嵌关联循环计划里的循环数目。也就是说它不是最终的结果集里的行数而是MySQL为了找到符合条件的结果集而必须读取的行的平均数。 对于 InnoDB 表这个数是一个估值而且可能并不总是准确的。 11、filteredJSON 名filtered filtered 属性表示被筛选条件过滤掉的记录条数占全表的估计百分比。最大值是100意味着记录全部被过滤掉。从100开始递减的值表示过滤的量在增加。rows 属性表示了需要检查的估计行数rows 乘 filtered 表示了将会被后面的表关联的记录条数。例如如果 rows 是1000filtered 是 50.0050%那么要与后面的表连接的记录条数就是 1000 × 50% 500。 对于filtered 原文的描述是The filtered column indicates an estimated percentage of table rows that will be filtered by the table condition. The maximum value is 100, which means no filtering of rows occurred.  这里面有一个语义上的陷阱即 filtered 究竟表示的是 “被过滤掉的” 还是 “过滤后(留下来)的” 经过本人测试filtered 表示的是前者即 “被过滤掉的” 这样后面的语义也就基本自洽了。而 filtering 则表示 “过滤后留下来的” 。 12、ExtraJSON 名none 这一列显示了关于 MySQL如何处理查询的额外信息。对于不同值的描述参考Extra Information. 或参考下面 2.3 节。 2.2 EXPLAIN type访问类型EXPLAIN Join Types type 属性描述了表之间是如何连接或关联的。在 JSON 格式输出中对应 access_type 属性。下面的列表描述了访问类型顺序从“最理想类型”到“最糟糕的类型” system const eq_ref ref range index ALL 2.2.1 system不常见 表只有一行系统表。是 const 连接类型的一种特殊情况。 2.2.2 const 表最多只有 1 条匹配记录在查询开始时就会读取该表。因为只有一行所以这一行中列的值可以被其他优化器视为常量。const 访问类型非常快因为他们只会被读取一次。MySQL能将这个查询转换为一个常量然后可以高效地将表从连接操作中移除。 const 会在你使用整个主键all parts of a PRIMARY KEY或唯一索引UNIQUE index去比较一个常量的时候用到。在下面的查询中tb1_name 就是一张 const 表 SELECT * FROM tbl_name WHERE primary_key1;SELECT * FROM tbl_nameWHERE primary_key_part11 AND primary_key_part22; 2.2.3 eq_ref 使用这种索引查找MySQL知道最多只返回一条符合条件的记录。它会在所有的索引部分都被用到的时候以及索引是主键或非空唯一索引时出现到它会将它们与某个参考值做比较。MySQL 对于这类访问类型的优化做的非常好因为MySQL知道无须估计匹配行的范围或在找到匹配行后再继续查找。 eq_ref 会在索引列使用 号的时候用到。比较的值可以是一个常量也可以是一个从前表读取的列的表达式。在下面的例子中MySQL 可以使用 eq_ref 类型来处理 ref_table SELECT * FROM ref_table,other_tableWHERE ref_table.key_columnother_table.column;SELECT * FROM ref_table,other_tableWHERE ref_table.key_column_part1other_table.columnAND ref_table.key_column_part21; 2.2.4 ref 这是一种索引访问有时也叫“索引查找”它返回所有匹配某个单个值的行是查找和扫描的混合体。此类索引访问只有当使用非唯一性索引或唯一性索引的非唯一性前缀时才会发生。把它叫做 ref 是因为索引要跟某个参考值相比较。这个参考值可以是一个常数或是来自多表查询的结果值。如果该筛选列可以匹配少量的记录那 ref 还算是一个不错的连接类型。 ref_or_null 是ref 之上的一个变体它意味着MySQL必须在初次查找的结果里进行第二次查找以找出NULL条目。 ref 也可以在索引列使用 或 号的时候被用到。下面的例子MySQL 可以使用 ref 来处理 ref_table SELECT * FROM ref_table WHERE key_columnexpr;SELECT * FROM ref_table,other_tableWHERE ref_table.key_columnother_table.column;SELECT * FROM ref_table,other_tableWHERE ref_table.key_column_part1other_table.columnAND ref_table.key_column_part21; 2.2.5 full_text不常见 这种连接方式会在使用 FULLTEXT 索引的时候用到。 2.2.6 ref_or_null不常见 这种连接方式和 ref 类似除此之外 MySQL 还会额外搜索包含 NULL 值的记录。这种连接类型的优化绝大多数是在处理子查询的时候。在下面的例子中 MySQL 会使用 ref_or_null 来处理 ref_table SELECT * FROM ref_tableWHERE key_columnexpr OR key_column IS NULL; 参考Section 8.2.1.13, “IS NULL Optimization”.  2.2.7 index_merge不常见 这种连接类型表示使用了索引合并优化Index Merge optimization。这种情况下explain 中的 key 属性会罗列出被用到的索引key_len 属性会列出用到的索引的最长的索引部分。参考Section 8.2.1.3, “Index Merge Optimization”. 2.2.8 unique_subquery不常见 这种类型在类似下面的一些使用 IN 的子查询时取代了 eq_ref value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery 只是一个索引查找函数它完全取代了子查询以提高效率。 2.2.9 index_subquery不常见 这种连接类型有点像 unique_subquery 。它取代了 IN 子查询但它只在子查询中有非唯一索引时才会起作用类似下面这样 value IN (SELECT key_column FROM single_table WHERE some_expr) 2.2.10 range  这种连接类型会使用索引查询给定范围内的记录。EXPLAIN 输出中的 key 属性表示了哪个 索引列 被用到。key_len 包含了被用到的最长的索引部分。ref 属性为 NULL。 range 类型会在索引列使用 、、、、、、IS NULL、、BETWEEN、LIKE、或 IN() 任意一种操作符去比较常量的时候被用到。当使用 IN或 OR 列表的时候显示的范围扫描其实并不能和 这类比较符的性能等同虽然它们在EXPLAIN中显示的类型都是 range但是 IN() 列表其实属于等值列表。参考《MySQL高级 —— 高性能索引》6.2 节。 SELECT * FROM tbl_nameWHERE key_column 10;SELECT * FROM tbl_nameWHERE key_column BETWEEN 10 and 20;SELECT * FROM tbl_nameWHERE key_column IN (10,20,30);SELECT * FROM tbl_nameWHERE key_part1 10 AND key_part2 IN (10,20,30); 2.2.11 index index 类型除了会扫描索引树之外其他和 ALL 是一样的。会有两种情况出现 1、如果索引是一个覆盖索引那么这种类型的查询就只会扫描索引树。这种情况下 Extra 属性会显示 Using Index。一个只扫描索引的方式比 ALL 更快这是因为索引数据肯定要比表中数据要少。 2、以索引次序扫描全表。Extra 不会显示 Uses Index。 index 类型的主要优点是避免了排序最大缺点是要承担按索引次序读取整个表的开销。 MySQL 会在查询只用到了单一索引列的时候用到 index 这种类型。 2.2.12 ALL 这就是人们常说的“全表扫描”这种类型会对前面各表的组合记录都进行全表扫描。如果表是第一个没有被标记为 const 的表这通常是不好的在所有其他情况下通常是非常糟糕的。通常你可以通过增加索引来避免 ALL 。但也有例外例如在查询中使用了 LIMIT或在 Extra 列中显示“Using distinct/not exists”。 2.3 EXPLAIN Extra 信息EXPLAIN Extra Information Extra 属性显示了MySQL如何执行查询的额外信息。 2.3.1 Using index 此值表示MySQL将使用覆盖索引以避免访问表。不要把覆盖索引和 type index 访问类型混淆了。 2.3.2 Using where 这意味着MySQL服务器将在存储引擎检索行后再进行过滤。当它读取索引时就能被存储引擎检验因此不是所有带有 WHERE子句的查询都会显示“Using where” 。有时“Using where” 的出现就是一个暗示查询可受益于不同的索引。 2.3.3 Using temporary 这意味着MySQL在对查询结果排序时会使用一个临时表。 2.3.4 Using filesort 这意味着MySQL会对结果使用一个外部索引排序而不是按照索引次序从表里读取行。MySQL有两种文件排序算法两种方式都可以在内存或磁盘上完成。EXPLAIN 不会告诉你 MySQL将使用哪一种文件排序也不会告诉你排序会在内存里还是在磁盘上完成。 2.3.5 Range checked for each record (index map:N) 这个值意味着没有好用的索引新的索引将在连接的每一行上重新估算。N是显示在possible_keys 列中索引的位图并且是冗余的。 2.4 EXPLAIN 输出的解释 EXPLAIN输出可以给你在连接各种表查询的时候一个非常好的指示作用。这会大致告诉你MySQL 在执行查询的时候必须要检查多少行记录。如果你限制了 max_join_size 系统变量那么 EXPLAIN 也会被用来告诉我们一些有用的东西。参考 Section 5.1.1, “Configuring the Server”. 下面的例子显示了多表连接是如何基于 EXPLAIN 提供的信息一点点优化的。 假设你有一个查询语句并且你通过 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.CUSTNAMEFROM tt, et, et AS et_1, doWHERE tt.SubmitTime IS NULLAND tt.ActualPC et.EMPLOYIDAND tt.AssignedPC et_1.EMPLOYIDAND tt.ClientID do.CUSTNMBR; 对于这个例子做出下面的假设 1、比较的列译者注columns being compared实际上指的就是where 子句后面作为筛选条件的列因为往往需要用到 号等操作符因此在官网中一般都被称为被比较的列定义如下 TableColumnData TypettActualPCCHAR(10)ttAssignedPCCHAR(10)ttClientIDCHAR(10)etEMPLOYIDCHAR(15)doCUSTNMBRCHAR(15) 2、表有以下这些索引 TableIndexttActualPCttAssignedPCttClientIDetEMPLOYID (primary key)doCUSTNMBR (primary key) 3、tt 表的 ActualPC 字段不是均匀分布的。 首先在所有优化执行之前 EXPLAIN 语句输出了下面的信息 table type possible_keys key key_len ref rows Extra et ALL PRIMARY NULL NULL NULL 74 do ALL PRIMARY NULL NULL NULL 2135 et_1 ALL PRIMARY NULL NULL NULL 74 tt ALL AssignedPC, NULL NULL NULL 3872ClientID,ActualPCRange checked for each record (index map: 0x23) 因为每张表的连接类型都是 ALL 这表明MySQL 正在生成一张笛卡尔集a Cartesian product也就是表中的每一行都进行了组合。这会花费相当长的时间因为必须检查每个表中行数的乘积。对于这个案例乘积就是74 × 2135 × 74 × 3872 45,268,558,720 行。如果表再大一点你可以想象一下它需要花费多长时间。 这里有个问题如果比较的列被声明以相同的大小和类型那么 MySQL 就可以更高效的使用列上的索引。在这种语境下VARCHAR 和 CHAR 如果被设定为相同的大小那么就被认为是相同的。tt.ActualPC 被声明为 CHAR(10) 而 et.EMPLOYID 声明为 CHAR(15)所以长度不匹配。 为了修复这种列长度的不一致使用 ALTER TABLE 来延长 ActualPC 从 10个字符到15个字符。 mysql ALTER TABLE tt MODIFY ActualPC VARCHAR(15); 现在 tt.ActualPC 和 et.EMPLOYID 都是 VARCHAR(15) 了。再次执行 EXPLAIN 就会得到下面的结果 table type possible_keys key key_len ref rows Extra tt ALL AssignedPC, NULL NULL NULL 3872 UsingClientID, whereActualPC do ALL PRIMARY NULL NULL NULL 2135Range checked for each record (index map: 0x1) et_1 ALL PRIMARY NULL NULL NULL 74Range checked for each record (index map: 0x1) et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1 这依然不够完美但是也稍微好了点rows 的乘积少了 74 倍译者注et 表的 rows 由 74 变为了 1。这一版的执行会在几秒钟完成。 第二处修改可以针对 tt.AssignedPC et_1.EMPLOYID 和 tt.ClientID do.SUTNMBR 这两个比较中有关列长度不匹配的问题。 mysql ALTER TABLE tt MODIFY AssignedPC VARCHAR(15),MODIFY ClientID VARCHAR(15); 这次修改之后EXPLAIN 输出就会变成下面这样 table type possible_keys key key_len ref rows Extra et ALL PRIMARY NULL NULL NULL 74 tt ref AssignedPC, ActualPC 15 et.EMPLOYID 52 UsingClientID, whereActualPC et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1 do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1 此时查询几乎已经优化的足够好了。遗留的问题是默认情况下MySQL 假设 tt.ActualPC 字段上的值是均匀分布的但 tt 表并不是这样的前面的假设。幸运的是要告诉 MySQL 分析列值分布情况是非常简单的你只需要这样做 mysql ANALYZE TABLE tt; 凭借额外的索引信息连接查询已经变得完美EXPLAIN 也变成了如下结果 table type possible_keys key key_len ref rows Extra tt ALL AssignedPC NULL NULL NULL 3872 UsingClientID, whereActualPC et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1 et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1 do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1 EXPLAIN输出中的rows列是来自MySQL连接优化器的猜测。通过将 rows 的乘积与查询返回的实际行数进行比较就可以检查这些数字是否接近实际情况。如果数字与实际查询的行数相差甚远你可以通过在你的 SELECT 语句中使用 STRAIGHT_JOIN 并尝试在 FROM 子句中以不同的顺序罗列所查各表来获取更好的性能。但是STRAIGHT_JOIN 可能会妨碍到索引的使用因为它禁用了半连接转换。参考Section 8.2.2.1, “Optimizing Subqueries, Derived Tables, and View References with Semijoin Transformations”. 在某些情况下当EXPLAIN SELECT与子查询一起使用时可以执行修改数据的语句。参考Section 13.2.10.8, “Derived Tables”. 总结 这篇译文翻译了很长时间断断续续可能有一个月。本篇文章有些地方可能翻译的并不准确因此希望各位可以与原文比较阅读增加理解。 另外本来想在 Extra 部分就结束本篇翻译没想到 MySQL 官网在最后一节给出了一个非常亲民的案例讲解可以让我们一览 EXPLAIN 的常规用法。这一部分也是我认为翻译的比较准确的部分。 因为 EXPLAIN 语句非常重要因此这篇译文我也会经常翻阅加深理解的同时不断纠正文中翻译的不准确或有所偏颇之处同时希望大家能给予意见或建议。 2020-05-29 追加的部分分散在文章的各个小节中主要是在读完《高性能MySQL第三版》的五六章以及附录EXPLAIN的部分对执行计划和一些索引的概念有了更进一步的理解和认识。之前翻译的不是很准确的地方做了校对和润色某些废话也是能删就删我还写了很多关于索引及查询优化相关的文章可以和这些文章一起阅读结合实践并反复回看的话相信一定可以成为MySQL性能优化领域的好手。
http://www.pierceye.com/news/463944/

相关文章:

  • 如何看出网站用dede做的网站百度快照
  • 做网站很难吗五种新型营销方式
  • 个人网站搭建模拟感想江西企业网站建设哪家好
  • 长春企业网站建设网站制作公司相关工作
  • 免费课程网站有哪些兼职网站项目建设报告
  • 建立网站免费dedecms网站地图制作
  • 网页设计公司网站制作做网站最主要是那个一类商标
  • 卫生局网站建设方案网站架构设计英文翻译
  • 学做衣服网站有哪些智能开发平台软件
  • wordpress 下载站插件wordpress清楚所有评论
  • 公司网站建设工作计划网站设置受信任
  • 网站如何做实名验证码深圳企业网站推广
  • 傻瓜式大型网站开发工具餐饮业手机php网站
  • 网站建设小细节图片东阳网站建设yw126
  • 为什么找不到做网站的软件怎么做音乐mp3下载网站
  • 做一个网站需要什么网络营销方式分析论文
  • 可以做3d电影网站企业网站优化应该怎么做
  • 中山做网站联系电话app客户端开发公司
  • 秦皇岛网站推广价钱南京建设网站制作
  • 2018钓鱼网站建设邢台seo公司
  • 深圳建设交易中心网站域名网站建设
  • 做网站色弱可以吗一个网址多少钱
  • 如何查询网站接入信息产品营销网站
  • 常用博客建站程序遂溪网站开发公司
  • 网站开发软件系统安徽通皖建设工程有限公司网站
  • 意派网站开发新手篇做平面常用的网站
  • 广州网站设计费用深圳室内设计师网
  • 有什么可以做兼职的网站吗建设网站的需求分析
  • 专门做进口产品的网站6wordpress赚钱方法
  • 长兴网站建设公司郫县城乡规划建设管理局网站