暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

如何用MySQL最大化提升数据库查询效率和性能

原创 Paul Namuag 2019-12-20
1393

慢查询,低效率查询或长时间运行的查询经常困扰DBA。它们始终无处不在,但对于负责管理数据库的任何人来说,它们都是生活中不可避免的一部分。

数据库设计不佳会影响查询的效率及其性能。缺乏知识或对函数调用,存储过程或例程的不当使用也会导致数据库性能下降,甚至可能损害整个MySQL数据库集群。

对于主从复制,导致这些问题的一个非常常见的原因是缺少主索引或辅助索引的表。这会导致从属滞后,这种滞后会持续很长时间(在更糟的情况下)。

下面将为您提供有关如何解决MySQL中数据库查询最大化以提高效率和性能的进阶讲解。

始终在表中添加唯一索引

当数据变大时,没有主键或唯一键的表通常会产生巨大的问题。发生这种情况时,简单的数据修改就会使数据库停顿。缺少适当的索引,并且已将UPDATE或DELETE语句应用于特定表,MySQL将选择全表扫描作为查询计划。这可能会导致磁盘I / O读写过多,并降低数据库性能。请参阅以下示例:

root[test]> show create table sbtest2\G
 
*************************** 1. row ***************************
 
       Table: sbtest2
 
Create Table: CREATE TABLE `sbtest2` (
 
  `id` int(10) unsigned NOT NULL,
 
  `k` int(10) unsigned NOT NULL DEFAULT '0',
 
  `c` char(120) NOT NULL DEFAULT '',
 
  `pad` char(60) NOT NULL DEFAULT ''
 
) ENGINE=InnoDB DEFAULT CHARSET=latin1
 
1 row in set (0.00 sec)
 
 
 
root[test]> explain extended update sbtest2 set k=52, pad="xx234xh1jdkHdj234" where id=57;
 
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+
 
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref | rows | filtered | Extra       |
 
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+
 
|  1 | UPDATE      | sbtest2 | NULL       | ALL | NULL | NULL | NULL    | NULL | 1923216 | 100.00 | Using where |
 
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+
 
1 row in set, 1 warning (0.06 sec)
复制

带有主键的表有很好的查询计划,

root[test]> show create table sbtest3\G
 
*************************** 1. row ***************************
 
       Table: sbtest3
 
Create Table: CREATE TABLE `sbtest3` (
 
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 
  `k` int(10) unsigned NOT NULL DEFAULT '0',
 
  `c` char(120) NOT NULL DEFAULT '',
 
  `pad` char(60) NOT NULL DEFAULT '',
 
  PRIMARY KEY (`id`),
 
  KEY `k` (`k`)
 
) ENGINE=InnoDB AUTO_INCREMENT=2097121 DEFAULT CHARSET=latin1
 
1 row in set (0.00 sec)
 
 
 
root[test]> explain extended update sbtest3 set k=52, pad="xx234xh1jdkHdj234" where id=57;
 
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
 
| id | select_type | table   | partitions | type | possible_keys | key     | key_len | ref | rows | filtered | Extra   |
 
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
 
|  1 | UPDATE      | sbtest3 | NULL       | range | PRIMARY | PRIMARY | 4       | const | 1 | 100.00 | Using where |
 
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
 
1 row in set, 1 warning (0.00 sec)

复制

主键或唯一键是表结构的重要组成部分,因为这非常重要,尤其是在对表执行维护时。例如,使用Percona工具包中的工具(例如pt-online-schema-change或pt-table-sync)建议您必须具有唯一的键。请记住,PRIMARY KEY已经是一个唯一键,并且一个主键不能保存NULL值,而是唯一键。将NULL值分配给主键会导致类似以下错误:

ERROR 1171 (42000): All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead
复制

对于从属节点,在某些情况下,表上不存在主键/唯一键也是很常见的,因此这是表结构的差异。您可以使用mysqldiff实现此目的,也可以使用mysqldump --no-data…params并运行diff来比较其表结构并检查是否存在差异。

扫描具有重复索引的表,然后将其删除

索引重复也会导致性能下降,尤其是当表包含大量记录时。MySQL必须进行多次尝试来优化查询并执行更多查询计划以进行检查。它包括扫描大型索引分布或统计信息,并增加了性能开销,因为它可能导致内存争用或高I / O内存利用率。

当在表上观察到重复索引时查询的降级也归因于缓冲池的饱和。当检查点将事务日志刷新到磁盘时,这也会影响MySQL 的性能。这是由于处理和存储了不需要的索引(实际上浪费了该表的特定表空间中的空间)。请注意,重复的索引也存储在表空间中,该表空间也必须存储在缓冲池中。

