テストケース
PostgreSQL9.1。限られたリソースでデータベースをテストしますが、この小さなケースには十分です。照合のロケールが関連します:
SHOW LC_COLLATE;
de_AT.UTF-8
ステップ1)生のテスト環境を再構築する
-- 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);
ステップ2)分析
ANALYZE x.product;
ANALYZE x.django_site;
ステップ3)by random()
で並べ替えます-- DROP TABLE x.p;
CREATE TABLE x.p AS
SELECT *
FROM x.product
ORDER BY random();
ANALYZE x.p;
結果
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)分析前(->ビットマップインデックススキャン)
2)分析後(->シーケンススキャン)
3)ランダム()による並べ替え、分析
ORDER BY d.domain, p.ordering, p.name
1)合計実行時間:1253.543ミリ秒
2)合計実行時間:1250.351ミリ秒
3)合計実行時間:1283.111ミリ秒
ORDER BY p.ordering, p.name
1)合計実行時間:177.266ミリ秒
2)合計実行時間:174.556ミリ秒
3)合計実行時間:177.797ミリ秒
ORDER BY d.id, p.ordering, p.name
1)合計実行時間:176.628ミリ秒
2)合計実行時間:176.811ミリ秒
3)合計実行時間:178.150ミリ秒
プランナーは明らかにそのd.id コード> 機能に依存しています。
ORDER BY d.int_col, p.ordering, p.name -- integer column in other table
1)合計実行時間:242.218ミリ秒-!!
2)合計実行時間:245.234ミリ秒
3)合計実行時間:254.581ミリ秒
プランナーは明らかにそのd.int_col
を見逃しています (NOT NULL)は、機能に依存します。ただし、整数列による並べ替えは安価です。
ORDER BY p.name -- varchar(255) in same table
1)合計実行時間:2259.171ミリ秒-!!
2)合計実行時間:2257.650ミリ秒
3)合計実行時間:2258.282ミリ秒
(長い) varchar
による並べ替え またはtext
カラムは高価です...
ORDER BY p.name COLLATE "C"
1)合計実行時間:327.516ミリ秒-!!
2)合計実行時間:325.103ミリ秒
3)合計実行時間:327.206ミリ秒
...ただし、ロケールなしで実行した場合はそれほど高価ではありません。
ロケールが邪魔にならないように、 varchar
で並べ替えます カラムは完全ではありませんが、ほぼ同じくらい高速です。ロケール"C"
事実上「ロケールなし、バイト値で並べ替えるだけ」です。マニュアルを引用します:
システムがロケールをサポートしていないかのように動作させる場合は、特別なロケール名C、または同等のPOSIXを使用します。
すべてをまとめると、@dvdは次のように選択しました。
ORDER BY d.domain COLLATE "C", p.ordering, p.name
... 3)合計実行時間:275.854ミリ秒
それで十分です。