2010-05-09 15 views
6

Me gustaría obtener el recuento total de resultados y las primeras n filas de alguna consulta: ¿es posible en una sola declaración?¿puedo obtener count() y filas de una consulta sql en el servidor sql?

yo esperaría los resultados como:

count(..) column1  column2 
125   some_value some_value 
125   some_value some_value 

gracias de antemano!

+0

sí posible. Por favor, consulte el siguiente enlace. http://stackoverflow.com/questions/610932/how-to-retrieve-the-total-row-count-of-a-query-with-top – Sahi

Respuesta

3

Usted puede hacer esto con un CROSS JOIN y CTE, pero no es muy eficiente:

WITH Rows_CTE AS 
(
    SELECT Column1, Column2 
    FROM Table 
    WHERE (...) 
) 
SELECT c.Cnt, r.Column1, r.Column2 
FROM Rows_CTE r 
CROSS JOIN (SELECT COUNT(*) AS Cnt FROM Rows_CTE) c 

creo que una mejor manera de conseguir lo que quieres sería utilizar una sola consulta sino múltiple resultado conjuntos, lo que se puede hacer mediante el uso de COMPUTE:

SELECT Column1, Column2 
FROM Table 
WHERE (...) 
COMPUTE COUNT([Column1]) 
+0

¿Por qué usar un CTE? Una simple combinación cruzada en una tabla derivada lo hará. Y COMPUTE está en desuso también. – gbn

+0

@gbn: usé una 'CROSS JOIN'. El CTE es para que los predicados se puedan reutilizar (tenga en cuenta la inclusión de 'WHERE (...)', que falta en la pregunta pero que probablemente se incluye en el entorno de producción). Y sé que 'COMPUTE' está técnicamente desaprobado, pero' ROLLUP' no puede reemplazarlo aquí y usar 'COMPUTE' elimina una exploración completa de tabla/índice del plan. – Aaronaught

+0

Francamente, siempre me molesta que hayan dejado de usar 'COMPUTE', porque sigue siendo la * única * forma de calcular agregados sin una cláusula' GROUP BY'. Pero eso es una diana para otro día. – Aaronaught

8

de esta manera:

SELECT TOP 100 --optional 
    MC.Cnt, M.Column1, M.Column2 
FROM 
    myTable M 
    CROSS JOIN 
    (SELECT COUNT(*) AS Cnt FROM myTable) MC 

Editar: Después del downvote y COUNT/OVER answer. Una comparación en 2 mesas de mina de

Se puede ver una gran diferencia entre mi CROSS JOIN/simple agregado y un recuento/ORDEN POR cláusula vacía

SELECT COUNT(*) OVER() AS C, key1col, key2col 
FROM myTable 

(24717 row(s) affected) 

Table 'Worktable'. Scan count 3, logical reads 49865, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'myTable'. Scan count 1, logical reads 77, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

StmtText 
    |--Nested Loops(Inner Join) 
     |--Table Spool 
     | |--Segment 
     |   |--Index Scan(OBJECT:([MyDB].[dbo].[myTable].[IX_useful])) 
     |--Nested Loops(Inner Join, WHERE:((1))) 
      |--Compute Scalar(DEFINE:([Expr1003]=CONVERT_IMPLICIT(int,[Expr1005],0))) 
      | |--Stream Aggregate(DEFINE:([Expr1005]=Count(*))) 
      |   |--Table Spool 
      |--Table Spool 

SELECT 
    MC.Cnt, M.key1col, M.key2col 
FROM 
    myTable M 
    CROSS JOIN 
    (SELECT COUNT(*) AS Cnt FROM myTable) MC 

(24717 row(s) affected) 

Table 'myTable'. Scan count 2, logical reads 154, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 


StmtText 
    |--Nested Loops(Inner Join) 
     |--Compute Scalar(DEFINE:([Expr1005]=CONVERT_IMPLICIT(int,[Expr1009],0))) 
     | |--Stream Aggregate(DEFINE:([Expr1009]=Count(*))) 
     |   |--Index Scan(OBJECT:([MyDB].[dbo].[myTable].[IX_useful])) 
     |--Index Scan(OBJECT:([MyDB].[dbo].[myTable].[IX_useful] AS [M])) 

He repetido esto en una tabla con filas 570k y aquí está el IO

Table 'Worktable'. Scan count 3, logical reads 1535456, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'myTable'. Scan count 1, logical reads 2929, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 


Table 'myTable'. Scan count 34, logical reads 6438, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
+0

+1 para sacar todas tus armas. Tendré que revisar mis planes ejecutivos. –

+0

@Chris Bednarski: ¡Me han mordido antes! También SET STATISTICS TIME ON si es útil: CPU es x5 a x10 y duración x2 para la solución OVER para mí – gbn

+0

@gbn: ahora estoy interesado en ver si hay mucha diferencia en el rendimiento entre 2005 y 2008. Corre como un perro en 2005. –

6

¿qué pasa con

SELECT COUNT(*) OVER() AS C, COLUMN1, COLUMN2 
FROM TABLE 

En cuanto CROSS JOIN consultas
En un entorno pesado INSERT/DELETE, la unión cruzada devolverá el conteo de filas incorrecto.

Prueba esto desde múltiples conexiones
conexión 1

set nocount on; 
drop table dbo.test_table; 
GO 
create table dbo.test_table 
(
    id_field uniqueidentifier not null default(newid()), 
    filler char(2000) not null default('a') 
); 
GO 
create unique clustered index idx_id_fld on dbo.test_table(id_field); 
GO 
while 1 = 1 
insert into dbo.test_table default values; 

conexión 2

select T2.cnt, T1.id_field, T1.filler 
from dbo.test_table T1 
cross join (select COUNT(*) as cnt from dbo.test_table) T2 

select T2.cnt, T1.id_field, T1.filler 
from dbo.test_table T1 
cross join (select COUNT(*) as cnt from dbo.test_table) T2 

select T2.cnt, T1.id_field, T1.filler 
from dbo.test_table T1 
cross join (select COUNT(*) as cnt from dbo.test_table) T2 

Cada vez, el recuento de los registros (@@ROWCOUNT) es diferente a T2.cnt

En el caso de COUNT(*) OVER(), solo hay una exploración de tabla única y el @@ROWCOUNT es siempre el mismo que T2.cnt

En cuanto a los planes de consulta: SQL 2005 SP3 parece ser mucho más débil al hacer COUNT(*) OVER() que SQL 2008 R2. Además de eso, informa incorrectamente los costos de consulta (nunca pensé que una consulta secundaria podría costar más del 100% de la consulta completa).

En muchos casos, el costo de la COUNT(*) OVER() es entre 50-75% de la CROSS JOIN

El mejor de los casos para una combinación cruzada sería si había un índice muy estrecho para hacer el recuento de .De esta forma habrá un análisis de índice agrupado para los datos + un análisis de índice para el recuento.

Como siempre, lo mejor es medir, medir, medir e ir con el compromiso con el que está feliz de vivir.

+0

Iba a sugerir la misma cosa (ish) –

+0

+1 para usar la función Analítica ..... –

+0

mucho mejor que las uniones, usa un solo escaneo solamente –

0

darle una oportunidad para esta consulta:

select ColumnId,Descr,(select COUNT(*) from ColumnSetUp)as c 
from ColumnSetUp 
group by ColumnId,Descr 
Cuestiones relacionadas