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

ratatata's questions

Martin Hope
ratatata
Asked: 2024-04-28 08:36:59 +0800 CST

A consulta MySQL é muito lenta para o que é, ajude-me a depurá-la

  • 6

Eu tenho a seguinte consulta que leva cerca de 5 segundos para ser concluída, costumava ser 0,5s, depois 1s, 2s agora estamos em 5s, apesar do fato de a quantidade de dados no banco de dados não ter mudado! Esta consulta faz um select para obter uma porção de dados para processar e atualizar algumas colunas (nenhuma nova linha é adicionada), normalmente tem um "limite 500" mas o tempo de consulta com "limite 1" e "limite 500" é o mesmo, então pela simplicidade mudei esse post para "limite 1".

Fiz uma cópia da tabela de produção no mesmo servidor para poder executar vários testes e alterações sem prejudicar os dados de produção, também alguns dados foram ofuscados mas todas as consultas e suas saídas são reais

A tabela “teste” possui 34 milhões de linhas e tamanho de 11,3 GB, cujo índice é de 3,3 GB. O servidor é Freebsd 13.2, mysql 8.0.35 em um drive Samsung nvme bastante decente, 64 GB de RAM e innodb_buffer_pool_size = 42G. O servidor não está trocando e tem quase 4 GB de memória livre. Há uma grande quantidade de carga de IO de disco proveniente de consultas para outros bancos de dados hospedados no mesmo servidor (e provavelmente principalmente log binário porque este é o mestre de replicação), no entanto, se eu desabilitar todas as outras consultas e executar apenas a consulta em questão, o tempo de execução é exatamente o mesmo.

A consulta lenta:

SELECT t_channel_id,login FROM test WHERE t_channel_id IS NOT NULL AND videos_scanned IS NULL AND videos_scanned_lock=0 limit 1;
+--------------+---------------+
| t_channel_id | login         |
+--------------+---------------+
| 933271419    | sunday1funday |
+--------------+---------------+
1 row in set (4.43 sec)

O índice é usado corretamente e cobre todas as colunas WHERE. Se eu remover a coluna videos_scanned_lock da consulta, o tempo será de 0,35s (ainda lento, mas muito mais rápido) se eu remover APENAS a coluna t_channel_id da consulta, o tempo será 0s

Eu tenho uma teoria de por que o tempo era muito mais rápido no início e agora está em torno de 5s. Agora estamos processando registros em torno de 30 milhões de linhas (de 34) e no início as linhas selecionadas eram do início da tabela e agora tipo “quase toda a tabela tem que ser verificada primeiro para chegar aos resultados”. Mas 34 milhões de registros são muito para o MySQL? Suponho que não, a tabela inteira tem menos de 1/4 do tamanho do buffer innodb. Como prova desta teoria, no parágrafo anterior escrevi que se eu remover a coluna t_channel_id da consulta, o tempo será 0s – isso porque se eu remover esta coluna serão mostrados resultados desde o início da tabela. A segunda prova, é que a consulta dá certo resultado, se eu alterar o valor de t_channel_id deste resultado para um número muito menor, o tempo de consulta será muito menor (porque com um ID menor ele será encontrado mais cedo). Tenho certeza de que respondi minha própria pergunta, MAS por que isso está acontecendo? Acredito que algo deve estar configurado incorretamente, mas não consigo encontrar o que é e espero encontrar uma resposta aqui. Qualquer dica para melhorar esta situação será apreciada :)

Abaixo, forneço dados de depuração: mostre criar tabela, criador de perfil, descreva análise e my.cnf

SHOW CREATE TABLE test;

CREATE TABLE `test` (
  `channel_id` bigint NOT NULL AUTO_INCREMENT,
  `t_channel_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin DEFAULT NULL,
  `login` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
  `display_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
  `videos_scanned` datetime DEFAULT NULL,
  `videos_scanned_lock` int NOT NULL DEFAULT '0',
  PRIMARY KEY (`channel_id`) USING BTREE,
  UNIQUE KEY `login` (`login`),
  KEY `t_channel_id_2` (`t_channel_id`,`videos_scanned`,`videos_scanned_lock`)
) ENGINE=InnoDB AUTO_INCREMENT=34626837 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
describe SELECT t_channel_id,login FROM test WHERE t_channel_id IS NOT NULL AND videos_scanned IS NULL AND videos_scanned_lock=0 limit 1;
+----+-------------+-------+------------+-------+----------------+----------------+---------+------+----------+----------+-----------------------+
| id | select_type | table | partitions | type  | possible_keys  | key            | key_len | ref  | rows     | filtered | Extra                 |
+----+-------------+-------+------------+-------+----------------+----------------+---------+------+----------+----------+-----------------------+
|  1 | SIMPLE      | test  | NULL       | range | t_channel_id_2 | t_channel_id_2 | 1023    | NULL | 16992061 |     1.00 | Using index condition |
+----+-------------+-------+------------+-------+----------------+----------------+---------+------+----------+----------+-----------------------+
describe analyze SELECT t_channel_id,login FROM test WHERE t_channel_id IS NOT NULL AND videos_scanned IS NULL AND videos_scanned_lock=0 limit
1;
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                                                                                                                                                                                                                                                             |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Limit: 1 row(s)  (cost=7.65e+6 rows=1) (actual time=4407..4407 rows=1 loops=1)
    -> Index range scan on test using t_channel_id_2 over (NULL < t_channel_id), with index condition: ((test.videos_scanned_lock = 0) and (test.t_channel_id is not null) and (test.videos_scanned is null))  (cost=7.65e+6 rows=17e+6) (actual time=4407..4407 rows=1 loops=1)
 |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (4.41 sec)
