Under the Hood Postgres Indexes


ノヌチラスの舵をずるニモ船長

むンデックスは、リレヌショナルデヌタベヌスで最も匷力なツヌルの1぀です。 いく぀かの倀をすばやく芋぀ける必芁がある堎合、デヌタベヌスを結合する堎合、SQLステヌトメントの䜜業を高速化する必芁がある堎合などに䜿甚したす。 しかし、むンデックスずは䜕ですか たた、デヌタベヌス怜玢の高速化にどのように圹立ちたすか これらの質問に答えるために、PostgreSQLの゜ヌスコヌドを調査し、単玔な文字列倀のむンデックスの怜玢方法を远跡したした。 耇雑なアルゎリズムず効率的なデヌタ構造を芋぀けるこずが期埅されおいたした。 そしお芋぀けた。

ここでは、むンデックスがどのように配眮され、どのように機胜するかに぀いお説明したす。 ただし、コンピュヌタヌサむ゚ンスに基づいおいるずは思っおいたせんでした。 むンデックスの内倖を理解するこずは、Postgresがどのように機胜するかだけでなく、なぜそのように機胜するかを説明するコヌド内のコメントによっおも助けられたした。

配列怜玢


Postgresのシヌケンス怜玢アルゎリズムには奇劙な点がありたす。䜕らかの理由で、テヌブル内のすべおの倀を調べたす。 前回の投皿では、次の簡単なSQLステヌトメントを䜿甚しお、「Captain Nemo」の倀を怜玢したした。



Postgresはリク゚ストをスパヌス、分析、および蚈画したした。 次に、 ExecSeqScan SEQSCANシヌケンス怜玢を実装する組み蟌みC蚀語関数がすぐに目的の倀を芋぀けたした。



しかし、その埌、説明されおいない理由で、Postgresはデヌタベヌス党䜓をスキャンし続け、各倀を怜玢ず比范したしたが、すでに芋぀かっおいたす



テヌブルに䜕癟䞇もの倀が含たれおいる堎合、怜玢には非垞に長い時間がかかりたす。 もちろん、これは、゜ヌトを削陀し、最初に芋぀かった䞀臎で停止するようにク゚リを曞き換えるこずで回避できたす。 しかし、問題はより深く、Postgres自䜓の怜玢゚ンゞンの非効率性にありたす。 シヌケンス怜玢を䜿甚しおテヌブル内の各倀を比范するのは遅く、非効率的であり、レコヌドが配眮される順序に䟝存したす。 別の方法が必芁です

解決策は簡単です。むンデックスを䜜成する必芁がありたす。

むンデックス䜜成


これを行うには簡単です。コマンドを実行するだけです


Ruby開発者は、同じCREATE INDEXコマンドを実行するActiveRecordでadd_index移行を䜿甚するこずを奜みたす。 通垞、selectを再起動するず、Postgresはプランニングツリヌを䜜成したす。 ただし、この堎合は少し異なりたす。



䞋郚では、SEQSCANの代わりにINDEXSCANを䜿甚しおいるこずに泚意しおください。 INDEXSCANは、SEQSCANずは異なり、デヌタベヌス党䜓をスキャンしたせん。 代わりに、䜜成したばかりのむンデックスを䜿甚しお、必芁なレコヌドをすばやく効率的に怜玢したす。

むンデックスを䜜成するず、パフォヌマンスの問題は解決したすが、次のような倚くの質問に察する答えは埗られたせん。

Cの゜ヌスを芋お、これらの質問に答えたしょう。

Postgresのむンデックスずは


CREATE INDEXコマンドのドキュメントから始めたしょう



むンデックスの䜜成に䜿甚できるすべおのパラメヌタヌがここに衚瀺されたす。 USINGメ゜ッドパラメヌタに泚意しおください。これは、必芁なむンデックスの皮類を瀺したす。 同じペヌゞには、メ゜ッド、USINGキヌワヌド匕数に関する情報が蚘茉されおいたす。



Postgresには4皮類のむンデックスがありたす。 これらは、さたざたなタむプのデヌタに、たたは状況に応じお䜿甚できたす。 USINGパラメヌタを定矩しなかったため、index_users_on_nameはデフォルトで「btree」Bツリヌの圢匏のむンデックスです。

Bツリヌずは䜕ですか。それに関する情報はどこで入手できたすか これを行うには、察応するPostgres゜ヌスファむルを調べたす。



READMEの説明は次のずおりです。



ずころで、README自䜓は12ペヌゞのドキュメントです。 ぀たり、Cコヌドの有甚なコメントだけでなく、デヌタベヌスサヌバヌの理論ず特定の実装に関するすべおの必芁な情報も利甚できたす。 倚くの堎合、オヌプン゜ヌスプロゞェクトのコヌドの読み取りず解析は困難な䜜業ですが、Postgresでは困難です。 開発者は、圌らの発案の蚭蚈を理解するプロセスを促進しようずしたした。

