1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【インフラエンジニアがSQLを使えるようになった日】「遅いから直せない」と言われた地獄で、私が実行計画を学ぶまで

Posted at

インフラエンジニアとしてキャリアをスタートさせたばかりの頃、私はある日、逃れられない大きな壁に直面しました。それは、 アプリケーションエンジニアが直せないと言い放った「パフォーマンス地獄」 です。

インフラ担当の私が、夜間の二重生活を通じてSQLを読み書きできるようになり、プロジェクトの危機を救うまでの生々しいストーリーと、そこから得た「職能の壁を越える」ための教訓を共有します。

序章:平和なインフラ領域と、最初の地獄

入社4年目。当時の私の仕事は、Oracle Databaseの起動・停止、パラメータチューニング、バックアップ・リカバリ1といった、インフラ視点のコマンドライン操作が中心でした。SQLはDCL(データ制御言語)2の一部を使う程度で、アプリケーションのビジネスロジックを読み解くDML(データ操作言語)3には手を出していませんでした。

しかし、最初のトラブルは突然訪れました。

突如訪れた「メモリの壁」

サービスイン直前に、PMの判断でメモリ増設を試みましたが、当時のOSであるWindows Server 2008 R2のエディションの制約で増設分を認識しないという事態が発生。急遽エディションをStandardからEnterpriseにアップグレードするという、前代未聞の事件がありました。この増設によりOracleのパフォーマンスは一時的に改善し、数カ月は平穏が保たれました。

Windows Serverのエディションはアップグレードインストールができるのですが、自宅の仮想環境で実証済みとは言えサービスイン直前でしたから痺れましたね。

第1章:「月次処理地獄」と突きつけられた拒絶

数カ月後、システムが本格的に稼働し、データが蓄積され始めた頃、顧客から厳しいクレームが入りました。

「月次処理の期間になるとパフォーマンスが著しく低下し、業務時間内に締め処理を行えない。取引先への支払遅延など、非常にまずい状況だ」

顧客からの要求は「来月までに改善」という厳しいものでした。

データが示す原因の特定

私はすぐに、サービスイン前に導入していたパフォーマンス分析ツール STATSPACK4の定期スナップショットを読み込みました。当時はGeminiのような生成AIは存在しないため、翔泳社の『新・門外不出のOracle現場ワザ』を文字通り読み込み、地道に仮説を立てていきました。

分析の結果、以下の異常が判明しました。

  • 待機イベント: db file sequential read5 が非常に多く、DB Time6のほとんどを占めている。
  • SQLの負荷: Physical Read が極端に多い50以上のSQLが存在する。

これは、「データベースがメモリ(SGA/PGA)7ではなくディスクへの読み書きに大量の時間を費やしている」、つまり**「ディスクI/O」がボトルネック**であることを示していました。

「無責任の壁」の誕生

私は分析結果をプロジェクトマネージャー(PM)に報告し、原因となっているSQLのチューニングを下請けのアプリケーションエンジニアに依頼しました。SQLチューニングは、アプリケーションのビジネスロジックを理解しているアプリ側の担当である、と当然思っていたからです。

しかし、返ってきた答えは予想外のものでした。

  • 「今までこれで動いてきたからSQLには問題ない」
  • 「データベースのチューニングで解決できるのではないか」
  • 「うちでは原因は分からないし、通常の保守業務で工数的に手一杯であり対応できない」

彼らには 「調べすらしてもらえませんでした」

私は驚きましたが、顧客と下請け業者の間に不信感があった経緯から自社のPMが間に入っていたこともあり、最終的にPMが下した決断は、

「SQLを読み書きできないお前(私)が、通常業務後にチューニングしろ」

というものでした。

第2章:背水の陣の1ヶ月間とSQLとの対峙

この無茶な決定により、私の 1ヶ月間にわたる「二重生活」 が始まりました。私の知識はインフラに留まっており、アプリケーションのSQLの読み書きができない状態からのスタートでした。

実行計画という名の「地図」の解読

STATSPACKで問題SQLは分かっても、なぜ遅いのか?を解明するため、私は問題のあるSQLの実行計画8を確認しました。すると、多くのSQLで TABLE ACCESS FULL9というアクセスパターンが非常に多いことが判明しました。

ここから私の学習が始まります。

  • SQLの読み解き: まずは複雑に結合された FROM 句と、テーブル結合順を照らし合わせるところから始めました。SQLが読めないため、ER図(当時は存在を知らなかった)に相当する図を自力で書き出して、テーブルの関連性を把握しました。
  • 検証の自動化: STATSPACKのレポート作成は時間がかかるため、SQL*PLUSで SET AUTOTRACE ON10 を実行し、実行計画を即座に確認できる検証サイクルを確立しました。
  • 分離と再構築: テスト環境で、複雑な結合SQLを分割し、どこで TABLE ACCESS FULL が発生するかを少しずつ元のSQLに戻しながら切り分けました。

この「生きているビジネスロジックのSQLを読み書きする」という経験を通じて、私は文字通りSQLを身体で覚えていきました。

悟りの瞬間:「大丈夫だった」のではなく「データが少なかった」

検証の過程で、私は最も深刻なボトルネックを発見し、衝撃を受けました。

それは、多くのSQLの結合条件に含まれていた、 「削除フラグが1でない」 というたった1行の条件です。

  • 型の闇: 削除フラグの列が、なんと文字列型でした。このため、比較演算子(<>1)を使うと暗黙の型変換11が発生し、インデックスが使えない状態になっていた可能性がありました。
  • 選択率の罠: 削除フラグにはインデックスがありましたが、ほとんどの行(9割以上)が該当する否定条件(<>1)を使うと、Oracleのオプティマイザはインデックススキャンよりテーブルフルスキャンの方が早いと判断します。