SET profiling = 1;
Query OK, 0 rows affected, 1 warning (0.00 sec)

SELECT t_channel_id,login FROM test WHERE t_channel_id IS NOT NULL AND videos_scanned IS NULL AND videos_scanned_lock=0 limit 1;
+--------------+---------------+
| t_channel_id | login         |
+--------------+---------------+
| 933271419    | sunday1funday |
+--------------+---------------+
1 row in set (4.43 sec)

show profile cpu;
+--------------------------------+----------+----------+------------+
| Status                         | Duration | CPU_user | CPU_system |
+--------------------------------+----------+----------+------------+
| starting                       | 0.000142 | 0.000372 |   0.000036 |
| Executing hook on transaction  | 0.000063 | 0.000048 |   0.000004 |
| starting                       | 0.000027 | 0.000022 |   0.000002 |
| checking permissions           | 0.000028 | 0.000025 |   0.000003 |
| checking permissions           | 0.000018 | 0.000016 |   0.000001 |
| Opening tables                 | 0.000098 | 0.000094 |   0.000009 |
| init                           | 0.000025 | 0.000019 |   0.000002 |
| System lock                    | 0.000026 | 0.000024 |   0.000002 |
| optimizing                     | 0.000091 | 0.000084 |   0.000008 |
| statistics                     | 0.000284 | 0.000269 |   0.000026 |
| preparing                      | 0.000126 | 0.000119 |   0.000011 |
| executing                      | 4.426675 | 6.156588 |   0.156978 |
| end                            | 0.000016 | 0.000005 |   0.000001 |
| query end                      | 0.000004 | 0.000003 |   0.000000 |
| waiting for handler commit     | 0.000005 | 0.000005 |   0.000001 |
| closing tables                 | 0.000006 | 0.000006 |   0.000000 |
| freeing items                  | 0.000010 | 0.000014 |   0.000002 |
| logging slow query             | 0.000027 | 0.000020 |   0.000001 |
| cleaning up                    | 0.000008 | 0.000007 |   0.000001 |
+--------------------------------+----------+----------+------------+
19 rows in set, 1 warning (0.00 sec)
[mysqld]
user                            = mysql
port                            = 3306
socket                          = /tmp/mysql.sock
bind-address                    = 0.0.0.0
datadir                         = /var/db/mysql
log-output                      = FILE
relay-log-recovery              = 1
slow-query-log                  = 1
server-id                       = 29
sync_binlog                     = 1
sync_relay_log                  = 1
binlog_cache_size               = 16M
binlog_expire_logs_seconds      = 43200
default_password_lifetime       = 0
enforce-gtid-consistency        = 1
gtid-mode                       = On
safe-user-create                = 1
lower_case_table_names          = 1
explicit-defaults-for-timestamp = 1
myisam-recover-options          = BACKUP,FORCE
table_open_cache                = 16384
table_definition_cache          = 8192
net_retry_count                 = 16384
key_buffer_size                 = 256M
max_allowed_packet              = 64M
long_query_time                 = 0.2
innodb_buffer_pool_size         = 42G
innodb_data_home_dir            = /var/db/mysql
innodb_log_group_home_dir       = /var/db/mysql
innodb_data_file_path           = ibdata1:128M:autoextend
innodb_temp_data_file_path      = ibtmp1:128M:autoextend
innodb_flush_method             = O_DSYNC
innodb_log_buffer_size          = 32M
innodb_write_io_threads         = 12
innodb_read_io_threads          = 12
innodb_autoinc_lock_mode        = 2
innodb_redo_log_capacity        = 8192M
log_error                       = /var/db/mysql/mysql-error.log
slow_query_log_file             = /var/db/mysql/mysql-slow.log
skip_name_resolve
mysqlx                          = 0
tls_version                     = TLSv1.2
innodb_flush_log_at_trx_commit  = 0
replica_parallel_workers        = 1
binlog_group_commit_sync_delay  = 10000

Editar para Ergest:

