mysql15个有用的mysql/mariadb性能调整和优化技巧(代码片段)

jpfss jpfss     2023-02-04     281

关键词:

MySQL 是一个强大的开源关系数据库管理系统(简称 RDBMS)。它发布于 1995 年(20年前)。它采用结构化查询语言(SQL),这可能是数据库内容管理中最流行的选择。最新的 MySQL 版本是 5.6.25,于 2015 年 5 月 29 日发布。

关于 MySQL 一个有趣的事实是它的名字来自于 Michael Widenius(MySQL 的创始人)的女儿“ My”。尽管有许多关于 MySQL 有趣的传闻,不过本文主要是向你展示一些有用的实践,以帮助你管理你的 MySQL 服务器。

 

 

2009 年 4 月,MySQL 被 Oracle 收购。其结果是MySQL 社区分裂,创建了一个叫 MariaDB 的分支 。创建该分支的主要原因是为了保持这个项目可以在 GPL 下的自由。

今天,MySQL 和 MariaDB 是用于类似 WordPress、Joomla、Magento 和其他web 应用程序的最流行的 RDMS 之一(如果不是最多的)。

这篇文章将告诉你一些基本的,但非常有用的关于如何优化 MySQL/MariaDB 性能的技巧。注意,本文假定您已经安装了 MySQL 或 MariaDB。如果你仍然不知道如何在系统上安装它们,你可以按照以下说明去安装:

在 RHEL/CentOS 7 上安装 LAMP

在 Fedora 22 上安装 LAMP

在 Ubuntu 15.04 安装 LAMP

在 Debian 8 上安装 MariaDB

在 Gentoo Linux 上安装 MariaDB

在 Arch Linux 上安装 MariaDB

重要提示: 在开始之前,不要盲目的接受这些建议。每个MySQL 设置都是不同的,在进行任何更改之前需要慎重考虑。

你需要明白这些:

MySQL/MariaDB 配置文件位于 /etc/my.cnf。 每次更改此文件后你需要重启 MySQL 服务,以使更改生效。

这篇文章使用 MySQL 5.6 版本。

 

1. 启用 InnoDB 的每张表一个数据文件设置

首先,有一个重要的解释, InnoDB 是一个存储引擎。MySQL 和 MariaDB 使用InnoDB 作为默认存储引擎。以前,MySQL 使用系统表空间来保存数据库中的表和索引。这意味着服务器唯一的目的就是数据库处理,它们的存储盘不用于其它目的。

InnoDB 提供了更灵活的方式,它把每个数据库的信息保存在一个 .ibd 数据文件中。每个 .idb 文件代表它自己的表空间。通过这样的方式可以更快地完成类似 “TRUNCATE” 的数据库操作,当删除或截断一个数据库表时,你也可以回收未使用的空间。

这样配置的另一个好处是你可以将某些数据库表放在一个单独的存储设备。这可以大大提升你磁盘的 I/O 负载。

MySQL 5.6及以上的版本默认启用 innodb_file_per_table。你可以在 /etc/my.cnf 文件中看到。该指令看起来是这样的:

innodb_file_per_table=1

 

2. 将 MySQL 数据库数据存储到独立分区上

注意:此设置只在 MySQL 上有效, 在 MariaDB 上无效。

有时候操作系统的读/写会降低你 MySQL 服务器的性能,尤其是如果操作系统和数据库的数据位于同一块磁盘上。因此,我建议你使用单独的磁盘(最好是 SSD)用于 MySQL 服务。

要完成这步,你需要将新的磁盘连接到你的计算机/服务器上。对于这篇文章,我假定磁盘挂在到 /dev/sdb。

 

下一步是准备新的分区:

#fdisk /dev/sdb

现在按 “N” 来创建新的分区。接着按 “P”,使其创建为主分区。在此之后,从 1-4 设置分区号。之后,你可以选择分区大小。这里按 enter。在下一步,你需要配置分区的大小。

如果你希望使用全部的磁盘,再按一次 enter。否则,你可以手动设置新分区的大小。准备就绪后按“w” 保存更改。现在,我们需要为我们的新分区创建一个文件系统。这可以用下面命令轻松地完成:

#mkfs.ext4 /dev/sdb1

现在我们会挂载新分区到一个目录。我在根目录下创建了一个名为 “ssd” 的目录:

