テーブル関数
私は、SQLをクライアント言語とサーバー言語の両方として使用して(他の言語は使用されていません)、非常に高速で複雑なデータベース移行を実行します。すべてサーバー側で実行され、コードはデータベースエンジンからほとんど表示されません。 テーブル関数は私の仕事で大きな役割を果たします 。 「カーソル」は速度が遅すぎてパフォーマンス要件を満たすことができないため、使用しません。また、実行することはすべて結果セット指向です。テーブル関数は、カーソルの使用を完全に排除し、非常に高速を実現する上で非常に役立ち、コード量の削減と単純さの向上に劇的に貢献しました。
つまり、クエリを使用します 2つ(またはそれ以上)のテーブル関数を参照して、1つのテーブル関数から次のテーブル関数にデータを渡します。 テーブル関数を呼び出すselectクエリ結果セットは、あるテーブル関数から次のテーブル関数にデータを渡すためのコンジットとして機能します。 私が取り組んでいるDB2プラットフォーム/バージョンでは、9.1 Postgresマニュアルをざっと見てみると、同じことが当てはまるようです。テーブル関数呼び出しへの入力として、列値の1行のみを渡すことができます。あなたが発見したように。 ただし、テーブル関数呼び出しはクエリの結果セット処理の途中で発生するため、データベースエンジンの配管ではデータが渡されますが、結果セット全体を各テーブル関数呼び出しに渡すのと同じ効果が得られます。各テーブル関数に対して一度に1行のみ。
テーブル関数は、1行の入力列を受け入れ、関数を呼び出した呼び出しクエリ(つまり、select)に単一の結果セットを返します。 テーブル関数から返された結果セットの列は、呼び出し元のクエリの結果セットの一部になるため、次のテーブル関数への入力として使用できます。 、通常は後続の結合として、同じクエリで後で参照されます。最初のテーブル関数の結果列は、入力として(一度に1行ずつ)2番目のテーブル関数に送られます。2番目のテーブル関数は、その結果セット列を呼び出し元のクエリの結果セットに返します。 1番目と2番目のテーブル関数の結果セット列の両方が呼び出しクエリの結果セットの一部になり、3番目のテーブル関数への入力(一度に1行)として使用できるようになりました。 各テーブル関数呼び出しは、返す列を介して呼び出しクエリの結果セットを拡張します。 これは、結果セットの幅の制限に達し始めるまで続く可能性があります。これは、データベースエンジンごとに異なる可能性があります。
この例を検討してください(DB2で作業しているため、Postgresの構文要件または機能と一致しない場合があります)。これは、私がテーブル関数を使用する多くのデザインパターンの1つであり、非常に例示的であると私が思うより単純なものの1つであり、もし テーブル関数は主流で多用されていました(私の知る限りではありませんが、注目に値するものだと思います)。
この例では、使用されているテーブル関数は、VALIDATE_TODAYS_ORDER_BATCH、POST_TODAYS_ORDER_BATCH、およびDATA_WAREHOUSE_TODAYS_ORDER_BATCHです。私が取り組んでいるDB2バージョンでは、テーブル関数を「TABLE(place table function call and parameters here)」でラップしていますが、Postgresのマニュアルをざっと見てみると、「TABLE()」ラッパーが省略されているようです。
create table TODAYS_ORDER_PROCESSING_EXCEPTIONS as (
select TODAYS_ORDER_BATCH.*
,VALIDATION_RESULT.ROW_VALID
,POST_RESULT.ROW_POSTED
,WAREHOUSE_RESULT.ROW_WAREHOUSED
from TODAYS_ORDER_BATCH
cross join VALIDATE_TODAYS_ORDER_BATCH ( ORDER_NUMBER, [either pass the remainder of the order columns or fetch them in the function] )
as VALIDATION_RESULT ( ROW_VALID ) --example: 1/0 true/false Boolean returned
left join POST_TODAYS_ORDER_BATCH ( ORDER_NUMBER, [either pass the remainder of the order columns or fetch them in the function] )
as POST_RESULT ( ROW_POSTED ) --example: 1/0 true/false Boolean returned
on ROW_VALIDATED = '1'
left join DATA_WAREHOUSE_TODAYS_ORDER_BATCH ( ORDER_NUMBER, [either pass the remainder of the order columns or fetch them in the function] )
as WAREHOUSE_RESULT ( ROW_WAREHOUSED ) --example: 1/0 true/false Boolean returned
on ROW_POSTED = '1'
where coalesce( ROW_VALID, '0' ) = '0' --Capture only exceptions and unprocessed work.
or coalesce( ROW_POSTED, '0' ) = '0' --Or, you can flip the logic to capture only successful rows.
or coalesce( ROW_WAREHOUSED, '0' ) = '0'
) with data
- テーブルTODAYS_ORDER_BATCHに1,000,000行が含まれている場合、VALIDATE_TODAYS_ORDER_BATCHは各行に1回ずつ、1,000,000回呼び出されます。
- 900,000行がVALIDATE_TODAYS_ORDER_BATCH内で検証に合格した場合、POST_TODAYS_ORDER_BATCHは900,000回呼び出されます。
- 850,000行のみが正常に投稿された場合、VALIDATE_TODAYS_ORDER_BATCHにはいくつかのループホールが閉じられたLOLが必要であり、DATA_WAREHOUSE_TODAYS_ORDER_BATCHは850,000回呼び出されます。
- 850,000行がデータウェアハウスに正常に取り込まれた場合(つまり、追加の例外が生成されなかった場合)、テーブルTODAYS_ORDER_PROCESSING_EXCEPTIONSには1,000,000〜850,000=150,000の例外行が入力されます。
この例のテーブル関数呼び出しは単一の列のみを返しますが、多くの列を返す可能性があります。たとえば、注文行を検証するテーブル関数は、注文が検証に失敗した理由を返す可能性があります。
この設計では、HLLリクエスターがデータベースにバッチ全体を1つの要求で処理するように要求しているため、HLLとデータベース間のチャタリングは事実上すべて排除されます。これにより、データベースへの数百万のSQL要求が削減され、数百万のHLLプロシージャまたはメソッド呼び出しが大幅に削除され、その結果、ランタイムが大幅に改善されます。対照的に、一度に1つの行を処理することが多いレガシーコードは、通常、TODAYS_ORDER_BATCHの各行に1つずつ、1,000,000のフェッチSQLリクエストに加えて、検証目的で少なくとも1,000,000のHLLおよび/またはSQLリクエストに加えて、少なくとも1,000,000のHLLと/または投稿目的のSQLリクエスト、およびデータウェアハウスに注文を送信するための1,000,000HLLおよび/またはSQLリクエスト。確かに、このテーブル関数の設計を使用すると、テーブル関数内でSQL要求がデータベースに送信されますが、データベースがそれ自体に要求を行うと(つまり、テーブル関数内から)、SQL要求ははるかに高速に処理されます(特にHLLリクエスターがリモートシステムから単一行の処理を実行しているレガシーシナリオで、WANを介した最悪の場合-OMGはそれを実行しないでください)。
テーブル関数を使用して「結果セットをフェッチ」し、その結果セットを他のテーブルに結合すると、パフォーマンスの問題が発生しやすくなります。その場合、SQLオプティマイザーは、テーブル関数から返される行のセットを予測できないため、後続のテーブルへの結合を最適化できません。そのため、結果セットの行数が非常に少なく、パフォーマンスの問題が発生しないこと、または後続のテーブルに結合する必要がないことがわかっている場合を除いて、結果セットのフェッチにこれらを使用することはめったにありません。
私の意見では、テーブル関数が十分に活用されていない理由の1つは、結果セットをフェッチするためのツールとしてのみ認識されることが多く、パフォーマンスが低いことが多いため、使用する「貧弱な」ツールとして取り消されるためです。
テーブル関数は、より多くの機能をサーバーにプッシュしたり、データベースサーバーとリモートシステム上のプログラム間のチャタリングのほとんどを排除したり、データベースサーバーと同じサーバー上の外部プログラム間のチャタリングを排除したりするのに非常に役立ちます。同じサーバー上のプログラム間のチャタリングでさえ、多くの人が認識しているよりも多くのオーバーヘッドを運び、その多くは不要です。テーブル関数の力の核心は、結果セット処理内でアクションを実行するためにそれらを使用することにあります。
上記のパターンに基づいてテーブル関数を使用するためのより高度なデザインパターンがあり、結果セットの処理をさらに最大化できますが、この投稿はほとんどの人がすでに吸収しているものです。