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 / 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

Por que o MySQL faria E/S síncrona serial?

  • 772

Ao olhar para uma consulta particularmente irritante sobre tabelas MyISAM que leva muito tempo para executar em várias ocasiões, notei que o MySQL parece expor um padrão de I/O bastante estranho: ao executar uma única consulta e ter que fazer um quantidade de E/S (por exemplo, para uma varredura de tabela ou quando os caches estão vazios, echo 3 > /proc/sys/vm/drop_cachesentão os índices precisam ser carregados do disco primeiro), o tamanho da fila para o dispositivo de bloco subjacente está próximo do valor 1, com desempenho péssimo de apenas 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

Embora os 150 IOPS sejam simplesmente o que um único disco na configuração fornecida é capaz de fornecer em termos de I/O aleatório, o resultado ainda me surpreende, pois eu esperaria que o MySQL fosse capaz de executar I/O assíncrono para leituras e buscar um grande quantidade de blocos simultaneamente em vez de lê-los e avaliá-los um por um, negligenciando efetivamente os ganhos de paralelização disponíveis nas configurações de RAID. Qual decisão de projeto ou opção de configuração é responsável por isso? Este é um problema específico da plataforma?

Embora eu tenha testado isso com tabelas MyISAM grandes, vejo efeitos semelhantes com as mesmas tabelas convertidas para InnoDB (embora não seja tão ruim, a consulta de amostra ainda leva de 20 a 30 segundos, com a maior parte do tempo gasta na leitura do disco com um comprimento de fila de 1) depois de reiniciar o daemon mysql e, portanto, os buffer pools estão vazios. Também verifiquei que o mesmo problema persiste no 5.6 GA e no atual marco 14 do 5.7 - enquanto estiver usando um único thread de consulta, o MySQL parece incapaz de paralelizar as operações de E/S necessárias para o processamento da consulta.


A pedido, alguns detalhes adicionais sobre o cenário. O comportamento pode ser observado com vários tipos de consulta. Eu escolhi arbitrariamente um para testes adicionais, que é mais ou menos assim:

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;

Sei que há espaço para otimização, mas decidi deixar por isso mesmo por vários motivos e me concentrar em encontrar uma explicação geral para o padrão de E/S inesperado que estou vendo.

As tabelas usadas têm um monte de dados nelas:

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)

Agora, quando estou executando a consulta acima nessas tabelas, estou obtendo tempos de execução de mais de 1 minuto, enquanto o sistema está aparentemente continuamente ocupado lendo dados do disco com um único thread.

O perfil para uma execução de consulta de amostra (que levou 1 minuto e 9,17 segundos neste exemplo) tem a seguinte aparência:

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

2 respostas

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

    Primeiro, deixe-me esclarecer confirmando que o MyISAM não faz E/S assíncrona, mas que o InnoDB faz e fará por padrão no MySQL 5.5. Antes do 5.5, ele usava "AIO simulado" usando threads de trabalho.

    Eu acho que também é importante distinguir entre três situações:

    1. Múltiplas consultas sendo executadas ao mesmo tempo
    2. Uma única consulta sendo executada em paralelo
    3. Algum tipo de leitura lógica antecipada para varreduras de tabela / casos claros em que as próximas páginas são bem conhecidas.

    Para (1) I/O será capaz de executar em paralelo para isso. Existem alguns limites com o MyISAM: bloqueio de tabela e um bloqueio global protegendo o key_buffer(cache de índice). InnoDB no MySQL 5.5+ realmente brilha aqui.

    Para (2), isso não é suportado no momento. Um bom caso de uso seria com particionamento, onde você poderia pesquisar cada tabela particionada em paralelo.

    Para (3) o InnoDB tem leitura antecipada linear para ler uma extensão completa (grupo de 64 páginas) se > 56 páginas forem lidas (isso é configurável), mas há espaço para aprimoramento adicional. O Facebook escreveu sobre a implementação de readhead lógico em sua ramificação (com um ganho de perf 10x em tablecans).

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

    Espero que missing_datanão seja MyISAM porque uma tabela MyISAM vazia geralmente tem 1024 bytes .MYI. Um tamanho de byte diferente de zero é esperado de um MyISAM. Um byte zero .MYIsoa um pouco assustador para mim.

    Se você executar esta consulta de metadados

    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';
    

    e o mecanismo dessa mesa é MyISAM, você precisa repará-lo.

    NOTA LATERAL: Se enginefor NULL, é uma exibição. Se for uma visualização ou não for MyISAM, ignore o restante da minha postagem e adicione essa informação à pergunta. Se a tabela for MyISAM, continue lendo...

    De acordo com sua consulta de metadados, missing_data.MYDé cerca de 46M.

    Primeiro, execute este

    SHOW CREATE TABLE mydb.missing_data\G
    

    Você obterá a descrição da tabela ou uma mensagem de erro dizendo algo como

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

    Se você obtiver a descrição da tabela e for MyISAM, execute

    OPTIMIZE TABLE mydb.missing_data;
    

    Ele recriará a tabela sem fragmentação e calculará novas estatísticas de índice. Se isso não funcionar, tente:

    REPAIR TABLE mydb.missing_data;
    

    Isso deve regenerar as páginas de índice para o MyISAM.

    Apenas por segurança (se estiver usando o MySQL 5.6), execute-o após o reparo

    FLUSH TABLES mydb.missing_data;
    

    Sua pergunta

    Os índices de sua tabela podem não ser carregados na memória se o MySQL Query Optimizer decidir não usar. Se sua cláusula WHERE determinar que uma quantidade significativa de linhas deve ser lida a partir dos índices, o MySQL Query Optimizer verá isso ao construir o plano EXPLAIN e decidirá usar uma verificação completa da tabela.

    As operações paralelas de E/S em uma tabela MyISAM são inatingíveis porque não são configuráveis.

    O InnoDB pode ser ajustado para aumentar o desempenho assim.

    • 2

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