質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

解決済

3回答

1703閲覧

行数が少ない場合に、select count(*) でindexを読まない理由を教えてください

motisen

総合スコア92

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

0クリップ

投稿2018/02/23 09:00

各種バージョン

postgres のバージョンは9.5
AWS上のEC2に作成
EC2はCentOS 6.8

テーブル構成

親テーブル A (1億レコードほど)
小テーブル a,b,c,d.... (イベントがあるごとに作る運用となっている。大体500万レコードほど)

それぞれindexの構成は同じ。

小テーブルは親テーブルをパーティションのため継承している。

質問させていただきたいこと

継承によるパーティションがされているテーブルAに対して、
explain analyze select count(*) from A;
を投げた所、小テーブルのScan方法のほとんどが index only scan だったのですが、
とあるテーブルではSeq Scanでした。

そのテーブルは 30行しか入っていません。
(なぜこのような小テーブルがあるのかは謎です。)

select で取得するカラムがあるのであれば、行数が少ないのでindexを読まないという選択があるのはわかります。

しかし、今回はcount(*)なので、行数が少ないにせよindexを読んだほうがほんの少し(本当に少しですが)早いと思います。
テーブルよりもindexのサイズは小さいはずです。

なぜindexを読まないのでしょうか。
30行程度なら「index読もうがテーブル読もうが誤差だ誤差!」みたいな丼勘定なのでしょうか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

テーブルとインデックスが占めるディスクブロック数が同じ(両方とも1)場合は、どちらを利用するか未定です。
プランナで使用される統計情報

投稿2018/02/23 10:18

hihijiji

総合スコア4150

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

motisen

2018/02/24 13:06

ご回答ありがとうございます。 hihijijiさんの回答も知らなかったです。 勉強になりました。ありがとうございます。
guest

0

ベストアンサー

以下が参考になるかと思います。
65.1. 行数推定の例

以下抜粋

非常に簡単な問い合わせから始めましょう。
SELECT * FROM tenk1;
ページ数および行数はpg_classから検索されます。
これらの値は最後にそのテーブルをVACUUMまたはANALYZEを行った時点のものです。 プランナはその後、テーブル内の実際のページ数を取り出します(これはテーブルスキャンを行わない安価な操作です)。 それがrelpagesと異なる場合、reltuplesを得られたページ数の割合に応じて変更して現在の推定行数を求めます。

where条件の無いCount(*)で件数を求める場合、先ずは「テーブルスキャンを行わない安価な操作」が行われます。この状況のみで件数を取得した場合には、実行計画はindex scan にはなりません。

投稿2018/02/23 12:23

sazi

総合スコア25138

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

motisen

2018/02/24 13:05

ご回答ありがとうございます。テーブルスキャンを行わない安価な操作などで実際のページ数と取り出しているとは・・・。知りませんでした。ありがとうございます。
guest

0

極端に小さなテーブルだと、メモリに全テーブルが乗っている(けどインデックスはメモリにない)ので、「わざわざインデックスを呼び出すより、テーブルを全部読むほうが速い」となる状況があるのかもしれません。

投稿2018/02/23 09:06

maisumakun

総合スコア145121

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

motisen

2018/02/24 13:08

ご回答ありがとうございます。 selct count(*) したあとに、explain analyze select count(*) していました。 確かにメモリ(キャッシュ)に乗ってそうです。今後はそのあたりも考えて計測したいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問