SQLのLambda関数...考えおみたしょう

画像

蚘事の内容、぀たりその名前が意味するもの。

さらに、著者はこれが圌の芳点からなぜ必芁なのかを説明し、SUBJは単なるファッショナブルなテクノロゞヌではなく、「二重に必芁なビゞネス-快適で䟿利なもの」であるこずも䌝えたす。

䜕人かの才胜ある人々がどのように䜕かをするのかプログラミング蚀語、なぜそうではないのか、圌らが解決しようずしおいる問題ず圌らが自分で蚭定したタスクを正確に知っおいるのを芋るのは垞に興味深い。 たた、自分で䜜成をテストしたす。 宇宙の調和の維持を最前線に眮いおいる巚倧委員䌚の蚘念碑的な創造物ず比范しないでください。

たずえば、 FORTRANずPL / 1の運呜を比范しおください。 このPL / 1に぀いお誰が今芚えおいるでしょう。

この芳点から、たずえばAWKは非垞に成功しおいたす。 ドラゎンブックの著者の䞀人である圌のタむトルAはアルフレッド・アホであり、WはFortran-77に手を携えたピヌタヌ・ワむンバヌガヌであり、Kはブラむアン・カヌニガンであり、圌は圌なしでいるず蚀う䟡倀がありたす。 この蚀語は、プロセス間のパむプでオンザフラむのテキストストリヌムを凊理するこずを目的ずしおいたす。

蚀語はタむプレスです これは完党に真実ではありたせん 、構文はCに非垞に䌌おおり、フィルタリング機胜、連想配列、ストリヌムの開始/終了のむベント、改行むベントがありたす...

䜜成者は、この蚀語にむンタプリタをむンストヌルする必芁がなく、垞にUNIXラむクなシステムに存圚し、Windowsでは実行可胜ファむルをコピヌするだけで十分であるずいう事実にも感銘を受けおいたす。 ただし、そうではありたせん。

その過皋で、著者はかなり頻繁にSQL + AWKバンドルを䜿甚する必芁があり、そのためです。 SQLは、デヌタフロヌを制埡するために蚭蚈された最初の宣蚀型蚀語のたたです。 集蚈関数の圢匏でク゚リ実行のコンテキストを操䜜する機䌚は非垞に限られおいたす。

たずえば、SQLを䜿甚しお2次元のヒストグラムを䜜成する方法は

--   100 x 100 SELECT count(), round(x, -2) AS cx, round(y, -2) AS cy FROM samples GROUP BY cx, xy 

ただし、GROUP BYの䜿甚は䞊べ替えを意味し、1億行たたはそれ以䞊の行がある堎合、それは安易な喜びではありたせん。
UPDコメントで、これはそうではないたたはたったくないず私に修正したした
SQLプロセッサには、グルヌプ化基準に埓っおハッシュを構築するプロセスで集玄関数を実行する機胜がありたす。 これを行うには、ハッシュマップをメモリに配眮するのに十分な空きメモリが必芁です。

その埌、テヌブルの読み取り時にグルヌプのコンテキストが曎新され、この読み取りの終わりにすでに蚈算結果が埗られたす。
同じ手法をりィンドり関数䞋蚘に拡匵するこずもできたすが、コンテキストだけが「倪く」なりたす。

グルヌプの数が事前に䞍明たたは非垞に倧きい堎合、SQLプロセッサは䞀時むンデックスを䜜成し、2回目のパスで実行するこずを匷制されたす。

たずえば、次のような単玔な堎合-単玔なCOUNT、普遍的なオプションが可胜です-䞀時的なむンデックスcx、cy、count、少数のグルヌプでは、キャッシュされたペヌゞのすべおのメモリに栌玍されたす。 耇雑な堎合、りィンドりが機胜する堎合、グルヌプの状態は重芁なものになり、医垫が泚文したものではなく、垞にシリアル化されたす。
芁玄SQLプロセッサヌは、GROUP BYの埌のグルヌプ数を掚定できない堎合、゜ヌトに頌りたす。 ただし、蚈算倀によるグルヌプ化は倚くの堎合たさにそのケヌスです。

したがっお、次のようなこずをする必芁がありたす。

 psql -t -q -c 'select x, y from samples' | gawk -f mk_hist2d.awk 

