バージョンごとのドキュメント一覧

36.15. 演算子最適化に関する情報 #

<title>Operator Optimization Information</title>

A <productname>PostgreSQL</productname> operator definition can include several optional clauses that tell the system useful things about how the operator behaves. These clauses should be provided whenever appropriate, because they can make for considerable speedups in execution of queries that use the operator. But if you provide them, you must be sure that they are right! Incorrect use of an optimization clause can result in slow queries, subtly wrong output, or other Bad Things. You can always leave out an optimization clause if you are not sure about it; the only consequence is that queries might run slower than they need to. PostgreSQLの演算子定義では、システムに演算子がどう振舞うかに関する有用なことを通知する、いくつかのオプション句を持つことができます。 これらの句により演算子を使用する問い合わせの実行速度がかなり向上しますので、これらの句は適切な時には常に提供しなければなりません。 しかし、提供する時にはそれらが正しいことを確認しなければいけません! 間違って最適化用の句を使用すると、問い合わせの低速化、わけのわからないおかしな出力、その他有害な事が起こり得ます。 最適化用の句についてわからなければ、使用しなくても構いません。 使用された時よりも問い合わせの実行が遅くなるかもしれないというだけです。

Additional optimization clauses might be added in future versions of <productname>PostgreSQL</productname>. The ones described here are all the ones that release &version; understands. PostgreSQLの今後のバージョンで、最適化用の句はさらに追加される可能性があります。 ここで説明するものはすべて、バージョン17.0で有効なものです。

It is also possible to attach a planner support function to the function that underlies an operator, providing another way of telling the system about the behavior of the operator. See <xref linkend="xfunc-optimization"/> for more information. 演算子の基となる関数にプランナサポート関数を結び付けて、システムに演算子の振舞いを通知する別の方法を提供することも可能です。 より詳細な情報については36.11を参照してください。

36.15.1. COMMUTATOR #

The <literal>COMMUTATOR</literal> clause, if provided, names an operator that is the commutator of the operator being defined. We say that operator A is the commutator of operator B if (x A y) equals (y B x) for all possible input values x, y. Notice that B is also the commutator of A. For example, operators <literal>&lt;</literal> and <literal>&gt;</literal> for a particular data type are usually each others' commutators, and operator <literal>+</literal> is usually commutative with itself. But operator <literal>-</literal> is usually not commutative with anything. COMMUTATOR句が与えられた場合、それは定義する演算子の交代演算子となる演算子の名前です。 取り得る全ての入力値x、yに対して、(x A y)が(y B x)と等しい時、演算子Aは演算子Bの交代演算子であると言います。 また、BはAの交代演算子となることにも注意してください。 例えば、通常、特定のデータ型用の演算子<>は互いの交代演算子になります。 また、通常、演算子+は自身が交代演算子となります。 しかし、通常、演算子-は交代演算子を持ちません。

The left operand type of a commutable operator is the same as the right operand type of its commutator, and vice versa. So the name of the commutator operator is all that <productname>PostgreSQL</productname> needs to be given to look up the commutator, and that's all that needs to be provided in the <literal>COMMUTATOR</literal> clause. 交代可能な演算子の左オペランドの型は、その交代演算子の右オペランドの型と同一で、その逆もまた同様です。 したがって、PostgreSQLで交代演算子を検索する時に必要なものは交代演算子の名前のみになりますので、COMMUTATOR句でそれのみを与えておけば十分です。

