<!--
$Header: /usr/prj/pg/cvsroot/doc/doc/src/sgml/perform.sgml,v 1.4 2001/06/28 01:32:05 t-ishii Exp $
-->

 <chapter id="performance-tips">
<!--  <title>Performance Tips</title>-->
 <title>パフォーマンスに関するヒント</title>
<indexterm><primary sortas="ぱふぉーまんす">パフォーマンス</primary></indexterm>
<indexterm><primary>PostgreSQL</primary><secondary sortas="ぱふぉーまんす">パフォーマンス</secondary></indexterm>
  <para>
   <!-- Query performance can be affected by many things. Some of these can 
   be manipulated by the user, while others are fundamental to the underlying
   design of the system.  This chapter provides some hints about understanding
   and tuning <productname>Postgres</productname> performance.-->

   問い合わせの性能は、多くの要因に影響されます。ユーザーが制御できるものもありますが、利用しているシステムの設計に起因する要因もあります。この章では、<productname>Postgres</productname>の性能を理解し、チューニングする
ためのヒントを提供します。
  </para>

  <sect1 id="using-explain">
   <!-- <title>Using <command>EXPLAIN</command></title>-->
   <title><command>EXPLAIN</command>の利用</title>
<indexterm><primary>EXPLAIN</primary></indexterm>
<indexterm><primary>PostgreSQL</primary><secondary>EXPLAIN</secondary></indexterm>
   <note>
    <!-- <title>Author</title>-->
    <title>著者</title>
    <para>
     <!--Written by Tom Lane, from e-mail dated 2000-03-27.-->
     Tom Laneの2000年3月27日のe-mailから記述。
    </para>
   </note>

   <para>
    <!--<productname>Postgres</productname> devises a <firstterm>query
    plan</firstterm> for each query it is given.  Choosing the right
    plan to match the query structure and the properties of the data
    is absolutely critical for good performance.  You can use the
    <command>EXPLAIN</command> command to see what query plan the system
    creates for any query.  Unfortunately,
    plan-reading is an art that deserves a tutorial, and I haven't
    had time to write one.  Here is some quick &amp; dirty explanation.-->

    <productname>Postgres</productname>は、与えられた問い合わせから<firstterm>問い合わせ実行計画</firstterm>を作り出します。<indexterm><primary sortas="といあわせじっこうけいかく">問い合わせ実行計画</primary></indexterm><indexterm><primary>PostgreSQL</primary><secondary sortas="といあわせじっこうけいかく">問い合わせ実行計画</secondary></indexterm>問い合わせの構造と含まれるデータの性質に適した正しい問い合わせ実行計画を作成することが高い性能を得るために非常に重要になります。<command>EXPLAIN</command>コマンドを使えば、システムがどのような問い合わせ実行計画を作ったのかわかります。問い合わせ実行計画を読みこなすことは別にチュートリアルを作らなければいけないほどの内容なのですが、残念ながら、それを書いている時間ありません。ここではてっとり早く簡潔に説明をします。
   </para>

   <para>
    <!--The numbers that are currently quoted by EXPLAIN are:-->
	現在のところEXPLAINが出力する数値は以下のものです。