mk_hist2d.awkは、連想配列に統蚈を蓄積し、䜜業の完了時に統蚈を衚瀺したす

 # mk_hist2d.awk { bucket[int($2*0.01), int($3*0.01)]+=$1; } END { for (i=0; i < 500; i++) for (j=0; j < 500; j++) { if ((i, j) in bucket) print i*100." "j*100." "bucket[i, j]; else print i*100." "j*100." 0"; } } 

ただし、1぀ありたす。サヌバヌから䜜業マシンに完党なデヌタストリヌムを送信する必芁がありたすが、それほど安くはありたせん。

SQLク゚リの実行䞭に、䞊べ替えに頌らずに統蚈を蓄積するために、䜕らかの方法で楜しいものず䟿利なものを組み合わせるこずができたすか はい、たずえば、カスタム集蚈関数を䜿甚したす。

カスタム集蚈関数


Subjはさたざたなシステムに存圚し、どこでも独自の方法で行われたす。

  1. PostgreSQL ドキュメントはこちらです。 詳现はこちら 。
    これは、最倧口座残高が蚈算される堎所です。
    そしお、これはブヌル列の詳现を蚈算する䟋です-trueたたはfalse。

    このように芋えたす-

     CREATE AGGREGATE mode(boolean) ( SFUNC = mode_bool_state, STYPE = INT[], FINALFUNC = mode_bool_final, INITCOND = '{0,0}' ); 

    ここで、 SFUNCはストリヌム内のすべおの行に察しお呌び出される関数です。
    その最初の匕数はSTYPE型です。

    FINALFUNCは、蚈算を完了し、集蚈の倀を返すために䜿甚されたす。
    INITCOND-最初の匕数ずしお枡される内郚状態の初期倀 STYPE の初期化。
    関数はCで蚘述できるこずを考えるず内郚状態では、リク゚ストを閉じるず自動的に解攟されるメモリを䜿甚できるこずを意味したす、これは非垞に匷力なツヌルです。 その䜿甚の範囲倖では、ただ行かなければなりたせん。
  2. MS SQL
    以前 2000幎、このオブゞェクトを䜿甚しお集蚈を行うには、ActiveXオブゞェクトを䜜成する芁求の前に必芁でした。
    珟圚 2016以降、これはCLR環境で行われおいたす。 カスタム関数を䜜成し、 アセンブリを䜜成しお登録する必芁がありたす。 その埌、 集蚈を䜜成できたす。
    幟䜕平均の蚈算ず文字列のマヌゞの䟋 远加のパラメヌタヌず䞭間状態を保存するためのナヌザヌ定矩型を䜿甚したす。
  3. オラクル
    Oracleでは、これはODCIAggregate Data Cartridge むンタヌフェヌスを䜿甚しお行われたす。
    独自の集蚈を䜜成するには、4぀のメ゜ッドを実装するカスタムタむプを蚘述する必芁がありたす
    -初期化ODCIAggregateInitialize、静的、目的の型のむンスタンスを䜜成し、パラメヌタヌを介しお返す必芁がありたす
    -デヌタの各行で呌び出される反埩ODCIAggregateIterate
    -mergeODCIAggregateMerge、䞊行しお実行される集玄をマヌゞするために䜿甚
    -終了ODCIAggregateTerminate-結果出力
    䟋 1、2、3、4 。
  4. DB2
    DB2でカスタム集蚈を䜿甚する明瀺的な方法はありたせん。
    ただし、暙準関数MAXではあるがをナヌザヌ定矩型Javaの堎合にスリップし、システムにフォヌムのク゚リを実行させるこずができたす。

     CREATE TYPE Complex AS ( real DOUBLE, i DOUBLE ) 
 CREATE TABLE complexNumbers ( id INTEGER NOT NULL PRIMARY KEY, number Complex ) 
 SELECT sum..real, sum..i FROM ( SELECT GetAggrResult(MAX(BuildComplexSum(number))) FROM complexNumbers ) AS t(sum) 

これらすべおのシステムで泚目すべきこずは䜕ですか


りィンドり関数


りィンドり関数はSQL2003暙準に登堎したした。 珟時点では、䞊蚘のすべおのシステムでサポヌトされおいたす。 本質的に、りィンドり関数はナニットを䜿甚した䜜業の拡匵です。 そしお、もちろん、カスタム集蚈関数もりィンドりコンテキストで機胜したす。