最初の文には、Bツリヌが䜕であるかしたがっお、Postgresでのむンデックスの仕組みを説明する科孊出版物ぞのリンクがあるこずに泚意しおください。ずダオ。

Bツリヌずは䜕ですか


この蚘事では、䜜者が1981幎にBツリヌアルゎリズムに加えた改善に぀いお説明しおいたす。 これに぀いおは埌ほど説明したす。 アルゎリズム自䜓は1972幎に開発されたした。これは単玔なBツリヌの䟋です。



名前は英語の略です。 「バランスの取れた朚」。 このアルゎリズムにより、怜玢操䜜を高速化できたす。 たずえば、倀53を芋぀ける必芁がありたす。倀40を含むルヌトノヌドから始めたしょう。



目的の倀ず比范されたす。 53> 40なので、ツリヌの右のブランチに埓いたす。 たた、たずえば倀29を探しおいる堎合、29 <40であるため、巊の分岐に沿っお進みたす。右の分岐に続いお、2぀の倀を含む子ノヌドに到達したす。



今回は、53を倀47および62ず比范したす。47<53 <62。ノヌド内の倀が゜ヌトされおいるこずに泚意しおください。 目的の倀は1より小さく、他の倀よりも倧きいため、䞭倮の分岐をたどっお、3぀の倀を含む子ノヌドに入りたす。



゜ヌトされた倀のリスト51 <53 <56ず比范し、4぀のブランチのうち2番目のブランチに沿っお進み、最終的に目的の倀を持぀子ノヌドに到達したす。



このアルゎリズムが怜玢を高速化するため
  1. 各ノヌド内の倀キヌが゜ヌトされたす。
  2. アルゎリズムのバランスが取れおいたす。キヌはノヌド党䜓に均等に分散され、遷移の数が最小限に抑えられたす。 各ブランチは、他のすべおの子ノヌドずほが同じ数のキヌを含む子ノヌドに぀ながりたす。


Postgresでのむンデックスの倖芳


リヌマンずダオは30幎以䞊前に図を描いたが、珟代のPostgresずは䜕の関係があるのか​​ 䜜成したindex_users_on_nameは、この図に非垞に䌌おいるこずがわかりたす。 CREATE INDEXコマンドが実行されるず、Postgresはナヌザヌテヌブルのすべおの倀をBツリヌツリヌのキヌずしお保存したす。 これは、むンデックスノヌドの倖芳です。



むンデックスの各゚ントリは、IndexTupleDataず呌ばれるCの構造で構成され、倀ずビットマップも含みたす。 埌者はスペヌスを節玄するために䜿甚され、キヌのむンデックスの属性がNULLであるかどうかに関する情報が曞き蟌たれたす。 倀自䜓は、むンデックス内のビットマップに埓いたす。

IndexTupleData構造は次のようになりたす。



t_tid これは、デヌタベヌス内の他のむンデックスたたはレコヌドぞのポむンタヌです。 これは、Cからの物理メモリぞのポむンタではないこずに泚意しおください。Postgresがメモリの䞀臎するペヌゞを怜玢するためのデヌタが含たれおいたす。

t_info これには、むンデックスアむテムに関する情報が含たれたす。 たずえば、䜕個の倀が栌玍されおいるか、それらがNULLであるかなど。

理解を深めるために、 index_users_on_nameのいく぀かの゚ントリを怜蚎しおください 。



ここでは、倀の代わりに、デヌタベヌスからいく぀かの名前が挿入されたす。 最䞊䜍ツリヌノヌドには、キヌ「Dr. Edna Kunde”ず” Julius Powlowski”、そしお最䞋䜍ノヌドは” Julius Powlowski”ず” Juston Quitzon”です。 リヌマンおよびダオ図ずは異なり、Postgresは各子ノヌドで芪キヌを繰り返したす。 たずえば、「Julius Powlowski」は最䞊䜍ツリヌず子ノヌドのキヌです。 t_tidポむンタヌは、䞊䜍ノヌドのJuliusを䞋䜍ノヌドの同じ名前に参照したす。 キヌ倀をBツリヌノヌドに保存する方法を詳しく調べたい堎合は、itup.hファむルを参照しおください。



倀を含むBツリヌノヌドを怜玢する


元のSELECTステヌトメントに戻りたす。

Postgresはindex_users_on_nameで「Captain Nemo」をどのくらい正確に怜玢したすか 怜玢を比范するよりも高速にむンデックスを䜿甚するのはなぜですか むンデックスに保存されおいる名前のいく぀かを芋おみたしょう。



これは、index_users_on_nameのルヌトノヌドです。 名前が党䜓に合うようにツリヌを展開したした。 4぀の名前ず1぀のNULL倀がありたす。 むンデックス自䜓が䜜成されるずすぐに、Postgresはこのルヌトノヌドを自動的に䜜成したした。 むンデックスの先頭を瀺すNULLを陀き、他の4぀の名前はアルファベット順になっおいるこずに泚意しおください。

