Testovací případ
PostgreSQL 9.1. Test databáze s omezenými zdroji, ale dostačující pro tento malý případ. Relevantní bude národní prostředí pro řazení:
SHOW LC_COLLATE;
de_AT.UTF-8
Krok 1) Zrekonstruujte nezpracované testovací prostředí
-- 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);
Krok 2) ANALÝZA
ANALYZE x.product;
ANALYZE x.django_site;
Krok 3) Změňte pořadí BY random()
-- DROP TABLE x.p;
CREATE TABLE x.p AS
SELECT *
FROM x.product
ORDER BY random();
ANALYZE x.p;
Výsledky
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) Před ANALÝZA (-> skenování indexu bitmapy)
2) Po ANALÝZE (-> sekvenční skenování)
3) Přeuspořádání podle náhodného(), ANALÝZY
ORDER BY d.domain, p.ordering, p.name
1) Celková doba běhu:1253,543 ms
2) Celková doba běhu:1250,351 ms
3) Celková doba běhu:1283,111 ms
ORDER BY p.ordering, p.name
1) Celková doba běhu:177,266 ms
2) Celková doba běhu:174,556 ms
3) Celková doba běhu:177,797 ms
ORDER BY d.id, p.ordering, p.name
1) Celková doba běhu:176,628 ms
2) Celková doba běhu:176,811 ms
3) Celková doba běhu:178,150 ms
Plánovač zjevně zohledňuje toto d.id je funkčně závislý.
ORDER BY d.int_col, p.ordering, p.name -- integer column in other table
1) Celková doba běhu:242,218 ms -- !!
2) Celková doba běhu:245,234 ms
3) Celková doba běhu:254,581 ms
Plánovači zjevně chybí d.int_col
(NOT NULL) je stejně funkčně závislý. Ale řazení podle celočíselného sloupce je levné.
ORDER BY p.name -- varchar(255) in same table
1) Celková doba běhu:2259,171 ms -- !!
2) Celková doba běhu:2257,650 ms
3) Celková doba běhu:2258,282 ms
Řazení podle (dlouhého) varchar
nebo text
sloupec je drahý ...
ORDER BY p.name COLLATE "C"
1) Celková doba běhu:327,516 ms -- !!
2) Celková doba běhu:325,103 ms
3) Celková doba běhu:327,206 ms
... ale ne tak drahé, pokud to uděláte bez národního prostředí.
S národním prostředím v cestě, řazení podle varchar
sloupec není úplně, ale téměř stejně rychlý. Národní prostředí "C"
je ve skutečnosti "žádné národní prostředí, pouze pořadí podle hodnoty bajtu". Cituji manuál:
Pokud chcete, aby se systém choval, jako by neměl podporu národního prostředí, použijte speciální název národního prostředí C nebo ekvivalentně POSIX.
Když jsme to dali dohromady, @dvd si vybral:
ORDER BY d.domain COLLATE "C", p.ordering, p.name
...3) Celková doba běhu:275,854 ms
To by mělo stačit.