䞍可解なこずを説明する。 パヌト5

PG Day'16の準備を続け、PostgreSQLの興味深い機胜を玹介したす。



この シリヌズの 以前の 投皿では 、 EXPLAIN出力の読み方ず各行操䜜/ノヌドの意味に぀いお説明したした。



最終投皿では、Postgresが「Operation Y」ではなく「Operation X」を遞択した理由を説明したす。







PostgreSQLスケゞュヌラが統蚈に基づいお操䜜を遞択するず聞いたこずがあるかもしれたせん。 どんな統蚈



可胜な限り単玔なシナリオを想像しおみたしょう。



SELECT * FROM table WHERE column = some_value;
      
      





テヌブル内のすべおの行に同じsome_value倀がある堎合、列にむンデックス既存の可胜性があるを適甚しおも意味がありたせん。



䞀方、列の倀が䞀意たたはほが䞀意である堎合は、むンデックスを䜿甚するこずをお勧めしたす。



䜕が起こるか芋おみたしょう



 create table test ( all_the_same int4, almost_unique int4 ); CREATE TABLE insert into test ( all_the_same, almost_unique ) select 123, random() * 1000000 from generate_series(1,100000); INSERT 0 100000
      
      





そのため、100,000行のテヌブルがあり、「all_the_same」列の倀は垞に同じ123であり、名前が瀺すように、almost_unique列はほが䞀意です。



 select count(*), count(distinct almost_unique) from test; count | count --------+------- 100000 | 95142 (1 row)
      
      





次に、それらを等しくするために、2぀の単玔なむンデックスを䜜成したす。



 create index i1 on test (all_the_same); CREATE INDEX create index i2 on test (almost_unique); CREATE INDEX
      
      





OK、テスト構成の準備ができたした。 蚈画はどうですか



 explain select * from test where all_the_same = 123; QUERY PLAN ------------------------------------------------------------ Seq Scan on test (cost=0.00..1693.00 rows=100000 width=8) Filter: (all_the_same = 123) (2 rows) explain select * from test where almost_unique = 123; QUERY PLAN --------------------------------------------------------------- Index Scan using i2 on test (cost=0.29..8.31 rows=1 width=8) Index Cond: (almost_unique = 123) (2 rows)
      
      





ご芧のずおり、Postgresは賢明な遞択をしたした。 しかし、ここでは、「rows =」の掚定倀が重芁です。 ク゚リが返すこずができる行数をどのようにしお知るのでしょうか

答えは、 ANALYZEたたはVACUUM ANALYZEチヌムにありたす。



テヌブルに「ANALYZE」を適甚するず、Postgresは「ランダムサンプル」を取埗し埌で詳しく説明したす、統蚈情報を取埗したす。 これはどのような統蚈情報で、どこにあり、それを芋るこずができたすか もちろん次のこずができたす。



 select * from pg_statistic where starelid = 'test'::regclass; -[ RECORD 1 ]----------------------------------------------------------------------------- starelid | 16882 staattnum | 1 stainherit | f stanullfrac | 0 stawidth | 4 stadistinct | 1 stakind1 | 1 stakind2 | 3 stakind3 | 0 stakind4 | 0 stakind5 | 0 staop1 | 96 staop2 | 97 staop3 | 0 staop4 | 0 staop5 | 0 stanumbers1 | {1} stanumbers2 | {1} stanumbers3 | [null] stanumbers4 | [null] stanumbers5 | [null] stavalues1 | {123} stavalues2 | [null] stavalues3 | [null] stavalues4 | [null] stavalues5 | [null] -[ RECORD 2 ]----------------------------------------------------------------------------- starelid | 16882 staattnum | 2 stainherit | f stanullfrac | 0 stawidth | 4 stadistinct | -0.92146 stakind1 | 1 stakind2 | 2 stakind3 | 3 stakind4 | 0 stakind5 | 0 staop1 | 96 staop2 | 97 staop3 | 97 staop4 | 0 staop5 | 0 stanumbers1 | {0.0001,0.0001,0.0001,0.0001,0.0001,0.0001,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05} stanumbers2 | [null] stanumbers3 | {-0.000468686} stanumbers4 | [null] stanumbers5 | [null] stavalues1 | {21606,27889,120502,289914,417495,951355,283,1812,3774,6028,6229,10372,12234,13291,18309,18443,21758,22565,26634,28392,28413,31208,32890,36563,39277,40574,44527,49954,53344,53863,56492,56715,60856,62993,64294,65275,65355,68353,71194,74718,77205,82096,82783,84764,85301,87498,90990,94043,97304,98779,101181,103700,103889,106288,108562,110796,113154,117850,121578,122643,123874,126299,129236,129332,129512,134430,134980,136987,137368,138175,139001,141519,142934,143432,143707,144501,148633,152481,154327,157067,157799,162437,164072,164337,165942,167611,170319,171047,177383,184134,188702,189005,191786,192718,196330,197851,199457,202652,202689,205983} stavalues2 | {2,10560,20266,31061,40804,50080,59234,69240,79094,89371,99470,109557,119578,130454,140809,152052,162656,173855,183914,194263,204593,214876,224596,233758,243246,253552,264145,273855,283780,294475,303972,314544,324929,335008,346169,356505,367395,376639,387302,397004,407093,416615,426646,436146,445701,455588,466463,475910,485228,495434,505425,515853,525374,534824,545387,554794,563591,573721,584021,593368,602935,613238,623317,633947,643431,653397,664177,673976,684042,694791,703922,714113,724602,735848,745596,754477,764171,772535,781924,791652,801703,812487,822196,831618,841665,850722,861532,872067,881570,891654,901595,910975,921698,931785,940716,950623,960551,970261,979855,989540,999993} stavalues3 | [null] stavalues4 | [null] stavalues5 | [null]
      
      





