Testfall
PostgreSQL 9.1. Testdatabas med begränsade resurser, men tillräckligt mycket för detta lilla fall. Lokalen för sortering kommer att vara relevant:
SHOW LC_COLLATE;
de_AT.UTF-8
Steg 1) Rekonstruera rå testmiljö
-- DROP TABLE x;
CREATE SCHEMA x; -- test schema
-- DROP TABLE x.django_site;
CREATE TABLE x.django_site (
id serial primary key
,domain character varying(100) not null
,int_col int not null
);
INSERT INTO x.django_site values (1,'www.testsite.com/foodir/', 3);
-- DROP TABLE x.product;
CREATE TABLE x.product (
id serial primary key
,site_id integer not null
,name character varying(255) not null
,slug character varying(255) not null
,sku character varying(255)
,ordering integer not null
,active boolean not 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 -- ordering in sequence
,NOT (random()* 0.5174346569119122)::int::bool
FROM generate_series(1, 17540) AS x(i);
-- SELECT ((591::float8 / 17540)* 0.5) / (1 - (591::float8 / 17540))
-- = 0.5174346569119122
CREATE INDEX product_site_id on x.product(site_id);
Steg 2) ANALYSE
ANALYZE x.product;
ANALYZE x.django_site;
Steg 3) Ordna om BY random()
-- DROP TABLE x.p;
CREATE TABLE x.p AS
SELECT *
FROM x.product
ORDER BY random();
ANALYZE x.p;
Resultat
EXPLAIN ANALYZE
SELECT p.*
FROM x.p
JOIN x.django_site d ON (p.site_id = d.id)
WHERE p.active
AND p.site_id = 1
-- ORDER BY d.domain, p.ordering, p.name
-- ORDER BY p.ordering, p.name
-- ORDER BY d.id, p.ordering, p.name
-- ORDER BY d.int_col, p.ordering, p.name
-- ORDER BY p.name COLLATE "C"
-- ORDER BY d.domain COLLATE "C", p.ordering, p.name -- dvd's final solution
1) Pre ANALYSE (-> bitmap index scan)
2) Post ANALYSE (-> seq scan)
3) Ordna om genom slumpmässig(), ANALYSE
ORDER BY d.domain, p.ordering, p.name
1) Total körtid:1253.543 ms
2) Total körtid:1250.351 ms
3) Total körtid:1283.111 ms
ORDER BY p.ordering, p.name
1) Total körtid:177,266 ms
2) Total körtid:174,556 ms
3) Total körtid:177,797 ms
ORDER BY d.id, p.ordering, p.name
1) Total körtid:176.628 ms
2) Total körtid:176.811 ms
3) Total körtid:178.150 ms
Planeraren tar naturligtvis hänsyn till att d.id är funktionsberoende.
ORDER BY d.int_col, p.ordering, p.name -- integer column in other table
1) Total körtid:242,218 ms -- !!
2) Total körtid:245,234 ms
3) Total körtid:254,581 ms
Planeraren missar uppenbarligen den d.int_col
(INTE NULL) är lika funktionellt beroende. Men att sortera efter en heltalskolumn är billigt.
ORDER BY p.name -- varchar(255) in same table
1) Total körtid:2259.171 ms -- !!
2) Total körtid:2257.650 ms
3) Total körtid:2258.282 ms
Sortering efter en (lång) varchar
eller text
kolumn är dyr ...
ORDER BY p.name COLLATE "C"
1) Total körtid:327.516 ms -- !!
2) Total körtid:325.103 ms
3) Total körtid:327.206 ms
... men inte lika dyrt om det görs utan språk.
Med lokalen ur vägen, sortering efter en varchar
kolumnen är inte riktigt men nästan lika snabb. Språk "C"
är i praktiken "ingen lokalitet, bara ordna efter bytevärde". Jag citerar manualen:
Om du vill att systemet ska bete sig som om det inte hade något språkstöd, använd det speciella språknamnet C, eller motsvarande POSIX.
När allt sammanslogs valde @dvd:
ORDER BY d.domain COLLATE "C", p.ordering, p.name
...3) Total körtid:275,854 ms
Det borde duga.