sql >> データベース >  >> RDS >> PostgreSQL

結合されたテーブルの列によるクエリの順序付けが遅い

    テストケース

    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ミリ秒
    それで十分です。



    1. 単一のクエリで複数のCTE

    2. MySQLWorkbenchを使用してクエリの結果をエクスポートする方法

    3. 日付範囲の比較

    4. Docker化されたアプリからDockerのpostgresサーバーに接続できませんでした