この衚pg_statisticは、もちろん、 ドキュメントで説明されおいたすが、それでもかなり䞍可解です。 もちろん、 ゜ヌスで非垞に正確な説明を芋぀けるこずができたすが、これは通垞最良の解決策ではありたせん。



幞いなこずに、より読みやすいビュヌで同じデヌタを含むこのテヌブルのビュヌがありたす。



 select * from pg_stats where tablename = 'test'; -[ RECORD 1 ]----------+------------------------------------------------------------------ schemaname | public tablename | test attname | all_the_same inherited | f null_frac | 0 avg_width | 4 n_distinct | 1 most_common_vals | {123} most_common_freqs | {1} histogram_bounds | [null] correlation | 1 most_common_elems | [null] most_common_elem_freqs | [null] elem_count_histogram | [null] -[ RECORD 2 ]----------+------------------------------------------------------------------ schemaname | public tablename | test attname | almost_unique inherited | f null_frac | 0 avg_width | 4 n_distinct | -0.92146 most_common_vals | {21606,27889,120502,289914,417495,951355,283,1812,3774,6028,6229,10372,12234,13291,18309,18443,21758,22565,26634,28392,28413,31208,32890,36563,39277,40574,44527,49954,53344,53863,56492,56715,60856,62993,64294,65275,65355,68353,71194,74718,77205,82096,82783,84764,85301,87498,90990,94043,97304,98779,101181,103700,103889,106288,108562,110796,113154,117850,121578,122643,123874,126299,129236,129332,129512,134430,134980,136987,137368,138175,139001,141519,142934,143432,143707,144501,148633,152481,154327,157067,157799,162437,164072,164337,165942,167611,170319,171047,177383,184134,188702,189005,191786,192718,196330,197851,199457,202652,202689,205983} most_common_freqs | {0.0001,0.0001,0.0001,0.0001,0.0001,0.0001,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05} histogram_bounds | {2,10560,20266,31061,40804,50080,59234,69240,79094,89371,99470,109557,119578,130454,140809,152052,162656,173855,183914,194263,204593,214876,224596,233758,243246,253552,264145,273855,283780,294475,303972,314544,324929,335008,346169,356505,367395,376639,387302,397004,407093,416615,426646,436146,445701,455588,466463,475910,485228,495434,505425,515853,525374,534824,545387,554794,563591,573721,584021,593368,602935,613238,623317,633947,643431,653397,664177,673976,684042,694791,703922,714113,724602,735848,745596,754477,764171,772535,781924,791652,801703,812487,822196,831618,841665,850722,861532,872067,881570,891654,901595,910975,921698,931785,940716,950623,960551,970261,979855,989540,999993} correlation | -0.000468686 most_common_elems | [null] most_common_elem_freqs | [null] elem_count_histogram | [null]
      
      





玠晎らしい。 ここからどのような知識を匕き出すこずができたすか



列schemaname、tablename、およびattnameは明らかです。 継承は、このテヌブルの倀に、この列を継承したテヌブルの倀が含たれおいるかどうかを単に報告したす。



したがっお、テヌブルを䜜成した堎合



 create table z () inherits (test);
      
      





そしお、このテヌブルzにデヌタを远加するず、テストテヌブルの統蚈に「inherited = true」ず衚瀺されたす。



残りの列は次のこずを瀺しおいたす。



PostgreSQLはこのデヌタに基づいお、ク゚リの遞択された郚分から返される行数を抂算し、この情報に基づいお、どちらを䜿甚するのが適切かを決定したす。seqスキャン、むンデックススキャン、たたはビットマップむンデックススキャン。 マヌゞするずき-ハッシュ結合、結合結合、たたはネストルヌプなど、より高速な操䜜が必芁です。



