AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 64206
Accepted
syneticon-dj
syneticon-dj
Asked: 2014-05-01 01:18:09 +0800 CST2014-05-01 01:18:09 +0800 CST 2014-05-01 01:18:09 +0800 CST

为什么 MySQL 会做串行同步 I/O?

  • 772

在查看一个特别烦人的 MyISAM 表查询时,它在很多情况下都需要很长时间才能执行,我注意到 MySQL 似乎暴露了一种相当奇怪的 I/O 模式:当执行单个查询并且必须执行大量操作时I/O 量(例如,对于表扫描或由于echo 3 > /proc/sys/vm/drop_caches需要首先从磁盘加载索引而导致缓存为空时),底层块设备的队列大小接近值 1,性能极差仅 4-5 MB/s:

root@mysql-test:~# iostat -xdm 5 /dev/sda
Linux 3.2.0-40-generic (mysql-test)  04/30/2014      _x86_64_        (4 CPU)

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.14    24.82   18.26   88.79     0.75     4.61   102.56     2.83   26.39   19.29   27.85   2.46  26.31

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.00    69.29  151.52   72.73     5.31     0.59    53.95     1.21    5.39    7.84    0.29   4.39  98.51

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.00   153.06  144.29  174.69     4.96     1.36    40.54     1.39    4.36    8.91    0.60   3.15 100.49

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.00   105.75  150.92  109.03     4.53     0.85    42.41     1.29    4.96    8.15    0.54   3.90 101.36

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.00    48.89  156.36   51.72     5.28     0.76    59.38     1.28    6.16    8.02    0.55   4.77  99.23

虽然 150 IOPS 只是给定配置中的单个磁盘在随机 I/O 方面能够提供的,但结果仍然让我感到惊讶,因为我希望 MySQL 能够运行异步 I/O 进行读取并获取一个同时处理大量块而不是一个一个地读取和评估它们,有效地忽略了 RAID 配置中可用的并行化增益。什么设计决策或配置选项对此负责?这是特定于平台的问题吗?

虽然我已经用大型 MyISAM 表对此进行了测试,但我发现将相同的表转换为 InnoDB 会产生类似的效果(虽然还不错,示例查询仍然需要 20-30 秒,其中大部分时间都花在读取磁盘上在我重新启动 mysql 守护程序后,队列长度为 1),因此缓冲池为空。我还验证了同样的问题在 5.6 GA 和当前的 5.7 里程碑 14 上仍然存在——只要我使用单个查询线程,MySQL 似乎无法并行化查询处理所需的 I/O 操作。


根据请求,有关该场景的一些其他详细信息。可以通过多种查询类型观察到该行为。我随意选择了一个进行进一步测试,内容有点像这样:

SELECT herp.id, herp.firstname, herp.lastname, derp.label, herp.email, 
(SELECT CONCAT(label, " (", zip_code, " ", city,")" ) FROM subsidiaries WHERE subsidiaries.id=herp.subsidiary_id ) AS subsidiary, 
(SELECT COUNT(fk_herp) from herp_missing_data WHERE fk_herp=herp.id) AS missing_data
FROM herp LEFT JOIN derp ON derp.id=herp.fk_derp
WHERE (herp.fk_pools='123456')  AND herp.city LIKE '%Some City%' AND herp.active='yes' 
ORDER BY herp.id desc LIMIT 0,10;

我知道它有一些优化空间,但出于多种原因我决定将其留在那儿,并专注于为我看到的意外 I/O 模式寻找一般解释。

使用过的表中确实有一堆数据:

mysql> select table_name, engine, table_rows, data_length, index_length from information_schema.tables WHERE tables.TABLE_SCHEMA = 'mydb' and tables.table_name in ( 'herp', 'derp', 'missing_data', 'subsidiaries');
+-------------------------+--------+------------+-------------+--------------+
| table_name              | engine | table_rows | data_length | index_length |
+-------------------------+--------+------------+-------------+--------------+
| derp                    | MyISAM |      14085 |     1118676 |       165888 |
| herp                    | MyISAM |     821747 |   828106512 |    568057856 |
| missing_data            | MyISAM |    1220186 |    15862418 |     29238272 |
| subsidiaries            | MyISAM |       1499 |     6490308 |       103424 |
+-------------------------+--------+------------+-------------+--------------+
4 rows in set (0.00 sec)

现在,当我在这些表上运行上面的查询时,我得到的执行时间超过 1 分钟,而系统显然一直忙于使用单个线程从磁盘读取数据。

示例查询执行的配置文件(在此示例中耗时 1 分 9.17 秒)如下所示:

