17

PostgreSQLで基本的に複数の行でifを実行するより高速な方法はありますか?

私はテーブルを持っていると言う

ticket | row | archived
1      | 1   | true
1      | 2   | true
1      | 3   | true
2      | 1   | false
2      | 2   | true

ticket = の列に if ステートメントを実行する方法はありますか? そのため、 where ticket = 1 は true になります。

true && true && true = true

どこで ticket = 2 は false になります。

false && true = false

それとも、私はただ固執するべきですか

SELECT ( (SELECT COUNT(*) FROM table WHERE ticket = 1)
       = (SELECT COUNT(*) FROM table WHERE ticket = 1 AND archived = true) )
4

3 に答える 3

21

集計関数bool_and()

シンプル、簡潔、明快:

SELECT bool_and(archived)
FROM   tbl
WHERE  ticket = 1;

マニュアル:

すべての入力値が true の場合は true、そうでない場合は false

サブクエリ式EXISTS

@Mike提供のように。

もっと早く。ただし、行が存在するかどうかをさらに確認する必要があります。そうしないと、ticket = 1存在しないチケットに対して誤った結果が得られます。

SELECT EXISTS (SELECT 1 FROM tbl WHERE ticket=1)
       AND NOT
       EXISTS (SELECT 1 FROM tbl WHERE ticket=1 AND archived = FALSE);

指数

どちらの形式でも、次のようなインデックスを使用できます。

CREATE index tbl_ticket_idx ON tbl (ticket);

.. これにより、両方が高速になりますが、EXISTSクエリが高速になります。これは、このフォームは最初に一致する行が見つかるとすぐにスキャンを停止できるためです。チケットあたりの行数が少ない場合、2 つのクエリにほとんど違いはありませんが、チケットあたりの行数が多い場合は大きな違いがあります。

pg 9.2 でインデックスのみのスキャンを利用するには、次の形式の複数列インデックスが必要です。

CREATE index tbl_ticket_archived_idx ON tbl (ticket, archived);

これは、ほとんどの場合、どのバージョンの PostgreSQL でも優れています。データの配置により、インデックスに aを追加しても、インデックスはまったく大きくなりません。ほとんどコストをかけずにメリットを追加。booleaninteger

ただし、インデックス付きの列は、HOT (ヒープ オンリー タプル) 更新を防ぎます。たとえば、UPDATE列のみを変更しますarchived。列がどのインデックスでも (何らかの方法で) 使用されていない場合、行は HOT 更新できます。そうしないと、このショートカットを使用できません。HOT アップデートの詳細:

それはすべて、実際のワークロードによって異なります。

于 2012-10-22T17:07:57.123 に答える
5

次のようなものはどうですか:

select not exists (select 1 from table where ticket=1 and not archived)

count インデックスを使用する場合と使用しない場合があり、実際に知る必要があるのは、そのチケットに行が存在するかどう だけであるため、これはカウントを比較するよりも有利であると思います。部分インデックスを作成するだけで、信じられないほど高速になるFALSEと思います。ticket

SQL フィドル

于 2012-10-22T16:05:29.710 に答える
1
select not false = any (
        select archived
        from foo
        where ticket = 1
    )

SQL フィドル

于 2012-10-22T16:12:33.357 に答える