sql >> Database teknologi >  >> RDS >> PostgreSQL

Vælg forespørgsel med offset-grænse er for langsom

Den er langsom, fordi den skal finde den øverste offset rækker og scan de næste 100. Ingen mængder af optimering vil ændre det, når du har at gøre med store forskydninger.

Dette skyldes, at din forespørgsel bogstaveligt talt instruerer DB-motoren til at besøge mange rækker ved at bruge offset 3900000 -- det er 3,9 mio. rækker. Mulighederne for at fremskynde dette noget er ikke mange.

Superhurtig RAM, SSD'er osv. vil hjælpe. Men du vil kun vinde med en konstant faktor ved at gøre det, hvilket betyder, at den blot sparker dåsen ned ad vejen, indtil du når en større nok offset.

At sikre, at bordet passer i hukommelsen, med meget mere til overs, vil ligeledes hjælpe med en større konstant faktor - undtagen første gang. Men dette er muligvis ikke muligt med en tabel eller et indeks, der er stort nok.

At sikre, at du laver kun indeksscanninger, fungerer i et vist omfang. (Se velis' svar; det har mange fordele.) Problemet her er, at du for alle praktiske formål kan tænke på et indeks som en tabel, der gemmer en diskplacering og de indekserede felter. (Det er mere optimeret end som så, men det er en rimelig første tilnærmelse.) Med nok rækker vil du stadig løbe ind i problemer med en større nok offset.

At forsøge at gemme og vedligeholde rækkernes præcise position vil helt sikkert også være en dyr tilgang. (Dette foreslås af f.eks. benjist.) Selvom det er teknisk muligt, lider det af begrænsninger svarende til dem, der stammer fra at bruge MPTT med en træstruktur:du vil vinde betydeligt på læsninger, men vil ende med for lange skrivetider, når en node indsættes, opdateres eller fjernes på en sådan måde, at store bidder af dataene skal opdateres ved siden af.

Som det forhåbentlig er mere klart, er der ikke nogen rigtig magisk kugle, når du har at gøre med så store forskydninger. Det er ofte bedre at se på alternative tilgange.

Hvis du paginerer baseret på ID'et (eller et datofelt eller ethvert andet indekserbart sæt felter), ville et potentielt trick (brugt af blogspot, for eksempel) være at få din forespørgsel til at starte på et vilkårligt punkt i indekset.

Sagt på en anden måde i stedet for:

example.com?page_number=[huge]

Gør noget som:

example.com?page_following=[huge]

På den måde holder du et spor af, hvor du er i dit indeks, og forespørgslen bliver meget hurtig, fordi den kan gå direkte til det rigtige udgangspunkt uden at pløje gennem en gazillion rækker:

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

Naturligvis mister man evnen til at springe til f.eks. side 3000. Men tænk på dette ærligt:​​Hvornår var sidste gang du hoppede til et stort sidetal på et websted i stedet for at gå direkte til dets månedlige arkiver eller bruge dets søgefelt?

Hvis du paginerer, men ønsker at holde siden forskudt på nogen måde, er endnu en fremgangsmåde at forbyde brugen af ​​større sidetal. Det er ikke dumt:det er, hvad Google gør med søgeresultater. Når du kører en søgeforespørgsel, giver Google dig et estimeret antal resultater (du kan få et rimeligt antal ved at bruge explain ), og så giver dig mulighed for at gennemse de bedste par tusinde resultater - intet mere. Det gør de blandt andet af præstationsmæssige årsager – netop den, du løber ind i.



  1. Sådan installeres Oracle på en Mac

  2. Hvornår er det tid til at opgradere til SQL?

  3. MySQL Workbench:Sådan holder du forbindelsen i live

  4. Sådan fungerer SIGN() i MariaDB