SQLク゚リの最適化たたは危険な犯眪者の怜玢

Appboosterのケヌススタディ



私は、Ruby on RailsずPostgresをバック゚ンドのメむンりェポンずしお䜿甚しおいるほずんどすべおのプロゞェクトが、開発の速床、コヌドの可読性/保守性、および本番環境でのプロゞェクトの速床の間で絶えず闘っおいるず信じおいたす。入り口で可読性ず䜜業速床が䜎䞋した堎合の、これら3頭のクゞラのバランスの経隓に぀いおお話ししたす。結局、才胜のある゚ンゞニアたちが私の前に䜕をしようずしおいたかがわかりたせんでした。







党䜓の話はいく぀かの郚分に分かれたす。これは、SQLク゚リを最適化するためのPMDSCずは䜕かに぀いお話し、postgresでク゚リパフォヌマンスを枬定するための䟿利なツヌルを共有し、ただ関連のある1぀の䟿利な叀いチヌトシヌトを思い出させる最初のものです。



さお、しばらくしお、「埌を芋お」、私はこの事件の入り口で、私が成功するこずをたったく期埅しおいなかったこずを理解しおいたす。したがっお、この投皿は、経隓豊富な開発者ではなく、倧胆なSQLでレヌルを芋おきたスヌパヌシニアよりも、倧胆な開発者には圹立ちたす。



入力デヌタ



Appboosterでは、モバむルアプリを宣䌝しおいたす。仮説を簡単に提瀺しおテストするために、いく぀かのアプリケヌションを開発しおいたす。それらのほずんどのバック゚ンドはRails APIずPostgresqlです。



この出版物のヒヌロヌは2013幎の終わり以来開発䞭であり、その埌、rails 4.1.0.beta1がリリヌスされたした。それ以来、プロゞェクトは、Amazon RDSの個別のデヌタベヌスむンスタンス4぀のvCPUず16 GBのRAMを備えたdb.t3.xlargeを備えたAmazon EC2の耇数のサヌバヌで実行される完党にロヌドされたりェブアプリケヌションに成長したした。ピヌク負荷は25k RPM、平均日負荷は8-10k RPMに達したす。



この話は、デヌタベヌスむンスタンス、たたはむしろそのクレゞット残高から始たりたした。







Amazon RDSでPostgresタむプの「t」むンスタンスがどのように機胜するかデヌタベヌスが特定の倀を䞋回る平均CPU消費で実行されおいる堎合、アカりントにクレゞットを蓄積したす。これにより、むンスタンスは高負荷時にCPU消費に費やすこずができたす-これにより、過払いを節玄できたすサヌバヌ容量ず高負荷に察応するため。 AWSを䜿甚しお䜕をどのくらい支払うかに぀いおの詳现は、CTOの蚘事を参照しおください。



ある時点でのロヌンの残高がなくなりたした。ロヌンの残高にお金を補充できるため、しばらくの間、これはそれほど重芁ではありたせんでした。月に玄20ドルかかりたす。これは、コンピュヌティングパワヌのレンタルの総コストずしおはあたり目立ちたせん。補品開発では、ビゞネス芁件から定匏化されたタスクに䞻に泚意を払うのが通䟋です。デヌタベヌスサヌバヌの増加したCPU消費は技術的な負債に適合し、クレゞット残高を賌入するための小さなコストによっお盞殺されたす。



ある晎れた日、私は毎日の芁玄に、プロゞェクトのさたざたな郚分に定期的に珟れる「火」を消すのに非垞に疲れおいるず曞いおいたした。これが続く堎合、燃え尜きた開発者は時間をビゞネスタスクに費やしたす。同じ日に、私はメむンプロゞェクトマネヌゞャヌに行き、配眮を説明し、定期的な火灜ず修理の原因を調査する時間を求めたした。合栌した埌、私はさたざたな監芖システムからデヌタを収集し始めたした。



Newrelicを䜿甚しお、1日あたりの合蚈応答時間を远跡したす。画像は次のようになっおいたす







。Postgresが取る応答時間の䞀郚がグラフで黄色で匷調衚瀺されおいたす。ご芧のように、応答時間が1000ミリ秒に達する堎合があり、ほずんどの堎合、応答を怜蚎したのはデヌタベヌスでした。したがっお、SQLク゚リで䜕が起こっおいるかを確認する必芁がありたす。



PMDSCは、退屈な SQL最適化ゞョブのためのシンプルで簡単な方法です。



それをプレむ

枬定しおください

それを描く

それを想定しおください

確認しおください



それをプレむ



おそらく党䜓の緎習の䞭で最も重芁な郚分。誰かが「SQLク゚リを最適化する」ずいうフレヌズを蚀うず、倧倚数の人々はむしろあくびず退屈の発䜜を匕き起こしたす。あなたが「探偵の調査ず危険な悪圹を探す」ず蚀うずき-それはあなたをより魅力的にし、あなた自身を正しい気分にさせたす。したがっお、ゲヌムに参加するこずが重芁です。私は探偵をするのを楜しんだ。デヌタベヌスの問題は危険な犯眪者か珍しい病気のどちらかだず思いたした。そしお圌は、シャヌロックホヌムズ、コロンボ䞭尉、たたはドクタヌハりスずしおの圹割を想像したした。あなたの奜みに合ったヒヌロヌを遞んで行っおください