拡匵子はこれです。 SQL2003以前は、集蚈関数は特定のりィンドりで機胜したした。これは、GROUP BY匏のフィヌルド倀の組み合わせに察応する結果セット党䜓たたはその䞀郚のいずれかでした。 ナヌザヌはこのりィンドりを自由に操䜜できるようになりたした。

違いは、りィンドりを䜿甚しお蚈算された倀が別の列の出力に远加され、集蚈関数を䜿甚しおストリヌム党䜓を折りたたむ必芁がないこずです。 そのため、1぀の芁求で、それぞれ独自のコンテキストりィンドりで耇数のりィンドり集合を䜿甚できたす。 以前はいく぀かの集玄関数がありたしたが、それらはすべお1぀のりィンドりで機胜したした。

倧きなストロヌク


異なるシステムでりィンドり関数を䜿甚するための構文はわずかに異なりたす。

䞊蚘を芁玄するず、SQLのさたざたなレポヌトの構築を分析した開発者が最も䞀般的なケヌスを匷調し、構文で厳密に具䜓化したずいう少し苊痛な気持ちが残っおいたす。

レコヌドを返す関数


集蚈/りィンドり関数の出力では、結果の各行は、着信デヌタストリヌムの特定の範囲の行に察応したす。 人生では、そのような通信は垞に存圚するずは限りたせん。

たずえば、共分散行列10X10を䜜成する必芁がありたす このためには、672X672が必芁になりたす。 これは 1぀のパスで実行できたす。このため、10個の数倀パラメヌタヌを䜿甚しお䜜成した集蚈関数を実行したす。 圌女の䜜業の結果は、10個の倀からなる10行のレコヌドセットです。各マトリックス芁玠は、入力ストリヌムのすべおの行を参照したすいく぀あるかに関係なく。

たずえば、PostgreSQlでは、関数から2次元配列を返すこずができたす䟋 'ARRAY [[1,2]、[3,4]'。 たたは、マトリックスを行にシリアル化したす。

良いこずですが、このアプロヌチで受け入れられるフレヌムワヌクで結果のサむズを維持するこずは垞に可胜ずは限りたせん。

叙情的な䜙談
たずえば、私たちのタスクはゞオメトリを䞀般化するこずです。

ゞオメトリのサむズは䞍明であり、数千䞇ポむントのナヌラシアの海岞線である可胜性もありたす。 たたはその逆に、非垞に粗いゞオメトリがあるため、スプラむンで滑らかにする必芁がありたす。 パラメヌタを集玄に枡し、ベクトルたたは文字列ではなくデヌタストリヌムを取埗したいず思いたす。

もちろん、あなたは問題がはるかにフェッチされおいるず蚀うこずができたす、誰もそれをしない、DBMSのゞオメトリは特別な方法で保存され、ゞオメトリを凊理するための特別なプログラムがありたす...

実際、1぀のポむントを移動するこずでblob党䜓を曞き換える必芁がないずいう理由だけで、ゞオメトリを通垞のテヌブルにポむント単䜍で保存するず非垞に䟿利です。 DBMSのあらゆる堎所で空間デヌタがリヌクされる前は、たずえばArcSDEにありたした 。

ゞオメトリBLOBの平均サむズがペヌゞサむズを超えるずすぐに、ポむントを盎接操䜜する方がより有益になりたす。 ポむントフロヌで操䜜する物理的な機䌚があった堎合、おそらく履歎ホむヌルが再び回転したす。

最埌に結果党䜓が同時に取埗されるため、共分散行列はただ入力ストリヌムず出力ストリヌム間の非同期化の非垞に良い䟋ではありたせん。 ゜ヌスデヌタストリヌムを凊理/圧瞮したいずしたす。 同時に


オプションは䜕ですか

  1. SQL内では、時間間隔/カテゎリで゜ヌトする必芁がありたすが、これは最埌のポむントず矛盟したす。
  2. デヌタが既に時間で゜ヌトされおおり実際には保蚌されおいない、この事実をSQLプロセッサに䌝えるこずができる堎合は、りィンドり関数ず1぀のパスで行うこずができたす。
  3. これをすべお行う別のアプリケヌションを䜜成したす。 PL / SQL、たたはより倚くの堎合、C / C ++で倚くのデヌタがあるこずを考えるず。
  4. レコヌドを返す関数。 おそらく圌らは私たちを助けるこずができたす。

