バインド変数/パラメータスニッフィングを管理
Oracle
-- Use binds instead of literals (for plan sharing):
SELECT * FROM customer WHERE city = :city;
-- Share legacy code that uses literals:
ALTER SESSION SET cursor_sharing = FORCE;バインド変数はハードパースを削減する。Adaptive Cursor Sharing は、偏った分布のバインド値に対して複数の実行計画を保持することでスニッフィングの問題を緩和する。cursor_sharing=FORCE は慎重に使用する。
PostgreSQL
-- Parameterize with a prepared statement:
PREPARE q (text) AS SELECT * FROM customer WHERE city = $1;
EXECUTE q('Ankara');
-- Set plan cache behavior:
SET plan_cache_mode = force_custom_plan;plan_cache_mode=auto は汎用プランとカスタムプランを選択する。force_custom_plan は実行のたびにパラメータ固有の実行計画を生成する(スニッフィングに似た問題への対策)。
MySQL
-- Server-side prepared statement:
PREPARE stmt FROM 'SELECT * FROM customer WHERE city = ?';
SET @city = 'Ankara';
EXECUTE stmt USING @city;
DEALLOCATE PREPARE stmt;プリペアドステートメントは SQL インジェクションを防ぎ、解析コストを下げる。MySQL はドライバレベルでのパラメータ化もサポートする。
SQL Server
-- Parameterized query (sp_executesql):
EXEC sp_executesql N'SELECT * FROM dbo.customer WHERE city = @city', N'@city nvarchar(50)', @city = N'Ankara';
-- Handle sniffing with a hint:
SELECT ... OPTION (RECOMPILE);
-- or OPTION (OPTIMIZE FOR (@city = 'Ankara'));OPTION(RECOMPILE) は実行のたびにパラメータ固有の実行計画を生成する(CPU コストが高い)。OPTIMIZE FOR は実行計画を特定の/典型的な値に固定し、OPTIMIZE FOR UNKNOWN は平均的な選択性を使用する。
MongoDB
// The query shape is the key of the plan cache:
db.customer.find({ city: "Ankara" }).explain("queryPlanner")
// Clear a stale plan:
db.customer.getPlanCache().clear()同じ形状(同じフィールド/演算子)のクエリはキャッシュされた実行計画を共有する。リテラル値が異なっても新しい実行計画は生成されない。値の分布が大きく偏っている場合は planCacheClear でリセットする。
Redis
# Not applicable: there is no query planner or parameter sniffing.コマンドは直接実行される。パラメータ化ではなくキー設計がパフォーマンスを決める。
Elasticsearch
# Reuse the query with a parameterized search template:
POST _scripts/customer_city
{ "script": { "lang": "mustache", "source": { "query": { "term": { "city": "{{city}}" } } } } }
GET <index>/_search/template
{ "id": "customer_city", "params": { "city": "Ankara" } }search template(Mustache)はクエリ本体をパラメータ化する。アプリケーションは固定のテンプレートを異なる値で呼び出し、クエリの一貫性とキャッシュの利用効率を向上させる。