与 XAMPP 相比,MariaDB Docker 容器中的 INSERT SQL 查询非常慢

Posted

技术标签:

【中文标题】与 XAMPP 相比,MariaDB Docker 容器中的 INSERT SQL 查询非常慢【英文标题】:INSERT SQL query very slow in MariaDB Docker container compared to XAMPP 【发布时间】:2020-01-05 18:47:52 【问题描述】:

我正在寻找 Web 应用程序的瓶颈,发现 INSERT 查询运行速度明显变慢,如下所示:

MariaDB [myforum]> insert into tag set tagtext='abc12345',dateline=unix_timestamp(),canonicaltagid=1234;
Query OK, 1 row affected (0.24 sec)

这是通过在应用程序容器中安装 mysql-client 来进行测试的。对于这样一个简单的查询,240 毫秒似乎很长。我假设一些 dns/网络问题。但是当我直接在 MariaDB 容器中运行查询时,我看到了类似的结果,其中使用 -h 127.0.0.1 建立了连接:

MariaDB [myforum]> insert into tag set tagtext='abc123',dateline=unix_timestamp(),canonicaltagid=1234;
Query OK, 1 row affected (0.251 sec)

仅执行 INSERT 查询。 SELECT 和预期的一样快。奇怪的是,这似乎与 MariaDB Docker 安装有关:我在本地 XAMPP 安装上有相同的数据库,其中相同的查询很快:

MariaDB [myforum]> insert into tag set tagtext='abc123',dateline=unix_timestamp(),canonicaltagid=123;
Query OK, 1 row affected (0.00 sec) 

我只能对表格本身进行有限的更改,因为这些来自 vBulletin(旧的专有论坛 CMS)。

我想知道为什么这些简单的查询如此缓慢?

已经尝试过

Changed the I/O Scheduler 用于运行时的两个光盘以及in Grub with reboot Setting barrier=0 in fstab Set slice_idle and group_idle to zero (default value was 8) Optimized all tables

测试表的结构(似乎也影响其他表)

