Difference between revisions of "Slow Counting/ja"

From PostgreSQL wiki
Jump to: navigation, search
m
(Translate note about index-only scans in 9.2)
 
(One intermediate revision by one other user not shown)
Line 1: Line 1:
 
{{Languages}}
 
{{Languages}}
 +
'''以下の記事は9.2より前のPostgreSQLバージョンにのみ適用されることに注意してください。今はインデックスオンリースキャンが実装されています。'''
 +
 
以下の例のようなテーブル内の全行数を数えることは、PostgreSQLの性能が遅いことが分かっている操作の1つです。
 
以下の例のようなテーブル内の全行数を数えることは、PostgreSQLの性能が遅いことが分かっている操作の1つです。
  
Line 28: Line 30:
 
</pre></code>
 
</pre></code>
  
これによりこうした問い合わせは大きく高速化されます。PostgreSQLはまだ、行が存在するかどうかを検証するために結果行を読み取る必要があります。他のデータベースシステムの多くは、こうした状況ではインデックスを参照する必要があるだけです。
+
これによりこうした問い合わせは大きく高速化されます。PostgreSQLはまだ、行が存在するかどうかを検証するために結果行を読み取る必要があります。他のデータベースシステムでは、こうした状況ではインデックスを参照する必要があるだけかもしれません。
  
 
== 行数の推定 ==
 
== 行数の推定 ==
Line 44: Line 46:
 
この前提となるのは、統計情報が最新情報を維持できるほど十分にテーブルに対してANALYZEを実行していることです。
 
この前提となるのは、統計情報が最新情報を維持できるほど十分にテーブルに対してANALYZEを実行していることです。
  
行数が必要だが、コミット中のトランザクションが含まれないことを許容できるアプリケーションでは、他にもよくつかわれる方法があります。
+
他にもトリガを基にした機構を使用してテーブル内の行数を数える方法がよく使われます。
それはトリガを基にした機構を使用してテーブル内の行数を数える方法です。
 
 
これらの技法の片方、または両方の説明は以下にあります。
 
これらの技法の片方、または両方の説明は以下にあります。
 
* [http://www.varlena.com/GeneralBits/120.php Counting Rows]
 
* [http://www.varlena.com/GeneralBits/120.php Counting Rows]
 
* [http://www.varlena.com/GeneralBits/49.php Tracking the Row Count]
 
* [http://www.varlena.com/GeneralBits/49.php Tracking the Row Count]
* [http://blog.charcoalphile.com/2007/12/12/postgresql-count-workaround/ PostgreSQL Slow Count() Workaround]
 
 
<p>
 
<p>
 
* 元原稿:  [[Why PostgreSQL Instead of MySQL: Comparing Reliability and Speed in 2007|Why PostgreSQL Instead of MySQL]] (これにはMySQLとどのように異なるかについても議論されています)
 
* 元原稿:  [[Why PostgreSQL Instead of MySQL: Comparing Reliability and Speed in 2007|Why PostgreSQL Instead of MySQL]] (これにはMySQLとどのように異なるかについても議論されています)

Latest revision as of 01:16, 19 September 2012

以下の記事は9.2より前のPostgreSQLバージョンにのみ適用されることに注意してください。今はインデックスオンリースキャンが実装されています。

以下の例のようなテーブル内の全行数を数えることは、PostgreSQLの性能が遅いことが分かっている操作の1つです。

SELECT COUNT(*) FROM table

これが低速となる理由はPostgreSQLのMVCC実装に関連します。 複数のトランザクションが異なるデータ状態を参照することができることは、"COUNT(*)"のためにテーブル全体に渡るデータをまとめる簡単な方法があり得ないことを意味します。 別の見方をすると、PostgreSQLは必ずすべての行をたどります。 これは通常、テーブル内の全行に関する情報をシーケンシャルスキャンを使用して読み取ることになります。 問い合わせがどのように進んでいるかを確認する優れた方法はEXPLAIN ANALYZEを使用することです。

postgres=# EXPLAIN ANALYZE SELECT COUNT(*) FROM accounts;
                                                      QUERY PLAN                                                       
-----------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=4499.00..4499.01 rows=1 width=0) (actual time=465.588..465.591 rows=1 loops=1)
   ->  Seq Scan on accounts  (cost=0.00..4249.00 rows=100000 width=0) (actual time=0.011..239.212 rows=100000 loops=1)
 Total runtime: 465.642 ms
(3 rows)

悲観的にならざるを得ないのがこの厳密な集約構文だけであることがわかることには価値があります。もし次のように"WHERE"句があったとすると、PostgreSQLは限定されたフィールドに対して利用可能なインデックスを利用して、数えなければならないレコードの行数を制限します。

SELECT COUNT(*) FROM table WHERE status = 'something'

これによりこうした問い合わせは大きく高速化されます。PostgreSQLはまだ、行が存在するかどうかを検証するために結果行を読み取る必要があります。他のデータベースシステムでは、こうした状況ではインデックスを参照する必要があるだけかもしれません。

行数の推定

おおよその行数だけが必要である場合、PostgreSQLには1つの代替方法があります。 これは以下のようにpg_classカタログのreltuplesフィールドを使用することです。

pgbench=# select reltuples from pg_class where relname='tellers';
 reltuples 
-----------
       250

この前提となるのは、統計情報が最新情報を維持できるほど十分にテーブルに対してANALYZEを実行していることです。

他にもトリガを基にした機構を使用してテーブル内の行数を数える方法がよく使われます。 これらの技法の片方、または両方の説明は以下にあります。