Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Il conteggio di SQL Server è lento

Approssimativamente molto vicino (ignorando qualsiasi transazione in volo) sarebbe:

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

Questo ritornerà molto, molto più velocemente di COUNT(*) , e se la tua tabella sta cambiando abbastanza velocemente, non è davvero per niente meno precisa - se la tua tabella è cambiata tra quando hai iniziato il tuo COUNT (e sono stati presi i blocchi) e quando è stato restituito (quando sono stati rilasciati i blocchi e tutte le transazioni di scrittura in attesa erano ora autorizzati a scrivere al tavolo), è molto più prezioso? Non credo.

Se hai qualche sottoinsieme della tabella che vuoi contare (diciamo, WHERE some_column IS NULL ), potresti creare un indice filtrato su quella colonna e strutturare la clausola where in un modo o nell'altro, a seconda che fosse l'eccezione o la regola (quindi crea l'indice filtrato sull'insieme più piccolo). Quindi uno di questi due indici:

CREATE INDEX IAmTheException ON dbo.table(some_column)
  WHERE some_column IS NULL;

CREATE INDEX IAmTheRule ON dbo.table(some_column)
  WHERE some_column IS NOT NULL;

Quindi potresti ottenere il conteggio in modo simile utilizzando:

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]
  INNER JOIN sys.indexes AS i
  ON p.index_id = i.index_id
  WHERE t.name = N'myTable'
  AND s.name = N'dbo'
  AND i.name = N'IAmTheException' -- or N'IAmTheRule'
  AND p.index_id IN (0,1);

E se vuoi sapere il contrario, devi semplicemente sottrarre dalla prima query sopra.