私はこのとき、悟りました。

今まで大丈夫だったのは、Oracleがいい感じの実行計画を選んでいたのではなくて、総データ数が少なかったから影響が小さかったのだ。そして今、メモリに乗り切らないだけのデータ数になったのだ。

問題の根本は、 「データ量の増大」というインフラの現実と、「SQL設計の甘さ」 が重なったところにありました。

第3章:解決編と「最強の武器」の獲得

原因が判明したことで、私はインフラエンジニアの立場ながら、SQLのチューニングに着手しました。

高度なチューニングによる突破

削除フラグとフルスキャンの問題を解決するために、私は当時、Oracle現場ワザの本で学んだ高度なテクニックを使いました。

  • 型の統一: 削除フラグを TO_NUMBER(削除フラグ) < 1 や > 1 と書き換え、文字列を数値として扱うことを強制しました。
  • ファンクションインデックスの作成: 結合キー、SELECTステートメントで登場するすべての列に加え、TO_NUMBER(削除フラグ) を含んだファンクションインデックス12を作成しました。

インデックスの選択率が90%以上という低い値であっても、テーブルフルスキャンよりも、このインデックスフルスキャン13の方がI/O効率が改善し、複雑な結合が多いSQLのパフォーマンスは大幅に向上しました。

(ちなみに、今思えば 削除フラグ <> '1' と文字列で比較するだけで、暗黙の型変換は防げたかもしれません。また自己結合も多かったためWINDOW関数14による大幅な(最大50%程度の)改善ができたかも知れません。完璧な仕事ではなかったですが、目の前の問題を解決する「生きた学び」でした。)

この対応により、その後サーバーリプレースに至るまで、大きなパフォーマンスクレームは発生しなくなりました。

結論:インフラエンジニアの「最終責任」とは何か

この1ヶ月間の地獄の経験は、私にとって最高の教材となり、「SQLを読み書きできる」というインフラエンジニアとして最強の武器を与えてくれました。

そして、この経験を通じて、私は職能の境界線と真の責任範囲について、以下のような結論に達しました。

1. 共通言語としてのSQLの不可欠性

STATSPACKのレポートを読み込むのはインフラエンジニアの範疇ですが、そこで抽出されたSQLを見て、 「このSQLはインフラから見てどう問題があるか」 を理解し、実行計画を提示するまでがインフラエンジニアの仕事です。

SQLの読み書きができなければ、その一歩を踏み出すことすらできません。

2. 真の問題解決者となる

「遅いから直せない」という無責任な壁に直面したとき、それを回避するのではなく、オーナーシップを持って解決する道を選ぶこと。

インフラエンジニアの仕事は、DBサーバーという「箱」を守ることではありません。データベースの性能を通じて、ビジネスの継続性、つまり「顧客の取引先にも迷惑をかけない」というビジネス上の責務を守り抜くことこそが、私たちの最終的な責任です。

「インフラエンジニアがSQLを使えるようになった日」は、単なるスキルアップの日ではなく、職能の壁を超えてサービス全体の安定に責任を持つという、エンジニアとしてのオーナーシップを確立した日だったのです。

  1. バックアップ・リカバリ: データベースのデータを安全に保管し、障害時に元の状態に戻すための作業。

  2. DCL (Data Control Language): データベースのユーザーの権限を制御する命令文(GRANT, REVOKEなど)。

  3. DML (Data Manipulation Language): データベースのデータ操作を行う命令文(SELECT, INSERT, UPDATE, DELETEなど)。

  4. STATSPACK: Oracle Databaseのパフォーマンス統計情報を一定間隔で収集・保存し、レポートとして出力するツール。パフォーマンス分析の基本。

  5. db file sequential read: Oracleの待機イベントの一つで、インデックスを使用した読み込み、またはディスクからのデータブロックの連続読み込みを待っている状態。これが極端に多いとディスクI/Oがボトルネックであることを示唆する。

  6. DB Time: データベースがユーザー要求を処理するために費やした合計時間。パフォーマンス分析の最重要指標。

  7. SGA/PGA (System Global Area / Program Global Area): Oracle Databaseが使用するメモリ領域。データやSQLの実行計画などをキャッシュする重要な場所。

  8. 実行計画 (Execution Plan): データベースがSQL文を実行する際に、データにアクセスし、処理を実行する具体的な手順と経路を示したもの。性能チューニングの「地図」。

  9. TABLE ACCESS FULL: テーブルの全行を最初から最後まで読み込むアクセス方法。大量のI/Oが発生しやすく、多くの場合は非効率とされる。

  10. SET AUTOTRACE ON: SQL*PLUSというコマンドラインツールでSQLを実行する際、そのSQLの実行計画と統計情報(CPU時間、I/O回数など)を自動で表示させるコマンド。迅速な検証に必須。

  11. 暗黙の型変換: SQLの比較演算で、データ型が異なる場合、データベースが自動的に一方のデータ型をもう一方に合わせて変換すること。これによりインデックスが使われなくなり、フルスキャンが発生する主な原因となる。

  12. ファンクションインデックス: 列の値ではなく、その列に関数(ファンクション)を適用した結果に基づいて作成されるインデックス。SQLのWHERE句で関数が使われている場合に、インデックスを使用可能にする高度なテクニック。

  13. インデックスフルスキャン: インデックスの全エントリを読み込むアクセス方法。テーブル全体を読み込むよりは効率的だが、大量のデータを取得する際には発生しやすい。

  14. WINDOW関数(分析関数): SQLで集合(ウィンドウ)内の行に対して計算を行い、結果を各行に返す関数(例: RANK, ROW_NUMBER, SUM/AVG overなど)。テーブルの自己結合(Self-Join)を排除し、処理を大幅に高速化できる高度なテクニック。

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?