「SQL」カテゴリーアーカイブ

SQL関連のカテゴリ

SQL:中央値(MEDIAN)をSQLで求める方法まとめ

中央値を使う場面

中央値(MEDIAN)は、極端な値(外れ値)の影響を受けにくい指標として、業務システムやデータ分析でよく使われます。
例:処理時間の中央値、売上の中央値、レスポンス時間の中央値など。

SQLではDBMSによって書き方が大きく異なるため、この記事では主要DBMSごとに中央値の求め方をわかりやすく整理します。


1. Oracleで中央値を求める(標準でMEDIAN関数あり)

Oracle Database は最も簡単で、MEDIAN集計関数が標準で使用可能

条件付き

パーティションごと(グループ別)

Oracleユーザーは基本これだけでOKです。


2. PostgreSQLで中央値を求める

PostgreSQL には MEDIAN関数は無い ため、percentile_cont を使います。

グループ別

col がNULLの場合は自動的に除外されます。


3. MySQLで中央値を求める(8.0〜)

MySQLにも MEDIAN関数は無い ため、以下の方法を使います。

方法1:ウィンドウ関数+ROW_NUMBER

奇数なら真ん中の値、偶数なら2つの平均を返します。


4. SQL Serverで中央値を求める

SQL Server も MEDIAN 関数なし。
PERCENTILE_CONT を使うのが最もシンプル。

グループ別

SQL Serverユーザーはこの書き方を覚えておけば十分です。


5. SQLiteで中央値を求める

SQLite はウィンドウ関数が使える(3.25〜)ので MySQLと同じ方法が有効。


6. DBMS別「中央値の求め方」まとめ表

DBMS中央値の関数代表的な書き方
OracleMEDIANSELECT MEDIAN(col)
PostgreSQLpercentile_contpercentile_cont(0.5) WITHIN GROUP
MySQLなし(手動)ウィンドウ関数で行番号+平均
SQL ServerPERCENTILE_CONTPERCENTILE_CONT(0.5)
SQLiteなし(手動)ウィンドウ関数で行番号+平均

外れ値があるデータ分析では平均より中央値の方が実態を正確に示すケースが多いので、SQLでの算出方法を覚えておくと便利です。

SQL:DELETEが異常に遅い原因と対処法まとめ|大量データで固まる時のチェックポイント

大量データを扱うシステムでは、
「DELETE文が異常に遅い」「1000件削除するだけで何分もかかる」
という現象は珍しくありません。

実際、筆者の環境でも

  • 1500万件のテーブル

  • DELETE 1件 = 約1.2秒

  • DELETE 100件 = 約2分

  • DELETE 1000件 = 約20分

という、明らかに正常とは言えない状態に遭遇しました。

この記事では、
SQL(特にOracle)で DELETEが異常に遅くなる原因と対処法
現場目線でわかりやすくまとめます。


1. DELETEが遅い原因は「処理そのものが重い」から

SELECTは一瞬で返るのに、DELETEだけ異様に遅い。
これは DELETE内部の処理コストが非常に重い ためです。

DELETEが行うことは主に以下:

  1. 対象行の削除(表領域から除去)

  2. インデックスから該当エントリの削除

  3. Undoログの生成

  4. Redoログの生成

  5. ロック管理

  6. トリガー処理(あれば)

このどれか、あるいは複数が詰まると
DELETEは1件ずつ遅くなり、数百件〜数千件だと“永遠に終わらない”状態になります。


2. DELETEが異常に遅いときの主な原因

2-1. インデックスの断片化・肥大化(最も多い)

大量INSERT / DELETE / UPDATE を繰り返したテーブルは
インデックスが “B-tree破損状態” になります。

症状:

  • DELETE 1件 = 1秒以上

  • 100件DELETEでも数分

  • SELECTは速い(インデックス検索は生きている)

これはインデックス劣化の典型。

→ インデックス再構築で劇的に改善することがあります。


2-2. Undo / Redo の処理が追いつかない

大量DELETEを連続してキャンセルすると

  • Undoセグメント肥大

  • Redoログ切替待ち

  • I/Oスラッシング

  • Undo segment extension 待ち

などが発生し、DELETEが異常に遅くなります。


