Mysql: crear índice en 1.4 billones de registros

9

Tengo una mesa con 1.4 billones de registros. La estructura de la tabla es la siguiente:

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

El requisito es crear un índice sobre la columna text.

El tamaño de la mesa es de aproximadamente 34G.

He intentado crear el índice con la siguiente declaración:

ALTER TABLE text_page ADD KEY ix_text (text)

Después de 10 horas de espera, finalmente abandono este enfoque.

¿Hay alguna solución viable para este problema?

ACTUALIZACIÓN : es poco probable que la tabla se actualice, inserte o elimine. La razón por la que se crea un índice en la columna textes porque este tipo de consulta SQL se ejecuta con frecuencia:

SELECT page_id FROM text_page WHERE text = ?

ACTUALIZACIÓN : He resuelto el problema al particionar la tabla.

La mesa está dividida en 40 piezas en columna text. Luego, la creación del índice en la tabla tarda aproximadamente 1 hora en completarse.

Parece que la creación del índice MySQL se vuelve muy lenta cuando el tamaño de la tabla se vuelve muy grande. Y la partición reduce la tabla en troncos más pequeños.

SiLent SoNG
fuente
1
¿Qué hay de malo en usar la CREATE INDEXdeclaración normal ?
Sugeriría que esta pregunta podría estar mejor en ServerFault: es más un administrador de base de datos que una pregunta de programación.
allí
@Derk: el enfoque normal CREATE INDEX es demasiado lento. Tengo que completar la tarea dentro de 1 día.
1
Hmm ... no creo que puedas evitar esto. La creación del índice requiere que el DBMS explore todos los registros, recopile sus campos de "texto" e inserte / cambie los nodos / subárboles del árbol correspondientes. Y esto lleva mucho tiempo para 34G ...
chiccodoro
¿Cuánta memoria tiene su servidor DB? ¿Has configurado MySQL para usar toda esa memoria, o se está limitando?

Respuestas:

4

¿Podría ser que su sistema simplemente no está a la altura? No uso MySQL (SQL Server aquí), pero conozco el dolor de indexar una tabla de 800 millones de entradas. Básicamente ... necesita el hardware adecuado para eso (como en: muchos discos rápidos). Ahora uso casi una docena de Velociraptors y el rendimiento es excelente;)

Los servidores SQL (no como MS SQL Server, sino como servidores de bases de datos que usan SQL) viven y mueren con acceso a disco, y los discos normales simplemente no están a la altura de las operaciones más grandes.

TomTom
fuente
Mi duda es que la creación de índices suele ser muy rápida si el recuento de registros es pequeño; digamos millones. Pero cuando el recuento es de miles de millones, la creación del índice se vuelve muy lenta. Parece que el crecimiento temporal es exponencial.
Realmente no debería ser. MySQL en general tiene límites, pero no es una base de datos basura, y eso sería MUY malo. La generación de índices se vuelve más lenta, pero por log (n), no (n), por lo que no debería ser TAN malo.
TomTom
4

Es posible que desee crear un índice en los primeros (por ejemplo, 10) caracteres del campo de texto.

De los documentos:

Se pueden crear índices que utilicen solo la parte inicial de los valores de columna, utilizando la sintaxis col_name (longitud) para especificar una longitud de prefijo de índice:

CREATE INDEX ix_text ON text_page (text(10))

fuente
4

He resuelto el problema dividiendo la tabla.

La mesa está dividida en 40 piezas en columna text. Luego, la creación del índice en la tabla tarda aproximadamente 1 hora en completarse.

Parece que la creación del índice MySQL se vuelve muy lenta cuando el tamaño de la tabla se vuelve muy grande. Y la partición reduce la tabla en troncos más pequeños.

SiLent SoNG
fuente
Entonces, ¿40 x 1 hora es menos de 10 horas?
symcbean
3

Establezca sort_buffer_size en 4GB (o la cantidad que pueda dependiendo de la cantidad de memoria que tenga).

En este momento, el índice de creación está haciendo una clasificación, pero dado que tiene un 32MB sort_buffer_size, básicamente está agotando innecesariamente el disco duro.

tster
fuente
Estas publicaciones están en desacuerdo directo con usted: xaprb.com/blog/2010/05/09/how-to-tune-mysqls-sort_buffer_size y mejor ronaldbradford.com/blog/… Parece que no es un valor global, es por consulta, por lo que son 4 GB por consulta que está recomendando. Además, cuando excede los 256K, se asigna a mem en el disco en lugar de ser memoria real en memoria. Si lo mantiene pequeño, requiere múltiples pases, pero evita el disco (no se intercambia).
Ry4an Brase
3

Si no necesita hacer consultas como:

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

Sugeriría crear una nueva columna hash e indexar la tabla por la columna. El tamaño general de la tabla + índice podría ser mucho menor.

UPD : Por cierto, 1.400 millones de enteros de clave primaria ocupan alrededor de 6 GB, es decir, la longitud promedio de la cadena es inferior a 30 caracteres, por lo que es más preferible indexar en un prefijo.

También deberías echar un vistazo al motor de almacenamiento MERGE .

nuevo
fuente
2

Una forma de hacerlo es crear una nueva tabla con el conjunto de índices y copiar los datos a la nueva tabla.

Además, asegúrese de tener suficiente espacio temporal.

descompilado
fuente
1
He intentado este enfoque. Después de 10 horas, se ha copiado menos del 1% de los datos en la nueva tabla.
1
Amigo ... son 1.4 BILLONES de registros. No millones, MIL MILLONES. Eso es mucho. Tomará un tiempo independientemente.
Si elige hacer este método, divida la copia en trozos más pequeños. Digamos entre 100 y 200 millones por cada copia.
1
@ descompilado, dividirlo en trozos más pequeños no hará nada (en realidad, podría hacerlo menos eficiente). @Bryan, incluso con 1.4 billones de registros, no debería tomar 1,000 horas.
0

En caso de que todavía se pregunte cómo hacerlo mejor, le sugiero que use una herramienta de alteración de tablas en línea.

Hay muchos en Internet, uno de los famosos es:

Tenemos los mismos problemas con las tablas grandes (más de 500 mil registros) y la modificación es perfecta. Crea una nueva tabla tmp, agrega disparador en la tabla original (para los nuevos registros de actualización / eliminación / inserción) y, mientras tanto, copia todos los registros a la nueva tabla (con la nueva estructura)

¡Buena suerte!

Ali Alwash
fuente