2011-06-21 22 views
7

Tengo una consulta de la siguiente manera;Rendimiento SQL lento

SELECT COUNT(Id) FROM Table 

La tabla contiene 33 millones de registros: contiene una clave principal en Id y ningún otro índice.

La consulta tarda 30 segundos.

El plan de ejecución real muestra que utiliza un análisis de índice agrupado.

Hemos analizado la tabla y hemos encontrado que no está fragmentada utilizando la primera consulta que se muestra en este enlace: http://sqlserverpedia.com/wiki/Index_Maintenance.

Alguna idea de por qué esta consulta es tan lenta y cómo solucionarla.

la tabla de definición:

CREATE TABLE [dbo].[DbConversation](
[ConversationID] [int] IDENTITY(1,1) NOT NULL, 
[ConversationGroupID] [int] NOT NULL, 
[InsideIP] [uniqueidentifier] NOT NULL, 
[OutsideIP] [uniqueidentifier] NOT NULL, 
[ServerPort] [int] NOT NULL, 
[BytesOutbound] [bigint] NOT NULL, 
[BytesInbound] [bigint] NOT NULL, 
[ServerOutside] [bit] NOT NULL, 
[LastFlowTime] [datetime] NOT NULL, 
[LastClientPort] [int] NOT NULL, 
[Protocol] [tinyint] NOT NULL, 
[TypeOfService] [tinyint] NOT NULL, 
    CONSTRAINT [PK_Conversation_1] PRIMARY KEY CLUSTERED 
(
[ConversationID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
GO 

Una cosa que he notado es la base de datos se espera que crezca en trozos 1 MB.

Es un sistema en vivo, por lo que restringimos en lo que podemos jugar, ¿alguna idea?

ACTUALIZACIÓN:

OK - hemos mejorado el rendimiento de la consulta real de interés mediante la adición de nuevos índices no agrupados en columnas apropiadas así que no es un tema crítico más.

SELECT COUNT sigue siendo lento - lo probé con consejos NOLOCK - no hay diferencia.

Todos pensamos que es algo relacionado con el crecimiento automático establecido en 1Mb en lugar de un número mayor, pero sorprende que tenga este efecto. ¿La fragmentación de MDF en el disco puede ser una posible causa?

+1

Pregunta 1: ¿realmente necesita el recuento exacto? ¿O solo una estimación? –

+0

Ninguno: esta es solo una consulta que ejecutamos después de observar el rendimiento lento en otra cosa. Nos sorprendió bastante descubrir que era muy lento. Voy a intentar actualizar las estadísticas, pero están configuradas para actualizarse automáticamente. – BonyT

+0

¿No puedes usar una constante? Quiero decir, ¿cómo le afecta la diferencia entre tener 33 millones ~ o tener realmente 33.212.293 registros? – bevacqua

Respuesta

5

¿Es ésta una tabla frecuentemente leída/insertada/actualizada? ¿Hay actividad de actualización/inserción concurrente con su selección?

Supongo que la demora se debe a una disputa.

Puedo ejecutar un conteo en 189m filas en 17 segundos en mi servidor de desarrollo, pero no hay nada más que golpee esa tabla.

Si no está demasiado preocupado por la contención o la precisión absoluta que puede hacer:

exec sp_spaceused 'MyTableName' que dará un recuento basado en los meta-datos.

Si desea un conteo más exacto, pero no necesariamente importa si reflejan concurrente DELETE o INSERT actividad que puede hacer su consulta actual con un NOLOCK pista:

SELECT COUNT(id) FROM MyTable WITH (NOLOCK) que no obtendrá bloqueos a nivel de fila para su consulta y debe ejecutar más rápido.

+0

No es una base de datos muy ocupada: la contención no es un problema (la afirmación casi siempre toma exactamente el mismo tiempo para responder los 30 y usar la sugerencia de NOLOCK no hace diferencia). – BonyT

+0

@BonyT - Entonces tiene otros problemas. ¿Qué tan ancha es esta mesa? Esto no es directamente relevante para el 'COUNT', pero sí afecta la cantidad de páginas que SQL necesita extraer para obtener el recuento, lo que puede importar a volúmenes más altos. ¿Qué otros problemas de rendimiento tienes? – JNK

+0

Se acepta, aunque nunca se sabe cuál fue el problema real/está aquí, como en otras partes del césped, y ellos han puesto en práctica una solución que yo entiendo. – BonyT

1
use [DatabaseName] 

select tbl.name, dd.rows from sysindexes dd 
inner join sysobjects tbl on dd.id = tbl.id where dd.indid < 2 and tbl.xtype = 'U' 

select sum(dd.rows)from sysindexes dd 
inner join sysobjects tbl on dd.id = tbl.id where dd.indid < 2 and tbl.xtype = 'U' 

Mediante el uso de estas consultas se puede recuperar recuento de todos los sitios dentro de 0-5 segundos

uso cláusula where acuerdo a sus necesidades .....

+0

El sitio de referencia es: http://planetofcoders.blogspot.com/2011/06/how-to-count-all-rows-in-particular.html –

+1

lea la publicación detenidamente, su preocupación no es el 'select count (id) 'bastante lento rendimiento de la consulta – Rahul

2

Pensamientos:

  • Use SELECT COUNT(*) que es correcto para "¿Cuántas filas" (según ANSI SQL). Incluso si ID es el PK y, por lo tanto, no puede contener nulos, SQL Server contará el ID. No filas

  • Si puede vivir con conteos aproximados, entonces use sys.dm_db_partition_stats. Véase mi respuesta aquí: Fastest way to count exact number of rows in a very large table?

  • Si se puede vivir con medias lecturas utilizar WITH (NOLOCK)

+0

Realmente no importa ya que el optimizador efectivamente utiliza el mismo plan lo que sea que coloque entre los corchetes. Sin embargo, algunas personas son quisquillosas con el uso del "*". Lo que sea que esto sea irrelevante para el problema. – BonyT

+0

@BonyT: si crees que es "quisquilloso" te sugiero que verifiques que * soy consciente * de las [diferencias] (http://stackoverflow.com/questions/1221559/count-vs-count1/1221649#1221649) pero cuente (col) puede no dar el mismo plan que contar (*). De ahí mi sugerencia – gbn

+0

Sí, tenemos - de hecho comenzamos con * :) – BonyT

0

Otra idea: Cuando los archivos crecen con las piezas de 1 MB, puede ser fragmentado en el sistema de archivos. No puede ver esto por SQL, lo ve usando una herramienta de desfragmentación de disco.

Cuestiones relacionadas