Asesoramiento sobre cómo escalar y mejorar los tiempos de ejecución de una "consulta basada en pivotes" en una tabla de mil millones de filas, aumentando un millón por día

StackOverflow https://stackoverflow.com/questions/1002086

Pregunta

Nuestra compañía está desarrollando un proyecto interno para analizar archivos de texto. Esos archivos de texto están compuestos de metadatos que se extraen mediante expresiones regulares. Diez computadoras analizan los archivos de texto las 24 horas del día, los 7 días de la semana, y alimentan una base de datos Intel Xeon SQL Server 2005 de alta gama con los metadatos extraídos.

El esquema de base de datos simplificado tiene este aspecto:

Items

| Id | Name   |
|----|--------|
| 1  | Sample |
Items_Attributes

| ItemId | AttributeId |
|--------|-------------|
| 1      | 1           |
| 1      | 2           |
Attributes

| Id | AttributeTypeId | Value |
|----|-----------------|-------|
| 1  | 1               | 500mB |
| 2  | 2               | 1.0.0 |
AttributeTypes

| Id | Name    |
|----|---------|
| 1  | Size    |
| 2  | Version |

Hay muchos tipos distintos de archivos de texto con metadatos distintos dentro. Para cada archivo de texto tenemos un Item y para cada valor de metadatos extraído tenemos un Attribute.

Items_Attributes nos permite evitar valores duplicados de Attribute que evitan que el tamaño de la base de datos aumente x ^ 10.

Este esquema particular nos permite agregar dinámicamente nuevas expresiones regulares y obtener nuevos metadatos de nuevos archivos procesados ??sin importar la estructura interna que tengan.

Además, esto nos permite filtrar los datos y obtener informes dinámicos según los criterios del usuario. Estamos filtrando por Attribute y luego girando el conjunto de resultados ( http://msdn.microsoft.com/en-us/library/ms177410.aspx ). Así que este ejemplo de consulta pseudo-sql

SELECT FROM Items WHERE Size = @A AND Version = @B

devolvería una tabla dinámica como esta

| ItemName | Size  | Version |
|----------|-------|---------|
| Sample   | 500mB | 1.0.0   |

La aplicación ha estado ejecutándose durante meses y el rendimiento disminuyó terriblemente en ese momento ya no es utilizable. Los informes no deben tomar más de 2 segundos y la tabla Items_Attributes aumenta un promedio de 10,000,000 filas por semana. Todo está correctamente indexado y pasamos mucho tiempo analizando y optimizando los planes de ejecución de consultas.

Entonces, mi pregunta es, ¿cómo escalaría esto para disminuir los tiempos de ejecución de informes?

Llegamos con estas posibles soluciones:

  • Compre más hardware y configure un clúster de SQL Server. (necesitamos asesoramiento sobre la "estrategia de agrupamiento" adecuada)
  • Use una base de datos clave / valor como HBase (realmente no sabemos si resolvería nuestro problema)
  • Use un ODBMS en lugar de un RDBMS (hemos estado considerando db4o)
  • Mueva nuestro software a la nube (no tenemos experiencia)
  • Genera informes de forma estática en tiempo de ejecución. (Realmente no queremos)
  • Vistas indexadas estáticas para informes comunes (el rendimiento es casi el mismo)
  • Esquema de normalización (algunos de nuestros informes incluyen hasta 50 tablas en una sola consulta)
¿Fue útil?

Solución

Quizás este documento técnico del equipo CAT de SQL Server sobre los escollos del modelo de base de datos Entity-Attribute-Value puede ayudar: http://sqlcat.com/whitepapers/archive/2008/09/03/best-practices- for-semantic-data-modeling-for-performance-and-scalability.aspx

Otros consejos

Comenzaría con la publicación de metadatos de tablas exactas (junto con los detalles de indexación), el texto de consulta exacto y el plan de ejecución.

Con su diseño de tabla actual, la consulta es similar a esta:

SELECT FROM Items WHERE Size = @A AND Version = @B

no puede beneficiarse con el uso de un índice compuesto en (Tamaño, Versión) , ya que es imposible crear dicho índice.

Ni siquiera puedes crear una vista indexada, ya que contendría una auto-unión en atributos .

Probablemente, la mejor decisión sería desnormalizar la tabla de esta manera:

id  name  size  version

y cree un índice en (tamaño, versión)

Trabajó con tales esquemas mucho tiempo. Nunca se desempeñan bien. Lo mejor es almacenar los datos según lo necesite, en la forma:

| ItemName | Tamaño | Version | | ---------- | ------- | --------- | | Muestra | 500mB | 1.0.0 |

Entonces no necesitas pivotar. Y, por cierto, no llame a su esquema EAV original "normalizado" - no está normalizado.

Me parece que emitir algunas consultas OLAP en una base de datos optimizada para transacciones OLTP. Sin saber los detalles, recomiendo crear un " datawarehouse " Optimizado para el tipo de consultas que está haciendo. Eso implicaría agregar datos (si es posible), desnormalización y también tener una base de datos, que tiene aproximadamente 1 día de antigüedad. Usted actualizaría los datos de forma incremental cada día o en cualquier intervalo que desee.

Por favor, publique el DDL e índices exactos, si tiene índices en las columnas de ID, entonces su consulta resultará en una exploración

en lugar de algo como esto

SELECT FROM Items WHERE Size = @A AND Version = @B

necesitas hacer esto

SELECT FROM Items WHERE ID = 1

en otras palabras, necesita capturar los valores de texto, encontrar los identificadores que está indexando y luego usarlos como su consulta para obtener resultados en su lugar

Probablemente también es una buena idea ver la función de partición para distribuir sus datos

la agrupación en clúster se realiza por disponibilidad, no por rendimiento, si un nodo muere (el clúster activo), el otro nodo (el clúster pasivo) se activará ... por supuesto, también hay una agrupación activa, pero eso es otra historia

Una solución a corto plazo puede ser usar partición horizontal . Supongo que su tabla más grande es Items_Attributes . Podría particionar horizontalmente esta tabla, colocando cada partición en un grupo de archivos separado en un controlador de disco separado.

Suponiendo que no estés intentando informar a la vez sobre todos los ItemId s.

Mencionas 50 tablas en una sola consulta. Si bien el servidor SQL admite hasta 256 tablas en una sola consulta monolítica, este enfoque reduce las posibilidades de que el optimizador produzca un plan eficiente.

Si está casado con el esquema tal como está, considere dividir sus consultas de informes en una serie de pasos que materialicen sus resultados en tablas temporales (#). Este enfoque le permite llevar a cabo las partes más selectivas de la consulta de forma aislada y, en mi experiencia, puede ofrecer grandes ganancias de rendimiento. En general, las consultas también son más fáciles de mantener.

Además (un poco como una posibilidad remota, esto) no dice en qué versión de servidor SQL está; pero si está en SQL 2005, dada la cantidad de tablas involucradas en sus informes y el volumen de datos, vale la pena verificar que su servidor SQL esté parcheado al menos a SP2.

Trabajé en un proyecto de ETL utilizando cientos de millones de tablas, donde encontramos que el optimizador de consultas en SQL 2005 RTM / SP1 no podía producir de manera consistente planes eficientes para consultas que se unen a más de 5 tablas en las que una o más de Las tablas eran de esta escala. Este problema se resolvió en SP2.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top