sql >> Databáze >  >> RDS >> PostgreSQL

Pomalé řazení dotazů podle sloupce ve spojené tabulce

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.



  1. TSQL - Jak používat GO uvnitř bloku BEGIN .. END?

  2. Práce s databázemi cPanel MySQL

  3. Je možné uložit hodnotu jednoho vybraného sloupce a použít ji pro další?

  4. Vyhýbání se řazení pomocí zřetězení sloučení spojení