mysql> show profile for query 1;
+--------------------------------+-----------+
| Status                         | Duration  |
+--------------------------------+-----------+
| starting                       |  0.000118 |
| Waiting for query cache lock   |  0.000035 |
| init                           |  0.000033 |
| checking query cache for query |  0.000399 |
| checking permissions           |  0.000077 |
| checking permissions           |  0.000030 |
| checking permissions           |  0.000031 |
| checking permissions           |  0.000035 |
| Opening tables                 |  0.000158 |
| init                           |  0.000294 |
| System lock                    |  0.000056 |
| Waiting for query cache lock   |  0.000032 |
| System lock                    |  0.000116 |
| optimizing                     |  0.000063 |
| statistics                     |  0.001964 |
| preparing                      |  0.000104 |
| Sorting result                 |  0.000033 |
| executing                      |  0.000030 |
| Sending data                   |  2.031349 |
| optimizing                     |  0.000054 |
| statistics                     |  0.000039 |
| preparing                      |  0.000024 |
| executing                      |  0.000013 |
| Sending data                   |  0.000044 |
| optimizing                     |  0.000017 |
| statistics                     |  0.000021 |
| preparing                      |  0.000019 |
| executing                      |  0.000013 |
| Sending data                   | 21.477528 |
| executing                      |  0.000070 |
| Sending data                   |  0.000075 |
| executing                      |  0.000027 |
| Sending data                   | 45.692623 |
| end                            |  0.000076 |
| query end                      |  0.000036 |
| closing tables                 |  0.000109 |
| freeing items                  |  0.000067 |
| Waiting for query cache lock   |  0.000038 |
| freeing items                  |  0.000080 |
| Waiting for query cache lock   |  0.000044 |
| freeing items                  |  0.000037 |
| storing result in query cache  |  0.000033 |
| logging slow query             |  0.000103 |
| cleaning up                    |  0.000073 |
+--------------------------------+-----------+
44 rows in set, 1 warning (0.00 sec)
mysql performance
  • 2 2 个回答
  • 1062 Views

2 个回答

  • Voted
  1. Best Answer
    Morgan Tocker
    2014-05-08T09:39:08+08:002014-05-08T09:39:08+08:00

    首先让我澄清一下,确认 MyISAM 不执行异步 I/O,但 InnoDB 执行并将默认从 MySQL 5.5 开始。在 5.5 之前,它通过使用工作线程来使用“模拟 AIO”。

    我认为区分三种情况也很重要:

    1. 一次执行多个查询
    2. 并行执行的单个查询
    3. 表扫描的某种逻辑预读/清除下一页众所周知的情况。

    对于 (1) I/O 将能够为此并行执行。MyISAM 有一些限制:表锁定和保护key_buffer(索引缓存)的全局锁。MySQL 5.5+ 中的 InnoDB 在这里非常出色。

    对于 (2) 这目前不支持。一个很好的用例是分区,您可以在其中并行搜索每个分区表。

    对于 (3) InnoDB 如果读取 >56 页(这是可配置的),则 InnoDB 具有线性预读以读取完整范围(64 页组),但还有进一步增强的空间。Facebook 已经写了关于在他们的分支中实现逻辑读取头(在表扫描上有 10 倍的性能增益)。

    • 8
  2. RolandoMySQLDBA
    2014-05-06T06:48:41+08:002014-05-06T06:48:41+08:00

    我希望missing_data不是 MyISAM,因为一个空的 MyISAM 表通常有 1024 字节.MYI。MyISAM 需要非零字节大小。零字节.MYI对我来说听起来有点令人毛骨悚然。

    如果您运行此元数据查询

    select table_name, table_rows, data_length, index_length, engine
    from information_schema.tables
    WHERE tables.TABLE_SCHEMA = 'mydb'
    and tables.table_name = 'missing_data';
    

    那个表的引擎是MyISAM,你需要修复它。

    旁注:如果engine是NULL,则为视图。如果它是一个视图或者它不是 MyISAM,请忽略我帖子的其余部分并将该信息添加到问题中。如果表是 MyISAM,请继续阅读...

    根据你的元数据查询,missing_data.MYD大概是46M。

    首先,运行这个

    SHOW CREATE TABLE mydb.missing_data\G
    

    您将获得表格描述或一条错误消息,内容如下

    ERROR 126 (HY000): Incorrect key file for table ...
    

    如果你得到表描述并且它是 MyISAM,请运行

    OPTIMIZE TABLE mydb.missing_data;
    

    它将重新创建没有碎片的表并计算新的索引统计信息。如果这不起作用,请尝试:

    REPAIR TABLE mydb.missing_data;
    

    这应该为 MyISAM 重新生成索引页。

    为了安全起见(如果使用 MySQL 5.6),修复后运行它

    FLUSH TABLES mydb.missing_data;
    

    你的问题

    如果 MySQL 查询优化器决定不使用,则表的索引可能不会加载到内存中。如果您的 WHERE 子句指示必须从索引中读取大量行,则 MySQL 查询优化器将在构建 EXPLAIN 计划时看到这一点,并决定改用全表扫描。

    MyISAM 表上的并行 I/O 操作是无法实现的,因为它是不可配置的。

    可以像这样调整 InnoDB 以提高性能。

    • 2

相关问题

  • 我在哪里可以找到mysql慢日志?

  • 如何优化大型数据库的 mysqldump?

  • 什么时候是使用 MariaDB 而不是 MySQL 的合适时机,为什么?

  • 组如何跟踪数据库架构更改?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve