2010-03-13 9 views
9

En nuestra aplicación, recopilamos datos sobre el rendimiento del motor automotriz, básicamente datos de origen sobre el rendimiento del motor en función del tipo de motor, el vehículo que lo ejecuta y el diseño del motor. Actualmente, la base para las nuevas inserciones de hileras es un período de encendido/apagado del motor; supervisamos las variables de rendimiento en función de un cambio en el estado del motor de activo a inactivo y viceversa. El relacionada engineState tabla es el siguiente:En MySQL, ¿cuál es el diseño de consulta más efectivo para unir tablas grandes con muchas o muchas relaciones entre los predicados de unión?

+---------+-----------+---------------+---------------------+---------------------+-----------------+ 
| vehicle | engine | engine_state | state_start_time | state_end_time  | engine_variable | 
+---------+-----------+---------------+---------------------+---------------------+-----------------+ 
| 080025 | E01  | active  | 2008-01-24 16:19:15 | 2008-01-24 16:24:45 |    720 | 
| 080028 | E02  | inactive  | 2008-01-24 16:19:25 | 2008-01-24 16:22:17 |    304 | 
+---------+-----------+---------------+---------------------+---------------------+-----------------+ 

Para un análisis específico, nos gustaría analizar el contenido de la tabla en base a una granularidad fila de minutos, en lugar de la base actual del estado del motor activo/inactivo. Para esto, estamos pensando en crear una tabla simple productionMinute con una fila por cada minuto en el período que estamos analizando y unir las tablas productionMinute y engineEvent en las columnas de fecha y hora de cada tabla. Entonces, si nuestro período de análisis es del 2009-12-01 al 2010-02-28, creamos una nueva tabla con 129.600 filas, una por cada minuto de cada día durante ese período de tres meses. Las primeras filas de la tabla productionMinute:

+---------------------+ 
| production_minute | 
+---------------------+ 
| 2009-12-01 00:00 | 
| 2009-12-01 00:01 | 
| 2009-12-01 00:02 |  
| 2009-12-01 00:03 | 
+---------------------+ 

La unión entre las tablas serían:

 FROM engineState AS es 
LEFT JOIN productionMinute AS pm ON pm.production_minute >= es.state_start_time 
           AND pm.production_minute <= es.event_end_time 

esta unión, sin embargo, nos lleva a varios problemas ambientales:

  1. El engineState la tabla tiene 5 millones de filas y la tabla productionMinute tiene 130,000 filas
  2. Cuando un engineState fila abarca más de un minuto (es decir la diferencia entre es.state_start_time y es.state_end_time es mayor que un minuto), como es el caso en el ejemplo anterior, hay varias filas productionMinute de mesa que se unen a una sola fila engineState tabla
  3. Cuando hay más de un motor en funcionamiento durante cualquier dado minutos, también como por el ejemplo anterior, múltiples engineState filas de la tabla se unen a un solo productionMinute fila

En la prueba de nuestra lógica y utilizando sólo un pequeño extracto de mesa (un día en lugar de 3 meses, para la tabla productionMinute) la consulta tarda más de una hora en generar. Al investigar este ítem para mejorar el rendimiento para que sea factible consultar datos de tres meses, pensamos en crear una tabla temporal a partir del engineEvent, eliminando cualquier información de tabla que no sea crítica para el análisis, y unirnos al tabla temporal a la tabla productionMinute. También estamos planeando experimentar con diferentes combinaciones, específicamente una unión interna, para ver si eso mejoraría el rendimiento.

¿Cuál es el mejor diseño de consulta para unir tablas con la relación muchos: muchos entre los predicados de unión como se describe anteriormente? ¿Cuál es el mejor tipo de combinación (izquierda/derecha, interior)?

+0

Un ejemplo concreto de qué tipo de informe está tratando de generar ayudaría. Es muy posible que no necesite ampliar las observaciones por minuto y pueda generar sus resultados directamente. Además, ¿qué índices tiene en su tabla engineState? – Martin

+0

Sus quejas número 2 y 3 no son problemas ambientales, son problemas de diseño. Lo que quiero decir es que no puedo ver nada malo en ninguno de ellos; son ciertos porque usted ha establecido sus datos de esa manera. Debe describir por qué lo ve como un problema y dejar en claro qué espera de la unión que ha escrito (qué significado semántico le gustaría asignarle: D). – Unreason