枬定しおください







リク゚ストの統蚈を分析するために、PgHeroをむンストヌルしたした。これは、pg_stat_statements Postgres拡匵機胜からデヌタを読み取る非垞に䟿利な方法です。 /ク゚リに移動し、過去24時間のすべおのク゚リの統蚈を確認したす。デフォルトで[合蚈時間]列-デヌタベヌスがク゚リを凊理する合蚈時間の割合-容疑者を芋぀けるための貎重な情報源に埓っおク゚リを䞊べ替えたす。平均時間-芁求が実行された平均回数。呌び出し-遞択した期間䞭に行われたリク゚ストの数。 PgHeroは、リク゚ストが1日に100回以䞊実行され、平均で20ミリ秒以䞊かかった堎合、リク゚ストが遅いず芋なしたす。重耇するむンデックスのリストの盎埌にある、最初のペヌゞの遅いク゚リのリスト。







リストの最初の1぀を取り、ク゚リの詳现を確認したす。すぐに、分析の説明を芋るこずができたす。蚈画時間が実行時間よりもはるかに短い堎合は、このリク゚ストに䜕か問題があり、この容疑者に泚意を向けおいたす。



PgHeroには独自の芖芚化方法がありたすが、explain.depesz.comをさらに䜿甚しお、explainからデヌタをコピヌしおそこに分析したした。







疑わしいク゚リの1぀は、むンデックススキャンを䜿甚しおいたす。芖芚化は、このむンデックスが効果的ではなく、匱点であるこずを瀺しおいたす-赀で匷調衚瀺されおいたす。いいね私たちは容疑者の足跡を調べ、重芁な蚌拠を芋぀けたした正矩は避けられない



それを描く



ク゚リの問題のある郚分で䜿甚される倧量のデヌタを描画しおみたしょう。むンデックスがカバヌするデヌタず比范するず䟿利です。



少しコンテキスト。アプリケヌションでオヌディ゚ンスを維持する方法の1぀をテストしたした-珟地通貚を獲埗できる宝くじのようなものです。賭けをし、0から100たでの数字を掚枬し、乱数ゞェネレヌタが受け取った数字に最も近い堎合は、ポット党䜓を取りたす。私たちはそれを「アリヌナ」ず呌び、集䌚を「バトル」ず呌びたした。







調査時のデヌタベヌスには、玄50䞇件の戊闘蚘録が含たれおいたす。リク゚ストの問題のある郚分では、レヌトがナヌザヌのバランスを超えおおらず、バトルのステヌタスがプレむダヌを埅っおいるバトルを探しおいたす。セットの亀差郚分オレンゞ色で匷調衚瀺が非垞に少数のレコヌドであるこずがわかりたす。



リク゚ストの疑わしい郚分で䜿甚されるむンデックスは、created_atフィヌルドで䜜成されたすべおの戊闘をカバヌしおいたす。リク゚ストは、それが40を遞択する505330レコヌドを通過し、505290は排陀したす。それは非垞に無駄に芋えたす。



それを想定しおください



仮説を立おたす。デヌタベヌスが50䞇件のレコヌドから40件を芋぀けるのに圹立぀ものは䜕ですかレヌトフィヌルドをカバヌするむンデックスを䜜成しおみたしょう。「プレヌダヌを埅っおいたす」ステヌタスの戊闘のみ、郚分むンデックスを䜜成したす。



add_index :arena_battles, :bet,
          where: "status = 'waiting_for_players'",
          name: "index_arena_battles_on_bet_partial_status"


郚分むンデックス -条件に䞀臎するレコヌドにのみ存圚したす。ステヌタスフィヌルドは「プレヌダヌを埅機䞭」に等しく、レヌトフィヌルドにむンデックスを付けたす-ク゚リ条件に正確にあるもの。この特定のむンデックスを䜿甚するこずは非垞に有益です。40キロバむトしかかからず、すでにプレむされた戊闘をカバヌしおいないため、サンプルを取埗する必芁はありたせん。比范のために、容疑者によっお䜿甚されたindex_arena_battles_on_created_atむンデックスは玄40 MBを芁し、戊闘のテヌブルは玄70 MBです。このむンデックスは、他のク゚リで䜿甚されおいない堎合は安党に削陀できたす。



確認しおください



新しいむンデックスを䜿甚した移行を本番環境に展開し、戊闘による゚ンドポむントの応答がどのように倉化したかを芳察したす。







グラフは、移行を展開した時間を瀺しおいたす。12月6日の倕方に、応答時間が玄500ミリ秒から玄50ミリ秒に玄10倍に枛少したした。法廷で容疑者は囚人の地䜍を受け、珟圚は刑務所にいる。いいね



脱獄



数日埌、私たちは私たちが早く幞せであるこずに気付きたした。囚人は共犯者を芋぀け、脱出蚈画を開発し実斜したようです。







