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

标签 mysql docker ubuntu mariadb vbulletin

我一直在寻找 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 查询。 SELECTs 和预期的一样快。奇怪的是,这似乎与 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)。

我想知道为什么那些简单的查询速度如此之慢?

已经尝试过

测试表的结构(好像也影响其他表)

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)。而且它目前没有用于任何其他应用程序,也没有来自用户的任何负载。所以我可以排除它是一个负载问题。

最佳答案

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

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 毫秒。

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

set global innodb_flush_log_at_trx_commit = 2;

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

innodb_flush_log_at_trx_commit

Crying about Innodb being 100 times slower than MyISAM ? You probably forgot to adjust this value. Default value of 1 will mean each update transaction commit (or each statement outside of transaction) will need to flush log to the disk which is rather expensive, especially if you do not have Battery backed up cache. Many applications, especially those moved from MyISAM tables are OK with value 2 which means do not flush log to the disk but only flush it to OS cache. The log is still flushed to the disk each second so you normally would not loose more than 1-2 sec worth of updates. Value 0 is a bit faster but is a bit less secure as you can lose transactions even in case MySQL Server crashes. Value 2 only cause data loss with full OS crash.

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

关于mysql - 与 XAMPP 相比,MariaDB Docker 容器中的 INSERT SQL 查询非常慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57761895/

相关文章:

php - 带有 4 个表的 INNER JOIN

PHP 阻止直接访问文件但只允许登录文件的所有者

node.js - 在docker镜像 Node :7中升级或安装Ghostscript 9.21

线程 "main"java.net.UnknownHostException : Test: Test: unknown error OS ubuntu 中的 java 异常

mysqlshow 中缺少 mySQL 数据库

mysql - 连接 3 个表,SUM() 来自其中 2 个表的值 (MYSQL)

c# - 如何通过从另一个表单调用它来将数据库中的数据显示到另一个表单

Docker Daemon API 升级到 v1.4

Docker Kubernetes 集群错误 Request had insufficient authentication scopes on Google Cloud

python - 文件太大 python