Respuesta

0

El rendimiento dependerá de cómo estén estructurados sus datos en las tablas.

una combinación externa izquierda o derecha solo es útil si desea todos los valores en la tabla izquierda o derecha para la proyección seleccionada y esos valores pueden no tener algo en la tabla que se está uniendo.

Confíe en su optimizador de consultas para encontrar el algoritmo de combinación más eficiente para sus datos ... fue creado para saber cómo hacer bien su trabajo.Si tiene problemas de rendimiento, observe cómo se estructuran y almacenan los datos.

+0

Gracias Jeremy; pero esa es exactamente la pregunta que estoy haciendo: ¿cómo deberíamos (re) estructurar y almacenar datos en tablas para optimizar el rendimiento de las consultas al trabajar a través de una relación muchos: muchos entre los predicados de unión y trabajar con grandes conjuntos de datos? Tenga en cuenta que no estamos atados a nuestro diseño actual porque podemos usar tablas temporales para reestructurar datos y poner índices en los predicados de unión ... ¿pero este es un enfoque que ha funcionado para otros que enfrentan un desafío de rendimiento similar? Si no, ¿qué enfoques han funcionado? – lighthouse65

+0

Pero esa no es la pregunta que hizo. Preguntó específicamente sobre las uniones. Si tiene un conjunto de datos muy grande y tiene varios campos que desea indexar, lo mejor es usar árboles B + para indexar sus campos. Se requerirán menos IO en casi todos los casos al hacer una consulta. No estoy seguro de cuánto control le da MySQL sobre las técnicas de indexación que puede emplear, pero si tiene opciones, elija eso. Si no tiene opción, entonces sospecho que usa B + Trees para indexar y especificar un campo para indexar debe cubrirlo. – joejoeson

+0

Gracias por el repost Jeremy. Creo que MySQL nos permite especificar el tipo de índice a emplear. Veremos más esta opción y publicaré lo que encontremos. – lighthouse65

1

rendimiento de la recuperación de datos es la función de

  • velocidad de acceso a los datos en el disco (depende en la existencia de índices, el tamaño de tablas, el tamaño de la memoria caché, lo crudo/velocidad O)
  • número de registros que deben ser devueltos (algunos se une a reducir el número de filas devueltas , algunos aumento, algunas condiciones se pueden aplicar en los índices algunos deben ir a los registros)
  • número de columnas que necesita devolver

Para todos estos se puede optimizar

  • índices añadiendo
  • reduciendo el tamaño de la tabla de particiones en ella verticalmente (la división de la tabla en dos o más tablas semánticamente diferentes; por ejemplo, si desde su tabla de 5m usted solo trabaja con 100k registros el 99.5% del tiempo, puede dividir la tabla en activa/inactiva o similar)
  • proporcionando que no puede dividir verticalmente puede dividir una tabla horizontalmente; el número de columnas también influye en la velocidad de recuperación (pero no tanto)
  • mejorando finalmente la velocidad de E/S en bruto se puede lograr dividiendo la tabla de forma transparente en varios discos duros (pero sepa sus propiedades subyacentes de sistema de archivos)

Los índices tienen el mayor impacto en el rendimiento porque pueden reducir el tiempo de acceso al disco y la velocidad en las operaciones de memoria en órdenes de magnitud (convierten O (n) en O (n) a costa del mantenimiento de la estructura del índice; por lo que ralentizan las actualizaciones)

Los índices de velocidad máxima de recuperación deben cubrir todas las uniones y las condiciones y consultas deben escribirse de tal manera que el optimizador de consultas pueda determinar cuál de ellas tendrá el mayor beneficio si se ejecuta primero selectividad).

Para su ejemplo particular tratan de combinación diferente de los índices de referencia

  1. pm.production_minute debe ser indexado a ciencia cierta
  2. con es.state_start_time y es.state_end_time tiene 4 opciones posibles de índice (que se puede combinar):
    índice en es.state_start_time índice
    en es.state_end_time índice
    en (es.state_start_time, es.state_end_time)
    índice en (es.state_end_time , es.state_start_time)

Conocer sus datos le permitirá determinar cuál es el óptimo. No me sorprendería si encontrara que tener los dos últimos dos índices de columna funcionaría mejor. O tener una sola columna y otro índice de dos columnas (pero en orden inverso de columnas).