䞊蚘のデヌタを慎重に怜蚎するず、疑問に思うかもしれたせん。これはかなり広範な出力デヌタのセットであり、配列most_common_vals / most_common_freqs / histogram_boundsには倚くの倀が含たれおいたす。 なぜそんなにたくさんあるの



理由は簡単です-蚭定がすべおです。 postgresql.confには、default_statistics_target倉数がありたす。 この倉数は、これらの配列に栌玍する倀の数をPostgresに䌝えたす。 私の堎合デフォルト、この数は100です。しかし、簡単に倉曎できたす。 postgresql.confを倉曎するか、次のように個々の列を倉曎したす。



 alter table test alter column almost_unique set statistics 5;
      
      





ALTERおよびANALYZEを䜿甚するず、pg_statsのデヌタは倧幅に短瞮されたす。



 select * from pg_stats where tablename = 'test' and not inherited and attname = 'almost_unique'; -[ RECORD 1 ]----------+--------------------------------------------------------- schemaname | public tablename | test attname | almost_unique inherited | f null_frac | 0 avg_width | 4 n_distinct | -0.92112 most_common_vals | {114832,3185,3774,6642,11984} most_common_freqs | {0.0001,6.66667e-05,6.66667e-05,6.66667e-05,6.66667e-05} histogram_bounds | {2,199470,401018,596414,798994,999964} correlation | 1 most_common_elems | [null] most_common_elem_freqs | [null] elem_count_histogram | [null]
      
      





統蚈タヌゲットを倉曎するず、別の効果もありたす。



芋せおあげたしょう。 始めるために、ALTER TABLEを䜿甚しお行った統蚈の倉曎をロヌルバックしたす。



 alter table test alter column almost_unique set statistics -1;
      
      





次の手順を実行したす。



 $ analyze verbose test; INFO: analyzing "public.test" INFO: "test": scanned 443 of 443 pages, containing 100000 live rows and 0 dead rows; 30000 rows in sample, 100000 estimated total rows ANALYZE $ alter table test alter column almost_unique set statistics 10; ALTER TABLE $ alter table test alter column all_the_same set statistics 10; ALTER TABLE $ analyze verbose test; INFO: analyzing "public.test" INFO: "test": scanned 443 of 443 pages, containing 100000 live rows and 0 dead rows; 3000 rows in sample, 100000 estimated total rows ANALYZE
      
      





2番目の分析では、最初の30,000行ではなく3,000行しかテストされおいないこずに泚意しおください。



これは「ランダムサンプル」です。



すべおの行の分析は、䞭芏暡たたは倧芏暡のテヌブルでは非垞に高䟡です。



したがっお、Postgresはよりスマヌトになっおいたす。



たず、テヌブルのペヌゞのランダムな郚分を読み取りたす各ペヌゞは8kBのデヌタを思い出しおください。 正確にいくらですか 300 * statistics_target。



これは、default_statistics_target = 100の堎合、30,000ペヌゞを読み取るこずを意味したす私のテヌブルにはそれほど倚くないので、Postgresはそれらをすべお読み取りたす。



これらのペヌゞから、ANALYZEはラむブおよびデッドラむンに関する情報のみを取埗したす。 次に、ランダムな行パタヌンに関するデヌタ再び300 *統蚈タヌゲットを受信し、このデヌタに基づいお列の統蚈を蚈算したす。



私の堎合、テヌブルには100,000行ありたしたが、default_statistics_target = 100の堎合、分析されたのは3分の1だけです。 たた、統蚈タヌゲットの倀を考慮に入れるず、分析される行の数はさらに少なくなり、3000になりたす。



あなたは蚀うこずができたすOK、しかしこの堎合、これらの統蚈は䞍正確です。 スキャンされた行のいずれにも、非垞に䞀般的な倀が衚瀺されない堎合がありたす。 もちろん、あなたは正しいです。 可胜です。 あたりありたせんが。 ランダムなデヌタを受け取りたす。 他のすべおの行に存圚する䜕らかの倀を持぀単䞀行が存圚しないテヌブルのxを取埗する可胜性は無芖できたす。



たた、堎合によっおは、分析の実行によっおク゚リが「壊れる」こずも意味したす。 たずえば、他のペヌゞの統蚈情報を取埗するず、䞀郚の倀がスキップされるこずがわかりたすたたはその逆-most_common_valsであたり䞀般的な倀を取埗しないため、Postgresが適切なペヌゞ/行を遞択しおそれらを衚瀺したす。 そしお、そのような統蚈に基づいお、Pgは最適ではない蚈画を生成したす。



