7

目的:

カウントの大きさが100,000〜10,000,000の場合に、2回の間に何かが発生した回数を取得します。

現在の実装:

  • PostgreSQLの使用
  • 各「インシデント」は、テーブルの個別の行として記録されます

列:

  • インシデントタイプ
  • 日時発生時刻

カウントを取得するためのクエリ(擬似コード):

COUNT rows WHERE time_occurred > <begin_time> AND time_occurred < <end_time>

問題:

これは機能しますが、クエリは非常に非効率的で、応答するのに約40秒かかります。私が理解しているように、PostgreSQLはこのタイプのクエリに使用するのに適したデータベースではありません。

私は座って、このタイプのクエリにインデックスを付けてO(log n)時間で実行できるいくつかの方法を考えたので、tが可能であることがわかりました。

これを行うにはどのツールを使用する必要がありますか?カウント行を格納するために別のデータベースを使用する必要がありますか?これを簡単に行うためにPostgreSQLの上にインストールできるパッケージはありますか?私たちのオプションは何ですか?

ノート:

私がこれについてはっきりしていたかどうかはわかりません。の結果はCOUNT、100,000〜10,000,000のオーダーになるはずです。これは、クエリに一致する行数が100,000〜10,000,000のオーダーになることを意味します。テーブル内の実際の行数は1桁多くなります。

本当にありがとう!

4

4 に答える 4

5

PostgreSQL 9.2より前では、MVCCの実装では、テーブルの各行にアクセスして、そのバージョンの行が現在のトランザクションに表示されているかどうかを確認するクエリが必要でした。これは、クエリにインデックス付きの列のみが含まれている場合でも発生します。これは、単純な場合でも、大きなテーブルでのカウントが遅いこととして現れます。

PostgreSQL 9.2は、インデックスのみのスキャンを実装します。これは、一部のワークロードでこの問題を軽減するのに役立つ場合があります。

v9.2未満でスタックしている場合、単純なクエリでおおよその行数のみが必要な場合は、いくつかの既知の回避策があります。http://wiki.postgresql.org/wiki/Count_estimateを参照してください。

于 2013-03-10T07:31:29.213 に答える
1

日ごとに集計されたインシデントのテーブルを保持します。

create table incidents_agreggated_by_day (
    "day" date primary key, total integer
);

毎日の実行:

insert into events_agreggated_by_day ("day", total) values
select date_trunc('day', time_occurred), count(*) total
from incidents
where 
    time_occurred < current_date
    and date_trunc('day', time_occurred) not in (
        select "day" from incidents_agreggated_by_day
    )
group by 1

'2013-01-0110:37'と'2013-03-0211:20'の間の合計が必要だとします。

select
(
    select sum(total)
    from incidents_aggregated_by_day
    where "day" >= '2013-01-02'::date and "day" < '2013-03-02'::date
) +
(
    select count(*)
    from incidents
    where 
        time_ocurred >= '2013-01-01 10:37':timestamp
        and time_ocurred < '2013-01-02'
        or
        time_ocurred <= '2013-03-02 11:20':timestamp
        and time_ocurred >= '2013-01-02'
) total

1億行を読み取る代わりに、数百または数千行を読み取ります。適切にインデックス付けされていれば、高速になります。

于 2013-03-11T00:42:25.023 に答える
1

別のアプローチは、テーブルを分割することかもしれません。この男は、パーティショニングに関する非常によく似た問題を解決したようです。

http://www.if-not-true-then-false.com/2009/performance-testing-between-partitioned-and-non-partitioned-postgresql-tables-part-3/

彼のアプローチを使用することに関する私の懸念は、保守性です。彼の例(チュートリアルのパート1をクリックしてパーティションの作成方法を確認する必要があります)では、各子テーブルを手動で作成し、トリガーで子テーブルへのルーティングをハードコーディングしています。テーブルが絶えず成長している場合は、多くのDBA作業を行うことになります。

ただし、彼はパフォーマンスを大幅に向上させているようです。したがって、それをより保守しやすくする方法を理解できれば、これは先に進むための良い方法かもしれません。

于 2013-03-11T22:12:56.773 に答える
1

これはまさに、次元モデリングとデータウェアハウジングが解決するように設計されている問題です。

以前のプロジェクトでは、このようなクエリを処理するために数週間でRubyにデータウェアハウスを構築し、単純なRESTAPIを使用してメインアプリに公開しました。基本的に、データを抽出して「スタースキーマ」に変換します。これは、説明するようなクエリ用に高度に最適化されています。

Postgresqlは、データウェアハウスデータベースに適しています。

これは非常に詳細なテーマであり、優れたスターターリソースは次のとおりです。http: //www.amazon.com/Data-Warehouse-Toolkit-Complete-Dimensional/dp/0471200247

于 2013-03-11T22:54:26.743 に答える