2-3. 外部キー参照(子テーブル)が存在する

DELETEのたびに

  • 子テーブルを参照

  • 存在チェック

  • 参照整合性確認

を行うため、対象行が多いと極端に遅くなります。

※子テーブルを先に削除済なら影響なし。


2-4. トリガーが動いている

DELETEトリガーがあると
行ごとに処理が実行されるため、100行DELETEで100回 トリガーが動きます。

トリガー内でINSERT/UPDATEが走っていると、一気に重くなります。


2-5. テーブルやインデックスの断片化

特に1500万件級の大規模テーブルでは
断片化やI/O劣化によって DELETE が遅くなります。


2-6. ロックではない(SELECT が速ければ別原因)

「DELETEが遅い=ロック」と思われがちですが、
SELECTが瞬時に返るならロックではないことが多いです。

DELETE固有の処理が遅い証拠です。


3. DELETEが遅いときのチェックポイント(すぐ実行できる)

✔ ① SELECT COUNT は速い?

→ 速いならロックではない。

✔ ② 1件DELETEの時間を計測

→ 1秒以上かかるならインデックス劣化 or Undo詰まり。

✔ ③ インデックス数は多すぎない?

✔ ④ トリガーが無いか?

✔ ⑤ 子テーブルの外部キーは?

これだけでも原因の大半は特定できます。


4. 対策まとめ(実務で使える)

4-1. インデックス再構築(効果大)

DBA権限が必要ですが、再構築すると劇的に速くなります。


4-2. 統計情報の更新


4-3. 子テーブルを先に削除 or 一時的に外部キー無効化


4-4. トリガーの見直し / 一時無効化


4-5. DELETEを小分け(100件単位)で実行

大量DELETEは一度にやるのではなく
100件 or 1000件ごとに分割してCOMMITする方が安全。

※筆者環境では
100件DELETE = 約2分
1000件DELETE = 約20分
でした。


4-6. 一番速いのは「論理削除」

物理削除できないなら DELETE_FLG を立てる方法が最も安全。

これは DELETE より圧倒的に軽いです。


4-7. 本当に大量削除するなら「CTAS」が最強

残すデータだけ別テーブルにコピーして入れ替える方法。

DELETEより何倍も速いです。


5. まとめ

DELETEは単純なSQLに見えますが、
内部的には

  • インデックス更新

  • Undo/Redo 生成

  • ロック管理

  • 外部キー参照

  • トリガー処理

など多くの処理が絡むため
大量データでは極端に遅くなることがあります。

特に大規模テーブル(1000万件以上)だと
1件 DELETE でも1秒以上かかることが普通にあります。

もし DELETE が遅くて固まる場合は、

  1. SELECT が速いか確認

  2. 1件DELETEの時間を計測

  3. インデックス・Undo/Redo・トリガーを疑う

  4. 小分けDELETE or 論理削除に切り替える

  5. 必要に応じてDBAにインデックス再構築を依頼

といったステップで原因を切り分けると
安全で確実に改善できます。

SQL:半角 全角 変換 SQLだけで行う方法(Oracle / SQL Server / PostgreSQL)

SQLで半角 全角 変換 SQL を実行したい場面は、顧客データの正規化・文字種統一・基幹システム間のデータ連携などで非常に多く発生します。
カタカナ・英数字・記号などは半角/全角の表記ゆれが多く、SQLだけで統一できるとバッチ処理やETLの品質が向上します。

本記事では、Oracle・SQL Server・PostgreSQL・MySQLといった主要DBMSごとに
SQLだけで行う半角⇔全角変換の方法(半角 全角 変換 SQL) をまとめてわかりやすく解説します。


🟦 1. 半角 全角 変換 SQL が必要になる理由

半角/全角の違いは以下の問題を引き起こします。

  • 同じ文字でも別文字として扱われ、一致検索・JOINが失敗する

  • 顧客名・住所・カナ項目で表記ゆれが大量発生

  • 帳票やCSV出力の品質が揺れる

SQLで半角 全角 変換 SQL を実行して正規化 しておくと、後続処理が安定し、システム全体のデータ品質が高まります。


🟦 2. Oracleでの半角 全角 変換 SQL(CONVERT / TRANSLATE)

