OLTP Anti-Patterns
一部のコンテンツは LLM によって生成されており、まだ手動で検証されていません。
OLTP(Online Transaction Processing)システムの一般的 なアンチパターンとベストプラクティス。
flowchart LR
subgraph Bad["アンチパターン"]
A[逐次処理]
B[長いトランザクション]
C[フルテーブルスキャン]
end
subgraph Good["ベストプラクティス"]
D[バッチ処理]
E[短いトランザクション]
F[インデックス検索]
end
A -.-> D
B -.-> E
C -.-> F
クエリ効率
| アンチパターン | 問題 | ベストプラクティス |
|---|---|---|
| DML 入れ子 クエリ | 毎回 サブクエリを実行 、性能 が非常 に悪 い | JOINを使用 または事前 クエリ後 バッチ処理 |
| 逐次 カーソル処理 | 大量 データの行 単位 処理 、効率 が低 い | バッチ操作 またはset-basedロジック |
| 過度 な動的 SQL | 最適化 困難 、SQLインジェクションの危険 | パラメータ化 クエリと準備 済 みステートメント |
DML 入れ子クエリの例
アンチパターン:
UPDATE orders
SET status = 'processed'
WHERE customer_id IN (
SELECT id FROM customers WHERE region = 'APAC'
);
-- サブクエリは毎回customersテーブルをスキャンベストプラクティス:
-- JOINを使用
UPDATE orders o
JOIN customers c ON o.customer_id = c.id
SET o.status = 'processed'
WHERE c.region = 'APAC';カーソル処理 vs バッチ操作
アンチパターン(逐次 処理 ):
DECLARE cur CURSOR FOR SELECT id FROM orders WHERE status = 'pending';
OPEN cur;
FETCH NEXT FROM cur INTO @id;
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE orders SET status = 'processing' WHERE id = @id;
FETCH NEXT FROM cur INTO @id;
END;ベストプラクティス(バッチ処理 ):
UPDATE orders SET status = 'processing' WHERE status = 'pending';トランザクション管理
| アンチパターン | 問題 | ベストプラクティス |
|---|---|---|
| 大量 データ単一 トランザクション | ロック保持 時間 が長 い、undo log膨張 | 分割 コミット、各 バッチの件数 を制御 |
| 無効 なトランザクション境界 | ビジネスロジックが正 しくトランザクションに含 まれていない | トランザクション範囲 と分離 レベルを明確 に定義 |
| バッチ処理 を使用 しない | 大量 INSERT/UPDATEを逐次 実行 | bulk insert、batch updateを使用 |
分割コミットの例
アンチパターン:
BEGIN TRANSACTION;
DELETE FROM logs WHERE created_at < '2020-01-01';
-- 数百万行に影響、ロック時間が長すぎる
COMMIT;ベストプラクティス:
WHILE EXISTS (SELECT 1 FROM logs WHERE created_at < '2020-01-01')
BEGIN
BEGIN TRANSACTION;
DELETE TOP (10000) FROM logs WHERE created_at < '2020-01-01';
COMMIT;
END;インデックス設計
| アンチパターン | 問題 | ベストプラクティス |
|---|---|---|
| インデックス不足 | 頻繁 なフルテーブルスキャン、クエリが遅 い | クエリパターンに基 づいて適切 なインデックスを作成 |
| 過度 なインデックス | 書 き込 み性能 低下 、維持 コスト高 い | インデックス使用率 を定期的 に確認 、冗長 なものを削除 |
| 過度 な正規化 | 頻繁 なJOINが性能 に影響 | 適度 な非正規化 またはマテリアライズドビュー |
インデックス設計の考慮事項
インデックス要件 の評価 :
-- スロークエリの確認
SELECT * FROM sys.dm_exec_query_stats
ORDER BY total_elapsed_time DESC;
-- 欠落インデックスの提案を確認(SQL Server)
SELECT * FROM sys.dm_db_missing_index_details;
-- 未使用インデックスの確認
SELECT * FROM sys.dm_db_index_usage_stats
WHERE user_seeks = 0 AND user_scans = 0;複合 インデックスの順序 原則 :
選択性 の高 い列 を先 に
WHERE条件 で頻繁 に使用 される列 を優先
カバリングインデックスを検討
その他の問題
| アンチパターン | 問題 | ベストプラクティス |
|---|---|---|
| トリガーの乱用 | ビジネスロジックの隠蔽 、デバッグ困難 、性能 問題 | ロジックをアプリケーション層 または明示的 なstored procedureに移行 |
トリガーの適切な使用場面
トリガーの使用 に適 した場面 :
監査 ログ(audit logging)
タイムスタンプの自動 更新
データ整合性 の強制 (制約 で実現 できない場合 )
トリガーを避 けるべき場面 :
複雑 なビジネスロジック
複数 テーブルにまたがる連鎖 更新
トランザクション制御 が必要 な操作