2012-09-18 19 views
28

Las tablas de recuento con gran cantidad de datos pueden ser muy lentas, a veces tardan unos minutos; también puede generar interbloqueo en un servidor ocupado. Quiero mostrar valores reales, NOLOCK no es una opción.SQL Server El recuento es lento

Los servidores que uso son SQL Server 2005 o 2008 Standard o Enterprise, si es necesario. Me imagino que SQL Server mantiene los recuentos para cada tabla y si no hay una cláusula WHERE, podría obtener ese número bastante rápido, ¿no?

Por ejemplo:

SELECT COUNT(*) FROM myTable 

debe volver inmediatamente con el valor correcto. ¿Debo confiar en las estadísticas para actualizar?

+2

Obtener un [plan de ejecución de la consulta] (http://stackoverflow.com/questions/7359702/how-do -i-obtain-a-query-execution-plan), entonces podemos hablar ...('SELECT COUNT' consulta directamente la tabla en lugar de usar estadísticas, ya que las estadísticas pueden estar desactualizadas) – Justin

+2

Pregunta tonta, pero ¿tiene un índice? – Kermit

+0

@FreshPrinceOfSO todavía es lento si cuenta con 'Id' (letra grande, clave principal, especificación de identidad = verdadera). – ANeves

Respuesta

37

Muy cerca aproximada (haciendo caso omiso de cualquier transacción en vuelo) sería:

SELECT SUM(p.rows) FROM sys.partitions AS p 
    INNER JOIN sys.tables AS t 
    ON p.[object_id] = t.[object_id] 
    INNER JOIN sys.schemas AS s 
    ON s.[schema_id] = t.[schema_id] 
    WHERE t.name = N'myTable' 
    AND s.name = N'dbo' 
    AND p.index_id IN (0,1); 

Esta voluntad devuelve mucho, mucho más rápido que COUNT (*), y si su tabla está cambiando con la suficiente rapidez, no es menos preciso: si su tabla ha cambiado entre cuando inició su COUNT y cuándo fue devuelta, ¿es mucho más valiosa? ?

+0

También se puede usar cuando no hay índice presente. – Kermit

+0

su solución parecía muy prometedora, pero después de probar aproximadamente 5 millones de registros, obtuve los mismos tiempos de respuesta. probará en una base de datos más grande pronto. – Adi

+2

@Adi ¿Una consulta contra sys.partitions tomó mucho tiempo? Encuentro eso muy difícil de creer. –

8

(¿Qué tan grande es el "gran cantidad de datos" - debería haber comentado este principio, pero tal vez el ejecutivo a continuación le ayude, ya)

Si ejecuta una consulta en una estática (significa que no hay nadie molesto con lectura/escritura/actualizaciones en bastante tiempo, así que la contención no es un problema) tabla con 200 millones de filas y COUNT (*) en 15 segundos en mi máquina dev (oráculo). Teniendo en cuenta la cantidad pura de los datos, esto sigue siendo bastante rápido (al menos para mí)

Como usted ha dicho NOLOCK no es una opción, usted podría considerar

exec sp_spaceused 'myTable' 

también.

Pero esta imagen Contactos reducido casi a la misma que NOLOCK (ignorando la contención + borrar/actualizar yo sepa)

2

Count realizará una exploración de tabla o una exploración de índice. Entonces, para un gran número de filas, será lento. Si realiza esta operación con frecuencia, la mejor manera es mantener el registro de conteo en otra tabla.

Sin embargo, si usted no quiere hacer eso, puede crear un índice ficticio (que no se utilizará por la consulta de) y Query es el número de elementos, algo así como:

select 
    row_count 
from sys.dm_db_partition_stats as p 
inner join sys.indexes as i 
    on p.index_id = i.index_id 
    and p.object_id = i.object_id 
where i.name = 'your index' 

que estoy sugiriendo creando un nuevo índice, porque este (si no se usará) no se bloqueará durante otras operaciones.

Como dijo Aaron Bertrand, mantener la consulta puede ser más costoso que usar uno ya existente. Entonces la elección es tuya

+0

Pero incluso si este índice no se usa para otras operaciones * leídas *, aún debe mantenerse para otros archivos DML. Creo que este índice ficticio es más costoso de lo que piensas. –

+0

Puede ser como dices. Tiene que ser probado. El sql se puede usar sin crear realmente un nuevo índice, pero en un índice existente. Usé algo similar en índices filtrados. Nunca necesité contar la mesa desde la cabeza hasta el final. –

0

Si solo necesita un conteo aproximado de la cantidad de filas, es decir. para asegurarse una mesa cargada correctamente o para asegurarse de que los datos no se ha eliminado, haga lo siguiente:

MySQL> connect information_schema; 
MySQL> select table_name,table_rows from tables; 
Cuestiones relacionadas