Oracleには完全な変換専用関数がありませんが、
CONVERTTRANSLATE の組み合わせで実現できます。


■ 2-1. 半角 → 全角(カナ)

Oracle独自の US7ASCII → JA16SJIS を使う裏技です。

※ 半角カナ → 全角カナに有効(英数字は別途処理)


■ 2-2. 半角 → 全角(英数字)


■ 2-3. 全角 → 半角

Oracleは全角→半角カナが標準で無いため、TRANSLATEでマッピングする必要があります。


🟩 3. SQL Serverでの半角 全角 変換 SQL(TRANSLATE)

SQL Server 2017以降は TRANSLATE が使用可能で、Oracleより簡単です。


■ 3-1. 半角 → 全角


■ 3-2. 全角 → 半角


🟧 4. PostgreSQLでの半角 全角 変換 SQL(translate関数)

PostgreSQLも Oracle / SQL Server と同様に translate() を使用します。


■ 4-1. 半角 → 全角


■ 4-2. 全角 → 半角


🟥 5. MySQLでの半角 全角 変換 SQL(REPLACE)

MySQLは専用関数がないため、REPLACE を多段適用します。


■ 5-1. 半角 → 全角(数字の例)

全変換を行う場合は、ストアド関数化が実務的です。


🟪 6. 実務で使える半角 全角 変換 SQL:関数化例(Oracle)


■ 半角 → 全角


■ 全角 → 半角


🧩 7. 半角 全角 変換 SQL を行う際の注意点

① 濁点・半濁点が合成文字として扱われる

例:パ = ハ + ゚

② DB文字コードで変換結果が異なる

Oracle(AL32UTF8 / JA16SJIS)では特に差が出やすい。

③ カナ変換はDBMSによって不得意

全角↔半角カナは、Oracleの CONVERT 技など固有の知識が必要。


✔ 結論:SQLだけで半角⇔全角変換は可能(ただしDB依存)

DBMS半角→全角全角→半角
OracleCONVERT + TRANSLATETRANSLATE(要マッピング)
SQL ServerTRANSLATETRANSLATE
PostgreSQLtranslate()translate()
MySQLREPLACEREPLACE

総じて SQLだけで半角 全角 変換 SQL を実現できる ものの、
DBMSごとに得意・不得意があるため、場面に応じて使い分けることが重要です。

SQL:VIEWの仕組みを理解する – 仮想テーブルはどう評価される?

SQLのVIEW(ビュー)は、データベースの中に“仮想テーブル”を作る仕組みです。
名前は知っていても、

  • VIEWは物理的にデータを持つのか?

  • SELECTすると実際にはどう評価されるのか?

  • VIEWをネストしたらパフォーマンスはどうなる?

といった点まで正しく理解されているケースは意外と少ないです。

この記事では、VIEWの“実体”と、クエリ実行時の評価タイミング、パフォーマンスへの影響を分かりやすく解説します。


1. VIEW(ビュー)とは? – 定義文を保存する“仮想テーブル”

VIEWはテーブルのように見えますが、実際にはデータを持っていません
DBに保存されるのは、以下のような「SQL定義(SELECT文)」だけです。

このv_salesはあたかもテーブルのように扱えますが、中身は 上記SELECT文の“参照” でしかありません。


2. VIEWはいつ“評価”されるのか? – クエリ実行時に展開される

VIEWの最大の誤解ポイントはここです。
ビューは“保存されたSELECT文”なので、クエリ実行のたびに展開されます

以下のクエリを実行すると、

実際には DB 内部で次のように変換されます。

つまり、

  • VIEWが実体化して保存されるわけではない

  • 実行時、その都度“SELECT文の中にインライン展開”される

  • テーブルアクセスもフィルタもすべて本テーブルに作用する

というのがVIEWの基本動作です。


3. DBはVIEWを最適化してくれる – クエリオプティマイザの働き

多くのRDBMS(Oracle / PostgreSQL / MySQL / SQL Server)は、VIEW展開後のSQLを 単一のクエリとして最適化 します。

例えば、

VIEW内にWHERE status='OK'という条件、外側に日付条件があった場合でも、

オプティマイザが結合・条件式をまとめて最適な実行計画に変換する

