sql >> Databasteknik >  >> RDS >> PostgreSQL

Långsam sökordning efter en kolumn i en sammanfogad tabell

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.



  1. SQL SKAPA TABELL för nybörjare

  2. Hur man installerar MySQL på CentOS 7

  3. Hur många poster kan jag lagra i 5 MB PostgreSQL på Heroku?

  4. Hur man behandlar MAX() i en tom tabell som 0 istället för NULL