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 / 问题 / 314864
Accepted
Googlebot
Googlebot
Asked: 2022-07-27 05:15:04 +0800 CST2022-07-27 05:15:04 +0800 CST 2022-07-27 05:15:04 +0800 CST

从 InnoDB 表中选择的瓶颈是什么?

  • 772

对于具有 5 亿行的 InnoDB 表(在单独的 NVMe 驱动器上),SELECT COUNT(*)大约需要 3 分钟。

SHOW ENGINE INNODB STATUS\G显示ROW OPERATIONS大约 2M reads/s,这与查询花费的时间一致。

它还显示FILE I/O大约 3,000 次读取/秒。这与 read from 类似iostat,也显示了大约 50MB/s 的读取速度。

NVMe 具有更多从磁盘读取数据的能力。

我想知道这里的瓶颈是什么?它仍然是I/O,还是 MySQL 处理?

例子

我做了一个基本的可重复测试。

CREATE TABLE test
(
id int(11) unsigned NOT NULL AUTO_INCREMENT,
Number int(11) unsigned NOT NULL,
PRIMARY KEY(id)
) ENGINE=InnoDB

INSERT INTO test (Number) SELECT * FROM seq_1_to_500000000;
Query OK, 500000000 rows affected (20 min 2.846 sec)
Records: 500000000  Duplicates: 0  Warnings: 0

SELECT COUNT(*) FROM test;
+-----------+
| COUNT(*)  |
+-----------+
| 500000000 |
+-----------+
1 row in set (1 min 20.234 sec)

重启后MySQL

innodb_buffer_pool_load_at_startup=OFF
innodb_buffer_pool_dump_at_shutdown=OFF
query_cache_type=0
query_cache_size=0

在没有任何其他活动的情况下,我得到了

SELECT COUNT(*) FROM test;
+-----------+
| COUNT(*)  |
+-----------+
| 500000000 |
+-----------+
1 row in set (1 min 13.245 sec)

关键问题:在典型的 NVMe 上运行此查询是最快的吗?

配置:

  • 50GB 缓冲池。该ibd文件为 17.7GB。
  • CPU 为 16/32 核/线程。
  • innodb_io_threads没有效果。我尝试了 4(默认)和 64(最大)。

和

SHOW GLOBAL STATUS LIKE 'innodb_buffer_pool%';
+-----------------------------------------+-------------+
| Variable_name                           | Value       |
+-----------------------------------------+-------------+
| Innodb_buffer_pool_dump_status          |             |
| Innodb_buffer_pool_load_status          |             |
| Innodb_buffer_pool_resize_status        |             |
| Innodb_buffer_pool_load_incomplete      | OFF         |
| Innodb_buffer_pool_pages_data           | 874527      |
| Innodb_buffer_pool_bytes_data           | 14328250368 |
| Innodb_buffer_pool_pages_dirty          | 0           |
| Innodb_buffer_pool_bytes_dirty          | 0           |
| Innodb_buffer_pool_pages_flushed        | 0           |
| Innodb_buffer_pool_pages_free           | 2351473     |
| Innodb_buffer_pool_pages_made_not_young | 0           |
| Innodb_buffer_pool_pages_made_young     | 0           |
| Innodb_buffer_pool_pages_misc           | 0           |
| Innodb_buffer_pool_pages_old            | 322843      |
| Innodb_buffer_pool_pages_total          | 3226000     |
| Innodb_buffer_pool_pages_lru_flushed    | 0           |
| Innodb_buffer_pool_read_ahead_rnd       | 682843      |
| Innodb_buffer_pool_read_ahead           | 0           |
| Innodb_buffer_pool_read_ahead_evicted   | 0           |
| Innodb_buffer_pool_read_requests        | 56901439    |
| Innodb_buffer_pool_reads                | 874396      |
| Innodb_buffer_pool_wait_free            | 0           |
| Innodb_buffer_pool_write_requests       | 515         |
+-----------------------------------------+-------------+
23 rows in set (0.001 sec)

关于表的附加信息

SHOW TABLE STATUS LIKE 'test';
+------+--------+---------+------------+-----------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+---------------------+------------+-----------------+----------+----------------+---------+------------------+-----------+
| Name | Engine | Version | Row_format | Rows      | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time         | Update_time         | Check_time | Collation       | Checksum | Create_options | Comment | Max_index_length | Temporary |
+------+--------+---------+------------+-----------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+---------------------+------------+-----------------+----------+----------------+---------+------------------+-----------+
| test | InnoDB |      10 | Dynamic    | 499216334 |             25 | 12859736064 |               0 |            0 |   7340032 |      500000001 | 2022-07-29 00:10:49 | 2022-07-29 00:32:52 | NULL       | utf8_general_ci |     NULL |                |         |                0 | N         |
+------+--------+---------+------------+-----------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+---------------------+------------+-----------------+----------+----------------+---------+------------------+-----------+
1 row in set (0.001 sec)