というのが一般的です。

そのため、VIEWを使ってもパフォーマンスが極端に悪化するわけではありません。
(※もちろん複雑なVIEWの“ネスト”は別の話なので後述)


4. VIEWをネストするとどうなる? – 複雑化 → 最適化が困難化

例えば次のようにVIEWを三重にしてしまうと、

v1 → v2 → v3 → メインSELECT

内部ではこんな巨大なSQLに展開されます。

オプティマイザは強力ですが、以下のような場合は最適化が限界に達します。

  • JOINが増えすぎる

  • CASE式やサブクエリが多すぎる

  • DISTINCT・GROUP BYが重複している

  • “VIEWの中でさらにVIEWをJOIN” している

その結果、

  • 不要な全表スキャン

  • 重複GROUP BYで大量のソート

  • 複雑化で実行計画が肥大化

というパフォーマンス低下が起きます。


5. VIEWのメリット

✔ コードの再利用性

複雑なSELECTを1つにまとめて使い回せる。

✔ 可読性の向上

アプリ側のSQLがスッキリする。

✔ 権限管理に使える

特定の列だけ公開するVIEWを作り、ユーザにはVIEWだけ権限付与できる。


6. 気をつけるべきポイント(よくある落とし穴)

❌ VIEWが高速化してくれると思い込む

→ VIEWは基本的には“ただのSQLの保存”。高速化しない。

❌ VIEWを多段に重ねて巨大SQLになっている

→ 実行計画が複雑化しパフォーマンス劣化。

❌ UNION・DISTINCT入りVIEWの多用

→ 展開後に何度もソートが発生する。

❌ VIEW経由にするとインデックスが効かないと思い込む

→ 展開後のSQLにインデックスが適用されるので誤解。


7. MATERIALIZED VIEWとの違い(超重要)

種類データ保持更新タイミング用途
VIEW (通常VIEW)持たない(常に仮想)実行時に展開再利用・権限管理・コード整理
MATERIALIZED VIEWデータを保持(物理表)リフレッシュ時高速化(集計 / 重いJOIN結果のキャッシュ)

高速化したい時は VIEWではなく MATERIALIZED VIEW を使うのが正解です。


8. VIEWをどう使うべきか?(ベストプラクティス)

✔ 単純ビューを使う

1〜2テーブルのJOIN、軽いWHERE程度に留める。

✔ 複雑なロジックをVIEWに押し込まない

アプリ側に処理を書くか、ストアドやマテリアライズドビューで対応。

✔ 多段VIEWは避ける

どうしても必要な場合は“1段階に統合して新VIEWを作る”。

✔ パフォーマンス課題が出たら、展開SQLを確認する

実行計画を見ると改善点がすぐわかる。


まとめ:VIEWは“実体のないSELECT文”であり、実行時に展開される

ポイントを整理すると:

  • VIEWはデータを持たない(仮想テーブル)

  • DBはVIEW定義を毎回展開し、1つのSQLとして最適化する

  • 単純なVIEWは便利だが、多段ビューはパフォーマンス悪化の原因

  • 高速化目的なら MATERIALIZED VIEW を使うべき

VIEWは便利な反面、仕組みを誤解すると性能劣化の原因にもなります。
“何がどう評価されているのか”を理解した上で、適切に設計しましょう。

Oracleで文字列操作を極める:SUBSTR・INSTR・REPLACEの活用術

Oracle SQLで文字列を自在に扱えるようになると、データ抽出や整形が格段に効率化します。
本記事では、文字列操作の3大関数「SUBSTR」「INSTR」「REPLACE」の使い方をわかりやすく解説します。


1️⃣ SUBSTR:文字列の一部を取り出す

SUBSTRは指定した位置から任意の長さの文字列を切り出す関数です。

🔸 使用例

結果:

📘 ポイント

  • 開始位置は 1から数える

  • 第3引数(文字数)を省略すると、開始位置以降をすべて取得

  • 負の値を指定すると末尾からカウントされる

→ 結果:EF


2️⃣ INSTR:文字列の位置を検索する

INSTRは、指定した文字が出現する**位置(インデックス)**を返します。

🔸 使用例

結果:

→ 2つ目のカンマ「,」が4文字目にあることを示します。

📘 応用テクニック

INSTRSUBSTRを組み合わせることで、区切り文字を含む文字列から特定部分を抜き出すことが可能です。

結果:


3️⃣ REPLACE:文字列の置換を行う

REPLACEは、指定した文字列を別の文字列に置き換える関数です。

🔸 使用例

結果:

📘 応用テクニック

REPLACEを使えば、不要な文字の削除も簡単に行えます。

結果:


4️⃣ 組み合わせテクニック:実用的な例

💡 メールドメインを抽出する例

結果例:

EMAILDOMAIN
user@example.comexample.com

💡 ファイル名から拡張子を削除

結果例:

FILE_NAMEBASE_NAME
report.xlsxreport

5️⃣ まとめ

関数用途主な特徴
SUBSTR部分文字列の取得開始位置・文字数指定が可能
INSTR指定文字の位置取得出現回数も指定可能
REPLACE文字列の置換不要文字の削除にも利用可能

これらを組み合わせることで、Oracle SQLでの文字列処理は自由自在になります。
ログ解析、ファイル名分割、メールドメイン抽出など、日常的な業務で大活躍する関数です。

サブクエリを使ったUPDATE文:別テーブルの値で更新する方法

■ 概要

SQLでデータを更新する際、別のテーブルの値を参照してUPDATEしたい場面は多くあります。
たとえば、マスタテーブルの最新情報でトランザクションテーブルを更新するケースなどです。

この記事では、Oracleデータベースを例に、サブクエリを使ったUPDATE文の書き方をわかりやすく解説します。


■ 基本構文

Oracleでサブクエリを用いたUPDATEを行う場合、基本的な構文は次の通りです。

ここで重要なのは、
SET句の中でサブクエリを使って値を取得し、
WHERE EXISTSで更新対象を限定する点です。


■ 実際の例:商品価格マスタをもとに在庫テーブルを更新

【例題】

  • PRODUCT_MASTER(商品マスタ)テーブル:

    • PRODUCT_ID

    • PRICE(最新の価格)

  • STOCK_INFO(在庫情報)テーブル:

    • PRODUCT_ID

    • PRICE(販売価格を更新したい)

【目的】

マスタの最新価格を在庫情報に反映する。

【SQL例】


■ ポイント解説

  1. サブクエリは1行1列を返す必要がある

    • サブクエリが複数行を返すと ORA-01427: single-row subquery returns more than one row エラーになります。

    • PRODUCT_IDなどの条件で一意に絞り込みましょう。

  2. WHERE EXISTSで更新対象を限定

    • EXISTSを使わない場合、サブクエリが該当しないレコードは NULL で更新される可能性があります。

    • 余計な更新を防ぐためにも、WHERE EXISTSを併用するのが安全です。

  3. パフォーマンス最適化のためにインデックスを確認

    • 結合条件に使う列(例:PRODUCT_ID)にはインデックスを付与すると高速化できます。


■ 別の書き方:MERGE文を使う方法

Oracleでは、サブクエリUPDATEの代わりにMERGE文を使っても同じことができます。

MERGE文は「更新または挿入」を同時に扱える構文で、
大量データ更新時にはこちらの方が効率的なこともあります。


■ まとめ

方法特徴
サブクエリを使ったUPDATEシンプルで分かりやすい。少量データ更新に最適。
MERGE文更新+挿入を同時に扱える。大量データ更新に向く。

■ この記事のポイント

  • Oracleでサブクエリを使ったUPDATEは「単一行サブクエリ+EXISTS」で安全に実装する

  • 一意性を保証できない場合は MERGE の利用を検討

  • インデックス設計で性能を最適化

SQL:実行計画(EXPLAIN PLAN)の読み方とボトルネックの見つけ方

データベースチューニングにおいて「どのSQLが遅いのか」だけでなく、「どの処理がボトルネックなのか」を正しく把握することは非常に重要です。
そのための基本ツールが**実行計画(EXPLAIN PLAN)**です。

本記事では、Oracleを例に実行計画の見方とボトルネックの探し方を、初心者でも理解できるように解説します。


✅ EXPLAIN PLANとは?