</para>

    <itemizedlist>
     <listitem>
      <para>
       <!--Estimated start-up cost (time expended before output scan can start,
       e.g., time to do the sorting in a SORT node).-->

	   予想される初期処理のコスト（検索結果が出力されるまでに消費される時間、たとえばSORTノードで実行されるソート処理の時間）
      </para>
     </listitem>

     <listitem>
      <para>
       <!--Estimated total cost (if all tuples are retrieved, which they may not
       be &bsol;-&bsol;-&bsol;- a query with a LIMIT will stop short of paying the total cost,
       for example).-->
	   予想される全体のコスト（結果のタプル全体が抽出される場合のみ。必ずしもそうでない場合もある。たとえば、LIMITを使うとこのコスト全部はかかりません）。
      </para>
     </listitem>

     <listitem>
      <para>
       <!--Estimated number of rows output by this plan node (again, without
       regard for any LIMIT).-->
	   このプランノードが出力する行数の予想（これもLIMITを考慮しません）。
      </para>
     </listitem>

     <listitem>
      <para>
	  このプランノードが出力する行の平均幅（バイト単位）の予想。
      </para>
     </listitem>
    </itemizedlist>

   <para>
    <!--The costs are measured in units of disk page fetches.  (CPU effort
    estimates are converted into disk-page units using some
    fairly arbitrary fudge-factors. If you want to experiment with these
    factors, see the list of run-time configuration parameters in the
    <citetitle>Administrator's Guide</citetitle>.)-->

これらのコストは、ディスクから読み出すページ単位で計測します（CPU消費見積もりは、適当に恣意的に決めた基準にしたがってディスクページ単位に換算されます。もしこれらの基準値の効果を知りたい場合は、<citetitle>&admin-guide;</citetitle>のランタイムコンフィギュレーションパラメータの一覧を参照してください）。
   </para>

   <para>
    <!--It's important to note that the cost of an upper-level node includes
    the cost of all its child nodes.  It's also important to realize that
    the cost only reflects things that the planner/optimizer cares about.
    In particular, the cost does not consider the time spent transmitting
    result tuples to the frontend &bsol;-&bsol;-&bsol;- which could be a pretty dominant
    factor in the true elapsed time, but the planner ignores it because
    it cannot change it by altering the plan.  (Every correct plan will
    output the same tuple set, we trust.)-->

特記すべき点は、上位のノードのコストは、すべての下位のノードのコストを含んでいるということです。また、このコストはプランナやオプティマイザが関与するコストしか反映していない点も重要です。とりわけ、結果のタプルをフロントエンドに転送するコストは、実際には処理時間の大半を占める可能性があるにもかかわらず、プランナは無視します。これは、プランを如何に変更しようともどうすることもできないからです（正しいプランはどんなものであれ、すべて同じ結果のタプルを出力すると考えられます）。
   </para>

   <para>
    <!--Rows output is a little tricky because it is <emphasis>not</emphasis> the
    number of rows
    processed/scanned by the query &bsol;-&bsol;-&bsol;- it is usually less, reflecting the
    estimated selectivity of any WHERE-clause constraints that are being
    applied at this node.  Ideally the top-level rows estimate will
    approximate the number of rows actually returned, updated, or deleted
    by the query (again, without considering the effects of LIMIT).-->

出力行数についてはちょっと特殊です。処理や検索の対象となる行数<emphasis>ではなく</emphasis>、該当ノードに適用されるWEHRE節の制限から来る検索率の見積もりを反映した、通常より少ない行数になります。理想的ならば、最上位の行数に関する見積もりが実際に問い合わせによって返されたり、更新/削除される実際の行数になります（これもLIMITの効果を考慮しません）。

   </para>

   <para>
    <!--Average width is pretty bogus because the thing really doesn't have
    any idea of the average length of variable-length columns.  I'm thinking
    about improving that in the future, but it may not be worth the trouble,
    because the width isn't used for very much.-->

実際には可変長列の平均幅について関知していないため、行の平均幅は役に立ちません。将来これを改良する予定ですが、行幅というものはさほど使われているわけではないため、するだけの価値があるかどうかわかりません。
   </para>

   <para>
    <!--Here are some examples (using the regress test database after a
    vacuum analyze, and almost-7.0 sources):-->

いくつか例を示します（vacuum analyzeをかけたあとのregress testデータベースを使っています。使用したシステムは7.0リリース直前のものです）。</para>

<programlisting>
regression=# explain select * from tenk1;
NOTICE:  QUERY PLAN:

Seq Scan on tenk1  (cost=0.00..333.00 rows=10000 width=148)
</programlisting>

   <para>
    <!--This is about as straightforward as it gets.  If you do-->
これはほとんど見たままです。</para>
<programlisting>
select * from pg_class where relname = 'tenk1';
</programlisting>

    <!--you'll find out that tenk1 has 233 disk
    pages and 10000 tuples.  So the cost is estimated at 233 block
    reads, defined as 1.0 apiece, plus 10000 * cpu_tuple_cost which is
    currently 0.01 (try <command>show cpu_tuple_cost</command>).-->

<para>上記のものをを実行すると、tenk1には233のディスクページと10,000タプルがあることがわかります。ですから、単位あたり1.0とコストが決まっている233ブロックの読み出し、それに加えてこれは現在0.01に設定されているcpu_tuple_cost（<command>show cpu_tuple_cost</command>を試してみてください）を1,000倍したものを加えたものがコストの見積もりになるわけです。

   </para>

   <para>
    <!--Now let's modify the query to add a qualification clause:-->
では、条件節を加えて問い合わせを変更してみます。</para>

<programlisting>
regression=# explain select * from tenk1 where unique1 &lt; 1000;
NOTICE:  QUERY PLAN:

Seq Scan on tenk1  (cost=0.00..358.00 rows=1000 width=148)
</programlisting>

    <!--The estimate of output rows has gone down because of the WHERE clause.
    (This estimate is uncannily accurate because tenk1 is a particularly
    simple case &bsol;-&bsol;-&bsol;- the unique1 column has 10000 distinct values ranging
    from 0 to 9999, so the estimator's linear interpolation between min and
    max column values is dead-on.)  However, the scan will still have to
    visit all 10000 rows, so the cost hasn't decreased; in fact it has gone
    up a bit to reflect the extra CPU time spent checking the WHERE
    condition.-->

<para>WHERE節があるため、出力行数の見積もりが小さくなっています（不自然に見積もりが正確なのは、単にtenk1が非常に単純なケースであるからです。unique1列には0から9,999までの10,000の異なる値が割り当てられているため、コスト見積もり部が最小値から最大値の間で線形補間を行った結果の値にぴったり一致します）。しかし、依然として100,000行すべてを走査する必要があるため、コストは小さくなっていません。実際には、WHERE条件を検査するために余分なCPUタイムがかかることを反映してほんの少しですがコストが上昇しています。

   </para>

   <para>
    <!--Modify the query to restrict the qualification even more:-->
ではさらに問い合わせを変更し、条件節の制限を強くしてみます。</para>

<programlisting>
regression=# explain select * from tenk1 where unique1 &lt; 100;
NOTICE:  QUERY PLAN:

Index Scan using tenk1_unique1 on tenk1  (cost=0.00..89.35 rows=100 width=148)
</programlisting>

    <!--and you will see that if we make the WHERE condition selective
    enough, the planner will
    eventually decide that an indexscan is cheaper than a sequential scan.
    This plan will only have to visit 100 tuples because of the index,
    so it wins despite the fact that each individual fetch is expensive.-->

<para>WHERE節の条件を十分検索率の高いものにすると、プランナはシーケンススキャンよりもインデックススキャンが安価でであると決定するようになることがわかります。この計画では、インデックスがあるためにたった100タプルだけをアクセスすればよいことになります。ですから、個々のインデックスのアクセスは高価につくにもかかわらず、この計画が採用されます。
   </para>

   <para>
    <!--Add another condition to the qualification:-->
別の検索条件を追加してみます。</para>

<programlisting>
regression=# explain select * from tenk1 where unique1 &lt; 100 and
regression-# stringu1 = 'xxx';
NOTICE:  QUERY PLAN:

Index Scan using tenk1_unique1 on tenk1  (cost=0.00..89.60 rows=1 width=148)
</programlisting>

    <!--The added clause "stringu1 = 'xxx'" reduces the output-rows estimate,
    but not the cost because we still have to visit the same set of tuples.-->

<para>追加したwhere節「stringu1 = 'xxx'」により出力行数の見積もりは減少するものの、検査するタプルの集合は変わらないためにコストは減っていません。

   </para>

   <para>
    <!--Let's try joining two tables, using the fields we have been discussing:-->
今まで説明に使ってきたフィールドを使って2つのテーブルを結合してみましょう。</para>

<programlisting>
regression=# explain select * from tenk1 t1, tenk2 t2 where t1.unique1 &lt; 100
regression-# and t1.unique2 = t2.unique2;
NOTICE:  QUERY PLAN:

Nested Loop  (cost=0.00..144.07 rows=100 width=296)
  -&gt;  Index Scan using tenk1_unique1 on tenk1 t1
             (cost=0.00..89.35 rows=100 width=148)
  -&gt;  Index Scan using tenk2_unique2 on tenk2 t2
             (cost=0.00..0.53 rows=1 width=148)
</programlisting>

   <para>
    <!--In this nested-loop join, the outer scan is the same indexscan we had
    in the example before last, and so its cost and row count are the same
    because we are applying the "unique1 &lt; 100" WHERE clause at that node.
    The "t1.unique2 = t2.unique2" clause isn't relevant yet, so it doesn't
    affect the outer scan's row count.  For the inner scan, the
    current
    outer-scan tuple's unique2 value is plugged into the inner indexscan
    to produce an indexqual like
    "t2.unique2 = <replaceable>constant</replaceable>".  So we get the
     same inner-scan plan and costs that we'd get from, say, "explain select
     * from tenk2 where unique2 = 42".  The loop node's costs are then set
     on the basis of the outer scan's cost, plus one repetition of the
     inner scan for each outer tuple (100 * 0.53, here), plus a little CPU
     time for join processing.-->

このnested-loop結合では、外側の走査に、最後の例で示したのと同じインデックス走査が使われています。そして、WHERE節の「unique1 < 100」を該当ノードに適用しているため、コストと出力行数は変わっていません。この段階では「t1.unique2 = t2.unique2」節は関係しておらず、外側の走査における出力行数に影響していません。内側の走査では、外側の走査における現在のタプルのunique2の値が内側のインデックス走査に投げ込まれ、インデックスの比較条件「t2.unique2 = constant」を生成します。したがって、内側の走査のプランとコストは、たとえば「explain select * from tenk2 where unique2 = 42」のような問い合わせと同じです。ループノードのコストは、外側の走査のコストと、各々の外側のタプルに対して内側の走査が繰り返されることによるコスト（ここでは100 * 0.53）を加え、さらに結合処理を行うための少々のCPU時間を加えたものになります。

   </para>

   <para>
    <!--In this example the loop's output row count is the same as the product
    of the two scans' row counts, but that's not true in general, because
    in general you can have WHERE clauses that mention both relations and
    so can only be applied at the join point, not to either input scan.
    For example, if we added "WHERE ... AND t1.hundred &lt; t2.hundred",
    that'd decrease the output row count of the join node, but not change
    either input scan.-->
この例では、ループ全体の出力行数は2つの走査の出力行数の積に等しくなっていますが、いつもそうなるわけではありません。たいていのばあい、2つのリレーションに関係するWHERE節があって、そのWHERE節は入力走査時ではなく、結合を行う際に適用されるからです。たとえば、「WHERE ... AND t1.hundred < t2.hundred」という節を追加したとすると、結合ノードの出力行数を減らしはしますが、入力走査には影響しません。
   </para>

   <para>
    <!--One way to look at variant plans is to force the planner to disregard
    whatever strategy it thought was the winner, using the enable/disable
    flags for each plan type.  (This is a crude tool, but useful.  See
    also <xref linkend="explicit-joins">.)-->

プランナが最もよいと考えているストラテジを強制的に否決することにより、別のプランを観察することができます（非常に原始的なツールですが、今現在使えるのはこれだけです。<xref linkend="explicit-joins">も参照してください）。</para>

<programlisting>
regression=# set enable_nestloop = off;
SET VARIABLE
regression=# explain select * from tenk1 t1, tenk2 t2 where t1.unique1 < 100
regression-# and t1.unique2 = t2.unique2;
NOTICE:  QUERY PLAN:

Hash Join  (cost=89.60..574.10 rows=100 width=296)
  -&gt;  Seq Scan on tenk2 t2
               (cost=0.00..333.00 rows=10000 width=148)
  -&gt;  Hash  (cost=89.35..89.35 rows=100 width=148)
        -&gt;  Index Scan using tenk1_unique1 on tenk1 t1
               (cost=0.00..89.35 rows=100 width=148)
</programlisting>

    <!--This plan proposes to extract the 100 interesting rows of tenk1
    using ye same olde indexscan, stash them into an in-memory hash table,
    and then do a sequential scan of tenk2, probing into the hash table
    for possible matches of "t1.unique2 = t2.unique2" at each tenk2 tuple.
    The cost to read tenk1 and set up the hash table is entirely start-up
    cost for the hash join, since we won't get any tuples out until we can
    start reading tenk2.  The total time estimate for the join also
    includes a pretty hefty charge for CPU time to probe the hash table
    10000 times.  Note, however, that we are NOT charging 10000 times 89.35;
    the hash table setup is only done once in this plan type.-->

<para>このプランでは、インデックス操作を使ってtenk1から必要な100行を取り出してメモリ上のハッシュテーブルに格納し、tenk2に対して「t1.unique2 = t2.unique2」を満たすものがあるかどうかそのハッシュテーブルをチェックしながら順次スキャンをtenk2に対して行います。tenk2の読み出しを開始するまでは出力結果は得られないため、tenk1を読みだしてハッシュテーブルをセットするコストは、そのハッシュジョインに対しては初期処理のコストとなります。この結合に関するコスト見積もりには、ハッシュテーブルを10,000回検査する非常に大きなCPUコストが含まれています。しかしながら、ハッシュテーブルのセットはこのプランでは一度しか行われないため、89.35の10,000倍のコストが課せられるわけではないことに注意してください。
   </para>
  </sect1>

 <sect1 id="explicit-joins">
  <!--<title>Controlling the Planner with Explicit JOINs</title>-->
  <title>明示的なJOINでプランナを制御する</title>
<indexterm><primary>PostgreSQL</primary><secondary sortas="ぷらんなのせいぎょ">プランナの制御</secondary></indexterm>
  <para>
   <!--Beginning with <productname>Postgres</productname> 7.1 it is possible
   to control the query planner to some extent by using explicit JOIN
   syntax.  To see why this matters, we first need some background.-->

   <productname>Postgres</productname> 7.1から明示的なJOIN構文を使ってクエリプランナをある程度制御できるようになりました。どうしてこういうことが問題になるのか、まずその背景を見る必要があります。
  </para>



  <para>
   <!--In a simple join query, such as
<programlisting>
SELECT * FROM a,b,c WHERE a.id = b.id AND b.ref = c.id;
</programlisting>
   the planner is free to join the given tables in any order.  For example,
   it could generate a query plan that joins A to B, using the WHERE clause
   a.id = b.id, and then joins C to this joined table, using the other
   WHERE clause.  Or it could join B to C and then join A to that result.
   Or it could join A to C and then join them with B &bsol;-&bsol;-&bsol;- but that would
   be inefficient, since the full Cartesian product of A and C would have
   to be formed, there being no applicable WHERE clause to allow optimization
   of the join.
   (All joins in the <productname>Postgres</productname> executor happen
   between two input tables, so it's necessary to build up the result in one
   or another of these fashions.)  The important point is that these different
   join possibilities give semantically equivalent results but may have hugely
   different execution costs.  Therefore, the planner will explore all of them
   to try to find the most efficient query plan.-->

   単純な問い合わせ、たとえば以下のような問い合わせでは、プランナは自由に与えられたテーブルをさまざまな順で結合することができます。</para>

<programlisting>
SELECT * FROM a,b,c WHERE a.id = b.id AND b.ref = c.id;
</programlisting>


<para>たとえば、WHERE節の「a.id = b.id」を使ってまずAとBを結合し、他のWHERE節を使ってその結果にCを結合するといったプランを立てることができます。あるいは、BとCを結合し、その結果にAを結合することもできます。さらに、AとCを結合し、その結果にBを結合することもできるでしょう。しかし、それでは効率がよくありません。なぜなら、WHERE節を使って最適化を行う余地がないためにAとCの全直積が作られるからです（<productname>Postgres</productname>のエグゼキュータでは、結合はすべて2つのテーブルの間で行われるため、このようにして1つ1つ結果を作っていかなければいけません）。重要なのは、これらの違った結合の方法は意味的には結果として同じなのですが、実行コストは大きく違うということです。ですから、プランナはもっとも効率のよいプランを探すために、可能なプランをすべて検査します。

  </para>

  <para>
   <!--When a query only involves two or three tables, there aren't many join
   orders to worry about.  But the number of possible join orders grows
   exponentially as the number of tables expands.  Beyond ten or so input
   tables it's no longer practical to do an exhaustive search of all the
   possibilities, and even for six or seven tables planning may take an
   annoyingly long time.  When there are too many input tables, the
   <productname>Postgres</productname> planner will switch from exhaustive
   search to a <firstterm>genetic</firstterm> probabilistic search
   through a limited number of possibilities.  (The switchover threshold is
   set by the GEQO_THRESHOLD run-time
   parameter described in the <citetitle>Administrator's Guide</citetitle>.)
   The genetic search takes less time, but it won't
   necessarily find the best possible plan.-->

   結合の対象がせいぜい2、3個のテーブルなら、心配するほど結合の種類は多くありません。しかし、テーブルの数が増えると可能な結合の数は指数関数的に増えていきます。10個程度以上にテーブルが増えると、すべての可能性をしらみつぶしに探索することはもはや実用的ではなくなります。6個や7個のテーブルでさえも、プランを作成する時間が無視できなくなります。テーブルの数が多すぎるときは、<productname>Postgres</productname>のプランナはしらみつぶしの探索から、限られた可能性だけを探索する<firstterm>遺伝的</firstterm>確率的な探索へと切り替わります（しきい値は<citetitle>&admin-guide;</citetitle>に記述されている実行時パラメータのGEQO_THRESHOLDで設定されます）。遺伝的探索は短い時間で探索を行いますが、必ずしも最適なプランを見つけるとは限りません。
  </para>

  <para>
   <!--When the query involves outer joins, the planner has much less freedom
   than it does for plain (inner) joins. For example, consider
<programlisting>
SELECT * FROM a LEFT JOIN (b JOIN c ON (b.ref = c.id)) ON (a.id = b.id);
</programlisting>
   Although this query's restrictions are superficially similar to the
   previous example, the semantics are different because a row must be
   emitted for each row of A that has no matching row in the join of B and C.
   Therefore the planner has no choice of join order here: it must join
   B to C and then join A to that result.  Accordingly, this query takes
   less time to plan than the previous query.-->

外部結合が含まれるような問い合わせでは、プランナには通常（内部）結合よりもずっと選択の余地が小さくなります。たとえば、次のような問い合わせを考えてみます。</para>

<programlisting>
SELECT * FROM a LEFT JOIN (b JOIN c ON (b.ref = c.id)) ON (a.id = b.id);
</programlisting>

<para>この問い合わせの検索条件は前述の例と表面的には似ているように思えますが、BとCの結合結果の行に適合しないAの各行が出力されなければならないため、意味的には異なります。したがって、ここではプランナには結合順に関して選択の余地がありません。まずBとCを結合し、その結果にAを結合しなければいけないのです。そういうわけで、この問い合わせでは計画を立てるのに要する時間は前の例よりも短くなります。
  </para>

  <para>
   <!--In <productname>Postgres</productname> 7.1, the planner treats all
   explicit JOIN syntaxes as constraining the join order, even though
   it is not logically necessary to make such a constraint for inner
   joins.  Therefore, although all of these queries give the same result:
<programlisting>
SELECT * FROM a,b,c WHERE a.id = b.id AND b.ref = c.id;
SELECT * FROM a CROSS JOIN b CROSS JOIN c WHERE a.id = b.id AND b.ref = c.id;
SELECT * FROM a JOIN (b JOIN c ON (b.ref = c.id)) ON (a.id = b.id);
</programlisting>
   the second and third take less time to plan than the first.  This effect
   is not worth worrying about for only three tables, but it can be a
   lifesaver with many tables.-->

   <productname>PostgreSQL</productname> 7.1では、論理的には内部結合に関しては制約を設ける必要がないにもかかわらず、プランナはすべての明示的な結合で結合順が制約されるものとみなします。したがって、以下のすべての問い合わせは、同じ結果を与えるのにもかかわらず、2番目と3番目の問い合わせは最初のものよりも短い時間で計画を立てます。</para>

<programlisting>
SELECT * FROM a,b,c WHERE a.id = b.id AND b.ref = c.id;
SELECT * FROM a CROSS JOIN b CROSS JOIN c WHERE a.id = b.id AND b.ref = c.id;
SELECT * FROM a JOIN (b JOIN c ON (b.ref = c.id)) ON (a.id = b.id);
</programlisting>

<para>この効果はたった3つのテーブルでは気にするほどのものではありませんが、多くのテーブルを結合する際には最後の頼みの綱になるかも知れません。

  </para>

  <para>
   <!--You do not need to constrain the join order completely in order to
   cut search time, because it's OK to use JOIN operators in a plain
   FROM list.  For example,
<programlisting>
SELECT * FROM a CROSS JOIN b, c, d, e WHERE ...;
</programlisting>
   forces the planner to join A to B before joining them to other tables,
   but doesn't constrain its choices otherwise.  In this example, the
   number of possible join orders is reduced by a factor of 5.-->

   探索の時間を節約するために、結合順をいつも制約する必要はありません。なぜなら、普通のFROMリストの結合演算を使うのは問題ないからです。たとえば、以下の問い合わせを考えてみます。</para>

<programlisting>
SELECT * FROM a CROSS JOIN b, c, d, e WHERE ...;
</programlisting>

<para>ここではプランは他のテーブルと結合する前にAとBを結合しますが、それ以外については特に制約がありません。この例では、結合順の候補は5の階乗分の1に減ります。
  </para>

  <para>
   <!--If you have a mix of outer and inner joins in a complex query, you
   might not want to constrain the planner's search for a good ordering
   of inner joins inside an outer join.  You can't do that directly in the
   JOIN syntax, but you can get around the syntactic limitation by using
   subselects.  For example,
<programlisting>
SELECT * FROM d LEFT JOIN
        (SELECT * FROM a, b, c WHERE ...) AS ss
        ON (...);
</programlisting>
   Here, joining D must be the last step in the query plan, but the
   planner is free to consider various join orders for A,B,C.-->

   外部結合と内部結合を含む複雑な問い合わせでは、外部結合の内側で実行される内部結合のよい結合順をプランが探索するのを妨害しない方がよいかもしれません。結合構文で直接そのように指定することもできますが、副問い合わせを使って構文的な制約を回避することもできます。たとえば、次の例です。</para>

<programlisting>
SELECT * FROM d LEFT JOIN
        (SELECT * FROM a, b, c WHERE ...) AS ss
        ON (...);
</programlisting>

<para>ここでは、Dの結合は問い合わせプランの中では最終段階になければならないものの、A、B、Cの結合順に関してはプランナは自由に考えることができます。
  </para>

  <para>
   <!--Constraining the planner's search in this way is a useful technique
   both for reducing planning time and for directing the planner to a
   good query plan.  If the planner chooses a bad join order by default,
   you can force it to choose a better order via JOIN syntax &bsol;-&bsol;-&bsol;- assuming
   that you know of a better order, that is.  Experimentation is recommended.-->

   このようにしてプランナの探索を制約するのは、プランを立てる時間を節約するのみならず、プランナがよい問い合わせ計画を立てるように仕向けるためにも役立つテクニックです。もしそのままではプランナがよくない結合順を選択するようなら、結合構文を使ってプランナがよりよい結合順を選ぶように強制することができます。あなたが、よりよい問い合わせ計画を知っているとしての話ですが。実験してみるとよいでしょう。

  </para>
 </sect1>

 <sect1 id="populate">
  <!--<title>Populating a Database</title>-->
  <title>データベースへのデータ投入</title>
<indexterm><primary sortas="でーたべーす">データベース</primary><secondary sortas="でーたのとうにゅう">データの投入</secondary></indexterm>
  <para>
   <!--One may need to do a large number of table insertions when first
   populating a database. Here are some tips and techniques for making that as
   efficient as possible.-->

   まずデータベースにデータを初期導入するために、大量のデータ登録を行う必要がままあります。ここでは、そうしたことを効率よく行うためのちょっとしたヒントとテクニックを紹介します。
  </para>

  <sect2 id="disable-autocommit">
   <!--<title>Disable Auto-commit</title>-->
   <title>Auto-commitをオフにする</title>
<indexterm><primary>auto-commit</primary></indexterm>
   <para>
    <!--Turn off auto-commit and just do one commit at
    the end.  Otherwise <productname>Postgres</productname> is doing a
    lot of work for each record
    added.  In general when you are doing bulk inserts, you want
    to turn off some of the database features to gain speed.-->

	auto-commitをオフにし、最後に1回だけコミットします。そうしないと、<productname>Postgres</productname>はレコードを追加するたびに多くの仕事をしなければいけません。一般的にいって、大量のデータ登録をするためには、データベースの機能の一部をオフにしておく必要があります。

   </para>
  </sect2>

  <sect2 id="populate-copy-from">
   <!--<title>Use COPY FROM</title>-->
   <title>COPY FROMを使う</title>
<indexterm><primary>COPY FROM</primary></indexterm>
   <para>
    <!--Use <command>COPY FROM STDIN</command> to load all the records in one
    command, instead
    of a series of INSERT commands.  This reduces parsing, planning, etc
    overhead a great deal. If you do this then it's not necessary to fool
    around with autocommit, since it's only one command anyway.-->

	1個のコマンドですべてのデータをすべてのデータをロードするために、一連のINSERTコマンドではなく、<command>COPY FROM STDIN</command>を使いましょう。こうすればパーサーやプランナそのほかのオーバーへッドを減らすことができます。いずれにしてもこの方法では、コマンドは1個なので、auto-commitをあれこれする必要はありません。

   </para>
  </sect2>

  <sect2 id="populate-rm-indices">
   <!--<title>Remove Indices</title>-->
   <title>インデックスは削除しておく</title>
<indexterm><primary sortas="いんでっくす">インデックス</primary></indexterm>
   <para>
    <!--If you are loading a freshly created table, the fastest way is to
    create the table, bulk-load with COPY, then create any indexes needed
    for the table.  Creating an index on pre-existing data is quicker than
    updating it incrementally as each record is loaded.-->
	
	新規のテーブルにデータをロードするのなら、一番早い方法は、テーブルを作ってCOPYでデータを一括ロードし、それから必要に応じてインデックスを作ることです。データをロードしながら徐々にインデックスを更新するよりも既存のデータからインデックスを作る方が高速です。

   </para>

   <para>
    <!--If you are augmenting an existing table, you can <command>DROP
     INDEX</command>, load the table, then recreate the index. Of
    course, the database performance for other users may be adversely 
    affected during the time that the index is missing.-->

	既存のテーブルにデータを追加する場合は、<command>DROP INDEX</command>してからデータをテーブルにロードし、インデックスを再作成します。もちろんインデックスが消失している間はデータベースの性能が影響を受けるかも知れません。

   </para>
  </sect2>
  </sect1>

 </chapter>

<!-- Keep this comment at the end of the file
Local variables:
mode:sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"./reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:("/usr/lib/sgml/catalog")
sgml-local-ecat-files:nil
End:
-->