#mkdir /ssd/

挂载新分区到刚才创建的目录下:

#mount /dev/sdb1  /ssd/

你可以在 /etc/fstab 文件中添加如下行设置为开机自动挂载:

/dev/sdb1 /ssd ext3 defaults 00

 

现在我们将MySQL 移动到新磁盘中

首先停止 MySQL 服务:

# service mysqld stop

我建议你??同时停止 Apache/nginx,以防止任何试图写入数据库的操作:

  1. # service httpd stop
  2. # service nginx stop

现在复制整个 MySQL 目录到新分区中:

#cp /var/lib/mysql /ssd/ -Rp

这可能需要一段时间,具体取决于你的 MySQL 数据库的大小。一旦这个过程完成后重命名 MySQL 目录:

#mv /var/lib/mysql /var/lib/mysql-backup

然后创建一个符号链接:

#ln -s /ssd/mysql /var/lib/mysql

现在启动你的 MySQL 和 web 服务:

  1. # service mysqld start
  2. # service httpd start
  3. # service nginx start

以后你的数据库将使用新的磁盘访问。

 

3. 优化使用 InnoDB 的缓冲池

InnoDB 引擎在内存中有一个缓冲池用于缓存数据和索引。这当然有助于你更快地执行MySQL/MariaDB 查询语句。选择合适的内存大小需要一些重要的决策并对系统的内存消耗有较多的认识。

下面是你需要考虑的:

其它的进程需要消耗多少内存。这包括你的系统进程,页表,套接字缓冲。

你的服务器是否专门用于 MySQL 还是你运行着其它非常消耗内存的服务。

在一个专用的机器上,你可能会把 60-70%的内存分配给 innodb_buffer_pool_size。如果你打算在一个机器上运行更多的服务,你应该重新考虑专门用于 innodb_buffer_pool_size 的内存大小。

你需要设置 my.cnf 中的此项:

innodb_buffer_pool_size

 

4. 在 MySQL 中避免使用 Swappiness

“交换”是一个当系统移动部分内存到一个称为“交换空间” 的特殊磁盘空间时的过程。通常当你的系统用完物理内存后就会出现这种情况,系统将信息写入磁盘而不是释放一些内存。正如你猜测的磁盘比你的内存要慢得多。

该选项默认情况下是启用的:

  1. #sysctl vm.swappiness
  2. vm.swappiness= 60

运行以下命令关闭 swappiness:

#sysctl -w vm.swappiness=0

 

5. 设置 MySQL 的最大连接数

max_connections 指令告诉你当前你的服务器允许多少并发连接。MySQL/MariaDB 服务器允许有 SUPER 权限的用户在最大连接之外再建立一个连接。只有当执行 MySQL 请求的时候才会建立连接,执行完成后会关闭连接并被新的连接取代。

请记住,太多的连接会导致内存的使用量过高并且会锁住你的 MySQL 服务器。一般小网站需要 100-200 的连接数,而较大可能需要 500-800 甚至更多。这里的值很大程度上取决于你 MySQL/MariaDB 的使用情况。

你可以动态地改变 max_connections 的值而无需重启MySQL服务器:

  1. # mysql -u root -p
  2. mysql>setglobal max_connections = 300;

 

6. 配置 MySQL 的线程缓存数量

thread_cache_size 指令用来设置你服务器缓存的线程数量。当客户端断开连接时,如果当前线程数小于thread_cache_size,它的线程将被放入缓存中。下一个请求通过使用缓存池中的线程来完成。

要提高服务器的性能,你可以设置 thread_cache_size 的值相对高一些。你可以通过以下方法来查看线程缓存命中率:

  1. mysql>show status like ‘Threads_created‘;
  2. mysql>show status like ‘Connections‘;

你可以用以下公式来计算线程池的命中率:

100 - ((Threads_created / Connections) * 100)

如果你得到一个较低的数字,这意味着大多数mysql 连接使用新的线程,而不是从缓存加载。在这种情况下,你需要增加thread_cache_size

这里有一个好处是可以动态地改变 thread_cache_size 而无需重启 MySQL 服务。你可以通过以下方式来实现:

mysql>setglobal thread_cache_size = 16;

 

7. 禁用 MySQL 的 DNS 反向查询