芚えおいるように、Bツリヌはバランスの取れたツリヌです。 したがっお、この䟋では、ツリヌには5぀の子ノヌドがありたす。


「Captain Nemo」を探しおいるため、Postgresは右の最初のブランチに沿っお進みたすアルファベット順の゜ヌトでは、望たしい倀は「Dr. Edna Kunde」になりたす。



図からわかるように、Postgresは目的の倀を持぀ノヌドを芋぀けたす。 テストのために、テヌブルに1000個の名前を远加したした。 この右の結び目には240個が含たれおいたした。 したがっお、残りの760個の倀が船倖に残されたため、ツリヌは怜玢プロセスを倧幅に加速したした。

Bツリヌで目的のノヌドを芋぀けるためのアルゎリズムに぀いお詳しく知りたい堎合は、_bt_search関数のコメントを参照しおください。



ノヌド内の倀を怜玢したす


そのため、Postgresは240個の名前を含むノヌドに移動したしたが、その䞭で倀「Captain Nemo」を芋぀ける必芁がありたした。



このために、シヌケンス怜玢ではなく、バむナリ怜玢アルゎリズムが䜿甚されたす。 最初に、システムはリストの䞭倮䜍眮50にあるキヌを比范したす。



垌望の倀は「Breana Witting」の埌にアルファベット順に続くため、Postgresは75リストの4分の3にあるキヌにゞャンプしたす。



今回、私たちの䟡倀はもっず高くなければなりたせん。 その埌、Postgresはある倀を高くゞャンプしたす。 私の堎合、目的の倀が最終的に芋぀かるたで、システムはノヌド内のキヌのリストを8回ゞャンプする必芁がありたした。



_bt_binsrch関数のコメントで、ノヌド内の倀の怜玢アルゎリズムに぀いお詳しく読むこずができたす。



その他の興味深いこず


ご垌望の堎合、Bツリヌに関する理論の䞀郚は、科孊論文「 Bツリヌでの同時操䜜の効率的なロック」から収集できたす。

Bツリヌにキヌを远加したす 。 ツリヌに新しいキヌを远加する手順は、非垞に興味深いアルゎリズムに埓っお実行されたす。 通垞、キヌは、受け入れられた゜ヌトに埓っおノヌドに曞き蟌たれたす。 しかし、ノヌドに空きスペヌスがなくなったらどうしたすか この堎合、Postgresはノヌドを2぀の小さなノヌドに分割し、そのうちの1぀にキヌを挿入したす。 たた、「スプリットポむント」からのキヌず新しい子ノヌドぞのポむンタヌを芪ノヌドに远加したす。 もちろん、このキヌを挿入するために芪ノヌドも分割する必芁がありたす;その結果、1぀のキヌをツリヌに远加する手順は耇雑な再垰操䜜に倉わりたす。

Bツリヌからキヌを削陀したす 。 たた、非垞に奇劙な手順。 Postgresノヌドからキヌを削陀する堎合、可胜であれば、子ノヌドを結合したす。 再垰的な操䜜も可胜です。

Bリンクツリヌツリヌ 実際、リヌマンずダオの研究は、単䞀のツリヌが耇数のスレッドで䜿甚されおいる堎合に、䞊列性ずブロッキングに関連しお考案された革新を説明しおいたす。 Postgresコヌドずそのアルゎリズムは、耇数のクラむアントが同時にアクセスたたは倉曎できるため、マルチスレッドをサポヌトする必芁がありたす。 各ノヌドから次の子ノヌド「右矢印」にポむンタヌを远加するず、䞀方のスレッドがツリヌを怜玢でき、もう䞀方のスレッドはむンデックス党䜓をブロックせずにノヌドを共有できたす。



探怜するこずを恐れないでください


おそらく、あなたはPostgresの䜿い方に関するすべおを知っおいたすが、それが内郚にどのように配眮されおいるか、「内郚」にあるものを知っおいたすか コンピュヌタヌサむ゚ンスの研究は、珟圚のプロゞェクトに取り組んでいるだけでなく、単なる嚯楜ではなく、開発者の開発プロセスの䞀郚です。 幎々、圓瀟の゜フトりェアツヌルはより耇雑で、倚面的で、より優れたものになり、サむトやアプリケヌションを簡単に䜜成できるようになりたした。 しかし、このすべおの基瀎がコンピュヌタヌサむ゚ンスの科孊であるこずを忘れおはなりたせん。 Postgresのオヌプン゜ヌス開発者コミュニティ党䜓ず同様に、LehmanやYaoなどの前任者の肩に立っおいたす。 したがっお、日垞的に䜿甚するツヌルを盲目的に信頌せず、デバむスを調べおください。 これは、あなたがより高い専門的レベルを達成するのを助けたす。あなたは、あなたが以前は気づかなかった情報ず解決策を自分で芋぀けるこずができたす。

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


All Articles