Mysql优化概述与SELECT where子句优化

    本章说明如何优化MySQL性能并提供示例。优化涉及多个级别的配置,调整和测量性能。根据您的工作角色(开发人员,DBA或两者的组合),您可以在单个SQL语句,整个应用程序,单个数据库服务器或多个联网数据库服务器的级别进行优化。有时您可能会很主动,并提前计划性能,而其他时候,您可能会在问题发生后对配置或代码问题进行故障排除。优化CPU和内存使用率还可以提高可伸缩性,从而使数据库能够处理更多负载而不会降低速度。

1. 优化概述

    数据库性能取决于数据库级别的几个因素,如表、查询和配置设置。这些软件结构会导致在硬件级别上执行CPU和I/O操作,您必须尽可能减少这些操作并使其尽可能高效。在研究数据库性能时,首先学习软件方面的高级规则和指南,并使用时钟时间来衡量性能。当你成为一名专家时,你会学到更多关于内部发生的事情,并开始测量诸如CPU周期和I/O操作之类的事情。
    典型的用户旨在从其现有的软件和硬件配置中获得最佳的数据库性能。高级用户寻找机会改进MySQL软件本身,或者开发自己的存储引擎和硬件设备以扩展MySQL生态系统。

1.1 在数据库级别进行优化

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

  • 表格的结构是否正确?特别是,这些列是否具有正确的数据类型,并且每个表是否都具有适合于该工作类型的列?例如,执行频繁更新的应用程序通常有许多表,但表的列数很少,而分析大量数据的应用程序通常有很少的表,表中的列数很多。
  • 是否有合适的索引来提高查询效率?
  • 您是否为每个表使用了适当的存储引擎,并利用了您使用的每个存储引擎的优势和功能?特别是,事务性存储引擎(如InnoDB)或非事务性存储引擎(如MyISAM)的选择对于性能和可伸缩性非常重要。

注意
    InnoDB是新表的默认存储引擎。实际上,高级 InnoDB性能功能意味着 InnoDB表通常要比简单MyISAM表好,尤其是对于繁忙的数据库。

  • 每个表是否使用适当的行格式?此选择还取决于用于表的存储引擎。特别是,压缩表使用更少的磁盘空间,因此读写数据所需的磁盘I/O更少。压缩可用于具有InnoDB表的各种工作负载,也可用于只读MyISAM表。
  • 应用程序是否使用适当的锁定策略?例如,尽可能允许共享访问,以便数据库操作可以并发运行,并在适当时请求独占访问,以便关键操作获得最高优先级。再次,存储引擎的选择是重要的。InnoDB存储引擎可以在不需要您参与的情况下处理大多数锁定问题,从而在数据库中实现更好的并发性,并减少代码的实验和调整量。
  • 所有用于缓存的内存区域大小是否正确?也就是说,大到可以容纳频繁访问的数据,但不能大到使物理内存过载并导致分页。要配置的主要内存区域是InnoDB buffer池、MyISAM key缓存和MySQL查询缓存。
1.2 在硬件级别进行优化

    随着数据库变得越来越繁忙,任何数据库应用程序最终都会达到硬件极限。DBA必须评估是否有可能调整应用程序或重新配置服务器以避免这些瓶颈,或者是否需要更多的硬件资源。系统瓶颈通常来自以下来源:

  • 磁盘搜索。磁盘查找数据需要花费时间。对于现代磁盘,此操作的平均时间通常小于10毫秒,因此理论上我们可以每秒执行约100次的搜索。这段时间随着新磁盘的使用而缓慢改善,并且很难为单个表进行优化。优化寻道时间的方法是将数据分发到多个磁盘上。
  • 磁盘读写。当磁盘位于正确的位置时,我们需要读取或写入数据。使用现代磁盘,一个磁盘至少可提供10–20MB/s的吞吐量。与查找相比,优化起来更容易,因为您可以从多个磁盘并行读取。
  • CPU周期。当数据位于主存储器中时,我们必须对其进行处理以获得结果。与内存量相比,拥有大表是最常见的限制因素。但是对于小表,速度通常不是问题。
  • 内存带宽。当CPU需要的数据超出CPU缓存的容量时,主内存带宽将成为瓶颈。对于大多数系统来说,这是一个不常见的瓶颈,但是要意识到这一点。
1.3 平衡便携性和性能

    要在可移植的MySQL程序中使用面向性能的SQL扩展,可以在/*! */注释定界符中的语句中包装特定于MySQL的关键字。其他SQL Server忽略注释的关键字。

2. 优化SQL语句

    数据库应用程序的核心逻辑是通过SQL语句执行的,无论是通过解释程序直接发布还是通过API在后台提交。本节中的调整准则有助于加快各种MySQL应用程序的速度。该准则涵盖了读写数据的SQL操作,一般SQL操作的幕后开销以及在特定方案(例如数据库监视)中使用的操作。