SQLを実行する際、Oracleが内部的に考える**最適な実行手順(アクセス方法)**を表示する機能です。

実行計画を見ることで、次のようなことがわかります。

  • テーブルにアクセスする順番

  • インデックスを使っているかどうか

  • 結合(JOIN)の方式

  • フルスキャンが走っているか

  • コスト(予測負荷)


✅ 実行計画の取得方法

▼ 方法1:EXPLAIN PLAN文を使う

▼ 方法2:SQL Developer で「実行計画」ボタン

GUI環境ではワンクリックで参照できます。


✅ Oracle実行計画の基本構造

実行計画は階層構造で、上から順に処理が行われます。
インデントが深いほど「その処理の中で実行される詳細処理」です。

例:


✅ よく出るOperationと解釈ポイント

Operation説明見どころ
TABLE ACCESS FULLテーブルの全件スキャン大量データで出たら要注意
TABLE ACCESS BY INDEX ROWIDインデックス参照後にROWIDアクセス最適パターンの一つ
INDEX UNIQUE SCAN主キー・ユニークインデックス検索高速
INDEX RANGE SCAN範囲検索効率的だが条件次第
HASH JOINハッシュ表でJOIN大量データ向き、メモリ消費
NESTED LOOPS小規模データに適したJOIN結合相手の行数が多いと遅い
SORT ORDER BY並び替え必要ならOK、無駄がないか確認

✅ ボトルネックの探し方

① TABLE ACCESS FULL に注意

  • 条件にインデックスが効いていない可能性

  • 大規模テーブルで特に危険

対策:

  • WHERE句に使う列にインデックス追加

  • 不必要なSELECT *を避ける

  • ファンクションインデックス


② JOIN方式を確認

JOIN方式特徴適したケース
NESTED LOOPS小テーブル to 大テーブルに◎OLTP向き
HASH JOIN大量データ向き、高速DWH向き
MERGE JOIN並び替え前提、ソート負荷ソート後結合

Nested Loops × 大量データ → 遅い可能性


③ コスト(COST)とROWSを確認

項目意味
ROWS見積もられる行数
COSTOracleが見積もる負荷指数
BYTESデータ量

COSTが極端に高い行がボトルネック候補。


④ SORTが多い場合

ORDER BY や DISTINCTが多いと遅くなる

対策:

  • 必要な場面以外でDISTINCT使用しない

  • ORDER BYの列にインデックス


✅ 実例:遅いSQLの典型パターン

問題点

  • UPPER(ENAME) → 関数でインデックス無効

  • LIKE ‘%〇〇’ → 前方ワイルドカードでインデックス無効

  • SELECT * → 不要な列読み込み

改善例


✅ チューニングの基本手順まとめ

ステップ内容
1実行計画を見る
2TABLE FULL SCANをチェック
3JOIN方法確認(Nested Loops vs Hash Join)
4コスト高い箇所を特定
5インデックス/SQL修正

✅ まとめ

  • EXPLAIN PLANはSQLの動作設計図

  • インデックス利用とJOIN方式を重視

  • FULL SCANと高コスト行は警戒

  • 必要な列だけ取得し、関数利用に注意

SQLチューニングは**「まず実行計画を見る」**がスタートです。
慣れるほど読み解きが早くなり、効率的な分析ができるようになります。

インデックスの仕組みを理解してSQLを劇的に高速化する方法

SQLの処理が遅いと感じたとき、多くの人が「サーバが遅いのでは?」と思いがちです。
しかし、実際の原因の多くは「インデックス(索引)」の使い方にあります。
この記事では、インデックスの基本構造から、実際のチューニング手法までを体系的に解説します。


1. インデックスとは?

インデックスとは、データベースが**検索を高速化するために作成する“索引”**のことです。
書籍の巻末索引のように、「この値はどこにあるか」を素早く見つけるための目次のような仕組みです。

🔹 例:インデックスなしの検索

このとき、インデックスが無ければ、データベースは全件を1件ずつ確認します(フルスキャン)。

🔹 例:インデックスありの検索

これにより、該当レコードを索引経由で一瞬で特定できるようになります。


2. インデックスの仕組みを理解する

🧩 B-treeインデックス

