2008-12-03 44 views
13

Estoy importando datos del mercado accionario brasileño a una base de datos de SQL Server. En este momento tengo una tabla con información de precios de tres tipos de activos: acciones, opciones y forwards. Todavía estoy en datos de 2006 y la tabla tiene más de medio millón de registros. Tengo más 12 años de datos para importar, por lo que la tabla superará un millón de registros.¿Cuál es su enfoque para optimizar tablas grandes (+ 1M filas) en SQL Server?

Ahora, mi primer enfoque para la optimización era mantener los datos a un mínimo, lo que reduce el tamaño de fila a un promedio de 60 bytes, con las siguientes columnas:

 
[Stock] [int] NOT NULL 
[Date] [smalldatetime] NOT NULL 
[Open] [smallmoney] NOT NULL 
[High] [smallmoney] NOT NULL 
[Low] [smallmoney] NOT NULL 
[Close] [smallmoney] NOT NULL 
[Trades] [int] NOT NULL 
[Quantity] [bigint] NOT NULL 
[Volume] [money] NOT NULL 

Ahora, segundo enfoque para la optimización era hacer un índice agrupado. En realidad, el índice principal se ajusta automáticamente y lo convertí en un índice compuesto con los campos Stock y Fecha. Esto es único, no puedo tener dos datos de cotización para la misma acción en el mismo día.

El índice revisado se asegura de que las cotizaciones de la misma acción permanezcan juntas, y probablemente ordenadas por fecha. ¿Es esta segunda información verdadera?

En este momento, con medio millón de registros que está tomando alrededor de 200 ms para seleccionar cotizaciones de un activo específico. Creo que este número aumentará a medida que la mesa crezca.

Ahora, para un tercer enfoque, estoy pensando en dividir la tabla en tres tablas, cada una para un mercado específico (acciones, opciones y forwards). Esto probablemente reducirá el tamaño de la mesa en 1/3. Ahora, ¿ayudará este enfoque o no importa demasiado? En este momento, la mesa tiene 50mb de tamaño, por lo que puede caber completamente en la memoria RAM sin muchos problemas.

Otro enfoque sería utilizar la función de partición de SQL Server. No sé mucho al respecto, pero creo que normalmente se usa cuando las tablas son grandes y puede abarcar múltiples discos para reducir la latencia de E/S, ¿verdad? ¿Sería útil la partición en este caso? Creo que puedo dividir los valores más nuevos (últimos años) y los valores más antiguos en tablas diferentes. La probabilidad de buscar los datos más nuevos es mayor, y con una pequeña partición probablemente sea más rápida, ¿no?

¿Cuáles serían otros buenos enfoques para hacer esto lo más rápido posible? El uso principalmente seleccionado de la tabla será para buscar un rango específico de registros de un activo específico, como los últimos 3 meses del activo X. Habrá otros usos, pero este será el más común, ya que es posible que se ejecute en más de 3k usuarios concurrentemente.

+0

Algunas instrucciones SELECT y/o planes de consulta ayudarían .... –

Respuesta

11
  1. en 1 millón de registros, yo no consideraría esto una gran mesa de particular necesidad de técnicas de optimización inusuales, tales como la división de la tabla de arriba, desnormalización, etc. Pero esas decisiones vendrá cuando usted ha intentado todos los medios normales que no afectan su capacidad para usar técnicas de consulta estándar.

Ahora, el segundo enfoque para la optimización fue hacer un índice agrupado. En realidad, el índice principal se ajusta automáticamente y lo convertí en un índice compuesto con los campos Stock y Fecha. Esto es único, no puedo tener dos datos de cotización para la misma acción en el mismo día.

El índice agrupado se asegura de que las cotizaciones del mismo stock permanezcan juntas, y probablemente ordenadas por fecha. ¿Es esta segunda información verdadera?

Es lógicamente cierto: el índice agrupado define el orden lógico de los registros en el disco, que es todo lo que debería preocuparse. SQL Server puede omitir la sobrecarga de ordenar dentro de un bloque físico, pero seguirá comportándose como si lo hiciera, por lo que no es significativo. La consulta de una acción probablemente sea de 1 o 2 lecturas de página en cualquier caso; y el optimizador no se beneficia mucho de los datos desordenados dentro de una página leída.

En este momento, con medio millón de registros, se requieren alrededor de 200ms para seleccionar 700 cotizaciones de un activo específico. Creo que este número aumentará a medida que la mesa crezca.

No necesariamente de manera significativa. No hay una relación lineal entre el tamaño de la tabla y la velocidad de la consulta. Generalmente hay muchas más consideraciones que son más importantes. No me preocuparía en el rango que describes. ¿Es esa la razón por la que estás preocupado? Me parece que 200 ms son geniales, lo suficiente como para llegar al punto donde se cargan sus tablas y puede comenzar a hacer pruebas realistas, y obtener una mejor idea del rendimiento de la vida real.

