sql >> Base de Datos >  >> RDS >> Mysql

Rendimiento de MySQL:varias tablas frente a índice en una sola tabla y particiones

Crear 20.000 tablas es una mala idea. Necesitará 40.000 mesas en poco tiempo, y luego más.

Llamé a este síndrome Metadata Tribbles en mi libro SQL Antipatterns . Verá que esto sucede cada vez que planea crear una "tabla por X" o una "columna por X".

Esto causa problemas reales de rendimiento cuando tiene decenas de miles de tablas. Cada tabla requiere MySQL para mantener estructuras de datos internas, descriptores de archivos, un diccionario de datos, etc.

También hay consecuencias operativas prácticas. ¿Realmente quieres crear un sistema que requiera que crees una nueva tabla cada vez que se registre un nuevo usuario?

En su lugar, le recomiendo que utilice Particionamiento de MySQL .

Aquí hay un ejemplo de partición de la tabla:

CREATE TABLE statistics (
  id INT AUTO_INCREMENT NOT NULL,
  user_id INT NOT NULL,
  PRIMARY KEY (id, user_id)
) PARTITION BY HASH(user_id) PARTITIONS 101;

Esto le brinda la ventaja de definir una tabla lógica, al mismo tiempo que divide la tabla en muchas tablas físicas para un acceso más rápido cuando consulta un valor específico de la clave de partición.

Por ejemplo, cuando ejecuta una consulta como su ejemplo, MySQL accede solo a la partición correcta que contiene el ID de usuario específico:

mysql> EXPLAIN PARTITIONS SELECT * FROM statistics WHERE user_id = 1\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: statistics
   partitions: p1    <--- this shows it touches only one partition 
         type: index
possible_keys: NULL
          key: PRIMARY
      key_len: 8
          ref: NULL
         rows: 2
        Extra: Using where; Using index

El método HASH de partición significa que las filas se colocan en una partición por un módulo de la clave de partición entera. Esto significa que muchos id_usuarios se asignan a la misma partición, pero cada partición tendría solo 1/N de filas en promedio (donde N es el número de particiones). Y define la tabla con un número constante de particiones, por lo que no tiene que expandirla cada vez que obtiene un nuevo usuario.

Puede elegir cualquier número de particiones hasta 1024 (o 8192 en MySQL 5.6), pero algunas personas han informado problemas de rendimiento cuando alcanzan ese nivel.

Se recomienda utilizar un número primo de particiones. En caso de que sus valores de ID de usuario sigan un patrón (como usar solo números pares), usar un número primo de particiones ayuda a distribuir los datos de manera más uniforme.

Vuelva a sus preguntas en el comentario:

Para el particionamiento HASH, si usa 101 particiones como las que muestro en el ejemplo anterior, entonces cualquier partición dada tiene alrededor del 1% de sus filas en promedio. Dijiste que tu tabla de estadísticas tiene 30 millones de filas, así que si usas esta partición, solo tendrías 300k filas por partición. Eso es mucho más fácil de leer para MySQL. También puede (y debe) usar índices:cada partición tendrá su propio índice, y será solo el 1% del tamaño del índice en toda la tabla sin particiones.

Entonces, la respuesta a cómo puede determinar un número razonable de particiones es:¿qué tan grande es toda su tabla y qué tan grande quiere que sean las particiones en promedio?

El número de particiones no tiene por qué aumentar necesariamente si utiliza el particionamiento HASH. Eventualmente, puede tener un total de 30 mil millones de filas, pero descubrí que cuando su volumen de datos crece en órdenes de magnitud, eso exige una nueva arquitectura de todos modos. Si sus datos crecen tanto, probablemente necesite fragmentación en varios servidores, así como la partición en varias tablas.

Dicho esto, puede volver a particionar una tabla con ALTER TABLE:

ALTER TABLE statistics PARTITION BY HASH(user_id) PARTITIONS 401;

Esto tiene que reestructurar la tabla (como la mayoría de los cambios de ALTER TABLE), así que espere un tiempo.

Es posible que desee controlar el tamaño de los datos y los índices en las particiones:

SELECT table_schema, table_name, table_rows, data_length, index_length
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE partition_method IS NOT NULL;

Al igual que con cualquier tabla, desea que el tamaño total de los índices activos se ajuste a su grupo de búfer, porque si MySQL tiene que intercambiar partes de los índices dentro y fuera del grupo de búfer durante las consultas SELECT, el rendimiento se ve afectado.

Si usa el particionamiento RANGE o LIST, entonces es mucho más común agregar, eliminar, fusionar y dividir particiones. Consulte http://dev.mysql. com/doc/refman/5.6/en/partitioning-management-range-list.html

Le animo a leer la sección del manual sobre particiones , y también echa un vistazo a esta bonita presentación:Boost Performance Con particiones MySQL 5.1 .