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 / 334094
Accepted
Rohan
Rohan
Asked: 2023-12-15 20:19:47 +0800 CST2023-12-15 20:19:47 +0800 CST 2023-12-15 20:19:47 +0800 CST

Como adicionar índice a uma tabela grande com 60 milhões de registros sem tempo de inatividade?

  • 772
A recompensa expira em 6 dias . As respostas a esta pergunta são elegíveis para uma recompensa de +150 reputação. Rohan quer recompensar uma resposta existente .

temos lutado com um problema nos últimos dias. Queremos adicionar um índice a uma tabela enorme com 60 milhões de registros. No início, tentamos adicioná-lo com a sintaxe básica do MySQL. Mas isso obstruiu nosso banco de dados de produção. Essa tabela é usada com muita frequência em consultas de produção. Então tudo sofreu.

Nosso banco de dados está hospedado no AWS RDS. É Mysql 5.7. Estamos usando Laravel como nosso framework PHP

A próxima coisa que lemos foi que podemos copiar a tabela atual para uma nova. Em seguida, adicione o índice à nova tabela. Em seguida, mude o modelo laravel para usar a nova tabela. Achamos que fazia sentido e que seria bastante fácil

Mas copiar os dados da tabela de uma tabela para a nova demorava muito tempo. Nossos cálculos mostraram que levaria dias. Tentamos usar Laravel e também comandos SQL. Mas foi muito lento de qualquer maneira.

Depois tentamos exportar os dados como CSV e importá-los, mas, novamente, muito lento. Os primeiros milhões de registros seriam inseridos rapidamente, mas a inserção da tabela se tornaria extremamente lenta.

Finalmente tentamos mysqldumpe percebemos que ele também bloqueia a nova tabela durante a inserção, talvez por isso seja rápido o suficiente. Demorou cerca de 6 horas para copiar a tabela para uma nova. MAS faltavam 2 milhões de registros neste método. Também verificamos quantos registros entraram na tabela existente durante a exportação/importação, eram apenas cerca de 100K. Portanto, faltavam 1,9 milhão de registros na exportação/importação e não conseguimos descobrir o porquê.

Depois de passar por todos esses caminhos diferentes, decidimos colocar o aplicativo em tempo de inatividade e adicionar o índice na enorme mesa

Eu queria saber se outras pessoas também enfrentam esse problema? Existe uma maneira de adicionar índices em uma tabela enorme sem causar tempo de inatividade na produção? Ou existe uma maneira mais rápida de copiar uma grande tabela MySQL sem perda de dados?

mysql
  • 1 1 respostas
  • 7 Views

1 respostas

  • Voted
  1. Best Answer
    RolandoMySQLDBA
    2023-12-16T00:21:12+08:002023-12-16T00:21:12+08:00

    Para este exemplo, digamos que você tenha o seguinte no banco de dados mydb

    CREATE TABLE mytable (
        id INT NOT NULL AUTO_INCREMENT,
        num INT DEFAULT 0,
        dat VARCHAR(32),
        PRIMARY KEY (id)
    );
    

    e você deseja criar dois índices da seguinte maneira:

    ALTER TABLE mytable
        ADD INDEX num_ndx (ndx)
       ,ADD INDEX dat_ndx (dat)
    ;
    

    Existem dois métodos que você realmente precisa examinar.

    MÉTODO #1: Use DDL Online

    Você pode iniciar sua alteração com ALTER TABLE usando a seguinte sintaxe

    ALTER TABLE mytable
        ADD INDEX num_ndx (ndx)
       ,ADD INDEX dat_ndx (dat)
       ,ALGORITHM=INPLACE,LOCK=NONE
    ;
    

    Como você está adicionando um índice e não alterando nenhum tipo de dados em nenhuma coluna, os dados das linhas serão verificados para gerar páginas de índice.

    MÉTODO # 2: Use pt-online-schema-change

    Esta ferramenta tem sido um salva-vidas para muitos ao longo dos anos

    Você precisa executar isso em duas fases

    FASE #1: Teste a seco

    Esta fase, que é basicamente uma verificação de sintaxe, leva menos de 5 segundos para ser executada

    MYSQL_HOST=...
    MYSQL_USER=...
    MYSQL_PASS=...
    ALTER_TABLE_CLAUSE="ADD INDEX num_ndx (ndx),ADD INDEX dat_ndx (dat)"
    RUNMODE"--dry-run"
    PTOSC_OPTIONS="--alter-foreign-keys-method=auto"
    PTOSC_OPTIONS="${PTOSC_OPTIONS} --print"
    PTOSC_OPTIONS="${PTOSC_OPTIONS} --check-interval 10"
    PTOSC_OPTIONS="${PTOSC_OPTIONS} --max-lag 300"
    PTOSC_OPTIONS="${PTOSC_OPTIONS} ${RUNMODE}"
    DB-mydb
    TB=mytable
    
    pt-online-schema-change --alter "${ALTER_TABLE_CLAUSE}" \ 
        h=${MYSQL_HOST},u=${MYSQL_USER},p=${MYSQL_PASS},D=${DB},t=${TB} \
        ${PTOSC_OPTIONS} >dryrun.log 2>&1
    

    FASE #2: Corrida ao Vivo

    MYSQL_HOST=...
    MYSQL_USER=...
    MYSQL_PASS=...
    ALTER_TABLE_CLAUSE="ADD INDEX num_ndx (ndx),ADD INDEX dat_ndx (dat)"
    RUNMODE"--execute"
    PTOSC_OPTIONS="--alter-foreign-keys-method=auto"
    PTOSC_OPTIONS="${PTOSC_OPTIONS} --print"
    PTOSC_OPTIONS="${PTOSC_OPTIONS} --check-interval 10"
    PTOSC_OPTIONS="${PTOSC_OPTIONS} --max-lag 300"
    PTOSC_OPTIONS="${PTOSC_OPTIONS} ${RUNMODE}"
    DB-mydb
    TB=mytable
    
    pt-online-schema-change --alter "${ALTER_TABLE_CLAUSE}" \ 
        h=${MYSQL_HOST},u=${MYSQL_USER},p=${MYSQL_PASS},D=${DB},t=${TB} \
        ${PTOSC_OPTIONS} >liverun.log 2>&1
    

    Aqui está o que pt-online-schema-change fará

    CREATE TABLE _mytable_new LIKE mytable;
    ALTER TABLE _mytable_new ADD INDEX num_ndx (ndx),ADD INDEX dat_ndx (dat);
    

    pt-online-schema-change cria três gatilhos

    • INSERT AFTER Trigger de mytable para _mytable_new
    • UPDATE AFTER Trigger de mytable para _mytable_new
    • DELETE AFTER Trigger de mytable para _mytable_new

    Então, pt-online-schema-change copiará as linhas de mytable para _mytable_new. Se houver INSERTs, UPDATEs ou DELETEs durante a execução, os gatilhos preencherão essas alterações em _mytable_new

    Depois que cada linha for copiada para _mytable_new, pt-online-schema-change fará isso

    ANALYZE TABLE _mytable_new;
    RENAME TABLE mytable TO _mytable_old,_mytable_new TO mytable;
    DROP TABLE _mytable_old;
    

    Os três gatilhos são eliminados no final.

    Você pode ver essas etapas no arquivo dryrun.log

    Você pode ver o progresso em liverun.log

    NOTA: Execute o liverun em uma sessão de tela ou em um processo em segundo plano

    • 5

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

    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