Mysql: criar índice em 1,4 bilhões de registros

9

Eu tenho uma tabela com 1,4 bilhão de registros. A estrutura da tabela é a seguinte:

CREATE TABLE text_page (
    text VARCHAR(255),
    page_id INT UNSIGNED
) ENGINE=MYISAM DEFAULT CHARSET=ascii

O requisito é criar um índice sobre a coluna text.

O tamanho da tabela é de cerca de 34G.

Eu tentei criar o índice pela seguinte instrução:

ALTER TABLE text_page ADD KEY ix_text (text)

Após 10 horas de espera, finalmente desisto dessa abordagem.

Existe alguma solução viável para esse problema?

UPDATE : é improvável que a tabela seja atualizada, inserida ou excluída. A razão pela qual criar um índice na coluna texté porque esse tipo de consulta sql seria frequentemente executado:

SELECT page_id FROM text_page WHERE text = ?

ATUALIZAÇÃO : Eu resolvi o problema particionando a tabela.

A tabela é dividida em 40 partes na coluna text. A criação do índice na tabela leva cerca de 1 hora para ser concluída.

Parece que a criação do índice MySQL se torna muito lenta quando o tamanho da tabela se torna muito grande. E o particionamento reduz a tabela em troncos menores.

SiLent SoNG
fonte
1
O que há de errado em usar a CREATE INDEXdeclaração normal ?
Eu sugiro que esta pergunta seja melhor no ServerFault - é mais um administrador de banco de dados do que uma questão de programação.
daí
@ Derk: a abordagem normal de CREATE INDEX é muito lenta. Eu tenho que concluir a tarefa dentro de 1 dia.
1
Hmm ... eu não acho que você possa contornar isso. A criação do índice exige que o DBMS verifique todos os registros, reúna seus campos de "texto" e insira / altere os nós / subárvores correspondentes da árvore. E isso leva muito tempo para 34G ...
chiccodoro
Quanta memória seu servidor de banco de dados possui? Você configurou o MySQL para usar toda essa memória ou está se limitando?

Respostas:

4

Poderia ser o seu sistema simplesmente não está à altura da tarefa? Eu não uso o MySQL (SQL Server aqui), mas conheço a dificuldade de indexar uma tabela de entrada de 800 milhões. Basicamente .... você precisa do hardware certo para isso (como em: muitos discos rápidos). Agora uso quase uma dúzia de Velociraptors e o desempenho é ótimo;)

Servidores SQL (não como o MS SQL Server, mas como servidores de banco de dados usando SQL) vivem e morrem com acesso a discos, e discos normais simplesmente não estão à altura da tarefa de operações maiores.

TomTom
fonte
Minha dúvida é que a criação de índice geralmente é muito rápida se a contagem de registros for pequena; digamos, milhões. Mas quando a contagem é de bilhões, a criação do índice se torna muito lenta. Parece que o crescimento do tempo é exponencial.
Realmente não deveria ser. O MySQL em geral tem limites, mas não é um banco de dados de merda, e isso seria MUITO ruim. A geração de índice fica mais lenta, mas pelo log (n), não (n), portanto não deve ser TÃO ruim.
TomTom
4

Você pode criar um índice nos primeiros (por exemplo, 10) caracteres do campo de texto.

Dos documentos:

É possível criar índices que usam apenas a parte inicial dos valores da coluna, usando a sintaxe col_name (length) para especificar um comprimento de prefixo de índice:

CREATE INDEX ix_text ON text_page (text(10))

fonte
4

Eu resolvi o problema particionando a tabela.

A tabela é dividida em 40 partes na coluna text. A criação do índice na tabela leva cerca de 1 hora para ser concluída.

Parece que a criação do índice MySQL se torna muito lenta quando o tamanho da tabela se torna muito grande. E o particionamento reduz a tabela em troncos menores.

SiLent SoNG
fonte
Então 40 x 1 hora é menos de 10 horas?
Symcbean # 5/15
3

Defina o sort_buffer_size como 4 GB (ou o quanto você puder, dependendo da quantidade de memória que você possui).

No momento, o índice de criação está fazendo uma classificação, mas como você tem um tamanho de sort_buffer_size de 32 MB, basicamente está debulhando o disco rígido desnecessariamente.

tster
fonte
Essas postagens discordam diretamente de você: xaprb.com/blog/2010/05/09/how-to-tune-mysqls-sort_buffer_size e melhor ronaldbradford.com/blog/… Parece que esse valor não é global, mas sim por consulta, ou seja, 4 GB por consulta que você está recomendando. Além disso, quando excede 256K, ele é mapeado para o disco em vez de ser a memória real da memória. Se você o mantiver pequeno, será necessário vários passes, mas evita o disco (não é trocado).
Ry4an Brase 19/07/10
3

Se você não precisar fazer consultas como:

SELECT page_id FROM text_page WHERE text LIKE '?%';

Eu sugeriria criar uma nova coluna de hash e indexar a tabela pela coluna. O tamanho geral da tabela + índice pode ser muito menor.

UPD : A propósito, 1,4 bilhão de números inteiros de chave primária ocupam cerca de 6 GB, ou seja, o comprimento médio da string é inferior a 30 caracteres; a indexação em um prefixo pode ser mais preferível.

Você também deve dar uma olhada no mecanismo de armazenamento MERGE .

newtover
fonte
2

Uma maneira de fazer isso é criar uma nova tabela com o conjunto de índices e copiar os dados para a nova tabela.

Além disso, verifique se você tem espaço temporário suficiente.

descompilado
fonte
1
Eu tentei essa abordagem. Após 10 horas, menos de 1% dos dados foram copiados para a nova tabela.
1
Cara ... são 1,4 bilhões de registros. Não milhões, bilhões. Isso é muito. Vai demorar um pouco, independentemente.
Se você optar por fazer esse método, divida a cópia em partes menores. Diga cerca de 100 a 200 milhões para cada cópia.
1
@ descompilar, dividi-lo em pedaços menores não fará nada (na verdade, pode torná-lo menos eficiente). @Bryan, Mesmo com 1,4 bilhão de registros, não deve demorar 1.000 horas.
0

Caso você ainda esteja se perguntando como fazer isso da melhor maneira, sugiro que você use uma ferramenta de alteração de tabela on-line.

Existem muitos deles na internet, um dos famosos é:

Temos os mesmos problemas com grandes tabelas (mais de 500mil registros) e a alteração é perfeita. Ele cria uma nova tabela tmp, adiciona gatilho à tabela original (para os novos registros de atualização / exclusão / inserção) e, enquanto isso, copia todos os registros para a nova tabela (com a nova estrutura)

Boa sorte!

Ali Alwash
fonte