CREATE TABLE `tag` (
    `tagid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `tagtext` VARCHAR(100) NOT NULL DEFAULT '',
    `dateline` INT(10) UNSIGNED NOT NULL DEFAULT '0',
    `canonicaltagid` INT(10) UNSIGNED NOT NULL DEFAULT '0',
    PRIMARY KEY (`tagid`),
    UNIQUE INDEX `tagtext` (`tagtext`),
    INDEX `canonicaltagid` (`canonicaltagid`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=4112
;

Docker 编写文件

version: '2'
volumes:
  mysql-data:

services:
  # Here is another service that access the db using dns name 'mariadb'

  mariadb:
    container_name: mariadb
    image: mariadb:10.3
    mem_limit: 3GB
    restart: always
    env_file:
      - mariadb.env
    volumes:
      - ../dump.sql:/docker-entrypoint-initdb.d/dump.sql
      - mysql-data:/var/lib/mysql

有关底层 Docker 主机服务器的系统信息

# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.3 LTS
Release:        18.04
Codename:       bionic

# docker --version
Docker version 19.03.1, build 74b1e89
# docker-compose --version
docker-compose version 1.24.1, build 4667896b

服务器有一个软件 raid 1,有两个企业级硬盘、足够的 CPU 功率和内存 (32GB)。而且它目前没有用于任何其他应用程序,也没有来自用户的任何负载。所以我可以排除它的负载问题。

【问题讨论】:

这是插入还是更新?看起来像是两者的某种奇怪的混合体,我在精美手册 mariadb.com/kb/en/library/adding-and-changing-data-in-mariadb 中没有找到类似“插入表集列 = 值”之类的东西 - 它有什么作用? @CaiusJard 这并不奇怪,只是 MySQL 的一个扩展,请参阅 ***.com/a/861729/3276634 使用您的语法 insert tag(tagtext,dateline,canonicaltagid) values('a123',unix_timestamp(),123); 查询也需要 295 毫秒,所以它同样慢。 innodb_buffer_pool_size的值是多少? @RickJames innodb_buffer_pool_size = 268435456。我将整个 SQL 配置保留为 MariaDB 的默认值。 虽然不能解决问题,但还是应该将缓冲池设置为 RAM 的 70% 左右。 【参考方案1】:

经过一番研究,我找到了有关 InnoDB 刷新参数的信息。尤其是innodb_flush_log_at_trx_commit,默认设置为 1:

MariaDB [myforum]> show variables like '%innodb_flush%';
+--------------------------------+----------+
| Variable_name                  | Value    |
+--------------------------------+----------+
| innodb_flush_log_at_timeout    | 1        |
| innodb_flush_log_at_trx_commit | 1        |
| innodb_flush_method            | O_DIRECT |
| innodb_flush_neighbors         | 1        |
| innodb_flush_sync              | ON       |
| innodb_flushing_avg_loops      | 30       |
+--------------------------------+----------+

值 1 表示每次提交时写入和刷新。所以我认为这可能需要开销。一个相当大的妥协是 posted here 将其更改为 2。这将导致在每次提交后写入日志文件,但每秒仅将日志刷新一次到磁盘。

对我来说,这极大地提高了写入性能:MySQL cli 显示 0.000 秒,而不是像以前那样高达 ~300 毫秒。此外,受影响的 Web 应用程序的 html 呈现时间从 300 - 700 毫秒减少到 ~ 90 - 120 毫秒。

后果:在最坏的失败情况下,可能会丢失一秒钟的事务。对于非常敏感/重要的数据(如金融交易)和/或存在大量写入,这可能是不可接受的。我认为在像我这样的最常见的网络案例中,这是一个合适的修复,我在全局范围内更改了值:

set global innodb_flush_log_at_trx_commit = 2;

来自here 的技术文档证实了我的发现:

innodb_flush_log_at_trx_commit

为 Innodb 比 MyISAM 慢 100 倍而哭泣?您可能忘记调整此值。默认值 1 意味着每个更新事务提交(或事务之外的每个语句)都需要将日志刷新到磁盘,这相当昂贵,尤其是在您没有电池备份缓存的情况下。许多应用程序,尤其是那些从 MyISAM 表中移动的应用程序都可以使用值为 2 的应用程序,这意味着不将日志刷新到磁盘,而仅将其刷新到操作系统缓存。日志仍然每秒刷新到磁盘,因此您通常不会丢失超过 1-2 秒的更新。值 0 稍快一些,但安全性稍差一些,因为即使 MySQL 服务器崩溃,您也可能丢失事务。值 2 只会在整个操作系统崩溃时导致数据丢失。

但是,我仍然愿意接受其他/更好的解决方案。 This post 列出了其他一些技巧,但其中大多数都不适合我(服务器有足够多的资源、专有软件……)。但他们可能会喜欢其他有类似问题的人。

【讨论】:

请记住,除非您将新值放入 my.cnf [mysqld] 部分,否则您的“适当修复”仅在实例的下一次停止/启动之前有效。 附加信息请求。在 pastebin.com 上发布并分享链接。 A) 完整(未编辑)my.cnf 或 my.ini 以及您完整的 php.ini 文本结果: B) SHOW GLOBAL STATUS;至少 24 小时正常运行时间后 C) 显示全局变量; D) 显示完整的处理程序; E) 完整的 MySQLTuner 报告和可选的非常有用的信息,如果可用包括 - htop OR top OR mytop 用于大多数活动应用程序,ulimit -a 用于 linux/unix 限制列表,iostat -xm 5 3 用于按设备和核心/cpu 的 IOPS计数,用于服务器工作负载调整分析。

以上是关于与 XAMPP 相比,MariaDB Docker 容器中的 INSERT SQL 查询非常慢的主要内容,如果未能解决你的问题,请参考以下文章

XAMPP 与 MySQL 而不是 MariaDB

与独立的 mariaDB 服务器相比,使用 galera 获得非常糟糕的性能

如何在 Xampp 中升级 MariaDB

XAMPP 为 MariaDB 设置 root 用户密码

为啥我可以在 Windows 7 上使用 XAMPP 登录 MariaDB

XAMPP Windows 上的 MariaDB 未启动