AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 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

Qual é o gargalo no SELECT das tabelas InnoDB?

  • 772

Para uma tabela InnoDB com 500 milhões de linhas (em uma unidade NVMe separada), SELECT COUNT(*)leva cerca de 3 minutos.

SHOW ENGINE INNODB STATUS\Gmostra ROW OPERATIONScerca de 2 milhões de leituras/s, o que é consistente com o tempo que a consulta leva.

Também mostra FILE I/Ocerca de 3.000 leituras/s. Isso é semelhante ao read from iostat, que também mostra a velocidade de leitura de cerca de 50 MB/s.

O NVMe tem muito mais capacidade para ler os dados do disco.

Eu me pergunto qual é o gargalo aqui? Ainda I/Oé ou é o processamento do MySQL?

EXEMPLO

Fiz um teste reprodutível básico.

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)

Depois de reiniciarMySQL

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

na ausência de qualquer outra atividade, consegui

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

A pergunta-chave: é o mais rápido que você pode executar essa consulta em um NVMe típico?

Configurações:

  • Conjunto de buffers de 50 GB. O ibdarquivo tem 17,7 GB.
  • CPU é 16/32 núcleos/threads.
  • innodb_io_threadsnão tem efeito. Eu tentei 4 (padrão) e 64 (máximo).

e

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)

Informações adicionais sobre a mesa

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 respostas
  • 75 Views

2 respostas

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

    Questão simples; não é uma resposta simples. Tenha paciência comigo enquanto eu divagar...

    SELECT COUNT(*) FROM tblusará o índice "menor". Por favor, forneça SHOW CREATE TABLEpara que possamos discutir detalhes. Providencie também SHOW TABLE STATUSpara que possamos discutir os tamanhos.

    Dado que o escolhido INDEXé, digamos, 4GB em disco, divida isso por 16K para obter 256K blocos que precisam ser lidos. Alguns dos blocos podem já estar em cache. Infelizmente, esses números não correspondem a nada que você deu.

    Outra maneira de ver o esforço é executando isso antes e depois do SELECT:

     SHOW GLOBAL STATUS LIKE 'InnoDB%';
    

    Em seguida, subtraia os números. Alguns serão contagens de bytes; alguns com contagens de blocos. Há um fator de 16K entre os dois, deve ser óbvio para ver qual é qual. O em questão pode ser Innodb_buffer_pool_pages_data. Faça o processo uma segunda vez; veja como esse número muda.

    Até agora, não abordei sua pergunta diretamente. Vamos ver se consigo um pouco mais perto...

    • O InnoDB usa um thread principal para a consulta. [Aviso: a versão mais recente tenta fazer algum paralelismo para COUNT(*).]
    • Ele usa um thread em segundo plano para fazer a E/S real, mas isso realmente não importa, porque...
    • Ele lerá um bloco, contará as linhas e passará para o próximo bloco.
    • Pode haver atividade não relacionada acontecendo ao mesmo tempo. Por exemplo, se você inseriu recentemente muitas linhas, a atualização dos índices secundários pode estar atingindo o disco agora.
    • Como o COUNT deve ler cada bloco na RAM no buffer_pool, outros blocos podem precisar ser removidos desse cache. Isso pode levar a gravações de disco enquanto você executa uma tarefa essencialmente somente leitura.
    • Se você executar a consulta duas vezes, a segunda vez pode ser muito mais rápida que a primeira -- isso se deve ao fato de a primeira execução preencher o cache; o segundo não está fazendo nenhuma E/S! Mas...
    • Se o índice usado for maior do que cabe no cache, cada execução fará muitas leituras de E/S.
    • O InnoDB é mais projetado para fazer várias ações de conexões separadas "simultaneamente". Por exemplo, você pode fazer 10 contagens ao mesmo tempo em, digamos, 6 segundos. Com o que você se importa? Latência -- 3 segundos para uma única consulta versus taxa de transferência -- 10 consultas em 6 segundos?
    • Se essas 10 consultas estiverem tocando nos mesmos blocos, o armazenamento em cache evitará muitas E/S. Se eles estiverem tocando em blocos diferentes, a unidade de disco pode ser o gargalo.
    • 1
  2. Best Answer
    Wilson Hauck
    2022-08-02T04:16:27+08:002022-08-02T04:16:27+08:00

    Taxa por segundo = RPS

    Sugestões a serem consideradas para sua seção my.cnf [mysqld] para minimizar gargalos

    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
    

    Há provavelmente oportunidades adicionais a serem consideradas.

    • 1

relate perguntas

  • Onde posso encontrar o log lento do mysql?

  • Como posso otimizar um mysqldump de um banco de dados grande?

  • Quando é o momento certo para usar o MariaDB em vez do MySQL e por quê?

  • Como um grupo pode rastrear alterações no esquema do banco de dados?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

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

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve