2008-08-15 29 views
19

Tengo una gran base de datos de pedidos normalizados que se está volviendo muy lenta para consultar los informes. Muchas de las consultas que uso en los informes se unen a cinco o seis tablas y se deben examinar decenas o cientos de miles de líneas.¿Cuál es una buena forma de desnormalizar una base de datos mysql?

Hay muchas consultas y la mayoría se han optimizado tanto como sea posible para reducir la carga del servidor y aumentar la velocidad. Creo que es hora de comenzar a guardar una copia de los datos en un formato desnormalizado.

¿Alguna idea sobre un enfoque? ¿Debería comenzar con algunas de mis peores consultas e ir desde allí?

Respuesta

10

Conozco más sobre mssql que mysql, pero no creo que el número de uniones o el número de filas de las que está hablando deba causar demasiados problemas con los índices correctos en su lugar. ¿Has analizado el plan de consulta para ver si te falta alguno?

http://dev.mysql.com/doc/refman/5.0/en/explain.html

Dicho esto, una vez que esté satisfecha con sus índices y han agotado todas las demás vías, desnormalización podría ser la respuesta correcta. Si solo tiene una o dos consultas que son problemas, probablemente sea apropiado un enfoque manual, mientras que algún tipo de herramienta de almacenamiento de datos podría ser mejor para crear una plataforma para desarrollar cubos de datos.

Aquí hay un sitio que encontré que toca sobre el tema:

http://www.meansandends.com/mysql-data-warehouse/?link_body%2Fbody=%7Bincl%3AAggregation%7D

Aquí es una técnica sencilla que se puede utilizar para mantener consultas desnormalización simple, si sólo está haciendo unos pocos a la vez (y no reemplazaré sus tablas OLTP, solo crearé una nueva para fines de informes). Digamos que usted tiene esta consulta en su aplicación:

select a.name, b.address from tbla a 
join tblb b on b.fk_a_id = a.id where a.id=1 

Se puede crear una tabla sin normalizar y poblar con casi la misma consulta:

create table tbl_ab (a_id, a_name, b_address); 
-- (types elided) 

Aviso a los guiones bajos coinciden con los alias de tabla que utiliza

insert tbl_ab select a.id, a.name, b.address from tbla a 
join tblb b on b.fk_a_id = a.id 
-- no where clause because you want everything 

Luego, para arreglar su aplicación y usar la nueva tabla desnormalizada, cambie los puntos por guiones bajos.

select a_name as name, b_address as address 
from tbl_ab where a_id = 1; 

Para consultas enormes Esto puede ahorrar mucho tiempo y hace que sea claro dónde vienen los datos, y se puede volver a utilizar las consultas que ya tiene.

Recuerda, solo defiendo esto como último recurso. Apuesto a que hay algunos índices que te pueden ayudar. Y cuando se desincronice, no se olvide de tener en cuenta el espacio adicional en sus discos, y descubra cuándo ejecutará la consulta para rellenar las nuevas tablas. Esto probablemente debería ser por la noche o cuando la actividad sea baja. Y los datos en esa tabla, por supuesto, nunca estarán exactamente actualizados.

[Otra edición más] ¡No olvide que las nuevas tablas que crea deben ser indexadas también! Lo bueno es que puede indexar al contenido de su corazón y no preocuparse por la contención del bloqueo de actualización, ya que, aparte de su inserción masiva, la tabla solo verá selecciones.

1

Sé que esto es un poco tangencial, pero ¿ha intentado ver si hay más índices que puede agregar?

No tengo muchos antecedentes de DB, pero últimamente estoy trabajando con bases de datos, y he descubierto que muchas de las consultas se pueden mejorar simplemente agregando índices.

Estamos utilizando DB2, y hay un comando llamado db2expln y db2advis, el primero indicará si se utilizan escaneos de tabla frente a escaneos de índice, y el segundo recomendará índices que puede agregar para mejorar el rendimiento. Estoy seguro de que MySQL tiene herramientas similares ...

De todos modos, si esto es algo que no has considerado todavía, me ha estado ayudando mucho ... pero si ya has hecho esta ruta, entonces Supongo que no es lo que estás buscando.

Otra posibilidad es una "vista materializada" (o como lo llaman en DB2), que le permite especificar una tabla que se compone esencialmente de partes de varias tablas. Por lo tanto, en lugar de normalizar las columnas reales, podría proporcionar esta vista para acceder a los datos ... pero no sé si esto tiene un impacto severo en el rendimiento de las inserciones/actualizaciones/eliminaciones (pero si se "materializa", entonces debería ayudar con selecciones ya que los valores se almacenan físicamente por separado).

1

MySQL 5 admite views, lo que puede ser útil en este caso. Parece que ya has hecho muchas optimizaciones, pero si no, puedes utilizar la sintaxis de MySQL EXPLAIN para ver qué índices se están usando realmente y qué está ralentizando tus consultas.

En cuanto a la normalización de datos (ya sea que esté usando vistas o simplemente duplicando datos de una manera más eficiente), creo que comenzar con las consultas más lentas y seguir trabajando es un buen enfoque.

0

Es posible que también desee considerar seleccionar en una tabla temporal y luego realizar consultas en esa tabla temporal. Esto evitaría la necesidad de volver a unirse a sus tablas para cada consulta que emita (suponiendo que puede usar la tabla temporal para numerosas consultas, por supuesto). Básicamente, esto le proporciona datos desnormalizados, pero si solo está haciendo llamadas selectas, no existe preocupación por la consistencia de los datos.

2

De acuerdo con algunos de los otros comentarios, sin duda echaré un vistazo a su indexación.

Una cosa que descubrí a principios de este año en nuestras bases de datos MySQL fue el poder de los índices compuestos. Por ejemplo, si está informando los números de orden sobre los rangos de fechas, un índice compuesto en las columnas de número de pedido y fecha de pedido podría ayudar. Creo que MySQL solo puede usar un índice para la consulta, por lo que si solo tuviera índices separados sobre el número de orden y la fecha del pedido, tendría que decidir usar solo uno de ellos. Usar el comando EXPLAIN puede ayudar a determinar esto.

Para dar una indicación del rendimiento con buenos índices (incluyendo numerosos índices compuestos), puedo ejecutar consultas uniendo 3 tablas en nuestra base de datos y obtener resultados casi instantáneos en la mayoría de los casos. Para informes más complejos, la mayoría de las consultas se ejecutan en menos de 10 segundos. Estas 3 tablas tienen 33 millones, 110 millones y 140 millones de filas respectivamente. Tenga en cuenta que también hemos normalizado esto ligeramente para acelerar nuestra consulta más común en la base de datos.

Más información sobre sus tablas y los tipos de consultas de informes pueden permitir sugerencias adicionales.

0

Además de mi respuesta anterior, otro enfoque que hemos tomado en algunas situaciones es almacenar los datos clave de informes en tablas de resumen separadas. Hay ciertas consultas de informes que van a ser lentas incluso después de la desnormalización y optimizaciones, y descubrimos que la creación de una tabla y el almacenamiento de los totales acumulados o la información resumida a lo largo del mes a medida que llega el informe finaliza mucho más rápido.

Encontramos que este enfoque es fácil de implementar, ya que no rompió nada de lo que ya estaba funcionando, es solo inserciones de bases de datos adicionales en ciertos puntos.

0

He estado jugando con índices compuestos y he visto algunos beneficios reales ... tal vez voy a configurar algunas pruebas para ver si eso me puede salvar aquí ... al menos por un poco más de tiempo.

Cuestiones relacionadas