2012-06-21 10 views
25

Tengo una tabla SQL BookChapters con más de 20 millones de filas. Tiene una clave primaria agrupada (bookChapterID) y no tiene otras claves o índices. Se tarda milisegundos para ejecutar la consulta siguienteCuenta SQL (*) rendimiento

if (select count(*) from BookChapters) = 0 
... 

Sin embargo, se tarda más de 10 minutos cuando lo cambio al igual que

if (select count(*) from BookChapters) = 1 
... 

o

if (select count(*) from BookChapters) > 1 
... 

¿Por qué? ¿Cómo puedo obtener select count(*) para ejecutar más rápido?

+2

En términos generales, seleccione " recuento (*) de la tabla "- puede tener grandes problemas con datos más grandes;) –

Respuesta

40

Mikael Eriksson tiene una buena explicación abajo por qué la primera consulta es rápida:

servidor SQL optimizarlo en: if exists(select * from BookChapters). Así que busca la presencia de una fila en lugar de contar todas las filas de la tabla.

Para las otras dos consultas, SQL Server usaría la siguiente regla. Para realizar una consulta como SELECT COUNT(*), SQL Server utilizará el índice no agrupado más pequeño para contar las filas. Si la tabla no tiene ningún índice no agrupado , tendrá que escanear la tabla.

Además, si la tabla tiene un índice agrupado puede obtener su recuento aún más rápido utilizando la siguiente consulta (tomado de este sitio Get Row Counts Fast!)

--SQL Server 2005/2008 
SELECT OBJECT_NAME(i.id) [Table_Name], i.rowcnt [Row_Count] 
FROM sys.sysindexes i WITH (NOLOCK) 
WHERE i.indid in (0,1) 
ORDER BY i.rowcnt desc 

--SQL Server 2000 
SELECT OBJECT_NAME(i.id) [Table_Name], i.rows [Row_Count] 
FROM sysindexes i (NOLOCK) 
WHERE i.indid in (0,1) 
ORDER BY i.rows desc 

Se utiliza la tabla de sistema sysindexes. Más información se puede encontrar aquí SQL Server 2000, SQL Server 2005, SQL Server 2008, SQL Server 2012

Aquí hay otro enlace Why is my SELECT COUNT(*) running so slow? con otra solución. Muestra la técnica que utiliza Microsoft para mostrar rápidamente el número de filas al hacer clic derecho en la tabla y seleccionar propiedades.

select sum (spart.rows) 
from sys.partitions spart 
where spart.object_id = object_id(’YourTable’) 
and spart.index_id < 2 

Debería encontrar que esto vuelve muy rápido independientemente de la cantidad de tablas que tenga.

Si está utilizando SQL 2000 aún puede usar la tabla sysindexes para obtener el número.

select max(ROWS) 
from sysindexes 
where id = object_id(’YourTable’) 

Este número puede estar ligeramente desviado dependiendo de la frecuencia de SQL actualiza la tabla sysindexes, pero por lo general es Corrent (o al menos lo suficientemente cerca).

+1

¿estás de acuerdo con mi sugerencia? –

+1

Hola Aleksey, eres un genio, eso es, solo tenía curiosidad de que mi nueva tabla BookChapters2 devuelva el recuento de consultas mucho más rápido, vi, como dijiste, porque hay un índice que no es de clúster dentro de la tabla, gracias por eso mucho – danmiao

+1

+1 por la gran respuesta - ¡Gracias! Solo un punto adicional. Asegúrese de que los índices/estadísticas estén actualizados en la tabla que se está consultando. Dado que usa esas estadísticas para el conteo, las estadísticas desactualizadas arrojarán resultados inexactos. – jabs

4

¿Consideró la consulta select count(BookChapterId) from BookChapterTable? - donde `BookChapterId es índice no agrupado. Eso debería hacer que funcione mucho más rápido.

Dependiendo de cómo se utiliza la tabla y las filas acceder, consultar contra el índice no agrupado podría ser el punto clave: Me fui de puntos de MDSN:

  • Antes de crear índices no agrupados, entender cómo sus datos Se tendrá acceso a . Considere el uso de índices no agrupados para:
  • columnas que contienen un gran número de valores distintos, tales como una combinación de apellido y nombre (si un índice agrupado se utiliza para otras columnas)
    . Si hay muy pocos valores distintos, como
    solo 1 y 0, la mayoría de las consultas no usarán el índice porque una tabla
    escaneada suele ser más eficiente.
  • Consultas que no devuelven grandes conjuntos de resultados.
  • Columnas involucradas con frecuencia en las condiciones de búsqueda de una consulta (DONDE
    cláusula) que devuelven las coincidencias exactas.
  • Aplicaciones del sistema de soporte de decisiones para las cuales las uniones y agrupaciones son frecuentemente requeridas. Cree varios índices no agrupados en las columnas implicados en operaciones de unión y agrupación, y un índice agrupado en columnas de clave externa.
  • Cubriendo todas las columnas de una tabla en una consulta determinada. Esto elimina accediendo a la tabla o al índice agrupado por completo.
+0

Hola EIYusubov, probé, no hay diferencia, sigue siendo muy lento – danmiao

+0

revise sus índices, puede ser que tenga índices compuestos, o necesita reconstruirlos . –

+0

hola EIYusubov, es un índice de clúster de columna única, no índices compuestos, tengo que eliminar la clave principal y volver a crearla, pero no hay diferencia. – danmiao

7

Si mira los planes de ejecución de sus consultas, verá lo que está sucediendo.

Su primera consulta if (select count(*) from BookChapters) = 0 es reconocida por el optimizador de consultas como la misma que if exists(select * from BookChapters). SQL Server sabe que la expresión es verdadera si hay al menos una fila presente, por lo que busca la presencia de una fila en lugar de contar todas las filas de la tabla.

Para sus otras consultas, no puede ser tan inteligente y debe contar el número de filas en la tabla antes de que pueda decidir si la expresión se evalúa como verdadera o falsa.

3

probar esto, si es necesario detectar, si la tabla tiene más filas de uno:

if (SELECT COUNT(*) FROM (SELECT TOP 2 * FROM BookChapters) AS b) > 1 
11

probar esto si sólo se quiere saber el número de filas:

exec sp_spaceused [TABLE_NAME]