默认情况下当新的连接出现时,MySQL/MariaDB会进行 DNS 查询解析用户的 IP 地址/主机名。对于每个客户端连接,它的 IP 都会被解析为主机名。然后,主机名又被反解析为 IP 来验证两者是否一致。

当 DNS 配置错误或服务器出现问题时,这很可能会导致延迟。这就是为什么要关闭 DNS 的反向查询的原因,你可以在你的配置文件中添加以下选项去设定:

  1. [mysqld]
  2. #Skip reverse DNS lookup of clients
  3. skip-name-resolve

更改后你需要重启 MySQL 服务。

 

8. 配置 MySQL 的查询缓存容量

如果你有很多重复的查询并且数据不经常改变 – 请使用缓存查询。人们常常不理解 query_cache_size 的实际含义而将此值设置为 GB 级,这实际上会降低服务器的性能。

背后的原因是,在更新过程中线程需要锁定缓存。通常设置为 200-300 MB应该足够了。如果你的网站比较小的,你可以尝试给 64M 并在以后及时去增加。

在你的 MySQL 配置文件中添加以下设置:

  1. query_cache_type= 1
  2. query_cache_limit= 256K
  3. query_cache_min_res_unit= 2k
  4. query_cache_size= 80M

 

9. 配置临时表容量和内存表最大容量

tmp_table_size 和 max_heap_table_size 这两个变量的大小应该相同,它们可以让你避免磁盘写入。tmp_table_size 是内置内存表的最大空间。如果表的大小超出限值将会被转换为磁盘上的 MyISAM 表。

这会影响数据库的性能。管理员通常建议在服务器上设置这两个值为每 GB 内存给 64M。

  1. [mysqld]
  2. tmp_table_size=64M
  3. max_heap_table_size=64M

 

10. 启用 MySQL 慢查询日志

记录慢查询可以帮助你定位数据库中的问题并帮助你调试。这可以通过在你的 MySQL 配置文件中添加以下值来启用:

  1. slow-query-log= 1
  2. slow-query-log-file = /var/lib/mysql/mysql-slow.log
  3. long_query_time= 1

第一个变量启用慢查询日志,第二个告诉 MySQL 实际的日志文件存储位置。使用 long_query_time 来定义完成 MySQL 查询多少用时算长。

 

11. 检查 MySQL 的空闲连接

空闲连接会消耗资源,可以的话应该被终止或者刷新。空闲连接是指处于 “sleep” 状态并且保持了很长一段时间的连接。你可以通过运行以下命令查看空闲连接:

# mysqladmin processlist -u root -p | grep “Sleep”

这会显示处于睡眠状态的进程列表。当代码使用持久连接到数据库时会出现这种情况。使用 PHP 调用 mysql_pconnect 可以打开这个连接,执行完查询之后,删除认证信息并保持连接为打开状态。这会导致每个线程的缓冲都被保存在内存中,直到该线程结束。

首先你要做的就是检查代码问题并修复它。如果你不能访问正在运行的代码,你可以修改 wait_timeout 变量。默认值是 28800 秒,而你可以安全地将其降低到 60 :

wait_timeout=60

 

12. 为 MySQL 选择正确的文件系统

选择正确的文件系统对数据库至关重要。在这里你需要考虑的最重要的事情是 - 数据的完整性,性能和易管理性。

按照 MariaDB 的建议,最好的文件系统是XFS、ext4 和 Btrfs。它们都是可以使用超大文件和大容量存储卷的企业级日志型文件系统。

下面你可以找到一些关于这三个文件系统的有用信息:

文件系统

XFS

Ext4

Btrfs

文件系统最大容量

8EB

1EB

16EB

最大文件大小

8EB

16TB

16EB

我们的这篇文章详细介绍了 Linux 文件系统的利与弊: Linux 文件系统解析

 

13. 设置 MySQL 允许的最大数据包

MySQL 把数据拆分成包。通常一个包就是发送到客户端的一行数据。max_allowed_pa??cket 变量定义了可以被发送的最大的包。

此值设置得过低可能会导致查询速度变得非常慢,然后你会在 MySQL 的错误日志看到一个错误。建议将该值设置为最大包的大小。

14. 测试 MySQL 的性能优化