2.1 优化SELECT语句

    查询,以SELECT语句的形式执行数据库中的所有查找操作。无论是实现动态网页的亚秒级响应时间,还是缩短时间以生成大量的隔夜报告,调整这些语句都是当务之急。
    除了SELECT语句之外,查询的优化技术还适用于CREATE TABLE…as SELECT、INSERT in to…SELECT和DELETE语句中的WHERE子句等构造。这些语句有额外的性能考虑,因为它们将写操作与面向读的查询操作结合起来。
    优化查询的主要考虑因素是:

  • 为了使慢速SELECT … WHERE查询更快,首先要检查的是是否可以添加索引。在WHERE子句中使用的列上设置索引,以加快计算、筛选和最终检索结果的速度。为了避免浪费磁盘空间,请构造一小组索引,以加快应用程序中使用的许多相关查询。
    索引对于使用join和外键等功能引用不同表的查询尤其重要。您可以使用EXPLAIN语句来确定用于SELECT的索引。
  • 隔离和调整查询中花费时间过多的任何部分,例如函数调用。根据查询的结构,可以对结果集中的每一行调用一次函数,甚至可以对表中的每一行调用一次函数,从而极大地提高了效率。
  • 最小化查询中全表扫描的次数,尤其是对于大表。
  • 通过定期使用 ANALYZE TABLE 语句,使表统计信息保持最新,这样优化器就拥有了构建高效执行计划所需的信息。
  • 了解针对每个表的存储引擎所特有的优化技术、索引技术和配置参数。InnoDB和MyISAM都有一套指导方针来支持和维持查询的高性能。
  • 您可以使用第8.5.3节“优化InnoDB只读事务”中的技术为InnoDB表优化单查询事务。
  • 避免以难以理解的方式转换查询,特别是如果优化器自动执行某些相同的转换。
  • 如果使用基本准则之一不能轻松解决性能问题,请通过阅读EXPLAIN计划并调整索引,WHERE子句,连接子句等来调查特定查询的内部细节 。(当您达到一定的专业水平时,阅读 EXPLAIN计划可能是每个查询的第一步。)
  • 调整MySQL用于缓存的内存区域的大小和属性。由于有效地使用了 InnoDB buffer池, MyISAM键高速缓存和MySQL查询高速缓存,重复查询的运行速度更快,因为第二次及以后都从内存中检索了结果。
  • 即使对于使用缓存区域快速运行的查询,您也可能会进一步优化,以使它们需要更少的缓存,从而使您的应用程序更具可伸缩性。可伸缩性意味着您的应用程序可以处理更多的同时用户,更大的请求等,而不会导致性能大幅下降。
  • 处理锁定问题,其中其他会话同时访问表可能会影响查询速度。
2.1.1 WHERE子句优化

    本节讨论可用于处理WHERE子句的优化。这些示例使用SELECT语句,但相同的优化也适用于DELETE和UPDATE语句中的WHERE子句。
    注意:由于有关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
  • 索引使用的常量表达式只计算一次。
  • 不带WHERE的单个表上的COUNT(*)直接从MyISAM和MEMORY表的表信息中检索。当只与一个表一起使用时,这也适用于任何非空表达式。
  • 提前检测无效的常量表达式。MySQL快速检测到某些SELECT语句是不可能的,并且不返回任何行。
  • 如果不使用GROUP BY或聚合函数(COUNT()、MIN(),等等),HAVING将与WHERE合并。
  • 对于联接中的每个表,构造一个更简单的WHERE,以获得表的快速WHERE求值,并尽快跳过行。
  • 在查询中的所有其他表之前,首先读取所有常量表。常量表可以是以下任意一个:
    • 空表或具有一行的表。
    • 与主键或UNIQUE索引上的WHERE子句一起使用的表,其中所有索引部分都与常量表达式进行比较,并定义为NOT NULL。
      以下所有表均用作常量表:
SELECT * FROM t WHERE primary_key=1;
SELECT * FROM t1,t2
  WHERE t1.primary_key=1 AND t2.primary_key=t1.id;
  • 通过尝试所有可能的方法,可以找到连接表的最佳连接组合。如果ORDER BY和GROUP BY子句中的所有列都来自同一个表,则在联接时首选该表。
  • 如果存在一个ORDER BY子句和另一个GROUP BY子句,或者如果 ORDER BY或GROUP 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, ... ;

    今天就先到这,我翻译了一篇我自己看不懂的文章?
在这里插入图片描述

参考文档

https://dev.mysql.com/doc/refman/5.7/en/where-optimization.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章