En ambos casos, el optimizador decente sería capaz de determinar el conjunto de resultados simplemente leyendo los índices y sin siquiera mirar los registros reales, lo que reduce considerablemente el acceso al disco.

0

Mi experiencia es que el optimizador de consultas MySQL es bastante malo. El de PostgreSQL es mucho mejor.

Su problema es que sus datos están estructurados para facilitar la grabación, no para facilitar el análisis. Mi sugerencia es que continúes y crees la tabla temporal, pero no de la forma que te puedas imaginar. Creo que la mejor opción es tener un paso de postprocesamiento al final de cada día que tome todos los datos del día y cree entradas minuto a minuto en una nueva tabla (idealmente en un husillo diferente) con un índice production_minute. Esta nueva base de datos será más rápida para hacer sus consultas analíticas, y las consultas no ralentizarán notablemente la recopilación de datos.

1

Estoy de acuerdo con vy32. Debe realizar esta consulta una vez y solo una vez para obtener sus datos en un formato adecuado para el análisis. Debe usar una herramienta ETL adecuada (o diablos, simplemente perl o algo simple) para obtener los datos de la tabla engineState, calcular los minutos de producción y luego cargarlos en otra base de datos que modele adecuadamente las consultas de tipo de análisis.

Si piensa en su problema, simplemente está desnormalizando sus datos y asignando números de minutos como claves sustitutas. Este es un problema ETL relativamente fácil (y común) que no funciona en SQL directo, pero es simple con otros lenguajes y herramientas.

Su volumen de producción sería manejado fácilmente por un verdadero proceso de ETL.

0

Si entendí correctamente, está investigando un problema de BI. Un diseño de BI sería tener los datos operativos aparte del consolidado.

Para que esto suceda (rápido y sucio) necesitarás tres elementos.

  • Sus datos operativos
  • un trabajo de ETL, que sólo necesita para llevar a cabo la consulta que has mostrado e inserte el conjunto de resultados en otra tabla sin normalizar
  • tablas desnormalizado donde guardar los datos consilidated.

De esta manera acelerará su consulta, ya que ahora sería una simple selección.

Como en cualquier solución de BI, deberá ejecutar el ETL a diario (según sus necesidades de negocio) para actualizar su información desnormalizada.

Por otro lado, puede rechazar el modo BI y trabajar en su esquema/consulta actual. Podría agregar índices, estadísticas, modificar tablas pero, en mi opinión, esta no es una solución escalable. Podría resolver el problema de rendimiento de una base de datos de tres meses, pero ¿y si tiene una base de datos de tres años?

0

El uso de un LEFT JOIN, INNER JOIN o RIGHT JOIN es una diferencia semántica. Usar un join diferente para performance no es solo una mala idea, significa que la relación entre tablas no se ha entendido completamente, ya que los diferentes tipos de JOIN pueden devolver información diferente porque significan cosas diferentes.

Normalmente, INNER JOINs son muy amigables con el optimizador, ya que esto permite diferentes criterios de filtro de su cláusula WHERE y la condición JOIN que se aplicará mucho más para mejorar los escaneos de índice o escaneos de tabla. Las restricciones de integridad referencial también pueden dar la información del optimizador sobre la existencia de datos que se garantiza que existen en ambos lados.

Debe revisar sus planes de ejecución y ver sus estrategias de indexación. Lo ideal es que desee índices de cobertura reducidos y desee ver índices de búsquedas, escaneos de índices, escaneos de tablas (en orden de preferencia) en sus planes.

Normalmente, quiere que su modelo se normalice para el procesamiento de transacciones y se desnormalice para informar, pero dos modelos son molestos de tratar al principio, por lo que comienza tratando de generar informes y análisis de los datos normalizados, y esto puede funcionar por un tiempo con mejores índices y mirando los planes de ejecución.

Cuando sus informes se vuelven demasiado pobres en una forma normal bien indexada, buscaría transformar los datos a, tal vez, un modelo dimensional (mire la metodología de Kimball) con esquemas de estrellas que tienen esquemas muy simples para informar (por lo general, todas las UNIONES INNER y una estrella simple) y se puede optimizar muy bien en los sistemas de bases de datos tradicionales.

Cuestiones relacionadas