PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Бавно подреждане на заявките по колона в обединена таблица

Тестов случай

PostgreSQL 9.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 ms
2) Общо време на изпълнение:1250,351 ms
3) Общо време на изпълнение:1283,111 ms

ORDER  BY p.ordering, p.name

1) Общо време на изпълнение:177,266 ms
2) Общо време на изпълнение:174,556 ms
3) Общо време на изпълнение:177,797 ms

ORDER  BY d.id, p.ordering, p.name

1) Общо време на изпълнение:176,628 ms
2) Общо време на изпълнение:176,811 ms
3) Общо време на изпълнение:178,150 ms
Планиращият очевидно взема предвид този d.id код> е функционално зависима.

ORDER  BY d.int_col, p.ordering, p.name -- integer column in other table

1) Общо време на изпълнение:242,218 ms -- !!
2) Общо време на изпълнение:245,234 ms
3) Общо време на изпълнение:254,581 ms
Планиращият очевидно пропуска този d.int_col (NOT NULL) е също толкова функционално зависима. Но сортирането по колона с цяло число е евтино.

ORDER  BY p.name -- varchar(255) in same table

1) Общо време на изпълнение:2259,171 ms -- !!
2) Общо време на изпълнение:2257,650 ms
3) Общо време на изпълнение:2258,282 ms
Сортиране по (дълъг) varchar или текст колона е скъпа ...

ORDER  BY p.name COLLATE "C"

1) Общо време на изпълнение:327,516 ms -- !!
2) Общо време на изпълнение:325,103 ms
3) Общо време на изпълнение:327,206 ms
... но не толкова скъпо, ако се прави без локал.

Без локал, сортиране по varchar колоната не е съвсем, но почти толкова бърза. Локал "C" е ефективно "без локал, просто подреждане по стойност на байта". Цитирам ръководството:

Ако искате системата да се държи така, сякаш няма поддръжка за локал, използвайте специалното име на локал C или еквивалентно POSIX.

Обединявайки всичко това, @dvd избра:

ORDER  BY d.domain COLLATE "C", p.ordering, p.name

...3) Общо време на изпълнение:275,854 ms
Това трябва да стане.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Поправете „INSERT има повече изрази от целевите колони“ в PostgreSQL

  2. Постепенно архивиране на PostgreSQL и възстановяване в момента

  3. PostgreSQL параметризиран Order By / Limit във функцията на таблицата

  4. Функция RPAD() в PostgreSQL

  5. Много бавно стартиране на приложението Spring Boot