web-dev-qa-db-ja.com

固定幅の行はPostgreSQLの読み取りパフォーマンスを向上させますか?

テーブルarticlesがあります:

                                                       Table "articles"
     Column     |            Type             |                     Modifiers                      | Storage  | Stats target | Description
----------------+-----------------------------+----------------------------------------------------+----------+--------------+-------------
 id             | integer                     | not null default nextval('articles_id_seq'::regclass) | plain    |              |
 user_id        | integer                     |                                                    | plain    |              |
 title          | character varying(255)      |                                                    | extended |              |
 author         | character varying(255)      |                                                    | extended |              |
 body           | text                        | default '--- []                                   +| extended |              |
                |                             | '::text                                            |          |              |
 created_at     | timestamp without time zone |                                                    | plain    |              |
 updated_at     | timestamp without time zone |                                                    | plain    |              |
 published_date | timestamp without time zone |                                                    | plain    |              |

Indexes:
    "articles_pkey" PRIMARY KEY, btree (id)
    "index_articles_on_published_date" btree (published_date)
    "index_rents_on_user_id" btree (user_id)
    "index_articles_on_user_id_and_published_date" btree (user_id, published_date)

Postgres 9.4.4を使用しています。マシンのSSDには3.5 GBのメモリと150 GBのディスク容量があります。

注:「published_date」は、アプリケーションによって常に最も近い日付に丸められます。すべての時間/分/秒は常に00です。レガシー。修正する必要があります。等。

このテーブルには数億の記事があります。テーブルは、システムが応答するのと同じ速さで次のクエリを実行する同時プロセス(16もの)から大量の読み取りクエリを受け取ります。

  • 記事の総数のカウント

    SELECT COUNT(*) FROM articles;
    
  • 特定のユーザー向けに公開されたすべての記事の選択

    SELECT * FROM articles WHERE user_id = $1;
    
  • 特定のユーザーのために最近公開された記事の選択

    SELECT * FROM articles WHERE user_id = $1 ORDER BY published_date DESC LIMIT 1;
    

多数のワーカーがあるため、これらのクエリは非常に遅いことがわかりました。 (ピーク負荷では、最初の処理は完了するまで数分かかります。他の2つは10秒程度です。)特に、クエリがキューに入れられているようです。

質問

要約では、固定幅の値のみを持つテーブルは、可変幅のテーブルよりも読み取りクエリを実行しますか?(ディスクスペースは問題ではないふりをします)私の場合、 「本文」テキストフィールドを別のテーブルに抽出し、文字可変フィールドを固定幅文字フィールドに変換すると、パフォーマンスが向上します。

質問は少しカーゴカルティです。情報に基づいた仮説を構築するためのPostgres DBエンジンの内部については、私は十分に知りません。私はさまざまなスキーマと構成で実際の実験を行うつもりですが、さらに先に進む前に、Postgresが実際にどのように機能するかについての確かなメンタルモデルが欲しいです。

関連質問

Postgres DBエンジンの内部の詳細はどこで確認できますか?上記の質問のバリエーションをGoogleで検索しましたが、ほとんど成功していません。この検索に使用する正しい用語は何ですか?このレベルのドキュメントは、ソースとPostgres DBAの心にのみ存在しますか?また、このトピックに関する良い本の提案を謙虚に勧めます。

7
bobocopy

固定幅の値のみを持つテーブルは、可変幅のテーブルよりも読み取りクエリを実行しますか?

基本的にはありません。列にアクセスするときのコストはごくわずかですが、違いを測定することはできません。詳細:

特に:

  • character varying(255)textの間のパフォーマンスにはnoの違いがあります/すべてvarchar(255)は(textとは異なり)「固定幅」タイプである可能性があるように見えますが、そうではありません。どちらも可変長型であり、varchar(255)は最大長のチェックを追加するだけです。

    テーブル定義でのvarchar(255)の使用は、通常、Postgres型システムを理解していないことを示しています。その背後にいるアーキテクトはおそらくネイティブスピーカーではありません-または、レイアウトがSQL Serverのような別のRDBMSから引き継がれ、これが以前は重要でした。

  • 最も高価なクエリSELECT COUNT(*) FROM articlesは行データも考慮しませんまったく、合計サイズのみが間接的に重要です。 Postgresでは、MVCCモデルのため、すべての行をカウントするのはコストがかかります。たぶん見積もりは十分で、非常に安く

(ディスクの空き容量は問題ではありません)。

ディスク容量はalways問題があります。ディスク上のサイズ(読み取り/処理/書き込みが必要なデータページの数)は、パフォーマンスにとって最も重要な要素の1つです。

Postgres DBエンジンの内部の詳細はどこで確認できますか?

タグの情報ページ postgres には、書籍、Postgres Wiki、優れたマニュアルなどの詳細情報への最も重要なリンクがあります。後者は私の個人的なお気に入りです。

3番目のクエリに問題があります

SELECT * FROM articles WHERE user_id = $1 ORDER BY published_date DESC LIMIT 1;

ORDER BY published_date DESC、ただしpublished_dateはNULLにすることができます(NOT NULL制約なし)。最新の実際のpublished_dateよりもNULL値を優先する場合を除いて、NULL値が存在する可能性がある場合、これはロードされたフットガンです。

いずれかNOT NULL制約を追加します。 NULLにできない列に対しては、常にそれを行ってください。
またはORDER BY published_date DESCNULLS LASTにし、それに応じてインデックスを調整します。

"articles_user_id_published_date_idx" btree (user_id, published_date DESC NULLS LAST)

この最近の関連する回答の詳細:

published_dateを実際のdateに変換します

'published_date' is always roundedですが、実質的には単なる date で、timestampの8バイトではなく4バイトを占めます。 2つのtimestamp列の前に来るようにテーブル定義でそれを上に移動するのが最善です。これにより、4バイトのパディングを失うことがなくなります。

...
body           | text
published_date | date   --     <---- here
created_at     | timestamp without time zone
updated_at     | timestamp without time zone

より小さなオンディスクストレージdoesは、パフォーマンスに違いをもたらします。

さらに重要なことに、(user_id, published_date)のインデックスは、40xではなく32バイトを占有します。これは、2x4バイトでは余分なパディングが発生しないためです。そして、それはパフォーマンスに顕著な違いをもたらすでしょう。

余談ですが、このインデックスはデモされたクエリには関係ありません。他で使用されない限り削除:

"index_articles_on_published_date" btree (published_date)

11