Ahora, para un tercer enfoque, estoy pensando en dividir la tabla en tres tablas, cada una para un mercado específico (acciones, opciones y forwards). Esto probablemente reducirá el tamaño de la mesa en 1/3. Ahora, ¿ayudará este enfoque o no importa demasiado? En este momento, la mesa tiene 50mb de tamaño, por lo que puede caber completamente en la memoria RAM sin muchos problemas.

No! Este tipo de optimización es tan prematuro que probablemente nazca muerto.

Otro enfoque sería utilizar la función de partición de SQL Server.

Mismo comentario. Podrá permanecer durante mucho tiempo en un diseño de esquema estrictamente lógico y completamente normalizado.

¿Cuáles serían otros buenos enfoques para hacer esto lo más rápido posible?

El mejor primer paso es la agrupación en stock. La velocidad de inserción no tiene ninguna importancia hasta que está viendo múltiples registros insertados por segundo. No veo nada cerca de esa actividad aquí. Esto debería acercarlo a la máxima eficiencia porque leerá de manera eficiente cada registro asociado con una acción, y ese parece ser su índice más común. Cualquier optimización adicional debe lograrse en función de las pruebas.

10

Un millón de registros realmente no es tan grande. Sin embargo, parece que lleva demasiado tiempo buscar: ¿está indexada la columna que está buscando?

Como siempre, el primer puerto de escala debería ser el generador de perfiles SQL y el planificador de consultas. Pregúntele a SQL Server qué hará con las consultas que le interesan. Creo que incluso puede pedirle que sugiera cambios, como índices adicionales.

Aún no comencé a trabajar en la creación de particiones, como usted dice, debería estar cómodamente en la memoria en este momento, así que sospecho que su problema probablemente sea un índice faltante.

+0

Sí, está indexado, pero olvidé un punto extremadamente importante: todavía estoy insertando datos, que probablemente estén afectando la búsqueda mucho. Sé que no es tan grande, pero se consultará muy a menudo. –

+0

¿Lo ha perfilado aún y ha revisado el plan de consulta? ¿Siempre necesita poder consultar los datos más recientes? De lo contrario, es posible que lo mejor sea insertarlo en algunas tablas no indexadas, y luego agrupar las inserciones durante los períodos de silencio. –

1

Trabajo para un distrito escolar y tenemos que rastrear la asistencia de cada estudiante. Es la forma en que ganamos nuestro dinero. Mi tabla que contiene la marca de asistencia diaria para cada alumno es actualmente de 38.9 millones de registros. Puedo sacar la asistencia de un solo estudiante muy rápidamente de esto. Mantenemos 4 índices (incluida la clave principal) en esta tabla. Nuestro índice agrupado es estudiante/fecha que mantiene todos los registros del estudiante ordenados por eso.Hemos tomado un golpe en insertos a esta tabla con respecto a eso en el caso de que se inserte un antiguo registro para un estudiante, pero es un riesgo que vale la pena para nuestros propósitos.

Con respecto a la velocidad de selección, ciertamente aprovecharía el almacenamiento en caché en su caso.

3

Primero compruebe su plan de ejecución en esa consulta. Asegúrese de que sus índices estén siendo utilizados. Encontré eso. Un millón de registros no es mucho. Para dar un poco de perspectiva, teníamos una tabla de inventario con 30 millones de filas y toda nuestra consulta que unía toneladas de tablas y hacía muchos cálculos que podían ejecutarse en menos de 200 MS. Descubrimos que en un servidor Quad Proc de 64 bits, podríamos tener registros significativamente más, por lo que nunca nos molestamos en la partición.

Puede usar SQL Profier para ver el plan de ejecución, o simplemente ejecutar la consulta desde SQL Management Studio o el Analizador de consultas.

0

El plan de ejecución muestra que está utilizando el índice agrupado bastante bien, pero olvidé un hecho extremadamente importante, ¡aún estoy insertando datos! El inserto probablemente está bloqueando la mesa con demasiada frecuencia. Hay una manera en que podemos ver este cuello de botella?

El plan de ejecución no parece mostrar nada sobre problemas de bloqueo.

En este momento, estos datos son solo históricos, cuando el proceso de importación finaliza, las inserciones se detienen y son mucho menos frecuentes. Pero pronto tendré una tabla más grande para datos en tiempo real, que sufrirá este problema de inserción constante y será más grande que esta tabla. Entonces, cualquier enfoque para optimizar este tipo de situación es muy bienvenido.

+0

Ejecute su selección con NOLOCK para omitir cualquier bloqueo. No es que lo recomiende para producción, pero puede usarlo para probar problemas de bloqueo. Profiler también le mostrará bloqueos, pero puede ser difícil de resolver. –

+0

¿Qué tan rápido está insertando? No debería tomar mucho tiempo poner en 1 millón de registros si están agrupados. Si los estás haciendo uno a la vez, no habrá interferencia. – dkretz

3