It's critical to provide commutator information for operators that will be used in indexes and join clauses, because this allows the query optimizer to <quote>flip around</quote> such a clause to the forms needed for different plan types. For example, consider a query with a WHERE clause like <literal>tab1.x = tab2.y</literal>, where <literal>tab1.x</literal> and <literal>tab2.y</literal> are of a user-defined type, and suppose that <literal>tab2.y</literal> is indexed. The optimizer cannot generate an index scan unless it can determine how to flip the clause around to <literal>tab2.y = tab1.x</literal>, because the index-scan machinery expects to see the indexed column on the left of the operator it is given. <productname>PostgreSQL</productname> will <emphasis>not</emphasis> simply assume that this is a valid transformation &mdash; the creator of the <literal>=</literal> operator must specify that it is valid, by marking the operator with commutator information. インデックスや結合句で使用される演算子では交代演算子の情報を提供することが必須です。 これにより、問い合わせオプティマイザがその句を他の種類の実行計画で必要とされる形式にひっくり返すことができるためです。 例えば、tab1.x = tab2.yのようなWHERE句を持った問い合わせを考えてみます。 ここでtab1.xtab2.yはユーザ定義型で、tab2.yにはインデックスが付いていると仮定します。 オプティマイザは、この句をtab2.y = tab1.xという形にひっくり返す方法を知らない限り、インデックススキャンを生成できません。 インデックススキャン機構は演算子の左側にインデックス付けされた列があることを想定しているためです。 PostgreSQLは簡単にこの変形が有効であると前提しません=演算子の作成者がこれが有効であることを、交代演算子情報を持つ演算子であると印付けて指定しなければなりません。

36.15.2. NEGATOR #

The <literal>NEGATOR</literal> clause, if provided, names an operator that is the negator of the operator being defined. We say that operator A is the negator of operator B if both return Boolean results and (x A y) equals NOT (x B y) for all possible inputs x, y. Notice that B is also the negator of A. For example, <literal>&lt;</literal> and <literal>&gt;=</literal> are a negator pair for most data types. An operator can never validly be its own negator. NEGATOR句が与えられた場合、それは定義する演算子の否定子となる演算子の名前です。 入力値xとyの取り得るすべての値に対して両方の演算子が論理値を返し、(x A y)がNOT (x B y)と等しい場合、演算子Aは演算子Bの否定子であると言います。 また、BはAの否定子でもあることに注意してください。 例えば、ほとんどのデータ型では<>=は否定子の対となります。 演算子が自身の否定子になることは決してありません。

Unlike commutators, a pair of unary operators could validly be marked as each other's negators; that would mean (A x) equals NOT (B x) for all x. 交代演算子と異なり、単項演算子の対は互いに否定子として有効に指定されます。 つまりすべてのxに対して(A x)がNOT (B x)と等しいことを意味します。

An operator's negator must have the same left and/or right operand types as the operator to be defined, so just as with <literal>COMMUTATOR</literal>, only the operator name need be given in the <literal>NEGATOR</literal> clause. ある演算子の否定子は、その演算子定義の左オペランド、右オペランドと同じ型を持たなければなりません。 ですので、COMMUTATOR句と同様に演算子の名前のみNEGATOR句で与えるだけで済みます。

Providing a negator is very helpful to the query optimizer since it allows expressions like <literal>NOT (x = y)</literal> to be simplified into <literal>x &lt;&gt; y</literal>. This comes up more often than you might think, because <literal>NOT</literal> operations can be inserted as a consequence of other rearrangements. NOT (x = y)という式をx <> yという形に単純化させることが可能なので、否定子があると問い合わせオプティマイザにとって非常に役に立ちます。 他の再配置の結果としてNOT操作が挿入されることがありますので、この現象は思ったより頻繁に起こります。

36.15.3. RESTRICT #

The <literal>RESTRICT</literal> clause, if provided, names a restriction selectivity estimation function for the operator. (Note that this is a function name, not an operator name.) <literal>RESTRICT</literal> clauses only make sense for binary operators that return <type>boolean</type>. The idea behind a restriction selectivity estimator is to guess what fraction of the rows in a table will satisfy a <literal>WHERE</literal>-clause condition of the form: RESTRICT句が与えられた場合、それは、その演算子用の制限選択評価関数を指定します。 (演算子名ではなく関数名であることに注意してください。) RESTRICT句はboolean型を返す二項演算子に対してのみ有効です。 制限選択評価の目的は、現在の演算子と特定の定数値についてのWHERE

column OP constant