你应该定期检查 MySQL/MariaDB 的性能。这将帮助你了解资源的使用情况是否发生了改变或需要进行改进。

有大量的测试工具可用,但我推荐你一个简单易用的。该工具被称为 mysqltuner。

使用下面的命令下载并运行它:

  1. #wget https://github.com/major/MySQLTuner-perl/tarball/master
  2. #tar xf master
  3. #cd major-MySQLTuner-perl-993bc18/
  4. # ./mysqltuner.pl

你将收到有关 MySQL 使用的详细报告和推荐提示。下面是默认 MariaDB 安装的输出样例:

 

 

15. 优化和修复 MySQL 数据库

有时候 MySQL/MariaDB 数据库中的表很容易崩溃,尤其是服务器意外关机、文件系统突然崩溃或复制过程中仍然访问数据库。幸运的是,有一个称为 ‘mysqlcheck‘ 的免费开源工具,它会自动检查、修复和优化 Linux 中数据库的所有表。

  1. # mysqlcheck -u root -p --auto-repair --check --optimize--all-databases
  2. # mysqlcheck -u root -p --auto-repair --check --optimizedatabasename

就是这些!我希望上述文章对你有用,并帮助你优化你的MySQL 服务器。一如往常,如果你有任何疑问或评论,请在下面的评论部分提交。

如何在分组前排序(mysql,mariadb)

】如何在分组前排序(mysql,mariadb)【英文标题】:HowCanISortBEFOREGroupBy(mysql,mariadb)【发布时间】:2018-03-0211:15:40【问题描述】:我已经寻找了很长一段时间的答案。看起来应该很简单,但我不确定它是否......设置:一个数据库有... 查看详情

将 SQL Server 存储过程重写为 MySQL(MariaDB)

】将SQLServer存储过程重写为MySQL(MariaDB)【英文标题】:RewriteSQLServerStoredProceduretoMySQL(MariaDB)【发布时间】:2019-01-2001:02:48【问题描述】:我需要将存储过程从MSSQLServer语法重写为MariaDB标准的MySQL。我已经为此苦苦挣扎了好几个小时... 查看详情

如何让 MySQL/MariaDB 用户定义的变量在 grafana 中工作?

】如何让MySQL/MariaDB用户定义的变量在grafana中工作?【英文标题】:HowdoIgetaMySQL/MariaDBuserdefinedvariableworkingingrafana?【发布时间】:2020-07-2314:28:15【问题描述】:使用MariaDB5.5(我们的星号cdr数据库)并尝试从数据库中的现有数据中... 查看详情

mysql/mariadb 中的数据库条目连续记录 - 直到今天

】mysql/mariadb中的数据库条目连续记录-直到今天【英文标题】:Databaseentrystreakinmysql/mariadb-untiltoday【发布时间】:2020-08-0807:10:45【问题描述】:我昨天问了这个问题,但我似乎并没有说得足够清楚,所以我要添加一些信息以使一... 查看详情

超级有用的15个mysqlbinlog命令

  在MySQL或MariaDB中,任意时间对数据库所做的修改,都会被记录到日志文件中。例如,当你添加了一个新的表,或者更新了一条数据,这些事件都会被存储到二进制日志文件中。二进制日志文件在MySQL主从复合中是非常有用的... 查看详情

在不同 mysql/mariadb 数据库上共享数据的最佳实践

】在不同mysql/mariadb数据库上共享数据的最佳实践【英文标题】:Bestpracticeforsharingdataoverdifferenetmysql/mariadbdatabases【发布时间】:2017-08-0610:17:00【问题描述】:我的应用程序使用带有50多个表的数据库。现在我需要安装另一个应用... 查看详情

jOOQ 为嵌套选择生成的 SQL 在 MySQL/MariaDB 中不起作用

】jOOQ为嵌套选择生成的SQL在MySQL/MariaDB中不起作用【英文标题】:SQLgeneratedbyjOOQfornestedselectdoesn\'tworkinMySQL/MariaDB【发布时间】:2018-10-1300:24:51【问题描述】:对于一个经典的排名问题(每个玩家最好的3个结果的总和),我使用jOO... 查看详情

为啥 MySQL mariadb 无故回滚数据?

