Testcase
PostgreSQL 9.1. Testdatabase med begrænsede ressourcer, men nok til denne lille sag. Lokaliteten for sortering vil være relevant:
VIS LC_COLLATE; de_AT.UTF-8
Trin 1) Rekonstruer råt testmiljø
-- SLIP TABEL x;CREATE SCHEMA x; -- testskema-- DROP TABLE x.django_site;CREATE TABLE x.django_site (id seriel primær nøgle,domænekarakter varierende(100) ikke null,int_col int ikke null);INSERT INTO x.django_site værdier (1,'www. testsite.com/foodir/', 3);-- DROP TABLE x.product;CREATE TABLE x.product ( id seriel primær nøgle, site_id heltal ikke null, navnetegn varierende(255) ikke null, slug-tegn varierende(255) ikke null,sku karakter varierende(255), bestillingsheltal ikke null,active boolean ikke null);INSERT INTO x.product (site_id, name, slug, sku, ordering, active)SELECT 1 ,repeat(chr((random() * 255)::int + 32), (random()*255)::int) ,repeat(chr((random() * 255)::int + 32), (random()*255)::int ), repeat(chr((random() * 255)::int + 32), (random()*255)::int) ,i -- rækkefølge ,NOT (random()* 0,5174346569119122)::int ::boolFROM generate_series(1, 17540) AS x(i);-- SELECT ((591::float8 / 17540)* 0,5) / (1 - (591::float8 / 17540))-- =0,5174346569119122EX product_site-id IND på x.product(site_id);
Trin 2) ANALYSER
ANALYSE x.produkt; ANALYSE x.django_site;
Trin 3) Omarranger BY random()
-- DROP TABLE x.p;CREATE TABLE x.p ASSELECT *FRA x.productORDER BY random();ANALYSE x.p;
Resultater
EXPLAIN ANALYSE SELECT p.* FRA x.p JOIN x.django_site d ON (p.site_id =d.id) WHERE p.active AND p.site_id =1-- BESTILLE BY d.domain, p.ordering , s.navn-- BESTIL EFTER p.bestilling, s.navn-- BESTIL EFTER d.id, p.bestilling, s.navn-- BESTIL AF d.int_col, p.bestilling, s.navn-- BESTIL EFTER p. .name COLLATE "C"-- BESTIL AF d.domain COLLATE "C", p.ordering, p.name -- dvd's endelige løsning
1) Pre ANALYSE (-> bitmap indeks scan)
2) Post ANALYSE (-> seq scan)
3) Omarranger efter tilfældig(), ANALYSER
ORDER BY d.domain, p.ordering, p.name
1) Samlet kørselstid:1253.543 ms
2) Samlet kørselstid:1250.351 ms
3) Samlet kørselstid:1283.111 ms
ORDER BY p.ordering, p.name
1) Samlet kørselstid:177.266 ms
2) Samlet kørselstid:174.556 ms
3) Samlet kørselstid:177.797 ms
ORDER BY d.id, p.ordering, p.name
1) Samlet kørselstid:176.628 ms
2) Samlet kørselstid:176.811 ms
3) Samlet kørselstid:178.150 ms
Planlæggeren tager naturligvis højde for, at d.id er funktionelt afhængig.
BEstil AF d.int_col , p.ordering, p.navn -- heltalskolonne i anden tabel
1) Samlet kørselstid:242.218 ms -- !!
2) Samlet kørselstid:245.234 ms
3) Samlet kørselstid:254.581 ms
Planlæggeren savner åbenbart den d.int_col
(IKKE NULL) er lige så funktionelt afhængig. Men det er billigt at sortere efter en heltalskolonne.
BEstil efter s.navn -- varchar(255) i samme tabel
1) Samlet kørselstid:2259.171 ms -- !!
2) Samlet kørselstid:2257.650 ms
3) Samlet kørselstid:2258.282 ms
Sortering efter en (lang) varchar
eller tekst
kolonne er dyr ...
ORDER BY p.name SAMLER "C"
1) Samlet kørselstid:327.516 ms -- !!
2) Samlet kørselstid:325.103 ms
3) Samlet kørselstid:327.206 ms
... men ikke så dyrt, hvis det gøres uden lokalitet.
Med lokaliteten ude af vejen, sortering efter en varchar
kolonne er ikke helt, men næsten lige så hurtig. Landestandard "C"
er faktisk "ingen lokalitet, bare rækkefølge efter byteværdi". Jeg citerer manualen:
Hvis du ønsker, at systemet skal opføre sig, som om det ikke havde nogen lokalitetsunderstøttelse, skal du bruge det specielle lokalitetsnavn C eller tilsvarende POSIX.
Ved at sætte det hele sammen, valgte @dvd:
ORDER BY d.domain COLLATE "C", p.ordering, p.name
...3) Samlet kørselstid:275.854 ms
Det burde du gøre.