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 / 10257
Accepted
Ran
Ran
Asked: 2012-01-07 01:35:44 +0800 CST2012-01-07 01:35:44 +0800 CST 2012-01-07 01:35:44 +0800 CST

MySql - Como posso acelerar esta consulta

  • 772

Tenho as seguintes tabelas:

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `last_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `account_data` text COLLATE utf8_unicode_ci,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  `twitter_username` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `crypted_password` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `password_salt` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `persistence_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `single_access_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `perishable_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `login_count` int(11) NOT NULL DEFAULT '0',
  `failed_login_count` int(11) NOT NULL DEFAULT '0',
  `last_request_at` datetime DEFAULT NULL,
  `current_login_at` datetime DEFAULT NULL,
  `last_login_at` datetime DEFAULT NULL,
  `current_login_ip` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `last_login_ip` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `is_admin` tinyint(1) DEFAULT '0',
  `referrer_id` int(11) DEFAULT NULL,
  `partner` tinyint(1) DEFAULT '0',
  `subscription_type` varchar(255) COLLATE utf8_unicode_ci DEFAULT 'free',
  `workflow_state` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `persona_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `persona_index` (`persona_id`)
) ENGINE=InnoDB 

e a mesa:

CREATE TABLE `user_actions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `action_type` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `module` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `data` text COLLATE utf8_unicode_ci,
  `timestamp` datetime DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `user_id_index` (`user_id`),
  KEY `action_type_index` (`action_type`),
  KEY `user_action_type_index` (`user_id`,`action_type`),
  KEY `timestamp_index` (`timestamp`),
  KEY `user_id_timestamp_index` (`user_id`,`timestamp`)
) ENGINE=InnoDB 

o problema está na seguinte consulta:

    SELECT user_actions.*, users.twitter_username, users.email FROM `user_actions` 
INNER JOIN users ON (user_actions.user_id=users.id) ORDER BY timestamp DESC LIMIT 0, 30

aqui está a explicação:

user_actions    
The table was retrieved with this index: user_id_timestamp_index
You can speed up this query by querying only fields that are within the index. Or you can create an index that includes every field in your query, including the primary key.
Approximately 76 rows of this table were scanned.
users   
This table was retrieved with a full table scan, which is often quite bad for performance, unless you only retrieve a few rows.
The table was retrieved with this index:
No index was used in this part of the query.
A temporary table was created to access this part of the query, which can cause poor performance. This typically happens if the query contains GROUP BY and ORDER BY clauses that list columns differently.
MySQL had to do an extra pass to retrieve the rows in sorted order, which is a cause of poor performance but sometimes unavoidable.
You can speed up this query by querying only fields that are within the index. Or you can create an index that includes every field in your query, including the primary key.
Approximately 3445 rows of this table were scanned.

esta consulta demora muito para ser executada, alguma ideia de como melhorar?

mysql query
  • 2 2 respostas
  • 5201 Views

