In de loop der jaren is er een hoop ontwikkelaarszweet gestoken in het efficiënt pagineren van resultatensets. Toch is er niet één antwoord - het hangt af van uw gebruiksscenario. Een deel van de use case is om uw pagina efficiënt te krijgen, een deel is uitzoeken hoeveel rijen er in een complete resultatenset zitten. Dus sorry als ik een beetje afdwaal in paging, maar de twee zijn behoorlijk nauw met elkaar verbonden in mijn gedachten.
Er zijn veel strategieën, waarvan de meeste slecht zijn als je een soort datavolume hebt en niet in de use case passen. Hoewel dit geen volledige lijst is, volgen hier enkele van de opties.....
Voer aparte Count(*)
uit
- voer een aparte query uit die een simpele "select count(*) from MyTable" doet
- eenvoudig en gemakkelijk voor een kleine tafel
- goed voor een ongefilterde grote tabel die smal is of een compacte niet-geclusterde index heeft die u kunt gebruiken
- gaat kapot als je een ingewikkelde
WHERE/JOIN
. hebt criteria omdat het uitvoeren van deWHERE/JOIN
twee keer is duur. - breekt af op een brede index omdat het aantal leesbewerkingen omhoog gaat.
Combineer ROW_Number() OVER()
en COUNT(1) OVER(PARTITION By 1)
- Dit werd voorgesteld door @RBarryYoung. Het heeft het voordeel dat het eenvoudig te implementeren en zeer flexibel is.
- De keerzijde is dat er veel redenen zijn waarom dit snel extreem duur kan worden.
- Bijvoorbeeld, in een DB waar ik momenteel aan werk, is er een Media-tabel met ongeveer 6000 rijen. Het is niet bijzonder breed, heeft een geheel getal geclusterde PK en, evenals een compacte unieke index. Toch een simpele
COUNT(*) OVER(PARTITION BY 1) as TotalRows
resulteert in ~ 12.000 leest. Vergelijk dat met een simpeleSELECT COUNT(*) FROM Media
-- 12 leest. Wowzers.
Temptabellen / Tabelvariabelen
- Er zijn veel strategieën die een resultatenset gebruiken en relevante sleutels of segmenten van resultaten invoegen in tijdelijke tabellen/tabelvariabelen.
- Voor kleine/middelgrote resultaatsets kan dit geweldige resultaten opleveren.
- Dit type strategie werkt op bijna elk platform/versie van SQL.
- Meerdere keren op een resultatenset werken (vaak een vereiste) is ook eenvoudig.
- De keerzijde is dat wanneer u met grote resultatensets werkt ... het invoegen van een paar miljoen rijen in een tijdelijke tabel kosten met zich meebrengt.
- Om het probleem nog groter te maken, in een hoog volume kan de systeemdruk op TempDB een behoorlijke factor zijn, en tijdelijke tabellen werken effectief in TempDB.
Gaussiaanse som / dubbel rijnummer
- Dit idee is gebaseerd op subset van iets waar de wiskundige Gauss achter kwam (hoe een reeks getallen op te tellen). De subset is hoe u het aantal rijen kunt krijgen vanaf elk punt in de tabel.
- Van een reeks getallen (
Row_Number()
) het aantal rijen voor 1 tot N is(N + 1) - 1
. Meer uitleg in de links. - De formule lijkt uit te komen op slechts N, maar als je je aan de formule houdt, gebeuren er interessante dingen, dan kun je het aantal rijen berekenen vanaf een pagina in het midden van de tabel.
- Het netto resultaat is dat je
ROW_Number() OVER(Order by ID)
doet enROW_Number() OVER(Order by ID DESC)
tel dan de twee getallen op en trek 1 af. - Als ik mijn Media-tabel als voorbeeld gebruikte, daalden mijn leesresultaten van 12.000 naar ongeveer 75.
- Op een grotere pagina heb je gegevens vaak herhaald, maar de verschuiving in het lezen kan de moeite waard zijn.
- Ik heb dit niet in te veel scenario's getest, dus het kan in andere scenario's uit elkaar vallen.
Boven (@n) / ROWCOUNT INSTELLEN
- Dit zijn op zich geen specifieke strategieën, maar optimalisaties op basis van wat we weten over de query-optimizer.
- Creatief gebruik van Top(@n) [top kan een variabele zijn in SQL 2008] of SET ROWCOUNT kan uw werkset verkleinen ... zelfs als u een middelste pagina van een resultatenset trekt, kunt u het resultaat nog verkleinen
- Deze ideeën werken vanwege het gedrag van de queryoptimalisatie ... een servicepack/hotfix kan het gedrag veranderen (hoewel waarschijnlijk niet).
- In bepaalde gevallen kan SET ROWCOUNT een beetje nauwkeurig zijn
- Deze strategie houdt geen rekening met het verkrijgen van het volledige aantal rijen, maar maakt paging alleen efficiënter
Dus wat moet een ontwikkelaar doen?
Lees mijn goede man, lees. Hier zijn enkele artikelen waarop ik heb geleund...
- Een efficiëntere methode om door grote resultatensets te bladeren
- Optimaliseren van server-side paging - deel I
- Optimaliseren van server-side paging - deel II
- Uitleg van de Gaussiaanse som
- Gerangschikte resultaten retourneren met Microsoft SQL Server 2005
- ROW_NUMBER() OVER Niet snel genoeg met grote resultatenset
- De eerste N-records ophalen uit een SQL-query
- Server-side paging met SQL Server 2005
- Waarom zijn logische leesbewerkingen voor geaggregeerde vensterfuncties zo hoog?
Ik hoop dat dat helpt.