2010-05-09 7 views
6

Chciałbym uzyskać całkowitą liczbę wyników i górne n wierszy jakiegoś zapytania - czy jest możliwe w jednym zestawieniu?można uzyskać count() i wiersze z jednego kwerendy sql w serwerze sql?

będę oczekiwać na wyniki jako:

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

Z góry dziękuję!

+0

tak możliwe. Proszę zapoznać się z poniższym linkiem. http://stackoverflow.com/questions/610932/how-to-retrieve-the-total-row-count-of-a-query-with-top – Sahi

Odpowiedz

3

Ty może zrobić z CROSS JOIN i CTE, ale to nie jest bardzo wydajny:

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 

myślę lepszy sposób, aby uzyskać to, co chcesz byłoby użyć pojedynczego zapytania, ale wielu wynik ustawia, co można zrobić za pomocą COMPUTE:

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

Dlaczego warto korzystać z CTE? Wystarczy wykonać proste połączenie krzyżowe na tabeli pochodnej. Kompresja również jest przestarzała. – gbn

+0

@ gbn: Użyłem 'CROSS JOIN'. CTE jest tak, że predykaty mogą być ponownie użyte (zwróć uwagę na włączenie "WHERE (...)", którego brakuje w pytaniu, ale prawdopodobnie jest zawarte w środowisku produkcyjnym). I wiem, że "COMPUTE" jest technicznie przestarzałe, ale 'ROLLUP' nie może go tutaj zastąpić, a użycie polecenia 'COMPUTE' eliminuje z planu całe skanowanie tabeli/indeksu. – Aaronaught

+0

Szczerze mówiąc, zawsze denerwuje mnie to, że wycofali "COMPUTE", ponieważ jest to nadal * jedyny * sposób obliczania agregacji bez klauzuli "GROUP BY". Ale to jest rant na inny dzień. – Aaronaught

8

Jak to:

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

Edytuj: Po odliczeniu w dół i COUNT/OVER odpowiedzi. Porównanie 2 tablic kopalni

Widać ogromną różnicę między moim CROSS JOIN/prosty agregat i count/pusty ORDER BY klauzula

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])) 

mam powtarzać ten na stole z 570k wierszy i tutaj jest 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 za wyciągnięcie wszystkich swoich pistoletów. Będę musiał sprawdzić moje plany exec. –

+0

@ Chris Bednarski: Byłem już ugryziony! Również USTAW STATYSTYKI CZAS NA SI użyteczne: CPU jest x5 do x10 i czas x2 dla rozwiązania OVER dla mnie – gbn

+0

@ gbn: Jestem teraz zainteresowany, aby zobaczyć, czy istnieje duża różnica w wydajności między 2005 i 2008. Działa jak pies w 2005. –

6

co

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

Odnośnie CROSS JOIN zapytania
W środowisku ciężkim INSERT/DELETE połączenie poprzeczne zwróci nieprawidłową liczbę wierszy.

Spróbuj tego z wielu połączeń
Połączenie 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; 

połączenie 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 

Za każdym razem, liczba zapisów (@@ROWCOUNT) różni się T2.cnt

W przypadku z COUNT(*) OVER(), istnieje tylko jedno skanowanie tabeli i @@ROWCOUNT jest zawsze taki sam, jak T2.cnt Odnośnie planów zapytań - SQL 2005 SP3 wydaje się być znacznie słabszy przy wykonywaniu COUNT(*) OVER() niż SQL 2008 R2. Ponadto nieprawidłowo zgłasza koszty zapytania (nigdy nie sądziłem, że zapytanie może kosztować więcej niż 100% całego zapytania).

W wielu scenariuszy, koszt COUNT(*) OVER() wynosi między 50-75% wartości CROSS JOIN

Najlepszy scenariusz za krzyżem przyłączenia byłoby, gdyby nie było to bardzo wąski indeks zrobić liczyć na .W ten sposób zostanie utworzony indeks klastrowy dla danych + skanowanie indeksu dla zliczenia.

Jak zawsze, najlepiej mierzyć, mierzyć, mierzyć i iść z kompromisem, z którego jesteś zadowolony.

+0

Chciałem zasugerować to samo (ish) rzeczy –

+0

+1 za używanie funkcji analitycznej ..... –

+0

o wiele lepiej niż łączenia, używa tylko jednego skanowania –

0

spróbować dla tego zapytania:

select ColumnId,Descr,(select COUNT(*) from ColumnSetUp)as c 
from ColumnSetUp 
group by ColumnId,Descr 
Powiązane problemy