】为啥MySQLmariadb无故回滚数据?【英文标题】:WhyMySQLmariadbrollbackdatawithoutreason?为什么MySQLmariadb无故回滚数据?【发布时间】:2019-05-2819:09:03【问题描述】:在不同硬件(如装有Windows操作系统的笔记本电脑)中多次使用MySQL服务... 查看详情

SqlAlchemy 的 MySQL (mariaDB) 连接错误

】SqlAlchemy的MySQL(mariaDB)连接错误【英文标题】:MySQL(mariaDB)ConnectionErrorwithSqlAlchemy【发布时间】:2013-05-3000:16:42【问题描述】:您好,我在虚拟机中运行的Ubuntu服务器上有一个mariaDB数据库。使用“SequalPro”,我可以毫无问题地连... 查看详情

如何mysql和mariadb数据库修改root密码

mysql(mariadb)如何更改root密码,第一步是切换至root用户:mysql(mariadb)如何更改root密码,主要使用mysqladmin命令,-uroot,是指定用户,指定修改root用户的密码。-ppassword是密码选项,其后面的newpasswd即为新的密码。执行结果如下:mysql... 查看详情

将mysql数据库导入mariadb

】将mysql数据库导入mariadb【英文标题】:importmysqldatabaseintomariadb【发布时间】:2017-02-0815:31:22【问题描述】:尝试将数据库备份(.sql)从docker容器mysql:5.6导入我的本地MySQL(MariaDB)。这是我用过的命令:mysql-uroot-pdatabase_name</opt/datab... 查看详情

怎么不要mysql,mariadb乱码

...名;参考技术Amysql5.6商业版本是收费的,已经被收购mysql跟mariadb是同一个人开发,是两个不同的分支。只不过mariadb没有mysql完善而已由于mariadb完全免费 查看详情

MySQL/MariaDB - 按内部子查询排序

】MySQL/MariaDB-按内部子查询排序【英文标题】:MySQL/MariaDB-orderbyinsidesubquery【发布时间】:2014-12-0922:30:14【问题描述】:多年来,我在MySQL5.5(或以前的版本)中使用了以下查询,没有任何问题:SELECTt2.Codefrom(selectCountry.CodefromCount... 查看详情

MySQL/MariaDB - 按内部子查询排序

】MySQL/MariaDB-按内部子查询排序【英文标题】:MySQL/MariaDB-orderbyinsidesubquery【发布时间】:2014-12-0922:30:14【问题描述】:多年来,我在MySQL5.5(或以前的版本)中使用了以下查询,没有任何问题:SELECTt2.Codefrom(selectCountry.CodefromCount... 查看详情

为啥我在postgresql的json数据中查询,速度会比mysql慢很多

...N支持,成为少数几个支持NoSQL的关系型数据库之一。MySQL/MariaDB的当前版本是5.7.6(MariaDB为MySQL创建者MontyWidenius创建的一个MySQL分支),PostgreSQL的版本是9.4.1。Bolton从以下几个方面对比了两者的最新版本:ANSI标准兼容性:与先前... 查看详情

MySQL (MariaDB) [WinError 10053] 已建立的连接被主机中的软件中止

】MySQL(MariaDB)[WinError10053]已建立的连接被主机中的软件中止【英文标题】:MySQL(MariaDB)[WinError10053]Anestablishedconnectionwasabortedbythesoftwareinyourhostmachine【发布时间】:2021-11-1217:27:30【问题描述】:所以,我在mysql上苦苦挣扎我尝试使用... 查看详情

在 MySQL/MariaDB 中创建存储过程时出错

】在MySQL/MariaDB中创建存储过程时出错【英文标题】:errorcreatingstoredprocedureinMySQL/MariaDB【发布时间】:2018-03-2310:42:38【问题描述】:我正在尝试在MySQL中创建一个存储过程,但我不断收到错误#1064-您的SQL语法有错误;查看与您的Ma... 查看详情

如何在 MySQL/MariaDB 中创建与 root 具有相同权限的用户? [关闭]

】如何在MySQL/MariaDB中创建与root具有相同权限的用户?[关闭]【英文标题】:HowdoIcreateauserwiththesameprivilegesasrootinMySQL/MariaDB?[closed]【发布时间】:2013-05-2018:24:46【问题描述】:如何在MySQL/MariaDB中创建与root具有相同权限的用户?【... 查看详情