ほとんどのRDBMS(Oracle、MySQL、PostgreSQLなど)で採用されている構造です。
値が昇順に整理され、2分探索のように効率的に検索できます。

例えば「70」を探すとき、50より大きいので右に進み、次に70を発見します。
わずか2ステップで到達できるため、フルスキャンに比べて圧倒的に速いのです。


🧩 ビットマップインデックス(Oracleなど)

主に**値の種類が少ないカラム(性別、ステータスなど)**に有効です。
各値に対応するレコードのビットマップを管理することで、AND/OR検索が高速化します。


3. どんなカラムにインデックスを貼るべきか?

✅ 有効なケース

  • WHERE句で頻繁に検索される列

  • JOIN条件に使われる列

  • ORDER BYGROUP BYの対象列

  • 外部キー(FOREIGN KEY)列

🚫 不向きなケース

  • データ件数が極端に少ない列(例:性別など)

  • 更新頻度が高い列(INSERT/UPDATEが多いと再構築コストが増大)

  • テーブル全件を常に取得するクエリ


4. 実行計画で確認する

SQLの速度改善は、**「インデックスが使われているか」**を確認することが第一歩です。

結果例(MySQLの場合)

typekeyrowsExtra
refidx_users_email1Using index

「Using index」と表示されていれば、インデックスが利用されています。
逆に「ALL」となっている場合はフルスキャンです。


5. インデックスを使った高速化テクニック

🌟 複合インデックス(複数列)

複数の列を組み合わせた検索で効果を発揮します。
ただし、先頭の列が条件に含まれないと使われない点に注意が必要です。

例:


🌟 カバリングインデックス(Covering Index)

インデックスに必要な列すべてを含めることで、テーブルアクセスをスキップできます。

テーブルを参照せずにインデックスだけで完結するため、極めて高速です。


🌟 LIKE検索の最適化

前方一致(Yui%)はインデックスが有効ですが、

のような部分一致はインデックス無効です。
対策としては、**全文検索エンジン(MySQLのFULLTEXT、PostgreSQLのGIN/GiST)**を使う方法があります。


6. 注意点:インデックスの弊害

インデックスは便利ですが、万能ではありません。
特に以下の点には注意が必要です。

リスク説明
更新コスト増大INSERTやUPDATE時にインデックスも更新されるため、処理が重くなる
ストレージ消費大規模テーブルに多くのインデックスを張ると、容量が急増
メンテナンス負荷不要なインデックスを放置すると、統計情報がずれて性能が劣化

🧹 定期的に ANALYZE TABLEREBUILD INDEX を実施して、統計情報を更新しましょう。


7. 実践チューニング例

✏️ 例1:検索が遅いクエリ

🩹 改善策

✅ 実行計画の変化

  • 変更前:type = ALL(フルスキャン)

  • 変更後:type = ref(インデックス参照)

実行時間が数秒 → 数ミリ秒まで短縮されることもあります。


まとめ

ポイント内容
インデックスとはデータ検索を高速化するための“索引”
構造B-treeが主流。ビットマップは限定用途
効果的な付与検索条件、JOIN、GROUP BY、ORDER BY列
落とし穴更新負荷、容量増加、部分一致非対応
確認方法EXPLAINで実行計画を必ずチェック

🚀 結論

インデックスを理解すれば、SQLの速度は10倍以上高速化することも珍しくありません。
なんとなく作るのではなく、「どう検索されるか」を意識して設計することが重要です。

JOINの種類を解説!INNER/LEFT/RIGHT/FULLの違いとは?

SQLで複数のテーブルを結合してデータを取得したい場合、欠かせないのが「JOIN」構文です。しかし、INNER・LEFT・RIGHT・FULLと種類が多く、「どれを選べば良いかわからない…」という悩みをよく聞きます。

本記事では、各JOINの違いを図解付きでわかりやすく解説します。


✅JOINとは?

JOINとは、複数のテーブルを条件に基づいて結び付ける操作です。
たとえば、「社員テーブル」と「部署テーブル」を組み合わせて、社員名と部署名を一覧表示するといったケースが典型例です。


✅テスト用テーブル(例)