2 respostas

  • Voted
  1. Best Answer
    RolandoMySQLDBA
    2012-01-07T09:03:55+08:002012-01-07T09:03:55+08:00

    Aqui está sua consulta original:

    SELECT
        user_actions.*,
        users.twitter_username,
        users.email
    FROM
        `user_actions`  
        INNER JOIN users
        ON (user_actions.user_id=users.id)
        ORDER BY timestamp
        DESC LIMIT 0, 30
    ;
    

    A primeira coisa que noto é que você está juntando duas tabelas inteiras. Como você só precisa de twitter_usernamee emailda userstabela, você só deve ingressar usersusando três colunas id: twitter_usernamee email.

    A segunda coisa é a LIMITcláusula. Ele está sendo executado após a junção. Você deve executá-lo antes da junção. No seu caso, você está solicitando as 30 ações de usuário mais recentes. Se você puder garantir que apenas 30 linhas sejam recuperadas de user_actions, a junção deverá operar muito mais rapidamente.

    Se você ler a resposta de @DTest , seus dois primeiros marcadores já informam o que há de errado na consulta por causa das ações que o mysql executará na coleta de dados de cada tabela. A chave é entender como serão as tabelas temporárias enquanto a consulta está sendo processada e onde os dados residirão (memória ou disco).

    O que você precisa fazer é refatorar a consulta para enganar o MySQL Query Optimizer. Force a consulta a produzir tabelas temporárias menores. Na maioria dos casos, as alterações de configuração em my.cnf devem fazer uma diferença dramática. Em outros casos, como este, refatorar a consulta pode ser suficiente.

    Aqui está minha proposta de mudança para sua consulta que deve funcionar mais rápido:

    SELECT
        ua.*,
        u.twitter_username,
        u.email
    FROM
        (SELECT * FROM `user_actions`
        ORDER BY timestamp DESC LIMIT 30) ua
        LEFT JOIN
        (SELECT id,twitter_username,email FROM `users`) u
        ON (ua.user_id=u.id)
    ;
    

    Aqui estão os motivos para refatorar a consulta:

    MOTIVO Nº 1

    Se você olhar a tabela embutida ua, eu recupero apenas 30 linhas usando LIMIT. Isso acontecerá não importa o tamanho da user_actionsmesa . Já está ordenado porque o ORDER BY timestamp DESCacontece antes do LIMIT.

    MOTIVO Nº 2

    Se você olhar a tabela inline , uela tem id,,, . O é necessário para implementar a junção.twitter_usernameemailid

    MOTIVO Nº 3

    Eu uso LEFT JOINem vez de INNER JOINpor dois (2) motivos:

    1. Preservar a ordem da consulta com base emua
    2. Exiba todas as ações do usuário caso o user_id no uanão exista mais nas userstabelas.

    Fazer essas coisas forçará as tabelas temporárias a serem menores. No entanto, você ainda precisará implementar o marcador nº 3 da resposta do @DTest para evitar que as tabelas temporárias cheguem ao disco.

    • 5
  2. Derek Downey
    2012-01-07T08:00:23+08:002012-01-07T08:00:23+08:00

    Bem, o principal problema é que, como sua consulta não possui nenhuma filtragem (sem WHEREinstrução), ela coloca todas as linhas com colunas user_actions.*, twitter_username, emailem uma tabela temporária para fazer a classificação.

    Então, a primeira coisa que eu faria é tentar limitar o número de linhas que vão para o seu conjunto de resultados. Por exemplo, eu diria adicionar um WHERE timestamp > DATE_SUB(NOW(), INTERVAL 7 DAY)para obter apenas resultados nos últimos 7 dias (se isso for aceitável para o seu caso de uso).

    Em seguida, eu alteraria a consulta para obter apenas as colunas necessárias user_actionspara reduzir a quantidade de informações necessárias para colocar em uma tabela temporária.

    Agora que você pode ou não ter removido linhas/colunas que precisam ser colocadas na tabela temporária para serem classificadas, vamos ver como o MySQL lida com tabelas temporárias. Da documentação sobre a tmp_table_sizevariável (ênfase adicionada):

    O tamanho máximo de tabelas temporárias internas na memória. (O limite real é determinado como o mínimo de tmp_table_size e max_heap_table_size.) 1 Se uma tabela temporária na memória exceder o limite, o MySQL automaticamente a converterá em uma tabela MyISAM em disco.

    Primeiro, deixe-me apontar a ressalva representada pelo sobrescrito 1 : O tamanho da tabela temporária criada na memória é o mínimo de tmp_table_sizeou max_heap_table_size, portanto, se você aumentar um, certifique-se de aumentar o outro.

    Se a quantidade de seus dados exceder o tamanho mínimo dessas duas variáveis, eles serão colocados no disco. O disco está lento. Não faça disco se puder evitá-lo!

    Para recapitular:

    • Limite a quantidade de linhas que você está classificando, usando WHERE. Mesmo que você esteja fazendo um LIMIT, todas as linhas ainda estão sendo colocadas na tabela temporária para classificação.

    • Limite o número de colunas que você está solicitando. Se você não precisa deles, não os peça.

    • Último recurso, aumente o tamanho de tmp_table_sizee max_heap_table_sizese a consulta estiver aumentando sua Created_tmp_disk_tablesvariável de status. Além disso, não aumente isso drasticamente. Pode ter impacto no desempenho, dependendo do seu hardware e da quantidade de RAM que você possui no seu servidor.

    • 3

relate perguntas

  • Existem ferramentas de benchmarking do MySQL? [fechado]

  • 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

    Como ver a lista de bancos de dados no Oracle?

    • 8 respostas
  • Marko Smith

    Quão grande deve ser o mysql innodb_buffer_pool_size?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    restaurar a tabela do arquivo .frm e .ibd?

    • 10 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

    Como selecionar a primeira linha de cada grupo?

    • 6 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
    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
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +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
  • Martin Hope
    bernd_k Quando devo usar uma restrição exclusiva em vez de um índice exclusivo? 2011-01-05 02:32:27 +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