...
KEY `channel_id` (`videos_scanned_lock`,`channel_id`,`t_channel_id`) USING BTREE
SELECT t_channel_id,login FROM test force index (channel_id) WHERE t_channel_id IS NOT NULL AND videos_scanned IS NULL AND videos_scanned_lock=0 limit 1;
+--------------+----------------+
| t_channel_id | login          |
+--------------+----------------+
| 921437844    | marryme2       |
+--------------+----------------+
1 row in set (50.80 sec)
describe SELECT t_channel_id,login FROM test force index (channel_id) WHERE t_channel_id IS NOT NULL AND videos_scanned IS NULL AND videos_scanned_lock=0 limit 1;
+----+-------------+-------+------------+------+---------------+------------+---------+-------+-------+----------+------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key        | key_len | ref   | rows  | filtered | Extra                              |
+----+-------------+-------+------------+------+---------------+------------+---------+-------+-------+----------+------------------------------------+
|  1 | SIMPLE      | test  | NULL       | ref  | channel_id    | channel_id | 4       | const | 68378 |     9.00 | Using index condition; Using where |
+----+-------------+-------+------------+------+---------------+------------+---------+-------+-------+----------+------------------------------------+
1 row in set, 1 warning (0.00 sec)
describe format=json SELECT t_channel_id,login FROM test force index (channel_id) WHERE t_channel_id IS NOT NULL AND videos_scanned IS NULL AND videos_scanned_lock=0 limit 1;
....
 {
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "2094461.53"
    },
    "table": {
      "table_name": "test",
      "access_type": "ref",
      "possible_keys": [
        "t_channel_id_2",
        "channel_id"
      ],
      "key": "channel_id",
      "used_key_parts": [
        "videos_scanned_lock"
      ],
      "key_length": "4",
      "ref": [
        "const"
      ],
      "rows_examined_per_scan": 16992061,
      "rows_produced_per_join": 1529285,
      "filtered": "9.00",
      "index_condition": "(`db`.`test`.`t_channel_id` is not null)",
      "cost_info": {
        "read_cost": "395255.43",
        "eval_cost": "152928.54",
        "prefix_cost": "2094461.53",
        "data_read_per_join": "4G"
      },
      "used_columns": [
        "t_channel_id",
        "login",
        "videos_scanned",
        "videos_scanned_lock"
      ],
      "attached_condition": "(`db`.`test`.`videos_scanned` is null)"
    }
  }
} |

Para @Rick James

Simplesmente não funciona

show create table test;
....
KEY `t_channel_id` (`t_channel_id`,`login`,`videos_scanned`,`videos_scanned_lock`)
SELECT t_channel_id,login FROM test force index (t_channel_id) WHERE t_channel_id IS NOT NULL AND videos_scanned IS NULL AND videos_scanned_loc
k=0 limit 1;
+--------------+----------------+
| t_channel_id | login          |
+--------------+----------------+
| 921437844    | blahblahcar |
+--------------+----------------+
1 row in set (9.99 sec)
describe SELECT t_channel_id,login FROM test force index (t_channel_id) WHERE t_channel_id IS NOT NULL AND videos_scanned IS NULL AND videos_scanned_lock=0 limit 1;
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+----------+----------+--------------------------+
| id | select_type | table | partitions | type  | possible_keys | key          | key_len | ref  | rows     | filtered | Extra                    |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+----------+----------+--------------------------+
|  1 | SIMPLE      | test  | NULL       | range | t_channel_id  | t_channel_id | 1023    | NULL | 16992061 |     0.02 | Using where; Using index |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+----------+----------+--------------------------+
explain format=json SELECT t_channel_id,login FROM test force index (t_channel_id) WHERE t_channel_id IS NOT NULL AND videos_scanned IS NULL AND videos_scanned_lock=0 limit 1;
{
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "4712106.82"
    },
    "table": {
      "table_name": "test",
      "access_type": "range",
      "possible_keys": [
        "t_channel_id"
      ],
      "key": "t_channel_id",
      "used_key_parts": [
        "t_channel_id"
      ],
      "key_length": "1023",
      "rows_examined_per_scan": 16992061,
      "rows_produced_per_join": 3906,
      "filtered": "0.02",
      "using_index": true,
      "cost_info": {
        "read_cost": "4711716.19",
        "eval_cost": "390.62",
        "prefix_cost": "4712106.82",
        "data_read_per_join": "11M"
      },
      "used_columns": [
        "t_channel_id",
        "login",
        "videos_scanned",
        "videos_scanned_lock"
      ],
      "attached_condition": "((`db`.`test`.`videos_scanned_lock` = 0) and (`db`.`test`.`t_channel_id` is not null) and (`db`.`test`.`videos_scanned` is null))"
    }
  }
mysql
  • 2 respostas
  • 110 Views

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