社員テーブル(employees)部署テーブル(departments)
emp_idemp_namedept_id
1佐藤10
2鈴木20
3高橋30
4田中40

✅1. INNER JOIN(内部結合)

👉 両方のテーブルで一致するデータのみ取得

✅結果(部署が存在するデータだけ表示)

emp_namedept_name
佐藤営業
鈴木開発
高橋総務

❌部署IDが40の田中さんは表示されません。


✅2. LEFT JOIN(左外部結合)

👉 左側テーブル(employees)を基準に、マッチしない行も取得

✅結果(左基準)

emp_namedept_name
佐藤営業
鈴木開発
高橋総務
田中NULL

✔部署がない社員も「NULL」として表示されます。


✅3. RIGHT JOIN(右外部結合)

👉 右側テーブル(departments)を基準にマッチしない行も取得

✅結果(右基準)

emp_namedept_name
佐藤営業
鈴木開発
高橋総務

※部署側に存在しない社員は現れません。


✅4. FULL JOIN(完全外部結合)

👉 両テーブルのすべての行を対象に、合致しないデータも含めて取得

✅結果(両方)

emp_namedept_name
佐藤営業
鈴木開発
高橋総務
田中NULL

💡※MySQLではFULL JOINは直接サポートされていないため、UNIONで代替します。


✅JOINの違いまとめ(図で理解)

JOIN種類取得範囲イメージ
INNER🎯一致する部分のみ
LEFT📘左テーブル全体+一致
RIGHT📙右テーブル全体+一致
FULL🌐両テーブルの全体

✅どれを使えば良い?

シーンオススメJOIN
双方の共通データだけ欲しいINNER JOIN
左側を優先して一覧取得したいLEFT JOIN
右側を基準にしたいRIGHT JOIN
すべてのデータを見たいFULL JOIN

✅まとめ

JOIN特徴
INNER共通する行のみ取得
LEFT左基準で関連しない行も取得
RIGHT右基準で関連しない行も取得
FULL両テーブル全体を包括

👉まずは INNER JOINを基本とし、
「欠けているデータを埋めたいとき」にLEFT/RIGHTを検討すると理解しやすいです。

SQL:MERGE文でINSERTとUPDATEを一度に行う効率的な方法

MERGE文とは?

SQLのMERGE文は、対象テーブルにデータが存在する場合はUPDATE、存在しない場合はINSERTを1回の処理でまとめて行える便利な構文です。
従来は「UPDATE → 該当しなければINSERT」といった2回の処理が必要でしたが、MERGEを使うことで1回のSQLで済むため、処理効率やパフォーマンスが向上します。

本記事ではOracleをベースに解説しつつ、他DBでの対応についても補足します。


MERGE文の基本構文(Oracleの場合)



実用例①:顧客マスタの更新 or 追加

ID=C001 が存在すれば更新
✅ 存在しなければ新規追加


処理の流れ(フロー図で理解)


応用例②:条件によってDELETEも行う(Oracle/SQL Server対応)

✅ ステータスがCANCELなら削除
✅ そうでなければ更新
✅ 該当なしならINSERT


MERGE文のメリット

項目従来方法MERGE文
SQL実行回数UPDATEとINSERTの2回1回
パフォーマンスやや低い高い
ロジックの明確さ分岐が必要条件分が整理されやすい
メンテナンス性低め高い

注意点

注意点内容
ロックの影響大量データの場合、テーブルロックが発生しやすい
複雑な条件WHEN句が増えると可読性が下がる
DB依存性MySQLは8.0.19以降、PostgreSQLはINSERT ... ON CONFLICTで代替

他DBでの補足

DBMERGE対応備考
Oracle対応本記事基準
SQL Server対応ほぼ同構文
MySQL8.0.19~対応REPLACE/INSERT ON DUPLICATEも可
PostgreSQL15~対応それ以前はINSERT ON CONFLICT

まとめ

✅ MERGE文はINSERTとUPDATEを1回の処理にまとめる強力なSQL構文
✅ DELETEも組み合わせれば高度なロジックも実現可能
✅ Oracle・SQL Serverでは標準的に使用される
✅ MySQL/PostgreSQLではバージョン確認が必要

「同じキーのデータを更新 or 追加したい」場面で積極的に使いましょう!