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

PostgreSQL:generate_series()を使用して列の欠落している数値を特定する方法は?

    与えられたサンプルデータ:

    create table results ( commandid integer primary key);
    insert into results (commandid) select * from generate_series(1,1000);
    delete from results where random() < 0.20;
    

    これは機能します:

    SELECT s.i AS missing_cmd
    FROM generate_series(0,1000) s(i)
    WHERE NOT EXISTS (SELECT 1 FROM results WHERE commandid = s.i);
    

    この代替定式化も同様です:

    SELECT s.i AS missing_cmd
    FROM generate_series(0,1000) s(i)
    LEFT OUTER JOIN results ON (results.commandid = s.i) 
    WHERE results.commandid IS NULL;
    

    上記の両方とも、私のテストでは同じクエリプランになるようですが、EXPLAIN ANALYZEを使用してデータベース上のデータと比較する必要があります。 どちらが最適かを確認します。

    説明

    NOT INの代わりに注意してください NOT EXISTSを使用しました 1つの定式化でサブクエリを使用し、通常のOUTER JOIN 他で。 DBサーバーがこれらを最適化するのははるかに簡単であり、NULLで発生する可能性のある紛らわしい問題を回避します。 s in NOT IN

    私は当初、OUTER JOINを好みました 公式化されていますが、少なくとも9.1では、私のテストデータではNOT EXISTS フォームは同じ計画に最適化されます。

    どちらもNOT INよりもパフォーマンスが優れています あなたの場合のように、シリーズが大きい場合の以下の定式化。 NOT IN INの線形検索を実行するようにPgに要求するために使用されます テストされているすべてのタプルのリストですが、クエリプランを調べると、Pgは今すぐハッシュするのに十分賢い可能性があることがわかります。 NOT EXISTSJOINに変換されます クエリプランナーによる)およびJOIN うまく機能します。

    NOT IN NULL commandidが存在する場合、定式化はどちらも混乱を招きます sおよび非効率的である可能性があります:

    SELECT s.i AS missing_cmd
    FROM generate_series(0,1000) s(i)
    WHERE s.i NOT IN (SELECT commandid FROM results);
    

    だから私はそれを避けたいと思います。 1,000,000行で、他の2つは1.2秒で完了し、NOT IN 退屈してキャンセルするまで、定式化はCPUバウンドで実行されました。



    1. 破損したアクセスデータベースを修復する方法

    2. psqlのコマンドラインクエリで一重引用符をエスケープするにはどうすればよいですか?

    3. SQLServerは日時からミリ秒を削除します

    4. C#を介してOracleデータベースに接続しますか?