EXPLAIN FORMAT=JSON SELECT COUNT(*) FROM test;
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                                                                                                                                                                                  |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| {
  "query_block": {
    "select_id": 1,
    "table": {
      "table_name": "test",
      "access_type": "index",
      "key": "PRIMARY",
      "key_length": "4",
      "used_key_parts": ["id"],
      "rows": 499216334,
      "filtered": 100,
      "using_index": true
    }
  }
} |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)

SHOW VARIABLES LIKE 'innodb_io%';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| innodb_io_capacity     | 32000 |
| innodb_io_capacity_max | 64000 |
+------------------------+-------+
mysql performance
  • 2 2 个回答
  • 75 Views

2 个回答

  • Voted
  1. Rick James
    2022-07-27T07:18:17+08:002022-07-27T07:18:17+08:00

    简单的问题;不是一个简单的答案。在我闲逛的时候忍受我...

    SELECT COUNT(*) FROM tbl将使用“最小”索引。请提供SHOW CREATE TABLE,以便我们讨论细节。还提供SHOW TABLE STATUS,以便我们讨论尺寸。

    假设选择INDEX的是磁盘上的 4GB,将其除以 16K 以获得需要读取的 256K 块。一些块可能已经在缓存中。唉,这些数字与您提供的任何内容都不匹配。

    另一种查看工作量的方法是在 SELECT 之前和之后运行它:

     SHOW GLOBAL STATUS LIKE 'InnoDB%';
    

    然后减去数字。有些是字节数;有些是块数。两者之间有16K的系数,应该很明显看出哪个是哪个。有问题的可能是Innodb_buffer_pool_pages_data. 再次执行该过程;看看这个数字是如何变化的。

    到目前为止,我还没有直接回答你的问题。让我们看看我能不能再靠近一点……

    • InnoDB 使用一个主线程进行查询。[警告:最新版本尝试为 . 做一些并行性COUNT(*)。]
    • 它使用后台线程来执行实际的 I/O,但这并不重要,因为...
    • 它将读取一个块,计算行数,然后移动到下一个块。
    • 可能有不相关的活动同时进行。例如,如果您最近插入了很多行,则二级索引的更新可能刚刚触及磁盘。
    • 由于 COUNT 必须将每个块读入 buffer_pool 中的 RAM,因此可能需要将其他块从该缓存中取出。当您执行本质上只读的任务时,这可能会导致磁盘写入。
    • 如果您运行两次查询,第二次可能会比第一次运行得快很多——这是由于第一次运行填充了缓存;第二个不做任何 I/O!但...
    • 如果正在使用的索引大于缓存中的容量,则每次运行都会执行大量 I/O 读取。
    • InnoDB 更适合“同时”从单独的连接执行多个操作。例如,您可以在 6 秒内“同时”进行 10 次计数。你在乎哪个?延迟——单个查询 3 秒与吞吐量——6 秒内 10 个查询?
    • 如果这 10 个查询涉及相同的块,那么缓存可以避免大量 I/O。如果它们接触不同的块,那么磁盘驱动器可能是瓶颈。
    • 1
  2. Best Answer
    Wilson Hauck
    2022-08-02T04:16:27+08:002022-08-02T04:16:27+08:00

    每秒速率 = RPS

    建议为您的 my.cnf [mysqld] 部分考虑以尽量减少瓶颈

    Disable server_id with leading # to eliminate all REPL overhead
    have_query_cache=0  # from YES to aliminate all QC overhead
    innodb_flush_log_at_timeout=20  # from 1 for 20 second flush vs every second
    innodb_lru_scan_depth=100  # from 128 for minimim scan depth
    innodb_max_dirty_pages_pct_lwm-0.001  # from 0% to enable pre-flushing
    innodb_max_dirty_pages_pct=0.002  # from 0% to tolerate some dirty pages
    thread_cache_size=64  # from 8 
    read_rnd_buffer_size=32K  # from 1G to reduce handler_read_rnd_next RPS
    read_buffer_size=512K  # from 1G to reduce handler_read_next RPS
    innodb_buffer_pool_size=32G  # from ~ 50G - loading less than 20G data/ndx
    innodb_change_buffer_max_size=50  # from 0% for higher loading rows RPS
    innodb_fast_shutdown=0  # to ensure dirty pages to media before shutdown
    innodb_flushing_avg_loops=4  # from 30 to expedite dirty page reduction
    innodb_read_io_threads=64  # from 4 per stackexchange Q 5666 Rolando's advice
    innodb_write_io-threads=64  # from 4 per 9/12/2011 Rolando's advice
    

    可能还有其他机会需要考虑。

    • 1

相关问题

  • 我在哪里可以找到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