查看下表,该表包含多个重复键:

root[test]#> show create table sbtest3\G
 
*************************** 1. row ***************************
 
       Table: sbtest3
 
Create Table: CREATE TABLE `sbtest3` (
 
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 
  `k` int(10) unsigned NOT NULL DEFAULT '0',
 
  `c` char(120) NOT NULL DEFAULT '',
 
  `pad` char(60) NOT NULL DEFAULT '',
 
  PRIMARY KEY (`id`),
 
  KEY `k` (`k`,`pad`,`c`),
 
  KEY `kcp2` (`id`,`k`,`c`,`pad`),
 
  KEY `kcp` (`k`,`c`,`pad`),
 
  KEY `pck` (`pad`,`c`,`id`,`k`)
 
) ENGINE=InnoDB AUTO_INCREMENT=2048561 DEFAULT CHARSET=latin1
 
1 row in set (0.00 sec)

复制

大小为2.3GiB

root[test]#> \! du -hs /var/lib/mysql/test/sbtest3.ibd
 
2.3G    /var/lib/mysql/test/sbtest3.ibd
复制

让我们删除重复的索引,并使用no-op alter重建表,

root[test]#> drop index kcp2 on sbtest3; drop index kcp on sbtest3 drop index pck on sbtest3;
 
Query OK, 0 rows affected (0.01 sec)
 
Records: 0  Duplicates: 0  Warnings: 0
 
Query OK, 0 rows affected (0.01 sec)
 
Records: 0  Duplicates: 0  Warnings: 0
 
Query OK, 0 rows affected (0.01 sec)
 
Records: 0  Duplicates: 0  Warnings: 0
 
 
 
root[test]#> alter table sbtest3 engine=innodb;
 
Query OK, 0 rows affected (28.23 sec)
 
Records: 0  Duplicates: 0  Warnings: 0
 
 
 
root[test]#> \! du -hs /var/lib/mysql/test/sbtest3.ibd
 
945M    /var/lib/mysql/test/sbtest3.ibd
复制

它已经能够节省高达59%的旧表空间,这确实是巨大的。

要确定重复索引,可以使用pt-duplicate-checker为您处理作业。

调整缓冲池

在本节中,指的仅仅是InnoDB存储引擎。

缓冲池是InnoDB内核空间中的重要组件。InnoDB在访问时在这里缓存表和索引数据。由于使用BTREE将常用数据有效地存储在内存中,因此可以加快处理速度。例如,如果您有多个由> = 100GiB组成的表并被大量访问,那么我们建议您委派一个快速易失性内存,从128GiB的大小开始,并开始为缓冲池分配80%的物理内存。80%必须得到有效监控。您可以使用SHOW ENGINE INNODB STATUS \ G,也可以利用诸如ClusterControl之类的监视软件,该软件提供细粒度的监视,其中包括缓冲池及其相关的运行状况指标。同时设置innodb_buffer_pool_instances变量相应地。您可以将此值设置为大于8(如果innodb_buffer_pool_size> = 1GiB,则为默认值),例如16、24、32或64或更高(如有必要)。

监视缓冲池时,需要检查全局状态变量Innodb_buffer_pool_pages_free,该变量可让您考虑是否需要调整缓冲池,或者考虑是否还有不想要的或重复的索引消耗了缓冲区。该SHOW ENGINE INNODB STATUS \ G变还提供了缓冲池的信息,包括基于数量的个体缓冲池更详细的说明innodb_buffer_pool_instances您已设置。

使用FULLTEXT索引(但仅在适用时)

使用类似的查询

SELECT bookid, page, context FROM books WHERE context like '%for dummies%';
复制

其中 context是字符串类型(char,varchar,text)列,是超坏查询的示例!使用必须贪婪的过滤器提取大量记录最终会导致全表扫描,这简直太疯狂了。考虑使用FULLTEXT索引。一个FULLTEXT指数有一个倒排索引设计。倒排索引存储单词列表,每个单词列表包含该单词出现的文档列表。为了支持邻近搜索,还存储每个单词的位置信息,以字节偏移量为单位。

为了使用FULLTEXT来搜索或过滤数据,您需要使用MATCH()… AGAINST语法的组合,而不是上面的查询。当然,您需要将字段指定为FULLTEXT索引字段。

要创建FULLTEXT索引,只需指定FULLTEXT作为索引。请参阅以下示例:

root[minime]#> CREATE FULLTEXT INDEX aboutme_fts ON users_info(aboutme);
 
Query OK, 0 rows affected, 1 warning (0.49 sec)
 
Records: 0  Duplicates: 0  Warnings: 1
 
 
 
root[jbmrcd_date]#> show warnings;
 
+---------+------+--------------------------------------------------+
 
| Level   | Code | Message                                          |
 
+---------+------+--------------------------------------------------+
 
| Warning |  124 | InnoDB rebuilding table to add column FTS_DOC_ID |
 
+---------+------+--------------------------------------------------+
 
1 row in set (0.00 sec)

复制

尽管使用FULLTEXT索引可以在列内很大的上下文中搜索单词时带来好处,但如果使用不正确,也会产生问题。

在执行FULLTEXT搜索时,经常访问的大型表(许多客户端请求正在搜索不同的唯一关键字)可能会占用大量CPU。

在某些情况下,FULLTEXT不适用。请参阅此外部博客文章。尽管我尚未在8.0上尝试过此操作,但没有看到与此相关的任何更改。我们建议不要使用FULLTEXT搜索大数据环境,尤其是对于高流量表。否则,请尝试利用其他技术,例如Apache Lucene,Apache Solr,tsearch2或Sphinx。

避免在列中使用NULL

在MySQL中,包含空值的列完全可以。但是,如果在索引中使用具有空值的列,则会影响查询性能,因为由于索引分布不佳,优化器无法提供正确的查询计划。但是,有一些方法可以优化涉及空值的查询,但是当然可以满足要求。

有效地设计架构拓扑和表结构

在某种程度上,将数据库表从1NF(第一范式)规范化为3NF(第三范式)可为查询效率带来一些好处,因为规范化的表会避免多余的记录。对表进行适当的规划和设计非常重要,因为这是您检索或提取数据的方式,并且在这些操作的每一项中都需要一定的成本。对于规范化的表,数据库的目标是确保每个表中的每个非键列都直接依赖于键。整个钥匙,只有钥匙。如果达到了这一目标,它将以减少冗余,减少异常和提高效率的形式付出收益。

虽然规范化表有许多好处,但这并不意味着您需要以这种方式规范化所有表。您可以使用Star Schema为数据库实现设计。使用Star Schema设计表的优点是查询更简单(避免复杂的交叉联接),易于检索数据以进行报告,由于无需使用联合或复杂联接或快速聚合而提高了性能。星型模式易于实现,但是您需要仔细计划,因为当表变大并且需要维护时,星型模式会带来很大的问题和不利之处。Star Schema(及其基础表)容易出现数据完整性问题,因此您很可能会出现大量数据冗余的情况。

混合数据库设计(只要您能够确定并确定必须在表上提取哪种数据)非常重要,因为您可以从更高效的查询中受益,并帮助DBA进行备份,维护,和恢复。

摆脱常数和旧数据

如何删除旧数据或归档常量和旧数据如何提高查询效率呢?不断修改并插入新数据的较大表有很多好处,表空间可以快速增长。当记录或数据彼此连续并且对表中的下一行有意义时,MySQL和InnoDB会高效地执行。这意味着,如果您没有不再需要使用的旧记录,则优化器不需要将其包含在统计信息中,从而可以提供更为有效的结果。而且,查询效率不仅在应用程序方面,还需要在执行备份以及维护或故障转移时考虑其效率。

根据需要启用查询日志记录

始终根据您的自定义需求设置MySQL的慢查询日志。如果您使用的是Percona Server,则可以利用其扩展的慢查询日志记录功能。它允许您习惯地定义某些变量。您可以组合查询类型来过滤查询,例如full_scan,full_join,tmp_table等。您还可以通过变量log_slow_rate_type以及许多其他命令来确定慢查询的日志记录速率。

在MySQL中启用查询日志记录(例如慢速查询)的重要性对于检查查询很有用,这样您就可以通过调整某些适合您需求的变量来优化或调整MySQL。要启用慢速查询日志,请确保已设置以下变量:

  • long_query_time-为查询可以花费的时间分配正确的值。如果查询花费的时间超过10秒(默认),它将落入您分配的慢查询日志文件中。
  • slow_query_log-要启用它,请将其设置为1。
  • slow_query_log_file-这是慢速查询日志文件的目标路径。

慢查询日志对于查询分析和诊断导致停顿,从属延迟,长时间运行的查询,内存或CPU密集型甚至导致服务器崩溃的错误查询非常有帮助。如果您使用pt-query-digest或pt-index-usage,请使用慢查询日志文件作为报告这些查询的源目标。

结论

在此文中,讨论了一些可用于最大化数据库查询效率的方法。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论