2010-04-21 6 views
6

Tengo una tabla db con aproximadamente 10 o más columnas, dos de las cuales son mes y año. La tabla tiene aproximadamente 250k filas ahora, y esperamos que crezca en aproximadamente 100-150k registros por mes. Muchas consultas involucran la columna de mes y año (por ejemplo, todos los registros de marzo de 2010), por lo que con frecuencia necesitamos obtener las combinaciones disponibles de mes y año (es decir, ¿tenemos registros para abril de 2010?).La mejor manera de obtener valores distintos de la tabla grande

Un compañero de trabajo cree que deberíamos tener una tabla separada de la principal que solo contiene los meses y años de los que tenemos datos. Solo agregamos registros a nuestra tabla principal una vez al mes, por lo que sería una pequeña actualización al final de nuestros scripts para agregar la nueva entrada a esta segunda tabla. Esta segunda tabla sería consultada siempre que necesitemos encontrar las entradas mes/año disponibles en la primera tabla. Esta solución me parece kludgy y una violación de DRY.

¿Cuál crees que es la forma correcta de resolver este problema? ¿Hay una mejor manera que tener dos mesas?

Respuesta

3

Asegúrese de tener un índice agrupado en esas columnas. y divida su tabla en estas columnas de fecha y coloque los archivos de datos en diferentes unidades de disco. Creo que mantener la fragmentación de su índice bajo es su mejor opción.

También creo que tener una vista física con la selección deseada no es una buena idea, porque agrega Insertar/Actualizar sobrecarga. en promedio, hay 3,5 insertos por minuto. o aproximadamente 17 segundos entre cada inserción (en promedio corrígeme si estoy equivocado)

La pregunta es: ¿elige más de cada 17 segundos? Esa es la idea clave. Espero que haya sido de ayuda.

12

El uso de un simple índice en las columnas necesarias (año y mes) debería mejorar en gran medida ya sea un DISTINCT o GROUP BY consulta.

yo no iría con una tabla secundaria ya que esto añade extra sobre la cabeza para mantener la tabla secundaria (inserciones/actualizaciones eliminaciones requerirán la validación de la tabla secundaria)

EDIT:

incluso puede ser que desee considerar el uso Improving Performance with SQL Server 2005 Indexed Views

+2

+1. ¡Ni siquiera pienses en tener otra mesa! –

+1

Sugerí un índice, pero me dijeron que un grupo/distinto aún sería lento en una tabla con unos pocos millones de registros – derivation

+1

de acuerdo. La tabla secundaria es una mala idea, no solo desde un punto de vista hipotético de "esto no está normalizado", sino desde un punto de vista de las consecuencias de mantenimiento involuntario. ¡Crea un índice y listo! –

1

crear una vista indizada materializada de:

SELECT DISTINCT 
    MonthCol, YearCol 
    FROM YourTable 

ahora tendrá acceso a los valores distintivos precalculados sin tener que realizar el trabajo todo el tiempo.

+0

esto agrega una sobrecarga para inserción/actualización y si la tabla crece aproximadamente 100k-150k registros por mes, será una gran sobrecarga. Me encantaría saber que esta gran selección en estas columnas no se debe a la comprobación de que la línea exista antes de insertarla o actualizarla. –

+2

@Gabriel Guimarães, respondí asumiendo que tenían el índice en su lugar y que todavía era lento. Esta vista hará que la selección sea casi instantánea. Sin embargo, no hay almuerzo gratis, usted gana velocidad de selección masiva para algunos gastos indirectos de inserción/actualización/eliminación (150k por mes no es mucho por segundo). OP dice que 'frecuentemente necesitan obtener las combinaciones de mes y año disponibles' que luego usarían esta vista, y liberarían recursos y posiblemente incluso ayudarían a cualquier transacción que se escriba en esta tabla. –

1

Haga que la fecha sea la primera columna en la clave del índice agrupado de la tabla. Esto es muy típico para los datos históricos, porque la mayoría, si no todas, las consultas están interesadas en rangos específicos y un índice agrupado a tiempo puede abordar esto. Todas las consultas como "mes de mayo" deben abordarse como rangos, por ejemplo: WHERE DATECOLKEY BETWEEN '05/01/2010' AND '06/01/2001'. Responder a una pregunta como "¿Hay algún registro en mayo?" Implicará una simple búsqueda en el índice agrupado.

Si bien esto parece complicado para un programador, es la forma óptima de abordar un problema de diseño de la base de datos.

1

Cree una vista que devuelva los distintos valores de [mes] [año] y luego indexe [año] [mes] en la vista. SQL Server usará el pequeño índice en la vista en lugar de escanear la gran tabla. Debido a que el servidor SQL no le permitirá indexar una vista con la palabra clave DISTINCT, en su lugar AGRUPLE POR [año], [mes] y use BIG_COUNT (*) en SELECCIONAR. Se verá algo como esto:

CREATE VIEW dbo.vwMonthYear WITH SCHEMABINDING 
AS 

    SELECT 
    [year], 
    [month], 
    COUNT_BIG(*) [MonthCount] 
    FROM [dbo].[YourBigTable] 
    GROUP BY [year],[month] 
GO 

CREATE UNIQUE CLUSTERED INDEX ICU_vwMonthYear_Year_Month 
    ON [dbo].[vwMonthYear](Year,Month) 

Ahora cuando se selecciona DISTINCT [año], [Mes] en la mesa grande, el optimizador de consultas escaneará el pequeño índice en la vista en lugar de escanear millones de registros en el Mesa grande.

SELECT DISTINCT 
    [year], 
    [month] 
FROM YourBigTable 

Esta técnica me tomó de 5 millones lee con una I/O estimado del 10,9 a 36 lee con una I/O estimado de 0.003. La sobrecarga en esto será la de mantener un índice adicional, de modo que cada vez que se actualice la tabla grande, el índice en la vista también se actualizará. Luché con este mismo problema por un tiempo y estuve al punto de mantener una tabla por separado usando desencadenantes hasta que me di cuenta de esto. Espero que ayude a votarme.

ejemplo de trabajo completo:

CREATE TABLE YourBigTable(
     YourBigTableID INT IDENTITY(1,1) NOT NULL CONSTRAINT PK_YourBigTable_YourBigTableID PRIMARY KEY, 
     [Year] INT, 
     [Month] INT) 
    GO 


    CREATE VIEW dbo.vwMonthYear WITH SCHEMABINDING 
    AS 

     SELECT 
      [year], 
      [month], 
      COUNT_BIG(*) [MonthCount] 
     FROM [dbo].[YourBigTable] 
     GROUP BY [year],[month] 
    GO 

    CREATE UNIQUE CLUSTERED INDEX ICU_vwMonthYear_Year_Month ON [dbo].[vwMonthYear](Year,Month) 


    SELECT DISTINCT 
     [year], 
     [month] 
    FROM YourBigTable 

-- Actual execution plan shows SQL server scaning ICU_vwMonthYear_Year_Month 
Cuestiones relacionadas