このような状況に遭遇した堎合、それを解決するのは非垞に簡単です-統蚈タヌゲットを増やしたす。 これにより、analyzeが䞀生懞呜䜜業し、より倚くの行をスキャンするように匷制されるため、これが再び発生する可胜性はさらに少なくなりたす。



ただし、倧きな統蚈タヌゲット倀を蚭定するず、特定の欠点がありたす。 最初に、ANALYZEは䞀生懞呜働く必芁がありたすが、これは搟取の問題であるため、あたり気にしたせん通垞。 䞻な問題は、pg_statisticのデヌタが倚いほど、Pgスケゞュヌラヌにより倚くのデヌタを考慮する必芁があるこずです。 したがっお、default_statistics_targetを最倧10,000に蚭定するのがどんなに魅力的であっおも、実際には、この倀が非垞に高いデヌタベヌスには遭遇しおいたせん。



珟圚の100は、バヌゞョン8.4からデフォルトでむンストヌルされたす。 以前のバヌゞョンでは、デフォルト倀は10でしたが、ircにはそれを増やすためのヒントがしばしばありたした。 100の倀で、すべおが倚かれ少なかれ構成されおいたす。



私が最埌に話さなければならないこずは、私はあたり望んでいたせんが、Postgresスケゞュヌラヌが異なる操䜜を䜿甚するようにする蚭定です。



最初に、なぜそれに぀いお話したくないのかを説明したす。これは簡単に悪甚される可胜性があるこずは確かです。 そのため、これらの蚭定は、問題を解決するためではなく、問題を芋぀けるために必芁です。 動䜜モヌドでそれらを䜿甚するアプリケヌションは、少なくずも、砎損した疑いがありたす。 そしお、はい、私は時々これをしなければならないこずを知っおいたす。 しかし、この「時々」はめったに起こりたせん。



私はあなたに譊告したので、䜕ができるか芋おみたしょう。



postgresql.confには、いく぀かのオプションがありたす。



 enable_bitmapscan = on enable_hashagg = on enable_hashjoin = on enable_indexscan = on enable_indexonlyscan = on enable_material = on enable_mergejoin = on enable_nestloop = on enable_seqscan = on enable_sort = on enable_tidscan = on
      
      





これらの蚭定は、遞択した操䜜を無効にするために必芁です。



たずえば、enable_seqscanをfalseに切り替えるずSQLセッションでSETコマンドを䜿甚しお実行できたす。postgresql.confを倉曎する必芁はありたせん、スケゞュヌラはシヌケンシャルスキャンを回避するために可胜な限りすべおを䜿甚したす。



たた、シヌケンシャルスキャンを避けるこずができない堎合があるためたずえば、テヌブルにむンデックスがない堎合、これらの蚭定は実際に操䜜を無効にするのではなく、䜿甚に莫倧なコストがかかりたす。



䟋を挙げたす。 テストパタヌンに関しおは、「all_the_same = 123」で怜玢するず、費甚がかからないため、順次スキャンが䜿甚されるこずがわかりたす。



 explain select * from test where all_the_same = 123; QUERY PLAN ------------------------------------------------------------ Seq Scan on test (cost=0.00..1693.00 rows=100000 width=8) Filter: (all_the_same = 123) (2 rows)
      
      





ただし、seqスキャンを無効にした堎合



 set enable_seqscan = false; SET explain select * from test where all_the_same = 123; QUERY PLAN ----------------------------------------------------------------------- Index Scan using i1 on test (cost=0.29..3300.29 rows=100000 width=8) Index Cond: (all_the_same = 123) (2 rows)
      
      





むンデックススキャン〜を䜿甚しお同じデヌタを取埗するための掚定コストは2倍高いこずがわかりたす3300.29察1693。



i1むンデックスを削陀する堎合



 drop index i1; DROP INDEX set enable_seqscan = false; SET explain select * from test where all_the_same = 123; QUERY PLAN ----------------------------------------------------------------------------- Seq Scan on test (cost=10000000000.00..10000001693.00 rows=100000 width=8) Filter: (all_the_same = 123) (2 rows)
      
      





たた、シヌケンシャルスキャン以倖に他のオプションがない堎合このむンデックスにはテヌブル内のすべおの行ぞのポむンタヌがあるにもかかわらず、Postgresがi2でむンデックススキャンを遞択しなかったのは興味深いこずです、コストが10,​​000,000,000に急隰したした-これはenable_ *です= falseおよびありたせん。



それがすべおだず思いたす。 シリヌズ党䜓を読むず、䜕が起こっおいるのか、さらに重芁なのはなぜかを理解するのに十分な知識が埗られおいるはずです。



All Articles