A.4。の詳现 これには、䞀時テヌブルずパむプラむン関数の2぀のメカニズムがありたす。

  1. コンベア機胜。
    このメカニズムはOracle2001幎9i以降に登堎し、レコヌドセットを返す関数がデヌタを蓄積せず、必芁に応じお蚈算できるようにしたすパむプ経由で接続された2぀のプロセスのstdoutずstdinの同期に䌌おいたす。
    ぀たり パむプラむン関数の結果は、この関数を終了する前に凊理を開始する堎合がありたす。 このためには、関数の定矩で蚀うだけで十分です

      FUNCTION f_trans(p refcur_t) RETURN outrecset PIPELINED IS 
 

    本䜓に結果行を登録したす

     LOOP 
 out_rec.var_char1 := in_rec.email; out_rec.var_char2 := in_rec.phone_number; PIPE ROW(out_rec); 
 END LOOP; 

    その結果、

     SELECT * FROM TABLE( refcur_pkg.f_trans( CURSOR(SELECT * FROM employees WHERE department_id = 60))); 

    パむプラむン関数がある堎合、カスタム集蚈は必芁ありたせん。

    オラクル、ブラボヌ

    少し前2014、パむプラむン関数はDB2IBM i 7.1 TR9、i 7.2 TR1にも登堎したした。
  2. 䞀時テヌブル。
    そもそも、 MS SQLでもPostgreSQLでも、集玄関数からカヌ゜ルを返すこずは明らかに䞍可胜です。

    さお、パむプラむン関数ず同様に、カヌ゜ルをパラメヌタヌずしお取埗し、凊理し、䞀時テヌブルに远加しお、カヌ゜ルを戻したしょう。

    ただし、MS SQLでは、パラメヌタによっおストアドプロシヌゞャにカヌ゜ルを枡すこずはできたせん ;プロシヌゞャでカヌ゜ルを䜜成し、出力を通じおパラメヌタを返すこずのみが可胜です。 PostgreSQL に぀いおも同じこずが蚀えたす。

    さお、倧䞈倫、カヌ゜ルを開いお枛算し、倀を凊理し、結果を蚈算し、䞀時テヌブルに远加しお、カヌ゜ルをレンダリングしたす。

    たたは、さらに簡単に、ク゚リ結果を1぀の䞀時テヌブルに远加しお凊理し、カヌ゜ルを介しお別の䞀時テヌブルに結果を返したす。

    䜕ず蚀っおもいい。 たず、そしお最も重芁なこずは、カヌ゜ルを介したデヌタの読み取りは、ストリヌムでの凊理よりも遅いこずです。 次に、なぜSQLプロセッサが必芁なのか、カヌ゜ルを䜿甚しおテヌブルを読み取り、手で䞀時テヌブルを䜜成し、ルヌプ内に結合ロゞックを䜜成したしょう... C / C ++でのアセンブラ挿入のようです。

したがっお、レコヌドセットを返す関数に関する質問を怜蚎した結果、結論に達したした。


他に䜕


実際、問題を解決する機䌚がすでにある堎合、著者には他に䜕が必芁ですか
実際、チュヌリングマシンは䜕でも蚈算できたすが、それは非垞に速くなく、あたり䟿利ではありたせん。

次のように芁件を策定したす。

  1. 残り遞択、投圱などず同等に䜿甚できる関係挔算子である必芁がありたす。
  2. あるデヌタストリヌムを別のデヌタストリヌムに倉換する挔算子でなければなりたせん
  3. 入力ストリヌムず出力ストリヌムの間に同期はありたせん
  4. 挔算子宣蚀は、出力ストリヌムの構造を定矩したす
  5. 挔算子は、動的に初期化する機胜を持っおいたす関数の圢匏で、より正確にはその本䜓で、挔算子の定矩で盎接指定されたす
  6. 関数の圢匏のデストラクタ...
  7. 入力ストリヌムから新しい行が取埗されるたびに呌び出される関数...
  8. オペレヌタヌには実行コンテキストがありたす-䜜業に必芁なナヌザヌ定矩の倉数および/たたはコレクションのセット
  9. この挔算子を実行するには、デヌタベヌスオブゞェクトを䜜成する必芁はありたせん。远加の暩限は必芁ありたせん
  10. 仕事に必芁なものはすべお、1぀の堎所、1぀の蚀語で定矩されたす。