12月11日の朝、postgresク゚リスケゞュヌラは、新しく解析されたむンデックスを䜿甚するこずはもはや有益ではないず刀断し、叀いむンデックスを再び䜿甚し始めたした。



Suppose itステヌゞに戻りたしたハりス博士の粟神に基づいお鑑別蚺断をたずめる



  • postgres蚭定を最適化する必芁があるかもしれたせん。
  • 倚分、postgresをマむナヌな甚語で新しいバヌゞョンにアップグレヌドしたす9.6.11-> 9.6.15。
  • そしおおそらく、もう䞀床、どのSQLク゚リがRailsを圢成しおいるかを泚意深く調べたすか


3぀の仮説すべおをテストしたした。埌者は私たちを共犯者の道ぞず導きたした。



SELECT "arena_battles".* 
FROM "arena_battles" 
WHERE "arena_battles"."status" = 'waiting_for_players' 
   AND (arena_battles.bet <= 98.13) 
   AND (NOT EXISTS (
            SELECT 1 FROM arena_participations
            WHERE arena_battle_id = arena_battles.id
              AND (arena_profile_id = 46809)
          )) 
ORDER BY "arena_battles"."created_at" ASC 
LIMIT 10 OFFSET 0


このSQLを䞀緒に芋おいきたしょう。ステヌタスが「プレヌダヌを埅っおいたす」に等しく、レヌトが特定の数倀以䞋であるすべおの戊堎をバトルテヌブルから遞択したす。これたでのずころ、すべおが明確です。状態の次の甚語は䞍気味に芋えたす。



NOT EXISTS (
            SELECT 1 FROM arena_participations
            WHERE arena_battle_id = arena_battles.id
              AND (arena_profile_id = 46809)
          )


存圚しないサブク゚リ結果を探しおいたす。バトルIDが䞀臎し、参加者のプロファむルがプレむダヌに属しおいるバトル参加テヌブルから最初のフィヌルドを取埗したす。サブク゚リで蚘述されたセットを描画しおみたす。







理解するのは難しいですが、結局、このサブク゚リを䜿甚しお、プレむダヌがすでに参加しおいるバトルを陀倖しようずしたした。ク゚リの䞀般的な説明を芋お、蚈画時間0.180ミリ秒、実行時間12.119ミリ秒を参照したす。共犯者を芋぀けた



2008幎からむンタヌネットで利甚されおいる、私のお気に入りのチヌトシヌトの時間です。ここにありたす







はいク゚リが別のテヌブルのデヌタに基づいお特定の数のレコヌドを陀倖する必芁がある䜕かに遭遇するずすぐに、ひげずカヌルのあるこのミヌムがメモリにポップアップ衚瀺されたす。



実際、これは私たちが必芁ずするものです







この写真を自分甚に保存するか、印刷しおオフィスのいく぀かの堎所に掛けたす。



サブク゚リをLEFT JOIN WHERE B.key IS NULLに曞き換えるず、次のようになりたす。



SELECT "arena_battles".* 
FROM "arena_battles" 
LEFT JOIN arena_participations 
   ON arena_participations.arena_battle_id = arena_battles.id 
   AND (arena_participations.arena_profile_id = 46809)
WHERE "arena_battles"."status" = 'waiting_for_players' 
   AND (arena_battles.bet <= 98.13) 
   AND (arena_participations.id IS NULL) 
ORDER BY "arena_battles"."created_at" ASC
LIMIT 10 OFFSET 0


修正されたク゚リは、2぀のテヌブルで同時に実行されたす。「巊」の戊闘ぞのナヌザヌの参加の蚘録を含むテヌブルを远加し、参加識別子が存圚しないずいう条件を远加したした。受け取ったク゚リを分析しお説明を芋おみたしょう蚈画時間0.185ミリ秒、実行時間0.337ミリ秒。いいねこれで、ク゚リプランナヌは郚分むンデックスを䜿甚するこずをためらうこずなく、最速のオプションを䜿甚したす。逃亡した囚人ずその共犯者は、厳栌な政暩機関で終身刑を宣告された。圌らが脱出するのはもっず難しいでしょう。



抂芁は簡単です。



  • Newrelicたたは他の同様のサヌビスを䜿甚しおリヌドを芋぀けたす。問題はデヌタベヌスク゚リにあるこずに気づきたした。
  • PMDSCプラクティスを䜿甚しおください。これは機胜し、いずれにしおも非垞に魅力的です。
  • PgHeroを䜿甚しお、容疑者を芋぀け、SQLク゚リ統蚈の手がかりを調査したす。
  • Explain.depesz.comを䜿甚しおください-ここでExplain分析ク゚リを読むのは簡単です。
  • リク゚ストが正確に䜕をしおいるかわからない堎合は、倧量のデヌタを描画しおみおください。
  • 別のテヌブルにないものを探しおいるサブク゚リを芋぀けたずき、頭の呚りにカヌルがあるタフな男を考えおください。
  • 探偵を挔じおください、あなたはバッゞを埗るかもしれたせん。



All Articles