reevaluar los índices ... esa es la parte más importante, el tamaño de los datos en realidad no importa, pero lo hace, pero no del todo con fines de velocidad.

Mi recomendación es reconstruir los índices para esa tabla, hacer uno compuesto para las columnas que más necesitará. Ahora que solo tiene unos pocos registros, juegue con los diferentes índices; de lo contrario, será bastante molesto probar cosas nuevas una vez que tenga todos los datos históricos en la tabla.

Después de hacerlo revise su consulta, haga que el evaluador del plan de consulta sea su amigo y verifique si el motor está utilizando el índice correcto.

Acabo de leer la última publicación, ¿hay algo que no entiendo, estás cuestionando la tabla mientras insertas los datos? ¿al mismo tiempo?. ¿Para qué? Al insertar, ¿te refieres a uno registra cientos o miles? ¿Cómo te estás insertando? ¿uno a uno?

Pero de nuevo la clave de esto son los índices, no te metas con particiones y cosas todavía ... especialmente con un registro millon, eso no es nada, tengo tablas con 150 millones de registros, y devolver 40k registros específicos toma el motor aproximadamente 1500ms ...

+0

El procedimiento de inserción ahora mismo es muy flexible. No estoy insertando a granel, así que creo que ese es el problema principal. Es muy agradable leer los números de los tamaños contra el horario seleccionado, no tuve la medida para saber qué es rápido o no. –

0

Otra solución sería crear una tabla histórica para cada año, y poner todas estas tablas en una base de datos histórica, completar todas las entradas y luego crear los índices apropiados para ellas. Una vez que haya terminado con esto, no tendrá que tocarlos nunca más. ¿Por qué tendrías que seguir insertando datos? Para consultar todas esas tablas, simplemente "unirlas todas": p

La tabla del año actual debería ser muy diferente a esta tabla histórica. Por lo que entendí, ¿planeas insertar registros mientras viajas ?, planearía algo diferente, como hacer una inserción masiva o algo similar de vez en cuando a lo largo del día. Por supuesto, todo esto depende de lo que quieras hacer.

Los problemas aquí parecen estar en el diseño. Me gustaría un nuevo diseño.El que tienes ahora por lo que yo entiendo no es adecuado.

+2

La desnormalización es un mal consejo en esta base de datos de tamaño, y por años sería la forma incorrecta de todos modos. – dkretz

1

Ha mencionado que su clave principal es un compuesto en (Stock, Fecha) y en clúster. Esto significa que la tabla está organizada por Stock y luego por Fecha. Siempre que inserte una nueva fila, debe insertarla en el medio de la tabla, y esto puede hacer que las otras filas se desplieguen a otras páginas (divisiones de página).

Recomendaría intentar invertir la clave principal en (Fecha, Stock) y agregar un índice no agrupado en Stock para facilitar las búsquedas rápidas de un Stock específico. Esto permitirá que las inserciones siempre sucedan al final de la tabla (suponiendo que esté insertando en orden de fecha), y no afectará el resto de la tabla, y menores posibilidades de divisiones de página.

+0

No es correcto revertir el índice agrupado: las consultas son para varias acciones a la vez, no para varias fechas a la vez. Y los insertos serán totalmente insignificantes en 1 nuevo registro por stock por día. – dkretz

+0

En realidad obtendré mucho más de 1 nuevo registro por stock por día, ya que comenzaré a almacenar cada transacción de acciones, ¿quizás esto todavía es un buen consejo? –

0

En realidad, el índice principal se ajusta automáticamente y lo convertí en un índice compuesto con los campos Stock y Fecha. Esto es único, no puedo tener dos datos de cotización para la misma acción en el mismo día.

El índice agrupado se asegura de que las cotizaciones del mismo stock permanezcan juntas, y probablemente ordenadas por fecha. ¿Es esta segunda información verdadera?

Los índices en SQL Server siempre se ordenan por orden de columnas en el índice. Por lo tanto, un índice en [stock, fecha] primero clasificará en stock, luego en stock en fecha. Un índice el [fecha, stock] primero clasificará la fecha, luego dentro de la fecha en stock.

Al hacer una consulta, siempre debe incluir las primeras columnas de un índice en la parte WHERE, de lo contrario, el índice no se puede utilizar de manera eficiente.

Para su problema específico: Si las consultas de rango de fechas son el uso más común, haga la clave principal el [fecha, stock], por lo que los datos se almacenarán secuencialmente por fecha en el disco y debería obtener el acceso más rápido . Desarrolle otros índices según sea necesario. Haga la reconstrucción de índice/actualización de estadísticas después de insertar muchos datos nuevos.

+0

El Servidor SQL (y cualquier otro motor SQL) ya no es lo suficientemente inteligente como para reordenar los campos para que coincidan con los índices, por lo que la información de la cláusula WHERE es cuestionable. Las estadísticas se actualizan automáticamente. – dkretz

Cuestiones relacionadas