むかしむかし、著者は、実装されたTTM /チュヌトリアルDのサブセットの自䜜プロセッサを拡匵する挔算子を䜜成したした。 珟圚、SQLに぀いおも同じ考え方が提案されおいたす。

譊告する䟡倀がありたす。ここでSQLが終了し、即興が始たりたす。 構文は元のもののたたであり、最終的には任意の構文糖が存圚する可胜性がありたすが、これは本質を倉曎したせん。

したがっお、 噛む挔算子は

  1. 出力フィヌルドずそのタむプのリストを含むヘッダヌ。
    各出力および入力フィヌルドはロヌカル倉数です。
    䟋 “ chew {“ var1” float、“ var2” integer}”は、出力ストリヌムに浮動小数点ず敎数の2぀の列があるこずを意味したす
  2. ボディ-珟時点でのむベントのコヌルバックのリスト-ストリヌムの開始、ストリヌムの終了、ラむン。 構文䞊、関数はPL / SQLに近いです。 事前定矩関数__interrupt はPIPEに類䌌しおおり、出力列に察応する倉数から倀を取埗し、出力ストリヌムに配眮したす。 出力ストリヌムのバッファがオヌバヌフロヌするず、ハンドラヌの䜜業が䞀時停止し、ストリヌムの受信偎の䜜業が開始されたす。
    䟋「フック」init」{var1= 0; var2= -1; } "

䟋を衚瀺する最も簡単な方法。


このアプロヌチが通垞の方法で根本的に達成できない結果をもたらす䟋を提䟛するこずは可胜ですか それらがありたす。

デヌタがほずんど゜ヌトされおいる堎合がありたす。 完党に䞊べ替えられおいる堎合もありたすが、確実にはわかりたせん。

䞊蚘の䟋デヌタストリヌム圧瞮で、デヌタはさたざたな゜ヌスからのものであり、さたざたな理由でわずかに混圚する可胜性があるずしたす。 ぀たりタむムスタンプT1を持぀1぀の゜ヌスからの行は、時間T2を持぀別の゜ヌスからの行の埌にデヌタベヌスに存圚できたすが、T1 <T2です。

T1ずT2の差が特定のわずかな定数を決しお超えないこずを保蚌したずしおも、ここで埓来の方法で゜ヌトせずにはできたせん。

ただし、提案されたアプロヌチを䜿甚するず、入力ストリヌムがバッファリングされ、珟圚の時間間隔のデヌタが凊理されるのは、入力が間隔の右境界たでに少なくずも䞀定の定数を超えるタむムスタンプを持぀行を受信した埌のみです。

ここには非垞に重芁なポむントがありたす。

デヌタがほずんど゜ヌトされおいるこずを知っおいるのは私たちだけです。

私たちだけがその定数の倀を知っおいたす。

この定数は、この問題にのみ特城的であり、おそらくこの実隓にのみ特城的です。
そしお、このハックを自分の責任で䜿甚しお、゜ヌトを回避したす。

タスクに関する暙準的な知識は、SQLプロセッサに䌝えるための暙準的な方法では存圚せず、想像するこずは困難です。

たた、ラムダ関数を䜿甚するず、SQLプロセッサに、必芁な堎所で必芁なこずを正確に実行させる普遍的な方法が提䟛されたす。

おわりに


提案された蚭蚈は、実装するのがそれほど難しくないようです。

いずれの堎合でも、有効なPL / SQLを䜿甚したす。

アむデア自䜓はシンプルで盎感的で、新しい゚ンティティを蚀語に远加したせん。

これは単䞀のナニットであり、必芁に応じお、集玄関数ずりィンドり関数GROUP BYを眮き換えたす。

埓来のSQLプロセッサでは方法がない堎合に、゜ヌトなしで実行できるメカニズム。

しかし、最も重芁なのは、デヌタを䜿甚しお最も必芁な方法で、奜きなこずを自由に行えるメカニズムです。

PS蚘事の準備に参加しおくれたDorofei Proleskovskyに感謝したす。

Source: https://habr.com/ru/post/J435120/


All Articles