for the current operator and a particular constant value. This assists the optimizer by giving it some idea of how many rows will be eliminated by <literal>WHERE</literal> clauses that have this form. (What happens if the constant is on the left, you might be wondering? Well, that's one of the things that <literal>COMMUTATOR</literal> is for...) の条件を満たすテーブル内の行の割合を推測することです。 この形式を持ったWHERE句によって、どのくらいの行が除外されるのかを通知することで、オプティマイザの手助けをします。 (定数値が左項にあったら何が起こるかという疑問が生じるかもしれませんが、それはCOMMUTATORが存在する理由の1つでもあります。)

Writing new restriction selectivity estimation functions is far beyond the scope of this chapter, but fortunately you can usually just use one of the system's standard estimators for many of your own operators. These are the standard restriction estimators: 新しい制限選択評価関数の記述方法は本章の内容を超えていますが、幸いなことに、数多いユーザ定義の演算子に対し通常いくつかのシステム標準の評価関数を使用すれば事足ります。 システム標準の制限評価関数には下記のものがあります。

=用のeqsel
<>用のneqsel
<用のscalarltsel
<=用のscalarlesel
>用のscalargtsel
>=用のscalargesel

You can frequently get away with using either <function>eqsel</function> or <function>neqsel</function> for operators that have very high or very low selectivity, even if they aren't really equality or inequality. For example, the approximate-equality geometric operators use <function>eqsel</function> on the assumption that they'll usually only match a small fraction of the entries in a table. 非常に高いもしくは低い選択性を所有する演算子が、まったく等しいか等しくないかにかかわらず、eqselまたはneqselを使用しないことも往々にして可能です。 例えば、近似等号用の幾何演算子はテーブルのエントリの小部分にのみに合致すると仮定してeqselを使用します。

You can use <function>scalarltsel</function>, <function>scalarlesel</function>, <function>scalargtsel</function> and <function>scalargesel</function> for comparisons on data types that have some sensible means of being converted into numeric scalars for range comparisons. If possible, add the data type to those understood by the function <function>convert_to_scalar()</function> in <filename>src/backend/utils/adt/selfuncs.c</filename>. (Eventually, this function should be replaced by per-data-type functions identified through a column of the <classname>pg_type</classname> system catalog; but that hasn't happened yet.) If you do not do this, things will still work, but the optimizer's estimates won't be as good as they could be. 範囲比較のために数値スカラに変換することに多少の有意性があるデータ型を比較するために、scalarltselscalarleselscalargtselscalargeselを使用することも可能です。 できればsrc/backend/utils/adt/selfuncs.cconvert_to_scalar()のルーチンで理解できるところにデータ型を追加してください (今後、このルーチンはpg_typeシステムカタログの列で識別された、データ型ごとの関数で置き換えられなければなりませんが、まだ行われていません)。 これを行わなくても動きますが、オプティマイザは本来の推測機能を十分発揮することができません。

Another useful built-in selectivity estimation function is <function>matchingsel</function>, which will work for almost any binary operator, if standard MCV and/or histogram statistics are collected for the input data type(s). Its default estimate is set to twice the default estimate used in <function>eqsel</function>, making it most suitable for comparison operators that are somewhat less strict than equality. (Or you could call the underlying <function>generic_restriction_selectivity</function> function, providing a different default estimate.) もう1つの便利な組み込みの選択評価関数はmatchingselで、入力データ型に対して標準的な最頻値やヒストグラム統計を収集する場合、ほぼすべての二項演算子に対して動作します。 デフォルトの評価はeqselで設定されているデフォルトの評価の2倍に設定されており、等価性ほど厳密でないような比較演算子には最適です。 (裏で実行されるgeneric_restriction_selectivity関数に異なるデフォルトの評価を与えて呼び出すこともできます。)

There are additional selectivity estimation functions designed for geometric operators in <filename>src/backend/utils/adt/geo_selfuncs.c</filename>: <function>areasel</function>, <function>positionsel</function>, and <function>contsel</function>. At this writing these are just stubs, but you might want to use them (or even better, improve them) anyway. さらにsrc/backend/utils/adt/geo_selfuncs.cには、幾何演算子に対する選択評価関数areaselpositionselcontselがあります。 本章の執筆時点では、これらは単なるスタブですが、ともかく使いたい(あるいは改良したい)こともあるでしょう。

36.15.4. JOIN #

The <literal>JOIN</literal> clause, if provided, names a join selectivity estimation function for the operator. (Note that this is a function name, not an operator name.) <literal>JOIN</literal> clauses only make sense for binary operators that return <type>boolean</type>. The idea behind a join selectivity estimator is to guess what fraction of the rows in a pair of tables will satisfy a <literal>WHERE</literal>-clause condition of the form: JOIN句が与えられた場合、それはその演算子用の結合選択評価関数の名前を指定します。 (これが演算子名ではなく関数名であることに注意してください。) JOIN句はboolean型を返す二項演算子に対してのみ有効です。 結合選択評価の目的は、現在の演算子について、WHERE

table1.column1 OP table2.column2

for the current operator. As with the <literal>RESTRICT</literal> clause, this helps the optimizer very substantially by letting it figure out which of several possible join sequences is likely to take the least work. を満たすテーブルの組み合わせの行の割合を推測することです。 RESTRICT句の使用と同様、これはいくつかの取り得る結合手順のうち、どれが最も仕事量が少ないように考えられるのかをオプティマイザに計算させることで、大きなオプティマイザへの援助となります。

As before, this chapter will make no attempt to explain how to write a join selectivity estimator function, but will just suggest that you use one of the standard estimators if one is applicable: 以前と同様、本章でも結合選択評価関数の作成方法は説明しません。 しかし適用できるものがあれば、単に標準の評価関数を使用することをお勧めします。

=用のeqjoinsel
<>用のneqjoinsel
<用のscalarltjoinsel
<=用のscalarlejoinsel
>用のscalargtjoinsel
>=用のscalargejoinsel
汎用の一致演算子用のmatchingjoinsel
2次元面積を基にした比較用のareajoinsel
2次元位置を基にした比較用のpositionjoinsel
2次元包含関係を基にした比較用のcontjoinsel

36.15.5. HASHES #

The <literal>HASHES</literal> clause, if present, tells the system that it is permissible to use the hash join method for a join based on this operator. <literal>HASHES</literal> only makes sense for a binary operator that returns <literal>boolean</literal>, and in practice the operator must represent equality for some data type or pair of data types. HASHES句が存在する場合、それはシステムに対して、この演算子に基づいた結合にハッシュ結合方法を使っても問題がないことを伝えます。 HASHES句はboolean型を返す二項演算子にのみ有効です。 実際には、この演算子はあるデータ型またはデータ型の組み合わせの等価性を表現しなければなりません。

The assumption underlying hash join is that the join operator can only return true for pairs of left and right values that hash to the same hash code. If two values get put in different hash buckets, the join will never compare them at all, implicitly assuming that the result of the join operator must be false. So it never makes sense to specify <literal>HASHES</literal> for operators that do not represent some form of equality. In most cases it is only practical to support hashing for operators that take the same data type on both sides. However, sometimes it is possible to design compatible hash functions for two or more data types; that is, functions that will generate the same hash codes for <quote>equal</quote> values, even though the values have different representations. For example, it's fairly simple to arrange this property when hashing integers of different widths. ハッシュ結合の基礎となっている仮定は、結合演算子は左項と右項の値が同じハッシュコードを持つ時にのみ真を返すことができるということです。 2つの値が異なるハッシュのバケットに置かれた場合、結合演算子の結果が必ず偽であるという仮定を、結合は暗黙的に行い、それらを比べることをしません。 したがって、何らかの等価性を表さない演算子にHASHES句を指定することはまったく意味がありません。 ほとんどの場合、両辺に同一のデータ型をとる演算子に対してハッシュ機能をサポートすることが現実的です。 しかし時として、2つ以上のデータ型に対して互換的なハッシュ関数、つまり、値自体が異なる表現形態を持っていたとしても等しい値に対して同一のハッシュコードを生成する関数を設計することもできます。 例えば、サイズが異なる整数に対するハッシュでは、この性質を調整することで大変単純になります。

To be marked <literal>HASHES</literal>, the join operator must appear in a hash index operator family. This is not enforced when you create the operator, since of course the referencing operator family couldn't exist yet. But attempts to use the operator in hash joins will fail at run time if no such operator family exists. The system needs the operator family to find the data-type-specific hash function(s) for the operator's input data type(s). Of course, you must also create suitable hash functions before you can create the operator family. HASHES印を付けるためには、結合演算子はハッシュインデックスの演算子族内になければなりません。 演算子を作成する時には参照する演算子族がまだ存在しませんので、演算子の作成時にこれは強制されていません。 しかし、演算子族が存在しない場合に、この演算子をハッシュ結合で使用しようとすると、実行時に失敗します。 システムは、演算子の入力データ型用のデータ型特有のハッシュ関数を検索するために、演算子族を必要とします。 もちろん、演算子族を作成する前に適切なハッシュ関数を作成しなければなりません。

Care should be exercised when preparing a hash function, because there are machine-dependent ways in which it might fail to do the right thing. For example, if your data type is a structure in which there might be uninteresting pad bits, you cannot simply pass the whole structure to <function>hash_any</function>. (Unless you write your other operators and functions to ensure that the unused bits are always zero, which is the recommended strategy.) Another example is that on machines that meet the <acronym>IEEE</acronym> floating-point standard, negative zero and positive zero are different values (different bit patterns) but they are defined to compare equal. If a float value might contain negative zero then extra steps are needed to ensure it generates the same hash value as positive zero. ハッシュ関数を準備する時には注意が必要です。 マシンに依存することから、ハッシュ結合が適切な処理を行わずに失敗することがあるからです。 例えば、データ型が不要な部分を埋めるビットを持つ可能性がある構造体である場合、(推奨する戦略である、他の演算子と関数を作成して、不要なビットが常にゼロになることを保証しない限り、)その構造体全体を単にhash_anyに渡すことはできません。 この他の例として、IEEE浮動小数点標準を満たすマシンでは、マイナス0とプラス0は異なる値(異なるビット列)になりますが、この比較は等価と定義されます。 浮動小数点数値がマイナス0を持つ可能性があるのであれば、それがプラス0と同じハッシュコードを確実に生成するような処置が必要です。

A hash-joinable operator must have a commutator (itself if the two operand data types are the same, or a related equality operator if they are different) that appears in the same operator family. If this is not the case, planner errors might occur when the operator is used. Also, it is a good idea (but not strictly required) for a hash operator family that supports multiple data types to provide equality operators for every combination of the data types; this allows better optimization. ハッシュ結合可能な演算子は、同一演算子族内に存在する交代演算子を持たなければなりません。 (2つの入力データ型が同じ場合はその演算子自体が交代演算子となります。異なる場合は関連する等価性演算子となります。) これを満たさないと、演算子の使用時にプランナエラーが発生します。 また、複数のデータ型をサポートするハッシュ演算子族に対して、データ型の組み合わせすべてに対する等価性演算子を持たせることを推奨します(必要ではありません)。 これにより、より優れた最適化が可能になります。

注記

The function underlying a hash-joinable operator must be marked immutable or stable. If it is volatile, the system will never attempt to use the operator for a hash join. ハッシュ結合可能演算子の基となる関数はimmutableもしくはstableでなければなりません。 volatileの場合、システムはその演算子を決してハッシュ結合に使用しません。

注記

If a hash-joinable operator has an underlying function that is marked strict, the function must also be complete: that is, it should return true or false, never null, for any two nonnull inputs. If this rule is not followed, hash-optimization of <literal>IN</literal> operations might generate wrong results. (Specifically, <literal>IN</literal> might return false where the correct answer according to the standard would be null; or it might yield an error complaining that it wasn't prepared for a null result.) ハッシュ結合可能演算子の基となる関数が厳密(strict)な場合、その関数は完全、つまり2つの非NULL入力に対して、真または偽を返し、決してNULLを返さないものである必要があります。 この規則に従わないと、IN操作におけるハッシュ最適化は間違った結果を生成する可能性があります。 (特に、標準に従うとNULLが正しい答えになるところでINは偽を返すかもしれません。 もしくは、NULLという結果に対する準備をしていないといったエラーを生成するかもしれません。)

36.15.6. MERGES #

The <literal>MERGES</literal> clause, if present, tells the system that it is permissible to use the merge-join method for a join based on this operator. <literal>MERGES</literal> only makes sense for a binary operator that returns <literal>boolean</literal>, and in practice the operator must represent equality for some data type or pair of data types. MERGES句が存在する場合、それはシステムに対して、この演算子に基づいた結合にマージ結合方法を使っても問題がないことを伝えます。 MERGES句はboolean型を返す二項演算子にのみ有効です。 実際には、演算子がデータ型またはデータ型の組み合わせの等価性を表すものであることが必要です。

Merge join is based on the idea of sorting the left- and right-hand tables into order and then scanning them in parallel. So, both data types must be capable of being fully ordered, and the join operator must be one that can only succeed for pairs of values that fall at the <quote>same place</quote> in the sort order. In practice this means that the join operator must behave like equality. But it is possible to merge-join two distinct data types so long as they are logically compatible. For example, the <type>smallint</type>-versus-<type>integer</type> equality operator is merge-joinable. We only need sorting operators that will bring both data types into a logically compatible sequence. マージ結合は、左側のテーブル、右側のテーブルを順序よくソートし、並列にスキャンするという考えに基づいています。 したがって、両データ型には完全な順序付け機能が必要であり、結合演算子はソート順で同じ場所にある値の対のみを成功したものとするものである必要があります。 実際問題として、これは、結合演算子は等価性のような振舞いをしなければならないことを意味しています。 しかし、マージ結合は論理的な互換性を持つ別の2つのデータ型を取ることができます。 例えば、smallintintegerの等価性演算子はマージ結合が可能です。 両方のデータ型を論理的な互換性を保つ順番にソートする演算子のみが必要です。

To be marked <literal>MERGES</literal>, the join operator must appear as an equality member of a <literal>btree</literal> index operator family. This is not enforced when you create the operator, since of course the referencing operator family couldn't exist yet. But the operator will not actually be used for merge joins unless a matching operator family can be found. The <literal>MERGES</literal> flag thus acts as a hint to the planner that it's worth looking for a matching operator family. MERGES印を付けるためには、結合演算子は、btreeインデックス演算子族の等価性メンバとして存在しなければなりません。 演算子を作成する時には参照する演算子族がまだ存在しませんので、演算子の作成時にこれは強制されていません。 しかし、対応する演算子族が存在しない限り、実際にマージ結合に使用されることはありません。 このように、MERGESフラグは、プランナが対応する演算子族を検索すべきかどうかを決定する際のヒントとして動作します。

A merge-joinable operator must have a commutator (itself if the two operand data types are the same, or a related equality operator if they are different) that appears in the same operator family. If this is not the case, planner errors might occur when the operator is used. Also, it is a good idea (but not strictly required) for a <literal>btree</literal> operator family that supports multiple data types to provide equality operators for every combination of the data types; this allows better optimization. マージ結合可能な演算子は、同一演算子族内に存在する交代演算子を持たなければなりません。 (2つの入力データ型が同じ場合はその演算子自体が交代演算子となります。異なる場合は関連する等価性演算子となります。) これを満たさないと、演算子の使用時にプランナエラーが発生します。 また、複数のデータ型をサポートするbtree演算子族に対して、データ型の組み合わせすべてに対する等価性演算子を持たせることを推奨します(必要ではありません)。 これにより、より優れた最適化が可能になります。

注記

The function underlying a merge-joinable operator must be marked immutable or stable. If it is volatile, the system will never attempt to use the operator for a merge join. マージ結合可能演算子の背後にある関数はimmutableもしくはstableでなければなりません。 volatileの場合、システムはその演算子を決してマージ結合に使用しようとはしません。