sql >> Database >  >> RDS >> PostgreSQL

Selectquery met offsetlimiet is te traag

Het is traag omdat het de bovenste offset moet vinden rijen en scan de volgende 100. Geen enkele mate van optimalisatie zal dat veranderen als je te maken hebt met enorme offsets.

Dit komt omdat uw zoekopdracht letterlijk instrueert de DB-engine om veel rijen te bezoeken met behulp van offset 3900000 -- dat zijn 3,9 miljoen rijen. Er zijn niet veel opties om dit wat te versnellen.

Supersnel RAM, SSD's, enz. zullen helpen. Maar je wint er alleen maar door een constante factor bij, wat betekent dat het alleen maar het blikje op de weg schopt totdat je een voldoende grotere offset hebt bereikt.

Ervoor zorgen dat de tafel in het geheugen past, met nog veel meer over, zal ook helpen door een grotere constante factor - behalve de eerste keer. Maar dit is misschien niet mogelijk met een tabel of index die groot genoeg is.

Ervoor zorgen dat u alleen-index-scans uitvoert, werkt tot op zekere hoogte. (Zie het antwoord van Velis; het heeft veel verdienste.) Het probleem hier is dat je, voor alle praktische doeleinden, een index kunt zien als een tabel waarin een schijflocatie en de geïndexeerde velden worden opgeslagen. (Het is meer geoptimaliseerd dan dat, maar het is een redelijke eerste benadering.) Met voldoende rijen zul je nog steeds problemen tegenkomen met een voldoende grotere offset.

Proberen om de precieze positie van de rijen op te slaan en te behouden is ongetwijfeld ook een dure aanpak. (Dit wordt bijvoorbeeld gesuggereerd door benjist.) Hoewel het technisch haalbaar is, lijdt het aan beperkingen die vergelijkbaar zijn met die die voortvloeien uit het gebruik van MPTT met een boomstructuur:u wint aanzienlijk aan leesbewerkingen, maar u krijgt te maken met buitensporige schrijftijden wanneer een knooppunt zodanig wordt ingevoegd, bijgewerkt of verwijderd dat grote delen van de gegevens tegelijkertijd moeten worden bijgewerkt.

Zoals hopelijk duidelijker is, is er geen echte magische kogel als je te maken hebt met zulke grote compensaties. Het is vaak beter om naar alternatieve benaderingen te kijken.

Als u pagineert op basis van de ID (of een datumveld of een andere indexeerbare reeks velden), zou een mogelijke truc (die bijvoorbeeld door blogspot wordt gebruikt) zijn om uw zoekopdracht op een willekeurig punt in de index te laten beginnen.

Anders gezegd, in plaats van:

example.com?page_number=[huge]

Doe iets als:

example.com?page_following=[huge]

Op die manier houdt u een spoor bij van waar u zich in uw index bevindt, en de zoekopdracht wordt erg snel omdat deze rechtstreeks naar het juiste startpunt kan gaan zonder door een gazillion rijen te ploegen:

select * from foo where ID > [huge] order by ID limit 100

Natuurlijk verlies je de mogelijkheid om naar b.v. pagina 3000. Maar denk hier eens goed over na:wanneer was de laatste keer dat u naar een enorm paginanummer op een site sprong in plaats van rechtstreeks naar de maandelijkse archieven te gaan of het zoekvak te gebruiken?

Als u pagineert maar de pagina op enigerlei wijze wilt verschuiven, is een andere benadering om het gebruik van grotere paginanummers te verbieden. Het is niet gek:het is wat Google doet met zoekresultaten. Wanneer u een zoekopdracht uitvoert, geeft Google u een geschat aantal resultaten (u kunt een redelijk aantal krijgen door explain te gebruiken ), en dan kunt u door de top paar duizend resultaten bladeren - meer niet. Ze doen dit onder andere om prestatieredenen -- precies degene die u tegenkomt.



  1. Hoe de functie Degrees() werkt in PostgreSQL

  2. Vier dingen die u niet wist over Amazon Aurora

  3. EXPORTEREN ALS INSERT-VERKLARINGEN:Maar in SQL Plus overschrijft de regel 2500 tekens!

  4. Hoe NIET REGEXP werkt in MariaDB