{"index.json":{"schemaVersion":2,"app":"DBAtlas","updated":"2026-07-04","engines":"engines.json","rosetta":["rosetta/sessions.json","rosetta/storage.json","rosetta/performance.json","rosetta/backup.json","rosetta/security.json","rosetta/maintenance.json","rosetta/schema.json","rosetta/replication.json","rosetta/connect.json","rosetta/objects.json","rosetta/datamove.json","rosetta/monitoring.json","rosetta/automation.json","rosetta/lifecycle.json","rosetta/migration.json","rosetta/tuning.json","rosetta/tuning-adv.json","rosetta/advanced-features.json","rosetta/sql-syntax.json"],"cloud":["cloud/cloud-ops-1.json","cloud/cloud-ops-2.json"],"guide":{"bestPractices":["guide/best-practices.json","guide/best-practices-2.json","guide/best-practices-3.json","guide/best-practices-4.json"],"glossary":["guide/glossary.json","guide/glossary-2.json","guide/glossary-3.json"]},"rosettaOverlays":["rosetta/overlay-elasticsearch.json"],"types":"types/types-functions.json","errors":["errors/oracle.json","errors/postgres.json","errors/mysql.json","errors/mssql.json","errors/mongodb.json","errors/redis.json","errors/elasticsearch.json","errors/oracle-more.json","errors/postgres-more.json","errors/mysql-more.json","errors/mssql-more.json","errors/mongodb-more.json","errors/redis-more.json","errors/elasticsearch-more.json","errors/oracle-more2.json","errors/postgres-more2.json","errors/mysql-more2.json","errors/mssql-more2.json","errors/mongodb-more2.json","errors/redis-more2.json","errors/elasticsearch-more2.json","errors/oracle-more3.json","errors/postgres-more3.json","errors/mysql-more3.json","errors/mssql-more3.json","errors/mongodb-more3.json","errors/redis-more3.json","errors/elasticsearch-more3.json","errors/oracle-more4.json","errors/postgres-more4.json","errors/mysql-more4.json","errors/mssql-more4.json","errors/mongodb-more4.json","errors/redis-more4.json","errors/elasticsearch-more4.json"],"health":["health/oracle.json","health/postgres.json","health/mysql.json","health/mssql.json","health/mongodb.json","health/redis.json","health/elasticsearch.json"],"recipes":["recipes/oracle.json","recipes/oracle-ha.json","recipes/oracle-ops.json","recipes/postgres.json","recipes/postgres-ha.json","recipes/postgres-ops.json","recipes/mysql.json","recipes/mysql-ext.json","recipes/mssql.json","recipes/mssql-ext.json","recipes/mongodb.json","recipes/mongodb-ext.json","recipes/redis.json","recipes/redis-ext.json","recipes/elasticsearch.json","recipes/elasticsearch-ext.json"],"playbooks":["playbooks/playbooks.json","playbooks/hadr.json","playbooks/security.json","playbooks/cloud.json","playbooks/automation.json"],"solver":["solver/slow-query.json","solver/deadlock.json","solver/disk-full.json","solver/connection-storm.json","solver/replication-lag.json","solver/ora-01555.json","solver/backup-restore.json","solver/upgrade-wizard.json","solver/migration-wizard.json","solver/high-cpu.json","solver/memory-pressure.json","solver/install-setup.json","solver/corruption-recovery.json","solver/failover-drill.json","solver/security-incident.json","solver/audit-setup.json","solver/decide-ha.json","solver/decide-isolation.json","solver/decide-sqlnosql.json","solver/decide-shard-replica.json","solver/decide-backup.json","solver/decide-index.json","solver/decide-partition.json","solver/decide-pooling.json","solver/decide-cache.json","solver/decide-datatype.json","solver/decide-capacity.json","solver/slow-write.json","solver/io-bottleneck.json","solver/undo-temp-pressure.json","solver/long-transaction.json","solver/plan-regression.json","solver/replica-resync.json","solver/cache-hit-low.json","solver/arch-oltp.json","solver/arch-dwh.json","solver/arch-microservice.json","solver/arch-eventdriven.json","solver/arch-multiregion.json","solver/arch-highscale.json"],"reference":{"params":["reference/params-oracle.json","reference/params-postgres.json","reference/params-mysql.json","reference/params-mssql.json","reference/params-mongodb.json","reference/params-redis.json","reference/params-elasticsearch.json"],"waits":["reference/waits-oracle.json","reference/waits-postgres.json","reference/waits-mysql.json","reference/waits-mssql.json","reference/waits-mongodb.json","reference/waits-redis.json","reference/waits-elasticsearch.json"],"alerts":["reference/alerts-oracle.json","reference/alerts-postgres.json","reference/alerts-mysql.json","reference/alerts-mssql.json","reference/alerts-mongodb.json","reference/alerts-redis.json","reference/alerts-elasticsearch.json"]},"install":"install/index.json"},"engines.json":{"schemaVersion":1,"updated":"2026-07-03","engines":[{"id":"oracle","name":"Oracle","full":"Oracle Database","color":"#C74634","family":"sql","cli":"sqlplus","docs":"https://docs.oracle.com/en/database/"},{"id":"postgres","name":"PostgreSQL","full":"PostgreSQL","color":"#3461B5","family":"sql","cli":"psql","docs":"https://www.postgresql.org/docs/"},{"id":"mysql","name":"MySQL","full":"MySQL / MariaDB","color":"#00758F","family":"sql","cli":"mysql","docs":"https://dev.mysql.com/doc/"},{"id":"mssql","name":"SQL Server","full":"Microsoft SQL Server","color":"#6E3FC4","family":"sql","cli":"sqlcmd","docs":"https://learn.microsoft.com/en-us/sql/"},{"id":"mongodb","name":"MongoDB","full":"MongoDB","color":"#2E7D32","family":"document","cli":"mongosh","docs":"https://www.mongodb.com/docs/"},{"id":"redis","name":"Redis","full":"Redis","color":"#B45309","family":"keyvalue","cli":"redis-cli","docs":"https://redis.io/docs/"},{"id":"elasticsearch","name":"Elasticsearch","full":"Elasticsearch","color":"#BE2A6E","family":"search","cli":"curl / Kibana","docs":"https://www.elastic.co/guide/"}]},"rosetta/sessions.json":{"category":"セッションとアクティビティ","categoryId":"sessions","order":1,"concepts":[{"id":"active-sessions","title":"アクティブなセッション/実行中のクエリを表示","aliases":["active sessions","running queries","who is connected","current activity","active session","running query","who is connected now","processlist","current op"],"engines":{"oracle":{"command":"SELECT sid, serial#, username, status, sql_id, machine, program\nFROM v$session\nWHERE type = 'USER' AND status = 'ACTIVE';","note":"v$session で現在アクティブなセッションを取得する。完全な SQL テキストは sql_id で v$sql と結合して取得する。","danger":"safe"},"postgres":{"command":"SELECT pid, usename, state, wait_event_type, query\nFROM pg_stat_activity\nWHERE state <> 'idle';","note":"state = 'active' はその時点でクエリを実行中のものを示す。所要時間は backend_start / query_start から算出する。","danger":"safe"},"mysql":{"command":"SELECT id, user, host, db, command, time, state, info\nFROM information_schema.processlist\nWHERE command <> 'Sleep';\n-- Shortcut: SHOW FULL PROCESSLIST;","note":"MySQL 8 / MariaDB では performance_schema.processlist のほうが取得するロックが少ない。","danger":"safe"},"mssql":{"command":"SELECT r.session_id, s.login_name, r.status, r.command,\n       r.cpu_time, r.total_elapsed_time, t.text AS sql_text\nFROM sys.dm_exec_requests r\nJOIN sys.dm_exec_sessions s ON r.session_id = s.session_id\nCROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t\nWHERE s.is_user_process = 1;","note":"簡易確認: EXEC sp_who2 'active';","danger":"safe"},"mongodb":{"command":"db.currentOp({ \"active\": true })","note":"長時間実行中の操作の絞り込み: db.currentOp({ active: true, secs_running: { $gt: 5 } })","danger":"safe"},"redis":{"command":"CLIENT LIST\n# For a summary: INFO clients","note":"Redis はシングルスレッドのため、「実行中のクエリ」ではなく接続中のクライアントを一覧表示する。遅いコマンドには SLOWLOG GET を使用する。","danger":"safe"}}},{"id":"blocking-sessions","title":"ブロックしている/ロック待ちのセッションを特定","aliases":["blocking","locks","lock wait","deadlock source","blocking session","lock waiting","who is blocking","who is blocking me","blocked","lock holder","what am I waiting on"],"engines":{"oracle":{"command":"SELECT blocking_session, sid, serial#, username,\n       sql_id, seconds_in_wait, event\nFROM v$session\nWHERE blocking_session IS NOT NULL;","note":"blocking_session が設定されているセッションは、blocking_session の値の SID によってブロックされている。","danger":"safe"},"postgres":{"command":"SELECT pid, usename, pg_blocking_pids(pid) AS blocked_by,\n       wait_event, query\nFROM pg_stat_activity\nWHERE cardinality(pg_blocking_pids(pid)) > 0;","note":"blocked_by 配列は、この pid をブロックしている PID を示す。","danger":"safe"},"mysql":{"command":"SELECT * FROM sys.innodb_lock_waits\\G\n-- MySQL 8: SELECT * FROM performance_schema.data_lock_waits;","note":"sys スキーマは、待機中およびブロック中の trx_id / スレッドを読みやすい形式で示す。","danger":"safe"},"mssql":{"command":"SELECT r.session_id, r.blocking_session_id,\n       r.wait_type, r.wait_time, r.wait_resource\nFROM sys.dm_exec_requests r\nWHERE r.blocking_session_id <> 0;","note":"blocking_session_id <> 0 のリクエストはブロックされている。チェーンを辿るには再帰クエリを構築できる。","danger":"safe"},"mongodb":{"command":"db.currentOp({ \"waitingForLock\": true })","note":"WiredTiger はドキュメント/コレクションレベルでロックする。長時間の操作は killOp で終了できる。","danger":"safe"},"redis":{"command":"# Not applicable: Redis commands run atomically one at a time; there are no row locks.\n# Closest diagnostic: SLOWLOG GET 10","note":"ブロッキングは通常、単一の長時間実行コマンド(例: KEYS *、大きな SORT)が原因。SLOWLOG で確認できる。","danger":"safe"}}},{"id":"kill-session","title":"セッション/クエリを終了(kill)","aliases":["kill session","terminate","cancel query","terminate session","cancel the query","kill query","killop"],"engines":{"oracle":{"command":"ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;\n-- To cancel only the running statement (18c+):\n-- ALTER SYSTEM CANCEL SQL 'sid,serial#';","note":"v$session から sid と serial# の値を取得する。IMMEDIATE はロールバックを即座に開始する。","danger":"danger"},"postgres":{"command":"-- Cancel only the running query (the session stays):\nSELECT pg_cancel_backend(pid);\n-- Close the session entirely:\nSELECT pg_terminate_backend(pid);","note":"まず pg_cancel_backend を試し、効かなければ pg_terminate_backend を使用する。","danger":"danger"},"mysql":{"command":"-- Kill only the query:\nKILL QUERY <id>;\n-- Close the connection entirely:\nKILL CONNECTION <id>;","note":"<id> の値は processlist の Id 列。","danger":"danger"},"mssql":{"command":"KILL <session_id>;\n-- To see rollback progress:\n-- KILL <session_id> WITH STATUSONLY;","note":"KILL はオープン中のトランザクションをロールバックする。大きなトランザクションではロールバックに長時間かかることがある。","danger":"danger"},"mongodb":{"command":"db.killOp(<opid>)","note":"opid の値は db.currentOp() 出力の opid フィールドから取得する。","danger":"danger"},"redis":{"command":"CLIENT KILL ID <client-id>\n# or by address: CLIENT KILL ADDR 10.0.0.5:6379","note":"client-id は CLIENT LIST で取得する。既に実行中の単一コマンドは中断できない(Lua スクリプトは例外: SCRIPT KILL)ため、完了を待つ必要がある。BLPOP/XREAD BLOCK などのブロッキングコマンドで待機中のクライアントを接続を切らずに解放するには CLIENT UNBLOCK <client-id> [TIMEOUT|ERROR] を使用する。CLIENT UNPAUSE は CLIENT PAUSE で一時停止したクライアントを再開するだけ。","danger":"caution"}}},{"id":"connection-count","title":"接続数と接続上限を表示","aliases":["connections","max connections","connection limit","connection count","how many connections","is the connection pool full"],"engines":{"oracle":{"command":"SELECT COUNT(*) AS current_sessions FROM v$session WHERE type = 'USER';\nSELECT name, value FROM v$parameter WHERE name IN ('processes','sessions');","note":"上限は processes/sessions パラメータ。使用率は resource_limit ビューでも確認できる。","danger":"safe"},"postgres":{"command":"SELECT count(*) FROM pg_stat_activity WHERE backend_type = 'client backend';\nSHOW max_connections;","note":"pg_stat_activity にはバックグラウンドプロセスも含まれるため、クライアント接続(backend_type = 'client backend')のみをカウントする。superuser_reserved_connections のスロットは管理者用に予約されている。","danger":"safe"},"mysql":{"command":"SHOW STATUS LIKE 'Threads_connected';\nSHOW VARIABLES LIKE 'max_connections';","note":"Max_used_connections ステータスはピーク値を示す。","danger":"safe"},"mssql":{"command":"SELECT COUNT(*) FROM sys.dm_exec_sessions WHERE is_user_process = 1;\nSELECT @@MAX_CONNECTIONS AS configured_max;","note":"@@MAX_CONNECTIONS は理論上の上限。実際の上限はメモリとワーカースレッドに依存する。","danger":"safe"},"mongodb":{"command":"db.serverStatus().connections","note":"current、available、totalCreated フィールドを返す。上限は net.maxIncomingConnections で設定する。","danger":"safe"},"redis":{"command":"INFO clients\nCONFIG GET maxclients","note":"connected_clients は現在の接続数、maxclients は設定された上限(デフォルト 10000)。","danger":"safe"}}}]},"rosetta/storage.json":{"category":"領域とストレージ","categoryId":"storage","order":2,"concepts":[{"id":"database-size","title":"データベースの合計サイズを表示","aliases":["database size","db size","database size","how much space does it use","disk usage","total size"],"engines":{"oracle":{"command":"SELECT ROUND(SUM(bytes)/1024/1024/1024, 2) AS total_gb\nFROM dba_data_files;","note":"使用中のセグメントのみなら dba_segments を合計する。TEMP は dba_temp_files を加算する。","danger":"safe"},"postgres":{"command":"SELECT pg_size_pretty(pg_database_size(current_database()));","note":"全データベースの場合: SELECT datname, pg_size_pretty(pg_database_size(datname)) FROM pg_database ORDER BY 2 DESC;","danger":"safe"},"mysql":{"command":"SELECT table_schema AS db,\n       ROUND(SUM(data_length + index_length)/1024/1024, 1) AS mb\nFROM information_schema.tables\nGROUP BY table_schema\nORDER BY mb DESC;","note":"InnoDB ではこの値は推定値。正確なファイルサイズは OS レベルで ibdata/各ファイルを確認する。","danger":"safe"},"mssql":{"command":"EXEC sp_spaceused;\n-- All databases:\nSELECT DB_NAME(database_id) AS db,\n       CAST(SUM(size) * 8.0 / 1024 AS DECIMAL(10,1)) AS mb\nFROM sys.master_files\nGROUP BY database_id;","note":"size 列は 8 KB ページ単位。* 8 / 1024 で MB に変換する。","danger":"safe"},"mongodb":{"command":"db.stats(1024*1024)\n// returns the dataSize, storageSize, indexSize fields in MB","note":"storageSize は圧縮後のディスク上のサイズ、dataSize は非圧縮の論理サイズ。","danger":"safe"},"redis":{"command":"INFO memory\n# the used_memory_human line gives the total size in memory\nDBSIZE  # number of keys","note":"Redis はメモリベースのため、「サイズ」は RAM 使用量を意味する。RDB/AOF ファイルのサイズはディスクに永続化された状態。","danger":"safe"}}},{"id":"largest-tables","title":"最大のテーブル/コレクションを一覧表示","aliases":["largest tables","biggest tables","top tables by size","largest table","tables using the most space","bigkeys"],"engines":{"oracle":{"command":"SELECT segment_name, segment_type,\n       ROUND(bytes/1024/1024, 1) AS mb\nFROM dba_segments\nWHERE segment_type IN ('TABLE','TABLE PARTITION')\nORDER BY bytes DESC\nFETCH FIRST 10 ROWS ONLY;","note":"インデックスも表示するには segment_type フィルタを外す。","danger":"safe"},"postgres":{"command":"SELECT relname AS table,\n       pg_size_pretty(pg_total_relation_size(relid)) AS total\nFROM pg_catalog.pg_statio_user_tables\nORDER BY pg_total_relation_size(relid) DESC\nLIMIT 10;","note":"pg_total_relation_size はテーブル + インデックス + TOAST の合計。テーブルのみなら pg_relation_size を使用する。","danger":"safe"},"mysql":{"command":"SELECT table_name,\n       ROUND((data_length + index_length)/1024/1024, 1) AS mb\nFROM information_schema.tables\nWHERE table_schema = DATABASE()\nORDER BY (data_length + index_length) DESC\nLIMIT 10;","note":"特定のスキーマに限定するには WHERE table_schema = 'name' を使用する。","danger":"safe"},"mssql":{"command":"SELECT TOP 10 OBJECT_NAME(object_id) AS table_name,\n       SUM(reserved_page_count) * 8 / 1024 AS mb\nFROM sys.dm_db_partition_stats\nGROUP BY object_id\nORDER BY mb DESC;","note":"reserved_page_count は予約済みの全ページ(データ + インデックス)を含む。","danger":"safe"},"mongodb":{"command":"db.getCollectionNames()\n  .map(c => ({ name: c, mb: +(db[c].stats().storageSize/1048576).toFixed(1) }))\n  .sort((a, b) => b.mb - a.mb)\n  .slice(0, 10)","note":"storageSize は圧縮後のディスク上のサイズ。stats() のコストは大きなコレクションでも低い。","danger":"safe"},"redis":{"command":"redis-cli --bigkeys\n# To rank by memory (bytes): redis-cli --memkeys","note":"どちらも SCAN でキースペース全体を走査する(サーバーはブロックしないが負荷は増える)。違いはメトリクスで、--bigkeys は型ごとに要素数/長さが最大のキーを、--memkeys は MEMORY USAGE によるメモリ消費量で報告する。単一キーには MEMORY USAGE <key> を使用する。","danger":"caution"}}},{"id":"free-space","title":"空き領域/使用率を確認","aliases":["free space","disk full","free space","usage","space left","tablespace usage","disk is full"],"engines":{"oracle":{"command":"SELECT df.tablespace_name,\n       ROUND(SUM(df.bytes)/1024/1024) AS total_mb,\n       ROUND(NVL(fs.free, 0)/1024/1024) AS free_mb,\n       ROUND((1 - NVL(fs.free,0)/SUM(df.bytes)) * 100, 1) AS pct_used\nFROM dba_data_files df\nLEFT JOIN (SELECT tablespace_name, SUM(bytes) free\n           FROM dba_free_space GROUP BY tablespace_name) fs\n  ON df.tablespace_name = fs.tablespace_name\nGROUP BY df.tablespace_name, fs.free;","note":"AUTOEXTEND が有効なファイルでは実際の上限は maxbytes。MAXSIZE は dba_data_files.maxbytes で確認する。","danger":"safe"},"postgres":{"command":"-- Datafile usage is at the OS level (df -h). Tablespace sizes from inside the DB:\nSELECT spcname, pg_size_pretty(pg_tablespace_size(spcname))\nFROM pg_tablespace;","note":"PostgreSQL はディスクの空き領域を OS に依存する。重要なしきい値には OS の監視(df)が不可欠。","danger":"safe"},"mysql":{"command":"SELECT table_schema,\n       ROUND(SUM(data_free)/1024/1024, 1) AS reclaimable_mb\nFROM information_schema.tables\nGROUP BY table_schema;","note":"data_free はテーブル内の再利用可能な(断片化した)領域。ディスクの空き領域は OS レベルの話。","danger":"safe"},"mssql":{"command":"SELECT name AS file_name,\n       size/128.0 AS size_mb,\n       size/128.0 - CAST(FILEPROPERTY(name,'SpaceUsed') AS int)/128.0 AS free_mb\nFROM sys.database_files;","note":"SpaceUsed はページ単位。128 で割ると MB になる(8 KB ページ)。","danger":"safe"},"mongodb":{"command":"var s = db.stats();\n({ fsTotalGB: +(s.fsTotalSize/1073741824).toFixed(1),\n   fsUsedGB:  +(s.fsUsedSize/1073741824).toFixed(1) })","note":"WiredTiger では fsTotalSize / fsUsedSize が OS レベルのディスクの合計サイズと使用サイズを示す。","danger":"safe"},"redis":{"command":"INFO memory\nCONFIG GET maxmemory\n# Usage = used_memory / maxmemory","note":"maxmemory が 0 の場合は上限なしで、RAM が埋まると OS の OOM killer が介入する。eviction の動作は maxmemory-policy で決まる。","danger":"safe"}}},{"id":"row-count","title":"行数/ドキュメント数を取得(高速)","aliases":["row count","count rows","row count","how many records","document count","how many rows"],"engines":{"oracle":{"command":"-- Statistics-based (fast, estimated):\nSELECT num_rows FROM dba_tables WHERE table_name = 'CUSTOMER';\n-- Exact: SELECT COUNT(*) FROM customer;","note":"num_rows は最後の ANALYZE/DBMS_STATS 実行時点の値。正確な値には COUNT(*) を使用する。","danger":"safe"},"postgres":{"command":"-- Estimated (instant):\nSELECT reltuples::bigint FROM pg_class WHERE relname = 'customer';\n-- Exact: SELECT count(*) FROM customer;","note":"reltuples は最後の ANALYZE/VACUUM 時点の推定値。大きなテーブルでの完全な COUNT は高コスト。","danger":"safe"},"mysql":{"command":"-- Estimated (InnoDB):\nSELECT table_rows FROM information_schema.tables\nWHERE table_name = 'customer';\n-- Exact: SELECT COUNT(*) FROM customer;","note":"InnoDB の table_rows は推定値で、最大 50% ずれることがある。","danger":"safe"},"mssql":{"command":"SELECT SUM(row_count) AS rows\nFROM sys.dm_db_partition_stats\nWHERE object_id = OBJECT_ID('dbo.customer')\n  AND index_id IN (0, 1);","note":"index_id 0(ヒープ)または 1(クラスタ化)で行数が得られる。COUNT(*) スキャンよりはるかに高速。","danger":"safe"},"mongodb":{"command":"// Fast (from metadata):\ndb.customer.estimatedDocumentCount()\n// Exact (can count with a filter): db.customer.countDocuments({})","note":"estimatedDocumentCount はメタデータを読む(即時)。countDocuments は実際にスキャンを行う。","danger":"safe"},"redis":{"command":"DBSIZE\n# Specific pattern: count roughly with SCAN (do not use KEYS * in production)","note":"DBSIZE は選択中のデータベースのキー総数を O(1) で返す。","danger":"safe"}}}]},"rosetta/performance.json":{"category":"パフォーマンス","categoryId":"performance","order":3,"concepts":[{"id":"top-slow-queries","title":"最も遅い/高コストなクエリを特定","aliases":["slow queries","top queries","slowest queries","top resource consumers","expensive queries","slowlog"],"engines":{"oracle":{"command":"SELECT sql_id,\n       ROUND(elapsed_time/1e6, 1) AS elapsed_sec,\n       executions,\n       ROUND(elapsed_time/1e6/NULLIF(executions,0), 3) AS sec_per_exec,\n       sql_text\nFROM v$sql\nORDER BY elapsed_time DESC\nFETCH FIRST 10 ROWS ONLY;","note":"履歴分析には AWR の dba_hist_sqlstat を使用する。sql_id があれば DBMS_XPLAN.DISPLAY_CURSOR で実行計画を表示できる。","danger":"safe"},"postgres":{"command":"SELECT calls,\n       ROUND(total_exec_time::numeric, 1) AS total_ms,\n       ROUND(mean_exec_time::numeric, 2) AS mean_ms,\n       query\nFROM pg_stat_statements\nORDER BY total_exec_time DESC\nLIMIT 10;","note":"pg_stat_statements 拡張(shared_preload_libraries)が必要。pg_stat_statements_reset() でリセットする。","danger":"safe"},"mysql":{"command":"SELECT digest_text,\n       count_star AS calls,\n       ROUND(sum_timer_wait/1e12, 2) AS total_sec,\n       ROUND(avg_timer_wait/1e9, 2) AS avg_ms\nFROM performance_schema.events_statements_summary_by_digest\nORDER BY sum_timer_wait DESC\nLIMIT 10;","note":"代替手段: slow_query_log = ON と long_query_time によるスロークエリログ。","danger":"safe"},"mssql":{"command":"SELECT TOP 10\n       qs.execution_count,\n       qs.total_elapsed_time/1000 AS total_ms,\n       qs.total_elapsed_time/qs.execution_count/1000 AS avg_ms,\n       SUBSTRING(t.text, 1, 200) AS sql_text\nFROM sys.dm_exec_query_stats qs\nCROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t\nORDER BY qs.total_elapsed_time DESC;","note":"Query Store が有効なら、より詳細な履歴分析に sys.query_store_runtime_stats を使用する。","danger":"safe"},"mongodb":{"command":"// Enable the profiler for operations over 100ms:\ndb.setProfilingLevel(1, { slowms: 100 })\n// Then read the slowest ones:\ndb.system.profile.find().sort({ millis: -1 }).limit(10)","note":"プロファイラは書き込みのオーバーヘッドを伴う。診断後は db.setProfilingLevel(0) で無効にする。","danger":"caution"},"redis":{"command":"SLOWLOG GET 10\n# Set the threshold (microseconds): CONFIG SET slowlog-log-slower-than 10000","note":"slowlog-log-slower-than はマイクロ秒単位(10000 = 10 ms)。SLOWLOG RESET でクリアする。","danger":"safe"}}},{"id":"explain-plan","title":"クエリの実行計画を取得(EXPLAIN)","aliases":["explain","execution plan","query plan","explain plan","show plan","explain analyze","why slow"],"engines":{"oracle":{"command":"EXPLAIN PLAN FOR\nSELECT * FROM customer WHERE city = 'Ankara';\nSELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);\n-- For the actual executed plan:\n-- SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('&sql_id', NULL, 'ALLSTATS LAST'));","note":"EXPLAIN PLAN は推定の実行計画を返す。実際の行数には DISPLAY_CURSOR + STATISTICS_LEVEL=ALL を使用する。","danger":"safe"},"postgres":{"command":"EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)\nSELECT * FROM customer WHERE city = 'Ankara';","note":"ANALYZE はクエリを実際に実行する(INSERT/UPDATE/DELETE では注意。トランザクション内で試して ROLLBACK する)。","danger":"caution"},"mysql":{"command":"EXPLAIN ANALYZE\nSELECT * FROM customer WHERE city = 'Ankara';\n-- Estimate only (does not execute): EXPLAIN FORMAT=JSON SELECT ...;","note":"EXPLAIN ANALYZE(MySQL 8.0.18+)はクエリを実行する。FORMAT=JSON は実行せずに詳細を返す。","danger":"caution"},"mssql":{"command":"SET STATISTICS PROFILE ON;\nSELECT * FROM dbo.customer WHERE city = 'Ankara';\nSET STATISTICS PROFILE OFF;\n-- Estimated plan only (does not execute):\n-- SET SHOWPLAN_XML ON;","note":"SSMS では「Include Actual Execution Plan」(Ctrl+M)でグラフィカルな実行計画を表示できる。","danger":"caution"},"mongodb":{"command":"db.customer.find({ city: \"Ankara\" }).explain(\"executionStats\")","note":"executionStats は実際に返されたドキュメント数とインデックスの使用状況(IXSCAN vs COLLSCAN)を示す。","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no query planner.\n# The complexity of each command is documented (e.g. GET O(1), SORT O(N+M*log(M))).","note":"パフォーマンスはコマンドの計算量とキー/データ構造のサイズで決まる。SLOWLOG で計測する。","danger":"safe"}}},{"id":"unused-indexes","title":"未使用のインデックスを検出","aliases":["unused indexes","unused index","redundant index","index usage","drop index candidate"],"engines":{"oracle":{"command":"-- Start monitoring:\nALTER INDEX customer_city_idx MONITORING USAGE;\n-- Check after a while (12c+, all schemas):\nSELECT owner, index_name, used FROM dba_object_usage;","note":"USED = NO なら、そのインデックスは監視期間中に使用されていない。監視は NOMONITORING USAGE で無効にする。旧来の v$object_usage はセッションユーザーのインデックスのみを表示し、12c 以降は非推奨。12.2+ ではインデックスの使用状況が DBA_INDEX_USAGE で自動的に追跡される。","danger":"safe"},"postgres":{"command":"SELECT relname AS table, indexrelname AS index, idx_scan\nFROM pg_stat_user_indexes\nWHERE idx_scan = 0\nORDER BY relname;","note":"idx_scan = 0 は、統計が最後にリセットされて以降そのインデックスが使われていないことを意味する。UNIQUE/PK インデックスは削除しないこと。","danger":"safe"},"mysql":{"command":"SELECT * FROM sys.schema_unused_indexes;","note":"performance_schema が有効で、サーバーがしばらく稼働している必要がある。UNIQUE 制約は除外される。","danger":"safe"},"mssql":{"command":"SELECT OBJECT_NAME(i.object_id) AS table_name, i.name AS index_name\nFROM sys.indexes i\nLEFT JOIN sys.dm_db_index_usage_stats s\n  ON i.object_id = s.object_id AND i.index_id = s.index_id\n  AND s.database_id = DB_ID()\nWHERE i.type_desc = 'NONCLUSTERED'\n  AND COALESCE(s.user_seeks + s.user_scans + s.user_lookups, 0) = 0;","note":"usage_stats はサーバー再起動時にリセットされる。十分な観測期間を確保すること。","danger":"safe"},"mongodb":{"command":"db.customer.aggregate([{ $indexStats: {} }])\n// Indexes with low/0 accesses.ops are candidates","note":"accesses.ops は accesses.since のタイムスタンプ以降のアクセス数をカウントする。_id インデックスは削除できない。","danger":"safe"},"redis":{"command":"# Not applicable: core Redis has no secondary indexes.\n# If the RediSearch module is used, check statistics with FT.INFO <index>.","note":"データモデルがキーバリューのため、従来のインデックスの概念はない。","danger":"safe"}}},{"id":"cache-hit-ratio","title":"キャッシュヒット率を計測","aliases":["cache hit ratio","buffer cache","cache hit","hit ratio","buffer pool hit"],"engines":{"oracle":{"command":"SELECT metric_name, ROUND(value, 2) AS pct\nFROM v$sysmetric\nWHERE metric_name = 'Buffer Cache Hit Ratio'\n  AND intsize_csec = (SELECT MAX(intsize_csec) FROM v$sysmetric);","note":"低い比率が常に悪いとは限らない。単独ではなくワークロードの文脈で解釈すること。","danger":"safe"},"postgres":{"command":"SELECT ROUND(sum(blks_hit) * 100.0 / NULLIF(sum(blks_hit) + sum(blks_read), 0), 2) AS cache_hit_pct\nFROM pg_stat_database;","note":"通常は 99% 以上が目標。低い場合は shared_buffers と OS キャッシュを見直す。","danger":"safe"},"mysql":{"command":"SELECT ROUND((1 - (\n    (SELECT variable_value FROM performance_schema.global_status WHERE variable_name='Innodb_buffer_pool_reads') /\n    (SELECT variable_value FROM performance_schema.global_status WHERE variable_name='Innodb_buffer_pool_read_requests')\n  )) * 100, 2) AS buffer_pool_hit_pct;","note":"reads はディスクからの読み取り、read_requests は読み取りの総数。低い場合は innodb_buffer_pool_size を増やす。","danger":"safe"},"mssql":{"command":"SELECT ROUND(\n  100.0 * (SELECT cntr_value FROM sys.dm_os_performance_counters WHERE counter_name='Buffer cache hit ratio')\n        / NULLIF((SELECT cntr_value FROM sys.dm_os_performance_counters WHERE counter_name='Buffer cache hit ratio base'), 0), 2) AS pct;","note":"最新の SQL Server では、Page Life Expectancy (PLE) のほうがメモリ圧迫の指標として有意義。","danger":"safe"},"mongodb":{"command":"var c = db.serverStatus().wiredTiger.cache;\n({ configuredMB: +(c['maximum bytes configured']/1048576).toFixed(0),\n   inCacheMB:    +(c['bytes currently in the cache']/1048576).toFixed(0),\n   readIntoCache: c['pages read into cache'],\n   evictedPages:  c['unmodified pages evicted'] })","note":"「pages read into cache」と eviction が多い場合は、WiredTiger キャッシュが小さすぎることを示す。","danger":"safe"},"redis":{"command":"INFO stats\n# keyspace_hits / (keyspace_hits + keyspace_misses) = hit ratio","note":"ヒット率が継続的に低い場合は、TTL/eviction の設定またはアクセスパターンの見直しが必要。","danger":"safe"}}}]},"rosetta/backup.json":{"category":"バックアップとリカバリ","categoryId":"backup","order":4,"concepts":[{"id":"logical-dump","title":"論理バックアップ(ダンプ)を取得","aliases":["backup","dump","export","take backup","logical dump","logical backup","pg_dump","mysqldump","mongodump"],"engines":{"oracle":{"command":"expdp system/password DIRECTORY=dpump_dir \\\n  SCHEMAS=hr DUMPFILE=hr_%U.dmp LOGFILE=hr_exp.log PARALLEL=4","note":"Data Pump を使用する。DIRECTORY オブジェクトは事前に CREATE DIRECTORY で定義しておく必要がある。物理バックアップには RMAN を使用する。","danger":"safe"},"postgres":{"command":"pg_dump -U postgres -h localhost -Fc -f db.dump mydb\n# -Fc = compressed custom format (restored with pg_restore)","note":"-Fc は柔軟なリストア(テーブル選択/並列)を可能にする。クラスタ全体(ロールを含む)には pg_dumpall を使用する。","danger":"safe"},"mysql":{"command":"mysqldump -u root -p --single-transaction \\\n  --routines --triggers --events mydb > db.sql","note":"--single-transaction により InnoDB でロックなしの一貫性のあるバックアップを取得できる。大容量データ向けの並列オプション: mydumper/myloader または MySQL Shell の util.dumpInstance()/dumpSchemas()(mysqlpump は 8.0.34 で非推奨となり 8.4 で削除)。","danger":"safe"},"mssql":{"command":"BACKUP DATABASE [MyDB]\nTO DISK = N'C:\\backup\\MyDB_full.bak'\nWITH COMPRESSION, CHECKSUM, INIT;","note":"INIT は既存ファイルを上書きする。追記するには NOINIT を使用する。ログバックアップには BACKUP LOG を使用する(FULL 復旧モデル)。","danger":"safe"},"mongodb":{"command":"mongodump --uri=\"mongodb://localhost:27017\" \\\n  --archive=db.archive.gz --gzip --db=mydb","note":"シャードクラスタでは、一貫性のためにバランサーを停止したうえで mongos 経由で取得する。","danger":"safe"},"redis":{"command":"BGSAVE\n# Takes an RDB snapshot in the background (dump.rdb).\n# Non-blocking copy: redis-cli --rdb /backup/dump.rdb","note":"BGSAVE は fork によりバックグラウンドで実行される。SAVE はサーバーをブロックする(本番環境では使用しない)。AOF を有効にすると失われるデータが少なくなる。","danger":"safe"}}},{"id":"restore-dump","title":"バックアップからリストア","aliases":["restore","import","restore backup","restore from backup","recover","pg_restore","mongorestore"],"engines":{"oracle":{"command":"impdp system/password DIRECTORY=dpump_dir \\\n  SCHEMAS=hr DUMPFILE=hr_%U.dmp LOGFILE=hr_imp.log","note":"別のスキーマへのロードには REMAP_SCHEMA、別の表領域には REMAP_TABLESPACE を使用する。","danger":"danger"},"postgres":{"command":"# custom format:\npg_restore -U postgres -d target_db --clean --if-exists db.dump\n# plain SQL: psql -U postgres -d target_db -f db.sql","note":"--clean は既存オブジェクトを削除する。並列リストアには -j <n> を使用する。","danger":"danger"},"mysql":{"command":"mysql -u root -p target_db < db.sql","note":"ターゲットデータベースは事前に存在している必要がある(CREATE DATABASE)。大きなファイルには source コマンドが推奨される。","danger":"danger"},"mssql":{"command":"RESTORE DATABASE [MyDB]\nFROM DISK = N'C:\\backup\\MyDB_full.bak'\nWITH REPLACE, RECOVERY;","note":"ポイントインタイムリカバリでは、フルバックアップを WITH NORECOVERY でリストアし、その後 STOPAT 付きでログバックアップを適用する。","danger":"danger"},"mongodb":{"command":"mongorestore --uri=\"mongodb://localhost:27017\" \\\n  --archive=db.archive.gz --gzip --drop","note":"--drop はリストア前にターゲットのコレクションを削除する。選択的リストアには --nsInclude を使用する。","danger":"danger"},"redis":{"command":"# 1) Stop Redis   2) Copy dump.rdb to the 'dir' location\n# 3) Start Redis (the RDB is loaded automatically at startup)\nredis-cli CONFIG GET dir   # find the target directory","note":"AOF が有効な場合は RDB ではなく AOF がロードされる。RDB からリストアするには appendonly no で起動するか、AOF を再構築する。","danger":"danger"}}},{"id":"last-backup-status","title":"最終バックアップの状態/時刻を確認","aliases":["last backup","backup status","when was the last backup","backup state","backup history","rpo"],"engines":{"oracle":{"command":"SELECT session_key, input_type, status,\n       start_time, end_time,\n       output_bytes_display\nFROM v$rman_backup_job_details\nORDER BY start_time DESC\nFETCH FIRST 10 ROWS ONLY;","note":"RMAN の履歴は RMAN> LIST BACKUP SUMMARY でも確認できる。","danger":"safe"},"postgres":{"command":"-- WAL archiving health (for physical backup/PITR):\nSELECT last_archived_wal, last_archived_time,\n       failed_count, last_failed_time\nFROM pg_stat_archiver;","note":"論理バックアップ(pg_dump)は DB 内に記録されない。バックアップツール/ジョブのログを確認する。","danger":"safe"},"mysql":{"command":"-- There is no built-in backup record; check the backup tool's log.\n-- For the binlog-based PITR window:\nSHOW BINARY LOGS;","note":"SHOW BINARY LOGS は利用可能な binlog ファイル(PITR の範囲)を示す。バックアップ履歴はツール(Xtrabackup など)のログにある。","danger":"safe"},"mssql":{"command":"SELECT database_name,\n       MAX(backup_finish_date) AS last_backup,\n       CASE type WHEN 'D' THEN 'Full' WHEN 'I' THEN 'Diff'\n                 WHEN 'L' THEN 'Log' END AS backup_type\nFROM msdb.dbo.backupset\nGROUP BY database_name, type\nORDER BY database_name;","note":"msdb.dbo.backupset には SQL Server が取得したすべてのバックアップが記録される。","danger":"safe"},"mongodb":{"command":"// There is no built-in backup record. PITR window = oplog duration:\nrs.printReplicationInfo()  // oplog first/last event times","note":"oplog の範囲によって、レプリカセットからどこまで遡って PITR できるかが決まる。バックアップ履歴はツールのログにある。","danger":"safe"},"redis":{"command":"INFO persistence\n# check the rdb_last_save_time (epoch), rdb_last_bgsave_status,\n# aof_last_bgrewrite_status lines","note":"rdb_last_save_time は最後に成功した RDB 保存の時刻(Unix エポック)、rdb_changes_since_last_save はまだバックアップされていない書き込み数を示す。","danger":"safe"}}}]},"rosetta/security.json":{"category":"ユーザーと権限","categoryId":"security","order":5,"concepts":[{"id":"list-users","title":"ユーザー/ロールを一覧表示","aliases":["list users","show users","list users","roles","who has access","accounts"],"engines":{"oracle":{"command":"SELECT username, account_status, default_tablespace, created\nFROM dba_users\nORDER BY username;","note":"account_status は LOCKED/EXPIRED の状態を示す。ロールには dba_roles を使用する。","danger":"safe"},"postgres":{"command":"SELECT rolname, rolsuper, rolcanlogin, rolvaliduntil\nFROM pg_roles\nORDER BY rolname;\n-- Shortcut (psql): \\du","note":"PostgreSQL のユーザーは LOGIN 属性を持つロール。rolcanlogin で区別する。","danger":"safe"},"mysql":{"command":"SELECT user, host, account_locked, password_expired\nFROM mysql.user\nORDER BY user;","note":"MySQL のアカウントはユーザー + ホストの組('app'@'%' と 'app'@'localhost' は別物)。","danger":"safe"},"mssql":{"command":"-- Server logins:\nSELECT name, type_desc, is_disabled FROM sys.server_principals\nWHERE type IN ('S','U','G');\n-- Database users:\nSELECT name, type_desc FROM sys.database_principals\nWHERE type IN ('S','U','G');","note":"ログインはサーバーレベル、ユーザーはデータベースレベル。両者は SID で対応付けられる。","danger":"safe"},"mongodb":{"command":"// Users in the current database:\ndb.getUsers()\n// All users in the system: use admin; db.system.users.find({}, {user:1, db:1, roles:1})","note":"ユーザーは作成されたデータベース(authenticationDatabase)で定義される。","danger":"safe"},"redis":{"command":"ACL LIST\n# Names only: ACL USERS\n# Your own identity: ACL WHOAMI","note":"Redis 6+ の ACL システム。それ以前は単一の 'default' ユーザーと requirepass のみだった。","danger":"safe"}}},{"id":"create-user-grant","title":"ユーザーを作成して権限を付与","aliases":["create user","grant","add user","create user","grant privilege","grant permission","new user"],"engines":{"oracle":{"command":"CREATE USER app IDENTIFIED BY \"Strong#Pass1\";\nGRANT CREATE SESSION TO app;\nGRANT SELECT, INSERT, UPDATE ON hr.employee TO app;","note":"CREATE SESSION がないとユーザーは接続できない。クォータの設定: ALTER USER app QUOTA 100M ON users;","danger":"caution"},"postgres":{"command":"CREATE ROLE app LOGIN PASSWORD 'Strong#Pass1';\nGRANT CONNECT ON DATABASE mydb TO app;\nGRANT USAGE ON SCHEMA public TO app;\nGRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA public TO app;","note":"今後作成されるテーブルの場合: ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO app;","danger":"caution"},"mysql":{"command":"CREATE USER 'app'@'%' IDENTIFIED BY 'Strong#Pass1';\nGRANT SELECT, INSERT, UPDATE ON mydb.* TO 'app'@'%';","note":"'%' は任意のホストからの接続を許可する。セキュリティのため、可能な限り特定の IP/ホストを指定する。CREATE USER/GRANT は即座に反映される。FLUSH PRIVILEGES が必要なのは権限テーブルに直接 DML を実行した場合のみ。","danger":"caution"},"mssql":{"command":"CREATE LOGIN app WITH PASSWORD = 'Strong#Pass1';\nUSE mydb;\nCREATE USER app FOR LOGIN app;\nGRANT SELECT, INSERT, UPDATE ON SCHEMA::dbo TO app;","note":"ログインはサーバー全体で有効、ユーザーは各データベースで個別に作成する。ロールの場合: ALTER ROLE db_datareader ADD MEMBER app;","danger":"caution"},"mongodb":{"command":"db.createUser({\n  user: \"app\",\n  pwd: \"Strong#Pass1\",\n  roles: [ { role: \"readWrite\", db: \"mydb\" } ]\n})","note":"ユーザーを作成した db がその認証 db になる。組み込みロール: read、readWrite、dbAdmin、clusterAdmin...","danger":"caution"},"redis":{"command":"ACL SETUSER app on >Strong#Pass1 ~app:* +@read +@write\n# To persist: ACL SAVE if an aclfile is defined, otherwise CONFIG REWRITE (users are written to redis.conf)","note":"on = 有効、>password はパスワードを追加、~app:* はキーパターン、+@read/+@write はコマンドカテゴリ。永続化しないと再起動で失われる。ACL SAVE は aclfile が設定されている場合のみ動作し、それ以外はエラーを返す。その場合は CONFIG REWRITE を使用する。","danger":"caution"}}},{"id":"show-privileges","title":"ユーザーの権限を表示","aliases":["show grants","privileges","show privileges","who can access what","permissions","roles of user"],"engines":{"oracle":{"command":"SELECT privilege FROM dba_sys_privs WHERE grantee = 'APP'\nUNION ALL SELECT granted_role FROM dba_role_privs WHERE grantee = 'APP'\nUNION ALL SELECT privilege||' ON '||owner||'.'||table_name\n          FROM dba_tab_privs WHERE grantee = 'APP';","note":"grantee は大文字で格納される。ロール経由で付与された間接的な権限は role_role_privs も辿る。","danger":"safe"},"postgres":{"command":"SELECT grantee, table_schema, table_name, privilege_type\nFROM information_schema.role_table_grants\nWHERE grantee = 'app';\n-- Role memberships (direct): \\drg app (PG16+; earlier \\du app)","note":"ロールのメンバーシップ(継承)は pg_auth_members に格納される。\\du/\\drg は直接のメンバーシップのみを表示するため、間接的なメンバーシップには pg_has_role('app', '<role>', 'MEMBER') を使用する。","danger":"safe"},"mysql":{"command":"SHOW GRANTS FOR 'app'@'%';","note":"ロール(MySQL 8)の場合は、先に SET ROLE ALL を実行するか、SHOW GRANTS FOR 'app'@'%' USING 'role_name'; を使用する。","danger":"safe"},"mssql":{"command":"SELECT dp.name AS principal, p.permission_name,\n       p.state_desc, o.name AS object\nFROM sys.database_permissions p\nJOIN sys.database_principals dp ON p.grantee_principal_id = dp.principal_id\nLEFT JOIN sys.objects o ON p.major_id = o.object_id\nWHERE dp.name = 'app';","note":"ロール経由で付与された権限は、sys.database_role_members のメンバーシップも確認する。","danger":"safe"},"mongodb":{"command":"db.getUser(\"app\", { showPrivileges: true, showCredentials: false })","note":"showPrivileges はロールの展開された(実効)権限も一覧表示する。","danger":"safe"},"redis":{"command":"ACL GETUSER app","note":"許可されたコマンド、キーパターン(~)、pub/sub チャネル(&)、パスワードハッシュを返す。","danger":"safe"}}},{"id":"change-password","title":"ユーザーのパスワードを変更","aliases":["change password","reset password","change password","reset password","alter password"],"engines":{"oracle":{"command":"ALTER USER app IDENTIFIED BY \"New#Pass2\";","note":"ロックされたアカウントのロック解除: ALTER USER app ACCOUNT UNLOCK; パスワードが期限切れの場合も同じコマンドでリセットされる。","danger":"caution"},"postgres":{"command":"ALTER ROLE app WITH PASSWORD 'New#Pass2';","note":"パスワードをログに残さないために、\\password app(psql)メタコマンドはクライアント側でパスワードをハッシュ化する。","danger":"caution"},"mysql":{"command":"ALTER USER 'app'@'%' IDENTIFIED BY 'New#Pass2';","note":"正しいホストを選択すること。'app'@'localhost' は別のアカウント。ALTER USER は即座に反映され、FLUSH PRIVILEGES は不要。","danger":"caution"},"mssql":{"command":"ALTER LOGIN app WITH PASSWORD = 'New#Pass2';\n-- For a user changing their own password: add OLD_PASSWORD","note":"MUST_CHANGE で初回ログイン時の変更を強制できる: WITH PASSWORD='...' MUST_CHANGE, CHECK_POLICY=ON.","danger":"caution"},"mongodb":{"command":"db.changeUserPassword(\"app\", \"New#Pass2\")","note":"ユーザーの認証データベースに切り替えていること(use mydb)を確認する。","danger":"caution"},"redis":{"command":"# Clear old passwords and set the new one:\nACL SETUSER app resetpass >New#Pass2\n# Persistence: ACL SAVE if an aclfile is defined, otherwise CONFIG REWRITE","note":"resetpass は既存のパスワードをすべて削除する。> は追加するだけ。永続化するには、aclfile を使用している場合は ACL SAVE、ユーザーが redis.conf で定義されている場合は CONFIG REWRITE を実行する(aclfile がないと ACL SAVE はエラーを返す)。","danger":"caution"}}}]},"rosetta/maintenance.json":{"category":"メンテナンスと管理","categoryId":"maintenance","order":6,"concepts":[{"id":"update-statistics","title":"統計を更新(オプティマイザ用)","aliases":["update statistics","analyze","update stats","gather stats","optimizer stats","analyze for planner"],"engines":{"oracle":{"command":"EXEC DBMS_STATS.GATHER_TABLE_STATS('HR', 'EMPLOYEE');\n-- Whole schema: EXEC DBMS_STATS.GATHER_SCHEMA_STATS('HR');","note":"通常は AUTO タスクが夜間に収集する。問題発生時は手動で収集する。ESTIMATE_PERCENT=>AUTO_SAMPLE_SIZE が推奨。","danger":"safe"},"postgres":{"command":"ANALYZE customer;\n-- Both cleanup and analyze: VACUUM ANALYZE customer;","note":"autovacuum が自動で行う。急なデータロードの後に手動で ANALYZE を実行すると正確な実行計画が得られる。","danger":"safe"},"mysql":{"command":"ANALYZE TABLE customer;","note":"InnoDB では短時間の読み取りロックを取得する。大きなテーブルでは負荷の低い時間帯に実行する。","danger":"safe"},"mssql":{"command":"UPDATE STATISTICS dbo.customer WITH FULLSCAN;\n-- Whole database: EXEC sp_updatestats;","note":"FULLSCAN は最も正確だが最も高コスト。大きなテーブルではサンプリング(SAMPLE)が好ましい場合がある。","danger":"safe"},"mongodb":{"command":"// There are no manual statistics; the planner measures at runtime.\n// To clear a stale plan cache:\ndb.customer.getPlanCache().clear()","note":"MongoDB はコスト見積もりの代わりに実際の試行(plan racing)を行う。手動での統計は不要。","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no query optimizer / statistics.","note":"コマンドの計算量は固定。パフォーマンスはデータ構造の選択に依存する。","danger":"safe"}}},{"id":"rebuild-index","title":"インデックスを再構築/再編成","aliases":["rebuild index","reindex","refresh index","reorganize","index maintenance","defrag index"],"engines":{"oracle":{"command":"ALTER INDEX customer_city_idx REBUILD ONLINE;","note":"ONLINE はテーブルをロックせずに再構築する(Enterprise Edition)。別の表領域へ移動するには: ... REBUILD TABLESPACE new_ts.","danger":"caution"},"postgres":{"command":"REINDEX INDEX CONCURRENTLY customer_city_idx;\n-- Whole table: REINDEX TABLE CONCURRENTLY customer;","note":"CONCURRENTLY(PG 12+)はテーブルへの書き込みをブロックせずに再構築する。低速だが安全。","danger":"caution"},"mysql":{"command":"-- Rebuild InnoDB indexes + table:\nALTER TABLE customer ENGINE=InnoDB, ALGORITHM=INPLACE, LOCK=NONE;\n-- Alternative: OPTIMIZE TABLE customer;","note":"LOCK=NONE は同時書き込みを許可する。すべての ALTER で INPLACE が可能とは限らない。","danger":"caution"},"mssql":{"command":"-- Rebuild for high fragmentation:\nALTER INDEX ALL ON dbo.customer REBUILD WITH (ONLINE = ON);\n-- Lighter option for low fragmentation:\n-- ALTER INDEX ALL ON dbo.customer REORGANIZE;","note":"一般的なしきい値: 断片化 5-30% なら REORGANIZE、>30% なら REBUILD。ONLINE は Enterprise の機能。","danger":"caution"},"mongodb":{"command":"db.customer.reIndex()","note":"フォアグラウンドですべてのインデックスを再構築し、コレクションをロックする。6.0+ ではスタンドアロンでのみ実行可能(レプリカセットのメンバーでは不可)。レプリカセットでは、dropIndex + createIndex で単一のインデックスをノードごとに(ローリング)再構築する。","danger":"danger"},"redis":{"command":"# Not applicable (core). If RediSearch is used:\n# FT.ALTER / rebuilding is done per the module documentation.","note":"キーバリューモデルには従来のインデックスメンテナンスがない。","danger":"safe"}}},{"id":"reclaim-space","title":"空き領域を回収(shrink / vacuum / compact)","aliases":["reclaim space","vacuum","shrink","compact","free up space","clean up bloat","bloat"],"engines":{"oracle":{"command":"ALTER TABLE customer ENABLE ROW MOVEMENT;\nALTER TABLE customer SHRINK SPACE;","note":"SHRINK は高水位標(HWM)を下げる。インデックスも縮小するには SHRINK SPACE CASCADE を使用する。","danger":"caution"},"postgres":{"command":"-- Online, light locking (does not return space to the OS):\nVACUUM (VERBOSE, ANALYZE) customer;\n-- Return space to the OS (locks the table!):\n-- VACUUM FULL customer;","note":"VACUUM FULL は AccessExclusiveLock を取得してテーブルを書き直す。ピーク時間帯には実行しないこと。代替手段: pg_repack。","danger":"caution"},"mysql":{"command":"OPTIMIZE TABLE customer;","note":"InnoDB ではテーブルを再構築して data_free の領域を返却する。大きなテーブルでは長時間かかる。","danger":"caution"},"mssql":{"command":"-- Generally NOT RECOMMENDED (causes fragmentation). If really needed:\nDBCC SHRINKFILE (N'MyDB_data', 1024);  -- target 1024 MB","note":"データファイルの縮小はインデックスの断片化を引き起こす。その後にインデックスを REBUILD する。ログの場合は先にバックアップを取得する。","danger":"danger"},"mongodb":{"command":"db.runCommand({ compact: \"customer\" })","note":"WiredTiger では空き領域を OS に返却しようとする(常に可能とは限らない)。4.4+ では読み取り/書き込みはブロックせず、同じコレクションに対する一部の DDL 操作のみをブロックする。IO 負荷が高いため、セカンダリ上でメンテナンスウィンドウに実行するほうが安全。","danger":"danger"},"redis":{"command":"MEMORY PURGE\n# Tries to return jemalloc fragmentation to the OS","note":"activedefrag yes の設定でオンラインの自動デフラグが行われる。MEMORY DOCTOR は推奨事項を示す。","danger":"caution"}}},{"id":"version-uptime","title":"バージョンと稼働時間を表示","aliases":["version","uptime","server version","how long has it been running","server version","days since startup"],"engines":{"oracle":{"command":"SELECT banner_full FROM v$version;\nSELECT startup_time, ROUND(SYSDATE - startup_time, 1) AS up_days\nFROM v$instance;","note":"v$instance は status や host_name などのインスタンス情報も提供する。","danger":"safe"},"postgres":{"command":"SELECT version();\nSELECT pg_postmaster_start_time() AS started,\n       now() - pg_postmaster_start_time() AS uptime;","note":"server_version_num は数値比較に便利(例: 160002 = 16.2)。","danger":"safe"},"mysql":{"command":"SELECT VERSION();\nSHOW GLOBAL STATUS LIKE 'Uptime';  -- seconds","note":"Uptime は秒単位。86400 で割ると日数になる。","danger":"safe"},"mssql":{"command":"SELECT @@VERSION;\nSELECT sqlserver_start_time,\n       DATEDIFF(DAY, sqlserver_start_time, GETDATE()) AS up_days\nFROM sys.dm_os_sys_info;","note":"SERVERPROPERTY('ProductVersion') と ('Edition') でバージョン/エディションの詳細が得られる。","danger":"safe"},"mongodb":{"command":"db.version()\ndb.serverStatus().uptime   // seconds","note":"serverStatus() には host、process、connections の情報も含まれる。","danger":"safe"},"redis":{"command":"INFO server\n# redis_version and uptime_in_seconds / uptime_in_days lines","note":"INFO server は os、run_id、tcp_port の情報も提供する。","danger":"safe"}}},{"id":"show-config-param","title":"構成パラメータを表示","aliases":["show config","parameter","show setting","config parameter","setting","memory setting","variable"],"engines":{"oracle":{"command":"SHOW PARAMETER sga_target;\n-- or: SELECT name, value, isdefault FROM v$parameter WHERE name = 'sga_target';","note":"変更するには: ALTER SYSTEM SET ... SCOPE=BOTH;(一部は SCOPE=SPFILE + 再起動でのみ)。","danger":"safe"},"postgres":{"command":"SHOW shared_buffers;\n-- Details: SELECT name, setting, unit, context FROM pg_settings WHERE name = 'shared_buffers';","note":"context 列は、変更に再起動とリロード(SELECT pg_reload_conf())のどちらが必要かを示す。","danger":"safe"},"mysql":{"command":"SHOW VARIABLES LIKE 'innodb_buffer_pool_size';","note":"GLOBAL と SESSION の違いに注意: SHOW GLOBAL VARIABLES はサーバー全体の値を示す。","danger":"safe"},"mssql":{"command":"SELECT name, value, value_in_use, is_dynamic\nFROM sys.configurations\nWHERE name LIKE '%max server memory%';","note":"変更するには: sp_configure + RECONFIGURE。is_dynamic=0 のオプションは再起動が必要。","danger":"safe"},"mongodb":{"command":"db.adminCommand({ getParameter: 1, cursorTimeoutMillis: 1 })\n// All startup options: db.adminCommand({ getCmdLineOpts: 1 })","note":"実行時に変更可能なものには setParameter を使用する。永続的な設定は mongod.conf ファイルにある。","danger":"safe"},"redis":{"command":"CONFIG GET maxmemory\n# Wildcard: CONFIG GET max*","note":"実行時の変更には CONFIG SET、永続化には CONFIG REWRITE を使用する(redis.conf に書き込む)。","danger":"safe"}}}]},"rosetta/schema.json":{"category":"スキーマとオブジェクト","categoryId":"schema","order":7,"concepts":[{"id":"list-tables","title":"テーブル/コレクションを一覧表示","aliases":["list tables","show tables","list all tables","table list","list collections","collections","which tables exist"],"engines":{"oracle":{"command":"SELECT table_name FROM user_tables ORDER BY table_name;\n-- All schemas: SELECT owner, table_name FROM dba_tables ORDER BY owner, table_name;","note":"user_tables は現在のスキーマのテーブル、all_tables はアクセス可能なテーブルを返す。","danger":"safe"},"postgres":{"command":"SELECT table_schema, table_name\nFROM information_schema.tables\nWHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog','information_schema')\nORDER BY 1, 2;\n-- psql shortcut: \\dt *.*","note":"public スキーマのみの場合: WHERE table_schema = 'public'.","danger":"safe"},"mysql":{"command":"SHOW TABLES;\n-- Another schema: SHOW TABLES FROM mydb;","note":"詳細: SELECT table_name, table_rows FROM information_schema.tables WHERE table_schema = DATABASE();","danger":"safe"},"mssql":{"command":"SELECT s.name AS schema_name, t.name AS table_name\nFROM sys.tables t\nJOIN sys.schemas s ON t.schema_id = s.schema_id\nORDER BY s.name, t.name;","note":"ショートカット: SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE';","danger":"safe"},"mongodb":{"command":"show collections\n// or: db.getCollectionNames()","note":"システムコレクションも表示するには: db.getCollectionInfos().","danger":"safe"},"redis":{"command":"SCAN 0 MATCH * COUNT 100\n# Continue with SCAN <cursor> ... using the returned cursor","note":"Redis には「テーブル」がなく、キーを一覧表示する。本番環境では KEYS * を絶対に使用しないこと(ブロックする)。SCAN はカーソルベース。","danger":"caution"}}},{"id":"describe-table","title":"テーブルの列/構造を表示(describe)","aliases":["describe","desc table","columns","table columns","table structure","show schema","field types","fields"],"engines":{"oracle":{"command":"SELECT column_name, data_type, data_length, nullable\nFROM user_tab_columns\nWHERE table_name = 'EMPLOYEE'\nORDER BY column_id;\n-- Shortcut (SQL*Plus): DESC employee","note":"テーブル名は(引用符なしで作成した場合)大文字で格納される。","danger":"safe"},"postgres":{"command":"SELECT column_name, data_type, is_nullable, column_default\nFROM information_schema.columns\nWHERE table_name = 'customer'\nORDER BY ordinal_position;\n-- psql shortcut: \\d customer","note":"\\d はインデックス、制約、外部キーも表示する。","danger":"safe"},"mysql":{"command":"DESCRIBE customer;\n-- or: SHOW COLUMNS FROM customer;","note":"完全な定義には SHOW CREATE TABLE customer; を使用する(下記の「DDL を生成」を参照)。","danger":"safe"},"mssql":{"command":"SELECT c.name, t.name AS type, c.max_length, c.is_nullable\nFROM sys.columns c\nJOIN sys.types t ON c.user_type_id = t.user_type_id\nWHERE c.object_id = OBJECT_ID('dbo.customer')\nORDER BY c.column_id;\n-- Shortcut: EXEC sp_help 'dbo.customer';","note":"sp_help は列に加えてインデックスと制約も一覧表示する。","danger":"safe"},"mongodb":{"command":"// The schema is flexible; infer it from a sample document:\ndb.customer.findOne()\n// For field coverage: db.customer.aggregate([{ $sample: { size: 100 } }])","note":"MongoDB には固定スキーマがなく、フィールドはドキュメントごとに異なり得る。$jsonSchema バリデータが定義されていれば db.getCollectionInfos で確認できる。","danger":"safe"},"redis":{"command":"TYPE mykey        # string | list | set | hash | zset | stream\nOBJECT ENCODING mykey   # internal encoding","note":"固定スキーマはなく、各キーの型とエンコーディングは個別に照会する。ハッシュのフィールドには HGETALL を使用する。","danger":"safe"}}},{"id":"list-indexes","title":"テーブルのインデックスを一覧表示","aliases":["list indexes","show indexes","show table indexes","which indexes","table indexes","getindexes"],"engines":{"oracle":{"command":"SELECT index_name, column_name, column_position\nFROM user_ind_columns\nWHERE table_name = 'EMPLOYEE'\nORDER BY index_name, column_position;","note":"インデックスのタイプ/一意性は user_indexes と結合して取得する。","danger":"safe"},"postgres":{"command":"SELECT indexname, indexdef\nFROM pg_indexes\nWHERE tablename = 'customer';","note":"indexdef は完全な CREATE INDEX 文を返す。psql の \\d customer でも一覧表示できる。","danger":"safe"},"mysql":{"command":"SHOW INDEX FROM customer;","note":"Non_unique、Seq_in_index、Cardinality 列はインデックスの構造と選択性を示す。","danger":"safe"},"mssql":{"command":"EXEC sp_helpindex 'dbo.customer';\n-- Details: join sys.indexes + sys.index_columns","note":"sp_helpindex はインデックス名、タイプ、列を返す。フィルタ付き/付加列には sys ビューを使用する。","danger":"safe"},"mongodb":{"command":"db.customer.getIndexes()","note":"各インデックスのキーと、一意性や TTL/partial などのオプションを返す。","danger":"safe"},"redis":{"command":"# Not applicable (core). If the RediSearch module is present:\n# FT._LIST        (all indexes)\n# FT.INFO idx     (details of one index)","note":"キーバリューモデルにはセカンダリインデックスがない。RediSearch/RedisJSON などのモジュールでのみ提供される。","danger":"safe"}}},{"id":"create-index","title":"インデックスを作成","aliases":["create index","add index","build index","new index","createindex"],"engines":{"oracle":{"command":"CREATE INDEX customer_city_idx ON customer(city) ONLINE;","note":"ONLINE はテーブルをロックせずに作成する。一意インデックスは CREATE UNIQUE INDEX、複合インデックスは (a, b) を使用する。","danger":"caution"},"postgres":{"command":"CREATE INDEX CONCURRENTLY customer_city_idx ON customer(city);","note":"CONCURRENTLY はテーブルへの書き込みをブロックしないが、トランザクションブロック内では実行できず、低速。","danger":"caution"},"mysql":{"command":"CREATE INDEX customer_city_idx ON customer(city);\n-- Lock-free: ... ALGORITHM=INPLACE, LOCK=NONE;","note":"InnoDB はほとんどのインデックスをオンラインで追加する。大きなテーブルでは LOCK=NONE で書き込みを許可する。","danger":"caution"},"mssql":{"command":"CREATE NONCLUSTERED INDEX IX_customer_city\nON dbo.customer (city)\nWITH (ONLINE = ON);","note":"ONLINE は Enterprise の機能。カバリング列には INCLUDE (col1, col2) を使用する。","danger":"caution"},"mongodb":{"command":"db.customer.createIndex({ city: 1 })\n// Unique: { city: 1 }, { unique: true }\n// Built in the background without blocking (default behavior in 4.2+)","note":"1 は昇順、-1 は降順。大きなコレクションでは、先にセカンダリで作成すると負荷を軽減できる。","danger":"caution"},"redis":{"command":"# Not applicable (core). If RediSearch is present:\n# FT.CREATE idx ON HASH PREFIX 1 customer: SCHEMA city TAG","note":"セカンダリインデックスは RediSearch モジュールでのみ提供される。コアの Redis ではキーでアクセスする。","danger":"safe"}}},{"id":"show-ddl","title":"オブジェクトの DDL(CREATE 文)を生成","aliases":["show ddl","get ddl","create statement","generate ddl","table definition","show create table","generate script"],"engines":{"oracle":{"command":"SELECT DBMS_METADATA.GET_DDL('TABLE', 'EMPLOYEE', 'HR') FROM dual;","note":"インデックスには 'INDEX'、パッケージには 'PACKAGE' などを使用する。長い出力の切り捨ては SET LONG 100000 で防ぐ。","danger":"safe"},"postgres":{"command":"-- There is no single function in SQL; from the shell:\npg_dump -t public.customer --schema-only mydb","note":"psql では \\d customer で構造を読みやすく表示できる。完全な DDL には pg_dump --schema-only を使用する。","danger":"safe"},"mysql":{"command":"SHOW CREATE TABLE customer\\G","note":"完全な CREATE TABLE(列、インデックス、エンジン、文字セット)を単一コマンドで返す。","danger":"safe"},"mssql":{"command":"-- T-SQL has no single built-in command. Options:\n-- 1) SSMS: right-click > Script Table as > CREATE To\n-- 2) EXEC sp_help 'dbo.customer';  (structure summary)\n-- 3) mssql-scripter tool (command line)","note":"プロシージャ/ビューの本体: SELECT OBJECT_DEFINITION(OBJECT_ID('dbo.usp_name'));","danger":"safe"},"mongodb":{"command":"// There is no DDL (schemaless). View collection options/validator:\ndb.getCollectionInfos({ name: \"customer\" })","note":"options.validator ($jsonSchema) が定義されていれば、それが唯一の「スキーマ定義」。インデックスは getIndexes() で別途取得する。","danger":"safe"},"redis":{"command":"# Not applicable: there is no schema/DDL concept.","note":"データ構造はアプリケーションコードで定義される。永続化は RDB/AOF ファイルで行われる。","danger":"safe"}}}]},"rosetta/replication.json":{"category":"レプリケーションと HA","categoryId":"replication","order":8,"concepts":[{"id":"replication-status","title":"レプリケーションの状態と遅延を表示","aliases":["replication status","replica lag","replication status","lag","slave lag","standby lag","how far behind"],"engines":{"oracle":{"command":"-- Role and mode:\nSELECT database_role, open_mode FROM v$database;\n-- Data Guard lag:\nSELECT name, value, unit FROM v$dataguard_stats\nWHERE name LIKE '%lag%';","note":"apply lag と transport lag が Data Guard の主要な遅延メトリクス。スタンバイで実行する。","danger":"safe"},"postgres":{"command":"-- On the PRIMARY:\nSELECT client_addr, state, sync_state,\n       write_lag, flush_lag, replay_lag\nFROM pg_stat_replication;\n-- On the STANDBY:\nSELECT now() - pg_last_xact_replay_timestamp() AS replay_lag;","note":"replay_lag は再生の遅延。sync_state = 'sync' は同期レプリカを示す。","danger":"safe"},"mysql":{"command":"SHOW REPLICA STATUS\\G\n-- Before 8.0.22: SHOW SLAVE STATUS\\G","note":"Seconds_Behind_Source が遅延を示す。Replica_IO_Running と Replica_SQL_Running は 'Yes' である必要がある。SHOW SLAVE STATUS は 8.0.22–8.3 ではエイリアスで、8.4 で削除された。","danger":"safe"},"mssql":{"command":"SELECT ar.replica_server_name, drs.synchronization_state_desc,\n       drs.log_send_queue_size, drs.redo_queue_size\nFROM sys.dm_hadr_database_replica_states drs\nJOIN sys.availability_replicas ar ON drs.replica_id = ar.replica_id;","note":"Always On 向け。redo_queue_size が大きい場合はセカンダリレプリカが遅れていることを意味する。","danger":"safe"},"mongodb":{"command":"rs.printSecondaryReplicationInfo()\n// Detailed status: rs.status()","note":"各セカンダリがプライマリから何秒遅れているかを示す。optimeDate の値を比較する。","danger":"safe"},"redis":{"command":"INFO replication\n# Check the role, connected_slaves, master_repl_offset,\n# and slaveN:...,offset=... lines","note":"master_repl_offset と slave の offset の差が遅延を示す。master_link_status は 'up' である必要がある。","danger":"safe"}}},{"id":"list-replicas","title":"レプリカ/クラスタノードを一覧表示","aliases":["list replicas","show replicas","list replicas","nodes","cluster members","slaves","standby list"],"engines":{"oracle":{"command":"-- Standby destinations:\nSELECT dest_id, destination, status, target\nFROM v$archive_dest\nWHERE status <> 'INACTIVE';\n-- RAC instances: SELECT inst_id, instance_name, status FROM gv$instance;","note":"Data Guard の構成は DGMGRL> SHOW CONFIGURATION でも確認できる。","danger":"safe"},"postgres":{"command":"SELECT application_name, client_addr, state, sync_state\nFROM pg_stat_replication;","note":"接続中のレプリカは PRIMARY 上でのみ一覧表示される。各行がスタンバイ。","danger":"safe"},"mysql":{"command":"SHOW REPLICAS;\n-- Before 8.0.22: SHOW SLAVE HOSTS;","note":"ソースサーバーで実行する。report-host が設定されたレプリカを表示する。SHOW SLAVE HOSTS は 8.0.22–8.3 ではエイリアスで、8.4 で削除された。","danger":"safe"},"mssql":{"command":"SELECT ar.replica_server_name, ars.role_desc,\n       ars.connected_state_desc, ars.synchronization_health_desc\nFROM sys.dm_hadr_availability_replica_states ars\nJOIN sys.availability_replicas ar ON ars.replica_id = ar.replica_id;","note":"role_desc は PRIMARY/SECONDARY を区別し、synchronization_health_desc は全体的な健全性を示す。","danger":"safe"},"mongodb":{"command":"rs.status().members.map(m => ({ name: m.name, state: m.stateStr, health: m.health }))","note":"stateStr は PRIMARY/SECONDARY/ARBITER を返す。health 1 は正常を意味する。","danger":"safe"},"redis":{"command":"INFO replication\n# If Sentinel is used:\n# SENTINEL replicas <master-name>","note":"slave0、slave1... の行が各レプリカの ip/port/offset を示す。","danger":"safe"}}},{"id":"promote-failover","title":"レプリカを昇格/フェイルオーバー(promote)","aliases":["promote","failover","switchover","promote","role change","stepdown","make master","make primary"],"engines":{"oracle":{"command":"-- Data Guard broker (DGMGRL):\nSWITCHOVER TO 'standby_db';     -- planned, no data loss\n-- FAILOVER TO 'standby_db';     -- on loss of the primary, emergency","note":"SWITCHOVER は計画的なロール遷移。FAILOVER はプライマリに到達できない状態で実行され、データ損失のリスクを伴う。","danger":"danger"},"postgres":{"command":"-- Promote the standby to primary:\nSELECT pg_promote();\n-- or from the shell: pg_ctl promote -D /var/lib/pgsql/data","note":"昇格の前に、旧プライマリが確実に停止していることを確認する(スプリットブレインのリスク)。昇格後、旧プライマリを新プライマリのレプリカとして再参加させるには pg_rewind が必要で、そのためには wal_log_hints = on またはデータチェックサムが有効である必要がある。","danger":"danger"},"mysql":{"command":"-- On the replica (manual):\n-- 1) Stop receiving new events, wait until the received relay log is fully applied:\nSTOP REPLICA IO_THREAD;\nSELECT RECEIVED_TRANSACTION_SET FROM performance_schema.replication_connection_status;\nSELECT @@GLOBAL.gtid_executed;  -- the received set must be fully contained here\n-- 2) Remove replication and enable writes:\nSTOP REPLICA;\nRESET REPLICA ALL;\nSET GLOBAL read_only = OFF;  -- also turns off super_read_only\n-- 3) Fence the old source against writes, then redirect the application.","note":"リレーログが完全に適用される前に RESET REPLICA ALL を実行すると、受信済みで未適用のトランザクションが失われる。レプリカは通常 read_only/super_read_only を有効にして稼働しており、これらを無効にするまで書き込みは受け付けない。旧ソースが書き込み可能なままだとスプリットブレインのリスクがある。この構文は 8.0.22+(それ以前は STOP SLAVE / RESET SLAVE ALL。旧形式は 8.4 で削除)。本番環境で自動かつ安全なフェイルオーバーには InnoDB Cluster/Group Replication、Orchestrator または MHA を推奨する。","danger":"danger"},"mssql":{"command":"-- On the target secondary replica (synchronous):\nALTER AVAILABILITY GROUP [AG_Name] FAILOVER;\n-- Force it, with risk of data loss:\n-- ALTER AVAILABILITY GROUP [AG_Name] FORCE_FAILOVER_ALLOW_DATA_LOSS;","note":"同期レプリカへの計画的なフェイルオーバーではデータ損失はない。FORCE は障害シナリオでのみ使用する。","danger":"danger"},"mongodb":{"command":"// Trigger an election on the current primary:\nrs.stepDown(60)   // step down from primary for 60 s","note":"stepDown は新しい選出を開始する。特定のノードを優先するには、メンバーの priority 値を調整する。","danger":"danger"},"redis":{"command":"# Make the replica an independent primary:\nREPLICAOF NO ONE\n# With Sentinel (recommended): SENTINEL FAILOVER <master-name>","note":"Sentinel/Cluster を使用している場合は、手動の REPLICAOF ではなく SENTINEL FAILOVER を使用する。そうしないとスプリットブレインのリスクがある。","danger":"danger"}}},{"id":"open-transactions","title":"オープン中/長時間実行中のトランザクションを特定","aliases":["open transactions","long running transaction","open transaction","long transaction","idle in transaction","oldest transaction","undo"],"engines":{"oracle":{"command":"SELECT s.sid, s.serial#, s.username,\n       t.start_time, t.used_ublk AS undo_blocks\nFROM v$transaction t\nJOIN v$session s ON t.ses_addr = s.saddr\nORDER BY t.start_time;","note":"used_ublk が大きい場合は、大きなトランザクションが大量の undo を消費しており、コミット/ロールバック待ちの可能性がある。","danger":"safe"},"postgres":{"command":"SELECT pid, usename, state,\n       now() - xact_start AS xact_age, query\nFROM pg_stat_activity\nWHERE xact_start IS NOT NULL\nORDER BY xact_start;","note":"'idle in transaction' 状態の長いトランザクションは VACUUM とタプルのクリーンアップをブロックする。監視すること。","danger":"safe"},"mysql":{"command":"SELECT trx_id, trx_state, trx_started,\n       TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS age_sec,\n       trx_mysql_thread_id\nFROM information_schema.innodb_trx\nORDER BY trx_started;","note":"trx_mysql_thread_id で PROCESSLIST と突き合わせ、必要に応じて KILL する。","danger":"safe"},"mssql":{"command":"DBCC OPENTRAN;\n-- Detailed:\nSELECT st.session_id, dt.database_transaction_begin_time\nFROM sys.dm_tran_database_transactions dt\nJOIN sys.dm_tran_session_transactions st ON st.transaction_id = dt.transaction_id\nWHERE dt.database_id = DB_ID()\nORDER BY dt.database_transaction_begin_time;","note":"長時間オープンのトランザクションはログの切り捨てを妨げ、ログファイルを肥大化させる。","danger":"safe"},"mongodb":{"command":"db.adminCommand({\n  currentOp: 1,\n  \"transaction\": { $exists: true }\n})","note":"長いマルチドキュメントトランザクションは transactionLifetimeLimitSeconds(デフォルト 60 s)経過後に自動的に中止される。","danger":"safe"},"redis":{"command":"# Not applicable: MULTI/EXEC transactions are short and atomic; they do not stay open.","note":"Redis のトランザクションはロックを保持しない。長時間実行の単一コマンドは SLOWLOG で確認する。","danger":"safe"}}}]},"rosetta/connect.json":{"category":"接続と CLI","categoryId":"connect","order":9,"concepts":[{"id":"connect-cli","title":"コマンドラインから接続(CLI / 接続文字列)","aliases":["connect","connection string","connect","how do i connect","cli connect","login","dsn","uri"],"engines":{"oracle":{"command":"sqlplus app_user/password@//host:1521/service_name\n# As SYSDBA: sqlplus sys/password@//host:1521/orcl AS SYSDBA","note":"//host:port/service は「簡易接続(Easy Connect)」形式。代わりに tnsnames.ora の TNS エイリアスも使用できる。","danger":"safe"},"postgres":{"command":"psql -h host -p 5432 -U postgres -d mydb\n# With a URI: psql \"postgresql://app_user:password@host:5432/mydb?sslmode=require\"","note":"コマンドラインでパスワードを入力しないためには、~/.pgpass ファイルまたは PGPASSWORD 環境変数を使用する。","danger":"safe"},"mysql":{"command":"mysql -h host -P 3306 -u root -p mydb\n# Require TLS: --ssl-mode=REQUIRED","note":"-p は単独で指定する(パスワードの入力を求められる)。'mysql -pPassword' 形式ではパスワードがプロセス一覧に露出する。","danger":"safe"},"mssql":{"command":"sqlcmd -S host,1433 -U sa -P password -d mydb\n# Windows authentication: sqlcmd -S host -E -d mydb","note":"新しい go-sqlcmd では、TLS のために -C(サーバー証明書を信頼)と -N(暗号化)フラグが必要な場合がある。","danger":"safe"},"mongodb":{"command":"mongosh \"mongodb://app_user:password@host:27017/mydb?authSource=admin\"\n# Replica set: ...mongodb://h1,h2,h3/db?replicaSet=rs0","note":"authSource は通常ユーザーが定義されたデータベース(多くの場合 admin)。","danger":"safe"},"redis":{"command":"redis-cli -h host -p 6379 -a password\n# With TLS: redis-cli -h host -p 6379 --tls -a password\n# Redis 6+ ACL: redis-cli -h host --user app --pass password","note":"-a はパスワードをコマンドラインで渡す(警告が出る)。安全にログインするには REDISCLI_AUTH 環境変数を使用する。","danger":"safe"}}},{"id":"list-databases","title":"データベース/スキーマを一覧表示","aliases":["list databases","show databases","list databases","which databases","list schemas","pdbs","show dbs"],"engines":{"oracle":{"command":"-- Schemas (users):\nSELECT username FROM dba_users ORDER BY username;\n-- Multitenant (CDB) PDBs:\nSELECT name, open_mode FROM v$pdbs;","note":"Oracle では「データベース」はインスタンスに相当する。分離はスキーマ(ユーザー)レベル、または CDB 内の PDB レベルで行われる。","danger":"safe"},"postgres":{"command":"SELECT datname FROM pg_database WHERE datistemplate = false;\n-- psql shortcut: \\l","note":"スキーマの場合: SELECT schema_name FROM information_schema.schemata;","danger":"safe"},"mysql":{"command":"SHOW DATABASES;","note":"MySQL では「database」と「schema」は同義。","danger":"safe"},"mssql":{"command":"SELECT name, state_desc FROM sys.databases ORDER BY name;","note":"state_desc は ONLINE/OFFLINE/RESTORING などのデータベースの状態を示す。","danger":"safe"},"mongodb":{"command":"show dbs\n// or: db.adminCommand({ listDatabases: 1 })","note":"空のデータベース(まだデータが書き込まれていない)は一覧に表示されない。","danger":"safe"},"redis":{"command":"INFO keyspace\n# db0:keys=..., db1:keys=... lines show the logical DBs in use","note":"Redis には番号付きの論理 DB がある(デフォルト 0-15)。Cluster モードでは DB 0 のみ使用される。","danger":"safe"}}},{"id":"switch-database","title":"アクティブなデータベース/スキーマを変更","aliases":["switch database","use database","change database","switch","change schema","change schema","use db"],"engines":{"oracle":{"command":"-- Change the default schema:\nALTER SESSION SET CURRENT_SCHEMA = hr;\n-- Switch to a PDB (inside a CDB):\nALTER SESSION SET CONTAINER = pdb1;","note":"CURRENT_SCHEMA はオブジェクト名の解決のみを変更し、権限は変わらない。","danger":"safe"},"postgres":{"command":"-- Switch to another DB inside psql (reconnects):\n\\c mydb\n-- Schema search path (same connection):\nSET search_path TO hr, public;","note":"PostgreSQL の接続は単一のデータベースに紐付く。DB を変更するには再接続が必要。","danger":"safe"},"mysql":{"command":"USE mydb;","note":"接続を切らずにアクティブなスキーマを変更する。","danger":"safe"},"mssql":{"command":"USE mydb;","note":"バッチのコンテキストを変更する。以降のコマンドはこのデータベースで実行される。","danger":"safe"},"mongodb":{"command":"use mydb","note":"データベースが存在しなくても切り替わる。実際には最初のドキュメントが書き込まれた時点で作成される。","danger":"safe"},"redis":{"command":"SELECT 1\n# Switches to a logical DB index between 0 and 15","note":"Cluster モードでは SELECT は 0 のみサポートする。論理 DB による分離ではなくキーのプレフィックスを使用する。","danger":"safe"}}}]},"rosetta/objects.json":{"category":"オブジェクト管理","categoryId":"objects","order":10,"concepts":[{"id":"create-partition","title":"パーティションを作成/分割/削除","aliases":["partition","partition","split","split partition","drop partition","add partition","remove partition"],"engines":{"oracle":{"command":"-- Add a RANGE partition\nALTER TABLE sales ADD PARTITION p2026 VALUES LESS THAN (TO_DATE('2027-01-01','YYYY-MM-DD'));\n\n-- Split an existing partition\nALTER TABLE sales SPLIT PARTITION pmax AT (TO_DATE('2027-01-01','YYYY-MM-DD')) INTO (PARTITION p2026, PARTITION pmax);\n\n-- Drop a partition\nALTER TABLE sales DROP PARTITION p2020 UPDATE INDEXES;","note":"RANGE/LIST/HASH パーティショニングをサポートする。DROP PARTITION はそのパーティションの全行を削除する。UPDATE INDEXES を付けるとグローバルインデックスは有効なまま保たれる。インターバルパーティショニングではパーティションを自動追加できる。","danger":"caution","priv":"テーブルに対する ALTER","minver":"Partitioning Option"},"postgres":{"command":"-- Declarative partitioning: parent table\nCREATE TABLE sales (id bigint, created_at date, amount numeric) PARTITION BY RANGE (created_at);\n\n-- Add a new partition\nCREATE TABLE sales_2026 PARTITION OF sales FOR VALUES FROM ('2026-01-01') TO ('2027-01-01');\n\n-- Attach a standalone (existing) table as a partition\nCREATE TABLE sales_2027 (LIKE sales INCLUDING ALL);\nALTER TABLE sales ATTACH PARTITION sales_2027 FOR VALUES FROM ('2027-01-01') TO ('2028-01-01');\n\n-- Detach a partition (the table is not dropped; it remains a standalone table)\nALTER TABLE sales DETACH PARTITION sales_2026;","note":"コアの PostgreSQL には SPLIT/MERGE PARTITION がない(PG17 時点)。分割するには、パーティションを DETACH し、新しい境界で 2 つのパーティションを作成してデータを移動し、ATTACH する。DETACH ... CONCURRENTLY(PG14+)はロック時間を短縮する。","danger":"caution","priv":"テーブル所有者","minver":"PG10"},"mysql":{"command":"-- Partitioned table\nCREATE TABLE sales (id BIGINT, created_at DATE) PARTITION BY RANGE (YEAR(created_at)) (\n  PARTITION p2024 VALUES LESS THAN (2025),\n  PARTITION p2025 VALUES LESS THAN (2026),\n  PARTITION pmax VALUES LESS THAN MAXVALUE\n);\n\n-- Add / split / drop a partition\nALTER TABLE sales REORGANIZE PARTITION pmax INTO (\n  PARTITION p2026 VALUES LESS THAN (2027),\n  PARTITION pmax VALUES LESS THAN MAXVALUE\n);\nALTER TABLE sales DROP PARTITION p2024;","note":"パーティショニング列はすべての PRIMARY KEY / UNIQUE キーに含まれている必要がある。RANGE の分割/結合は REORGANIZE PARTITION で行う。DROP PARTITION は行も削除する(RANGE/LIST)。","danger":"caution","priv":"テーブルに対する ALTER、DROP","minver":"5.7"},"mssql":{"command":"-- 1) Partition function and scheme\nCREATE PARTITION FUNCTION pf_date (date) AS RANGE RIGHT FOR VALUES ('2025-01-01','2026-01-01');\nCREATE PARTITION SCHEME ps_date AS PARTITION pf_date ALL TO ([PRIMARY]);\n\n-- 2) Add a new boundary (split)\nALTER PARTITION SCHEME ps_date NEXT USED [PRIMARY];\nALTER PARTITION FUNCTION pf_date() SPLIT RANGE ('2027-01-01');\n\n-- 3) Remove a boundary (merge)\nALTER PARTITION FUNCTION pf_date() MERGE RANGE ('2025-01-01');","note":"パーティション関数とパーティション構成を定義し、CREATE TABLE ... ON ps_date(created_at) でその構成上にテーブルを作成する。SPLIT の前に NEXT USED ファイルグループを設定しておく必要がある。データを除去するには、SWITCH PARTITION でステージングテーブルに切り出す。","danger":"caution","priv":"テーブルに対する ALTER、ALTER ANY DATASPACE","minver":"2016 SP1(全エディション)"},"mongodb":{"command":"// MongoDB uses sharding instead of table partitioning\nsh.shardCollection(\"db.sales\", { created_at: 1 });\n\n// Native time-series collection for time series\ndb.createCollection(\"measurements\", { timeseries: { timeField: \"ts\", granularity: \"hours\" } });","note":"従来の意味でのパーティショニングはない。水平分割はシャーディングによりチャンク単位で行う。時系列データでは time-series コレクションが自動バケット化を提供する。","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no table/partition concept; scaling is done with Redis Cluster hash slots (16384).","note":"Redis Cluster はキーを 16384 のハッシュスロットに分散する。これはアプリケーションレベルの分割であり、テーブルパーティショニングではない。手動のパーティションコマンドはない。","danger":"safe"},"elasticsearch":{"command":"# Time-based automatic splitting (rollover) with an ILM policy + data stream\nPUT _ilm/policy/logs-policy\n{ \"policy\": { \"phases\": { \"hot\": { \"actions\": { \"rollover\": { \"max_size\": \"50gb\", \"max_age\": \"30d\" } } } } } }\n\nPUT _index_template/logs-tmpl\n{ \"index_patterns\": [\"logs*\"], \"data_stream\": {}, \"template\": { \"settings\": { \"index.lifecycle.name\": \"logs-policy\" } } }","note":"Elasticsearch では、インデックスをシャードに分割することで、また時系列では ILM + データストリーム(rollover)で新しいバッキングインデックスを作成することで分割を実現する。古いインデックスは ILM で削除できる。","danger":"safe"}}},{"id":"sequence","title":"シーケンス/自動採番の値を作成","aliases":["sequence","sequence","auto increment","identity","auto-increment","nextval","serial"],"engines":{"oracle":{"command":"-- Sequence\nCREATE SEQUENCE customer_seq START WITH 1 INCREMENT BY 1 NOCACHE;\nSELECT customer_seq.NEXTVAL FROM dual;\n\n-- or an identity column (12c+)\nCREATE TABLE customer (id NUMBER GENERATED ALWAYS AS IDENTITY, name VARCHAR2(100));","note":"従来の方法は CREATE SEQUENCE + NEXTVAL/CURRVAL。12c 以降は GENERATED AS IDENTITY 列もサポートされる。CACHE 値は性能を向上させるが、欠番が生じることがある。","danger":"safe","priv":"CREATE SEQUENCE","minver":"IDENTITY は 12c"},"postgres":{"command":"-- Sequence\nCREATE SEQUENCE customer_seq START 1 INCREMENT 1;\nSELECT nextval('customer_seq');\n\n-- Modern method: identity column\nCREATE TABLE customer (id int GENERATED ALWAYS AS IDENTITY PRIMARY KEY, name text);\n-- Classic: serial (creates a sequence behind the scenes)\nCREATE TABLE logs (id serial PRIMARY KEY, message text);","note":"GENERATED ... AS IDENTITY は SQL 標準で推奨される。serial は従来の省略形。手動では nextval/currval でアクセスする。値は setval でリセットできる。","danger":"safe","priv":"スキーマに対する CREATE","minver":"IDENTITY は PG10"},"mysql":{"command":"-- AUTO_INCREMENT column\nCREATE TABLE customer (id BIGINT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100));\n\n-- Set the starting value\nALTER TABLE customer AUTO_INCREMENT = 1000;\n\n-- Get the last inserted value\nSELECT LAST_INSERT_ID();","note":"MySQL には独立した(標準の)シーケンスオブジェクトがなく、AUTO_INCREMENT 列を使用する(テーブルごとに 1 つ、インデックスが必要)。MariaDB 10.3+ は CREATE SEQUENCE をサポートする。","danger":"safe","priv":"テーブルに対する CREATE、ALTER"},"mssql":{"command":"-- IDENTITY column\nCREATE TABLE customer (id INT IDENTITY(1,1) PRIMARY KEY, name NVARCHAR(100));\n\n-- Standalone sequence object\nCREATE SEQUENCE customer_seq AS INT START WITH 1 INCREMENT BY 1;\nSELECT NEXT VALUE FOR customer_seq;","note":"IDENTITY(seed,increment) はテーブルの列に紐付く。CREATE SEQUENCE(2012+)はテーブルから独立し、複数テーブルで共有できるカウンタを提供する。値は NEXT VALUE FOR で取得する。","danger":"safe","priv":"CREATE SEQUENCE / テーブルに対する ALTER","minver":"SEQUENCE は 2012"},"mongodb":{"command":"// MongoDB has no auto counter; counter pattern with findOneAndUpdate\ndb.counters.findOneAndUpdate(\n  { _id: \"customer\" },\n  { $inc: { seq: 1 } },\n  { upsert: true, returnDocument: \"after\" }\n);","note":"デフォルトの _id は ObjectId(既に一意で、おおむね増加する)。連番の整数が必要なら、別の counters コレクションで $inc によりアトミックに生成する。","danger":"safe"},"redis":{"command":"# Atomic counter\nINCR customer:id\n# or with a specific step\nINCRBY customer:id 10","note":"INCR/INCRBY はアトミックで、分散環境で一意の増加 ID を生成するのに最適。キーが存在しなければ 0 から開始する。","danger":"safe"},"elasticsearch":{"command":"# Not applicable: Elasticsearch does not offer a sequence object. Document IDs are assigned automatically;\n# the internal _seq_no and _primary_term fields are used for concurrency control.\nPOST logs/_doc\n{ \"message\": \"sample\" }","note":"ID なしで POST すると、ES はランダムな一意の _id(増加しない)を割り当てる。_seq_no は書き込みごとに増加する内部シーケンス番号だが、楽観的同時実行制御用であり、アプリケーションのカウンタではない。","danger":"safe"}}},{"id":"add-constraint","title":"制約(FK/CHECK/UNIQUE)の追加/無効化","aliases":["constraint","constraint","foreign key","check","unique","foreign key","disable constraint"],"engines":{"oracle":{"command":"-- Add a foreign key\nALTER TABLE orders ADD CONSTRAINT fk_customer FOREIGN KEY (customer_id) REFERENCES customer(id);\n-- CHECK\nALTER TABLE product ADD CONSTRAINT chk_price CHECK (price >= 0);\n-- Disable / enable\nALTER TABLE orders DISABLE CONSTRAINT fk_customer;\nALTER TABLE orders ENABLE CONSTRAINT fk_customer;","note":"Oracle の制約は DISABLE/ENABLE で一時的に無効化できる(一括ロードに有用)。ENABLE VALIDATE は既存の行を検査し、NOVALIDATE は検査しない。","danger":"caution","priv":"テーブルに対する ALTER、参照先に対する REFERENCES"},"postgres":{"command":"-- Foreign key and CHECK\nALTER TABLE orders ADD CONSTRAINT fk_customer FOREIGN KEY (customer_id) REFERENCES customer(id);\nALTER TABLE product ADD CONSTRAINT chk_price CHECK (price >= 0);\n\n-- Instead of disabling the FK: NOT VALID + validate later\nALTER TABLE orders ADD CONSTRAINT fk2 FOREIGN KEY (c_id) REFERENCES customer(id) NOT VALID;\nALTER TABLE orders VALIDATE CONSTRAINT fk2;\nALTER TABLE orders DROP CONSTRAINT fk2;","note":"PostgreSQL には制約の DISABLE がない。大きなテーブルでロックを減らすには、NOT VALID で制約を追加し、後で VALIDATE する。ALTER TABLE ... DISABLE TRIGGER ALL は FK の内部トリガーも無効にし、superuser が必要。無効中に挿入されたデータは検証されず、再有効化しても遡って検査されない(気付かないうちに整合性が失われるリスク)。代わりに、制約を DROP して NOT VALID で再追加し、VALIDATE CONSTRAINT を実行する。","danger":"caution","priv":"テーブル所有者、参照先に対する REFERENCES"},"mysql":{"command":"-- Foreign key and CHECK\nALTER TABLE orders ADD CONSTRAINT fk_customer FOREIGN KEY (customer_id) REFERENCES customer(id);\nALTER TABLE product ADD CONSTRAINT chk_price CHECK (price >= 0);\n\n-- Temporarily disable FK checks for the session\nSET FOREIGN_KEY_CHECKS = 0;\n-- ... bulk operation ...\nSET FOREIGN_KEY_CHECKS = 1;","note":"InnoDB が必要。個別の制約を無効化する代わりに、セッションレベルの SET FOREIGN_KEY_CHECKS=0 を使用する。CHECK 制約が実際に適用されるのは MySQL 8.0.16 以降(それ以前は無視されていた)。","danger":"caution","priv":"テーブルに対する ALTER、REFERENCES","minver":"CHECK は 8.0.16"},"mssql":{"command":"-- Foreign key and CHECK\nALTER TABLE orders ADD CONSTRAINT fk_customer FOREIGN KEY (customer_id) REFERENCES customer(id);\nALTER TABLE product ADD CONSTRAINT chk_price CHECK (price >= 0);\n\n-- Disable / re-enable (validate with WITH CHECK)\nALTER TABLE orders NOCHECK CONSTRAINT fk_customer;\nALTER TABLE orders WITH CHECK CHECK CONSTRAINT fk_customer;","note":"SQL Server では FK/CHECK 制約を NOCHECK CONSTRAINT で無効化する。再有効化時に WITH CHECK CHECK CONSTRAINT を使用しないと、制約は「not trusted」のままとなり、クエリオプティマイザが利用できない。","danger":"caution","priv":"テーブルに対する ALTER、参照先に対する REFERENCES"},"mongodb":{"command":"// Constraint-like checks with schema validation rules\ndb.runCommand({ collMod: \"product\",\n  validator: { $jsonSchema: { required: [\"price\"], properties: { price: { bsonType: \"number\", minimum: 0 } } } },\n  validationLevel: \"strict\"\n});\n// Unique index for uniqueness\ndb.customer.createIndex({ email: 1 }, { unique: true });","note":"外部キーはない(アプリケーション層で担保する)。UNIQUE に相当するのは一意インデックス。CHECK の代わりに $jsonSchema 検証を使用し、validationAction: 'warn' で無効化と同じ効果が得られる。","danger":"caution"},"redis":{"command":"# Not applicable: Redis has no FK/CHECK/UNIQUE constraints. Uniqueness is enforced at the application level with SET or\n# SETNX/conditional writes.\nSET customer:email:sample@x.com 1 NX","note":"リレーショナルな整合性や制約の概念はない。一意性はアプリケーション側で SET ... NX(存在しない場合のみ書き込み)や別の SET/HASH の確認で管理する。","danger":"safe"},"elasticsearch":{"command":"# Not applicable: Elasticsearch has no FK/CHECK. Field types are enforced with the mapping,\n# and uniqueness with a fixed _id.\nPUT product/_doc/ABC-123\n{ \"price\": 100 }","note":"リレーションと制約はエンジンに存在しない。型チェックはマッピングで行う。UNIQUE 相当の効果には、自然キーを _id として使用する(同じ _id への書き込みは上書きされる)か、op_type=create で競合を拒否する。","danger":"safe"}}},{"id":"create-view","title":"ビューを作成/変更","aliases":["view","view","create view","alter view","or replace"],"engines":{"oracle":{"command":"CREATE OR REPLACE VIEW active_customer AS\nSELECT id, name, email FROM customer WHERE status = 'ACTIVE';\n\n-- Drop\nDROP VIEW active_customer;","note":"CREATE OR REPLACE VIEW で作成と変更の両方を行う。特定の条件下で更新可能なビューには WITH CHECK OPTION を付けられる。","danger":"safe","readonly":true,"priv":"CREATE VIEW"},"postgres":{"command":"CREATE OR REPLACE VIEW active_customer AS\nSELECT id, name, email FROM customer WHERE status = 'ACTIVE';\n\nDROP VIEW active_customer;","note":"CREATE OR REPLACE では新しい列は末尾にのみ追加できる。列の型/順序を変更するには先に DROP が必要。単純なビューは自動的に更新可能。","danger":"safe","readonly":true,"priv":"スキーマに対する CREATE"},"mysql":{"command":"CREATE OR REPLACE VIEW active_customer AS\nSELECT id, name, email FROM customer WHERE status = 'ACTIVE';\n\n-- Modify\nALTER VIEW active_customer AS SELECT id, name FROM customer;\nDROP VIEW active_customer;","note":"定義は CREATE OR REPLACE VIEW または ALTER VIEW で更新する。実行方式は ALGORITHM = MERGE/TEMPTABLE で設定できる。WITH CHECK OPTION は更新可能なビューを保護する。","danger":"safe","readonly":true,"priv":"テーブルに対する CREATE VIEW"},"mssql":{"command":"CREATE OR ALTER VIEW active_customer AS\nSELECT id, name, email FROM customer WHERE status = 'ACTIVE';\n\nDROP VIEW active_customer;","note":"CREATE OR ALTER VIEW(2016 SP1+)は単一の文で作成/変更する。古いバージョンでは先に CREATE し、その後 ALTER VIEW を使用する。ビューの文はバッチ内の最初の文である必要がある。","danger":"safe","readonly":true,"priv":"CREATE VIEW","minver":"OR ALTER は 2016 SP1"},"mongodb":{"command":"// Read-only view (on top of an aggregation pipeline)\ndb.createView(\"active_customer\", \"customer\", [ { $match: { status: \"ACTIVE\" } }, { $project: { name: 1, email: 1 } } ]);\n\ndb.active_customer.drop();","note":"db.createView はソースコレクションと集計パイプラインに基づく読み取り専用のビューを作成する。ビューには書き込めない。定義を変更するには削除して再作成する(または collMod を使用する)。","danger":"safe","readonly":true},"redis":{"command":"# Not applicable: Redis has no view concept; derived views are provided on the application\n# side or with RedisJSON/RediSearch indexes.","note":"クエリで定義するビューはサポートされない。同様の用途には、事前計算したキーを保持するか、RediSearch で検索可能なインデックスを構築する。","danger":"safe"},"elasticsearch":{"command":"# Filtered logical view with an alias\nPOST _aliases\n{ \"actions\": [ { \"add\": { \"index\": \"customer\", \"alias\": \"active_customer\",\n  \"filter\": { \"term\": { \"status\": \"ACTIVE\" } } } } ] }","note":"従来の SQL ビューはない。フィルタ付きエイリアスが最も近く、クエリに自動的にフィルタを適用する。列の選択にはクエリで _source フィルタリングを使用する。","danger":"safe","readonly":true}}},{"id":"materialized-view","title":"マテリアライズドビューを作成してリフレッシュ","aliases":["materialized view","mview","refresh","refresh","cached view","materialize"],"engines":{"oracle":{"command":"-- FAST refresh first requires an MV log on the source table:\nCREATE MATERIALIZED VIEW LOG ON sales\n  WITH ROWID, SEQUENCE (region, amount) INCLUDING NEW VALUES;\n\nCREATE MATERIALIZED VIEW mv_revenue\nBUILD IMMEDIATE REFRESH FAST ON COMMIT\nAS SELECT region, SUM(amount) total, COUNT(*) cnt, COUNT(amount) amount_cnt\n   FROM sales GROUP BY region;\n\n-- Manual refresh\nEXEC DBMS_MVIEW.REFRESH('MV_REVENUE', 'C');","note":"REFRESH FAST にはマテリアライズドビューログが必要。COMPLETE('C')は完全に再計算し、FAST('F')は増分。ON COMMIT/ON DEMAND でリフレッシュのタイミングが決まる。","danger":"caution","priv":"CREATE MATERIALIZED VIEW"},"postgres":{"command":"CREATE MATERIALIZED VIEW mv_revenue AS\nSELECT region, SUM(amount) AS total FROM sales GROUP BY region;\n\n-- Refresh (CONCURRENTLY requires a unique index)\nCREATE UNIQUE INDEX ON mv_revenue (region);\nREFRESH MATERIALIZED VIEW CONCURRENTLY mv_revenue;","note":"REFRESH はすべてを再計算する(増分ではない)。CONCURRENTLY は読み取りをブロックしないが、一意インデックスが必要で低速。","danger":"caution","priv":"テーブル所有者","minver":"PG9.3(CONCURRENTLY は 9.4)"},"mysql":{"command":"-- MySQL/MariaDB has no built-in materialized views.\n-- Approach: summary table + refresh with a trigger or a scheduled event\nCREATE TABLE mv_revenue (region VARCHAR(50) PRIMARY KEY, total DECIMAL(18,2));\n\nCREATE EVENT ev_mv_revenue ON SCHEDULE EVERY 1 HOUR DO\n  REPLACE INTO mv_revenue SELECT region, SUM(amount) FROM sales GROUP BY region;","note":"ネイティブのマテリアライズドビューはサポートされない。サマリーテーブルを保持し、トリガーで即時に、または EVENT SCHEDULER で定期的に再投入する。","danger":"caution","priv":"スキーマに対する CREATE、EVENT"},"mssql":{"command":"-- Indexed view (materialized view equivalent)\nCREATE VIEW dbo.mv_revenue WITH SCHEMABINDING AS\nSELECT region, SUM(ISNULL(amount, 0)) AS total, COUNT_BIG(*) AS cnt\nFROM dbo.sales GROUP BY region;\nGO\nCREATE UNIQUE CLUSTERED INDEX ix_mv_revenue ON dbo.mv_revenue (region);","note":"SQL Server ではインデックス付きビューを使用する。WITH SCHEMABINDING が必須で、一意のクラスタ化インデックスを作成するとデータが物理的に格納され自動的に維持される(別途 REFRESH は不要)。GROUP BY では COUNT_BIG(*) が必要。SUM 内の列が NULL 許容なら SUM(ISNULL(amount, 0)) と書く(そうしないとエラー 8662)。ビューは QUOTED_IDENTIFIER と ANSI_NULLS を ON にして作成する必要がある。クエリオプティマイザによる自動ビューマッチングは Enterprise(および Developer)エディションのみ。Standard では WITH (NOEXPAND) ヒントでビューを参照する。","danger":"caution","priv":"CREATE VIEW、スキーマに対する ALTER"},"mongodb":{"command":"// On-demand materialized view: write the result to a collection with $merge\ndb.sales.aggregate([\n  { $group: { _id: \"$region\", total: { $sum: \"$amount\" } } },\n  { $merge: { into: \"mv_revenue\", whenMatched: \"replace\", whenNotMatched: \"insert\" } }\n]);","note":"集計結果を $out または $merge で永続コレクションに書き込むことで、オンデマンドのマテリアライズドビューが得られる。リフレッシュするにはパイプラインを再実行する(手動またはスケジューラで)。","danger":"caution"},"redis":{"command":"# Not applicable: Redis has no materialized views. The computed result is written to a key\n# and cached with a TTL.\nSET mv:revenue:region1 12345 EX 3600","note":"マテリアライズドビューの概念はない。最も近い方法は、事前計算した値をキー(String/Hash/Sorted Set)に保持し、EX/TTL で期間限定でキャッシュすること。","danger":"safe"},"elasticsearch":{"command":"# Continuous/materialized summary index with a transform\nPUT _transform/mv_revenue\n{ \"source\": { \"index\": \"sales\" },\n  \"dest\": { \"index\": \"mv_revenue\" },\n  \"pivot\": { \"group_by\": { \"region\": { \"terms\": { \"field\": \"region\" } } },\n            \"aggregations\": { \"total\": { \"sum\": { \"field\": \"amount\" } } } } }\nPOST _transform/mv_revenue/_start","note":"transform はソースインデックスをピボットし、サマリー用の宛先インデックスに実体化する。この例はバッチ transform で、_start で一度実行されて停止する。新しいデータの到着に応じて自動更新される continuous transform にするには、時刻フィールドを指定した \"sync\": { \"time\": { \"field\": \"<time_field>\", \"delay\": \"60s\" } } を構成に追加する(continuous: true という設定はない)。","danger":"caution"}}},{"id":"rename-object","title":"テーブル/オブジェクトの名前を変更","aliases":["rename","rename","change name","rename table","sp_rename"],"engines":{"oracle":{"command":"-- Table\nALTER TABLE old_name RENAME TO new_name;\n-- or\nRENAME old_name TO new_name;\n-- Column\nALTER TABLE customer RENAME COLUMN name TO full_name;","note":"テーブル/ビュー/シーケンスには RENAME または ALTER ... RENAME TO を使用する。依存オブジェクト(ビュー、シノニム)は無効になり、再コンパイルが必要になる場合がある。","danger":"caution","priv":"オブジェクトに対する ALTER"},"postgres":{"command":"ALTER TABLE old_name RENAME TO new_name;\nALTER TABLE customer RENAME COLUMN name TO full_name;\nALTER VIEW old_view RENAME TO new_view;","note":"ALTER ... RENAME TO はほとんどのオブジェクトタイプで使用できる。外部キーとインデックスの参照は、名前が変わっても自動的に維持される(OID ベース)。","danger":"caution","priv":"テーブル所有者"},"mysql":{"command":"RENAME TABLE old_name TO new_name;\n-- or\nALTER TABLE old_name RENAME TO new_name;\n-- Column (8.0+)\nALTER TABLE customer RENAME COLUMN name TO full_name;","note":"RENAME TABLE はアトミックで、単一の文で複数のテーブルを移動できる。列名の変更は 8.0+ では RENAME COLUMN を使用する。それ以前は CHANGE を使用し、型も指定する必要がある。","danger":"caution","priv":"旧名に対する ALTER、DROP。新名に対する CREATE、INSERT"},"mssql":{"command":"-- Table\nEXEC sp_rename 'dbo.old_name', 'new_name';\n-- Column\nEXEC sp_rename 'dbo.customer.name', 'full_name', 'COLUMN';","note":"SQL Server には RENAME TABLE 文がなく、システムプロシージャ sp_rename を使用する。スキーマのプレフィックスはテーブル名には付けるが、新しい名前には付けない。依存するビュー/プロシージャは手動で更新する必要がある。","danger":"caution","priv":"オブジェクトに対する ALTER、CONTROL"},"mongodb":{"command":"// Rename a collection\ndb.old_name.renameCollection(\"new_name\");\n// or the admin command\ndb.adminCommand({ renameCollection: \"db.old_name\", to: \"db.new_name\" });","note":"renameCollection でコレクション名を変更する。フィールド名を変更するには updateMany で $rename 演算子を使用する。シャードコレクションは 5.0+ で名前変更でき、それより古いバージョンではサポートされない。","danger":"caution","priv":"renameCollectionSameDB / clusterManager"},"redis":{"command":"# Rename a key\nRENAME old_key new_key\n# Without overwriting if the target exists\nRENAMENX old_key new_key","note":"RENAME はキーの名前を変更する。ターゲットが既に存在する場合は上書きされる。RENAMENX はターゲットが存在しない場合のみ動作する。ソースキーが存在しない場合はエラーが返る。","danger":"caution"},"elasticsearch":{"command":"# An index cannot be renamed directly; reindex + alias approach\nPOST _reindex\n{ \"source\": { \"index\": \"old_name\" }, \"dest\": { \"index\": \"new_name\" } }\nDELETE old_name\n# or use an alias for a seamless switch\nPOST _aliases\n{ \"actions\": [ { \"add\": { \"index\": \"new_name\", \"alias\": \"customer\" } } ] }","note":"インデックス名を変更するコマンドはない。_reindex で新しい名前に再インデックスし、古いものを削除する。アプリケーションをインデックス名に依存させないよう、固定のエイリアス経由で運用することを推奨する。","danger":"caution"}}}]},"rosetta/datamove.json":{"category":"データ移動","categoryId":"datamove","order":11,"concepts":[{"id":"bulk-import","title":"データを一括ロード(CSV / ファイルから)","aliases":["import","bulk load","load csv","bulk insert","load data","copy from","import data"],"engines":{"oracle":{"command":"-- SQL*Loader (from the shell)\nsqlldr app_user/password control=customer.ctl log=load.log\n\n-- Contents of customer.ctl:\n-- LOAD DATA INFILE 'customer.csv'\n-- INTO TABLE customer FIELDS TERMINATED BY ','\n-- (id, name, email)\n\n-- Alternative: with an external table\nCREATE TABLE ext_customer (id NUMBER, name VARCHAR2(100))\nORGANIZATION EXTERNAL (TYPE ORACLE_LOADER DEFAULT DIRECTORY dir_csv\n  ACCESS PARAMETERS (FIELDS TERMINATED BY ',') LOCATION ('customer.csv'));","note":"最も一般的なツールは SQL*Loader(制御ファイルを使用)。ファイルをクエリのように読むには外部表を使用する。大容量ではダイレクトパスロード(DIRECT=TRUE)が高速。","danger":"caution","priv":"テーブルに対する INSERT、DIRECTORY オブジェクト"},"postgres":{"command":"-- Server side (file on the server; requires superuser/pg_read_server_files)\nCOPY customer (id, name, email) FROM '/data/customer.csv' WITH (FORMAT csv, HEADER true);\n\n-- Client side (psql, file on the client)\n\\copy customer (id, name, email) FROM 'customer.csv' WITH (FORMAT csv, HEADER true)","note":"COPY はサーバー上のファイルを読み、権限が必要。psql の \\copy はクライアントのファイルを読み、追加の権限は不要。CSV をロードする最速の方法。","danger":"caution","priv":"テーブルに対する INSERT(COPY には pg_read_server_files)"},"mysql":{"command":"-- Server side\nLOAD DATA INFILE '/data/customer.csv' INTO TABLE customer\nFIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY '\\n' IGNORE 1 LINES;\n\n-- From a client file\nLOAD DATA LOCAL INFILE 'customer.csv' INTO TABLE customer\nFIELDS TERMINATED BY ',' IGNORE 1 LINES;","note":"LOAD DATA INFILE は一括ロードの最速の方法。LOCAL はクライアントのファイルを読み、サーバー(local_infile=ON)とクライアントの両方で有効にする必要がある。secure_file_priv はサーバーのパスを制限する。","danger":"caution","priv":"FILE(LOCAL には INSERT)"},"mssql":{"command":"-- T-SQL BULK INSERT\nBULK INSERT customer FROM 'C:\\data\\customer.csv'\nWITH (FORMAT='CSV', FIRSTROW=2, FIELDTERMINATOR=',', ROWTERMINATOR='0x0a');\n\n-- bcp from the shell\nbcp mydb.dbo.customer in customer.csv -c -t, -S server -T","note":"BULK INSERT は SQL Server サービスアカウントがアクセスできるパスからファイルを読む。bcp はコマンドラインツールで、-c は文字モード、-t はフィールド区切り文字。最大速度を得るには TABLOCK で最小ログ記録を狙う。","danger":"caution","priv":"INSERT、ADMINISTER BULK OPERATIONS"},"mongodb":{"command":"# Import CSV / JSON (from the shell)\nmongoimport --db=shop --collection=customer --type=csv --headerline --file=customer.csv\n\n# For a JSON array\nmongoimport --db=shop --collection=customer --file=customer.json --jsonArray","note":"mongoimport は CSV/TSV/JSON をロードする。--headerline は先頭行をフィールド名として扱う。既存ドキュメントを更新するには --mode=upsert --upsertFields を使用する。大容量データでは --numInsertionWorkers で高速化できる。","danger":"caution","priv":"insert(readWrite)"},"redis":{"command":"# Fastest: feed commands in protocol format and pipe them\ncat commands.txt | redis-cli --pipe\n\n# Example lines in commands.txt:\n# SET customer:1 \"Alice\"\n# SET customer:2 \"Bob\"","note":"一括ロードには redis-cli --pipe(mass insert)を使用する。単一の接続で RESP プロトコル形式のコマンドをストリーミングするため非常に高速。代わりにパイプライニングでコマンドをまとめる方法もある。","danger":"caution"},"elasticsearch":{"command":"# _bulk API (NDJSON: an action line + a source line per document)\ncurl -s -H 'Content-Type: application/x-ndjson' -XPOST 'localhost:9200/customer/_bulk' --data-binary @data.ndjson\n\n# Contents of data.ndjson:\n# { \"index\": {} }\n# { \"id\": 1, \"name\": \"Alice\" }\n# { \"index\": {} }\n# { \"id\": 2, \"name\": \"Bob\" }","note":"_bulk API は NDJSON を受け付ける(ドキュメントごとにアクション行 + データ行。ファイルは \\n で終わる必要がある)。CSV には Logstash、Filebeat または elasticdump を使用する。ロード中に refresh_interval を無効にすると高速化する。","danger":"caution","priv":"index / create index 権限"}}},{"id":"bulk-export","title":"データをエクスポート(CSV / ファイルへ)","aliases":["export","export data","export csv","copy to","outfile","dump","extract data"],"engines":{"oracle":{"command":"-- CSV with SQL*Plus (spool)\nSET MARKUP CSV ON\nSPOOL customer.csv\nSELECT id, name, email FROM customer;\nSPOOL OFF\n\n-- Logical export with Data Pump (from the shell)\nexpdp app_user/password tables=customer directory=dir_dmp dumpfile=customer.dmp","note":"CSV には SQL*Plus の SET MARKUP CSV ON + SPOOL(12.2+)を使用する。スキーマ/テーブルを移動するには、Data Pump(expdp)がバイナリの .dmp を生成し、別の Oracle データベースに impdp でインポートする。","danger":"safe","readonly":true,"priv":"テーブルに対する SELECT","minver":"MARKUP CSV は 12.2"},"postgres":{"command":"-- Server side\nCOPY (SELECT id, name, email FROM customer) TO '/data/customer.csv' WITH (FORMAT csv, HEADER true);\n\n-- Client side (psql)\n\\copy (SELECT id, name, email FROM customer) TO 'customer.csv' WITH (FORMAT csv, HEADER true)","note":"COPY ... TO はクエリ結果をファイルに書き込む(サーバー側、権限が必要)。psql の \\copy はクライアントのファイルに書き込む。HEADER true でヘッダー行を追加する。","danger":"safe","readonly":true,"priv":"テーブルに対する SELECT"},"mysql":{"command":"-- To a file on the server\nSELECT id, name, email FROM customer\nINTO OUTFILE '/data/customer.csv'\nFIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY '\\n';\n\n-- To the client: mysql -e ... > file (tab-separated)\n-- mysql -e \"SELECT * FROM customer\" shop > customer.tsv","note":"SELECT ... INTO OUTFILE はサーバー上にファイルを作成する(secure_file_priv のパスと FILE 権限が必要。上書きはできない)。クライアント側に出力するには mysql -e でリダイレクトする。","danger":"safe","readonly":true,"priv":"SELECT、FILE"},"mssql":{"command":"-- Export with bcp (from the shell)\nbcp \"SELECT id, name, email FROM shop.dbo.customer\" queryout customer.csv -c -t, -S server -T\n\n-- or the whole table\nbcp shop.dbo.customer out customer.dat -n -S server -T","note":"bcp out/queryout はデータをファイルに書き込む: -c は文字モード、-t, はフィールド区切り文字、-n はネイティブのバイナリ形式。クエリ結果には queryout を使用する。SSMS の「Results to File」も選択肢。","danger":"safe","readonly":true,"priv":"テーブルに対する SELECT"},"mongodb":{"command":"# Export CSV (fields must be specified)\nmongoexport --db=shop --collection=customer --type=csv --fields=id,name,email --out=customer.csv\n\n# As JSON\nmongoexport --db=shop --collection=customer --out=customer.json","note":"mongoexport は CSV/JSON を生成する。CSV では --fields で列を明示的に指定する必要がある。絞り込みには --query を使用する。完全なバイナリバックアップには mongodump が推奨される。","danger":"safe","readonly":true,"priv":"find(read)"},"redis":{"command":"# Scan keys (SCAN instead of KEYS in production)\nredis-cli --scan --pattern 'customer:*' > keys.txt\n\n# For a full data backup, download an RDB snapshot to the client side (non-blocking)\nredis-cli --rdb ./dump.rdb","note":"構造化された CSV エクスポートは組み込まれていない。キーの一覧には --scan(ノンブロッキング)を、全データには RDB ファイルを使用する。redis-cli --rdb はサーバー上でバックグラウンド生成されたスナップショットをローカルファイルにダウンロードする。ファイルをサーバー上に置きたい場合は BGSAVE を使用する。SAVE はメインスレッドをブロックするため本番環境では使用しないこと。値も取得するには、スキャン結果をループで読む。","danger":"safe","readonly":true},"elasticsearch":{"command":"# Export with elasticdump\nelasticdump --input=http://localhost:9200/customer --output=customer.json --type=data\n\n# For large data, paged reads with scroll / point-in-time\nGET customer/_search?scroll=1m\n{ \"size\": 1000, \"query\": { \"match_all\": {} } }","note":"直接の CSV エクスポートはない。全データを取得するには elasticdump を使用するか、scroll/PIT(point-in-time)で _search をページングする。CSV への変換には Logstash の csv 出力または外部ツールが必要。","danger":"safe","readonly":true,"priv":"インデックスに対する read"}}},{"id":"copy-between","title":"テーブル間/環境間でデータをコピー","aliases":["copy","copy","insert select","ctas","reindex","move data","between tables"],"engines":{"oracle":{"command":"-- Into an existing table\nINSERT INTO target_tbl (id, name) SELECT id, name FROM source_tbl WHERE status = 'ACTIVE';\n\n-- By creating a new table (CTAS)\nCREATE TABLE target_tbl AS SELECT * FROM source_tbl;\n\n-- From a remote database via a database link\nINSERT INTO target_tbl SELECT * FROM source_tbl@remote_db;","note":"同一データベース内では INSERT ... SELECT または CREATE TABLE AS SELECT(CTAS)を使用する。環境間のコピーにはデータベースリンク(@remote_db)または Data Pump が推奨される。APPEND ヒントはダイレクトパスで高速化する。","danger":"caution","priv":"ソースに対する SELECT、ターゲットに対する INSERT/CREATE"},"postgres":{"command":"-- Same database\nINSERT INTO target_tbl (id, name) SELECT id, name FROM source_tbl;\nCREATE TABLE target_tbl AS SELECT * FROM source_tbl;\n\n-- Between environments (psql pipe)\n-- pg_dump -t source_tbl sourcedb | psql targetdb\n-- or read the remote table with postgres_fdw and INSERT","note":"同一 DB 内では INSERT ... SELECT / CTAS を使用する。サーバー間では pg_dump | psql のパイプライン、または postgres_fdw の外部テーブル経由でコピーする。","danger":"caution","priv":"ソースに対する SELECT、ターゲットに対する INSERT/CREATE"},"mysql":{"command":"-- Same database\nINSERT INTO target_tbl (id, name) SELECT id, name FROM source_tbl;\nCREATE TABLE target_tbl AS SELECT * FROM source_tbl;\n\n-- Between servers (mysqldump pipe)\n-- mysqldump sourcedb source_tbl | mysql -h targethost targetdb","note":"同一 DB 内では INSERT ... SELECT または CREATE TABLE ... AS SELECT。異なるサーバー間では mysqldump の出力を mysql クライアントにパイプする方法が一般的。CTAS はインデックスと制約をコピーしない。","danger":"caution","priv":"ソースに対する SELECT、ターゲットに対する INSERT/CREATE"},"mssql":{"command":"-- Into an existing table\nINSERT INTO target_tbl (id, name) SELECT id, name FROM source_tbl;\n\n-- By creating a new table\nSELECT * INTO target_tbl FROM source_tbl;\n\n-- Between servers: linked server\nINSERT INTO target_tbl SELECT * FROM [REMOTE_SRV].shop.dbo.source_tbl;","note":"SQL Server では新しいテーブルへのコピーは SELECT ... INTO(CTAS 相当)で行う。サーバー間ではリンクサーバー(4 部構成名)、bcp out/in または SSIS を使用する。","danger":"caution","priv":"ソースに対する SELECT、ターゲットに対する INSERT / CREATE TABLE"},"mongodb":{"command":"// Write an aggregation result to another collection\ndb.source_tbl.aggregate([\n  { $match: { status: \"ACTIVE\" } },\n  { $out: \"target_tbl\" }\n]);\n\n// Merge into an existing collection (upsert)\ndb.source_tbl.aggregate([ { $merge: { into: \"target_tbl\", whenMatched: \"merge\", whenNotMatched: \"insert\" } } ]);","note":"$out はターゲットコレクションを完全に置き換える。$merge は既存ドキュメントにマージ/挿入する(同じ DB または別の DB)。サーバー間の移動には mongodump | mongorestore または mongoexport/mongoimport を使用する。","danger":"caution","priv":"ソースに対する find、ターゲットに対する insert"},"redis":{"command":"# Move a single key to another server (deleted from the source)\nMIGRATE target_host 6379 customer:1 0 5000\n\n# To copy (without deleting): DUMP + RESTORE\nDUMP customer:1          # returns the serialized value\nRESTORE customer:1new 0 \"<dump-data>\"","note":"MIGRATE はキーをターゲットインスタンスにアトミックに移動し、ソースから削除する(COPY オプションでは削除しない)。同一インスタンス内でコピーするには COPY コマンド(6.0+)または DUMP+RESTORE を使用する。","danger":"caution"},"elasticsearch":{"command":"# Within the same cluster\nPOST _reindex\n{ \"source\": { \"index\": \"source_tbl\" }, \"dest\": { \"index\": \"target_tbl\" } }\n\n# From a remote cluster (remote reindex; requires the whitelist setting)\nPOST _reindex\n{ \"source\": { \"remote\": { \"host\": \"http://remote:9200\" }, \"index\": \"source_tbl\" },\n  \"dest\": { \"index\": \"target_tbl\" } }","note":"_reindex はインデックス間でコピーする。クエリで絞り込み、スクリプトで変換できる。クラスタ間ではリモート reindex を使用する(ターゲットに reindex.remote.whitelist の定義が必要)。大規模なジョブは slices で並列化する。","danger":"caution","priv":"ソースに対する read、ターゲットに対する write"}}},{"id":"generate-insert","title":"データを INSERT スクリプトとして生成","aliases":["generate insert","insert script","generate script","data dump","inserts","generate script"],"engines":{"oracle":{"command":"-- DBMS_METADATA for object DDL\nSELECT DBMS_METADATA.GET_DDL('TABLE','CUSTOMER') FROM dual;\n\n-- Generating row data as INSERTs is not built in;\n-- use SQL Developer 'Export > Insert' or SQLcl 'SET SQLFORMAT INSERT':\n-- SET SQLFORMAT INSERT\n-- SELECT * FROM customer;","note":"Oracle には、データを直接 INSERT スクリプトに変換する SQL コマンドはない。DDL には DBMS_METADATA.GET_DDL を、行の INSERT には SQLcl(SET SQLFORMAT INSERT)または SQL Developer のエクスポートウィザードを使用する。","danger":"safe","readonly":true,"priv":"テーブルに対する SELECT"},"postgres":{"command":"-- Data only, as INSERT statements\npg_dump --data-only --inserts --table=customer shop > insert.sql\n\n-- With column names (more robust to schema differences)\npg_dump --data-only --column-inserts --table=customer shop > insert.sql","note":"pg_dump --inserts は各行を個別の INSERT として書き出す。--column-inserts は列名も付加する(スキーマの差異に強い)。デフォルト(フラグなし)は COPY 形式で、ロードがはるかに高速。","danger":"safe","readonly":true,"priv":"テーブルに対する SELECT"},"mysql":{"command":"-- Data only (INSERTs), without the table definition\nmysqldump --no-create-info shop customer > insert.sql\n\n-- One INSERT per row (more readable)\nmysqldump --no-create-info --skip-extended-insert shop customer > insert.sql","note":"mysqldump はデフォルトで INSERT 文を生成する。--no-create-info は CREATE TABLE を省き、データのみを出力する。--skip-extended-insert は各行を個別の INSERT にする(デフォルトでは多数の行を 1 つの文にまとめる)。","danger":"safe","readonly":true,"priv":"テーブルに対する SELECT"},"mssql":{"command":"-- SSMS: right-click > Tasks > Generate Scripts >\n--   Advanced > 'Types of data to script' = Data only (or Schema and data)\n\n-- Command-line alternative (sqlpackage / mssql-scripter tool)\n-- mssql-scripter -S server -d shop -t customer --data-only > insert.sql","note":"SQL Server にはこのための組み込み T-SQL コマンドはない。最も一般的な方法は、SSMS の「Generate Scripts」ウィザードで Data only を選択すること。コマンドラインでは Microsoft の mssql-scripter ツールが --data-only で INSERT を生成する。","danger":"safe","readonly":true,"priv":"テーブルに対する SELECT"},"mongodb":{"command":"# Produces a binary/BSON backup instead of INSERT SQL\nmongodump --db=shop --collection=customer --out=./backup\n\n# As JSON text (can be adapted to insertMany)\nmongoexport --db=shop --collection=customer --jsonArray --out=customer.json","note":"SQL の INSERT の概念はない。可搬性のあるバックアップには mongodump を使用する(BSON、mongorestore でリストア)。コードに埋め込む insertMany には mongoexport --jsonArray の出力を使用できる。","danger":"safe","readonly":true,"priv":"find(read)"},"redis":{"command":"# Portable serialization of a single key\nDUMP customer:1\n# The output is restored with RESTORE:\n# RESTORE customer:1 0 \"<dump-data>\"\n\n# RDB snapshot for all data\nredis-cli --rdb dump.rdb","note":"SQL の INSERT スクリプトは生成されない。キーごとの DUMP + RESTORE シリアライズと、全データには RDB(--rdb)ファイルを使用する。コマンド一覧が必要な場合は、SCAN で走査し、型ごとに適切な SET/HSET コマンドを組み立てる。","danger":"safe","readonly":true},"elasticsearch":{"command":"# The INSERT equivalent is _bulk NDJSON; produce it with elasticdump\nelasticdump --input=http://localhost:9200/customer --output=customer_bulk.json --type=data\n\n# Manual: converting a _search result to _bulk NDJSON requires an external script","note":"SQL の INSERT は生成されない。Elasticsearch でのロードの単位は _bulk NDJSON。既存データを再ロード可能な形式で取り出すには elasticdump(type=data)を使用する。_search + PIT の出力は外部スクリプトで NDJSON に変換できる。","danger":"safe","readonly":true,"priv":"インデックスに対する read"}}}]},"rosetta/monitoring.json":{"category":"監視と診断","categoryId":"monitoring","order":12,"concepts":[{"id":"current-locks","title":"現在のロックを一覧表示","aliases":["locks","lock list","lock list","current locks","active locks"],"engines":{"oracle":{"command":"SELECT s.sid, s.serial#, l.type, DECODE(l.lmode,0,'None',1,'Null',2,'Row-S',3,'Row-X',4,'Share',5,'S/Row-X',6,'Exclusive') AS lmode, o.object_name, s.username, s.blocking_session\nFROM v$lock l\nJOIN v$session s ON s.sid = l.sid\nLEFT JOIN v$locked_object lo ON lo.session_id = l.sid\nLEFT JOIN dba_objects o ON o.object_id = lo.object_id\nORDER BY s.sid;","note":"v$lock と v$locked_object により、アクティブなロックとブロックしているセッション(blocking_session)を表示する。","danger":"safe","readonly":true,"priv":"v$lock、v$session に対する SELECT"},"postgres":{"command":"SELECT l.locktype, l.mode, l.granted, a.pid, a.usename, a.state, a.wait_event_type, a.query\nFROM pg_locks l\nJOIN pg_stat_activity a ON a.pid = l.pid\nWHERE l.pid <> pg_backend_pid()\nORDER BY l.granted, a.pid;","note":"pg_locks と pg_stat_activity を結合する。granted=false の行は待機中(ブロックされた)ロックを示す。","danger":"safe","readonly":true,"priv":"pg_monitor ロール(全クエリを表示するため)"},"mysql":{"command":"SELECT ENGINE, OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, THREAD_ID\nFROM performance_schema.data_locks;\n-- For waiters: SELECT * FROM performance_schema.data_lock_waits;","note":"performance_schema.data_locks は現在の InnoDB ロックを、data_lock_waits は待機関係を一覧表示する。","danger":"safe","readonly":true,"priv":"performance_schema に対する SELECT","minver":"8.0"},"mssql":{"command":"SELECT tl.resource_type, tl.resource_database_id, tl.request_mode, tl.request_status, tl.request_session_id, es.login_name, er.blocking_session_id\nFROM sys.dm_tran_locks tl\nLEFT JOIN sys.dm_exec_sessions es ON es.session_id = tl.request_session_id\nLEFT JOIN sys.dm_exec_requests er ON er.session_id = tl.request_session_id\nORDER BY tl.request_session_id;","note":"sys.dm_tran_locks は現在のロック要求を示す。request_status = WAIT のものはブロックされた要求。","danger":"safe","readonly":true,"priv":"VIEW SERVER STATE"},"mongodb":{"command":"db.currentOp({ \"$or\": [ { \"waitingForLock\": true }, { \"locks\": { \"$exists\": true } } ] })","note":"db.currentOp はロック待ちの操作(waitingForLock)とロックを保持している操作を示す。MongoDB は行レベルではなくドキュメント/コレクションレベルでロックする。","danger":"safe","priv":"inprog / clusterMonitor ロール"},"redis":{"command":"# Not applicable: Redis has no row/table lock concept; commands run sequentially on a single thread. For blocking analysis, use the SLOWLOG and LATENCY commands.","note":"Redis はシングルスレッドのため、従来のロック一覧はない。","danger":"safe"},"elasticsearch":{"command":"GET _cluster/pending_tasks","note":"Elasticsearch には行ロックがない。これはマスター上でキューに入っているクラスタ変更タスク(pending tasks)を一覧表示する。","danger":"safe","readonly":true}}},{"id":"long-operations","title":"長時間実行中の操作の進捗を表示","aliases":["progress","operation progress","long operations","long-running operations","longops"],"engines":{"oracle":{"command":"SELECT sid, serial#, opname, target, sofar, totalwork,\n       ROUND(sofar / NULLIF(totalwork,0) * 100, 2) AS pct_done,\n       time_remaining, elapsed_seconds\nFROM v$session_longops\nWHERE totalwork > 0 AND sofar < totalwork\nORDER BY start_time;","note":"v$session_longops は、6 秒を超えて実行されている操作の進捗率と残り時間(time_remaining)を示す。","danger":"safe","readonly":true,"priv":"v$session_longops に対する SELECT"},"postgres":{"command":"SELECT pid, phase, heap_blks_total, heap_blks_scanned,\n       ROUND(heap_blks_scanned::numeric / NULLIF(heap_blks_total,0) * 100, 2) AS pct\nFROM pg_stat_progress_vacuum;\n-- Others: pg_stat_progress_create_index, _cluster, _analyze, _copy, _basebackup","note":"pg_stat_progress_* ビューは VACUUM、CREATE INDEX、CLUSTER、ANALYZE、COPY 操作の進捗を報告する。","danger":"safe","readonly":true,"minver":"9.6"},"mysql":{"command":"SELECT t.processlist_id, st.event_name, st.work_completed, st.work_estimated,\n       ROUND(st.work_completed / NULLIF(st.work_estimated,0) * 100, 2) AS pct\nFROM performance_schema.events_stages_current st\nJOIN performance_schema.threads t ON t.thread_id = st.thread_id\nWHERE st.work_estimated > 0;","note":"ステージのインストルメンテーションが有効な場合、events_stages_current は work_completed/work_estimated で進捗を示す(例: ALTER TABLE)。","danger":"safe","readonly":true,"priv":"performance_schema に対する SELECT"},"mssql":{"command":"SELECT session_id, command, percent_complete,\n       DATEADD(ms, estimated_completion_time, GETDATE()) AS est_finish,\n       total_elapsed_time / 1000 AS elapsed_sec\nFROM sys.dm_exec_requests\nWHERE percent_complete > 0\nORDER BY percent_complete;","note":"sys.dm_exec_requests.percent_complete は BACKUP、RESTORE、DBCC、インデックスの再構築などの操作の進捗率を示す。","danger":"safe","readonly":true,"priv":"VIEW SERVER STATE"},"mongodb":{"command":"db.currentOp({ \"active\": true, \"secs_running\": { \"$gte\": 3 } })","note":"db.currentOp の出力では、長時間実行中の操作と、インデックス作成の場合は 'progress' フィールド(done/total)が進捗を示す。","danger":"safe","priv":"inprog / clusterMonitor ロール"},"redis":{"command":"INFO persistence\n# Keys: rdb_bgsave_in_progress, aof_rewrite_in_progress, rdb_last_bgsave_status, loading, loading_loaded_perc","note":"INFO persistence セクションは、RDB/AOF の保存や書き換えが進行中かどうかと、ロードの進捗率を報告する。","danger":"safe","readonly":true},"elasticsearch":{"command":"GET _tasks?detailed=true&actions=*reindex,*update/byquery,*delete/byquery\n# For recovery/shard relocation: GET _cat/recovery?v&active_only=true","note":"_tasks?detailed は長時間実行タスク(reindex、update_by_query)の状態を、_cat/recovery はアクティブなシャードリカバリの進捗を示す。","danger":"safe","readonly":true}}},{"id":"session-trace","title":"セッション/クエリをトレース(トレース/プロファイリングを有効化)","aliases":["trace","enable tracing","profiling","session trace","query tracing"],"engines":{"oracle":{"command":"-- For a specific session (10046 event tracing):\nBEGIN\n  DBMS_MONITOR.SESSION_TRACE_ENABLE(session_id => 123, serial_num => 4567, waits => TRUE, binds => TRUE);\nEND;\n/\n-- To disable: DBMS_MONITOR.SESSION_TRACE_DISABLE(123, 4567);","note":"DBMS_MONITOR.SESSION_TRACE_ENABLE はセッションの 10046 トレースファイルを生成する。終了後は必ず無効にすること(トレースはオーバーヘッドとディスク使用を伴う)。","danger":"caution","priv":"DBMS_MONITOR に対する EXECUTE"},"postgres":{"command":"LOAD 'auto_explain';\nSET auto_explain.log_min_duration = 0;\nSET auto_explain.log_analyze = true;\n-- Simple alternative: SET log_min_duration_statement = 0;","note":"auto_explain はクエリの実行計画を、log_min_duration_statement は遅い/すべてのクエリをログファイルに書き込む。値 0 はすべてのクエリを記録するため、ログ量に注意する。","danger":"caution","priv":"SUPERUSER(LOAD の場合)またはセッションレベルの SET"},"mysql":{"command":"-- performance_schema approach (recommended):\nUPDATE performance_schema.setup_consumers SET ENABLED='YES' WHERE NAME LIKE 'events_statements%';\n-- Legacy/simple method (being deprecated):\nSET profiling = 1;\n-- run the query, then:\nSHOW PROFILES;","note":"クエリのトレースは performance_schema の events_statements で行う。SET profiling の方法は古い(非推奨)が、セッション単位で手早く計測できる。","danger":"caution","priv":"performance_schema に対する SELECT/UPDATE"},"mssql":{"command":"CREATE EVENT SESSION [trace_slow] ON SERVER\nADD EVENT sqlserver.sql_statement_completed(\n  WHERE duration > 1000000)\nADD TARGET package0.event_file(SET filename=N'trace_slow.xel');\nGO\nALTER EVENT SESSION [trace_slow] ON SERVER STATE = START;","note":"Extended Events (XEvents) は最新のトレース方法。セッションを作成して START で開始し、終了後は STOP/DROP で停止する。","danger":"caution","priv":"ALTER ANY EVENT SESSION"},"mongodb":{"command":"db.setProfilingLevel(2)\n// 1 = slow operations only (slowms threshold), 0 = off\n// Results: db.system.profile.find().sort({ ts: -1 }).limit(10)","note":"setProfilingLevel(2) はすべての操作を system.profile コレクションに記録する。レベル 2 はオーバーヘッドを伴うため、本番環境では 1(遅いもののみ)が推奨される。","danger":"caution","priv":"dbAdmin / enableProfiler"},"redis":{"command":"MONITOR\n# Streams all commands arriving at the server in real time. Exit: Ctrl-C","note":"MONITOR はすべてのコマンドをリアルタイムで表示するが、性能が大きく低下する。本番環境では短時間に限り慎重に使用する。代替手段: SLOWLOG GET。","danger":"caution"},"elasticsearch":{"command":"GET my-index/_search\n{\n  \"profile\": true,\n  \"query\": { \"match\": { \"title\": \"elastic\" } }\n}\n// Persistent slow query tracing: the index.search.slowlog.threshold.query.warn setting","note":"\"profile\": true は単一の検索のクエリ/集計の所要時間の内訳を返す。継続的な監視には slowlog のしきい値を設定する。","danger":"safe","readonly":true}}},{"id":"top-wait-events","title":"上位の待機イベントを表示","aliases":["wait events","wait event list","top waits","waits"],"engines":{"oracle":{"command":"SELECT event, total_waits, time_waited, ROUND(time_waited/100,2) AS sec_waited\nFROM v$system_event\nWHERE wait_class <> 'Idle'\nORDER BY time_waited DESC\nFETCH FIRST 20 ROWS ONLY;\n-- For real-time analysis: v$active_session_history (ASH)","note":"v$system_event は累積の待機イベントを、v$active_session_history は直近数分間のアクティブセッションのサンプリングを提供する(Diagnostics Pack のライセンスが必要)。","danger":"safe","readonly":true,"priv":"v$system_event に対する SELECT"},"postgres":{"command":"SELECT wait_event_type, wait_event, count(*)\nFROM pg_stat_activity\nWHERE wait_event IS NOT NULL AND state = 'active'\nGROUP BY 1, 2\nORDER BY 3 DESC;","note":"pg_stat_activity は現在の待機状態を示す。繰り返しサンプリング(ポーリング)すると最も頻繁な待機イベントが分かる。","danger":"safe","readonly":true,"priv":"pg_monitor ロール"},"mysql":{"command":"SELECT event_name, count_star, sum_timer_wait,\n       ROUND(sum_timer_wait/1000000000000, 2) AS sec_waited\nFROM performance_schema.events_waits_summary_global_by_event_name\nWHERE count_star > 0\nORDER BY sum_timer_wait DESC\nLIMIT 20;","note":"events_waits_summary_global_by_event_name はイベントごとの合計待機時間(ピコ秒単位)を示す。待機のインストルメントを有効にする必要がある。","danger":"safe","readonly":true,"priv":"performance_schema に対する SELECT"},"mssql":{"command":"SELECT wait_type, waiting_tasks_count, wait_time_ms,\n       signal_wait_time_ms, wait_time_ms - signal_wait_time_ms AS resource_wait_ms\nFROM sys.dm_os_wait_stats\nWHERE wait_time_ms > 0\nORDER BY wait_time_ms DESC;","note":"sys.dm_os_wait_stats はインスタンス起動以降の累積の待機タイプを示す。DBCC SQLPERF でリセットできる。","danger":"safe","readonly":true,"priv":"VIEW SERVER STATE"},"mongodb":{"command":"db.serverStatus().wiredTiger.concurrentTransactions\n// For general waits/congestion:\n// db.serverStatus().globalLock  and  db.serverStatus().wiredTiger.cache","note":"WiredTiger には従来の待機イベントがない。concurrentTransactions(チケット)の枯渇、globalLock.currentQueue、キャッシュ圧迫が輻輳を示す。","danger":"safe","priv":"clusterMonitor ロール"},"redis":{"command":"CONFIG SET latency-monitor-threshold 100\nLATENCY LATEST\nLATENCY HISTORY command\n# For the slowest commands: SLOWLOG GET 10","note":"latency monitor のしきい値を設定すると、LATENCY LATEST/HISTORY が最も大きなレイテンシを引き起こしているイベントを報告する。","danger":"safe"},"elasticsearch":{"command":"GET _nodes/hot_threads","note":"_nodes/hot_threads は CPU を最も消費しているスレッドのスタックトレースを示し、ボトルネックを明らかにする。","danger":"safe","readonly":true}}},{"id":"os-resource","title":"DB 内からサーバーのリソース使用状況(CPU/IO)を表示","aliases":["os resource","cpu io","resource usage","server resources","system metrics"],"engines":{"oracle":{"command":"SELECT stat_name, value FROM v$osstat\nWHERE stat_name IN ('NUM_CPUS','BUSY_TIME','IDLE_TIME','IOWAIT_TIME','PHYSICAL_MEMORY_BYTES');\n-- Real-time metrics: SELECT metric_name, value FROM v$sysmetric WHERE group_id = 2;","note":"v$osstat は OS の CPU/メモリカウンタを、v$sysmetric は直近の間隔のリアルタイム DB メトリクス(CPU、IOPS)を提供する。","danger":"safe","readonly":true,"priv":"v$osstat、v$sysmetric に対する SELECT"},"postgres":{"command":"SELECT backend_type, object, context, reads, writes, hits, evictions\nFROM pg_stat_io\nORDER BY reads DESC;\n-- Note: CPU usage is not visible from inside the DB; an OS tool (top, sar) is required.","note":"pg_stat_io は読み取り/書き込み/キャッシュヒットのカウンタを提供する。PostgreSQL は CPU 使用率を公開しないため、OS のツールが必要。","danger":"safe","readonly":true,"minver":"16"},"mysql":{"command":"SELECT * FROM sys.host_summary;\n-- For InnoDB I/O and thread details:\nSHOW ENGINE INNODB STATUS\\G","note":"sys スキーマのサマリービュー(host_summary)は IO/レイテンシの内訳を示す。SHOW ENGINE INNODB STATUS はバッファプールと IO のアクティビティを示す。","danger":"safe","readonly":true,"priv":"sys に対する SELECT、PROCESS"},"mssql":{"command":"SELECT object_name, counter_name, cntr_value\nFROM sys.dm_os_performance_counters\nWHERE counter_name LIKE '%CPU%' OR counter_name LIKE '%Page life expectancy%';\n-- CPU history: sys.dm_os_ring_buffers (RING_BUFFER_SCHEDULER_MONITOR)","note":"sys.dm_os_performance_counters は DB のパフォーマンスカウンタを、dm_os_ring_buffers は直近約 256 分間の SQL/その他プロセスの CPU 比率を提供する。","danger":"safe","readonly":true,"priv":"VIEW SERVER STATE"},"mongodb":{"command":"db.serverStatus().metrics\n// Relevant fields: .opcounters, .network, .wiredTiger.cache, .mem, .extra_info.page_faults","note":"serverStatus() はメモリ、ネットワーク、opcounters、WiredTiger キャッシュのメトリクスを提供する。OS の詳細な CPU/IO には mongostat または OS のツールを使用する。","danger":"safe","priv":"clusterMonitor ロール"},"redis":{"command":"INFO cpu\nINFO stats\n# used_cpu_sys, used_cpu_user, instantaneous_ops_per_sec, total_net_input_bytes","note":"INFO cpu は Redis プロセスの CPU 消費を、INFO stats は毎秒の操作数とネットワークトラフィックを報告する。","danger":"safe","readonly":true},"elasticsearch":{"command":"GET _nodes/stats/os,process\n// Look at the os.cpu.percent, os.mem, process.cpu.percent, fs (disk) fields","note":"_nodes/stats/os,process はノードごとの CPU 使用率、メモリ、プロセスのメトリクスを提供する。ディスクには fs セクションを使用する。","danger":"safe","readonly":true}}}]},"rosetta/automation.json":{"category":"自動化と監査","categoryId":"automation","order":13,"concepts":[{"id":"schedule-job","title":"スケジュールジョブを作成","aliases":["schedule job","scheduled job","cron","create job","scheduled task"],"engines":{"oracle":{"command":"BEGIN\n  DBMS_SCHEDULER.CREATE_JOB(\n    job_name        => 'NIGHTLY_MAINT',\n    job_type        => 'PLSQL_BLOCK',\n    job_action      => 'BEGIN my_maintenance_proc; END;',\n    start_date      => SYSTIMESTAMP,\n    repeat_interval => 'FREQ=DAILY; BYHOUR=3',\n    enabled         => TRUE);\nEND;\n/","note":"DBMS_SCHEDULER.CREATE_JOB はスケジュールジョブを定義する。repeat_interval はカレンダー式で繰り返し間隔を設定する。","danger":"caution","priv":"CREATE JOB"},"postgres":{"command":"SELECT cron.schedule('nightly-vacuum', '0 3 * * *', 'VACUUM ANALYZE');\n-- Requires the pg_cron extension. Alternative: pgAgent.","note":"pg_cron 拡張は cron.schedule により標準の cron 構文でジョブを定義する。拡張がインストールされていない場合は pgAgent または OS の cron を使用する。","danger":"caution","priv":"pg_cron がインストール済み。通常は superuser/拡張の所有者"},"mysql":{"command":"SET GLOBAL event_scheduler = ON;\nCREATE EVENT nightly_cleanup\nON SCHEDULE EVERY 1 DAY STARTS '2026-01-01 03:00:00'\nDO\n  DELETE FROM logs WHERE created_at < NOW() - INTERVAL 30 DAY;","note":"CREATE EVENT はイベントスケジューラによって実行される。event_scheduler グローバル変数が ON でないとイベントは起動しない。","danger":"caution","priv":"EVENT"},"mssql":{"command":"USE msdb;\nEXEC dbo.sp_add_job @job_name = N'NightlyMaint';\nEXEC dbo.sp_add_jobstep @job_name = N'NightlyMaint', @step_name = N'Step1',\n     @subsystem = N'TSQL', @command = N'EXEC dbo.usp_Maintenance;';\nEXEC dbo.sp_add_schedule @schedule_name = N'Daily3AM',\n     @freq_type = 4, @freq_interval = 1, @active_start_time = 030000;\nEXEC dbo.sp_attach_schedule @job_name = N'NightlyMaint', @schedule_name = N'Daily3AM';\nEXEC dbo.sp_add_jobserver @job_name = N'NightlyMaint';","note":"SQL Server Agent のジョブは msdb のプロシージャで作成する。ジョブ、ステップ、スケジュールを定義してサーバーに関連付ける。SQL Server Agent サービスが稼働している必要がある。","danger":"caution","priv":"SQLAgentUserRole または sysadmin"},"mongodb":{"command":"# Not applicable: MongoDB has no built-in scheduler. Use external cron/systemd timers, an application scheduler or a MongoDB Atlas Scheduled Trigger.","note":"Community エディションにはスケジュールジョブがない。外部スケジューラまたは Atlas Trigger が必要。","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no built-in job scheduler. Use EXPIRE/keyspace notifications for key expiry and external cron for periodic tasks.","note":"Redis はスケジュールジョブを実行しない。TTL/キースペース通知と外部の cron で対応する。","danger":"safe"},"elasticsearch":{"command":"PUT _slm/policy/daily-snapshot\n{\n  \"schedule\": \"0 30 1 * * ?\",\n  \"name\": \"<snap-{now/d}>\",\n  \"repository\": \"backup_repo\",\n  \"config\": { \"indices\": [\"*\"] },\n  \"retention\": { \"expire_after\": \"30d\" }\n}","note":"SLM (Snapshot Lifecycle Management) はスケジュールされたスナップショットを取得する。データのライフサイクルには ILM を、高度な自動化には Watcher を使用する。","danger":"caution","priv":"manage_slm クラスタ権限"}}},{"id":"list-jobs","title":"スケジュールジョブを一覧表示/状態を表示","aliases":["list jobs","show jobs","job status","scheduled jobs","job history"],"engines":{"oracle":{"command":"SELECT job_name, enabled, state, last_start_date, next_run_date\nFROM dba_scheduler_jobs\nORDER BY next_run_date;\n-- Run history: SELECT job_name, status, actual_start_date, run_duration\n--                 FROM dba_scheduler_job_run_details ORDER BY log_date DESC;","note":"dba_scheduler_jobs は定義済みのジョブとその状態を、dba_scheduler_job_run_details は過去の実行の成功/失敗の結果を示す。","danger":"safe","readonly":true,"priv":"dba_scheduler_jobs に対する SELECT"},"postgres":{"command":"SELECT jobid, schedule, command, nodename, active FROM cron.job;\n-- Run history:\nSELECT jobid, status, return_message, start_time, end_time\nFROM cron.job_run_details ORDER BY start_time DESC LIMIT 20;","note":"pg_cron では、cron.job が定義済みのジョブを一覧表示し、cron.job_run_details が各実行の状態と戻りメッセージを示す。","danger":"safe","readonly":true,"priv":"pg_cron がインストール済み。cron スキーマへのアクセス"},"mysql":{"command":"SELECT event_schema, event_name, status, interval_value, interval_field, last_executed\nFROM information_schema.events\nORDER BY last_executed DESC;","note":"information_schema.events は定義済みのイベント、その状態(ENABLED/DISABLED)、最終実行時刻を一覧表示する。","danger":"safe","readonly":true,"priv":"EVENT / SELECT"},"mssql":{"command":"SELECT j.name, j.enabled, h.run_status, h.run_date, h.run_time\nFROM msdb.dbo.sysjobs j\nLEFT JOIN msdb.dbo.sysjobhistory h ON h.job_id = j.job_id AND h.step_id = 0\nORDER BY h.run_date DESC, h.run_time DESC;","note":"msdb.dbo.sysjobs は定義済みの Agent ジョブを、sysjobhistory は実行履歴と結果(run_status)を示す。","danger":"safe","readonly":true,"priv":"SQLAgentReaderRole / msdb へのアクセス"},"mongodb":{"command":"# Not applicable: there is no built-in scheduler, so there are no jobs to list. If Atlas Triggers are used, view them in the Atlas UI/API.","note":"Community 版 MongoDB にはジョブテーブルがない。Atlas Trigger は Atlas のインターフェースで管理する。","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no concept of scheduled jobs, so there are no jobs to list.","note":"Redis にはジョブスケジューラが含まれておらず、一覧表示するジョブはない。","danger":"safe"},"elasticsearch":{"command":"GET _slm/policy\nGET _ilm/policy\n// For Watcher states: GET _watcher/stats  and  GET _watcher/_query/watches","note":"_slm/policy はスナップショットポリシーを、_ilm/policy はライフサイクルポリシーを一覧表示し、_watcher/stats は Watcher の実行状態を示す。","danger":"safe","readonly":true,"priv":"read_slm / read_ilm 権限"}}},{"id":"enable-audit","title":"監査/ロギングを有効化","aliases":["audit","auditing","logging","enable audit","audit log"],"engines":{"oracle":{"command":"-- Unified Auditing (12c+):\nCREATE AUDIT POLICY table_audit\n  ACTIONS SELECT, INSERT, UPDATE, DELETE ON hr.employees;\nAUDIT POLICY table_audit;\n-- Monitoring: SELECT * FROM unified_audit_trail ORDER BY event_timestamp DESC;","note":"Unified Auditing では、ポリシーを作成して AUDIT で有効化する。記録は unified_audit_trail ビューに保持される。","danger":"caution","priv":"AUDIT SYSTEM / AUDIT_ADMIN ロール","minver":"12.1"},"postgres":{"command":"-- pgaudit extension (recommended; first shared_preload_libraries = 'pgaudit' + restart + CREATE EXTENSION pgaudit):\nALTER SYSTEM SET pgaudit.log = 'write, ddl';\nSELECT pg_reload_conf();\n-- Simple built-in method:\nALTER SYSTEM SET log_statement = 'ddl';\nSELECT pg_reload_conf();","note":"pgaudit は詳細な監査ロギングを提供する。サーバー全体に適用するには ALTER SYSTEM で設定する(セッションレベルの SET はそのセッションのみを監査する)。拡張がない場合は log_statement('ddl','mod','all')で基本的なロギングを有効にする。ログ量に注意すること。","danger":"caution","priv":"superuser(ALTER SYSTEM)"},"mysql":{"command":"-- Enterprise/MariaDB audit plugin:\nINSTALL PLUGIN audit_log SONAME 'audit_log.so';\nSET GLOBAL audit_log_policy = 'ALL';\n-- Simple alternative (all queries):\nSET GLOBAL general_log = 'ON';","note":"audit_log プラグイン(Enterprise、MariaDB では server_audit)は詳細な監査証跡を保持する。general_log はすべてのクエリを記録するが性能を低下させる。","danger":"caution","priv":"SUPER / SYSTEM_VARIABLES_ADMIN"},"mssql":{"command":"USE master;\nCREATE SERVER AUDIT Audit_A TO FILE (FILEPATH = 'C:\\\\audit\\\\');\nALTER SERVER AUDIT Audit_A WITH (STATE = ON);\nUSE mydb;\nCREATE DATABASE AUDIT SPECIFICATION db_spec\n  FOR SERVER AUDIT Audit_A\n  ADD (SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo BY public)\n  WITH (STATE = ON);","note":"まず SERVER AUDIT のターゲット(ファイル/イベントログ)を作成して有効にし、次にサーバーまたはデータベースの AUDIT SPECIFICATION で追跡するイベントを定義する。","danger":"caution","priv":"ALTER ANY SERVER AUDIT / CONTROL SERVER"},"mongodb":{"command":"# MongoDB Enterprise / Atlas only. Configuration (mongod.conf):\n#   auditLog:\n#     destination: file\n#     format: JSON\n#     path: /var/log/mongodb/audit.json\n#     filter: '{ atype: { $in: [\"authCheck\",\"createCollection\",\"dropCollection\"] } }'\n# mongod --auditDestination file --auditPath /var/log/mongodb/audit.json","note":"監査は Enterprise と Atlas でのみ利用でき、mongod 構成の auditLog セクションで有効にする。Community エディションには存在しない。","danger":"caution"},"redis":{"command":"ACL LOG\n# Shows rejected authentication/command/key access attempts.\n# To reset: ACL LOG RESET\n# For general command auditing: an external proxy or MONITOR (with care).","note":"ACL LOG はセキュリティイベント(認証の失敗、許可されていないコマンド/キー)を自動的に記録する。完全なコマンド監査は組み込まれていない。","danger":"safe","priv":"ACL 権限(デフォルトでは admin)"},"elasticsearch":{"command":"# elasticsearch.yml (on all nodes, restart required):\nxpack.security.audit.enabled: true\n# Optional event filter:\nxpack.security.audit.logfile.events.include: [ \"authentication_failed\", \"access_denied\" ]","note":"監査ロギングは xpack.security.audit.enabled で有効にする。elasticsearch.yml で設定し、ノードの再起動が必要(動的ではない)。商用ライセンスが必要。","danger":"caution"}}},{"id":"current-config-diff","title":"デフォルト以外の設定を一覧表示","aliases":["config diff","changed settings","non-default settings","modified settings","modified config"],"engines":{"oracle":{"command":"SELECT name, value, isdefault\nFROM v$parameter\nWHERE isdefault = 'FALSE'\nORDER BY name;","note":"v$parameter で isdefault = 'FALSE' の行は、デフォルトと異なる(明示的に設定された)パラメータを示す。","danger":"safe","readonly":true,"priv":"v$parameter に対する SELECT"},"postgres":{"command":"SELECT name, setting, unit, source\nFROM pg_settings\nWHERE source NOT IN ('default', 'override')\nORDER BY name;","note":"pg_settings.source が 'default' と 'override' 以外の場合、その設定は構成ファイル、コマンドライン、またはセッションによって変更されている。","danger":"safe","readonly":true},"mysql":{"command":"SHOW GLOBAL VARIABLES;\n-- MySQL does not automatically compare variables with defaults; with performance_schema\n-- you can see the source of each setting:\nSELECT VARIABLE_NAME, VARIABLE_SOURCE, VARIABLE_VALUE\nFROM performance_schema.variables_info\nWHERE VARIABLE_SOURCE <> 'COMPILED';","note":"SHOW GLOBAL VARIABLES はすべての設定を返すが、デフォルトとの差分を直接は示さない。performance_schema.variables_info の VARIABLE_SOURCE 列は、コンパイル時のデフォルト以外による変更(ファイル、コマンドライン、動的)を示す。","danger":"safe","readonly":true,"minver":"8.0"},"mssql":{"command":"SELECT name, value, value_in_use, is_dynamic, is_advanced\nFROM sys.configurations\nWHERE value <> value_in_use\nORDER BY name;\n-- value <> value_in_use: changes not yet RECONFIGUREd or awaiting a restart (is_dynamic = 0).","note":"sys.configurations はサーバー設定を返す。value と value_in_use が異なる場合、RECONFIGURE で適用されていない(または再起動待ちの)変更がある。sys.configurations はデフォルト値を保持しない(minimum/maximum は許容範囲にすぎない)。デフォルトとの差分を確認するには、ドキュメント記載のデフォルト値と比較する。","danger":"safe","readonly":true,"priv":"VIEW SERVER STATE"},"mongodb":{"command":"db.adminCommand({ getCmdLineOpts: 1 })\n// The 'parsed' field shows settings explicitly provided (configuration file/command line) beyond the defaults.","note":"getCmdLineOpts コマンドの 'parsed' セクションは、明示的に指定された(デフォルト以外の)設定のみを一覧表示する。","danger":"safe","priv":"clusterMonitor / hostInfo 権限"},"redis":{"command":"CONFIG GET *\n# Redis lists all settings but does not compare them with defaults.\n# To see differences, compare the output with the default redis.conf values for your version.","note":"CONFIG GET * は実行中のすべての設定を返す。デフォルトとの差分機能は組み込まれていないため、出力を該当バージョンのデフォルトの redis.conf の値と比較する。","danger":"safe","readonly":true},"elasticsearch":{"command":"GET _cluster/settings\n// Returns only explicitly set persistent and transient settings.\n// For everything including defaults: GET _cluster/settings?include_defaults=true&flat_settings=true","note":"_cluster/settings はデフォルト以外の(persistent/transient)クラスタ設定を返す。include_defaults=true を付けると、比較用にデフォルト値も表示される。","danger":"safe","readonly":true}}}]},"rosetta/lifecycle.json":{"category":"インストールとアップグレード","categoryId":"lifecycle","order":14,"concepts":[{"id":"check-version","title":"インストール済みのバージョンとパッチレベルを表示","aliases":["version","patch level","server version","patch level check","release","build"],"engines":{"oracle":{"command":"SELECT * FROM v$version;\n-- Registered RU/patch history (SQL layer):\nSELECT patch_id, action, status, action_time\nFROM dba_registry_sqlpatch ORDER BY action_time;\n-- From the OS shell (patches installed in ORACLE_HOME):\n-- $ORACLE_HOME/OPatch/opatch lspatches","note":"v$version のバナーがバージョンを示す。dba_registry_sqlpatch は適用済みの Release Update (RU) と個別パッチが SQL 層に登録されているかを示し、'opatch lspatches' はホーム内のバイナリパッチを示す。","danger":"safe","readonly":true,"priv":"v$version、dba_registry_sqlpatch に対する SELECT"},"postgres":{"command":"SELECT version();\n-- Numeric version only:\nSHOW server_version;\nSELECT current_setting('server_version_num');","note":"version() はビルド情報を含む完全なテキストを返す。PostgreSQL には個別のパッチ番号がなく、マイナーバージョン(例: 16.3)が修正レベルを表す。","danger":"safe","readonly":true},"mysql":{"command":"SELECT VERSION();\n-- Detailed build information:\nSHOW VARIABLES LIKE 'version%';","note":"VERSION() は例えば '8.0.36' を返し、最後の要素がパッチ(リリース)レベル。version_comment 変数は、ビルドが Community/Enterprise か MariaDB かを示す。","danger":"safe","readonly":true},"mssql":{"command":"SELECT @@VERSION;\n-- Structured version fields:\nSELECT SERVERPROPERTY('ProductVersion')       AS version,\n       SERVERPROPERTY('ProductLevel')         AS service_pack,\n       SERVERPROPERTY('ProductUpdateLevel')   AS cu_level,\n       SERVERPROPERTY('ProductUpdateReference') AS kb_number,\n       SERVERPROPERTY('Edition')              AS edition;","note":"ProductUpdateLevel は適用済みの Cumulative Update(例: CU12)を、ProductUpdateReference は関連する KB 番号を示す。ProductLevel は 'RTM'、古いバージョンでは 'SP' を示す。","danger":"safe","readonly":true},"mongodb":{"command":"db.version()\n// Detailed build information:\ndb.serverBuildInfo()\n// or: db.adminCommand({ buildInfo: 1 })","note":"db.version() はバージョン文字列(例: '7.0.11')を返す。MongoDB では修正は新しいパッチバージョンとしてリリースされ、独立した「パッチレベル」の概念はない。","danger":"safe"},"redis":{"command":"INFO server\n# redis-cli one-liner: redis-cli INFO server | grep redis_version","note":"INFO server 出力の redis_version フィールドがインストール済みのバージョンを示す。Redis では修正は新しいパッチバージョン(例: 7.2.5)として提供される。redis_git_sha1 フィールドはビルド識別子も示す。","danger":"safe"},"elasticsearch":{"command":"GET /\n# curl: curl -s http://localhost:9200/","note":"ルートエンドポイントは version.number(例: '8.14.1')、lucene_version、build_flavor を返す。全ノードのバージョンを確認するには: GET _cat/nodes?v&h=name,version","danger":"safe","readonly":true}}},{"id":"check-upgrade-readiness","title":"アップグレード前の互換性/準備状況チェック","aliases":["upgrade readiness","preupgrade","compatibility check","readiness","compatibility check","deprecation"],"engines":{"oracle":{"command":"-- Recommended method for 19c and later (AutoUpgrade analyze mode):\n-- $ java -jar autoupgrade.jar -config db.cfg -mode analyze\n-- Legacy/alternative: preupgrade script (produces a report only):\n-- $ $NEW_ORACLE_HOME/jdk/bin/java -jar $NEW_ORACLE_HOME/rdbms/admin/preupgrade.jar FILE TEXT DIR /tmp","note":"AutoUpgrade の 'analyze' モードは、データを変更せずにアップグレード前レポートを生成し、修正が必要な警告と自動的に解決される項目を一覧表示する。実際のアップグレードの前に必ず実行すること。","danger":"safe"},"postgres":{"command":"# With the new version's binaries, compatibility check only (moves no data):\n$ pg_upgrade \\\n    --old-datadir=/var/lib/pgsql/16/data \\\n    --new-datadir=/var/lib/pgsql/17/data \\\n    --old-bindir=/usr/pgsql-16/bin \\\n    --new-bindir=/usr/pgsql-17/bin \\\n    --check","note":"--check はデータを変更せずにアップグレードが可能かを検証する(不足している拡張、互換性のないデータ型などを報告する)。--check は旧クラスタの稼働中にも実行でき、実際のアップグレードは両方のクラスタを停止して行う。","danger":"safe"},"mysql":{"command":"-- 8.0 and later: Upgrade Checker utility (MySQL Shell):\n-- $ mysqlsh -- util check-for-server-upgrade { --user=root --host=localhost }\n-- Table consistency for legacy 5.7->8.0:\n$ mysqlcheck --all-databases --check-upgrade -u root -p","note":"MySQL Shell の util.checkForServerUpgrade() は、削除された機能、予約語の衝突、互換性のない定義を報告する。8.0 以降はサーバーが起動時に自らディクショナリのアップグレードを行うため、個別の mysql_upgrade は不要になった。","danger":"safe"},"mssql":{"command":"-- Run from the desktop with Data Migration Assistant (DMA):\n-- DmaCmd.exe /AssessmentName=... /AssessmentDatabases=...\n-- (Produces compatibility/deprecated feature and blocker reports.)","note":"Data Migration Assistant (DMA) は旧来の Upgrade Advisor に代わるもので、データベースごとに非推奨の機能、破壊的変更、ブロッカーを報告する。アップグレード前に実行し、検出事項を解決する。","danger":"safe"},"mongodb":{"command":"// Verify the current Feature Compatibility Version (FCV):\ndb.adminCommand({ getParameter: 1, featureCompatibilityVersion: 1 })\n// Compatibility items (deprecations) in the release notes are reviewed manually.","note":"バイナリバージョンをアップグレードする前に、FCV が現在のバージョンと一致している必要がある。そうでないとアップグレードはブロックされる。MongoDB には自動の「非推奨スキャナ」がなく、リリースの互換性に関する注記を手動で確認する。","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no separate pre-upgrade readiness tool.\n# Checklist: read the target version's release notes for RDB/AOF persistence format,\n# changed configuration directives, and removed commands/arguments.","note":"Redis のアップグレードは一般に前方互換。公式の準備状況スキャナはないため、RDB/AOF のファイル形式、削除された構成ディレクティブ、コマンドの変更をリリースノートで手動で確認する。","danger":"safe"},"elasticsearch":{"command":"GET _migration/deprecations\n# For a specific component: GET <index>/_migration/deprecations","note":"Deprecation Info API は、次のメジャーバージョンへの移行時に問題となるクラスタ、ノード、インデックス、ML の設定を 'critical' / 'warning' として一覧表示する。Kibana Upgrade Assistant は同じデータを視覚化する。","danger":"safe","readonly":true}}},{"id":"apply-patch","title":"パッチを適用","aliases":["apply patch","patching","patch","minor upgrade","hotfix","ru apply"],"engines":{"oracle":{"command":"# 1) Shut down the database, apply the binary patch with OPatch:\n$ $ORACLE_HOME/OPatch/opatch apply\n# 2) Open the database and load the SQL layer changes:\n$ $ORACLE_HOME/OPatch/datapatch -verbose","note":"opatch apply は Oracle Home のバイナリを更新する。その後 datapatch がオープン中のデータベースにディクショナリ/SQL の変更を適用し、dba_registry_sqlpatch に記録する。RAC ではローリング適用可能なパッチをノードごとに適用できる。","danger":"caution","priv":"OS: ORACLE_HOME の所有者、SQL: SYSDBA"},"postgres":{"command":"# Minor version patch = replace binaries + restart (no dump needed):\n$ sudo systemctl stop postgresql-16\n$ sudo dnf update postgresql16-server   # or apt upgrade\n$ sudo systemctl start postgresql-16","note":"同じメジャーバージョン系列内のマイナーパッチ(16.3 -> 16.4)はデータ形式を変更しない。パッケージを更新してサービスを再起動するだけでよく、pg_upgrade やダンプ/リストアは不要。","danger":"caution"},"mysql":{"command":"# Minor/patch update: update the package and restart the service\n$ sudo systemctl stop mysqld\n$ sudo dnf update mysql-community-server   # or apt upgrade\n$ sudo systemctl start mysqld","note":"MySQL 8.0+ は起動時にデータディクショナリを自動的にアップグレードするため、個別の mysql_upgrade の手順は不要。レプリケーションでは、先にレプリカ、次にソースにパッチを適用する。","danger":"caution"},"mssql":{"command":"-- Run the Cumulative Update (CU) or GDR security update installer:\n-- SQLServer2022-KB<no>-x64.exe /quiet /IAcceptSQLServerLicenseTerms\n--   /Action=Patch /InstanceName=MSSQLSERVER\n-- The instance then restarts; verify the version with SERVERPROPERTY.","note":"CU (Cumulative Update) と GDR (General Distribution Release) の更新は setup インストーラで適用し、インスタンスの再起動が必要。Always On グループでは、ダウンタイムを最小化するため、先にセカンダリレプリカにパッチを適用してからフェイルオーバーする。","danger":"caution"},"mongodb":{"command":"// 'Rolling' patch on a replica set: one node at a time\n// 1) Stop mongod, replace the binary with the new patch version, restart\n// 2) Secondaries first, the primary last\n// Step down the primary manually before patching it:\nrs.stepDown()","note":"同じメジャーバージョン内(7.0.x)のパッチ更新は、セカンダリから順にローリング方式で行う。プライマリは rs.stepDown() で役割を引き渡してからパッチを適用し、書き込みのダウンタイムを最小化する。","danger":"caution"},"redis":{"command":"# Patch via rolling restart in a replicated deployment:\n# 1) Stop one replica node, install the new version, start it, wait for sync\n# 2) Repeat for the remaining replicas\n# 3) Finally, fail over the master and patch it:\nredis-cli -h <replica> REPLICAOF NO ONE   # promote the upgraded replica","note":"パッチバージョン(7.2.x)はローリング再起動で適用する。先にレプリカをアップグレードして再同期し、次にレプリカを master に昇格させて旧 master にパッチを適用する。Sentinel/Cluster はフェイルオーバーを自動化する。","danger":"caution"},"elasticsearch":{"command":"# Rolling upgrade (patch within the same major version), per node:\nPUT _cluster/settings\n{ \"persistent\": { \"cluster.routing.allocation.enable\": \"primaries\" } }\n# -> stop the node, update the package, start the node, then:\nPUT _cluster/settings\n{ \"persistent\": { \"cluster.routing.allocation.enable\": null } }","note":"パッチ/マイナーアップグレードはローリングアップグレードで行う。シャードの割り当てを制限し、ノードを 1 台ずつ更新して再起動した後、割り当てを再度有効にし、クラスタが green に戻るのを待つ。","danger":"caution"}}},{"id":"upgrade-major","title":"メジャーバージョンアップグレード","aliases":["major upgrade","major version","version upgrade","release upgrade","version upgrade"],"engines":{"oracle":{"command":"# Recommended: AutoUpgrade (analyze + fixups + deploy in a single flow):\n$ java -jar $NEW_ORACLE_HOME/rdbms/admin/autoupgrade.jar -config db.cfg -mode deploy\n# Graphical alternative: DBUA (Database Upgrade Assistant)\n$ $NEW_ORACLE_HOME/bin/dbua","note":"AutoUpgrade は分析、事前修正、アップグレード、事後処理を単一のコマンドで実行する。複数のデータベースを順に処理してダウンタイムを短縮できる。DBUA は同じ処理をガイド付きインターフェースで行う。事前のフルバックアップは必須。","danger":"danger","priv":"SYSDBA + OS: 新しい ORACLE_HOME の所有者"},"postgres":{"command":"# pg_upgrade to the new major version (with both clusters stopped):\n$ pg_upgrade \\\n    --old-datadir=/var/lib/pgsql/16/data \\\n    --new-datadir=/var/lib/pgsql/17/data \\\n    --old-bindir=/usr/pgsql-16/bin \\\n    --new-bindir=/usr/pgsql-17/bin \\\n    --link   # fast migration with hard links\n# Then gather statistics (analyze_new_cluster.sh was removed in PG14):\n$ vacuumdb --all --analyze-in-stages","note":"pg_upgrade はメジャーバージョンの移行(16 -> 17)をインプレースで行う。--link モードはファイルをコピーせずにハードリンクを作成して時間を短縮するが、旧クラスタは使用不能になる。移行後は統計を再収集する必要がある。","danger":"danger"},"mysql":{"command":"# In-place upgrade (same datadir, new binaries):\n$ sudo systemctl stop mysqld\n$ sudo dnf install mysql-community-server-8.4   # replacing the old package\n$ sudo systemctl start mysqld   # the server upgrades the dictionary automatically","note":"MySQL 8.x 以降はインプレースのメジャーアップグレードがサポートされる。新しいバイナリで起動したサーバーがデータディクショナリとシステムテーブルを自動的に変換する(旧来の個別の mysql_upgrade 手順は削除された)。メジャーバージョンは 1 つずつアップグレードする。","danger":"danger"},"mssql":{"command":"-- In-place major version upgrade (with setup):\n-- setup.exe /q /ACTION=upgrade /INSTANCENAME=MSSQLSERVER\n--   /IAcceptSQLServerLicenseTerms\n-- Alternative: install a new instance side by side and move the databases (restore/attach).","note":"setup /ACTION=upgrade はインスタンスを新しいメジャーバージョンにインプレースでアップグレードする。より安全な方法は、サイドバイサイドでインストールし、バックアップ/リストアでデータベースを移行して、互換性レベルを別の手順で引き上げること。","danger":"danger"},"mongodb":{"command":"// Stepwise major upgrade (e.g. 6.0 -> 7.0), one major version at a time:\n// 1) Roll the binary to 7.0 on all nodes\n// 2) Once the cluster is stable, raise the FCV:\ndb.adminCommand({ setFeatureCompatibilityVersion: \"7.0\", confirm: true })","note":"MongoDB のメジャーアップグレードは 2 段階。まず全ノードのバイナリを新バージョンにローリングで更新し、クラスタが安定したら FCV を新バージョンに引き上げる。一度に上げられるメジャーバージョンは 1 つのみ。ダウングレードに備えて FCV は個別に管理される。","danger":"danger"},"redis":{"command":"# Major upgrade via a replica (no downtime):\n# 1) Create a replica on the new version, wait for full sync from the master\n# 2) Prepare the application; fail over the master:\nredis-cli -h <new-replica> REPLICAOF NO ONE   # make the new version the master\n# 3) Upgrade the old master, attach it as a replica of the new master","note":"Redis のメジャーバージョン移行(6.x -> 7.x)は、新バージョンでレプリカを構築して同期させ、それを master に昇格させることで行う。これにより書き込みのダウンタイムはほぼゼロに抑えられる。RDB ファイルは後のバージョンと互換性がある。","danger":"danger"},"elasticsearch":{"command":"# Major versions cannot be skipped; one major at a time, via the last minor first (e.g. 6.8 -> 7.17 -> 8.x):\n# 1) Upgrade to the last minor (7.17), resolve the GET _migration/deprecations warnings\n# 2) Rolling upgrade, per node: set allocation to \"primaries\" -> update the node -> start -> wait for green\n# Alternative: full-cluster restart (stop all nodes -> upgrade -> start together); this also moves only one major","note":"Elasticsearch はいかなる方法でもメジャーバージョンの飛び越しをサポートしない。ローリングアップグレードもクラスタ全体の再起動も次のメジャー(n -> n+1)にのみ移行でき、ソースは最後のマイナー(例: 7.17)である必要がある。2 つ前のメジャー(例: 6.x)で作成されたインデックスは新バージョンで開けないため、移行前に _reindex で再構築する必要がある(8.x では読み取り専用のアーカイブインデックスとして限定的にのみ読める)。移行前にスナップショットを取得し、非推奨の警告を解決すること。","danger":"danger"}}},{"id":"set-compatibility","title":"互換性レベル/機能バージョンを設定","aliases":["compatibility level","database compatibility level","feature version","fcv","compatible","compat level"],"engines":{"oracle":{"command":"-- Raise the COMPATIBLE initialization parameter (irreversible!):\nALTER SYSTEM SET COMPATIBLE = '19.0.0' SCOPE=SPFILE;\n-- Then restart the instance. To see the current value:\nSHOW PARAMETER compatible;","note":"COMPATIBLE パラメータは、どのバージョンの機能とファイル形式を有効にするかを決める。一度引き上げてインスタンスを再起動すると元に戻せない(ダウングレードはブロックされる)。そのため、アップグレードの成功が確認されるまで段階的に引き上げる。","danger":"danger","priv":"ALTER SYSTEM (SYSDBA)"},"postgres":{"command":"# Not applicable: PostgreSQL has no database compatibility level.\n# If legacy behavior is needed, set the relevant GUCs (e.g. SET standard_conforming_strings=off)\n# or manage the major migration with dump/restore.","note":"PostgreSQL には SQL Server/Oracle のような「互換性レベル」の概念はなく、バージョンの挙動はバイナリバージョンに直接結び付く。バージョン間の移行は pg_dump/pg_restore または pg_upgrade で行う。","danger":"safe"},"mysql":{"command":"# Not applicable: MySQL has no configurable database compatibility level.\n# Behavioral differences are managed with sql_mode:\nSET GLOBAL sql_mode = 'STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION';","note":"MySQL にはバージョンベースの互換性レベルはなく、SQL の挙動は主にバイナリバージョンと sql_mode の設定に依存する。既存アプリケーションの挙動を維持するには sql_mode を細かく調整する。","danger":"caution"},"mssql":{"command":"-- Set the database compatibility level (e.g. SQL Server 2022 = 160):\nALTER DATABASE Sales SET COMPATIBILITY_LEVEL = 160;\n-- To see the current value:\nSELECT name, compatibility_level FROM sys.databases;","note":"COMPATIBILITY_LEVEL は、クエリオプティマイザと言語機能がどのバージョンのように動作するかを決める(150=2019、160=2022)。インスタンスのアップグレード後もデータベースは旧レベルのままにでき、段階的に引き上げて実行計画の劣化を監視することが推奨される。再度下げることもできる。","danger":"caution"},"mongodb":{"command":"// Set the Feature Compatibility Version (FCV):\ndb.adminCommand({ setFeatureCompatibilityVersion: \"7.0\", confirm: true })\n// Read the current value:\ndb.adminCommand({ getParameter: 1, featureCompatibilityVersion: 1 })","note":"FCV は、バージョンに伴う永続データ形式の変更と新機能をいつ有効にするかを制御する。バイナリのアップグレード後、クラスタが安定している間に引き上げる。引き下げは、同じバイナリバージョンが下位の FCV をまだサポートしている場合のみ可能。","danger":"caution","priv":"clusterManager / root ロール"},"redis":{"command":"# Not applicable: Redis has no compatibility level / feature version concept.\n# Behavior depends directly on the running binary version.","note":"Redis には設定可能な互換性レベルがなく、機能セットは実行中のバージョンに完全に依存する。互換性は RDB/AOF のファイル形式レベルで、前方向にのみ維持される。","danger":"safe"},"elasticsearch":{"command":"# Not applicable: Elasticsearch has no configurable compatibility level.\n# An index is tied to the format of the version it was created in; very old indices\n# cannot be read in the new version and require a reindex.","note":"Elasticsearch には互換性レベルの設定がなく、各インデックスは作成されたメジャーバージョンの形式を保持する。前のメジャーバージョンで作成されたインデックスは読めるが、それより古いものは _reindex で新バージョンに移行する必要がある。","danger":"safe"}}},{"id":"post-upgrade-tasks","title":"アップグレード後のタスク(再コンパイル/統計)","aliases":["post upgrade","post-upgrade","recompile","analyze","refresh statistics","invalid objects"],"engines":{"oracle":{"command":"-- 1) Compile invalid objects in parallel:\n@?/rdbms/admin/utlrp.sql\n-- 2) Refresh dictionary/fixed object statistics:\nEXEC DBMS_STATS.GATHER_DICTIONARY_STATS;\nEXEC DBMS_STATS.GATHER_FIXED_OBJECTS_STATS;\n-- Check remaining invalid objects:\nSELECT owner, object_name, object_type FROM dba_objects WHERE status='INVALID';","note":"utlrp.sql はアップグレード後に INVALID となったパッケージ/ビュー/トリガーを再コンパイルする。その後ディクショナリと固定オブジェクトの統計を収集すると、新バージョンでオプティマイザが適切な実行計画を生成できる。","danger":"caution","priv":"SYSDBA"},"postgres":{"command":"# 1) Regather statistics after pg_upgrade (mandatory):\n$ vacuumdb --all --analyze-in-stages\n-- 2) Bring extensions to the new version:\nALTER EXTENSION postgis UPDATE;\n-- 3) If the collation changed, rebuild text indexes (can take long):\nREINDEX DATABASE database_name;","note":"pg_upgrade(PG17 以前)はプランナの統計を引き継がない。analyze-in-stages はまず粗い統計、次に完全な統計を収集し、システムを早く使用可能にする。拡張は ALTER EXTENSION ... UPDATE で更新し、照合順序が変わった場合はインデックスを REINDEX する必要がある。","danger":"caution"},"mysql":{"command":"-- 8.0+ dictionary upgrade happens automatically at startup; additionally:\nANALYZE TABLE customer;   -- refresh statistics of critical tables\n-- Legacy 5.7 -> if needed on first startup:\n-- $ mysql_upgrade -u root -p   (before 8.0.16)","note":"MySQL 8.0.16 以降では mysql_upgrade の機能がサーバーに移ったため、個別には実行しない。アップグレード後は、大きな/重要なテーブルで ANALYZE TABLE により統計を更新すると実行計画の品質が保たれる。","danger":"safe"},"mssql":{"command":"-- 1) Correct page/row usage counters:\nDBCC UPDATEUSAGE(Sales);\n-- 2) Refresh statistics (sp_updatestats uses sampling; FULLSCAN for critical tables):\nEXEC sp_updatestats;\n-- UPDATE STATISTICS dbo.CriticalTable WITH FULLSCAN;\n-- 3) Raise the compatibility level to the new version (while monitoring):\nALTER DATABASE Sales SET COMPATIBILITY_LEVEL = 160;","note":"アップグレード後、DBCC UPDATEUSAGE は旧バージョンから引き継がれた不正確な領域/行カウンタを修正し、sp_updatestats は統計を更新する。互換性レベルを引き上げる際は、新しい Cardinality Estimator (CE) が引き起こし得る実行計画の劣化を監視する。","danger":"caution"},"mongodb":{"command":"// 1) Verify the FCV upgrade:\ndb.adminCommand({ getParameter: 1, featureCompatibilityVersion: 1 })\n// 2) Check indexes and compatibility warnings in the server logs:\ndb.customer.getIndexes()\n// If an index is incompatible: dropIndex + createIndex (rolling); do NOT use reIndex","note":"メジャーアップグレード後は、FCV がターゲットバージョンに達したことを確認する。インデックスの再構築は通常のアップグレード手順ではない。リリースノートでインデックスが言及されている場合やログに警告が出る場合は、dropIndex + createIndex で再作成する。6.0+ では reIndex はスタンドアロンでのみ動作し、レプリカセットのメンバーでは使用できない。","danger":"caution"},"redis":{"command":"# Usually no extra task is needed. Recommended: verify persistence and replication:\nredis-cli INFO replication   # is the master/replica link healthy\nredis-cli INFO persistence   # rdb_last_bgsave_status / aof_last_bgrewrite_status\nredis-cli DBSIZE             # is the key count as expected","note":"Redis のアップグレード後にスキーマのコンパイル/統計のタスクはない。レプリケーションが再確立されたこと、RDB/AOF の永続化が正常であること、キー数が維持されていることを確認する。","danger":"safe"},"elasticsearch":{"command":"# Verify cluster health:\nGET _cluster/health\n# Move indices created in an old major version that can no longer be read:\nPOST _reindex\n{ \"source\": { \"index\": \"old_index\" }, \"dest\": { \"index\": \"new_index\" } }","note":"アップグレード後、クラスタの状態が 'green' で、すべてのシャードが割り当てられていることを確認する。前のメジャーバージョンより古い形式のインデックスは新バージョンで読めないため、_reindex で現在の形式に移行する必要がある。","danger":"caution"}}}]},"rosetta/migration.json":{"category":"移行と転送","categoryId":"migration","order":15,"concepts":[{"id":"compare-schema","title":"2 つのスキーマ/環境を比較(スキーマ差分)","aliases":["schema diff","diff","compare schemas","compare","schema difference","ddl diff"],"engines":{"oracle":{"command":"-- Extract the schema DDL from both environments and take a text diff\n-- (generate deterministic DDL with DBMS_METADATA)\nEXEC DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM,'SQLTERMINATOR',TRUE);\nEXEC DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM,'STORAGE',FALSE);\nSELECT DBMS_METADATA.GET_DDL('TABLE', table_name) FROM user_tables ORDER BY table_name;\n-- Spool the output to a file in both environments and compare with diff/fc.\n\n-- Export the schema as a changelog with SQLcl's Liquibase integration:\n-- SQL> lb generate-schema\n-- Commercial: the Oracle SQL Developer 'Database Diff' tool is also used.","note":"Oracle には単一コマンドで行う組み込みのスキーマ差分はない。一般的な方法は、両方の環境から DBMS_METADATA.GET_DDL(STORAGE/セグメント属性をオフにして)で決定的な DDL を生成し、テキストの差分を取ること。視覚的/自動的な比較には SQL Developer の Database Diff ウィザードまたは SQLcl を使用する。","danger":"safe","readonly":true,"priv":"SELECT_CATALOG_ROLE またはスキーマの読み取り権限"},"postgres":{"command":"# Dump only the schema from both databases and diff them\npg_dump --schema-only --no-owner --no-privileges sourcedb > source_schema.sql\npg_dump --schema-only --no-owner --no-privileges targetdb  > target_schema.sql\ndiff -u source_schema.sql target_schema.sql\n\n# Tool that generates applicable ALTERs: apgdiff (Another PostgreSQL Diff Tool)\n# apgdiff source_schema.sql target_schema.sql > migration.sql\n# Alternatives: migra, Liquibase diffChangeLog","note":"最も簡単な方法は、両方の環境で pg_dump --schema-only の出力を取得し、diff で比較すること。apgdiff と migra は差分を直接実行可能な ALTER 文に変換するツール。決定的な出力にするには --no-owner --no-privileges を付ける。","danger":"safe","readonly":true,"priv":"SELECT / スキーマの読み取り(pg_dump のためのオブジェクトアクセス)"},"mysql":{"command":"# Schema/object comparison with MySQL Utilities (5.x):\nmysqldbcompare --server1=root:password@host1 --server2=root:password@host2 \\\n  shop:shop --difftype=sql --run-all-tests\n\n# Built-in method: take CREATE statements from both environments and diff them\nmysqldump --no-data --skip-comments shop > source_schema.sql\n# SHOW CREATE TABLE customer;  (to see a single table definition)","note":"MySQL Utilities の mysqldbcompare ツールは、2 つのサーバー間のオブジェクト/スキーマの差異を報告する(difftype=sql で適用可能な文として)。ツールを使わない方法は、両方の環境から mysqldump --no-data(スキーマのみ)または SHOW CREATE TABLE の出力を取得し、diff で比較すること。mysqldbcompare は現在非推奨で、MariaDB/8.x では Liquibase または Skeema が推奨される。","danger":"safe","readonly":true,"priv":"両スキーマに対する SELECT、SHOW VIEW"},"mssql":{"command":"-- Schema comparison/deploy report with SqlPackage (what will change before applying):\nsqlpackage /Action:DeployReport /SourceFile:source.dacpac \\\n  /TargetConnectionString:\"Server=target;Database=shop;Integrated Security=true\" \\\n  /OutputPath:diff_report.xml\n\n-- For data differences (row level), the tablediff utility:\ntablediff -sourceserver S1 -sourcedatabase shop -sourcetable customer \\\n  -destinationserver S2 -destinationdatabase shop -destinationtable customer","note":"スキーマの差異には、SqlPackage /Action:DeployReport がターゲットに適用される変更を XML レポートとして返し、/Action:Script が実行可能な差分スクリプトを生成する。Visual Studio / Azure Data Studio の「Schema Compare」も同じエンジンを使用する。行レベルのデータの差異には tablediff コマンドラインユーティリティがある。","danger":"safe","readonly":true,"priv":"VIEW DEFINITION(DeployReport にはターゲットの読み取り権限)"},"mongodb":{"command":"// The schema is implicit; extract and compare the field structure of both environments.\n// Read the $jsonSchema validator definition (collection rules):\ndb.getCollectionInfos({ name: \"customer\" })[0].options.validator\n\n// External tools for inferred schema comparison by sampling:\n// mongodb-schema (npm) or the Compass 'Schema' tab\n// Take samples with mongoexport and diff the field/type distribution of both environments.","note":"MongoDB はスキーマレスで、固定の DDL はない。比較には 2 つの方法がある。コレクションに定義された $jsonSchema バリデータのルールを比較する(getCollectionInfos 経由)か、mongodb-schema / Compass でデータから推定スキーマを生成し、フィールドと型の分布を比較する。インデックスは db.collection.getIndexes() の出力の差分を取る。","danger":"safe","readonly":true,"priv":"read(getCollectionInfos、listIndexes)"},"redis":{"command":"# Not applicable: Redis is a schemaless key-value store; there are no\n# table/column definitions (DDL) to compare.\n# Closest equivalent: compare the key space (namespace) structure\n# redis-cli --scan --pattern 'customer:*' | sort > source_keys.txt","note":"該当なし: Redis にはスキーマの概念(テーブル/列/DDL)がないため、従来のスキーマ差分は適用されない。構造的な比較が必要な場合は、SCAN でキーの命名パターン(名前空間)のみを一覧表示して比較できる。","danger":"safe","readonly":true},"elasticsearch":{"command":"# Fetch the index mapping from both clusters and compare\ncurl -s 'http://source:9200/customer/_mapping?pretty' > source_mapping.json\ncurl -s 'http://target:9200/customer/_mapping?pretty'  > target_mapping.json\ndiff -u source_mapping.json target_mapping.json\n\n# To compare settings as well:\n# GET customer/_settings   and   GET customer/_mapping","note":"Elasticsearch でスキーマに相当するのはインデックスのマッピング。標準的な方法は、両方のクラスタから GET <index>/_mapping の出力(必要に応じて _settings も)を取得し、diff で比較すること。マッピングのフィールドはほとんど変更不可のため、差異が検出された場合は新しいインデックス + _reindex が必要になることがある。","danger":"safe","readonly":true,"priv":"view_index_metadata / monitor"}}},{"id":"export-for-migration","title":"移行用の一貫性のあるエクスポート","aliases":["export","consistent export","consistent export","take a dump","migration export","snapshot"],"engines":{"oracle":{"command":"# Consistent logical export with Data Pump (at a single SCN)\nexpdp system/password schemas=shop directory=DIR_DMP \\\n  dumpfile=shop_%U.dmp logfile=shop_exp.log \\\n  flashback_scn=<scn> parallel=4\n\n# Current SCN for point-in-time consistency:\n# SELECT current_scn FROM v$database;\n# Alternative: FLASHBACK_TIME=SYSTIMESTAMP","note":"Data Pump(expdp)は移行用の標準的な論理エクスポートツール。読み取り一貫性のために FLASHBACK_SCN=<scn>(または FLASHBACK_TIME)を指定し、すべてのテーブルを単一の SCN で一貫してエクスポートする。稼働中のシステムではこれが重要。PARALLEL で高速化し、%U で複数ファイルを生成する。","danger":"caution","readonly":true,"priv":"DATAPUMP_EXP_FULL_DATABASE、DIRECTORY オブジェクト","minver":"10g(Data Pump)"},"postgres":{"command":"# Single compressed file in custom format (restorable in parallel)\npg_dump -Fc -Z6 -f shop.dump shop\n\n# Directory format (parallel dump + parallel restore):\npg_dump -Fd -j4 -f shop_dir shop\n\n# For the whole cluster + roles/tablespaces:\n# pg_dumpall --globals-only > roles.sql","note":"移行には pg_dump の -Fc(custom)または -Fd(directory)形式が推奨される。どちらも pg_restore で選択的/並列のロードが可能。pg_dump は単一のトランザクション内で実行されるため、出力は自動的に一貫性のあるスナップショットになる。ロールや表領域などのクラスタ全体のオブジェクトは pg_dumpall --globals-only で別途ダンプする。","danger":"safe","readonly":true,"priv":"SELECT(ダンプ対象の全オブジェクトに対して)"},"mysql":{"command":"# Consistent, lock-free export for InnoDB\nmysqldump --single-transaction --quick --routines --triggers --events \\\n  --source-data=2 shop > shop.sql\n\n# Note: older versions use --master-data=2 instead of --source-data.\n# Parallel, fast alternative: mydumper -B shop -o ./backup --threads 4","note":"InnoDB では --single-transaction が単一の一貫性のあるスナップショットを提供し、テーブルをロックしない。--source-data=2(旧 --master-data=2)は、レプリケーション/CDC の開始に必要な binlog の位置/GTID 情報を出力の先頭にコメントとして書き込む。これはゼロダウンタイムの切り替えに不可欠。大容量データでは mydumper が並列に実行される。","danger":"safe","readonly":true,"priv":"SELECT、LOCK TABLES、RELOAD、REPLICATION CLIENT(--source-data 用)"},"mssql":{"command":"-- Full backup for physical migration (to the same/compatible version):\nBACKUP DATABASE shop TO DISK = 'C:\\backup\\shop.bak' WITH COMPRESSION, CHECKSUM;\n\n-- Portable/version-independent logical export (BACPAC = schema+data):\n-- sqlpackage /Action:Export /SourceConnectionString:\"...\" /TargetFile:shop.bacpac\n\n-- For a single table: bcp shop.dbo.customer out customer.dat -n -S server -T","note":"同じまたは新しい SQL Server への移行では、BACKUP ... RESTORE が最も信頼できる方法(整合性は CHECKSUM で検証する)。バージョン/プラットフォームに依存しない移行や Azure SQL への移行には、SqlPackage /Action:Export でスキーマ + データを単一の .bacpac ファイルにエクスポートする方法が推奨される。個別のテーブルには bcp を使用する。","danger":"safe","readonly":true,"priv":"BACKUP DATABASE(db_backupoperator)または Export 用の読み取り権限"},"mongodb":{"command":"# Consistent binary (BSON) export; point-in-time consistency with the oplog\nmongodump --uri=\"mongodb://source:27017\" \\\n  --oplog --out=./backup --numParallelCollections=4\n\n# --oplog captures changes made during the dump (requires a replica set);\n# it works only with a FULL dump and cannot be combined with --db / --collection.\n# On restore, mongorestore --oplogReplay brings it to a single point in time.\n# If you need a single database: take it with --db=shop (without the oplog) or use --nsInclude='shop.*' on restore.","note":"mongodump は移行用の標準的なバイナリ(BSON)エクスポート。レプリカセットでは、--oplog オプションがダンプ実行中に書き込まれた変更を oplog から取得し、一貫性のある時点を提供する(mongorestore --oplogReplay と組み合わせる)。このオプションはフルダンプでのみ有効。大規模クラスタのクラスタ単位の移行には mongosync/ライブツールが適している。","danger":"safe","readonly":true,"priv":"read(oplog には local db の read / clusterMonitor)"},"redis":{"command":"# Create an RDB snapshot in the background (non-blocking)\nredis-cli BGSAVE\n# Check for completion:\nredis-cli INFO persistence | grep rdb_bgsave_in_progress\n\n# Move the resulting file (path: CONFIG GET dir + dbfilename)\n# e.g. /var/lib/redis/dump.rdb  ->  copy to the target server","note":"Redis での一貫性のあるエクスポートは RDB スナップショット。BGSAVE は fork によりメインプロセスをブロックせずに、バックグラウンドで一貫性のある dump.rdb を生成する(SAVE はブロックするため使用しない)。ファイルのパスは CONFIG GET dir と dbfilename で確認する。この dump.rdb をターゲットサーバーのデータディレクトリにコピーして移行する。","danger":"safe","readonly":true},"elasticsearch":{"command":"# 1) Register a snapshot repository (shared file system / S3)\nPUT _snapshot/migration_repo\n{ \"type\": \"fs\", \"settings\": { \"location\": \"/mnt/es_backup\" } }\n\n# 2) Take a consistent snapshot\nPUT _snapshot/migration_repo/migration_1?wait_for_completion=true\n{ \"indices\": \"customer,orders\", \"include_global_state\": false }","note":"Elasticsearch での移行用の一貫性のあるエクスポート方法はスナップショット。まずリポジトリ(fs、S3、GCS など)を登録し、次にスナップショットを取得する。スナップショットは増分で、取得時点の一貫性のある状態を捕捉する。小さなデータ/単一のインデックスには elasticdump も使用できるが、標準はスナップショット。","danger":"safe","readonly":true,"priv":"manage / create_snapshot"}}},{"id":"import-for-migration","title":"ターゲットへのインポート","aliases":["import","import data","restore","load","load into target","load"],"engines":{"oracle":{"command":"# Import with Data Pump; remap schema and tablespace\nimpdp system/password directory=DIR_DMP dumpfile=shop_%U.dmp \\\n  logfile=shop_imp.log \\\n  remap_schema=shop:shop_new \\\n  remap_tablespace=USERS:DATA parallel=4\n\n# For existing objects: TABLE_EXISTS_ACTION=TRUNCATE|APPEND|REPLACE","note":"impdp は expdp で取得した .dmp ファイルをターゲットにロードする。REMAP_SCHEMA はソースを別のスキーマに、REMAP_TABLESPACE は別の表領域に移す。環境間の移行で頻繁に使用される。既存テーブルに対する挙動は TABLE_EXISTS_ACTION で、速度は PARALLEL で設定する。","danger":"caution","priv":"DATAPUMP_IMP_FULL_DATABASE、ターゲット表領域のクォータ"},"postgres":{"command":"# Parallel restore (from custom/directory format)\npg_restore -j4 -d targetdb --no-owner --clean --if-exists shop.dump\n\n# A specific table only: pg_restore -d targetdb -t customer shop.dump\n# For a plain .sql dump:  psql -d targetdb -f shop.sql","note":"pg_restore -j を使用すると、custom/directory 形式のダンプが並列(複数プロセス)でロードされる。大きなデータベースではロードが大幅に高速化する。--clean --if-exists はターゲットのオブジェクトを先に削除し、--no-owner は異なるロール構成に適応させる。プレーン SQL のダンプは psql -f でロードする(並列ではない)。","danger":"caution","priv":"ターゲットデータベースに対する CREATE / 所有者権限"},"mysql":{"command":"# Load a plain SQL dump\nmysql --binary-mode shop < shop.sql\n\n# Parallel/fast load (if taken with mydumper):\nmyloader --directory=./backup --database=shop --threads=4 --overwrite-tables\n\n# Tip: SET FOREIGN_KEY_CHECKS=0; unique_checks=0 before loading speeds it up.","note":"mysqldump の SQL ダンプは mysql クライアントにリダイレクトしてロードする(mysql shop < dump.sql)。並列ではるかに高速にロードするには、mydumper で取得したディレクトリを myloader --threads でリストアする。ロード中に FOREIGN_KEY_CHECKS と UNIQUE_CHECKS を無効にすると性能が向上する。","danger":"caution","priv":"INSERT、CREATE(--overwrite/--clean には DROP も)"},"mssql":{"command":"-- Restore from a physical backup (move file paths to the new environment)\nRESTORE DATABASE shop FROM DISK = 'C:\\backup\\shop.bak'\nWITH MOVE 'shop_data' TO 'D:\\data\\shop.mdf',\n     MOVE 'shop_log'  TO 'D:\\log\\shop.ldf', REPLACE;\n\n-- Import from a BACPAC (schema+data):\n-- sqlpackage /Action:Import /TargetConnectionString:\"...\" /SourceFile:shop.bacpac","note":".bak バックアップは RESTORE DATABASE でロードする。異なるディスク構成に移す場合は、WITH MOVE でデータ/ログファイルを新しいパスにリダイレクトする。バージョン非依存/Azure SQL のターゲットには、SqlPackage /Action:Import で .bacpac ファイル(スキーマ + データ)から新しいデータベースを作成する。","danger":"caution","priv":"RESTORE には dbcreator/sysadmin、Import には CREATE DATABASE"},"mongodb":{"command":"# Restore the BSON backup; replay the oplog to land on a single point in time\nmongorestore --uri=\"mongodb://target:27017\" --oplogReplay \\\n  --numParallelCollections=4 ./backup\n\n# Renaming: --nsFrom='shop.*' --nsTo='shop_new.*'\n# Drop existing data before loading: --drop","note":"mongorestore は mongodump の BSON 出力をターゲットにロードする。--oplogReplay は --oplog で取得したバックアップ内の oplog の変更を再生し、ダンプを単一の一貫性のある時点に揃える。データベース/コレクション名は --nsFrom/--nsTo で変更でき、既存データは --drop で消去できる。","danger":"caution","priv":"readWrite(oplogReplay には restore/clusterAdmin)"},"redis":{"command":"# Stop the server, place dump.rdb in the data directory, start it again\n# 1) systemctl stop redis  (or SHUTDOWN NOSAVE)\n# 2) cp dump.rdb  <path found with CONFIG GET dir>/dump.rdb\n# 3) systemctl start redis   -> Redis loads the RDB into memory at startup\n\n# Alternative (live): feed a RESP command stream with redis-cli --pipe","note":"Redis は RDB を起動時にのみロードする。そのため、ターゲットサーバーを停止し、移行した dump.rdb をデータディレクトリ(CONFIG GET dir)に配置して、サーバーを再起動する。起動時に RDB からメモリに投入される。サーバーを停止せずにロードするには、redis-cli --pipe で RESP 形式のキーをストリーミングする。","danger":"caution"},"elasticsearch":{"command":"# Register the same repository on the target cluster, then restore the snapshot\nPUT _snapshot/migration_repo\n{ \"type\": \"fs\", \"settings\": { \"location\": \"/mnt/es_backup\" } }\n\nPOST _snapshot/migration_repo/migration_1/_restore\n{ \"indices\": \"customer,orders\",\n  \"rename_pattern\": \"(.+)\", \"rename_replacement\": \"restored_$1\" }","note":"ターゲットクラスタにソースと同じスナップショットリポジトリを登録し(ファイルにアクセスできる必要がある)、_snapshot/.../_restore でインデックスをリストアする。インデックス名は rename_pattern/rename_replacement で変更できる。既存のインデックスはオープン中はリストアできないため、先にクローズするか名前を変更する。","danger":"caution","priv":"manage(create_index、restore)"}}},{"id":"heterogeneous-migration","title":"別のデータベースへ移行(異種間)","aliases":["heterogeneous","heterogeneous migration","cross-database","different database","convert database","convert"],"engines":{"oracle":{"command":"# Oracle -> PostgreSQL: Ora2Pg (schema + data + PL/SQL conversion)\nora2pg -c ora2pg.conf -t TABLE   -o schema.sql\nora2pg -c ora2pg.conf -t COPY    -o data.sql   # data in COPY format\nora2pg -t SHOW_REPORT --estimate_cost           # migration cost estimate\n\n# Oracle -> (multiple targets) managed/online: AWS DMS or Oracle GoldenGate","note":"Oracle からの異種間移行(特に PostgreSQL へ)で最も一般的なオープンソースツールは Ora2Pg。テーブル、制約、PL/SQL、データをターゲットの方言に変換し、--estimate_cost で移行工数を見積もる。オンライン/低ダウンタイムの移行には AWS DMS または Oracle GoldenGate(CDC 付き)を使用する。","danger":"caution","readonly":true,"priv":"ソーススキーマに対する SELECT(DBA ビューの読み取り権限)"},"postgres":{"command":"# MySQL -> PostgreSQL: pgloader (schema+data+type conversion in one command)\npgloader mysql://app_user:password@source/shop \\\n         postgresql://app_user:password@target/shop\n\n# Also from SQLite/MSSQL sources: with a pgloader ./migration.load script\n# For a managed/online PostgreSQL target: AWS DMS","note":"pgloader は他のエンジン(MySQL、SQLite、MS SQL)から PostgreSQL へ移行するための標準ツール。接続文字列を指定すると単一のコマンドでスキーマを作成し、型をマッピングしてデータを高速にコピーする。独自の変換/型マッピングは .load スクリプトで定義する。ソースが Oracle なら Ora2Pg、オンライン移行には AWS DMS が推奨される。","danger":"caution","priv":"ターゲットに対する CREATE、ソースに対する SELECT"},"mysql":{"command":"# PostgreSQL/Oracle/MSSQL -> MySQL: AWS DMS (managed) is the most common path\n# or adapt the source-specific export for MySQL:\n#   pg_dump --inserts ... | (type/syntax fixes) | mysql shop\n\n# MySQL <-> MariaDB (compatible): mysqldump output loads directly\nmysqldump --single-transaction shop | mysql -h target_mariadb shop","note":"他のエンジンから MySQL への移行に支配的なオープンツールはない。最も一般的な解決策は AWS DMS(マネージド、CDC 対応)か、ソースのダンプを構文/型に合わせて調整し mysql クライアントでロードする方法。MySQL と MariaDB はほぼ互換性があり、mysqldump の出力は通常そのまま移行できる。","danger":"caution","priv":"ターゲットに対する CREATE、INSERT"},"mssql":{"command":"# SQL Server -> PostgreSQL: with pgloader\npgloader mssql://app_user:password@source/shop \\\n         postgresql://app_user:password@target/shop\n\n# SQL Server -> PostgreSQL compatibility layer: Babelfish for Aurora PostgreSQL\n# (runs T-SQL and the TDS protocol on top of PostgreSQL)\n# To other targets: SSMA (SQL Server Migration Assistant) or AWS DMS","note":"SQL Server から PostgreSQL への移行には pgloader(mssql:// ソース)を使用する。アプリケーションを変更せずに T-SQL を維持したい場合は、Babelfish for Aurora PostgreSQL が互換レイヤーを提供する。Microsoft の SSMA ツールは他のエンジン(Oracle、MySQL、DB2)から SQL Server への移行を自動化する。オンライン移行には AWS DMS。","danger":"caution","priv":"ソースに対する SELECT、ターゲットに対する CREATE"},"mongodb":{"command":"# Relational <-> MongoDB conversion requires schema mapping (ETL):\n#   - Relational Migrator (official MongoDB tool): maps tables to the document model\n#   - or generate JSON from the source -> load with mongoimport\nmongoexport --db=shop --collection=customer --type=csv --fields=id,name > c.csv\n# (To an SQL target: mongoexport CSV -> relational COPY/LOAD DATA)","note":"MongoDB と SQL エンジン間の移行には、行<->ドキュメントのモデル変換(ETL)が必要で、自動の単一コマンドはない。SQL から MongoDB へは、MongoDB Relational Migrator がテーブルをドキュメントスキーマにマッピングする。単純なケースでは、ソースから CSV/JSON を生成して mongoimport でロードする。逆方向では、mongoexport の出力を COPY/LOAD DATA でターゲットのリレーショナルテーブルにロードする。","danger":"caution","priv":"ソースに対する read、ターゲットに対する write"},"redis":{"command":"# With RIOT (Redis Input/Output Tools), to/from Redis from other sources:\n#   Relational -> Redis:\nriot db-import --jdbc-url \"jdbc:postgresql://host/shop\" \\\n  --sql \"SELECT * FROM customer\" hset --keyspace customer --keys id\n#   Redis -> another Redis / file:  riot replicate / riot file-export","note":"異種間移行では Redis は通常ターゲット/ソースとしてのキャッシュ層となる。リレーショナルまたはファイルのソースから Redis にデータをロードするには、Redis 公式の RIOT ツールを使用する(db-import は SQL の結果を HSET/SET 構造にマッピングする)。Redis から Redis へ、またはファイルへは riot replicate / file-export コマンドがある。","danger":"caution"},"elasticsearch":{"command":"# Relational/other source -> Elasticsearch: Logstash (JDBC input)\n# logstash.conf: input { jdbc { statement => \"SELECT * FROM customer\" } }\n#                output { elasticsearch { index => \"customer\" } }\n\n# ES -> ES (version/cluster upgrade): reindex from a remote source\nPOST _reindex\n{ \"source\": { \"remote\": { \"host\": \"http://old:9200\" }, \"index\": \"customer\" },\n  \"dest\": { \"index\": \"customer\" } }","note":"他のデータベースから Elasticsearch への移行で最も一般的なツールは Logstash(JDBC/file 入力 -> elasticsearch 出力)。Elastic 独自のコネクタ/Beats も使用される。古い Elasticsearch クラスタから新しいクラスタへの移行では、リモート reindex('remote' ソースを指定した _reindex)が一般的。ターゲットに reindex.remote.whitelist を定義する必要がある。","danger":"caution","priv":"ターゲットに対する write/create_index"}}},{"id":"setup-cdc-replication","title":"継続的レプリケーション/CDC を構成(ゼロダウンタイムの切り替え)","aliases":["cdc","replication","replication","zero-downtime migration","live migration","change data capture"],"engines":{"oracle":{"command":"# CDC-based replication with Oracle GoldenGate (outline)\n# 1) Enable supplemental logging on the source:\nALTER DATABASE ADD SUPPLEMENTAL LOG DATA;\n# 2) Extract (capture changes from redo) and Replicat (apply to the target) processes:\n#   GGSCI> ADD EXTRACT ext1, INTEGRATED TRANLOG, BEGIN NOW\n#   GGSCI> ADD REPLICAT rep1, INTEGRATED\n# Alternative: initial load with Data Pump + incremental capture with GoldenGate","note":"Oracle でゼロダウンタイム/異種間 CDC の標準ツールは Oracle GoldenGate。Extract プロセスが REDO ログから変更を取得し、Replicat がターゲットに適用する。サプリメンタルロギングを有効にする必要がある。典型的な移行では、初期ロードを Data Pump で取得し、以降は GoldenGate が変更をターゲットにストリーミングすることで、ほぼゼロのダウンタイムで切り替えられる。","danger":"caution","priv":"GoldenGate の管理者権限、サプリメンタルロギング"},"postgres":{"command":"-- Source (publisher): create a publication (wal_level must be logical)\nCREATE PUBLICATION migration_pub FOR ALL TABLES;\n\n-- Target (subscriber): create a subscription (initial copy + continuous stream)\nCREATE SUBSCRIPTION migration_sub\n  CONNECTION 'host=source dbname=shop user=repl password=***'\n  PUBLICATION migration_pub;","note":"PostgreSQL は組み込みの論理レプリケーションで CDC を提供する。ソースで CREATE PUBLICATION、ターゲットで CREATE SUBSCRIPTION を実行する。サブスクリプションの開始時に既存データをコピーし(初期コピー)、その後 WAL から変更を継続的にストリーミングする。wal_level=logical が必要。大規模/複雑なシナリオでは pglogical または Debezium が推奨される。","danger":"caution","priv":"ソースでは REPLICATION ロール。ターゲットでは CREATE SUBSCRIPTION に superuser(PG16+ では pg_create_subscription ロールでも可)","minver":"10(論理レプリケーション)"},"mysql":{"command":"-- Source: binlog must be enabled and in ROW format (log_bin, binlog_format=ROW)\n-- Grant a replication user: GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';\n\n-- Define the source on the target (start from the binlog position of the initial load):\nCHANGE REPLICATION SOURCE TO\n  SOURCE_HOST='source', SOURCE_USER='repl', SOURCE_PASSWORD='***',\n  SOURCE_LOG_FILE='binlog.000001', SOURCE_LOG_POS=1547;\nSTART REPLICA;","note":"MySQL でのゼロダウンタイムの切り替えは binlog ベースのレプリケーションで行う。初期ロードを mysqldump --source-data で取得し、binlog の位置/GTID を記録する。ターゲットでは CHANGE REPLICATION SOURCE TO(8.0.23+ の構文。旧 CHANGE MASTER TO)でその位置からレプリケーションを開始する。START REPLICA で変更を継続的に適用する。GTID ベースの構成のほうが安全。","danger":"caution","priv":"REPLICATION SLAVE(レプリケーションユーザー)、REPLICATION CLIENT","minver":"8.0.23(CHANGE REPLICATION SOURCE)"},"mssql":{"command":"-- Option A: Transactional Replication (publisher->distributor->subscriber) — SSMS wizard\n\n-- Option B: Change Data Capture (track changes as tables)\nEXEC sys.sp_cdc_enable_db;              -- enable CDC at database level\nEXEC sys.sp_cdc_enable_table\n  @source_schema = N'dbo', @source_name = N'customer',\n  @role_name = NULL;                    -- enable CDC at table level\n-- Changes are read from the cdc.dbo_customer_CT table and moved to the target.","note":"SQL Server の継続的レプリケーションには主に 2 つの方法がある。ターゲットへの直接のストリームが必要なら Transactional Replication(パブリッシャー/サブスクライバー)を構成する。独自の ETL で変更を移す場合は Change Data Capture(sp_cdc_enable_db + sp_cdc_enable_table)を有効にし、_CT テーブルから読み取る。異種のターゲットには CDC を AWS DMS/Debezium と組み合わせる。","danger":"caution","priv":"sysadmin(CDC の有効化)。SQL Server Agent が稼働している必要がある"},"mongodb":{"command":"// Watch changes live with Change Streams (requires a replica set/sharded cluster)\nconst cs = db.customer.watch([], { fullDocument: \"updateLookup\" });\nwhile (cs.hasNext()) { printjson(cs.next()); }  // apply to the target\n\n// Official tool for managed cluster-to-cluster replication/migration: mongosync\n// mongosync --cluster0 \"mongodb://source\" --cluster1 \"mongodb://target\"","note":"MongoDB では CDC に Change Streams を使用する。db.collection.watch() は oplog から insert/update/delete のイベントをリアルタイムでストリーミングし、ターゲットに適用する(レプリカセットが必要)。クラスタ間の完全な継続的移行/レプリケーションには、MongoDB 公式の Cluster-to-Cluster Sync ツールである mongosync(Atlas 専用ではなく、セルフマネージドのクラスタでも動作する)が初期ロード + 継続的同期を管理する。","danger":"caution","priv":"changeStream(read)。mongosync には clusterAdmin"},"redis":{"command":"# Make the target instance a replica of the source (live synchronization)\n# On the target Redis:\nREPLICAOF source_host 6379\n# Monitor sync status:\nINFO replication   # master_link_status must be up\n\n# Once the cutover is complete, make the target standalone:\nREPLICAOF NO ONE","note":"Redis でのゼロダウンタイムの切り替えはネイティブのレプリケーションで行う。ターゲットサーバーで REPLICAOF <source host port>(旧 SLAVEOF)を実行すると、ターゲットはまず完全な RDB を受信し、その後コマンドストリームで継続的に同期を保つ。INFO replication で master_link_status:up を確認し、切り替えが完了したら REPLICAOF NO ONE でターゲットをスタンドアロンにする。","danger":"caution"},"elasticsearch":{"command":"# Incremental reindex from the old cluster to the new one within the same version family\nPOST _reindex?wait_for_completion=false\n{ \"source\": { \"remote\": { \"host\": \"http://old:9200\" }, \"index\": \"customer\",\n    \"query\": { \"range\": { \"updated_at\": { \"gt\": \"<last-cursor>\" } } } },\n  \"dest\": { \"index\": \"customer\" } }\n\n# Licensed feature: Cross-Cluster Replication (CCR) — continuous following\n# On the target (follower) cluster: PUT /customer/_ccr/follow { \"remote_cluster\": \"old\", \"leader_index\": \"customer\" }","note":"Elasticsearch の本来の継続的レプリケーション機能は Cross-Cluster Replication (CCR)。ターゲットクラスタがソースのリーダーインデックスをフォローし、変更を継続的に取得する(商用/Platinum ライセンスが必要)。ライセンスがない場合は、定期的なリモート reindex(時刻/シーケンスフィールドに基づく増分)でほぼ継続的な同期を実現する。","danger":"caution","priv":"CCR には manage/read_ccr、リモート reindex には whitelist"}}},{"id":"verify-migration","title":"移行後の検証(行数/チェックサム)","aliases":["verify","verification","row count","checksum","row count","consistency check"],"engines":{"oracle":{"command":"-- Compare row counts on source and target\nSELECT 'customer' table_name, COUNT(*) row_count FROM customer;\n\n-- To find content differences at object level, DBMS_COMPARISON (via db link)\nBEGIN DBMS_COMPARISON.CREATE_COMPARISON(\n  comparison_name => 'COMPARE_CUSTOMER',\n  schema_name => 'SHOP', object_name => 'CUSTOMER',\n  dblink_name => 'TARGET_DB'); END;\n/\n-- SELECT DBMS_COMPARISON.COMPARE('COMPARE_CUSTOMER', scan_info) FROM dual;","note":"最も手早い確認は、両側でテーブルごとに COUNT(*) を比較すること。行レベルの実際の内容の差異を見つけるには DBMS_COMPARISON パッケージを使用する。データベースリンク経由でソースとターゲットのテーブルを行ごとに比較し、差異を報告/収束できる。チェックサムには ORA_HASH または STANDARD_HASH で列のダイジェストを取得できる。","danger":"safe","readonly":true,"priv":"両側での SELECT、DBMS_COMPARISON に対する EXECUTE"},"postgres":{"command":"-- Row count\nSELECT count(*) FROM customer;\n\n-- Ordered digest (checksum) of the whole table content — compare on both sides\nSELECT md5(string_agg(t.row_md5, '' ORDER BY t.row_md5)) AS digest\nFROM (SELECT md5(customer::text) AS row_md5 FROM customer) t;","note":"最初の手順は各テーブルの count(*) を比較すること。内容の検証では、各行のテキスト表現の md5 を取り、ソート順に連結して再度ハッシュする。これにより両側で順序に依存しないチェックサムが得られる。大容量データでは、変更され得る列/キー列のみでダイジェストを取る。再現性のために PK での並べ替えが重要。","danger":"safe","readonly":true,"priv":"テーブルに対する SELECT"},"mysql":{"command":"-- Built-in table checksum (run on both servers and compare)\nCHECKSUM TABLE customer;\n\n-- Row count\nSELECT COUNT(*) FROM customer;\n\n-- Preferred tool for live/large environments (compares row chunks online):\n-- pt-table-checksum h=source,D=shop  (Percona Toolkit)","note":"MySQL では CHECKSUM TABLE がテーブル内容の単一のチェックサムを返す。ソースとターゲットで実行して比較する(エンジン/バージョンが同じである必要がある)。行数には COUNT(*) を使用する。稼働中の本番環境やレプリケーションの整合性確認では、Percona Toolkit の pt-table-checksum が業界標準。チャンク単位で、オンラインかつ低負荷で比較する。","danger":"safe","readonly":true,"priv":"テーブルに対する SELECT"},"mssql":{"command":"-- Full row-level comparison (official tool that produces differences)\ntablediff -sourceserver S1 -sourcedatabase shop -sourcetable customer \\\n  -destinationserver S2 -destinationdatabase shop -destinationtable customer\n\n-- Quick aggregate checksum (single query, compare on both sides):\nSELECT COUNT_BIG(*) row_count, CHECKSUM_AGG(BINARY_CHECKSUM(*)) digest FROM dbo.customer;","note":"SQL Server で行レベルの差異を見つける公式のコマンドラインツールは tablediff(どの行が追加/変更されたかを報告し、オプションの -f で修正スクリプトを書き出す)。手早い全体確認には、CHECKSUM_AGG(BINARY_CHECKSUM(*)) が単一のテーブルダイジェストを返す。両側を COUNT_BIG(*) と合わせて比較する(行の順序に依存しない)。","danger":"safe","readonly":true,"priv":"両テーブルに対する SELECT"},"mongodb":{"command":"// Compare document counts (on source and target)\ndb.customer.countDocuments({});\n\n// For a content checksum, dbHash (md5 digest at collection/DB level):\ndb.runCommand({ dbHash: 1, collections: [\"customer\"] });\n// -> compare the md5 field across both environments.","note":"最初の確認は、countDocuments() で両側のドキュメント数を比較すること(estimatedDocumentCount は高速だがメタデータに依存する。正確な数には countDocuments を使用する)。内容の検証では、dbHash コマンドがコレクション/データベースレベルで md5 ダイジェストを生成する。2 つの環境のハッシュを比較する。インデックスは getIndexes() で別途確認する。","danger":"safe","readonly":true,"priv":"read(dbHash のアクセス)"},"redis":{"command":"# Compare key counts (on source and target)\nredis-cli DBSIZE\n\n# For a memory/data summary and key distribution:\nredis-cli INFO keyspace     # db0:keys=... information\n# For full content verification: DUMP each key and compare with the target\n# (e.g. redis-cli --scan | xargs -I{} redis-cli DUMP {})","note":"Redis での基本的な検証は、DBSIZE で総キー数を比較すること。データベースごとの分布は INFO keyspace で確認できる。Redis には組み込みのテーブルチェックサムがない。厳密な内容の検証が必要な場合は、キーごとに DUMP のシリアライズを取得して両側を比較する(TTL の差異に注意)。riot compare ツールも使用できる。","danger":"safe","readonly":true},"elasticsearch":{"command":"# Compare document counts (on source and target clusters)\nGET customer/_count\n\n# Details: for health/segment/storage comparison\nGET _cat/indices/customer?v&h=index,docs.count,store.size\n# Content by sampling: compare GET customer/_doc/<id> for the same _ids","note":"Elasticsearch での基本的な検証は、GET <index>/_count で両クラスタのドキュメント数を比較すること(_cat/indices の docs.count も手早い概要を示す)。比較は _count を基準にする。_cat/indices の docs.count は Lucene レベルでカウントする(nested のサブドキュメントを含む。例: nested 項目を 2 つ持つ 1 ドキュメントは 3 とカウントされる)ため、_count と異なることがある。内容の検証では、同じ _id の集合でドキュメントをサンプリングするか、ハッシュフィールドで比較する。","danger":"safe","readonly":true,"priv":"インデックスに対する read / monitor"}}}]},"rosetta/tuning.json":{"category":"パフォーマンスチューニング","categoryId":"tuning","order":16,"concepts":[{"id":"plan-baseline","title":"クエリの実行計画を固定/強制(プランベースライン/ヒント)","aliases":["plan baseline","force plan","pin plan","hint","plan stability","query store force"],"engines":{"oracle":{"command":"-- Load the good plan from the cursor cache as a baseline:\nDECLARE n NUMBER; BEGIN\n  n := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(sql_id => '&sql_id');\nEND;\n/","note":"SQL Plan Management は実行計画を固定する。劣化に対する最も強力な保護。/*+ ... */ ヒントも使用できる。","danger":"caution","priv":"ADMINISTER SQL MANAGEMENT OBJECT"},"postgres":{"command":"-- There is no built-in plan pinning; the pg_hint_plan extension:\n/*+ IndexScan(customer customer_city_idx) */ SELECT ... ;","note":"代替手段: enable_seqscan などの設定でセッションレベルで誘導する。永続的な固定には pg_hint_plan を使用する。","danger":"caution"},"mysql":{"command":"SELECT /*+ INDEX(customer customer_city_idx) */ * FROM customer WHERE city='Ankara';","note":"オプティマイザヒントはクエリに埋め込む。永続的な書き換えには query rewrite プラグインを使用する。","danger":"safe"},"mssql":{"command":"-- Force the good plan in Query Store:\nEXEC sp_query_store_force_plan @query_id = 42, @plan_id = 17;","note":"Query Store が有効である必要がある。代わりに OPTION (USE PLAN N'...') またはプランガイドも使用できる。","danger":"caution","priv":"データベースに対する ALTER"},"mongodb":{"command":"// Force an index for the query:\ndb.customer.find({ city: \"Ankara\" }).hint({ city: 1 })\n// Persistent: db.customer.getPlanCache() / index filter","note":"hint は特定のインデックスを強制する。古い実行計画は planCacheClear で消去する。","danger":"safe"},"redis":{"command":"# Not applicable: there is no query planner.","note":"パフォーマンスはデータ構造とコマンドの計算量で決まる。","danger":"safe"},"elasticsearch":{"command":"# There is no plan pinning; optimize the query/index and routing.\nGET <index>/_search { \"profile\": true, \"query\": {...} }","note":"profile でどのクエリが高コストかを確認し、shards/routing で誘導する。","danger":"safe"}}},{"id":"gather-stats-advanced","title":"高度なオプション(ヒストグラムなど)で統計を収集","aliases":["gather stats","histogram","statistics","analyze advanced","method_opt","estimate percent"],"engines":{"oracle":{"command":"EXEC DBMS_STATS.GATHER_TABLE_STATS(\n  ownname=>'HR', tabname=>'EMPLOYEE',\n  estimate_percent=>DBMS_STATS.AUTO_SAMPLE_SIZE,\n  method_opt=>'FOR ALL COLUMNS SIZE AUTO', degree=>4);","note":"method_opt はヒストグラムを、degree は並列度を制御する。統計を固定するには LOCK_TABLE_STATS を使用する。","danger":"safe"},"postgres":{"command":"ALTER TABLE customer ALTER COLUMN city SET STATISTICS 500;\nANALYZE customer;","note":"列ごとのサンプリングターゲット。default_statistics_target はグローバルのデフォルトを設定する。","danger":"safe"},"mysql":{"command":"ANALYZE TABLE customer UPDATE HISTOGRAM ON city WITH 32 BUCKETS;","note":"MySQL 8.0 のヒストグラムサポート。フィルタに使われるが選択性の低い列に有用。","danger":"safe"},"mssql":{"command":"UPDATE STATISTICS dbo.customer WITH FULLSCAN;\n-- Filtered statistics: CREATE STATISTICS ... WHERE ...","note":"FULLSCAN が最も正確。大きなテーブルでは SAMPLE を使用する。自動更新には AUTO_UPDATE_STATISTICS。","danger":"safe"},"mongodb":{"command":"// There are no manual statistics; the planner measures at runtime.\ndb.customer.getPlanCache().clear()","note":"古いプランキャッシュの消去以外に、手動の統計は不要。","danger":"safe"},"redis":{"command":"# Not applicable.","note":"統計/オプティマイザはない。","danger":"safe"},"elasticsearch":{"command":"# There is no statistics gathering; refresh searchability:\nPOST <index>/_refresh","note":"クエリ時には field data と doc values が使用される。force merge はセグメントを削減する。","danger":"safe"}}},{"id":"perf-report","title":"パフォーマンスレポートを生成(AWR / ASH と同等の機能)","aliases":["awr","ash","performance report","performance report","profile","workload report"],"engines":{"oracle":{"command":"-- AWR report (SQL*Plus):\n@?/rdbms/admin/awrrpt.sql\n-- ASH report: @?/rdbms/admin/ashrpt.sql\n-- Live: SELECT * FROM v$active_session_history WHERE sample_time > SYSDATE-1/24;","note":"AWR/ASH には Diagnostics Pack のライセンスが必要。Statspack はライセンス不要の同等機能。","danger":"safe","priv":"SELECT_CATALOG_ROLE"},"postgres":{"command":"-- pg_stat_statements summary + pg_profile/pgBadger:\nSELECT queryid, calls, total_exec_time, mean_exec_time, query\nFROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 20;","note":"AWR 相当には pg_profile 拡張(定期スナップショット)または pgBadger のログ分析を使用する。","danger":"safe"},"mysql":{"command":"-- sys schema summaries:\nSELECT * FROM sys.statement_analysis LIMIT 20;\nSELECT * FROM sys.io_global_by_file_by_bytes LIMIT 10;","note":"sys スキーマは performance_schema を読みやすいレポートに変換する。Enterprise Monitor はより包括的。","danger":"safe"},"mssql":{"command":"-- Query Store reports (SSMS) or:\nSELECT TOP 20 * FROM sys.query_store_runtime_stats ORDER BY avg_duration DESC;","note":"Query Store は実行計画/パフォーマンスを時系列で保持する。sp_BlitzFirst(コミュニティ)は手早い診断を提供する。","danger":"safe"},"mongodb":{"command":"# Live from the shell: mongostat --rowcount 10 ; mongotop\n// or Atlas Performance Advisor / profiler:\ndb.system.profile.find().sort({millis:-1}).limit(20)","note":"mongostat/mongotop は瞬間的な負荷を示し、プロファイラは遅い操作を記録する。","danger":"safe"},"redis":{"command":"INFO stats\nredis-cli --latency-history\nSLOWLOG GET 20","note":"--latency と --latency-history はレイテンシのプロファイルを示し、INFO はすべてのカウンタを示す。","danger":"safe"},"elasticsearch":{"command":"GET _nodes/stats\nGET _cat/thread_pool?v&h=node_name,name,active,queue,rejected\nGET _nodes/hot_threads","note":"hot_threads は最も高コストなスレッドを示し、_nodes/stats は全体的なメトリクスを提供する。監視(Kibana)は履歴ベース。","danger":"safe"}}},{"id":"optimizer-params","title":"オプティマイザ/並列処理の設定を表示/変更","aliases":["optimizer","parallelism","parallel","maxdop","optimizer_switch","cost","planner settings"],"engines":{"oracle":{"command":"SHOW PARAMETER optimizer;\n-- Session: ALTER SESSION SET optimizer_mode = FIRST_ROWS_10;\n-- Parallelism: ALTER SESSION FORCE PARALLEL QUERY PARALLEL 4;","note":"optimizer_index_cost_adj や parallel_degree_policy などの設定は実行計画の選択に影響する。慎重に変更すること。","danger":"caution"},"postgres":{"command":"SHOW random_page_cost;\nSHOW max_parallel_workers_per_gather;\n-- Session: SET enable_seqscan = off;","note":"SSD では random_page_cost ~1.1 が推奨される。enable_* フラグは診断用であり、恒久的な対策ではない。","danger":"caution"},"mysql":{"command":"SELECT @@optimizer_switch;\nSET SESSION optimizer_switch='index_merge=off';","note":"optimizer_switch は個々の最適化をオン/オフする。セッションレベルでテストする。","danger":"caution"},"mssql":{"command":"-- Instance-level MAXDOP and cost threshold:\nEXEC sp_configure 'max degree of parallelism', 8; RECONFIGURE;\n-- Database level: ALTER DATABASE SCOPED CONFIGURATION SET MAXDOP = 8;","note":"MAXDOP=0 は無制限。OLTP では通常 4-8。「cost threshold for parallelism」のデフォルト 5 は多くの場合低すぎる。","danger":"caution"},"mongodb":{"command":"# There are no optimizer parameters; indexes and query shape are decisive.\ndb.customer.find({...}).explain('allPlansExecution')","note":"allPlansExecution はプランナが評価したすべての実行計画を示す。","danger":"safe"},"redis":{"command":"# Not applicable.","note":"プランナはない。io-threads とデータ構造の選択がパフォーマンスを決める。","danger":"safe"},"elasticsearch":{"command":"GET <index>/_settings?include_defaults=true\n# search limits such as search.max_buckets, index.max_result_window","note":"オプティマイザはない。シャード数、routing、クエリ構造がパフォーマンスを決める。","danger":"safe"}}},{"id":"sql-monitor","title":"実行中/直近の SQL をリアルタイムで監視","aliases":["sql monitor","live monitoring","real time sql","live query","current sql","monitor active queries"],"engines":{"oracle":{"command":"SET LONG 1000000 LONGCHUNKSIZE 1000000 LINESIZE 250 PAGESIZE 0\nSELECT DBMS_SQLTUNE.REPORT_SQL_MONITOR(sql_id=>'&sql_id', type=>'TEXT') AS report FROM dual;\n-- or: SELECT sql_id, status, elapsed_time FROM v$sql_monitor WHERE status='EXECUTING';","note":"Real-Time SQL Monitoring は長時間/並列のクエリをリアルタイムで表示する(Tuning Pack)。","danger":"safe"},"postgres":{"command":"SELECT pid, now()-query_start AS dur, state, wait_event, query\nFROM pg_stat_activity WHERE state='active' ORDER BY query_start;","note":"auto_explain を使用すると、遅いクエリの実行計画を自動的にログに記録できる。","danger":"safe"},"mysql":{"command":"SELECT thread_id, event_name, timer_wait/1e9 AS ms, sql_text\nFROM performance_schema.events_statements_current;","note":"events_statements_current は現在実行中の文を示す。","danger":"safe"},"mssql":{"command":"SELECT r.session_id, r.status, r.wait_type, r.percent_complete, t.text\nFROM sys.dm_exec_requests r JOIN sys.dm_exec_sessions s ON s.session_id = r.session_id CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t\nWHERE s.is_user_process = 1;","note":"SSMS の「Live Query Statistics」は実行計画の進捗をリアルタイムで表示する。","danger":"safe"},"mongodb":{"command":"db.currentOp({ active: true, secs_running: { $gt: 1 } })","note":"長時間実行中の操作をリアルタイムで表示する。killOp で終了できる。","danger":"safe"},"redis":{"command":"MONITOR","note":"すべてのコマンドをリアルタイムでストリーミングする — 本番環境では性能に影響するため、短時間のみ使用すること。代わりに SLOWLOG を推奨する。","danger":"caution"},"elasticsearch":{"command":"GET _tasks?detailed=true&group_by=parents","note":"実行中のタスクをリアルタイムで表示する。長いタスクは POST _tasks/<id>/_cancel でキャンセルする。","danger":"safe"}}}]},"rosetta/tuning-adv.json":{"category":"高度なチューニング","categoryId":"tuning-adv","order":17,"concepts":[{"id":"parallel-query","title":"並列クエリを実行/並列度を設定","aliases":["parallel","parallelism","dop","degree of parallelism","parallel query"],"engines":{"oracle":{"command":"-- At query level with a hint:\nSELECT /*+ PARALLEL(t, 4) */ * FROM big_table t;\n-- Force at session level:\nALTER SESSION FORCE PARALLEL QUERY PARALLEL 4;","note":"PARALLEL ヒントはテーブルに並列スキャンを適用する。degree=DOP。過大な DOP はサーバーのリソースを使い果たすため、慎重に選択する。parallel_degree_policy=AUTO は自動的に管理する。","danger":"caution"},"postgres":{"command":"-- Set the number of parallel workers for the session:\nSET max_parallel_workers_per_gather = 4;\n-- The planner adds a Gather/Gather Merge node:\nEXPLAIN (ANALYZE) SELECT count(*) FROM big_table;","note":"実行計画に Gather/Parallel Seq Scan が表示されれば並列処理が有効。max_parallel_workers と min_parallel_table_scan_size も影響する。","danger":"safe"},"mysql":{"command":"-- Limited InnoDB parallelism (certain operations only):\nSET GLOBAL innodb_parallel_read_threads = 4;\n-- Effective for COUNT(*) and primary key scans.","note":"MySQL は汎用的な並列クエリ実行を提供しない。innodb_parallel_read_threads はクラスタ化インデックスのスキャン(例: COUNT(*))のみを並列化する。複雑な JOIN はシングルスレッド。","danger":"safe"},"mssql":{"command":"-- MAXDOP hint at query level:\nSELECT * FROM dbo.big_table OPTION (MAXDOP 4);\n-- Instance level: sp_configure 'max degree of parallelism', 4;","note":"MAXDOP は並列スレッド数を制限する。MAXDOP 1 は並列処理を無効にする。「cost threshold for parallelism」を超えると実行計画が並列になる。","danger":"safe"},"mongodb":{"command":"// Allow disk use for a large aggregation:\ndb.sale.aggregate([ { $group: { _id: \"$city\", t: { $sum: \"$amount\" } } } ], { allowDiskUse: true })\n// A sharded cluster processes each shard in parallel.","note":"シャードクラスタではクエリは各シャードで並列に実行される。単一ノードでは集計ステージはほぼ逐次。allowDiskUse はメモリ上限を超える操作を可能にする。","danger":"safe"},"redis":{"command":"# Not applicable: there is no concept of query parallelism.","note":"コマンドの実行はシングルスレッド。Cluster(シャーディング)でスケールするか、ネットワーク I/O の並列化に io-threads を使用する。","danger":"safe"},"elasticsearch":{"command":"# Shard count = unit of parallelism; a query runs in parallel across shards.\n# Parallelism by slicing within a single shard (with scroll/PIT):\nGET <index>/_search\n{ \"slice\": { \"id\": 0, \"max\": 4 }, \"query\": { \"match_all\": {} } }","note":"検索は関連するすべてのシャードで同時に実行される。プライマリシャードの数が並列処理の基本レベルを決める。slices は大きな scroll/reindex 操作を分割する。","danger":"safe"}}},{"id":"bind-variables","title":"バインド変数/パラメータスニッフィングを管理","aliases":["bind","bind variable","parameter","parameter sniffing","cursor sharing","prepared statement"],"engines":{"oracle":{"command":"-- Use binds instead of literals (for plan sharing):\nSELECT * FROM customer WHERE city = :city;\n-- Share legacy code that uses literals:\nALTER SESSION SET cursor_sharing = FORCE;","note":"バインド変数はハードパースを削減する。Adaptive Cursor Sharing は、偏った分布のバインド値に対して複数の実行計画を保持することでスニッフィングの問題を緩和する。cursor_sharing=FORCE は慎重に使用する。","danger":"caution"},"postgres":{"command":"-- Parameterize with a prepared statement:\nPREPARE q (text) AS SELECT * FROM customer WHERE city = $1;\nEXECUTE q('Ankara');\n-- Set plan cache behavior:\nSET plan_cache_mode = force_custom_plan;","note":"plan_cache_mode=auto は汎用プランとカスタムプランを選択する。force_custom_plan は実行のたびにパラメータ固有の実行計画を生成する(スニッフィングに似た問題への対策)。","danger":"safe"},"mysql":{"command":"-- Server-side prepared statement:\nPREPARE stmt FROM 'SELECT * FROM customer WHERE city = ?';\nSET @city = 'Ankara';\nEXECUTE stmt USING @city;\nDEALLOCATE PREPARE stmt;","note":"プリペアドステートメントは SQL インジェクションを防ぎ、解析コストを下げる。MySQL はドライバレベルでのパラメータ化もサポートする。","danger":"safe"},"mssql":{"command":"-- Parameterized query (sp_executesql):\nEXEC sp_executesql N'SELECT * FROM dbo.customer WHERE city = @city', N'@city nvarchar(50)', @city = N'Ankara';\n-- Handle sniffing with a hint:\nSELECT ... OPTION (RECOMPILE);\n-- or OPTION (OPTIMIZE FOR (@city = 'Ankara'));","note":"OPTION(RECOMPILE) は実行のたびにパラメータ固有の実行計画を生成する(CPU コストが高い)。OPTIMIZE FOR は実行計画を特定の/典型的な値に固定し、OPTIMIZE FOR UNKNOWN は平均的な選択性を使用する。","danger":"caution"},"mongodb":{"command":"// The query shape is the key of the plan cache:\ndb.customer.find({ city: \"Ankara\" }).explain(\"queryPlanner\")\n// Clear a stale plan:\ndb.customer.getPlanCache().clear()","note":"同じ形状(同じフィールド/演算子)のクエリはキャッシュされた実行計画を共有する。リテラル値が異なっても新しい実行計画は生成されない。値の分布が大きく偏っている場合は planCacheClear でリセットする。","danger":"safe"},"redis":{"command":"# Not applicable: there is no query planner or parameter sniffing.","note":"コマンドは直接実行される。パラメータ化ではなくキー設計がパフォーマンスを決める。","danger":"safe"},"elasticsearch":{"command":"# Reuse the query with a parameterized search template:\nPOST _scripts/customer_city\n{ \"script\": { \"lang\": \"mustache\", \"source\": { \"query\": { \"term\": { \"city\": \"{{city}}\" } } } } }\nGET <index>/_search/template\n{ \"id\": \"customer_city\", \"params\": { \"city\": \"Ankara\" } }","note":"search template(Mustache)はクエリ本体をパラメータ化する。アプリケーションは固定のテンプレートを異なる値で呼び出し、クエリの一貫性とキャッシュの利用効率を向上させる。","danger":"safe"}}},{"id":"partition-pruning","title":"パーティションプルーニングを検証","aliases":["partition pruning","partition elimination","partition","pruning","pstart pstop"],"engines":{"oracle":{"command":"EXPLAIN PLAN FOR\nSELECT * FROM sale WHERE sale_date = DATE '2026-01-15';\nSELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);\n-- Look for 'PARTITION RANGE ITERATOR/SINGLE' and the Pstart/Pstop columns in the plan.","note":"Pstart/Pstop は関連するパーティションのみが読まれていることを示す(KEY ではなく数値が理想)。パーティションキーに関数/暗黙の型変換を適用するとプルーニングが妨げられる。","danger":"safe"},"postgres":{"command":"SET enable_partition_pruning = on;\nEXPLAIN (ANALYZE)\nSELECT * FROM sale WHERE sale_date = DATE '2026-01-15';\n-- Verify in the plan that only the relevant partition (child table) is scanned.","note":"enable_partition_pruning が有効な場合、一致するパーティションのみが実行計画に表示され、その他は 'never executed' と表示される。定数値は計画時に、パラメータは実行時にプルーニングされる。","danger":"safe"},"mysql":{"command":"-- Show which partitions are scanned:\nEXPLAIN SELECT * FROM sale WHERE sale_date = '2026-01-15';\n-- 5.7 and earlier: EXPLAIN PARTITIONS SELECT ... (removed in 8.0)","note":"MySQL 5.7+ では通常の EXPLAIN 出力の 'partitions' 列がスキャン対象のパーティションを一覧表示する(EXPLAIN PARTITIONS 構文は 8.0 で削除)。関連するパーティションのみが表示されるはず。すべてのパーティションが表示される場合はプルーニングが行われていない。","danger":"safe"},"mssql":{"command":"-- Find which partition a value falls into:\nSELECT $PARTITION.pf_sale_date('2026-01-15') AS partition_no;\n-- Examine 'Actual Partition Count' and 'Actual Partitions Accessed' in the actual plan.","note":"$PARTITION 関数は値のパーティション番号を返す。実際の実行計画でアクセスされたパーティション数が 1 に近ければプルーニングが有効。すべてのパーティションがスキャンされている場合は述語が一致していない。","danger":"safe"},"mongodb":{"command":"// Targeted query using the shard key in a sharded cluster:\ndb.sale.find({ shop_id: 42 }).explain(\"executionStats\")\n// In explain, only the relevant shard should appear under 'shards'.","note":"クエリにシャードキーが含まれていれば、mongos は関連するシャードにのみルーティングする(targeted)。そうでなければすべてのシャードに展開される(scatter-gather)。explain の出力でアクセスされたシャードを確認する。","danger":"safe"},"redis":{"command":"# Not applicable: there is no table/partition concept.","note":"データは Cluster のハッシュスロットで分散される。クエリのプルーニングではなく、キーで直接アクセスする。","danger":"safe"},"elasticsearch":{"command":"# Route to the relevant shard with routing:\nGET <index>/_search?routing=customer42\n{ \"query\": { \"term\": { \"customer_id\": 42 } } }\n# Query only the relevant indices with a time-based index pattern:\nGET sale-2026-01/_search","note":"カスタム routing はクエリを単一のシャードに絞り込む(プルーニングに類似)。時系列データでは、日付パターンのインデックス名(sale-2026-01)により関連するインデックスのみが検索される。ワイルドカードではなく狭いパターンを使用する。","danger":"safe"}}},{"id":"result-cache","title":"結果/クエリキャッシュを使用","aliases":["result cache","result caching","query cache","query result cache","request cache"],"engines":{"oracle":{"command":"-- Result cache at query level:\nSELECT /*+ RESULT_CACHE */ city, COUNT(*) FROM customer GROUP BY city;\n-- Global mode: ALTER SYSTEM SET result_cache_mode = FORCE;","note":"Server Result Cache は結果を SGA に保持する。基礎となるテーブルが変更されると自動的に無効化される。RESULT_CACHE_MODE=FORCE は対象となるすべてのクエリに適用し、MANUAL はヒント経由のみ。頻繁に変更されるテーブルでは効果が小さい。","danger":"caution"},"postgres":{"command":"-- There is no built-in result cache.\n-- Precompute with a materialized view:\nCREATE MATERIALIZED VIEW mv_city_summary AS\n  SELECT city, COUNT(*) FROM customer GROUP BY city;\nREFRESH MATERIALIZED VIEW mv_city_summary;","note":"PostgreSQL はクエリ結果キャッシュを提供しない。マテリアライズドビュー(手動/スケジュールの REFRESH)またはアプリケーションレベルのキャッシュ(Redis)を使用する。注: Memoize ノードはネステッドループ内の行レベルのキャッシュを提供するもので、クエリ結果のキャッシュではない。","danger":"safe"},"mysql":{"command":"-- Query Cache was REMOVED in MySQL 8.0.\n-- Alternative: a materialized summary table or an application cache:\nCREATE TABLE city_summary AS SELECT city, COUNT(*) c FROM customer GROUP BY city;","note":"旧来の query_cache_type は MySQL 8.0 で完全に削除された(スケーラビリティの問題のため)。代わりに InnoDB バッファプール、サマリーテーブル、または外部キャッシュ(Redis/Memcached)を使用する。","danger":"safe"},"mssql":{"command":"-- There is no built-in query result cache.\n-- Precompute with an indexed (materialized) view:\nCREATE VIEW dbo.vw_city_summary WITH SCHEMABINDING AS\n  SELECT city, COUNT_BIG(*) c FROM dbo.customer GROUP BY city;\nCREATE UNIQUE CLUSTERED INDEX ix ON dbo.vw_city_summary(city);","note":"SQL Server は結果キャッシュを保持しない(プランキャッシュは保持する)。繰り返される集計にはインデックス付きビューが自動的に維持される。実行計画での自動マッチングは Enterprise(および Developer)エディションのみで、Standard では WITH (NOEXPAND) ヒントでビューをクエリする必要がある。加えて、バッファプールは頻繁に読まれるページをメモリに保持する。","danger":"safe"},"mongodb":{"command":"// There is no built-in query result cache.\n// Pre-aggregate and write to a collection ($merge):\ndb.sale.aggregate([\n  { $group: { _id: \"$city\", t: { $sum: \"$amount\" } } },\n  { $merge: \"city_summary\" }\n])","note":"MongoDB は結果キャッシュを提供しない。WiredTiger は頻繁にアクセスされるデータをメモリに保持する。高コストな集計には、$merge/$out による事前計算済みのサマリーコレクションまたはアプリケーションキャッシュ(Redis)を使用する。","danger":"safe"},"redis":{"command":"# Redis is already a cache layer; cache the result manually:\nSET query:city_summary \"{...}\" EX 300\nGET query:city_summary\n# If already computed, return it with GET; otherwise compute it and write it with SET.","note":"一般的な cache-aside パターン: キーが存在すれば GET で即座に返し、存在しなければソースから計算して EX(TTL)付きで SET する。Redis は通常、他のデータベースの結果キャッシュとして機能する。","danger":"safe"},"elasticsearch":{"command":"# Shard request cache (enabled by default for size:0 aggregations):\nGET <index>/_search?request_cache=true\n{ \"size\": 0, \"aggs\": { \"city\": { \"terms\": { \"field\": \"city\" } } } }\n# Setting: PUT <index>/_settings { \"index.requests.cache.enable\": true }","note":"シャードリクエストキャッシュは size:0(集計のみ)のリクエストのシャードごとの結果をキャッシュする。インデックスがリフレッシュされると無効化される。size>0(ヒットを返す)のクエリはデフォルトではキャッシュされない。","danger":"safe"}}}]},"rosetta/advanced-features.json":{"category":"高度な機能","categoryId":"advanced-features","order":18,"concepts":[{"id":"full-text-search","title":"全文検索","aliases":["full text","full text","fts","search","text search"],"engines":{"oracle":{"command":"-- Oracle Text: create a CONTEXT index\nCREATE INDEX article_idx ON article(content) INDEXTYPE IS CTXSYS.CONTEXT;\n-- Search with CONTAINS (label 1 ties CONTAINS to SCORE):\nSELECT id, SCORE(1) FROM article\nWHERE CONTAINS(content, 'database AND performance', 1) > 0\nORDER BY SCORE(1) DESC;","note":"Oracle Text(旧 interMedia)は CONTEXT インデックスにより言語を考慮した全文検索を提供する。CONTAINS 演算子は AND/OR/NEAR などの検索演算子をサポートする。インデックスは CTX_DDL.SYNC_INDEX または自動 SYNC で維持する。","danger":"safe"},"postgres":{"command":"-- Search with tsvector/tsquery, accelerated by a GIN index:\nCREATE INDEX article_fts_idx ON article\n  USING GIN (to_tsvector('english', content));\nSELECT id, ts_rank(to_tsvector('english', content), q) AS score\nFROM article, to_tsquery('english', 'database & performance') q\nWHERE to_tsvector('english', content) @@ q\nORDER BY score DESC;","note":"PostgreSQL の組み込み全文検索は、@@ 演算子で tsvector(文書)と tsquery(クエリ)を照合する。GIN インデックスは大きなテキストに対する検索を高速化する。言語構成('english')がステミングとストップワードの処理を行う。","danger":"safe"},"mysql":{"command":"-- Create a FULLTEXT index (InnoDB/MyISAM):\nALTER TABLE article ADD FULLTEXT INDEX ft_content (content);\n-- Search in natural language / boolean mode:\nSELECT id, MATCH(content) AGAINST('database performance') AS score\nFROM article\nWHERE MATCH(content) AGAINST('+database +performance' IN BOOLEAN MODE);","note":"MySQL の FULLTEXT インデックスは MATCH ... AGAINST 構文でクエリする。IN NATURAL LANGUAGE MODE は関連度スコアを返し、IN BOOLEAN MODE は +/-/* 演算子で細かく制御できる。InnoDB は 5.6 以降で全文検索をサポートする。","since":"MySQL 5.6","xnote":"InnoDB の全文検索は MySQL 5.6 で導入された。それ以前は MyISAM にのみ存在した。","danger":"safe"},"mssql":{"command":"-- Create a Full-Text Catalog and index:\nCREATE FULLTEXT CATALOG ft_catalog;\nCREATE FULLTEXT INDEX ON dbo.article(content)\n  KEY INDEX PK_article ON ft_catalog;\n-- Search with CONTAINS / FREETEXT:\nSELECT id FROM dbo.article\nWHERE CONTAINS(content, '\"database\" AND \"performance\"');","note":"SQL Server の Full-Text Search では、まず Full-Text Catalog、次にテーブルに Full-Text Index が必要(一意の KEY INDEX が必須)。CONTAINS は完全一致/近接検索と論理演算子を、FREETEXT は意味ベース(言語的)の検索をサポートする。Full-Text Search コンポーネントをインストールする必要がある。","danger":"safe"},"mongodb":{"command":"// Create a text index:\ndb.article.createIndex({ content: \"text\" })\n// Search with $text and sort by relevance score:\ndb.article.find(\n  { $text: { $search: \"database performance\" } },\n  { score: { $meta: \"textScore\" } }\n).sort({ score: { $meta: \"textScore\" } })","note":"MongoDB の text インデックスは $text 演算子による全文検索を提供する。コレクションに持てる text インデックスは 1 つのみ。textScore メタフィールドが関連度を示す。より高度な検索には Atlas Search($search、Lucene ベース)を使用する。","danger":"safe"},"redis":{"command":"# Requires the RediSearch module (Redis Stack).\n# Define the index:\nFT.CREATE article_idx ON HASH PREFIX 1 article: SCHEMA content TEXT\n# Full-text search:\nFT.SEARCH article_idx \"database performance\"","note":"コアの Redis は全文検索を提供しない。RediSearch モジュール(Redis Stack に同梱)が FT.CREATE によるインデックス作成と FT.SEARCH による検索を提供する。ステミング、あいまい検索、フィルタリング、ソートがサポートされる。モジュールがインストールされていなければ、この機能は利用できない。","danger":"safe"},"elasticsearch":{"command":"# Elasticsearch is natively a full-text search engine.\n# match query (analyzed text search):\nGET article/_search\n{\n  \"query\": {\n    \"match\": { \"content\": \"database performance\" }\n  }\n}","note":"Elasticsearch は本質的に Lucene 上に構築された全文検索エンジン。text フィールドはインデックス作成時に解析される(トークン化、ステミング)。match クエリは関連度スコア(_score)順に結果を返す。言語固有のアナライザ(例: 'english')を割り当てられる。","danger":"safe"}}},{"id":"json-query","title":"JSON データをクエリ","aliases":["json","json query","json query","jsonb","document query"],"engines":{"oracle":{"command":"-- Extract a scalar value with JSON_VALUE:\nSELECT JSON_VALUE(data, '$.customer.city') AS city FROM orders;\n-- Expand into rows with JSON_TABLE:\nSELECT t.product, t.quantity\nFROM orders s,\n     JSON_TABLE(s.data, '$.items[*]'\n       COLUMNS (product VARCHAR2(50) PATH '$.product',\n                quantity NUMBER PATH '$.quantity')) t;","note":"Oracle(12c+)は SQL/JSON パス式で JSON データをクエリする。JSON_VALUE は単一のスカラー値を、JSON_QUERY はオブジェクト/配列の断片を返し、JSON_TABLE は JSON をリレーショナルな行列構造に変換する。21c+ はネイティブの JSON データ型をサポートする。","since":"Oracle 12c","xnote":"SQL/JSON クエリは Oracle 12c で、ネイティブの JSON データ型は 21c で導入された。","danger":"safe"},"postgres":{"command":"-- jsonb operators:\nSELECT data->'customer'->>'city' AS city FROM orders;\n-- Containment (@>) and a GIN index:\nCREATE INDEX ix ON orders USING GIN (data);\nSELECT * FROM orders\nWHERE data @> '{\"status\": \"approved\"}';","note":"PostgreSQL の jsonb 型は豊富な演算子を提供する: ->(json オブジェクト/要素)、->>(テキスト値)、#>(パス)、@>(包含)、?(キーの存在)。GIN インデックスは @> と ? のクエリを高速化する。jsonb_path_query による SQL/JSON パスクエリも可能。","since":"PostgreSQL 9.4","xnote":"json 型は PostgreSQL 9.2 で、jsonb 型は 9.4 で導入された。","danger":"safe"},"mysql":{"command":"-- JSON_EXTRACT or shorthand operators:\nSELECT JSON_EXTRACT(data, '$.customer.city') AS city FROM orders;\n-- ->> returns unquoted text:\nSELECT data->>'$.customer.city' AS city FROM orders\nWHERE data->>'$.status' = 'approved';","note":"MySQL(5.7+)はネイティブの JSON 型を JSON_EXTRACT() でクエリする。-> 演算子は JSON_EXTRACT の、->> は JSON_UNQUOTE(JSON_EXTRACT()) の省略形。JSON フィールドに対する検索は生成列 + インデックスで高速化できる。","since":"MySQL 5.7","xnote":"ネイティブの JSON データ型は MySQL 5.7 で導入された。","danger":"safe"},"mssql":{"command":"-- Extract a scalar value with JSON_VALUE:\nSELECT JSON_VALUE(data, '$.customer.city') AS city FROM orders;\n-- Expand into rows with OPENJSON:\nSELECT k.product, k.quantity\nFROM orders s\nCROSS APPLY OPENJSON(s.data, '$.items')\n  WITH (product NVARCHAR(50) '$.product', quantity INT '$.quantity') k;","note":"SQL Server(2016+)は JSON を NVARCHAR 列に格納する。JSON_VALUE はスカラー値を、JSON_QUERY はオブジェクト/配列を返し、OPENJSON は JSON を表形式に変換する。ISJSON() で検証する。JSON パスに対する検索は計算列 + インデックスで高速化できる。","since":"SQL Server 2016","xnote":"JSON 関数(JSON_VALUE/OPENJSON)は SQL Server 2016 で導入された。","danger":"safe"},"mongodb":{"command":"// MongoDB is natively a document (BSON/JSON) database.\n// Access nested fields with dot notation:\ndb.orders.find({ \"customer.city\": \"Ankara\" })\n// Array element and projection:\ndb.orders.find(\n  { \"items.product\": \"pen\" },\n  { \"items.$\": 1 }\n)","note":"MongoDB はすべてのデータをドキュメント(JSON に似た BSON)として格納するため、クエリはネイティブ。ドット表記でネストされたフィールドや配列要素にアクセスする。複雑な変換は Aggregation Pipeline で行い、インデックスによりネストされたフィールドを高速に検索できる。","danger":"safe"},"redis":{"command":"# Requires the RedisJSON module (Redis Stack).\n# Write a JSON document:\nJSON.SET order:1 $ '{\"customer\":{\"city\":\"Ankara\"},\"status\":\"approved\"}'\n# Read a value with JSONPath:\nJSON.GET order:1 $.customer.city","note":"コアの Redis には JSON 型がない。RedisJSON モジュール(Redis Stack)が JSON.SET/JSON.GET による JSONPath ベースの読み書きを提供する。RediSearch と組み合わせると JSON ドキュメントをインデックス化してクエリできる。モジュールがない場合、JSON は文字列として格納され、アプリケーションで解析する。","danger":"safe"},"elasticsearch":{"command":"# Documents are already JSON; query fields directly:\nGET orders/_search\n{ \"query\": { \"term\": { \"customer.city\": \"Ankara\" } } }\n# For nested arrays, use the nested type and a nested query:\nGET orders/_search\n{ \"query\": { \"nested\": { \"path\": \"items\",\n  \"query\": { \"match\": { \"items.product\": \"pen\" } } } } }","note":"Elasticsearch はドキュメントをネイティブに JSON として格納し、インデックス化する。ネストされたオブジェクトの配列で要素の境界を保つには、'nested' フィールド型と nested クエリを使用する。そうしないと object 型の配列はフラット化される(交差マッチングのリスク)。object と nested の区別は正確性にとって重要。","danger":"safe"}}},{"id":"spatial-geo","title":"地理/空間クエリ","aliases":["spatial","geographic","geo","gis","location","map"],"engines":{"oracle":{"command":"-- Oracle Spatial: SDO_GEOMETRY column and spatial index\nCREATE INDEX location_sidx ON shop(location)\n  INDEXTYPE IS MDSYS.SPATIAL_INDEX;\n-- Shops within 5 km:\nSELECT name FROM shop\nWHERE SDO_WITHIN_DISTANCE(location,\n  SDO_GEOMETRY(2001, 4326,\n    SDO_POINT_TYPE(32.85, 39.92, NULL), NULL, NULL),\n  'distance=5 unit=KM') = 'TRUE';","note":"Oracle Spatial は地理データを SDO_GEOMETRY 型で格納する。USER_SDO_GEOM_METADATA のエントリと空間インデックスが必要。SDO_WITHIN_DISTANCE、SDO_RELATE、SDO_NN などの演算子が距離/交差/最近傍のクエリに対応する。SRID 4326 は WGS84(緯度/経度)系。","danger":"safe"},"postgres":{"command":"-- PostGIS extension:\nCREATE EXTENSION IF NOT EXISTS postgis;\nCREATE INDEX location_gix ON shop USING GIST (location);\n-- Shops within 5 km (geography, meters):\nSELECT name FROM shop\nWHERE ST_DWithin(location,\n  ST_SetSRID(ST_MakePoint(32.85, 39.92), 4326)::geography,\n  5000);","note":"PostGIS は PostgreSQL をフル機能の空間データベースにする。geometry(平面)と geography(球面)の型、および ST_Distance/ST_DWithin/ST_Intersects/ST_Contains などの数百の ST_ 関数を提供する。GiST/SP-GiST インデックスが空間クエリを高速化する。","danger":"safe"},"mysql":{"command":"-- Spatial column (with SRID) and SPATIAL index:\nALTER TABLE shop MODIFY location POINT NOT NULL SRID 4326;\nALTER TABLE shop ADD SPATIAL INDEX (location);\n-- Compute distance (meters, geography):\nSELECT name,\n  ST_Distance(location,\n    ST_SRID(POINT(32.85, 39.92), 4326)) AS distance\nFROM shop\nORDER BY distance LIMIT 10;","note":"MySQL(5.7+)は OGC 準拠の空間データ型(POINT、POLYGON など)と ST_ 関数をサポートする。SPATIAL インデックス(R-tree)は InnoDB/MyISAM の NOT NULL 列にのみ作成できる。オプティマイザが使用するには、列を SRID 属性(SRID 4326)付きで定義する必要がある。SRID 4326 では ST_Distance はメートル単位の測地距離を返す。POINT(x, y) + ST_SRID では x が経度、y が緯度。SRID 4326 の WKT 入力(ST_GeomFromText)では順序は緯度-経度。","danger":"safe"},"mssql":{"command":"-- geography type and spatial index:\nCREATE SPATIAL INDEX location_sidx ON dbo.shop(location);\n-- Shops within 5 km (STDistance returns meters):\nSELECT name FROM dbo.shop\nWHERE location.STDistance(\n  geography::Point(39.92, 32.85, 4326)) <= 5000;","note":"SQL Server は 2 つの空間型を提供する: geography(球面、緯度/経度)と geometry(平面)。STDistance、STIntersects、STContains などのメソッドがクエリに対応する。空間インデックス(グリッドベース)が性能を向上させる。geography::Point(latitude, longitude, SRID) の引数の順序に注意する。","danger":"safe"},"mongodb":{"command":"// 2dsphere index (for GeoJSON):\ndb.shop.createIndex({ location: \"2dsphere\" })\n// Shops nearest to a given point ($near):\ndb.shop.find({\n  location: {\n    $near: {\n      $geometry: { type: \"Point\", coordinates: [32.85, 39.92] },\n      $maxDistance: 5000\n    }\n  }\n})","note":"MongoDB は地理データを GeoJSON 形式で格納し、2dsphere インデックスで球面クエリを実行する。$near(距離順)、$geoWithin(領域内)、$geoIntersects 演算子がサポートされる。座標は [経度, 緯度] の順で、$maxDistance はメートル単位。","danger":"safe"},"redis":{"command":"# Built-in geospatial commands (built on sorted sets):\nGEOADD shops 32.85 39.92 \"kizilay\"\nGEOADD shops 32.86 39.93 \"cankaya\"\n# Search within 5 km of a point:\nGEOSEARCH shops FROMLONLAT 32.85 39.92\n  BYRADIUS 5 km ASC","note":"Redis は GEOADD(longitude latitude member)で地理的位置を Sorted Set に格納する。GEOSEARCH(Redis 6.2+、旧 GEORADIUS の後継)は半径またはボックス内のメンバーを距離順に返す。GEODIST は 2 点間の距離を返す。これはコア機能であり、モジュールは不要。","danger":"safe"},"elasticsearch":{"command":"# Map the field as geo_point:\nPUT shop\n{ \"mappings\": { \"properties\": { \"location\": { \"type\": \"geo_point\" } } } }\n# Query within 5 km:\nGET shop/_search\n{ \"query\": { \"geo_distance\": {\n  \"distance\": \"5km\",\n  \"location\": { \"lat\": 39.92, \"lon\": 32.85 } } } }","note":"Elasticsearch は geo_point(点)と geo_shape(ポリゴン/線)のフィールド型をサポートする。フィルタリングは geo_distance(半径)、geo_bounding_box(ボックス)、geo_polygon クエリで、ソートは geo_distance で、集計は geohash_grid/geotile_grid で行う。座標は lat/lon または [lon, lat] 配列で指定する。","danger":"safe"}}},{"id":"window-functions-adv","title":"ウィンドウ関数(ROW_NUMBER/RANK/LAG)","aliases":["window function","window function","row_number","rank","lag","over","analytic"],"engines":{"oracle":{"command":"-- Rank by amount within each city and fetch the previous value:\nSELECT city, name, amount,\n  ROW_NUMBER() OVER (PARTITION BY city ORDER BY amount DESC) AS row_num,\n  RANK()       OVER (PARTITION BY city ORDER BY amount DESC) AS rnk,\n  LAG(amount)   OVER (PARTITION BY city ORDER BY created_at)      AS prev_amount\nFROM sale;","note":"Oracle は分析(ウィンドウ)関数の先駆けで、ROW_NUMBER、RANK、DENSE_RANK、LAG、LEAD、SUM/AVG OVER、NTILE、FIRST_VALUE を完全にサポートする。OVER 内では PARTITION BY がグループを、ORDER BY が順序を、フレーム(ROWS/RANGE BETWEEN)がスライディングウィンドウを定義する。","since":"Oracle 8i","danger":"safe"},"postgres":{"command":"-- Window functions with OVER():\nSELECT city, name, amount,\n  ROW_NUMBER() OVER (PARTITION BY city ORDER BY amount DESC) AS row_num,\n  RANK()       OVER (PARTITION BY city ORDER BY amount DESC) AS rnk,\n  LAG(amount)   OVER (PARTITION BY city ORDER BY created_at)      AS prev_amount\nFROM sale;","note":"PostgreSQL は標準 SQL 構文でウィンドウ関数を完全にサポートする。ROW_NUMBER/RANK/DENSE_RANK、LAG/LEAD、OVER 付きの集計、NTILE、FIRST_VALUE/LAST_VALUE を利用できる。繰り返し使うウィンドウ定義は WINDOW 句で名前を付けて共有できる。","since":"PostgreSQL 8.4","danger":"safe"},"mysql":{"command":"-- MySQL 8.0+ window functions:\nSELECT city, name, amount,\n  ROW_NUMBER() OVER (PARTITION BY city ORDER BY amount DESC) AS row_num,\n  RANK()       OVER (PARTITION BY city ORDER BY amount DESC) AS rnk,\n  LAG(amount)   OVER (PARTITION BY city ORDER BY created_at)      AS prev_amount\nFROM sale;","note":"MySQL はバージョン 8.0 でウィンドウ関数を追加した(MariaDB 10.2+ もサポート)。ROW_NUMBER、RANK、DENSE_RANK、LAG、LEAD、NTILE、OVER 付きの集計を利用できる。8.0 より前のバージョンにはこれらの関数がなく、ユーザー変数で代用していた。","since":"MySQL 8.0","xnote":"MySQL 8.0 より前にはウィンドウ関数がなく、ユーザー変数で代用していた。","danger":"safe"},"mssql":{"command":"-- Window functions with OVER():\nSELECT city, name, amount,\n  ROW_NUMBER() OVER (PARTITION BY city ORDER BY amount DESC) AS row_num,\n  RANK()       OVER (PARTITION BY city ORDER BY amount DESC) AS rnk,\n  LAG(amount)   OVER (PARTITION BY city ORDER BY created_at)      AS prev_amount\nFROM dbo.sale;","note":"SQL Server は 2005(ROW_NUMBER/RANK)と 2012(LAG/LEAD、フレーム指定、OVER 付きの集計)以降ウィンドウ関数をサポートする。PARTITION BY、ORDER BY、ROWS/RANGE フレームを完全に利用できる。ページングには OFFSET/FETCH または ROW_NUMBER が一般的。","since":"SQL Server 2005","xnote":"ランキング関数は 2005 で、LAG/LEAD とフレーム指定は 2012 で導入された。","danger":"safe"},"mongodb":{"command":"// Window calculations with $setWindowFields:\ndb.sale.aggregate([\n  { $setWindowFields: {\n      partitionBy: \"$city\",\n      sortBy: { amount: -1 },\n      output: {\n        row_num: { $documentNumber: {} },\n        rnk: { $rank: {} },\n        prev_amount: { $shift: { output: \"$amount\", by: -1 } }\n      }\n  } }\n])","note":"MongoDB 5.0 で導入された $setWindowFields 集計ステージがウィンドウ関数を提供する: $documentNumber(ROW_NUMBER)、$rank/$denseRank、$shift(LAG/LEAD)、集計関数、スライディングウィンドウ(window: { documents/range })。partitionBy と sortBy は SQL の PARTITION BY/ORDER BY に相当する。","since":"MongoDB 5.0","xnote":"$setWindowFields ステージは MongoDB 5.0 で導入された。","danger":"safe"},"redis":{"command":"# Not applicable: there are no SQL-like window functions.","note":"Redis はキーバリューストアであり、分析用のウィンドウ関数はない。順序付きの結果には Sorted Set を使用できる(ZADD/ZRANGE による順位のようなアクセス)。ただし PARTITION BY/LAG などのリレーショナルなウィンドウ操作はアプリケーション層で行う。","danger":"safe"},"elasticsearch":{"command":"# Not applicable: there are no SQL-like window functions.\n# Closest equivalent: bucket aggregations.\nGET sale/_search\n{ \"size\": 0, \"aggs\": { \"by_city\": {\n  \"terms\": { \"field\": \"city\" },\n  \"aggs\": { \"total\": { \"sum\": { \"field\": \"amount\" } } } } } }","note":"Elasticsearch は従来のウィンドウ関数(ROW_NUMBER/RANK/LAG)を提供しない。グループ化と順序付けは集計フレームワークで行う。terms 集計は PARTITION BY に、top_hits は上位レコードに、derivative/serial_diff(パイプライン集計)は LAG のような連続した差分に近い。","danger":"safe"}}},{"id":"columnstore-analytics","title":"列指向ストレージ/分析","aliases":["columnstore","columnar","column store","analytics","olap","columnar"],"engines":{"oracle":{"command":"-- Database In-Memory: keep the table in memory in columnar format\nALTER TABLE sale INMEMORY;\n-- With priority and compression:\nALTER TABLE sale INMEMORY PRIORITY HIGH\n  MEMCOMPRESS FOR QUERY HIGH;","note":"Oracle Database In-Memory(12.1.0.2+)は、ディスク上の行形式を維持しながら(デュアルフォーマット)、テーブルをメモリ上に列形式で保持する(In-Memory Column Store, IM)ことで分析クエリを高速化する。INMEMORY は別ライセンスのオプション。inmemory_size パラメータが IM 領域のサイズを決める。","since":"Oracle 12.1.0.2","xnote":"Database In-Memory のカラムストアは Oracle 12.1.0.2 で導入された(別ライセンス)。","danger":"caution"},"postgres":{"command":"-- Core PostgreSQL is row-based; columnar storage needs an extension:\n-- Citus columnar access method:\nCREATE EXTENSION IF NOT EXISTS citus;\nCREATE TABLE sale_columnar (...) USING columnar;\n-- Alternatives: the Hydra/cstore_fdw extensions.","note":"コアの PostgreSQL は行ベース(ヒープ)のストレージのみを提供する。列指向ストレージには Citus の 'columnar' アクセスメソッド(USING columnar)、Hydra、または旧来の cstore_fdw 拡張を使用する。これらは分析/データウェアハウスのワークロード向けに圧縮とスキャン速度を提供する。","danger":"safe"},"mysql":{"command":"-- Not applicable: core InnoDB does not offer columnar storage.\n-- For analytics: MySQL HeatWave (cloud, in-memory columnar)\n-- or integration with external ClickHouse/Apache Doris.","note":"標準の MySQL(InnoDB)は行ベースで、組み込みのカラムストアはない。分析の高速化には MySQL HeatWave(Oracle Cloud のインメモリ列指向アクセラレータ)を使用する。オンプレミスでは通常、ClickHouse や Apache Doris などの外部の列指向エンジンを使用する。","danger":"safe"},"mssql":{"command":"-- Clustered columnstore index (for analytic tables):\nCREATE CLUSTERED COLUMNSTORE INDEX cci_sale ON dbo.sale;\n-- Nonclustered columnstore on a rowstore table (HTAP):\nCREATE NONCLUSTERED COLUMNSTORE INDEX ncci_sale\n  ON dbo.sale (city, product, amount, created_at);","note":"SQL Server のカラムストアインデックス(2012 で読み取り専用の非クラスタ化、2014 で更新可能なクラスタ化、2016 で更新可能な非クラスタ化)はデータを高圧縮で列ごとに格納する。バッチモードと組み合わせると、集計/スキャン中心の分析クエリが大幅に高速化する。クラスタ化はデータウェアハウスに、非クラスタ化は HTAP に適する。","since":"SQL Server 2012","xnote":"カラムストアインデックスは 2012 で(読み取り専用)、更新可能なクラスタ化カラムストアは 2014 で、更新可能な非クラスタ化カラムストアは 2016 で導入された。","danger":"safe"},"mongodb":{"command":"-- Not applicable: MongoDB is document (row-like) based.\n-- For analytics: dedicated Analytics Nodes in Atlas\n-- or export to a columnar format ($out)/an external engine.","note":"MongoDB はドキュメントを行に似た BSON として格納し、組み込みの列指向(カラムストア)ストレージはない。分析ワークロードには、Atlas レプリカセットの専用 Analytics Nodes、Atlas Data Federation、または列指向システム(例: Parquet)へのデータのエクスポートを使用する。","danger":"safe"},"redis":{"command":"-- Not applicable: there is no concept of columnar storage.","note":"Redis はインメモリのキーバリューストアであり、行/列のストレージの区別はない。分析用の集計は Sorted Set、HyperLogLog(近似カウント)、RedisTimeSeries などの特殊な構造で行う。大規模な OLAP には適さない。","danger":"safe"},"elasticsearch":{"command":"# doc_values: fields are stored column-wise on disk (enabled by default).\n# Required for sorting/aggregation; active on non-text fields.\nPUT sale\n{ \"mappings\": { \"properties\":\n  { \"amount\": { \"type\": \"double\", \"doc_values\": true } } } }","note":"ソートと集計のために、Elasticsearch はフィールドを doc_values というディスクベースの列指向構造に保持する(数値/keyword/date フィールドではデフォルトで有効)。この列指向のレイアウトが分析/集計クエリを高速化する。text フィールドではデフォルトで無効。","danger":"safe"}}},{"id":"in-memory","title":"インメモリテーブル/高速化","aliases":["in memory","in-memory","memory table","acceleration","in-memory oltp"],"engines":{"oracle":{"command":"-- Keep the table in memory with Database In-Memory:\nALTER TABLE orders INMEMORY;\n-- Memory size (init parameter):\nALTER SYSTEM SET inmemory_size = 4G SCOPE=SPFILE;","note":"Oracle Database In-Memory は、頻繁にクエリされるテーブルをメモリ上に列形式で保持することで分析を高速化する(別ライセンス)。OLTP では、バッファキャッシュと KEEP プールも頻繁にアクセスされるブロックをメモリに保持する。インメモリのソリューションはディスク上の行形式によって永続性を維持する。","danger":"caution"},"postgres":{"command":"-- Fast table without durability (writes no WAL):\nCREATE UNLOGGED TABLE temp_calc (id int, data text);\n-- Session-private temporary table (tends to stay in memory):\nCREATE TEMP TABLE session_data (id int) ON COMMIT DELETE ROWS;","note":"PostgreSQL には専用のインメモリテーブルエンジンがない。UNLOGGED テーブルは WAL の書き込みを省略して書き込みを高速化する(クラッシュ時に内容は失われ、永続性はない)。TEMP テーブルはセッションの間存在し、temp_buffers により可能な限りメモリに保持される。ホットデータは shared_buffers にキャッシュされる。","danger":"caution"},"mysql":{"command":"-- Table using the MEMORY (HEAP) storage engine:\nCREATE TABLE cache_table (\n  id INT PRIMARY KEY,\n  data VARCHAR(100)\n) ENGINE=MEMORY;","note":"MySQL の MEMORY(旧 HEAP)ストレージエンジンはテーブルデータを完全に RAM に保持する。非常に高速だが、サーバーの再起動でデータは失われる(構造は残る)。BLOB/TEXT をサポートせず、固定の行サイズを使用する。永続的なホットデータには InnoDB バッファプールが推奨される。","danger":"caution"},"mssql":{"command":"-- In-Memory OLTP: memory-optimized table\nCREATE TABLE dbo.session_state (\n  id INT NOT NULL PRIMARY KEY NONCLUSTERED,\n  data NVARCHAR(100)\n) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA);","note":"SQL Server In-Memory OLTP(Hekaton)は、メモリ最適化テーブル(MEMORY_OPTIMIZED=ON)とラッチフリーの構造により高い同時実行性の OLTP を提供する。DURABILITY=SCHEMA_AND_DATA はデータを永続化し、SCHEMA_ONLY はスキーマのみを保持する。メモリ最適化ファイルグループが必要。","since":"SQL Server 2014","xnote":"In-Memory OLTP(Hekaton)は SQL Server 2014 で導入された。","danger":"caution"},"mongodb":{"command":"-- Hot data is kept in the WiredTiger cache automatically.\n-- Set the cache size (default ~50% of RAM):\n// mongod --wiredTigerCacheSizeGB 8\n// or in the configuration: storage.wiredTiger.engineConfig.cacheSizeGB","note":"MongoDB には独立したインメモリテーブルの型がない(旧来の In-Memory Storage Engine は Enterprise 専用で、非推奨になった)。デフォルトの WiredTiger エンジンは、頻繁にアクセスされるデータとインデックスをメモリキャッシュに保持することで読み取り速度を向上させる。OS のファイルキャッシュも寄与する。","danger":"safe"},"redis":{"command":"# Redis already runs entirely in memory; nothing extra is needed.\n# Persistence and memory policy settings:\nCONFIG SET maxmemory 4gb\nCONFIG SET maxmemory-policy allkeys-lru","note":"Redis はすべてのデータを RAM に保持し、設計上これが速度の源泉となっている。永続化は RDB(スナップショット)と AOF(コマンドログ)のいずれかまたは両方で行う。maxmemory の上限と eviction ポリシー(LRU/LFU/random)が、メモリが満杯になった時の挙動を決める。","danger":"safe"},"elasticsearch":{"command":"-- Not applicable: there is no fully in-memory table mode.\n# Place hot data on fast nodes with a hot/cold architecture:\nPUT sale/_settings\n{ \"index.routing.allocation.require.data\": \"hot\" }","note":"Elasticsearch はデータをディスク(Lucene セグメント)に格納し、専用のインメモリテーブルエンジンは提供しない。速度は OS のファイルキャッシュ(ページキャッシュ)、doc_values、hot-warm-cold アーキテクチャに依存する。十分な RAM とヒープ設定がパフォーマンスにとって重要。","danger":"safe"}}},{"id":"time-series","title":"時系列データ","aliases":["time series","time series","timeseries","iot","metrics","sensor"],"engines":{"oracle":{"command":"-- Range partitioning by date:\nCREATE TABLE measurements (\n  ts TIMESTAMP, sensor_id NUMBER, value NUMBER)\nPARTITION BY RANGE (ts)\nINTERVAL (NUMTODSINTERVAL(1,'DAY'))\n( PARTITION p0 VALUES LESS THAN (TIMESTAMP '2026-01-01 00:00:00') );","note":"Oracle では、時系列データは通常 RANGE(INTERVAL)パーティショニングで管理する。新しいパーティションは自動的に作成され、古いパーティションは容易に削除できる(パーティションプルーニングによりクエリが高速化する)。圧縮(ILM/ADO)と集計用のマテリアライズドビューも使用される。","danger":"safe"},"postgres":{"command":"-- Hypertable with the TimescaleDB extension:\nCREATE EXTENSION IF NOT EXISTS timescaledb;\nCREATE TABLE measurements (ts TIMESTAMPTZ, sensor_id INT, value DOUBLE PRECISION);\nSELECT create_hypertable('measurements', 'ts');\n-- Summarize with a continuous aggregate.","note":"PostgreSQL はネイティブのパーティショニング(PARTITION BY RANGE)で時系列を保持できる。TimescaleDB 拡張は、時間ベースの自動チャンク化、圧縮、保持ポリシー、継続的集計を備えたハイパーテーブルを追加する。大規模な IoT/メトリクスのワークロードで一般的なソリューション。","danger":"safe"},"mysql":{"command":"-- RANGE partitioning by date:\nCREATE TABLE measurements (\n  ts DATETIME, sensor_id INT, value DOUBLE,\n  PRIMARY KEY (ts, sensor_id))\nPARTITION BY RANGE (TO_DAYS(ts)) (\n  PARTITION p2026_01 VALUES LESS THAN (TO_DAYS('2026-02-01')),\n  PARTITION pmax VALUES LESS THAN MAXVALUE);","note":"MySQL には専用の時系列エンジンがない。RANGE パーティショニング(TO_DAYS/UNIX_TIMESTAMP を使用)により、古いデータの高速な削除とパーティションプルーニングが可能。大容量の時系列には、通常は外部ソリューション(TimescaleDB、InfluxDB)またはサマリーテーブルが推奨される。","danger":"safe"},"mssql":{"command":"-- Partitioned table (partition function + scheme) or\n-- system-versioned temporal table (history kept automatically):\nCREATE TABLE dbo.measurements (\n  id INT PRIMARY KEY, value DECIMAL(10,2),\n  valid_from DATETIME2 GENERATED ALWAYS AS ROW START,\n  valid_to DATETIME2 GENERATED ALWAYS AS ROW END,\n  PERIOD FOR SYSTEM_TIME (valid_from, valid_to))\nWITH (SYSTEM_VERSIONING = ON);","note":"SQL Server は、パーティション関数/構成によるパーティショニングで時系列を管理する。これにより広い日付範囲にわたるデータのプルーニングと高速なアーカイブが可能になる。加えて、システムバージョン管理されたテンポラルテーブル(SYSTEM_VERSIONING)は行の変更履歴を自動的に保持し、ポイントインタイムのクエリ(FOR SYSTEM_TIME)を可能にする。","since":"SQL Server 2016","xnote":"システムバージョン管理されたテンポラルテーブルは SQL Server 2016 で導入された。","danger":"safe"},"mongodb":{"command":"// Time-series collection (MongoDB 5.0+):\ndb.createCollection(\"measurements\", {\n  timeseries: {\n    timeField: \"ts\",\n    metaField: \"sensor_id\",\n    granularity: \"seconds\"\n  }\n})","note":"MongoDB 5.0 で導入された time-series コレクションは、時刻とメタフィールドによりデータを圧縮された列に似た(バケット化された)形式で自動的に格納する。ディスクとインデックスの使用量を削減し、範囲クエリを高速化する。timeField は必須で、metaField(ソース/タグ)と granularity がパフォーマンスを決める。","since":"MongoDB 5.0","xnote":"time-series コレクションは MongoDB 5.0 で導入された。","danger":"safe"},"redis":{"command":"# Requires the RedisTimeSeries module (Redis Stack).\n# Create a series with a retention period:\nTS.CREATE sensor:1 RETENTION 86400000 LABELS type temperature\n# Add a sample (with an automatic timestamp):\nTS.ADD sensor:1 * 23.5","note":"コアの Redis には時系列の型がない。RedisTimeSeries モジュール(Redis Stack)は、TS.CREATE/TS.ADD による高速なサンプル取り込み、自動保持(RETENTION)、ダウンサンプリング(TS.CREATERULE)、TS.RANGE/TS.MRANGE によるラベルベースの範囲クエリを提供する。モジュールがない場合は Sorted Set で代用する。","danger":"safe"},"elasticsearch":{"command":"# Data stream: automatically rolling indexes for time series\nPUT _index_template/measurements-tpl\n{ \"index_patterns\": [\"measurements*\"], \"data_stream\": {},\n  \"template\": {\n    \"settings\": { \"index.mode\": \"time_series\", \"index.routing_path\": [\"sensor_id\"] },\n    \"mappings\": { \"properties\": {\n      \"@timestamp\": { \"type\": \"date\" },\n      \"sensor_id\": { \"type\": \"keyword\", \"time_series_dimension\": true },\n      \"temperature\": { \"type\": \"double\", \"time_series_metric\": \"gauge\" } } } } }\nPUT _data_stream/measurements","note":"Elasticsearch は時系列データをデータストリームで管理する。新しいバッキングインデックスは時間とともに自動的に作成され(rollover)、ILM が古いデータを hot/warm/cold の階層に移動して削除する。TSDS(index.mode: time_series)はメトリクスデータに特化したストレージ最適化を提供する。少なくとも 1 つの time_series_dimension フィールド、それを指す index.routing_path、@timestamp フィールドが必須(そうでないとテンプレートが拒否される)。","danger":"safe"}}},{"id":"vector-search","title":"ベクトル検索(AI/埋め込み)","aliases":["vector search","vector search","embedding","ai","semantic search","knn"],"engines":{"oracle":{"command":"-- Oracle 23ai native VECTOR type:\nCREATE TABLE docs (id NUMBER, content CLOB, embedding VECTOR);\n-- Similarity search (cosine distance):\nSELECT id FROM docs\nORDER BY VECTOR_DISTANCE(embedding, :query_vector, COSINE)\nFETCH FIRST 5 ROWS ONLY;","note":"Oracle Database 23ai はネイティブの VECTOR データ型と AI Vector Search 機能を提供する。VECTOR_DISTANCE 関数は COSINE/EUCLIDEAN/DOT のメトリクスで類似度を計算する。近似検索には HNSW と IVF のベクトルインデックスがサポートされる。埋め込みはデータベース内または外部モデルで生成する。","since":"Oracle 23ai","xnote":"ネイティブの VECTOR 型と AI Vector Search は Oracle 23ai で導入された。","danger":"safe"},"postgres":{"command":"-- pgvector extension:\nCREATE EXTENSION IF NOT EXISTS vector;\nCREATE TABLE docs (id int, embedding vector(1536));\nCREATE INDEX ON docs USING hnsw (embedding vector_cosine_ops);\n-- 5 nearest neighbors (<-> Euclidean, <=> cosine):\nSELECT id FROM docs ORDER BY embedding <=> :query_vec LIMIT 5;","note":"pgvector 拡張は PostgreSQL に vector 型と類似度演算子を追加する: <->(L2/ユークリッド)、<=>(コサイン)、<#>(内積)。HNSW または IVFFlat インデックスが近似最近傍(ANN)検索を高速化する。RAG やセマンティック検索のアプリケーションで広く使用されている。","xnote":"コアの PostgreSQL には vector 型がなく、pgvector 拡張が必要。","danger":"safe"},"mysql":{"command":"-- MySQL 9.0+ native VECTOR type:\nCREATE TABLE docs (id INT, embedding VECTOR(1536));\n-- Cosine distance (DISTANCE is HeatWave-only):\nSELECT id, DISTANCE(embedding, :query_vec, 'COSINE') AS d\nFROM docs ORDER BY d LIMIT 5;","note":"MySQL 9.0 はネイティブの VECTOR データ型と、STRING_TO_VECTOR/VECTOR_TO_STRING、VECTOR_DIM 関数を追加した(Community にもある)。DISTANCE() 関数と大規模な近似ベクトル検索は Oracle Cloud の MySQL HeatWave でのみ利用できる。Community/Enterprise では距離をアプリケーションまたは外部のベクトルストアで計算する。古いオンプレミスのバージョンでは外部のベクトルストアが必要。","since":"MySQL 9.0","xnote":"ネイティブの VECTOR データ型は MySQL 9.0 で導入された。","danger":"safe"},"mssql":{"command":"-- SQL Server 2025 native vector type:\nCREATE TABLE docs (id INT, embedding VECTOR(1536));\n-- Nearest neighbors by cosine distance:\nSELECT TOP 5 id,\n  VECTOR_DISTANCE('cosine', embedding, @query_vec) AS distance\nFROM dbo.docs ORDER BY distance;","note":"SQL Server 2025(および Azure SQL)はネイティブの vector データ型と VECTOR_DISTANCE 関数(cosine/euclidean/dot)を提供する。近似最近傍検索のための DiskANN ベースのベクトルインデックスは開発中。埋め込みは Azure OpenAI などの外部モデルで生成して格納する。","since":"SQL Server 2025","xnote":"ネイティブの vector データ型は SQL Server 2025 で導入された。","danger":"safe"},"mongodb":{"command":"// Atlas Vector Search ($vectorSearch aggregation stage):\ndb.docs.aggregate([\n  { $vectorSearch: {\n      index: \"vector_idx\",\n      path: \"embedding\",\n      queryVector: [0.12, 0.87, /* ... */],\n      numCandidates: 100,\n      limit: 5\n  } }\n])","note":"MongoDB Atlas Vector Search は $vectorSearch 集計ステージで埋め込みをクエリする。内部では HNSW ベースの近似最近傍検索を行う。ベクトルインデックスは Atlas Search インデックスとして定義する。この機能はマネージドの Atlas サービスに固有(オンプレミスの Community エディションでは利用できない)。","danger":"safe"},"redis":{"command":"# Requires the RediSearch (Redis Stack) VECTOR field type.\n# Define an HNSW vector index:\nFT.CREATE docs_idx ON HASH PREFIX 1 docs: SCHEMA\n  embedding VECTOR HNSW 6 TYPE FLOAT32 DIM 1536 DISTANCE_METRIC COSINE\n# KNN search (with a query vector):\nFT.SEARCH docs_idx \"*=>[KNN 5 @embedding $vec]\" PARAMS 2 vec \"...\"","note":"Redis は RediSearch モジュール(Redis Stack)によりベクトル検索を提供する。VECTOR フィールド型は FLAT(厳密)または HNSW(近似)のインデックスと、COSINE/L2/IP のメトリクスをサポートする。最近傍は FT.SEARCH 内の KNN 構文で取得する。低レイテンシのセマンティック検索と RAG に使用される。","danger":"safe"},"elasticsearch":{"command":"# dense_vector field and kNN search:\nPUT docs\n{ \"mappings\": { \"properties\": { \"embedding\":\n  { \"type\": \"dense_vector\", \"dims\": 1536, \"similarity\": \"cosine\" } } } }\nGET docs/_search\n{ \"knn\": { \"field\": \"embedding\", \"query_vector\": [0.12, 0.87],\n  \"k\": 5, \"num_candidates\": 100 } }","note":"Elasticsearch は dense_vector フィールド型と組み込みの knn 検索で近似最近傍(HNSW)クエリをサポートする。類似度は cosine/dot_product/l2_norm を指定できる。ベクトル検索を従来のテキストクエリと組み合わせる(ハイブリッド検索 / RRF)ことで関連度を向上できる。","since":"Elasticsearch 8.0","xnote":"組み込みの dense_vector kNN 検索は Elasticsearch 8.x で導入された。","danger":"safe"}}},{"id":"cdc-change-tracking","title":"変更追跡(CDC / change tracking)","aliases":["cdc","change data capture","change tracking","change tracking","replication feed","binlog"],"engines":{"oracle":{"command":"-- Read changes from redo logs with LogMiner:\n-- 1) Add the archived/redo log file to analyze:\nEXECUTE DBMS_LOGMNR.ADD_LOGFILE(\n  LOGFILENAME => '/u01/arch/1_1234_1122334455.arc',\n  OPTIONS => DBMS_LOGMNR.NEW);\n-- 2) Start the session:\nEXECUTE DBMS_LOGMNR.START_LOGMNR(\n  OPTIONS => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG);\nSELECT sql_redo, sql_undo FROM V$LOGMNR_CONTENTS\nWHERE seg_name = 'ORDERS';\n-- 3) When finished: EXECUTE DBMS_LOGMNR.END_LOGMNR;\n-- For enterprise CDC/replication, Oracle GoldenGate is used.","note":"Oracle は REDO ログに基づいて変更を追跡する。LogMiner は REDO/アーカイブログを SQL に変換して過去の DML を調査する。分析対象のログファイルは DBMS_LOGMNR.ADD_LOGFILE で追加する。意味のある結果を得るには、少なくとも最小限のサプリメンタルロギングを有効にする必要がある(ALTER DATABASE ADD SUPPLEMENTAL LOG DATA)。継続的で低レイテンシの CDC と異種間レプリケーションには Oracle GoldenGate(別製品)が標準。旧来の Streams/Change Data Capture 機能は非推奨。","danger":"caution"},"postgres":{"command":"-- Create a logical replication (logical decoding) slot:\nSELECT * FROM pg_create_logical_replication_slot(\n  'cdc_slot', 'wal2json');\n-- Consume changes as JSON:\nSELECT data FROM pg_logical_slot_get_changes('cdc_slot', NULL, NULL);","note":"PostgreSQL の論理デコーディングは、出力プラグイン(wal2json、pgoutput、test_decoding)を通じて WAL レコードを読み取り可能な変更ストリームに変換する。レプリケーションスロットが変更の損失を防ぐ。wal_level は logical である必要がある。Debezium はこの仕組みを使ってエンタープライズ向けの CDC を提供する。","danger":"caution"},"mysql":{"command":"-- The row-based binlog is the CDC source (binlog_format=ROW):\nSHOW BINARY LOGS;\nSHOW BINLOG EVENTS IN 'binlog.000042';\n-- Usually Debezium/Maxwell reads the binlog and turns it into a stream.","note":"MySQL での CDC のソースはバイナリログ。binlog_format=ROW ではすべての行の変更が記録される。Debezium や Maxwell などのツールはレプリカのように binlog を読み取り、Kafka へのイベントストリームを生成する。GTID を有効にすると、信頼性の高い位置追跡が容易になる。","danger":"caution"},"mssql":{"command":"-- Enable Change Data Capture on the database and the table:\nEXEC sys.sp_cdc_enable_db;\nEXEC sys.sp_cdc_enable_table\n  @source_schema = N'dbo', @source_name = N'orders',\n  @role_name = NULL;\n-- For lightweight tracking: ALTER DATABASE ... SET CHANGE_TRACKING = ON;","note":"SQL Server は 2 つの仕組みを提供する。Change Data Capture (CDC) はトランザクションログからすべての DML(旧値/新値付き)を変更テーブルに書き込み、SQL Server Agent が必要。Change Tracking はどの行が変更されたか(正味の変更)を軽量に追跡するのみで、データの完全な履歴は保持しない。","since":"SQL Server 2008","xnote":"CDC と Change Tracking は SQL Server 2008 で導入された。","danger":"caution"},"mongodb":{"command":"// Watch changes in real time with Change Streams:\nconst stream = db.orders.watch([\n  { $match: { operationType: { $in: [\"insert\", \"update\"] } } }\n]);\nwhile (stream.hasNext()) { printjson(stream.next()); }","note":"oplog 上に構築された MongoDB Change Streams は、コレクション/データベース/クラスタレベルの insert、update、delete イベントをリアルタイムのストリームとして配信する。レプリカセットまたはシャードクラスタが必要。resumeToken を使用すると、中断後に中断した位置からストリームを再開できる。CDC 連携の基盤となる。","since":"MongoDB 3.6","xnote":"Change Streams は MongoDB 3.6 で導入された。","danger":"safe"},"redis":{"command":"# Listen for key changes with keyspace notifications:\nCONFIG SET notify-keyspace-events KEA\n# Subscribe to changed keys via Pub/Sub:\nPSUBSCRIBE __keyevent@0__:set\nPSUBSCRIBE __keyevent@0__:expired","note":"Redis のキースペース通知は、キーに対するイベント(SET、DEL、EXPIRE など)を Pub/Sub チャネルで発行する。notify-keyspace-events 設定で有効にする(K=keyspace、E=keyevent、A=全イベント)。信頼性が高く永続的な変更ストリームには Redis Streams(XADD/XREAD)が推奨される。","danger":"safe"},"elasticsearch":{"command":"-- Not applicable: there is no built-in CDC/change stream.\n# Closest equivalent: incremental query on a timestamp field:\nGET orders/_search\n{ \"query\": { \"range\": { \"updated_ts\": { \"gt\": \"2026-07-05T00:00:00\" } } },\n  \"sort\": [ { \"updated_ts\": \"asc\" } ] }","note":"Elasticsearch は変更データキャプチャ(CDC)のストリームを提供せず、ドキュメントの変更をネイティブには通知しない。一般的な方法は、すべてのドキュメントに updated_ts フィールドを追加し、タイムスタンプによる増分クエリ(range + sort)を実行すること。通常はソースデータベースの CDC を Elasticsearch に取り込む。","danger":"safe"}}}]},"rosetta/sql-syntax.json":{"category":"SQL 構文とキーワード","categoryId":"sql-syntax","order":19,"concepts":[{"id":"with-cte","title":"WITH(共通テーブル式 / CTE)","aliases":["with","cte","common table expression","temporary query","temporary result set"],"engines":{"oracle":{"command":"WITH region AS (\n  SELECT city, COUNT(*) AS n\n  FROM customer\n  GROUP BY city\n)\nSELECT city, n FROM region WHERE n > 10;","note":"WITH はクエリ内に名前付きの一時的な結果セット(CTE)を定義する。サブクエリを繰り返し書く代わりに、一度定義して名前で参照する。複雑なクエリを読みやすい部分に分割できる。Oracle 9i 以降でサポートされる。","since":"Oracle 9i","danger":"safe"},"postgres":{"command":"WITH region AS (\n  SELECT city, COUNT(*) AS n\n  FROM customer\n  GROUP BY city\n)\nSELECT city, n FROM region WHERE n > 10;","note":"CTE は複雑なクエリを名前付きのブロックに分割する。PostgreSQL 12 より前の CTE は最適化の障壁(常にマテリアライズされる)だった。12 以降はインライン化でき、WITH ... AS MATERIALIZED で旧来の挙動を強制できる。","danger":"safe"},"mysql":{"command":"WITH region AS (\n  SELECT city, COUNT(*) AS n\n  FROM customer\n  GROUP BY city\n)\nSELECT city, n FROM region WHERE n > 10;","note":"CTE はクエリ内で一時的な名前付きの結果セットを定義し、可読性を向上させる。MySQL 8.0(および MariaDB 10.2)以降でサポートされる。古いバージョンでは派生テーブル(FROM 内のサブクエリ)が必要。","since":"MySQL 8.0","xnote":"MySQL 8.0 より前には CTE がなく、同じことを派生テーブル(FROM 内のサブクエリ)で行っていた。","danger":"safe"},"mssql":{"command":"WITH region AS (\n  SELECT city, COUNT(*) AS n\n  FROM customer\n  GROUP BY city\n)\nSELECT city, n FROM region WHERE n > 10;","note":"CTE は名前付きの一時的な結果セット。SQL Server では CTE の直前の文をセミコロンで終える必要があり、そのため WITH はしばしば ';WITH' と書かれる。単一の文(SELECT/INSERT/UPDATE/DELETE)の間だけ有効。","danger":"safe"},"mongodb":{"command":"// Closest equivalent: aggregation pipeline stages\ndb.customer.aggregate([\n  { $group: { _id: \"$city\", n: { $sum: 1 } } },\n  { $match: { n: { $gt: 10 } } }\n])","note":"MongoDB には SQL/CTE がなく、集計パイプラインのステージが同じ役割を果たす。各ステージは前のステージの出力を入力として受け取り、CTE のチェーンに似た段階的な処理となる。中間結果には $facet や $lookup も使用できる。","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no concept of SQL or CTEs.","note":"Redis はクエリ言語を持たないキーバリューのデータストア。中間結果はクライアント側で組み合わせるか、サーバー側のロジックには Lua スクリプト(EVAL)を使用する。","danger":"safe"},"elasticsearch":{"command":"# CTEs are not supported in Elasticsearch SQL.\nPOST _sql\n{ \"query\": \"SELECT city, COUNT(*) n FROM customer GROUP BY city HAVING COUNT(*) > 10\" }","note":"Elasticsearch SQL(_sql API)は WITH/CTE 構文をサポートしない。グループ化とフィルタリングは単一の SELECT に記述する。ネイティブの方法では、'terms' 集計と 'bucket_selector' パイプライン集計で同じことを行う。","danger":"safe"}}},{"id":"recursive-cte","title":"再帰 CTE(WITH RECURSIVE)","aliases":["recursive","recursion","with recursive","connect by","hierarchy","tree query"],"engines":{"oracle":{"command":"-- Hierarchy with CONNECT BY:\nSELECT id, name, manager_id, LEVEL\nFROM employee\nSTART WITH manager_id IS NULL\nCONNECT BY PRIOR id = manager_id;\n\n-- Alternative (11gR2+): standard recursive WITH (the RECURSIVE keyword is not written)\nWITH tree (id, name, manager_id) AS (\n  SELECT id, name, manager_id FROM employee WHERE manager_id IS NULL\n  UNION ALL\n  SELECT c.id, c.name, c.manager_id\n  FROM employee c JOIN tree a ON c.manager_id = a.id\n)\nSELECT * FROM tree;","note":"階層(ツリー)データの走査に使用する: 組織図、部品表など。Oracle の従来の方法は CONNECT BY / PRIOR と LEVEL 疑似列で、START WITH がルート行を設定する。11gR2 以降は標準の再帰 CTE もサポートされる。","since":"Oracle 11gR2","xnote":"CONNECT BY が従来の方法。標準の再帰 WITH(RECURSIVE キーワードなし)は Oracle 11gR2 で導入された。","danger":"safe"},"postgres":{"command":"WITH RECURSIVE tree (id, name, manager_id, level) AS (\n  SELECT id, name, manager_id, 1\n  FROM employee WHERE manager_id IS NULL\n  UNION ALL\n  SELECT c.id, c.name, c.manager_id, a.level + 1\n  FROM employee c JOIN tree a ON c.manager_id = a.id\n)\nSELECT * FROM tree ORDER BY level;","note":"WITH RECURSIVE はアンカークエリと再帰部分を UNION ALL で結合する。再帰部分は結果が空になるまで繰り返し実行される。階層とグラフの走査に最適。無限ループは UNION(ALL ではなく)または循環保護で防ぐ。","since":"PostgreSQL 8.4","danger":"safe"},"mysql":{"command":"WITH RECURSIVE tree (id, name, manager_id, level) AS (\n  SELECT id, name, manager_id, 1\n  FROM employee WHERE manager_id IS NULL\n  UNION ALL\n  SELECT c.id, c.name, c.manager_id, a.level + 1\n  FROM employee c JOIN tree a ON c.manager_id = a.id\n)\nSELECT * FROM tree ORDER BY level;","note":"MySQL 8.0(および MariaDB 10.2+)は標準準拠の WITH RECURSIVE 構文をサポートする。再帰の深さは cte_max_recursion_depth システム変数(デフォルト 1000)で制限される。古いバージョンではストアドプロシージャでループを書く必要があった。","since":"MySQL 8.0","xnote":"MySQL 8.0(MariaDB 10.2)より前には再帰クエリがなく、ストアドプロシージャでループを書いていた。","danger":"safe"},"mssql":{"command":"WITH tree (id, name, manager_id, level) AS (\n  SELECT id, name, manager_id, 1\n  FROM employee WHERE manager_id IS NULL\n  UNION ALL\n  SELECT c.id, c.name, c.manager_id, a.level + 1\n  FROM employee c JOIN tree a ON c.manager_id = a.id\n)\nSELECT * FROM tree ORDER BY level\nOPTION (MAXRECURSION 100);","note":"SQL Server では再帰 CTE に RECURSIVE キーワードを書かない。自身を参照する UNION ALL を含む CTE が自動的に再帰として扱われる。デフォルトの再帰上限は 100 で、OPTION (MAXRECURSION n) で変更する(0 = 無制限、慎重に使用する)。","since":"SQL Server 2005","danger":"safe"},"mongodb":{"command":"// Closest equivalent: the $graphLookup stage\ndb.employee.aggregate([\n  { $match: { manager_id: null } },\n  { $graphLookup: {\n      from: \"employee\",\n      startWith: \"$id\",\n      connectFromField: \"id\",\n      connectToField: \"manager_id\",\n      as: \"subordinates\"\n  } }\n])","note":"MongoDB には再帰 CTE がなく、階層の走査には $graphLookup 集計ステージを使用する。connectFromField/connectToField がリンクするフィールドを、maxDepth が深さの上限を設定する。ツリーとグラフの関係を単一のクエリで解決する。","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no recursive queries.","note":"Redis はクエリ言語を提供しない。階層/グラフの走査はアプリケーションコードで、またはサーバー側で Lua スクリプトで行う。コアの Redis ではツリーの走査はクライアント側で記述する。(以前使用されていた RedisGraph モジュールのサポートは 2023 年に終了した。)","danger":"safe"},"elasticsearch":{"command":"# Not applicable: recursive queries are not supported.\n# Approach: model with parent-child (join field) or nested,\n# deep hierarchies are traversed on the application side.","note":"Elasticsearch は再帰クエリを提供しない(WITH RECURSIVE / CONNECT BY に相当するものはない)。階層関係は 'join'(親/子)フィールド型で、またはツリーのパス(マテリアライズドパス)をフィールドに格納してモデル化する。多階層の走査は通常アプリケーションで行う。","danger":"safe"}}},{"id":"joins","title":"JOIN の種類(INNER/LEFT/RIGHT/FULL/CROSS)","aliases":["join","inner join","left join","right join","full join","cross join","combine tables","table join"],"engines":{"oracle":{"command":"-- INNER: matching rows\nSELECT m.name, s.amount\nFROM customer m JOIN orders s ON m.id = s.customer_id;\n-- LEFT: customers without orders are included too\nSELECT m.name, s.amount\nFROM customer m LEFT JOIN orders s ON m.id = s.customer_id;\n-- CROSS: Cartesian product\nSELECT r.name, u.name FROM color r CROSS JOIN product u;","note":"JOIN は指定した条件に従って 2 つのテーブルを結合する。INNER は一致するもののみを、LEFT/RIGHT は一方の全行を(一致しない箇所は NULL)、FULL は両方の行を、CROSS はすべての組み合わせを返す。標準の ANSI JOIN に加えて、Oracle は旧来の (+) 外部結合構文もサポートする。","danger":"safe"},"postgres":{"command":"SELECT m.name, s.amount\nFROM customer m INNER JOIN orders s ON m.id = s.customer_id;\n\nSELECT m.name, s.amount\nFROM customer m LEFT JOIN orders s ON m.id = s.customer_id;\n\nSELECT m.name, s.amount\nFROM customer m FULL OUTER JOIN orders s ON m.id = s.customer_id;","note":"PostgreSQL はすべての標準 JOIN の種類(INNER、LEFT/RIGHT/FULL OUTER、CROSS)を完全にサポートする。USING(my_column) は共通名の列に対する省略形で、NATURAL JOIN は同名のすべての列で自動的に結合する(慎重に使用する)。","danger":"safe"},"mysql":{"command":"SELECT m.name, s.amount\nFROM customer m INNER JOIN orders s ON m.id = s.customer_id;\n\nSELECT m.name, s.amount\nFROM customer m LEFT JOIN orders s ON m.id = s.customer_id;\n\n-- MySQL has no FULL OUTER JOIN:\nSELECT m.name, s.amount FROM customer m LEFT JOIN orders s ON m.id = s.customer_id\nUNION\nSELECT m.name, s.amount FROM customer m RIGHT JOIN orders s ON m.id = s.customer_id;","note":"MySQL/MariaDB は INNER、LEFT、RIGHT、CROSS JOIN をサポートするが、FULL OUTER JOIN は直接提供しない。LEFT と RIGHT の結果を UNION で組み合わせて代用する。旧来のカンマ形式の結合はデカルト積を生成するため、ON/WHERE で制限する必要がある。","danger":"safe"},"mssql":{"command":"SELECT m.name, s.amount\nFROM customer m INNER JOIN orders s ON m.id = s.customer_id;\n\nSELECT m.name, s.amount\nFROM customer m LEFT JOIN orders s ON m.id = s.customer_id;\n\nSELECT m.name, s.amount\nFROM customer m FULL OUTER JOIN orders s ON m.id = s.customer_id;","note":"SQL Server はすべての標準 JOIN の種類をサポートする。旧来の *= / =* 外部結合演算子は削除されており、ANSI JOIN 構文を使用する必要がある。APPLY(CROSS/OUTER APPLY)は、行ごとの相関サブクエリのための追加の結合形式。","danger":"safe"},"mongodb":{"command":"// Closest equivalent: $lookup (left outer join)\ndb.customer.aggregate([\n  { $lookup: {\n      from: \"orders\",\n      localField: \"id\",\n      foreignField: \"customer_id\",\n      as: \"orders\"\n  } }\n])","note":"MongoDB には従来の JOIN がない。$lookup 集計ステージが別のコレクションから一致するドキュメントを配列として取得する(左外部結合に類似)。INNER のような結果を得るには、その後 $match で空の配列を除外し、$unwind で配列を行に展開する。","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no tables or JOINs.","note":"Redis はリレーショナルな結合を提供しない。データは通常非正規化するか、複数のキーを読み取ってクライアント側で関係を構築する。限定的な結合のようなクエリには RediSearch(FT.AGGREGATE)を使用できる。RedisGraph モジュールのサポートは 2023 年に終了した。","danger":"safe"},"elasticsearch":{"command":"# Not applicable: there is no general JOIN in a distributed design.\n# Limited options: nested, parent/child (join field),\n# terms lookup. Data is usually denormalized at indexing time.","note":"分散アーキテクチャのため、Elasticsearch は任意のテーブル間 JOIN を提供しない。限定的な関係には、単一のインデックス内の 'nested' フィールド型と、同じシャード上の 'join'(親/子)フィールド型がある。最も一般的な解決策は、インデックス作成時にデータを非正規化すること。","danger":"safe"}}},{"id":"window-functions","title":"ウィンドウ関数(OVER / PARTITION BY)","aliases":["window","window function","over","partition by","row_number","rank","lag","lead","analytic function"],"engines":{"oracle":{"command":"SELECT name, department, salary,\n  ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS row_no,\n  RANK()       OVER (PARTITION BY department ORDER BY salary DESC) AS rank_no,\n  LAG(salary)    OVER (PARTITION BY department ORDER BY salary)      AS prev_salary\nFROM employee;","note":"ウィンドウ関数は、行をグループ化せずに(行数を減らさずに)各行について「ウィンドウ」上で計算する。PARTITION BY がウィンドウを分割し、ORDER BY が並べ替える。Oracle はこれらの分析関数の先駆けで、ROW_NUMBER、RANK、DENSE_RANK、LAG/LEAD、SUM() OVER を含む豊富なセットを提供する。","since":"Oracle 8i","danger":"safe"},"postgres":{"command":"SELECT name, department, salary,\n  ROW_NUMBER() OVER w AS row_no,\n  RANK()       OVER w AS rank_no,\n  LEAD(salary)   OVER w AS next_salary\nFROM employee\nWINDOW w AS (PARTITION BY department ORDER BY salary DESC);","note":"PostgreSQL はすべての標準ウィンドウ関数をサポートし、繰り返し使うウィンドウ定義に WINDOW ... AS で名前を付けられる。ROWS/RANGE/GROUPS のフレーム定義により、累計や移動平均などを計算できる。","since":"PostgreSQL 8.4","danger":"safe"},"mysql":{"command":"SELECT name, department, salary,\n  ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS row_no,\n  DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rank_no,\n  LAG(salary)    OVER (PARTITION BY department ORDER BY salary)      AS prev_salary\nFROM employee;","note":"MySQL 8.0(および MariaDB 10.2+)はウィンドウ関数をサポートする。それ以前はユーザー変数やサブクエリで代用していた。ROW_NUMBER、RANK、DENSE_RANK、NTILE、LAG/LEAD、FIRST_VALUE/LAST_VALUE、集計関数の OVER 形式を利用できる。","since":"MySQL 8.0","xnote":"MySQL 8.0 より前にはウィンドウ関数がなく、変数/自己結合で代用していた。","danger":"safe"},"mssql":{"command":"SELECT name, department, salary,\n  ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS row_no,\n  RANK()       OVER (PARTITION BY department ORDER BY salary DESC) AS rank_no,\n  SUM(salary)    OVER (PARTITION BY department) AS dept_total\nFROM employee;","note":"SQL Server は 2005 以降ランキングのウィンドウ関数を、2012 以降フレーム付きの集計と LAG/LEAD などの関数をサポートする。ROW_NUMBER はページング(OFFSET/FETCH と併用)やグループごとの上位 N 行の取得によく使われる。","since":"SQL Server 2005","xnote":"ランキングのウィンドウ関数は 2005 で、フレームと LAG/LEAD は 2012 で導入された。","danger":"safe"},"mongodb":{"command":"// Closest equivalent: $setWindowFields (MongoDB 5.0+)\ndb.employee.aggregate([\n  { $setWindowFields: {\n      partitionBy: \"$department\",\n      sortBy: { salary: -1 },\n      output: { row_no: { $rank: {} },\n                prev_salary: { $shift: { output: \"$salary\", by: -1 } } }\n  } }\n])","note":"MongoDB 5.0+ の $setWindowFields ステージは SQL のウィンドウ関数に相当する。partitionBy と sortBy でウィンドウを定義し、$rank/$denseRank/$documentNumber、$shift(LAG/LEAD)、累計などの出力を生成する。古いバージョンでは $group + コードで解決していた。","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no window functions.","note":"Redis は分析用のウィンドウ関数を提供しない。順序付きの結果と順位付けには Sorted Set(ZSET)構造を使用する。ZADD でスコアを割り当て、ZRANK/ZREVRANK で順位を、ZRANGE で範囲を読み取る。複雑な分析はアプリケーションで行う。","danger":"safe"},"elasticsearch":{"command":"# Closest equivalent: top_hits and pipeline aggregations\nGET employee/_search\n{\n  \"size\": 0,\n  \"aggs\": { \"dept\": { \"terms\": { \"field\": \"department\" },\n    \"aggs\": { \"top_paid\": { \"top_hits\": {\n      \"sort\": [ { \"salary\": \"desc\" } ], \"size\": 3 } } } } }\n}","note":"Elasticsearch には直接のウィンドウ関数がない。グループごとの上位 N レコードには 'top_hits' サブ集計を、移動/累積の計算には 'derivative'、'cumulative_sum'、'moving_fn' などのパイプライン集計を使用する。ソートと分割は terms 集計で行う。","danger":"safe"}}},{"id":"group-rollup","title":"GROUP BY、HAVING、ROLLUP/CUBE/GROUPING SETS","aliases":["group by","having","rollup","cube","grouping sets","grouping","subtotal","subtotals"],"engines":{"oracle":{"command":"-- Basic grouping + HAVING\nSELECT city, COUNT(*) AS n\nFROM customer\nGROUP BY city\nHAVING COUNT(*) > 5;\n\n-- Subtotals and grand total with ROLLUP\nSELECT city, district, SUM(balance)\nFROM customer\nGROUP BY ROLLUP(city, district);","note":"GROUP BY は指定した列で行をグループ化して集計関数を適用する。HAVING はグループ化された結果をフィルタリングする(WHERE はグループ化前に行をフィルタリングする)。ROLLUP は階層的な小計 + 総計を、CUBE はすべての組み合わせを、GROUPING SETS は選択したグループ化を生成する。Oracle は 3 つすべてをサポートする。","danger":"safe"},"postgres":{"command":"SELECT city, district, SUM(balance)\nFROM customer\nGROUP BY GROUPING SETS ((city, district), (city), ());\n\n-- CUBE produces all subset combinations\nSELECT city, district, SUM(balance)\nFROM customer\nGROUP BY CUBE(city, district);","note":"PostgreSQL 9.5+ は ROLLUP、CUBE、GROUPING SETS を標準準拠でサポートする。GROUPING() 関数は列が合計行(NULL)に含まれるかどうかを示す。HAVING は集計後に、WHERE は集計前にフィルタリングする。","since":"PostgreSQL 9.5","xnote":"ROLLUP、CUBE、GROUPING SETS は PostgreSQL 9.5 で導入された。","danger":"safe"},"mysql":{"command":"SELECT city, COUNT(*) AS n\nFROM customer\nGROUP BY city\nHAVING n > 5;\n\n-- ROLLUP in MySQL:\nSELECT city, district, SUM(balance)\nFROM customer\nGROUP BY city, district WITH ROLLUP;","note":"MySQL/MariaDB は GROUP BY ... WITH ROLLUP 構文で小計/総計を生成する。CUBE と GROUPING SETS はサポートされない。HAVING では SELECT のエイリアスを使用できる(Oracle/SQL Server では一般に動作しない)。ROLLUP の行では、グループ化された列は NULL として表示される。","danger":"safe"},"mssql":{"command":"SELECT city, COUNT(*) AS n\nFROM customer\nGROUP BY city\nHAVING COUNT(*) > 5;\n\n-- ROLLUP / CUBE / GROUPING SETS\nSELECT city, district, SUM(balance)\nFROM customer\nGROUP BY ROLLUP(city, district);","note":"SQL Server は GROUP BY に加えて、最新の構文で ROLLUP()、CUBE()、GROUPING SETS(2008+)をサポートする。旧来の WITH ROLLUP/WITH CUBE 形式は非推奨。GROUPING() と GROUPING_ID() は合計行の識別に役立つ。","since":"SQL Server 2008","xnote":"最新の GROUPING SETS 構文は SQL Server 2008 で導入された。","danger":"safe"},"mongodb":{"command":"// Closest equivalent: $group + $sum\ndb.customer.aggregate([\n  { $group: { _id: \"$city\", n: { $sum: 1 } } },\n  { $match: { n: { $gt: 5 } } }\n])\n// $facet is used for ROLLUP-like multi-level totals","note":"MongoDB では $group が SQL の GROUP BY に相当する。_id がグループ化キーを設定し、アキュムレータ($sum、$avg、$max)が集計を定義する。グループ化後のフィルタリングは $match で行う(HAVING に相当)。ROLLUP/CUBE のような多階層の合計は、$facet で複数のパイプラインを実行して得る。","danger":"safe"},"redis":{"command":"# Not applicable: core Redis has no GROUP BY.\n# Aggregation with RediSearch:\nFT.AGGREGATE customer_idx \"*\" GROUPBY 1 @city REDUCE COUNT 0 AS n","note":"コアの Redis はグループ化を提供しない。RediSearch モジュールの FT.AGGREGATE コマンドが GROUPBY と REDUCE(COUNT、SUM、AVG)で SQL のような集計を行う。FILTER ステップは HAVING のようにグループ化された結果をフィルタリングする。モジュールがない場合、集計はアプリケーションで行う。","danger":"safe"},"elasticsearch":{"command":"GET customer/_search\n{\n  \"size\": 0,\n  \"aggs\": {\n    \"by_city\": { \"terms\": { \"field\": \"city\" },\n      \"aggs\": { \"total\": { \"sum\": { \"field\": \"balance\" } } } }\n  }\n}","note":"Elasticsearch では、グループ化は 'terms' バケット集計で、集計値はメトリクス集計(sum、avg、cardinality)で行う。HAVING のようなフィルタリングには 'bucket_selector' パイプライン集計を使用する。多階層の小計はネストされた集計で構築する。","danger":"safe"}}},{"id":"case-expr","title":"CASE 式(条件付きの値)","aliases":["case","conditional","when","then","decode","if then","conditional value"],"engines":{"oracle":{"command":"-- Searched CASE\nSELECT name,\n  CASE WHEN salary >= 20000 THEN 'high'\n       WHEN salary >= 10000 THEN 'medium'\n       ELSE 'low' END AS tier\nFROM employee;\n\n-- Oracle-specific shortcut: DECODE (equality comparison)\nSELECT name, DECODE(status, 'A', 'Active', 'P', 'Passive', 'Unknown') FROM employee;","note":"CASE は条件に応じて式を異なる値にマッピングする。単純形式(CASE my_column WHEN value)と検索形式(CASE WHEN condition)の両方がある。Oracle の DECODE も同様の役割を果たすが、等価比較のみで NULL 同士を等しいとみなす。移植性のために CASE が推奨される。","danger":"safe"},"postgres":{"command":"SELECT name,\n  CASE WHEN salary >= 20000 THEN 'high'\n       WHEN salary >= 10000 THEN 'medium'\n       ELSE 'low' END AS tier\nFROM employee;","note":"PostgreSQL は標準の CASE 式を完全にサポートし、値を生成するあらゆる場所(SELECT、WHERE、ORDER BY、GROUP BY)で使用できる。Oracle 形式の DECODE はないため、代わりに CASE を、短い条件には COALESCE/NULLIF を使用する。","danger":"safe"},"mysql":{"command":"SELECT name,\n  CASE WHEN salary >= 20000 THEN 'high'\n       WHEN salary >= 10000 THEN 'medium'\n       ELSE 'low' END AS tier\nFROM employee;\n\n-- IF() for a short condition:\nSELECT name, IF(active = 1, 'Yes', 'No') FROM employee;","note":"MySQL/MariaDB は標準の CASE 式をサポートする。手早い 2 分岐の条件には IF(condition, if_true, if_false) 関数もある(SQL Server の IIF に類似)。CASE は任意の式のコンテキストで使用できる。","danger":"safe"},"mssql":{"command":"SELECT name,\n  CASE WHEN salary >= 20000 THEN 'high'\n       WHEN salary >= 10000 THEN 'medium'\n       ELSE 'low' END AS tier\nFROM employee;\n\n-- Shortcut: IIF() (2012+)\nSELECT name, IIF(active = 1, 'Yes', 'No') FROM employee;","note":"SQL Server は標準の CASE をサポートする。2012 以降は 2 分岐の条件のための IIF() ショートカットと、複数の一致のための CHOOSE() がある。IIF は実際には CASE に変換される。CASE は ORDER BY や計算列でも使用できる。","danger":"safe"},"mongodb":{"command":"// Closest equivalent: $switch or $cond\ndb.employee.aggregate([\n  { $project: { name: 1, tier: {\n      $switch: { branches: [\n        { case: { $gte: [\"$salary\", 20000] }, then: \"high\" },\n        { case: { $gte: [\"$salary\", 10000] }, then: \"medium\" } ],\n        default: \"low\" } } } }\n])","note":"MongoDB の集計では、CASE に相当するのは $switch(多分岐)と $cond(3 引数の if-then-else)演算子。$project や $addFields 内で使用して、条件付きの派生フィールドを作成する。","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no in-query conditional expression.","note":"Redis には CASE のようなクエリ式はない。条件ロジックはアプリケーションコードまたはサーバー側の Lua スクリプト(EVAL)で記述する。RediSearch の FT.AGGREGATE 内の APPLY で限定的な式の評価が可能。","danger":"safe"},"elasticsearch":{"command":"# Closest equivalent: a condition inside a runtime field or script\nGET employee/_search\n{\n  \"runtime_mappings\": { \"tier\": { \"type\": \"keyword\",\n    \"script\": \"if (doc['salary'].value >= 20000) emit('high'); else if (doc['salary'].value >= 10000) emit('medium'); else emit('low');\" } },\n  \"fields\": [\"tier\"]\n}","note":"Elasticsearch では、クエリ内の CASE ロジックは Painless スクリプト(runtime field、script_fields、scripted metric)として記述する。if/else のフローは Painless 言語で定義する。'range' 集計も分類のために CASE のようなバケットを生成できる。","danger":"safe"}}},{"id":"union-set","title":"UNION / UNION ALL / INTERSECT / EXCEPT(MINUS)","aliases":["union","union all","intersect","except","minus","set operations","combine","intersection","difference"],"engines":{"oracle":{"command":"-- Union without duplicates\nSELECT city FROM customer\nUNION\nSELECT city FROM supplier;\n\n-- Intersection and difference (MINUS instead of EXCEPT in Oracle)\nSELECT city FROM customer INTERSECT SELECT city FROM supplier;\nSELECT city FROM customer MINUS SELECT city FROM supplier;","note":"集合演算子は 2 つのクエリの結果セットを結合する。UNION は重複を除去し(低速)、UNION ALL はすべてを保持し(高速)、INTERSECT は共通の行を、差集合の演算子は最初の集合にのみ存在する行を返す。差集合に Oracle は標準の EXCEPT ではなく MINUS を使用する(21c 以降は EXCEPT も存在する)。","danger":"safe"},"postgres":{"command":"SELECT city FROM customer\nUNION\nSELECT city FROM supplier;\n\nSELECT city FROM customer INTERSECT SELECT city FROM supplier;\nSELECT city FROM customer EXCEPT SELECT city FROM supplier;","note":"PostgreSQL は標準の UNION、UNION ALL、INTERSECT、EXCEPT を完全にサポートする(差集合は MINUS ではなく EXCEPT)。各演算子の ALL 形式(INTERSECT ALL、EXCEPT ALL)は重複の数を保持する。列数と型は互換である必要がある。","danger":"safe"},"mysql":{"command":"SELECT city FROM customer\nUNION\nSELECT city FROM supplier;\n\n-- INTERSECT/EXCEPT arrive with MySQL 8.0.31+ and MariaDB 10.3+\nSELECT city FROM customer INTERSECT SELECT city FROM supplier;","note":"MySQL は長い間 UNION / UNION ALL のみをサポートしていた。INTERSECT と EXCEPT が追加されたのは MySQL 8.0.31(MariaDB 10.3)になってから。古いバージョンでは積集合に INNER JOIN/EXISTS を、差集合に LEFT JOIN ... IS NULL または NOT EXISTS を使用する。","since":"MySQL 8.0.31","xnote":"INTERSECT/EXCEPT は MySQL 8.0.31(MariaDB 10.3)で導入された。それ以前は JOIN/EXISTS で解決していた。","danger":"safe"},"mssql":{"command":"SELECT city FROM customer\nUNION\nSELECT city FROM supplier;\n\nSELECT city FROM customer INTERSECT SELECT city FROM supplier;\nSELECT city FROM customer EXCEPT SELECT city FROM supplier;","note":"SQL Server は標準の UNION、UNION ALL、INTERSECT、EXCEPT(2005+)をサポートする。差集合の演算子は EXCEPT(MINUS ではない)。INTERSECT/EXCEPT は NULL 値を等しいとみなして行を比較する。","since":"SQL Server 2005","danger":"safe"},"mongodb":{"command":"// Closest equivalent: $unionWith (MongoDB 4.4+)\ndb.customer.aggregate([\n  { $project: { city: 1, _id: 0 } },\n  { $unionWith: { coll: \"supplier\",\n      pipeline: [ { $project: { city: 1, _id: 0 } } ] } },\n  { $group: { _id: \"$city\" } }  // UNION (distinct) effect\n])","note":"MongoDB 4.4+ の $unionWith ステージは 2 つのコレクションの結果を結合する(UNION ALL に類似)。重複を除去するには、その後 $group で重複排除する。INTERSECT/EXCEPT に直接相当するものはなく、$lookup や集合演算子($setIntersection、$setDifference)でモデル化する。","danger":"safe"},"redis":{"command":"# Set operations with the Set data type:\nSUNION city_customer city_supplier    # union\nSINTER city_customer city_supplier    # intersection\nSDIFF  city_customer city_supplier    # difference","note":"Redis には SQL はないが、Set データ型がネイティブの集合演算を提供する: SUNION(和集合)、SINTER(積集合)、SDIFF(差集合)と、結果を保存する STORE 版。これらはクエリ結果ではなく、事前に構築された集合のメンバーに対して動作する。","danger":"safe"},"elasticsearch":{"command":"# There is no direct set operator.\n# For a union, search multiple indices in one query:\nGET customer,supplier/_search\n{ \"query\": { \"match_all\": {} } }","note":"Elasticsearch は UNION/INTERSECT/EXCEPT を提供しない。和集合の効果は、カンマ区切りの複数のインデックスをクエリすることで得られる。積集合と差集合には bool クエリの must/should/must_not 句、またはアプリケーション側の集合ロジックを使用する。","danger":"safe"}}},{"id":"exists-in","title":"EXISTS / IN / NOT EXISTS(サブクエリ)","aliases":["exists","in","not exists","not in","subquery","sub-select","correlated subquery"],"engines":{"oracle":{"command":"-- Customers with orders (EXISTS)\nSELECT name FROM customer m\nWHERE EXISTS (SELECT 1 FROM orders s WHERE s.customer_id = m.id);\n\n-- List membership with IN\nSELECT name FROM customer\nWHERE city IN ('Ankara', 'Izmir');\n\n-- Customers with no orders at all (NOT EXISTS)\nSELECT name FROM customer m\nWHERE NOT EXISTS (SELECT 1 FROM orders s WHERE s.customer_id = m.id);","note":"EXISTS は相関サブクエリが少なくとも 1 行を返すかを確認する(最初の一致で停止するため高速)。IN は値がリスト/サブクエリの結果に含まれるかを確認する。注意: サブクエリが NULL を生成し得る場合、NOT IN は予期しない結果になる。NOT EXISTS のほうが安全。Oracle のオプティマイザは多くの場合、両者を同じ実行計画に変換する。","danger":"safe"},"postgres":{"command":"SELECT name FROM customer m\nWHERE EXISTS (SELECT 1 FROM orders s WHERE s.customer_id = m.id);\n\nSELECT name FROM customer\nWHERE city IN (SELECT city FROM target_cities);\n\nSELECT name FROM customer m\nWHERE NOT EXISTS (SELECT 1 FROM orders s WHERE s.customer_id = m.id);","note":"PostgreSQL は EXISTS/IN/NOT EXISTS を完全にサポートする。NOT IN では、サブクエリに NULL が含まれると結果全体が空になることがあるため、NOT EXISTS または LEFT JOIN ... IS NULL が推奨される。プランナはほとんどの場合、IN と EXISTS をセミジョインとして同等に扱う。","danger":"safe"},"mysql":{"command":"SELECT name FROM customer m\nWHERE EXISTS (SELECT 1 FROM orders s WHERE s.customer_id = m.id);\n\nSELECT name FROM customer\nWHERE city IN ('Ankara', 'Izmir');\n\nSELECT name FROM customer m\nWHERE NOT EXISTS (SELECT 1 FROM orders s WHERE s.customer_id = m.id);","note":"MySQL/MariaDB は EXISTS/IN/NOT EXISTS をサポートする。MySQL 5.6 より前は相関サブクエリが遅くなることがあった。5.6+ はセミジョインとマテリアライズの最適化で IN サブクエリを高速化した。NOT IN + NULL の落とし穴はここでも当てはまる。","danger":"safe"},"mssql":{"command":"SELECT name FROM customer m\nWHERE EXISTS (SELECT 1 FROM orders s WHERE s.customer_id = m.id);\n\nSELECT name FROM customer\nWHERE city IN (SELECT city FROM target_cities);\n\nSELECT name FROM customer m\nWHERE NOT EXISTS (SELECT 1 FROM orders s WHERE s.customer_id = m.id);","note":"SQL Server は EXISTS/IN/NOT EXISTS をサポートし、オプティマイザはほとんどの場合これらをセミ/アンチジョインとして処理する。NOT IN のサブクエリに NULL が含まれると、結果が予期せず空になることがある。NOT EXISTS が安全な選択肢。同様のメンバーシップロジックには INTERSECT/EXCEPT も使用できる。","danger":"safe"},"mongodb":{"command":"// IN equivalent: the $in operator\ndb.customer.find({ city: { $in: [\"Ankara\", \"Izmir\"] } })\n\n// EXISTS equivalent: match check with $lookup + $match\ndb.customer.aggregate([\n  { $lookup: { from: \"orders\", localField: \"id\",\n      foreignField: \"customer_id\", as: \"s\" } },\n  { $match: { \"s.0\": { $exists: true } } }  // at least one order\n])","note":"MongoDB では値リストのメンバーシップは $in / $nin 演算子で行う。サブクエリの EXISTS に相当するのは、$lookup で一致するドキュメントの配列を取得し、配列が空かどうかでフィルタリングすること。フィールドの存在確認は別の { field: { $exists: true } } 演算子(行の関係ではなく、フィールドの有無)。","danger":"safe"},"redis":{"command":"# Membership check with Set/Hash:\nSISMEMBER target_cities \"Ankara\"   # is it in the set? (IN-like)\nEXISTS customer:1                 # does the key exist?","note":"Redis にはサブクエリがない。値のメンバーシップには Set に対する SISMEMBER を使用する(IN に類似)。EXISTS コマンドはサブクエリではなく、指定したキーが存在するかを返す。リレーショナルな存在確認は、複数のキーを読み取ってアプリケーション側で行う。","danger":"safe"},"elasticsearch":{"command":"# IN equivalent: terms query\nGET customer/_search\n{ \"query\": { \"terms\": { \"city\": [\"Ankara\", \"Izmir\"] } } }\n\n# Field existence: exists query\nGET customer/_search\n{ \"query\": { \"exists\": { \"field\": \"phone\" } } }","note":"Elasticsearch で IN に相当するのは 'terms' クエリ(複数の値のいずれかに一致)で、NOT IN は bool の must_not 内の terms。'exists' クエリは SQL の EXISTS には相当せず、ドキュメント内のフィールドに値があるかを確認する。テーブル間の相関 EXISTS には通常、非正規化が必要。","danger":"safe"}}},{"id":"limit-paging","title":"行数の制限/ページング(LIMIT/OFFSET、FETCH、ROWNUM、TOP)","aliases":["limit","offset","fetch","rownum","top","paging","page through results","pagination","row limit"],"engines":{"oracle":{"command":"-- 12c+ standard: OFFSET/FETCH\nSELECT name, salary FROM employee\nORDER BY salary DESC\nOFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;\n\n-- Older versions: with ROWNUM\nSELECT * FROM (\n  SELECT name, salary FROM employee ORDER BY salary DESC\n) WHERE ROWNUM <= 10;","note":"結果セットの制限/ページングに使用する。Oracle 12c 以降は標準の OFFSET n ROWS FETCH NEXT m ROWS ONLY がサポートされる。それ以前は ROWNUM 疑似列を使用していた。ROWNUM はソート前に割り当てられるため、ORDER BY のサブクエリで囲む必要がある。","since":"Oracle 12c","xnote":"Oracle 12c より前は、行数の制限は ROWNUM で行っていた。","danger":"safe"},"postgres":{"command":"-- LIMIT/OFFSET\nSELECT name, salary FROM employee\nORDER BY salary DESC\nLIMIT 10 OFFSET 20;\n\n-- Standard equivalent: FETCH\nSELECT name, salary FROM employee\nORDER BY salary DESC\nOFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;","note":"PostgreSQL は LIMIT n OFFSET m と標準の OFFSET ... FETCH 形式の両方をサポートする。大きな OFFSET 値は遅い。深いページングにはキーベース(keyset / 'WHERE id > last_id')のページネーションのほうが効率的。ORDER BY のない LIMIT は結果の順序を保証しない。","danger":"safe"},"mysql":{"command":"-- LIMIT [offset,] row_count\nSELECT name, salary FROM employee\nORDER BY salary DESC\nLIMIT 10 OFFSET 20;\n\n-- Short form: LIMIT offset, row_count\nSELECT name, salary FROM employee ORDER BY salary DESC LIMIT 20, 10;","note":"MySQL/MariaDB は LIMIT キーワードを 2 つの形式で使用する: LIMIT row_count OFFSET offset または LIMIT offset, row_count。MySQL 8.0.19+ は標準の FETCH 構文も受け付ける。深い OFFSET の性能対策には keyset ページネーションが推奨される。","danger":"safe"},"mssql":{"command":"-- First N with TOP\nSELECT TOP 10 name, salary FROM employee ORDER BY salary DESC;\n\n-- OFFSET/FETCH for paging (2012+), ORDER BY mandatory\nSELECT name, salary FROM employee\nORDER BY salary DESC\nOFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;","note":"SQL Server は先頭 N 行に TOP n(TOP (n) PERCENT / WITH TIES の変形あり)を、2012 以降のページングに OFFSET ... FETCH を使用する。OFFSET/FETCH が動作するには ORDER BY が必須。SQL Server には LIMIT キーワードはない。","since":"SQL Server 2012","xnote":"OFFSET/FETCH によるページングは 2012 で導入された。それ以前は TOP または ROW_NUMBER で行っていた。","danger":"safe"},"mongodb":{"command":"// Paging with skip/limit\ndb.employee.find()\n  .sort({ salary: -1 })\n  .skip(20)\n  .limit(10)","note":"MongoDB では limit() が返すドキュメント数を、skip() がスキップする数を設定し、sort() と組み合わせてページングを行う。大きな skip 値は高コスト。深いページングには、最後に見た値に基づく範囲(keyset)クエリが推奨される。","danger":"safe"},"redis":{"command":"# Range read on a sorted set (ZSET):\nZREVRANGE salary_sorted 20 29    # members ranked 21-30\n# Range on a list:\nLRANGE queue 0 9              # first 10 elements","note":"Redis には SQL の LIMIT はないが、範囲読み取りのコマンドがある: Sorted Set には ZRANGE/ZREVRANGE start stop(インデックスベース)または ZRANGEBYSCORE ... LIMIT offset count、List には LRANGE。これらのコマンドでページングのようなアクセスができる。","danger":"safe"},"elasticsearch":{"command":"GET employee/_search\n{\n  \"from\": 20,\n  \"size\": 10,\n  \"sort\": [ { \"salary\": \"desc\" } ]\n}","note":"Elasticsearch では 'size' が返すヒット数を、'from' がスキップする数を設定する(LIMIT/OFFSET に相当)。from+size は最大 index.max_result_window(デフォルト 10,000)まで。深いページングには 'search_after'(keyset)または PIT(point-in-time)を使用する。","danger":"safe"}}},{"id":"merge-upsert","title":"MERGE / UPSERT(存在すれば更新、なければ挿入)","aliases":["merge","upsert","on conflict","on duplicate key","insert or update","update if exists"],"engines":{"oracle":{"command":"MERGE INTO customer m\nUSING (SELECT 1 AS id, 'Ali' AS name, 500 AS balance FROM dual) k\nON (m.id = k.id)\nWHEN MATCHED THEN\n  UPDATE SET m.name = k.name, m.balance = k.balance\nWHEN NOT MATCHED THEN\n  INSERT (id, name, balance) VALUES (k.id, k.name, k.balance);","note":"MERGE(upsert)はソースをターゲットと照合し、一致する行を更新し、一致しない行を挿入する。一括のデータ同期に最適。Oracle は強力な MERGE をサポートし、WHEN MATCHED ... DELETE や条件付きの更新も記述できる。単一行のソースには dual テーブルを使用する。","since":"Oracle 9i","danger":"caution"},"postgres":{"command":"-- The PostgreSQL way: INSERT ... ON CONFLICT\nINSERT INTO customer (id, name, balance)\nVALUES (1, 'Ali', 500)\nON CONFLICT (id) DO UPDATE\n  SET name = EXCLUDED.name, balance = EXCLUDED.balance;","note":"PostgreSQL の従来の upsert は INSERT ... ON CONFLICT(一意の列)DO UPDATE / DO NOTHING。競合した行の新しい値には EXCLUDED エイリアスでアクセスする。PostgreSQL 15 以降は標準の MERGE 文もサポートされる。ON CONFLICT は単一のテーブルでアトミックであり、広く使用されている。","since":"PostgreSQL 15","xnote":"標準の MERGE 文は PostgreSQL 15 で導入された。それ以前は INSERT ... ON CONFLICT(9.5)で upsert を行っていた。","danger":"caution"},"mysql":{"command":"INSERT INTO customer (id, name, balance)\nVALUES (1, 'Ali', 500)\nON DUPLICATE KEY UPDATE\n  name = VALUES(name), balance = VALUES(balance);","note":"MySQL/MariaDB は upsert に INSERT ... ON DUPLICATE KEY UPDATE を使用する。一意キーまたは主キーが競合すると、その行が更新される。新しい値には VALUES(my_column)(8.0.19+ では行エイリアス 'new.my_column')でアクセスする。INSERT IGNORE は競合時にその行を黙ってスキップする。MySQL には標準の MERGE はない。","danger":"caution"},"mssql":{"command":"MERGE INTO customer AS m\nUSING (VALUES (1, 'Ali', 500)) AS k(id, name, balance)\nON m.id = k.id\nWHEN MATCHED THEN\n  UPDATE SET m.name = k.name, m.balance = k.balance\nWHEN NOT MATCHED THEN\n  INSERT (id, name, balance) VALUES (k.id, k.name, k.balance);","note":"SQL Server は 2008 以降 MERGE 文をサポートし、ターゲットの余分な行を削除するための WHEN NOT MATCHED BY SOURCE などの追加の分岐を提供する。MERGE 文はセミコロンで終える必要がある。注: 一部のエッジケースのバグのため、単純な upsert では INSERT/UPDATE 文を個別に書くほうが好ましい場合がある。","since":"SQL Server 2008","danger":"caution"},"mongodb":{"command":"// Find-and-update or insert with upsert:true\ndb.customer.updateOne(\n  { id: 1 },\n  { $set: { name: \"Ali\", balance: 500 } },\n  { upsert: true }\n)","note":"MongoDB では upsert はネイティブのオプション。updateOne/updateMany/findOneAndUpdate に { upsert: true } を追加すると、一致するドキュメントは更新され、そうでなければ新しいドキュメントが作成される。一括の同期には、集計の $merge ステージ(ターゲットコレクションへの書き込み/更新)が SQL の MERGE により近い。","danger":"caution"},"redis":{"command":"# SET is a natural upsert: it overwrites the key if present, otherwise creates it.\nSET customer:1 '{\"name\":\"Ali\",\"balance\":500}'\n# Update/add a hash field:\nHSET customer:1 name Ali balance 500","note":"Redis の書き込みコマンドは本質的に upsert: SET/HSET はキーまたはフィールドが存在すれば更新し、なければ作成する。存在しない場合のみ書き込むには SET ... NX オプションを、存在する場合のみなら XX を使用する。「存在すれば更新、なければ挿入」の区別は、ほとんどのコマンドで既にデフォルトの挙動。","danger":"safe"},"elasticsearch":{"command":"# An index call with a document id acts like an upsert (replaces if present):\nPUT customer/_doc/1\n{ \"name\": \"Ali\", \"balance\": 500 }\n# Partial update + insert if absent:\nPOST customer/_update/1\n{ \"doc\": { \"balance\": 500 }, \"doc_as_upsert\": true }","note":"Elasticsearch では、同じ _id での index(PUT)呼び出しは、ドキュメントが存在すれば完全に置き換え、なければ作成する(upsert に類似)。存在しない場合は挿入する部分更新には、_update API で 'doc_as_upsert': true または 'upsert' ブロックを使用する。スクリプトによる upsert も可能。","danger":"caution"}}},{"id":"returning-output","title":"変更された行を返す(RETURNING / OUTPUT)","aliases":["returning","output","inserted","deleted","returned value","modified row"],"engines":{"oracle":{"command":"-- Single row: RETURNING ... INTO (PL/SQL bind variable)\nUPDATE employee SET salary = salary * 1.1\nWHERE id = 5\nRETURNING salary INTO :new_salary;\n\n-- Get back the key generated by an INSERT\nINSERT INTO employee (name) VALUES ('Ayse')\nRETURNING id INTO :new_id;","note":"RETURNING は、INSERT/UPDATE/DELETE で変更された行の値(例: 自動生成された ID)を別の SELECT なしで返す。Oracle では、単一行は RETURNING ... INTO でバインド変数に、複数行は RETURNING ... BULK COLLECT INTO でコレクションに返す。","danger":"safe"},"postgres":{"command":"INSERT INTO employee (name, salary)\nVALUES ('Ayse', 15000)\nRETURNING id, name;\n\nUPDATE employee SET salary = salary * 1.1\nWHERE department = 'IT'\nRETURNING id, salary;","note":"PostgreSQL の RETURNING 句は非常に柔軟で、INSERT、UPDATE、DELETE、MERGE 文の影響を受けた行の任意の列(計算式を含む)を結果セットとして直接返す。生成された serial/identity の値を取得する最もすっきりした方法。","since":"PostgreSQL 8.2","danger":"safe"},"mysql":{"command":"-- MySQL has no RETURNING; the generated key is retrieved separately:\nINSERT INTO employee (name, salary) VALUES ('Ayse', 15000);\nSELECT LAST_INSERT_ID();\n\n-- MariaDB 10.5+ supports INSERT ... RETURNING:\nINSERT INTO employee (name) VALUES ('Ayse') RETURNING id;","note":"MySQL は標準の RETURNING をサポートしない。INSERT で生成された自動採番キーは LAST_INSERT_ID() で取得し、更新された値は別の SELECT で読み取る。MariaDB は 10.5 以降で INSERT ... RETURNING を、10.0 以降で DELETE ... RETURNING を提供する。","danger":"safe"},"mssql":{"command":"INSERT INTO employee (name, salary)\nOUTPUT INSERTED.id, INSERTED.name\nVALUES ('Ayse', 15000);\n\nUPDATE employee SET salary = salary * 1.1\nOUTPUT DELETED.salary AS old_salary, INSERTED.salary AS new_salary\nWHERE id = 5;","note":"SQL Server で相当するのは OUTPUT 句で、INSERTED(新しい値)と DELETED(古い値)の疑似テーブルにアクセスする。UPDATE では両方を使用できる。OUTPUT ... INTO で結果をテーブル/テーブル変数に書き込める。変更を監査テーブルにコピーするのに最適。","since":"SQL Server 2005","xnote":"OUTPUT 句は SQL Server 2005 で導入された。","danger":"safe"},"mongodb":{"command":"// findOneAndUpdate returns the modified document\ndb.employee.findOneAndUpdate(\n  { id: 5 },\n  { $mul: { salary: 1.1 } },\n  { returnDocument: \"after\" }   // return the updated version\n)","note":"MongoDB では findOneAndUpdate / findOneAndDelete / findOneAndReplace コマンドが、影響を受けたドキュメントを単一のアトミックな操作で返す。returnDocument: 'before' は変更前の版を、'after' は変更後の版を返す。insertOne は挿入したドキュメントの _id を返す。","danger":"safe"},"redis":{"command":"# Some commands return the old/new value directly:\nSET counter 0 GET       # (6.2+) returns the old value and writes the new one (replaces GETSET)\nINCR visits          # increments and returns the new value","note":"Redis には独立した RETURNING はないが、多くの書き込みコマンドは結果を直接返す: INCR/INCRBY は新しい値を、SET ... GET は古い値を(GETSET は 6.2 以降非推奨)、LPOP/RPOP は取り出した要素を返す。アトミックな読み書きでは、この挙動が RETURNING の代わりとなる。","danger":"safe"},"elasticsearch":{"command":"# The _update response can return the result:\nPOST employee/_update/5\n{\n  \"script\": { \"source\": \"ctx._source.salary *= 1.1\" },\n  \"_source\": true\n}\n# The response returns the updated document in get._source","note":"Elasticsearch では、index/update 操作は結果のメタデータ(_id、_version、result)を返す。更新されたドキュメントの本体を取得するには、_update リクエストに '_source': true を追加する。レスポンスの get フィールドに現在の _source が含まれる。別の GET 呼び出しは不要。","danger":"safe"}}},{"id":"lateral-apply","title":"LATERAL / CROSS APPLY(行ごとのサブクエリ)","aliases":["lateral","cross apply","outer apply","row-by-row subquery","correlated table function"],"engines":{"oracle":{"command":"-- Each customer's 3 most recent orders (LATERAL, 12c+)\nSELECT m.name, s.created_at, s.amount\nFROM customer m,\n     LATERAL (SELECT created_at, amount FROM orders\n              WHERE customer_id = m.id\n              ORDER BY created_at DESC FETCH FIRST 3 ROWS ONLY) s;\n\n-- Alternative: CROSS APPLY (12c+)\nSELECT m.name, s.amount\nFROM customer m\nCROSS APPLY (SELECT amount FROM orders WHERE customer_id = m.id) s;","note":"LATERAL/APPLY により、FROM 内のサブクエリがその左側のテーブルの列を参照できるため、「各行に対する先頭 N 行」のような相関結合を記述できる。Oracle 12c は ANSI の LATERAL と CROSS/OUTER APPLY の両方の構文をサポートする。","since":"Oracle 12c","xnote":"LATERAL と CROSS/OUTER APPLY は Oracle 12c で導入された。","danger":"safe"},"postgres":{"command":"SELECT m.name, s.created_at, s.amount\nFROM customer m\nCROSS JOIN LATERAL (\n  SELECT created_at, amount FROM orders\n  WHERE customer_id = m.id\n  ORDER BY created_at DESC LIMIT 3\n) s;","note":"PostgreSQL では、左側の行に依存するサブクエリを LATERAL キーワード(JOIN LATERAL / CROSS JOIN LATERAL / LEFT JOIN LATERAL)で記述する。「グループごとの上位 N 件」や、集合を返す関数による行の展開に非常に便利。CROSS APPLY 構文はなく、LATERAL を使用する。","since":"PostgreSQL 9.3","xnote":"LATERAL は PostgreSQL 9.3 で導入された。","danger":"safe"},"mysql":{"command":"-- MySQL 8.0.14+ supports LATERAL\nSELECT m.name, s.amount\nFROM customer m\nJOIN LATERAL (\n  SELECT amount FROM orders\n  WHERE customer_id = m.id\n  ORDER BY created_at DESC LIMIT 3\n) s ON true;","note":"MySQL 8.0.14 以降、LATERAL 派生テーブルがサポートされ、サブクエリが外側のテーブルの列を参照できる。それ以前、および CROSS APPLY については相当するものがなく、「グループごとの上位 N 件」はウィンドウ関数や相関サブクエリで解決していた。MariaDB にはまだ LATERAL がない。","since":"MySQL 8.0.14","xnote":"LATERAL 派生テーブルは MySQL 8.0.14 で導入された。MariaDB にはない。","danger":"safe"},"mssql":{"command":"SELECT m.name, s.created_at, s.amount\nFROM customer m\nCROSS APPLY (\n  SELECT TOP 3 created_at, amount FROM orders\n  WHERE customer_id = m.id\n  ORDER BY created_at DESC\n) s;\n-- Use OUTER APPLY to return non-matching rows too","note":"SQL Server で LATERAL に相当するのは APPLY 演算子: CROSS APPLY(INNER JOIN LATERAL に類似、一致しないものは除外)と OUTER APPLY(LEFT JOIN LATERAL に類似、一致しないものは NULL)。各行に対してテーブル値関数を呼び出す場合や、グループごとの上位 N 件のクエリによく使われる。","since":"SQL Server 2005","xnote":"CROSS/OUTER APPLY 演算子は SQL Server 2005 で導入された。","danger":"safe"},"mongodb":{"command":"// Closest equivalent: $lookup with a sub-pipeline\ndb.customer.aggregate([\n  { $lookup: {\n      from: \"orders\",\n      let: { mid: \"$id\" },\n      pipeline: [\n        { $match: { $expr: { $eq: [\"$customer_id\", \"$$mid\"] } } },\n        { $sort: { created_at: -1 } }, { $limit: 3 }\n      ],\n      as: \"last3\"\n  } }\n])","note":"MongoDB で LATERAL/APPLY に相当するのは、サブパイプラインと let 変数を使う $lookup の形式。外側のドキュメントのフィールドを let で $$variable としてサブパイプラインに渡し、そこで照合/ソート/制限を行う。これで「各ドキュメントに関連する上位 N 件」のパターンを解決できる。","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no subqueries / LATERAL.","note":"Redis は行ごとの相関サブクエリを提供しない。「各項目に関連する上位 N 件」のパターンは、アプリケーション側のループ(例: キーごとに個別の ZRANGE)またはサーバー側の Lua スクリプトで解決する。","danger":"safe"},"elasticsearch":{"command":"# Closest equivalent: terms + top_hits sub-aggregation\nGET orders/_search\n{\n  \"size\": 0,\n  \"aggs\": { \"by_customer\": { \"terms\": { \"field\": \"customer_id\" },\n    \"aggs\": { \"last3\": { \"top_hits\": {\n      \"sort\": [ { \"created_at\": \"desc\" } ], \"size\": 3 } } } } }\n}","note":"Elasticsearch には LATERAL/APPLY がない。「グループごとの上位 N レコード」のパターンは、terms 集計内にネストした top_hits サブ集計で実現する。相関サブクエリではなく、単一のインデックス上でのグループ化とグループ内のサンプリングとなる。","danger":"safe"}}},{"id":"pivot","title":"PIVOT / UNPIVOT(行↔列)","aliases":["pivot","unpivot","crosstab","cross tab","rows to columns","transpose"],"engines":{"oracle":{"command":"-- Turn sales by month into columns\nSELECT * FROM (\n  SELECT month, amount FROM sale\n)\nPIVOT (SUM(amount) FOR month IN ('Jan' AS jan, 'Feb' AS feb, 'Mar' AS mar));\n\n-- UNPIVOT: turn columns back into rows\nSELECT product, month, amount\nFROM sale_wide\nUNPIVOT (amount FOR month IN (jan AS 'Jan', feb AS 'Feb'));","note":"PIVOT は行内の異なる値を列に変換し(クロス集計)、UNPIVOT は列を行に戻す。サマリー/レポート用のテーブルで使用される。Oracle は 11g 以降、組み込みの PIVOT/UNPIVOT 演算子を提供する。列リストは静的である必要がある(動的な列には PIVOT XML またはコードが必要)。","since":"Oracle 11g","xnote":"組み込みの PIVOT/UNPIVOT 演算子は Oracle 11g で導入された。","danger":"safe"},"postgres":{"command":"-- The tablefunc extension for crosstab\nCREATE EXTENSION IF NOT EXISTS tablefunc;\nSELECT * FROM crosstab(\n  'SELECT product, month, amount FROM sale ORDER BY 1,2'\n) AS ct(product text, jan numeric, feb numeric, mar numeric);\n\n-- Without an extension: conditional aggregation\nSELECT product,\n  SUM(amount) FILTER (WHERE month = 'Jan') AS jan,\n  SUM(amount) FILTER (WHERE month = 'Feb') AS feb\nFROM sale GROUP BY product;","note":"PostgreSQL には組み込みの PIVOT 演算子がない。方法は 2 つ: tablefunc 拡張の crosstab() 関数、または移植性のある条件付き集計(SUM(...) FILTER (WHERE ...) または CASE を使用)。FILTER 句は PostgreSQL 固有のエレガントなピボット手法。","danger":"safe"},"mysql":{"command":"-- There is no PIVOT; conditional aggregation with manual CASE\nSELECT product,\n  SUM(CASE WHEN month = 'Jan' THEN amount ELSE 0 END) AS jan,\n  SUM(CASE WHEN month = 'Feb' THEN amount ELSE 0 END) AS feb,\n  SUM(CASE WHEN month = 'Mar' THEN amount ELSE 0 END) AS mar\nFROM sale\nGROUP BY product;","note":"MySQL/MariaDB には PIVOT/UNPIVOT 演算子がない。クロス集計は、GROUP BY と各ターゲット列に対する SUM(CASE WHEN ... THEN ... END) で手作業で構築する。列が動的な場合は、プリペアドステートメントでクエリを文字列として生成する。","danger":"safe"},"mssql":{"command":"SELECT * FROM (\n  SELECT product, month, amount FROM sale\n) src\nPIVOT (\n  SUM(amount) FOR month IN ([Jan], [Feb], [Mar])\n) pvt;\n\n-- Converting back with UNPIVOT is also supported","note":"SQL Server は 2005 以降 PIVOT と UNPIVOT 演算子をネイティブにサポートする。PIVOT の列リストは角括弧で囲んだ静的な値として指定する。動的な列には動的 SQL でクエリを構築する。小さなサマリーには条件付き集計(CASE)が代替手段。","since":"SQL Server 2005","xnote":"PIVOT/UNPIVOT 演算子は SQL Server 2005 で導入された。","danger":"safe"},"mongodb":{"command":"// PIVOT equivalent: conditional aggregation inside $group\ndb.sale.aggregate([\n  { $group: {\n      _id: \"$product\",\n      jan: { $sum: { $cond: [ { $eq: [\"$month\", \"Jan\"] }, \"$amount\", 0 ] } },\n      feb: { $sum: { $cond: [ { $eq: [\"$month\", \"Feb\"] }, \"$amount\", 0 ] } }\n  } }\n])","note":"MongoDB には PIVOT 演算子がない。クロス集計は $group ステージで各ターゲット列に対して $sum + $cond(条件付き集計)で構築する。逆方向(UNPIVOT)では、$objectToArray と $unwind でフィールドを行に展開する。","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no pivot/cross tab.","note":"Redis には行と列を入れ替える概念がない。サマリー/クロス集計はアプリケーション側で計算する。頻繁に要求されるサマリーは事前に計算して Hash フィールド(列ごとに 1 フィールド)に格納できる。RediSearch の FT.AGGREGATE はグループ化した集計を行えるが、本当のピボットではない。","danger":"safe"},"elasticsearch":{"command":"# Closest equivalent: nested terms aggregations\nGET sale/_search\n{\n  \"size\": 0,\n  \"aggs\": { \"product\": { \"terms\": { \"field\": \"product\" },\n    \"aggs\": { \"month\": { \"terms\": { \"field\": \"month\" },\n      \"aggs\": { \"total\": { \"sum\": { \"field\": \"amount\" } } } } } }\n}","note":"Elasticsearch には PIVOT 演算子がない。クロス集計はネストした terms 集計(外側のキー / 内側のキー)で構築し、結果は列ではなくネストしたバケットとして返るため、クライアントで表に変換する。transform ジョブでグループ化されたピボット風のターゲットインデックスを生成できる。","danger":"safe"}}},{"id":"coalesce-null","title":"NULL の扱い(COALESCE/NVL/NULLIF/IS NULL)","aliases":["coalesce","nvl","nullif","is null","ifnull","isnull","null handling","empty value"],"engines":{"oracle":{"command":"-- COALESCE: returns the first non-NULL value (standard)\nSELECT name, COALESCE(phone, mobile, 'none') AS contact FROM customer;\n\n-- Oracle-specific NVL / NVL2\nSELECT NVL(balance, 0) FROM customer;\nSELECT NVL2(discount, 'yes', 'no') FROM orders;\n\n-- NULLIF and IS NULL\nSELECT NULLIF(a, b) FROM t;   -- NULL if a=b\nSELECT name FROM customer WHERE phone IS NULL;","note":"NULL(不明な値)の扱い: COALESCE はリスト内の最初の NULL でない値を返す(標準、複数の引数)。Oracle の NVL(a,b) は 2 引数の同等関数で、NVL2 は値が NULL かどうかに応じて異なる値を返す。NULLIF(a,b) は等しい場合に NULL を返す。NULL の判定には常に IS NULL / IS NOT NULL を使用する(= NULL は機能しない)。","danger":"safe"},"postgres":{"command":"SELECT name, COALESCE(phone, mobile, 'none') AS contact FROM customer;\nSELECT NULLIF(divisor, 0) FROM t;   -- prevent division by zero\nSELECT name FROM customer WHERE phone IS NULL;\n-- The equivalent of Oracle NVL is COALESCE","note":"PostgreSQL は標準の COALESCE、NULLIF、IS NULL/IS NOT NULL を提供する。Oracle の NVL の代わりに COALESCE を使用する。NULL の比較には = ではなく IS を使用する。2 つの NULL を等しいとみなす必要がある場合は 'IS NOT DISTINCT FROM' 演算子を使う。","danger":"safe"},"mysql":{"command":"SELECT name, COALESCE(phone, mobile, 'none') AS contact FROM customer;\n\n-- MySQL shortcut: IFNULL (two arguments)\nSELECT IFNULL(balance, 0) FROM customer;\nSELECT NULLIF(a, b) FROM t;\nSELECT name FROM customer WHERE phone IS NULL;","note":"MySQL/MariaDB は標準の COALESCE と NULLIF をサポートする。IFNULL(a,b) は 2 引数のショートカット(Oracle の NVL に類似)。<=> 演算子は NULL セーフな等価比較を提供する(2 つの NULL を等しいとみなす)。NULL は IS NULL / IS NOT NULL で判定する。","danger":"safe"},"mssql":{"command":"SELECT name, COALESCE(phone, mobile, 'none') AS contact FROM customer;\n\n-- SQL Server shortcut: ISNULL (two arguments)\nSELECT ISNULL(balance, 0) FROM customer;\nSELECT NULLIF(a, b) FROM t;\nSELECT name FROM customer WHERE phone IS NULL;","note":"SQL Server は標準の COALESCE(複数の引数、データ型の昇格あり)と 2 引数の ISNULL(a,b) を提供する。両者は微妙に異なる(COALESCE は標準で、型の優先順位に関してより柔軟)。NULLIF と IS NULL もサポートされる。ISNULL は Oracle の NVL に相当する(名前が似ている)。","danger":"safe"},"mongodb":{"command":"// COALESCE equivalent: $ifNull\ndb.customer.aggregate([\n  { $project: { name: 1,\n      contact: { $ifNull: [\"$phone\", \"$mobile\", \"none\"] } } }\n])\n// NULL / missing field check:\ndb.customer.find({ phone: { $in: [null] } })","note":"MongoDB の集計で COALESCE に相当するのは $ifNull 演算子(複数の引数、null/missing でない最初の値を返す)。クエリでは、{ field: null } は値が null のドキュメントとフィールドが存在しないドキュメントの両方に一致する。{ field: { $type: 'null' } } または $exists で区別を明示する。","danger":"safe"},"redis":{"command":"# Instead of NULL, Redis has the concept of 'no such key/field':\nEXISTS customer:1              # does the key exist?\nHGET customer:1 phone        # returns nil if the field is absent\nGET missing_key                  # (nil)","note":"Redis には SQL の意味での NULL はない。相当するのは存在しないキーや存在しない Hash フィールドで、その場合コマンドは nil を返す。デフォルト値のロジック(COALESCE のような)は、アプリケーション側で nil を確認して適用する。フィールドの存在は HEXISTS で確認する。","danger":"safe"},"elasticsearch":{"command":"# Default assignment when a field is missing (missing bucket / null_value)\n# Find documents without the field in a query:\nGET customer/_search\n{ \"query\": { \"bool\": { \"must_not\": { \"exists\": { \"field\": \"phone\" } } } } }\n# Map empty values to a specific value with null_value in the mapping","note":"Elasticsearch では、null または存在しないフィールドは 'exists' クエリで確認する(must_not exists = フィールドのないドキュメント)。COALESCE のようなデフォルト値には、マッピングで 'null_value' を定義するか、集計で 'missing' パラメータを使って欠けているエントリに値を割り当てる。デフォルト値は runtime field/スクリプトでも生成できる。","danger":"safe"}}}]},"rosetta/overlay-elasticsearch.json":{"engineId":"elasticsearch","byConcept":{"active-sessions":{"command":"GET _tasks?detailed=true&actions=*search*\n# To see node pressure: GET _nodes/hot_threads","note":"Task API は現在実行中のタスク(search、reindex、bulk)を返す。瞬間的な CPU 負荷については、hot_threads が最もアクティブなスレッドを示す。","danger":"safe"},"blocking-sessions":{"command":"# Not applicable: Elasticsearch has no concept of row/document locks or blocking.\n# Closest diagnosis: find long-running tasks\nGET _tasks?detailed=true","note":"ブロッキングではなく、遅延は通常、長時間実行のタスク(大きな検索、reindex)に起因する。所要時間は running_time_in_nanos フィールドで評価する。","danger":"safe"},"kill-session":{"command":"POST _tasks/<task_id>/_cancel\n# task_id format: nodeId:taskNumber (e.g. oTUltX4IQMOUUVeiohTt8A:12345)","note":"task_id の値は GET _tasks の出力から取得する。停止できるのはキャンセル可能な(cancellable:true)タスクのみ。","danger":"danger"},"connection-count":{"command":"GET _nodes/stats/http","note":"current_open は現在オープン中の HTTP 接続を、total_opened はノード起動以降の総接続数を示す。HTTP 接続の上限は http.max_content_length ではなく、OS/ソケットの制限によって決まる。","danger":"safe"},"database-size":{"command":"GET _cluster/stats\n# For a simple summary: GET _cat/indices?v&h=index,store.size","note":"_cluster/stats は indices.store.size_in_bytes でクラスタ全体の合計ディスク使用量を示す。_cat/indices はインデックスごとのサイズを読みやすい形式で一覧表示する。","danger":"safe"},"largest-tables":{"command":"GET _cat/indices?v&s=store.size:desc&h=index,docs.count,store.size","note":"Elasticsearch で「テーブル」に相当するのはインデックス。s=store.size:desc で最大のインデックスが上位にソートされる。","danger":"safe"},"free-space":{"command":"GET _cat/allocation?v","note":"disk.used、disk.avail、disk.percent 列がノードごとのディスク使用量を示す。ウォーターマークのしきい値(85%/90%/95%)を超えると、シャードの割り当てが停止する。","danger":"safe"},"row-count":{"command":"GET <index>/_count\n# Shortcut: GET _cat/count/<index>?v","note":"_count はドキュメント数を高速に返す。絞り込んだカウントには本文でクエリを渡す: GET <index>/_count {\"query\":{\"term\":{\"status\":\"active\"}}}","danger":"safe"},"top-slow-queries":{"command":"PUT <index>/_settings\n{\n  \"index.search.slowlog.threshold.query.warn\": \"1s\",\n  \"index.search.slowlog.threshold.query.info\": \"500ms\",\n  \"index.search.slowlog.threshold.fetch.warn\": \"1s\"\n}\n# Queries exceeding the threshold are written to the <cluster>_index_search_slowlog.json log file","note":"Elasticsearch には中央のスロークエリテーブルがなく、search slowlog がしきい値を超えたクエリをノードのログファイルに書き込む。ログはそこで確認する。","danger":"caution"},"explain-plan":{"command":"GET <index>/_search\n{\n  \"profile\": true,\n  \"query\": { \"match\": { \"title\": \"test\" } }\n}\n# To check query validity/parsing:\n# GET <index>/_validate/query?explain=true","note":"profile:true は各クエリコンポーネントと集計ステップの所要時間を内訳表示する。_validate/query?explain はクエリの Lucene での同等表現と、拒否された理由を示す。","danger":"safe"},"unused-indexes":{"command":"# Not applicable: secondary indexes in ES differ from relational databases.\n# Closest: assess rarely used/unaccessed indices by size and search count\nGET _cat/indices?v&h=index,docs.count,store.size\nGET <index>/_stats/search","note":"未使用のフィールドインデックスではなく、_stats/search で検索回数(search.query_total)が少ない、またはもうクエリされていないインデックスを特定し、クローズ/削除する。","danger":"safe"},"cache-hit-ratio":{"command":"GET _nodes/stats/indices/query_cache\n# Ratio = hit_count / (hit_count + miss_count)","note":"query_cache はフィルタコンテキストでの結果をキャッシュする。request_cache は GET _nodes/stats/indices/request_cache で別途確認する。","danger":"safe"},"logical-dump":{"command":"# First define a repository (once): PUT _snapshot/<repo> {\"type\":\"fs\",\"settings\":{\"location\":\"/mnt/backups\"}}\nPUT _snapshot/<repo>/<snapshot_1>?wait_for_completion=true\n{\n  \"indices\": \"*\",\n  \"include_global_state\": true\n}","note":"Elasticsearch で論理ダンプに相当するのはスナップショット API。wait_for_completion=true は操作が完了するまで待機する。大きなスナップショットでは false のままにし、状態を別途照会する。","danger":"safe"},"restore-dump":{"command":"POST _snapshot/<repo>/<snapshot_1>/_restore\n{\n  \"indices\": \"*\",\n  \"rename_pattern\": \"(.+)\",\n  \"rename_replacement\": \"restored_$1\"\n}","note":"既存のインデックスをリストアするには、先にクローズする(POST <index>/_close)か、rename_pattern で新しい名前でリストアする。オープン中のインデックスの上にはリストアできない。","danger":"danger"},"last-backup-status":{"command":"GET _snapshot/<repo>/_all\n# For in-progress/latest snapshot details:\n# GET _snapshot/<repo>/<snapshot_1>/_status","note":"state フィールドは SUCCESS / IN_PROGRESS / PARTIAL / FAILED の値をとる。_status はシャードごとの詳細な進捗を示す。","danger":"safe"},"list-users":{"command":"GET _security/user","note":"X-Pack Security が有効である必要がある。単一のユーザーの場合: GET _security/user/<user>。組み込みユーザーも一覧に表示される。","danger":"safe"},"create-user-grant":{"command":"# 1) Create a role\nPOST _security/role/<role>\n{\n  \"cluster\": [\"monitor\"],\n  \"indices\": [ { \"names\": [\"log-*\"], \"privileges\": [\"read\"] } ]\n}\n# 2) Create the user and assign the role\nPOST _security/user/<user>\n{\n  \"password\": \"StrongPassword123\",\n  \"roles\": [\"<role>\"]\n}","note":"認可はロールベース。まずインデックス/クラスタの権限を含むロールを定義し、次にそれをユーザーに割り当てる。パスワードは 6 文字以上である必要がある。","danger":"caution"},"show-privileges":{"command":"GET _security/user/<user>\nGET _security/role/<role>\n# Check whether a specific privilege is held:\n# POST _security/user/<user>/_has_privileges { \"index\": [ { \"names\": [\"log-*\"], \"privileges\": [\"read\"] } ] }","note":"ユーザーのロールは _security/user で、ロールに含まれる権限は _security/role で確認する。_has_privileges は特定のアクションが許可されているかを検証する。","danger":"safe"},"change-password":{"command":"POST _security/user/<user>/_password\n{\n  \"password\": \"NewStrongPassword123\"\n}","note":"自分のパスワードを変更するには、POST _security/user/_password(ユーザー名なし)で十分。組み込みの elastic ユーザーには bin/elasticsearch-reset-password ツールも使用できる。","danger":"caution"},"update-statistics":{"command":"# Not applicable: Elasticsearch has no cost-based optimizer or table statistics gathering.\n# Closest: make newly written documents searchable\nPOST <index>/_refresh","note":"Lucene はセグメントベースであり、個別の統計更新の手順は不要。_refresh はまだ検索できないドキュメントを即座に検索可能にする(デフォルトでは 1s ごとに自動的に行われる)。","danger":"safe"},"rebuild-index":{"command":"POST _reindex\n{\n  \"source\": { \"index\": \"old_index\" },\n  \"dest\":   { \"index\": \"new_index\" }\n}\n# For large data: run in the background with POST _reindex?wait_for_completion=false","note":"reindex はマッピングの変更や、壊れたインデックスの再構築に使用する。シームレスに切り替えるには、エイリアスを新しいインデックスに向ける。","danger":"caution"},"reclaim-space":{"command":"POST <index>/_forcemerge?only_expunge_deletes=true\n# Full merge on read-only/old indices: POST <index>/_forcemerge?max_num_segments=1","note":"削除/更新されたドキュメントはトゥームストーンとしてセグメントに残る。forcemerge はこの領域を回収する。書き込みが活発なインデックスでは高コストのため、オフピークの時間帯に実行する。","danger":"caution"},"version-uptime":{"command":"GET /\n# Uptime (JVM uptime):\n# GET _nodes/stats/jvm\n# Short summary: GET _cat/nodes?v&h=name,uptime,version","note":"GET / ルートエンドポイントはバージョン、Lucene のバージョン、クラスタ名を返す。jvm.uptime_in_millis はノードの稼働時間。","danger":"safe"},"show-config-param":{"command":"GET _cluster/settings?include_defaults=true&flat_settings=true","note":"include_defaults=true はデフォルト値も表示する。persistent と transient の設定は別々のセクションで返される。ノードレベルの設定には GET _nodes/settings を使用する。","danger":"safe"},"list-tables":{"command":"GET _cat/indices?v","note":"Elasticsearch でリレーショナルなテーブルに相当するのはインデックス。health、status、docs.count、store.size 列で概要を示す。デフォルトの出力はオープンおよびクローズ済みのインデックスを一覧表示するが、非表示のもの(例: .ds- バッキングインデックス、システムインデックス)は含まない。含めるには &expand_wildcards=all を、オープン中のインデックスのみなら &expand_wildcards=open を追加する。","danger":"safe"},"describe-table":{"command":"GET <index>/_mapping","note":"マッピングはフィールドの型と解析設定を示し、DESCRIBE TABLE に相当する。単一のフィールドの場合: GET <index>/_mapping/field/<field>。","danger":"safe"},"list-indexes":{"command":"GET <index>/_mapping","note":"ES ではフィールドはデフォルトでインデックス化され、独立したセカンダリインデックスのテーブルはない。マッピングで \"index\": false のフィールドは検索できない。クラスタ全体のインデックス(テーブル)の場合: GET _cat/indices?v。","danger":"safe"},"create-index":{"command":"PUT <index>\n{\n  \"settings\": { \"number_of_shards\": 1, \"number_of_replicas\": 1 },\n  \"mappings\": {\n    \"properties\": {\n      \"title\": { \"type\": \"text\" },\n      \"created_at\": { \"type\": \"date\" }\n    }\n  }\n}\n# To add fields later: PUT <index>/_mapping {\"properties\":{...}}","note":"インデックスの作成後、プライマリシャード数はその場で変更できない(レプリカ数は動的)。必要な場合は _split / _shrink API または _reindex で新しいインデックスを作成する。既存のフィールドの型は変更できないが、新しいフィールドは追加できる。","danger":"caution"},"show-ddl":{"command":"GET <index>","note":"1 回の呼び出しで settings、mappings、aliases を返す。この 3 つを合わせたものがインデックスの「DDL」に相当する。同じ出力を新しい PUT <index> の本文として再利用できる。","danger":"safe"},"replication-status":{"command":"GET _cluster/health\n# For ongoing shard copy/recovery: GET _cat/recovery?v&active_only=true\n# For cross-cluster replication (CCR): GET <index>/_ccr/stats","note":"status はシャードの健全性を green/yellow/red で要約する。yellow = レプリカが未割り当て。active_shards_percent は完了率を示す。","danger":"safe"},"list-replicas":{"command":"GET _cat/shards?v&h=index,shard,prirep,state,node\n# For node roles: GET _cat/nodes?v","note":"prirep 列は p(プライマリ)または r(レプリカ)の値をとる。シャードがノード間にどう分散しているかと、その状態(STARTED/RELOCATING)を示す。","danger":"safe"},"promote-failover":{"command":"# Master election is automatic; no manual promote is needed.\n# To convert a CCR follower into an independent (writable) index:\nPOST <index>/_ccr/pause_follow\nPOST <index>/_close\nPOST <index>/_ccr/unfollow\nPOST <index>/_open","note":"ノード障害時、Elasticsearch は自動的にマスターを再選出し、プライマリシャードを再割り当てする。手動の引き継ぎが必要なのは、CCR のフォロワーインデックスをリーダーから切り離して書き込み可能にする場合のみ。","danger":"danger"},"open-transactions":{"command":"# Not applicable: Elasticsearch has no multi-document transactions (BEGIN/COMMIT).\n# Operations are atomic at the document level; the closest diagnosis is running tasks:\nGET _tasks?detailed=true","note":"単一ドキュメントへの書き込みはアトミックでバージョン管理される(楽観的同時実行制御: if_seq_no / if_primary_term)。オープン中のトランザクションを追跡する概念はない。","danger":"safe"},"connect-cli":{"command":"curl -u user:password -k https://host:9200\n# Kibana Dev Tools console (recommended): Kibana > Management > Dev Tools\n# With an API key: curl -H \"Authorization: ApiKey <base64key>\" https://host:9200","note":"REST ベースであり、独立した CLI クライアントの代わりに curl または Kibana Dev Tools を使用する。-k は自己署名の TLS 証明書の検証を省略する(本番環境では CA を使用する)。","danger":"safe"},"list-databases":{"command":"GET _cat/indices?v\n# For aliases (logical views): GET _aliases","note":"Elasticsearch には独立した「データベース」層がない。最も近い概念はインデックスと、それらをまとめるエイリアス。データストリームの場合: GET _data_stream。","danger":"safe"},"switch-database":{"command":"# Not applicable: the target index is specified directly in the request path; there is no session context to change.\nGET <index>/_search\n# In Kibana, a data view (index pattern) is selected as the default view","note":"USE <db> 形式のコマンドはなく、ターゲットのインデックス/エイリアスはすべてのリクエストのパスで指定する。複数のインデックスを検索するにはカンマで区切る: GET log-2024,log-2025/_search。","danger":"safe"}}},"errors/oracle.json":{"engineId":"oracle","engine":"Oracle","order":1,"errors":[{"code":"ORA-00001","title":"Unique constraint violated（一意制約違反）","severity":"caution","meaning":"挿入または更新される行が UNIQUE 制約または PRIMARY KEY 制約に違反している。つまり同じ値がすでに存在する。","cause":"同じキー値の行の再挿入、一意であるべき列への重複データの入力、またはレプリケーション/再実行時に同じレコードを 2 回処理すること。","fix":"エラーメッセージの制約名から違反した列を特定する: SELECT column_name FROM all_cons_columns WHERE constraint_name = 'CONSTRAINT_NAME'。重複データの検出には GROUP BY ... HAVING COUNT(*) > 1 を使う。アプリケーションでは既存レコードに対して INSERT ではなく UPDATE または MERGE を使う。シーケンス の値が遅れている場合は ALTER SEQUENCE で進める。","tags":["unique","uniqueness","constraint","unique constraint","primary key","duplicate","duplicate key","insert"]},{"code":"ORA-00054","title":"Resource busy and acquire with NOWAIT specified or timeout expired（リソースがビジー。NOWAIT 指定またはタイムアウト）","severity":"caution","meaning":"ロック対象のリソース (行またはテーブル) が別セッションにロックされており、NOWAIT が指定されていたか DDL_LOCK_TIMEOUT が経過したため、即座に取得できなかった。","cause":"通常は、テーブルが別トランザクションにロックされている間に DDL (ALTER TABLE、DROP、CREATE INDEX) を試行した場合。または SELECT ... FOR UPDATE NOWAIT でロック中の行に遭遇した場合。","fix":"ロックを保持しているセッションを特定する: SELECT * FROM v$locked_object。v$session と v$lock を結合してブロッキングセッションを特定する。トランザクションの終了を待つか、必要に応じて ALTER SYSTEM KILL SESSION で終了させる。DDL では待機時間を設定できる: ALTER SESSION SET DDL_LOCK_TIMEOUT = 60; DDL は負荷の低いメンテナンス時間帯に実行する。","tags":["lock","locked","ddl","nowait","busy","resource busy","timeout"]},{"code":"ORA-00060","title":"Deadlock detected while waiting for resource（リソース待機中にデッドロックを検出）","severity":"danger","meaning":"2 つ以上のセッションが互いに相手の保持するリソースを待ち、デッドロック状態になっている。Oracle はこの循環を検出して犠牲者を選び、そのセッションの文をロールバックする。","cause":"異なる順序で取得された行ロック、異なるトランザクションによる同じ行の交差更新、インデックスのない外部キーに起因する親テーブル更新時のテーブルロック、またはビットマップインデックスへの同時 DML。","fix":"アラートログに記録されたデッドロックトレース (グラフ) ファイルを調べ、競合している SQL 文と行を特定する。アプリケーションでは常に同じ順序でテーブル/行にアクセスする。外部キー列にインデックスを作成する (インデックスのない FK は典型的なデッドロック原因)。トランザクションを短く保ち、コミット頻度を見直す。デッドロックになったトランザクションをアプリケーションで捕捉して再試行する。","tags":["deadlock","deadlock detected","lock","locking","tx","transaction"]},{"code":"ORA-01017","title":"Invalid username/password; logon denied（ユーザー名/パスワードが無効。ログオン拒否）","severity":"caution","meaning":"データベース接続時に指定したユーザー名またはパスワードが誤っているため、ログオンが拒否された。","cause":"パスワードの誤り、ユーザー名の誤り、大文字小文字を区別するパスワード設定 (SEC_CASE_SENSITIVE_LOGON) が想定と異なる、パスワードの変更、またはアプリケーションの接続文字列に古い資格情報が残っている。","fix":"ユーザー名とパスワードを確認する。必要なら DBA としてパスワードをリセットする: ALTER USER app_user IDENTIFIED BY new_password。ユーザーが存在しロックされていないことを確認する: SELECT username, account_status FROM dba_users。12c 以降のパスワードハッシュバージョンでは 11g クライアントが接続できない場合がある。SQLNET.ALLOWED_LOGON_VERSION_SERVER の設定を見直す。","tags":["auth","credentials","password","password","logon","login","privilege"]},{"code":"ORA-01555","title":"Snapshot too old: rollback segment number too small（スナップショットが古すぎる）","severity":"danger","meaning":"長時間実行中のクエリが、開始時点の読み取り一貫性イメージを構築するのに必要な古い undo データにアクセスできなかった。その undo 情報が上書きされたため。","cause":"小さい undo 表領域、短い UNDO_RETENTION、非常に高負荷な同時 DML 中の長時間クエリ、またはクエリ内で同じテーブルに対してコミットするループ (fetch across commit)。","fix":"UNDO_RETENTION を増やし、undo 表領域を拡大する。可能なら自動管理 (AUTOEXTEND on) に任せる。長いクエリを小さく分割するか、オフピークに実行する。RETENTION GUARANTEE を検討する: ALTER TABLESPACE undotbs1 RETENTION GUARANTEE。ループ内でコミットするアプリケーションロジックを修正する。","tags":["undo","snapshot","rollback","read consistency","consistency","long query"]},{"code":"ORA-01652","title":"Unable to extend temp segment by N in tablespace（表領域で一時セグメントを拡張できない）","severity":"danger","meaning":"一時 (temp) セグメントを拡張するための十分な空き領域が表領域内に見つからなかった。通常はソート、ハッシュ結合、グローバル一時表の操作中に発生する。","cause":"TEMP 表領域が満杯。大きな ORDER BY、GROUP BY、DISTINCT、ハッシュ結合、インデックス作成が PGA メモリに収まらずディスクに溢れる。データファイルの AUTOEXTEND が off、またはディスク容量の枯渇。","fix":"TEMP 使用量を監視する: SELECT * FROM v$sort_usage / v$tempseg_usage。TEMP 表領域にファイルを追加するか拡大する: ALTER TABLESPACE temp ADD TEMPFILE '...' SIZE 2G AUTOEXTEND ON。永続表領域が満杯ならデータファイルを追加する。クエリの最適化 (適切なインデックス、より大きな PGA_AGGREGATE_TARGET) でディスクソートを減らす。","tags":["temp","tablespace","free space","space","sort","sorting","extend"]},{"code":"ORA-04031","title":"Unable to allocate N bytes of shared memory（共有メモリを割り当てられない）","severity":"danger","meaning":"共有メモリプール (通常は shared pool または large pool) に、要求サイズの連続メモリを割り当てられなかった。SGA コンポーネントがメモリ不足の状態にある。","cause":"バインド変数を使わない (リテラルだらけの) 一意な SQL 文の多発による shared pool の断片化、不十分な SHARED_POOL_SIZE、過剰な同時接続、大きな PL/SQL パッケージ、または ASMM/AMM のサイズ設定の誤り。","fix":"エラーメッセージがどのプール (shared pool、large pool など) を示しているか確認する。短期対応: ALTER SYSTEM FLUSH SHARED_POOL (注意: 本番ではすべての SQL の再解析、つまり一時的なハードパースの嵐を招き、断片化を恒久的には解消しない)。恒久対応: バインド変数の使用を徹底する (CURSOR_SHARING を含む)。SGA_TARGET / SHARED_POOL_SIZE / LARGE_POOL_SIZE を増やす。頻繁に使うパッケージは DBMS_SHARED_POOL.KEEP でメモリに固定する。メモリ配分は V$SGASTAT で調べる。","tags":["memory","shared memory","shared pool","sga","ora-4031","bind"]},{"code":"ORA-12154","title":"TNS: could not resolve the connect identifier specified（接続識別子を解決できない）","severity":"caution","meaning":"接続に使われたサービス名 (接続識別子 / TNS 別名) を解決できなかった。Oracle Net は指定された名前をサーバー/サービス情報に対応付けられない。","cause":"tnsnames.ora に別名がない、TNS_ADMIN 環境変数が誤ったディレクトリを指している、別名のつづりの誤り、EZConnect/LDAP のネーミング設定の欠如、または sqlnet.ora の NAMES.DIRECTORY_PATH の順序の誤り。","fix":"使用する別名が tnsnames.ora に定義されていることを確認する。接続をテストする: tnsping service_name。TNS_ADMIN が正しいフォルダを指していることを確認する。代わりに EZConnect を試す: app_user/password@host:1521/service_name。sqlnet.ora の NAMES.DIRECTORY_PATH = (TNSNAMES, EZCONNECT) 行を確認する。","tags":["tns","connect","connection","network","networking","tnsnames","service"]},{"code":"ORA-12514","title":"TNS: listener does not currently know of service requested in connect descriptor（リスナーが要求されたサービスを認識していない）","severity":"caution","meaning":"リスナーは稼働しているが、要求されたサービス名を認識していない。つまりサービスがリスナーに登録されていない。","cause":"データベースインスタンスが完全にオープンしていない、サービスがまだリスナーに登録されていない (12c 以降は LREG、11g 以前は PMON 登録の遅延)、誤った SERVICE_NAME の使用、または SID とサービス名の混同。","fix":"リスナーが認識しているサービスを表示する: lsnrctl status と lsnrctl services。データベースが OPEN であることを確認する。サービス登録を起動する: SQL で ALTER SYSTEM REGISTER。LOCAL_LISTENER パラメータと SERVICE_NAME の正しい使用を確認する。プラガブルデータベースでは PDB が OPEN であることを確認する。","tags":["tns","listener","service","service_name","connection","network","networking"]},{"code":"ORA-00942","title":"Table or view does not exist（表またはビューが存在しない）","severity":"caution","meaning":"クエリで参照されたテーブルまたはビューが存在しないか、アクセスするユーザーから見えない。","cause":"オブジェクトが実際に存在しない、別スキーマにあるのにスキーマ接頭辞を付けていない、ユーザーにオブジェクトへの権限 (SELECT など) がない、シノニムがない、またはオブジェクト名のつづりの誤り。","fix":"オブジェクトの存在と所有者を確認する: SELECT owner, object_type FROM all_objects WHERE object_name = 'TABLE_NAME'。別スキーマにある場合は schema.table と完全修飾するか、GRANT SELECT ON app_schema.my_table TO app_user で権限を付与する。必要ならパブリック/プライベートシノニムを作成する: CREATE SYNONYM my_table FOR app_schema.my_table。大文字小文字と引用符付き識別子に注意する。","tags":["table","missing table","view","missing view","grant","privilege","synonym","alias"]},{"code":"ORA-01031","title":"Insufficient privileges（権限不足）","severity":"caution","meaning":"実行しようとした操作に必要な権限 (システム権限またはオブジェクト権限) をユーザーが持っていない。","cause":"必要なシステム権限またはオブジェクト権限が付与されていない、権限がロール経由でしか与えられていない (定義者権限の PL/SQL ブロック内ではロールは無効)、SYSDBA/SYSOPER なしで管理操作を試行した、または定義者権限プロシージャに対する直接付与がない。","fix":"不足している権限を付与する。例: GRANT CREATE TABLE TO app_user または GRANT SELECT ON app_schema.my_table TO app_user。名前付き PL/SQL オブジェクトでは、権限はロール経由ではなく直接付与する必要がある点に注意する。SYSDBA が必要な操作では正しい資格情報で接続する。現在の権限を確認する: SELECT * FROM session_privs / user_sys_privs。","tags":["privilege","privileges","grant","permission","auth","role grant","role"]},{"code":"ORA-00257","title":"Archiver error. Connect internal only, until freed（アーカイバエラー）","severity":"danger","meaning":"アーカイバ (ARCH) プロセスが redo ログをアーカイブできない。通常はアーカイブ先 (FRA またはアーカイブログの出力先) が満杯。データベースは新しいトランザクションを停止する。","cause":"Flash Recovery Area (DB_RECOVERY_FILE_DEST) またはアーカイブログの出力先が満杯、ディスク容量の枯渇、RMAN バックアップがアーカイブログを削除していない、または DB_RECOVERY_FILE_DEST_SIZE の上限に到達。","fix":"領域を解放する: 古いアーカイブログを RMAN で FRA 以外の場所にバックアップして削除する: RMAN> BACKUP ARCHIVELOG ALL FORMAT '/backup/arc_%U' DELETE INPUT (FRA が満杯の間に FRA へバックアップを書き込むと失敗する)。Data Guard 環境では、スタンバイにまだ転送または適用されていないアーカイブを削除しない。削除するとスタンバイにギャップが生じる (CONFIGURE ARCHIVELOG DELETION POLICY TO APPLIED ON ALL STANDBY)。FRA の使用状況を表示する: SELECT * FROM v$recovery_file_dest / v$flash_recovery_area_usage。一時的に DB_RECOVERY_FILE_DEST_SIZE を増やすか、出力先をより大きなディスクに移す。ディスクレベルの空き容量を確認する。定期的なアーカイブ削除ポリシーを確立する。","tags":["archive","archivelog","archiver","fra","disk","space","redo"]},{"code":"ORA-01000","title":"Maximum open cursors exceeded（オープンカーソルの最大数を超過）","severity":"caution","meaning":"セッションが OPEN_CURSORS パラメータで許可された数を超えるカーソルをオープンした。新しいカーソルはオープンできない。","cause":"アプリケーションがオープンした Statement/ResultSet オブジェクトをクローズしていない (カーソルリーク)、OPEN_CURSORS がワークロードに対して低すぎる、またはループ内で新しいプリペアドステートメントを次々に準備してクローズしていない。","fix":"オープンカーソルを監視する: SELECT * FROM v$open_cursor WHERE sid = ...  さらに v$sesstat でセッションごとの数を確認する。本当の解決策は、アプリケーションですべての Statement/ResultSet を finally ブロックでクローズすること (カーソルリークの解消)。回避策として OPEN_CURSORS を増やす: ALTER SYSTEM SET OPEN_CURSORS = 1000。JDBC のステートメントキャッシュサイズを見直す。","tags":["cursor","open cursor","open_cursors","leak","cursor leak","jdbc"]},{"code":"ORA-00018","title":"Maximum number of sessions exceeded（セッションの最大数を超過）","severity":"danger","meaning":"データベースが SESSIONS パラメータで許可された最大セッション数に達した。新しいセッションをオープンできない。","cause":"SESSIONS/PROCESSES がワークロードの必要量より低い、過大な接続プール設定、接続リーク、またはクローズされないセッションの蓄積。","fix":"現在のセッション数を表示する: SELECT COUNT(*) FROM v$session。上限を確認する: SELECT * FROM v$resource_limit WHERE resource_name IN ('sessions','processes')。PROCESSES を増やし、間接的に SESSIONS も増やす (SPFILE 経由、再起動が必要): ALTER SYSTEM SET PROCESSES = 500 SCOPE=SPFILE。アプリケーションの接続プールサイズとリークを見直す。","tags":["session","session limit","sessions","processes","connection","connections","limit"]},{"code":"ORA-28000","title":"The account is locked（アカウントがロックされている）","severity":"caution","meaning":"接続先のデータベースユーザーアカウントがロックされているため、ログオンに失敗する。","cause":"プロファイルの FAILED_LOGIN_ATTEMPTS 上限を超えた (パスワードの誤りの繰り返し)、または DBA が手動でアカウントをロックした (ALTER USER ... ACCOUNT LOCK)。ログイン失敗によるロックは PASSWORD_LOCK_TIME 経過後に自動で解除される。注: PASSWORD_LIFE_TIME の期限切れではアカウントはロックされず、EXPIRED / EXPIRED(GRACE) に移行し ORA-28001/ORA-28002 を返す。","fix":"アカウントの状態を確認する: SELECT username, account_status, lock_date FROM dba_users WHERE username = 'APP_USER'。ロックを解除する: ALTER USER app_user ACCOUNT UNLOCK。再発防止のため、ログイン失敗の発生源を特定し、必要ならプロファイルの FAILED_LOGIN_ATTEMPTS を見直す。パスワードが期限切れなら新しいパスワードを設定する。","tags":["account","user account","locked","account locked","auth","password","profile"]},{"code":"ORA-01578","title":"Oracle data block corrupted (file #, block #)（Oracle データブロックの破損）","severity":"danger","meaning":"指定されたデータファイル内のデータブロックが破損している。Oracle はブロックが整合性チェック (チェックサム) に失敗したことを報告している。これは物理破損である。","cause":"ディスク/ハードウェア障害、ストレージ層のエラー、オペレーティングシステムまたはコントローラの問題、停電後の部分書き込みブロック、または破損したバックアップ/リストア。","fix":"破損とその範囲を確認する: RMAN> VALIDATE DATABASE / VALIDATE CHECK LOGICAL DATAFILE n。DBVERIFY (dbv) も実行し、v$database_block_corruption を確認する。バックアップがあればブロックレベルでリカバリする: RMAN> RECOVER DATAFILE n BLOCK m; または一覧のすべてのブロックに対して RMAN> RECOVER CORRUPTION LIST; (旧来の BLOCKRECOVER コマンドは 11g 以降非推奨)。インデックスブロックであればインデックスを再構築する。必ずハードウェア/ディスクの健全性を確認する。根本原因は通常ストレージにある。","tags":["corruption","block corruption","block","corrupt block","datafile","rman","disk"]},{"code":"ORA-01722","title":"Invalid number（数値が無効）","severity":"safe","meaning":"数値コンテキストが必要な箇所で、数値に変換できない文字列が使われた。暗黙的または明示的な変換が失敗した。","cause":"数値列と文字列の比較 (例: WHERE num_col = 'ABC')、数値フィールドへの英字を含む値の挿入、TO_NUMBER に不適切な書式、または小数点/桁区切り文字の不一致 (カンマとピリオド)。","fix":"変換に失敗した式を特定する。通常は WHERE 条件か INSERT の値。文字列/数値の比較では型の互換性を確保し、必要に応じて明示的な変換を使う: TO_NUMBER(my_column)、文字列側には TO_CHAR。アプリケーション層で数値列への非数値入力を防ぐ。NLS_NUMERIC_CHARACTERS の設定に注意する。","tags":["number","numeric","conversion","type conversion","to_number","datatype","data type"]},{"code":"ORA-02049","title":"Timeout: distributed transaction waiting for lock（分散トランザクションのロック待機タイムアウト）","severity":"danger","meaning":"分散トランザクションがリモートデータベース上のロックを待つ間に DISTRIBUTED_LOCK_TIMEOUT を超過した。トランザクションはタイムアウトした。","cause":"データベースリンク経由で実行中のトランザクションがリモート側のロック中の行を待っている。リモートセッションの長いトランザクション、ネットワーク遅延、または両端で保持される競合ロック。","fix":"リモートデータベース上のブロッキングロックとセッションを特定して解消する (v$lock、v$session)。分散トランザクションは短く保ち、必要なロックはできるだけ遅く取得する。必要ならワークロードに応じて DISTRIBUTED_LOCK_TIMEOUT を増やす (SPFILE、再起動が必要)。インダウト分散トランザクションは DBA_2PC_PENDING ビューを調べ、必要なら手動で解決する。","tags":["distributed","distributed transaction","dblink","lock","lock wait","timeout","2pc"]},{"code":"enq: TX - row lock contention","title":"待機: 別トランザクションが保持する行レベルロックでセッションがブロックされている","severity":"caution","meaning":"セッションが、別トランザクションの保持する行ロックの解放を待っている。アプリケーションレベルの典型的なロック待機イベント。","cause":"同じ行を更新しようとする同時トランザクション、長時間コミットされないトランザクション、インデックスのない外部キーによる広範なロック、または連番キーへの集中 (ホットブロック)。","fix":"ブロッキングセッションとブロックされているセッションを特定する: SELECT * FROM v$session WHERE blocking_session IS NOT NULL; さらに v$lock と突き合わせる。長いトランザクションが根本原因ならコミット戦略を見直す。外部キー列にインデックスを作成する。ホット行は設計 (順序、ハッシュ) を再検討する。必要に応じてブロッキングセッションを終了させる。","tags":["wait","wait event","enq","row lock","row lock wait","tx","contention","lock"]},{"code":"log file sync","title":"待機: コミット時に LGWR が redo をディスクにフラッシュするのをセッションが待っている","severity":"caution","meaning":"セッションが COMMIT すると、LGWR が redo レコードを redo ログファイルに書き込む (フラッシュする) のを待つ。この待機が多い場合はコミット遅延が発生している。","cause":"遅い redo ログディスク (高い I/O 遅延)、コミット頻度が高すぎるアプリケーション (行ごとのコミット)、LGWR プロセスの CPU 圧迫、または非常に多い redo 量。","fix":"AWR/Statspack で平均待機時間を測定する。redo ログファイルを高速・低遅延のディスク (SSD) に移す。アプリケーションの不要なコミット頻度を減らし、バッチ処理をまとめる。必要なら COMMIT_LOGGING/COMMIT_WAIT (commit_write) オプションを業務要件と照らして評価する。警告: NOWAIT/BATCH は耐久性を下げ、コミット済みに見えるトランザクションがクラッシュ時に失われる可能性がある。損失が許容される処理に限り、セッションまたは文レベルでのみ使用し、システム全体では有効にしない。LGWR とストレージの遅延を併せて調べる。","tags":["wait","wait event","log file sync","commit","lgwr","redo","latency"]},{"code":"db file sequential read","title":"待機: 単一ブロックの物理読み取り。通常はインデックスまたはテーブルの参照","severity":"caution","meaning":"セッションがディスクから単一ブロックが読み取られるのを待っている。通常はインデックスアクセスや ROWID による単一ブロック読み取りで見られ、通常は想定内のイベント。","cause":"バッファキャッシュにないブロックのディスクからの読み取り、選択性の低いインデックスまたは誤ったインデックスの使用、不十分なバッファキャッシュ、または遅いストレージ層。","fix":"多い場合は、最も多く読み取っている SQL 文を特定する (AWR Top SQL、v$sql)。適切なインデックスと正しいアクセスパスでクエリを改善し、不要なネステッドループを減らす。バッファキャッシュサイズ (DB_CACHE_SIZE) を評価する。ストレージの I/O 遅延を確認する。このイベントは多くの場合正常であり、異常に多い場合は SQL チューニングに注力する。","tags":["wait","wait event","db file sequential read","io","disk io","index","index access","single block"]},{"code":"db file scattered read","title":"待機: マルチブロックの物理読み取り。通常は全表スキャンまたはインデックス高速全スキャン","severity":"caution","meaning":"セッションがディスクから複数ブロック (マルチブロック) が読み取られるのを待っている。通常は全表スキャンまたはインデックス高速全スキャン中に発生する。","cause":"適切なインデックスがないことによる全表スキャン、古い統計による誤った実行計画、非常に大きなテーブルのスキャン、または選択されたアクセスパスがテーブルスキャンにフォールバックしている。","fix":"全スキャンを行っている SQL 文を特定し、必要なインデックスを追加するか既存のインデックスが使われるようにする。統計を更新する: DBMS_STATS.GATHER_TABLE_STATS。大規模なスキャンが本当に必要ならパラレルクエリまたはパーティション化を検討する。DB_FILE_MULTIBLOCK_READ_COUNT とストレージのスループットを見直す。","tags":["wait","wait event","db file scattered read","full scan","full table scan","io","disk io","multiblock"]},{"code":"buffer busy waits","title":"待機: 別セッションが読み取り中または変更中のバッファをめぐる競合","severity":"caution","meaning":"セッションが、別セッションが同時に読み取りまたは変更しているバッファブロックへのアクセスを待っている。これはメモリ上のブロック競合である。","cause":"ホットブロックへの集中、単調増加キーを持つインデックスの右端での競合、不十分な freelist/非 ASSM セグメント、または同じブロックへの大量の同時 DML。","fix":"影響を受けているセグメントとブロッククラスを特定する (v$session、v$segment_statistics、ASH)。ホットなインデックスブロックには逆キーインデックスまたはハッシュパーティションインデックスを検討する。ASSM (Automatic Segment Space Management) を使う。高い同時実行下では INITRANS/PCTFREE を増やす。アプリケーションのアクセスパターンを分散させる。","tags":["wait","wait event","buffer busy","hot block","hot blocks","contention","block contention"]},{"code":"gc buffer busy","title":"待機 (RAC): インスタンス間で転送中のキャッシュフュージョンブロックをめぐる競合","severity":"caution","meaning":"RAC 環境で、セッションが、キャッシュフュージョンにより他インスタンスとの間で転送中、またはそのインスタンスが使用中として保持しているグローバルブロックへのアクセスを待っている。","cause":"RAC ノード間で共有される同じホットブロック (インスタンス間ホットブロック)、インターコネクトの遅延/ボトルネック、連番キーを持つインデックスでのノード間競合、または偏ったワークロード分散。","fix":"v$segment_statistics と GV$ ビューで影響を受けているセグメントを特定する。インターコネクトの健全性と遅延を確認する (専用の高速ネットワーク)。ホットなインデックスには逆キーまたはハッシュパーティション化を使う。サービス単位でワークロードをノードに分離し、同じブロックをめぐるノード間競合を減らす。","tags":["wait","wait event","rac","gc buffer busy","cache fusion","interconnect","global"]},{"code":"library cache lock","title":"待機: ライブラリキャッシュのオブジェクトハンドルをめぐる競合 (解析/DDL のシリアライズ)","severity":"caution","meaning":"セッションが、ライブラリキャッシュ内のオブジェクト (SQL、PL/SQL、テーブル定義) のロックを待っている。通常は解析処理と DDL 操作のシリアライズが原因。","cause":"頻繁に使われるオブジェクトへの DDL (ALTER/CREATE)、頻繁に再コンパイルされる PL/SQL オブジェクト (無効化)、過剰なハードパース、依存オブジェクトの無効化、または大量の同時接続ストーム。","fix":"ブロッキングセッションとオブジェクトを特定する (v$session、ASH、必要ならライブラリキャッシュロックの診断)。頻繁に使われるオブジェクトへの DDL をピーク時間帯に実行しない。依存関係の連鎖を減らし、不要な再コンパイルを防ぐ。バインド変数を使ってハードパースを減らす。接続プールで接続ストームを平準化する。","tags":["wait","wait event","library cache lock","parse","parsing","ddl","hard parse"]}]},"errors/postgres.json":{"engineId":"postgres","engine":"PostgreSQL","order":2,"errors":[{"code":"23505","title":"unique_violation","severity":"caution","meaning":"挿入または更新された行が UNIQUE 制約または PRIMARY KEY に違反している。同じ値がすでにテーブルに存在する。","cause":"同じ一意キーでの再挿入、一意列への重複データの入力、手動挿入によるシーケンス 値の遅れ、または 2 つの同時リクエストによる同じキーの挿入。","fix":"エラー詳細の制約名とキー値から、どの行が競合しているかがわかる。既存行を更新するには INSERT ... ON CONFLICT (my_column) DO UPDATE または DO NOTHING を使う。重複の検出: SELECT my_column, COUNT(*) FROM my_table GROUP BY my_column HAVING COUNT(*) > 1。シーケンス が遅れている場合: SELECT setval('seq_name', (SELECT MAX(id) FROM my_table))。","tags":["unique","unique","constraint","constraint","duplicate","duplicate","23505","primary key"]},{"code":"23503","title":"foreign_key_violation","severity":"caution","meaning":"FOREIGN KEY 制約に違反した。挿入/更新された行が参照する親行が存在しないか、削除しようとした親行にまだ依存する子行がある。","cause":"存在しない親キーを参照する INSERT/UPDATE、まだ参照されている親行の削除/更新の試行、または誤った順序でのデータロード (子が先、親が後)。","fix":"先に親行を挿入し、次に子行を挿入する。削除時にカスケード動作が必要なら、制約を ON DELETE CASCADE または ON DELETE SET NULL で定義する。一括ロードでは親子の順序でデータをロードする。参照している行を特定する: SELECT * FROM child WHERE fk_column = value。","tags":["foreign key","foreign key","fk","constraint","constraint","reference","23503"]},{"code":"23502","title":"not_null_violation","severity":"caution","meaning":"NOT NULL 制約のある列に NULL を挿入しようとした、またはその列を NULL に設定しようとした。","cause":"必須列を INSERT から省略した、明示的に NULL を代入した、列に DEFAULT がない、またはアプリケーションから空/欠落した値が渡された。","fix":"列に有効な値を指定するか、適切な DEFAULT を定義する: ALTER TABLE my_table ALTER COLUMN my_column SET DEFAULT value。列が本当に必須である必要がなければ制約を削除する: ALTER TABLE my_table ALTER COLUMN my_column DROP NOT NULL。アプリケーション層に欠落データの検証を追加する。","tags":["not null","null","constraint","constraint","required","23502","insert"]},{"code":"40P01","title":"deadlock_detected","severity":"danger","meaning":"2 つ以上のトランザクションが互いに相手の保持するロックを待ち、デッドロックに陥った。PostgreSQL はこの循環を検出し、いずれかのトランザクションを取り消す。","cause":"異なる順序でのロック取得、同じ行の交差更新、長いトランザクション、または外部キーチェック中に取得される競合ロック。","fix":"サーバーログのデッドロック詳細に競合したクエリが示される。すべてのトランザクションで同じ順序でテーブル/行にアクセスする。トランザクションを短く保つ。取り消されたトランザクションをアプリケーションで捕捉して再試行する。pg_locks と pg_stat_activity を結合してロックを調べる。必要なら SELECT ... FOR UPDATE でロック順序を明示する。","tags":["deadlock","deadlock","lock","lock","40P01","tx","transaction"]},{"code":"40001","title":"serialization_failure","severity":"caution","meaning":"SERIALIZABLE または REPEATABLE READ 分離レベルで、同時実行された変更と競合したためトランザクションをシリアライズできず、取り消された。これはデータ一貫性を守るための想定どおりの動作である。","cause":"同じデータに同時アクセスするトランザクションをシリアライズ可能な順序に並べられない、高い同時実行下での書き込み競合、または SSI (Serializable Snapshot Isolation) が検出した危険な依存関係。","fix":"これはバグではなく想定どおりのシグナルである: トランザクションをそのまま再試行する。アプリケーションに自動再試行ロジックを追加する。競合を減らすにはトランザクションを短くし、本当に必要でなければより低い分離レベル (READ COMMITTED) を使う。ホット行での競合が減るように設計する。","tags":["serialization","serialization","isolation","isolation","retry","retry","40001","mvcc"]},{"code":"53300","title":"too_many_connections","severity":"danger","meaning":"サーバーが max_connections で許可された最大同時接続数に達した。新しい接続を受け付けられない。","cause":"接続プールがない、またはサイズが不適切、接続リーク、短命な接続を多数オープンするアプリケーション、または max_connections がワークロードより低い。","fix":"接続元を特定する: SELECT usename, state, COUNT(*) FROM pg_stat_activity GROUP BY 1,2。長時間アイドルのクライアント接続は対象を絞って終了させる (絞り込まずに一括終了するとすべてのアプリケーションとプールに影響する): SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'idle' AND backend_type = 'client backend' AND usename = 'app_user' AND state_change < now() - interval '10 minutes' AND pid <> pg_backend_pid()。本当の解決策は PgBouncer などの接続プール。max_connections を増やすとメモリを消費するため、プーリングを優先する。スーパーユーザー用に予約された接続により管理アクセスは確保される。","tags":["connection","connection","max_connections","too many","53300","pool","pool","pgbouncer"]},{"code":"53100","title":"disk_full","severity":"danger","meaning":"ディスクが満杯のため、サーバーがファイルに書き込めなかった。データディレクトリ、WAL、または一時ファイルを置くディスクに空き容量がない。","cause":"データの増加、制御されない WAL の蓄積 (アーカイブまたはレプリケーションスロットの遅れ)、大きな一時ファイル (巨大なソート)、肥大化したログファイル、またはテーブル/インデックスの肥大化 (bloat)。","fix":"ディスク使用量を調べ、不要なファイルを削除する。WAL の蓄積を確認する: pg_stat_replication と pg_replication_slots (未使用のスロットは削除する。遅れているスロットは WAL を保持し続ける)。ディスクが満杯の間は VACUUM FULL や REINDEX を実行しない: テーブルを書き直すため、テーブルサイズと同等の追加領域が必要となり、状況を悪化させうる。通常の VACUUM も領域をオペレーティングシステムに (ほぼ) 返さない。pg_wal ディレクトリ内のファイルを手動で削除することは絶対にしない。まず WAL/スロット、ログ、一時ファイルの発生源を解消して領域を確保し、ログと一時ファイルの配置を見直す。恒久対応としてディスク容量を増やし、監視/アラートを設定する。","tags":["disk","space","space","full","full","wal","53100","vacuum"]},{"code":"57014","title":"query_canceled","severity":"safe","meaning":"クエリが取り消された。通常は statement_timeout の経過、またはユーザーやクライアントからのキャンセル (pg_cancel_backend、ドライバのキャンセル) が原因。","cause":"statement_timeout の超過、pg_cancel_backend によるキャンセル、またはアプリケーション/クライアントから送られたキャンセル要求。類似の状況には別のコードがある: lock_timeout の経過は 55P03、idle_in_transaction_session_timeout は 25P03 (FATAL)、ホットスタンバイでのレプリケーション競合によるキャンセルは 40001 (場合により 40P01) を返す。","fix":"クエリが本当に長時間かかる場合はチューニングする (EXPLAIN ANALYZE、インデックス、実行計画)。タイムアウトが低すぎる場合は、該当セッション/ロールの statement_timeout を調整する。意図的なキャンセルには対応不要。ロックやスタンバイ競合によるキャンセルは 55P03 と 40001 の項目を参照する。","tags":["cancel","cancel","timeout","timeout","statement_timeout","57014","standby"]},{"code":"42P01","title":"undefined_table","severity":"caution","meaning":"クエリで参照されたテーブル (またはビュー) が存在しないか、search_path 内に見つからない。","cause":"テーブルが実際に存在しない、search_path に含まれない別スキーマにある、テーブル名の誤字/大文字小文字の誤り、引用符付き識別子での大文字小文字の不一致、またはオブジェクトが未作成か削除済み。","fix":"テーブルの存在とスキーマを確認する: SELECT schemaname, tablename FROM pg_tables WHERE tablename = 'my_table'。別スキーマにある場合は schema.table と修飾するか、search_path を設定する: SET search_path TO app_schema, public。引用符なしの識別子は小文字に変換される点に注意する。作成時に引用符を使った場合は同じ方法で参照する。","tags":["table","table","undefined","42P01","search_path","schema","schema"]},{"code":"42703","title":"undefined_column","severity":"caution","meaning":"クエリで参照された列がテーブル内または現在のスコープ内に存在しない。","cause":"列名の誤字、列の削除/名前変更、誤ったテーブルの参照、引用符付き識別子での大文字小文字の不一致、または複数テーブルのクエリでの曖昧/誤った修飾。","fix":"列を一覧表示する: \\d my_table または SELECT column_name FROM information_schema.columns WHERE table_name = 'my_table'。名前とテーブルを修正し、JOIN では列を table.column と修飾する。作成時に引用符を使った場合は同じ大文字小文字で参照する。","tags":["column","column","undefined","42703","typo","typo","schema"]},{"code":"42501","title":"insufficient_privilege","severity":"caution","meaning":"ロールが、実行しようとしている操作に必要な権限を持っていない。","cause":"テーブル/スキーマ/データベースに対する必要な GRANT が付与されていない、スキーマに対する USAGE がない、オブジェクトが別のロールに属している、または行レベルセキュリティ (RLS) ポリシーがアクセスを阻止している。","fix":"不足している権限を付与する: GRANT SELECT, INSERT ON my_table TO app_role; スキーマには GRANT USAGE ON SCHEMA app_schema TO app_role。一括付与には GRANT ... ON ALL TABLES IN SCHEMA を、今後作成されるオブジェクトには ALTER DEFAULT PRIVILEGES を使う。現在の権限を表示する: \\dp my_table。RLS が有効な場合は該当ポリシーを見直す。","tags":["privilege","privilege","permission","grant","42501","permission","rls"]},{"code":"28P01","title":"invalid_password","severity":"caution","meaning":"認証時に指定されたパスワードが誤っている。ロールのログインが拒否された。","cause":"パスワードの誤り、パスワードの変更、アプリケーションの接続文字列に残った古い資格情報、または pg_hba.conf で想定される認証方式 (scram-sha-256、md5) との不一致。","fix":"パスワードを確認し、必要ならリセットする: ALTER ROLE app_role WITH PASSWORD 'new_password'。pg_hba.conf の方式がクライアントと互換であることを確認する (古いクライアントは scram-sha-256 で問題が出ることがある)。変更後は SELECT pg_reload_conf() で設定を再読み込みする。","tags":["auth","identity","password","password","28P01","scram","md5","hba"]},{"code":"08006","title":"connection_failure","severity":"danger","meaning":"クライアントとサーバー間の接続を確立できなかった、または予期せず切断された。","cause":"サーバーが稼働していないか再起動中、ネットワーク/ファイアウォールの問題、誤ったホスト/ポート、アクセスを妨げる listen_addresses の設定、ネットワークにより切断されたアイドル接続、または過負荷のサーバー。","fix":"サーバーが起動しており、正しいホスト/ポートで待ち受けていることを確認する (pg_isready host port)。postgresql.conf の listen_addresses と pg_hba.conf のアクセスルールを確認する。ネットワーク/ファイアウォールと DNS の設定を確認する。接続プールの TCP keepalive とタイムアウト設定を見直す。サーバーログでクラッシュ/再起動の痕跡を探す。","tags":["connection","connection","network","network","08006","failure","disconnect"]},{"code":"55P03","title":"lock_not_available","severity":"caution","meaning":"要求したロックを即座に取得できなかった。通常は、他者が保持しているロックを NOWAIT で要求した場合、または lock_timeout が経過した場合に発生する。","cause":"SELECT ... FOR UPDATE NOWAIT または LOCK TABLE ... NOWAIT の使用時に行/テーブルがロックされていた、または lock_timeout の経過。ほとんどの場合、長いトランザクションがロックを保持している。","fix":"ブロッキングセッションを特定する: pg_locks と pg_stat_activity を結合する (待機/ブロックの関係)。長いトランザクションを終わらせるか、必要なら pg_terminate_backend(pid) で終了させる。NOWAIT の代わりに妥当な lock_timeout で待機し、再試行ロジックを追加する。トランザクションを短くしてロック保持時間を減らす。","tags":["lock","lock","nowait","lock_timeout","55P03","not available","busy"]},{"code":"54000","title":"program_limit_exceeded","severity":"caution","meaning":"PostgreSQL の実装/形式上の上限を超えた。例: 行またはフィールドの最大サイズ、インデックス行のサイズ、クエリ内のパラメータ/列の数の上限。","cause":"非常に大きな値の格納 (例: 1 GB を超えるフィールド)、B-tree ページの上限 (約 2704 バイト) を超えるインデックス値、または過剰な列数やクエリパラメータ数。","fix":"超過した上限を特定する (通常はメッセージに示される)。非常に大きなテキスト/データは構造を見直すか分割する。長いテキスト列には B-tree ではなくハッシュインデックスまたは式/部分インデックスを使う。クエリのパラメータ/列の数を減らすか、バッチを分割する。","tags":["limit","limit","program_limit","54000","index size","size","row size"]},{"code":"22001","title":"string_data_right_truncation","severity":"caution","meaning":"テキスト長が対象列の定義長 (例: VARCHAR(n)) を超えるため値が切り詰められることになる。PostgreSQL はこれを拒否してエラーを発生させる。","cause":"VARCHAR(n)/CHAR(n) 列への n より長いテキストの挿入または更新、アプリケーションから想定より長いデータが渡された、または必要に対して列長が狭すぎる。","fix":"値を列に収まるよう短くするか、列長を増やす: ALTER TABLE my_table ALTER COLUMN my_column TYPE VARCHAR(500)。長さ無制限のテキストが必要なら TEXT 型を使う。アプリケーションで長さを検証する。意図的に切り詰めたい場合は LEFT(value, n) を明示的に適用する。","tags":["truncation","truncation","varchar","string","text","22001","length","length"]},{"code":"25P02","title":"in_failed_sql_transaction","severity":"caution","meaning":"トランザクション内ですでにエラーが発生しており、以降のコマンドは実行できない。トランザクションはアボート状態にあり、ROLLBACK のみ受け付けられる。","cause":"トランザクションブロック内の前の文が失敗した (例: 制約違反) にもかかわらず、同じトランザクションに新しいコマンドが送られ続けている。アプリケーションがエラーを捕捉せずにトランザクションを続行している。","fix":"トランザクションをロールバックする: ROLLBACK し、改めて開始する。ブロックのエラーを切り離して続行したい場合は SAVEPOINT を使い、ROLLBACK TO SAVEPOINT でその地点に戻る。アプリケーションでは各文のエラーを捕捉し、トランザクションを適切に管理する (コミット/ロールバックの判断を明示する)。","tags":["transaction","transaction","aborted","aborted","25P02","rollback","savepoint"]},{"code":"53200","title":"out_of_memory","severity":"danger","meaning":"サーバーが操作に必要なメモリを割り当てられなかった。バックエンドプロセスまたはサーバー全体がメモリ不足の状態にある。","cause":"work_mem/maintenance_work_mem が高すぎ、高い同時実行数で掛け合わされている、1 つのクエリ内のハッシュ/ソート操作が多すぎる、過剰な接続数、メモリリーク、またはオペレーティングシステムの OOM killer による圧迫。","fix":"サーバーログのメモリコンテキストと OOM killer の痕跡を確認する。クエリ数と同時実行数を考慮して work_mem を適切に設定する (ソート/ハッシュごとに個別に割り当てられる)。プーリングで接続数を制限する。オペレーティングシステムのメモリ/overcommit 設定を見直す。重いクエリを最適化してメモリ要件を下げる。","tags":["memory","memory","out of memory","53200","work_mem","oom"]}]},"errors/mysql.json":{"engineId":"mysql","engine":"MySQL","order":3,"errors":[{"code":"1045","title":"Access denied for user (using password: YES/NO)（ユーザーのアクセス拒否）","severity":"caution","meaning":"ユーザー名、パスワード、または接続元ホストの認証に失敗し、ログインが拒否された。","cause":"パスワードの誤り、接続元ホストからの権限がユーザーにない (user@host)、アカウントが存在しない、認証プラグインの不一致 (caching_sha2_password と mysql_native_password)、または接続文字列に残った古い資格情報。","fix":"ユーザーとホストの一致を確認する: SELECT user, host, plugin FROM mysql.user。正しいホストに対して権限を付与する (例: 'app_user'@'%')。パスワードをリセットする: ALTER USER 'app_user'@'host' IDENTIFIED BY 'new_password'; (ALTER USER/GRANT は即座に有効になる。FLUSH PRIVILEGES が必要なのは権限テーブルを DML で直接変更した場合のみ)。'using password: NO' と表示される場合、クライアントはパスワードをまったく送っていない。プラグインの不一致は認証プラグインを見直す: MySQL 8.4 では mysql_native_password プラグインはデフォルトで無効 (--mysql-native-password=ON の場合のみロード) であり、このプラグインを使う古いアカウントや古いクライアントは接続できない。ALTER USER ... IDENTIFIED WITH caching_sha2_password BY '...'; でアカウントを移行し、クライアントドライバを更新する。","tags":["auth","authentication","access denied","access","password","password","1045","privilege"]},{"code":"1062","title":"Duplicate entry for key（キーの重複エントリ）","severity":"caution","meaning":"挿入または更新された行が UNIQUE インデックスまたは PRIMARY KEY に違反している。同じキー値がすでに存在する。","cause":"同じ一意キーでの INSERT の繰り返し、重複データの入力、遅れている AUTO_INCREMENT カウンタ、または既存テーブルに一意インデックスを追加する際に存在する重複行。","fix":"エラーメッセージに競合したキー値とインデックス名が示される。既存行を更新するには INSERT ... ON DUPLICATE KEY UPDATE または INSERT IGNORE / REPLACE を検討する。重複を検出する: SELECT my_column, COUNT(*) FROM my_table GROUP BY my_column HAVING COUNT(*) > 1。一意インデックスを追加できない場合は、先に重複を解消する。","tags":["duplicate","duplicate entry","unique","unique key","1062","primary key","insert"]},{"code":"1213","title":"Deadlock found when trying to get lock; try restarting transaction（ロック取得時にデッドロックを検出）","severity":"danger","meaning":"InnoDB が、2 つ以上のトランザクションが互いのロックを待つデッドロックを検出し、いずれかのトランザクションをロールバックして循環を解消した。","cause":"異なる順序で取得された行ロック、同じ行の交差更新、インデックスの欠如による広い行範囲のロック (ギャップロック)、または外部キーチェック中の競合。","fix":"最新のデッドロック詳細を表示する: SHOW ENGINE INNODB STATUS (LATEST DETECTED DEADLOCK セクション)。すべてのトランザクションで同じ順序で行/テーブルにアクセスし、トランザクションを短く保つ。適切なインデックスを追加してロック範囲を狭める。ロールバックされたトランザクションをアプリケーションで捕捉して再試行する (再試行ロジック)。","tags":["deadlock","deadlock detected","lock","row lock","innodb","1213","tx","transaction"]},{"code":"1205","title":"Lock wait timeout exceeded; try restarting transaction（ロック待機タイムアウトを超過）","severity":"danger","meaning":"トランザクションが必要な行ロックを innodb_lock_wait_timeout 秒間待ったが取得できず、タイムアウトした。","cause":"別のトランザクションがコミットもロールバックもせずに長時間ロックを保持している。アイドル状態のオープントランザクション、長時間実行される一括更新、または競合するホット行。","fix":"ブロッキングトランザクションを特定する: performance_schema.data_lock_waits と data_locks を結合する (旧バージョンでは information_schema.innodb_lock_waits/innodb_trx)。ブロッキングトランザクションをコミット/ロールバックするか、必要なら KILL <trx_mysql_thread_id> で終了させる。トランザクションを短く保ち、アイドル状態で放置しない (autocommit/アプリケーションロジック)。必要なら innodb_lock_wait_timeout をワークロードに合わせて調整する。","tags":["lock","lock wait","timeout","timed out","innodb","1205","wait","waiting"]},{"code":"1040","title":"Too many connections（接続数が多すぎる）","severity":"danger","meaning":"サーバーが max_connections で許可された最大同時接続数に達した。新しい接続は拒否されている。","cause":"サイズが不適切な接続プール、接続リーク、多数の短命な接続、長時間スリープ状態 (Sleep) の接続、またはワークロードに対して低すぎる max_connections の値。","fix":"接続を調べる: SHOW PROCESSLIST または SELECT * FROM performance_schema.processlist。不要なスリープ中の接続を KILL で閉じる。max_connections を増やす: SET GLOBAL max_connections = 500 (永続化するには my.cnf)。根本的な解決策は接続プールを使い、wait_timeout でアイドル接続を閉じること。SUPER/CONNECTION_ADMIN 用に緊急管理接続が 1 つ追加で予約されている。","tags":["connection","connections","too many","max_connections","1040","pool","connection pool"]},{"code":"1064","title":"You have an error in your SQL syntax（SQL 構文エラー）","severity":"safe","meaning":"SQL 文に構文エラーがあり、サーバーが解析できなかった。メッセージにはエラー付近のテキストが示される。","cause":"誤字、カンマや括弧の欠落/余分、列/テーブル名として引用符なしで使われた予約語、MySQL のバージョンでサポートされない構文、または引用符/エスケープの誤り。","fix":"メッセージの 'near ...' 部分がエラーの開始位置を示す。その直前を確認する。予約語はバッククォートで囲む: `order`、`group`。括弧とカンマの対応を確認する。使用中のバージョンでサポートされる構文であることを確認する。動的 SQL を生成している場合は、最終的なクエリ全体をログに出力して確認する。","tags":["syntax","syntax error","1064","parse","parsing","reserved word","reserved keyword"]},{"code":"1146","title":"Table doesn't exist（テーブルが存在しない）","severity":"caution","meaning":"クエリで参照されたテーブルが存在しないか、現在のデータベース内に見つからない。","cause":"テーブルが実際に存在しない、誤ったデータベースが選択されている、テーブル名の誤字、Linux でのテーブル名の大文字小文字の区別 (lower_case_table_names)、または InnoDB テーブルファイル (.ibd) の欠落/破損 (5.7 以前では .frm 定義ファイルも。8.0 では定義はデータディクショナリに格納される)。","fix":"テーブルを確認する: SHOW TABLES; 正しいデータベースを選択する: USE mydb。大文字小文字の区別に注意する (特に Linux)。SELECT ... FROM information_schema.tables でテーブル名とスキーマを確認する。InnoDB ファイルに問題がある場合はリストア/修復が必要になることがある。","tags":["table","table missing","doesn't exist","not found","1146","schema","database"]},{"code":"1054","title":"Unknown column in field list（フィールドリストに不明な列）","severity":"caution","meaning":"クエリで参照された列がテーブル内または現在のスコープ内に存在しない。","cause":"列名の誤字、列の削除/名前変更、誤ったテーブルの参照、JOIN での曖昧/誤った修飾、または引用符なしで書かれた文字列値が列として解釈された (WHERE name = 'value' ではなく WHERE name = value)。","fix":"列を一覧表示する: SHOW COLUMNS FROM my_table または DESCRIBE my_table。列名を修正し、JOIN では my_table.my_column と修飾する。文字列リテラルは単一引用符で囲む。バッククォートは識別子専用。information_schema.columns でも確認できる。","tags":["column","column name","unknown","unknown column","1054","typo","misspelling"]},{"code":"2002","title":"Can't connect to local MySQL server through socket（ソケット経由でローカル MySQL サーバーに接続できない）","severity":"danger","meaning":"クライアントが Unix ソケット経由でローカルの MySQL サーバーに接続できなかった。通常はサーバーが稼働していないか、ソケットパスが誤っている。","cause":"MySQL/MariaDB サービスが稼働していないかクラッシュした、ソケットファイルのパス (例: /var/run/mysqld/mysqld.sock) がクライアントとサーバーで異なる、権限の問題、またはサーバーが起動していない。","fix":"サービスの状態を確認して起動する (systemctl status mysql / start mysql)。正しいソケットパスを確認する: SHOW VARIABLES LIKE 'socket' と my.cnf の socket 設定。パスが異なる場合は --socket で明示的に指定するか、TCP を使う: mysql -h 127.0.0.1 -P 3306。サーバーログで起動/クラッシュのエラーを確認する。","tags":["connection","connect","socket","unix socket","2002","server","local","localhost"]},{"code":"2003","title":"Can't connect to MySQL server (TCP/IP)（MySQL サーバーに接続できない）","severity":"danger","meaning":"クライアントが、指定されたホストとポートで TCP/IP 経由で MySQL サーバーに接続できなかった。","cause":"サーバーが稼働していない、誤ったホスト/ポート、ファイアウォールがポート 3306 をブロックしている、サーバーが localhost のみにバインドされている (bind-address = 127.0.0.1)、または skip-networking が有効。","fix":"サーバーが起動しており、正しいポートで待ち受けていることを確認する。リモートアクセスには my.cnf で bind-address = 0.0.0.0 (または適切な IP) を設定し、skip-networking が無効であることを確認する。ファイアウォールでポート 3306 を開放する。ホスト/ポートを確認する: mysql -h host -P 3306 -u app_user -p。ユーザーにリモートホストからの権限があることを確認する。","tags":["connection","connect","tcp","port","2003","network","firewall","bind-address"]},{"code":"2006","title":"MySQL server has gone away（MySQL サーバーとの接続が失われた）","severity":"caution","meaning":"コマンド実行中にクライアントとサーバー間の接続が失われた。サーバーが接続を閉じたか、パケットを拒否した可能性がある。","cause":"wait_timeout/interactive_timeout の経過によるアイドル接続のクローズ、max_allowed_packet より大きいクエリ/データ、サーバーの再起動またはクラッシュ、またはネットワーク障害。","fix":"アイドル接続の問題には、接続プールで接続検証を使い、wait_timeout を見直す。大きなデータを送る場合は max_allowed_packet を増やす (例: SET GLOBAL max_allowed_packet = 64*1024*1024、永続化するには my.cnf)。サーバーログで再起動/クラッシュと OOM の痕跡を確認する。切断された接続に備えてアプリケーションに再接続ロジックを追加する。","tags":["connection","connection lost","gone away","disconnect","2006","timeout","max_allowed_packet"]},{"code":"1114","title":"The table is full（テーブルが満杯）","severity":"danger","meaning":"ストレージの上限または利用可能な領域の終端に達したため、テーブルにこれ以上データを書き込めない。","cause":"ディスクの満杯、MEMORY テーブルで max_heap_table_size の上限に到達、一時テーブルで tmp_table_size を超過、innodb_data_file_path で定義された固定サイズのテーブルスペースが満杯、またはファイルシステム/テーブル固有のサイズ上限。","fix":"まずディスク容量を確認して解放する。MEMORY/一時テーブルには max_heap_table_size と tmp_table_size を増やす。InnoDB では innodb_data_file_path が autoextend であることを確認するか、領域を追加する。大きな一時結果をディスクに溢れさせるクエリを最適化する。恒久対応としてストレージ容量を増やす。","tags":["table full","table is full","disk","space","1114","space","memory","innodb"]},{"code":"1215","title":"Cannot add foreign key constraint（外部キー制約を追加できない）","severity":"caution","meaning":"定義しようとしている外部キー制約を作成できない。MySQL は制約を追加できない。","cause":"子列と参照先列の間でのデータ型/長さ/符号 (signed-unsigned) または文字セット/照合順序の不一致、参照先列に適切なインデックス/PRIMARY KEY がない、テーブルのストレージエンジンが異なる (一方が MyISAM)、または参照先テーブルがまだ存在しない。","fix":"両側の列の型が完全に同一であることを確認する (例: 両方とも INT UNSIGNED)。参照先列にインデックスがあることを確認する (通常は PRIMARY KEY または UNIQUE)。両方のテーブルが InnoDB であることを確認する。文字列キーには同じ charset/collation を使う。詳細: SHOW ENGINE INNODB STATUS (LATEST FOREIGN KEY ERROR)。","tags":["foreign key","foreign key constraint","fk","1215","constraint","constraint error","innodb","type"]},{"code":"1451","title":"Cannot delete or update a parent row: a foreign key constraint fails（親行を削除/更新できない: 外部キー制約違反）","severity":"caution","meaning":"親行を削除するかそのキーを変更しようとしたが、依存する子行が存在するため外部キー制約が許可しない。","cause":"参照されている親行にまだ子行があり、制約の ON DELETE/UPDATE が RESTRICT/NO ACTION になっている。","fix":"先に依存する子行を削除するか別の親に移し、その後で親行を削除する。自動的な動作が必要なら、制約を ON DELETE CASCADE または ON DELETE SET NULL で再定義する。依存行を特定する: SELECT * FROM child_table WHERE fk_column = value。","tags":["foreign key","foreign key constraint","fk","1451","parent","parent row","delete","reference"]},{"code":"1452","title":"Cannot add or update a child row: a foreign key constraint fails（子行を追加/更新できない: 外部キー制約違反）","severity":"caution","meaning":"子行を挿入または更新しているが、その行が指す親キー値が参照先テーブルに存在しないため、外部キー制約が拒否している。","cause":"存在しない親キーを参照する INSERT/UPDATE、誤った順序でのデータロード (子が先)、または削除された親行。","fix":"先に親行を挿入し、次に子行を挿入する。参照値が存在することを確認する: SELECT * FROM parent_table WHERE key_column = value。一括ロードでは親子の順序を守る。SET FOREIGN_KEY_CHECKS=0 は管理されたメンテナンス作業でのみ使い、終了後に 1 に戻す。","tags":["foreign key","foreign key constraint","fk","1452","child","child row","reference","insert"]},{"code":"1366","title":"Incorrect string/integer value for column（列に対する文字列/整数値が不正）","severity":"caution","meaning":"列の型または文字セットと互換性のない値が列に挿入された。通常は文字エンコーディングまたは型の不一致が原因。","cause":"latin1 列への 4 バイトの絵文字/文字 (utf8mb4) の書き込み、数値列への非数値テキストの入力、誤った接続文字セット、または想定と異なる型の値の送信。","fix":"文字の問題には、列/テーブルを utf8mb4 に変換する: ALTER TABLE my_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci、さらに接続文字セットを utf8mb4 に設定する。数値フィールドはアプリケーションで型を検証する。サーバーは厳格 SQL モード (STRICT) で動作している点に注意する。根本原因はデータの型/エンコーディングにある。","tags":["charset","character","incorrect value","1366","utf8mb4","encoding","type","collation"]},{"code":"1044","title":"Access denied for user to database（データベースへのアクセス拒否）","severity":"caution","meaning":"ユーザーは正しく認証されたが、指定されたデータベースを操作する権限がない。","cause":"ユーザーにデータベースへの GRANT がない、データベース名の誤り、別のホスト (user@host) に対して定義された権限、または存在しないデータベース。","fix":"ユーザーの権限を表示する: SHOW GRANTS FOR 'app_user'@'host'。必要な権限を付与する: GRANT ALL PRIVILEGES ON mydb.* TO 'app_user'@'host'; (GRANT は即座に有効になり、FLUSH PRIVILEGES は不要)。ホストの一致とデータベース名が正しいことを確認する。最小権限の原則に従い、必要な権限のみを付与する。","tags":["access denied","access","database","database access","1044","grant","privilege","permission"]},{"code":"1264","title":"Out of range value for column（列の範囲外の値）","severity":"caution","meaning":"数値列または日付列に、型が許容する範囲外の値が挿入された。このエラーは厳格 SQL モードで発生する。","cause":"TINYINT/INT などの型の上限超過 (例: TINYINT への 200、UNSIGNED 列への負の値)、日付/数値のオーバーフロー、または想定より大きな値の送信。","fix":"必要に応じて列の型を広げる (例: TINYINT の代わりに INT、INT の代わりに BIGINT) か、符号 (SIGNED/UNSIGNED) を修正する。アプリケーションで値の範囲を検証する。暗黙の切り詰め動作を望む場合でも (非推奨)、sql_mode から STRICT を外すのではなく、データを型に適合させる。","tags":["out of range","value out of range","1264","value","int","tinyint","unsigned","overflow"]}]},"errors/mssql.json":{"engineId":"mssql","engine":"SQL Server","order":4,"errors":[{"code":"1205","title":"Transaction (Process ID) was deadlocked on lock resources with another process and has been chosen as the deadlock victim（デッドロックの犠牲者として選択された）","severity":"danger","meaning":"2 つ以上のトランザクションが互いに相手の保持するロックを待っている (デッドロック)。循環を断ち切るため、SQL Server は 1 つのトランザクションを犠牲者として選び、ロールバックする。","cause":"テーブル/行を異なる順序でロックするトランザクション、長時間実行されるトランザクション、インデックスの欠如による広範なスキャン、ロックエスカレーション、高い同時実行が典型的な原因。","fix":"アプリケーションでエラー 1205 を捕捉し、トランザクションを自動で再試行する。すべてのトランザクションで同じ順序でオブジェクトにアクセスし、トランザクションを短く保つ。デッドロックグラフを調べる: 詳細には拡張イベント (system_health セッション) またはトレースフラグ 1222 を使う。適切なインデックスを追加してスキャンとロックを減らす。必要なら READ COMMITTED SNAPSHOT (RCSI) 分離レベルを評価する。","tags":["deadlock","lock","locking","victim","rollback","1205","retry"]},{"code":"2627","title":"Violation of PRIMARY KEY / UNIQUE KEY constraint. Cannot insert duplicate key in object（PRIMARY KEY / UNIQUE KEY 制約違反）","severity":"caution","meaning":"PRIMARY KEY または UNIQUE 制約で保護された列に、すでに存在する値を挿入または更新しようとした。重複キーは受け付けられない。","cause":"同じ一意値の 2 回目の挿入、既存値と衝突する UPDATE、一意性チェックの欠如、または 2 つの同時リクエストによる同じ行の生成。","fix":"挿入前に行の存在を確認するか、MERGE / IF NOT EXISTS を使う。冪等な挿入には \"INSERT ... WHERE NOT EXISTS\" パターンを適用する。エラーを捕捉して意味のあるメッセージを返す。本当に重複データが必要な場合は制約を見直す。キー生成時の衝突を避けるには IDENTITY または SEQUENCE を使う。","tags":["unique","primary key","uniqueness","duplicate","constraint","constraint violation","2627"]},{"code":"2601","title":"Cannot insert duplicate key row in object with unique index. The duplicate key value is ...（一意インデックスに重複キー行を挿入できない）","severity":"caution","meaning":"UNIQUE INDEX が重複キー値のため行を拒否した。制約の場合は 2627、一意インデックスの場合は 2601 が発生する。","cause":"UNIQUE INDEX で保護された列への既存値の再書き込み、同時挿入、またはフィルター選択された一意インデックスの対象行同士の衝突。","fix":"重複値を削除または更新する。重複を許容する必要があれば IGNORE_DUP_KEY = ON オプションを検討する (重複は警告なしにスキップされる)。挿入前に NOT EXISTS チェックを追加する。フィルター選択されたインデックスがある場合は、その WHERE 句と衝突内容を確認する。","tags":["unique index","duplicate key","unique idx","duplicate","2601","index"]},{"code":"547","title":"The INSERT/UPDATE/DELETE statement conflicted with the FOREIGN KEY / CHECK constraint（FOREIGN KEY / CHECK 制約との競合）","severity":"caution","meaning":"文が FOREIGN KEY 制約または CHECK 制約に違反した。存在しない親行を参照したか、CHECK ルールに反する値を書き込んだか、まだ参照されている親行を削除しようとした。","cause":"FK: 挿入された子行が参照する親行が存在しない。DELETE/UPDATE: 削除/変更対象の親行に依存する子行がある。CHECK: 列の値が定義された条件を満たさない。","fix":"先に親行を挿入し、次に子行を挿入する。削除では先に依存行を削除するか、適切な場合は ON DELETE CASCADE を定義する。CHECK 違反では値をルールに適合させる。エラーテキストの制約名から違反した制約を特定する。","tags":["foreign key","fk","check","constraint","constraint violation","referential","547"]},{"code":"18456","title":"Login failed for user（ユーザーのログイン失敗）","severity":"danger","meaning":"認証時にログイン試行が拒否された。ユーザー名/パスワードの誤り、アカウントの無効化、またはユーザーにデータベースへのアクセス権がない可能性がある。","cause":"パスワードの誤り、存在しないログイン、無効化/ロックされたアカウント、Windows 認証のみ有効な状態での SQL ログインの使用、または既定データベースへのアクセス権がない。エラーテキストの State コードが真の原因を示す (State 5: ログインが存在しない、State 7: ログインが無効かつパスワードも誤り、State 8: パスワードの誤り (最も一般的)、State 18: パスワードの変更が必要、State 38: 指定されたデータベースを開けない、State 58: サーバーが Windows 認証のみのモードで SQL ログインを試行)。","fix":"SQL Server エラーログの State 値から根本原因を特定する (セキュリティ上の理由で詳細はクライアントに送られない)。ユーザー名/パスワードを確認する。サーバーが 'SQL Server and Windows Authentication Mode' (混合モード) で動作していることを確認する。変更した場合はサービスを再起動する。対象データベースでのログインのユーザーマッピングとアクセス許可を確認する。","tags":["login","session","authentication","authentication failed","password","18456","state"]},{"code":"8152","title":"String or binary data would be truncated（文字列またはバイナリデータが切り詰められる）","severity":"caution","meaning":"列の定義長より長いデータを書き込もうとした。SQL Server はデータ損失を防ぐため文を停止する (2628 は列/値を報告する同じエラーの新しい版)。","cause":"例えば VARCHAR(10) 列への 15 文字の書き込み、ソースより狭いターゲット列、データ型/長さの不一致、または ETL/転送でのフィールドサイズ不足。","fix":"データに合わせて列を広げる (ALTER TABLE ... ALTER COLUMN) か、データを短くする。SQL Server 2019 以降では、あふれたテーブル/列/値を示すエラー 2628 を使う。それ以前のバージョンでは LEN() で列を 1 つずつ確認して該当行を特定する。転送ではソースとターゲットのスキーマ長を揃える。","tags":["truncation","truncate","overflow","varchar","length","column length","8152","2628"]},{"code":"2628","title":"String or binary data would be truncated in table, column ...; truncated value（文字列またはバイナリデータが切り詰められる (テーブル/列/値を表示)）","severity":"caution","meaning":"8152 の拡張版 (SQL Server 2019 以降)。どのテーブル、どの列、どの値が切り詰められるかを明示的に報告する。","cause":"ターゲット列の定義長より長いテキスト/バイナリ値の書き込み。通常はスキーマの不一致、または想定外の長さの入力データ。","fix":"エラーテキストのテーブル名と列名を確認し、列を広げるかソース値を短くする。SQL Server 2019 では、2628 はデフォルトで互換性レベル 150 以上でのみ発生する。それより低いレベルでは ALTER DATABASE SCOPED CONFIGURATION SET VERBOSE_TRUNCATION_WARNINGS = ON またはトレースフラグ 460 で有効にする。SQL Server 2016 SP2 CU6 および 2017 CU12 以降では、トレースフラグ 460 で同じ詳細メッセージが得られる。転送層でフィールド長をターゲットに合わせる。","tags":["truncation","truncate","overflow","column","column name","length","2628","460"]},{"code":"1222","title":"Lock request time out period exceeded（ロック要求のタイムアウト期間を超過）","severity":"caution","meaning":"ロックの取得を待つ間にクエリのタイムアウトが経過した。別のトランザクションが必要なリソースを長時間ロックしていたため、要求は取り消された。","cause":"SET LOCK_TIMEOUT で設定した待機時間の超過、長時間実行されるブロッキングトランザクション、コミットされていないオープントランザクション、長いスキャン、ロックの競合。","fix":"ブロッカーを特定する: sys.dm_exec_requests、sys.dm_tran_locks、blocking_session_id 列を調べるか、sp_who2 / sp_whoisactive を使う。長いトランザクションを短くしてコミットする。必要なら LOCK_TIMEOUT を調整する。読み取りの多いシステムでは RCSI/スナップショット分離でリーダーとライターの競合を減らす。","tags":["lock timeout","lock wait timeout","blocking","blocked session","1222","lock_timeout"]},{"code":"9002","title":"The transaction log for database is full due to ...（トランザクションログが満杯）","severity":"danger","meaning":"データベースのトランザクションログファイルが満杯で、新しいトランザクションをログに記録できない。データベースは書き込みを拒否し、読み取り専用のように振る舞うことがある。","cause":"FULL 復旧モデルでログバックアップがない、長時間オープンしたままのトランザクション、レプリケーション/AlwaysOn の遅延、またはログが拡張できない (自動拡張の無効化またはディスクの満杯)。log_reuse_wait_desc が理由を示す。","fix":"sys.databases の log_reuse_wait_desc を確認する。FULL モデルで LOG_BACKUP なら、ログバックアップ (BACKUP LOG) を取得する。ACTIVE_TRANSACTION なら、オープンしたトランザクションを特定してコミット/ロールバックする (DBCC OPENTRAN)。ディスク領域を解放するか、ログファイルの自動拡張設定を修正する。ログが本当に肥大化した場合は、バックアップ後に DBCC SHRINKFILE で圧縮する。ログチェーンが不要なら復旧モデルを見直す。","tags":["transaction log","log is full","log full","9002","backup log","recovery model"]},{"code":"1105","title":"Could not allocate space for object in database because the filegroup is full（ファイルグループが満杯のため領域を割り当てられない）","severity":"danger","meaning":"データファイルを格納するファイルグループが満杯で、新しいデータに領域を割り当てられない。挿入/更新が失敗する。","cause":"データファイルが拡張できない (自動拡張の無効化または MAXSIZE に到達)、ディスクの空き容量がない、PRIMARY ファイルグループの枯渇、またはファイルサイズの上限。","fix":"ディスク領域を解放するか、新しいディスク/ファイルを追加する。データファイルの自動拡張を有効にするか拡大する (ALTER DATABASE ... MODIFY FILE)。ファイルグループに新しいファイルを追加する。不要/古いデータをアーカイブして削除する。tempdb の場合は tempdb ファイルとそのディスクを確認する。","tags":["filegroup full","file full","allocate space","disk","autogrow","1105"]},{"code":"208","title":"Invalid object name（無効なオブジェクト名）","severity":"safe","meaning":"クエリで参照されたテーブル、ビュー、またはオブジェクトが見つからなかった。SQL Server は指定された名前を解決できなかった。","cause":"オブジェクト名のつづりの誤り、誤ったデータベース/スキーマのコンテキスト (dbo 以外のスキーマ)、オブジェクトが実際に存在しないか未作成、または 2 部構成の名前 (schema.table) の欠如。","fix":"オブジェクト名とスキーマを正しく記述し、修飾名を使う (例: dbo.Customers)。正しいデータベースに接続していることを確認する (USE)。オブジェクトの存在を確認する: SELECT * FROM sys.objects WHERE name = 'YourObjectName'。一時テーブルが同じセッション内で作成されていることを確認する。","tags":["invalid object","invalid object name","table not found","table does not exist","schema","app schema","208"]},{"code":"229","title":"The SELECT/EXECUTE permission was denied on the object（オブジェクトに対する SELECT/EXECUTE 権限が拒否された）","severity":"caution","meaning":"ユーザーに、オブジェクトに対して要求された操作 (SELECT、INSERT、EXECUTE など) を実行する権限がない。セキュリティ上の理由でアクセスが拒否された。","cause":"必要な権限がユーザー/ロールに付与されていない、誤ったスキーマ所有権 (所有権の継承の断絶)、オブジェクトに対する明示的な DENY、またはユーザーが十分なロールのメンバーでない。","fix":"必要な権限を付与する: GRANT SELECT ON dbo.MyTable TO UserName (または GRANT EXECUTE ON dbo.MyProcedure TO ...)。ユーザーを適切なロールに追加する (例: db_datareader)。明示的な DENY を削除する。最小権限の原則に従って権限を整理する。既存の権限は sys.database_permissions で監査する。","tags":["permission denied","access denied","grant","privilege","security","security permissions","229"]},{"code":"4060","title":"Cannot open database requested by the login. The login failed（ログインが要求したデータベースを開けない）","severity":"danger","meaning":"認証は成功しても、要求されたデータベースを開けないため接続が拒否される。通常は 18456 と同時に見られる。","cause":"データベースが存在しない、OFFLINE/SINGLE_USER/RESTORING/SUSPECT の状態、ログインにそのデータベースでのユーザーマッピングがない、または接続文字列の既定データベースにアクセスできない。","fix":"データベースが存在し ONLINE であることを確認する: SELECT name, state_desc FROM sys.databases。データベース内にログイン用のユーザーを作成し、権限を付与する。接続文字列の Initial Catalog/Database の値を確認する。データベースが RESTORING/SUSPECT なら修復/リストアの手順に従う。","tags":["cannot open database","database cannot be opened","4060","login","state","offline"]},{"code":"233","title":"A connection was successfully established with the server, but then an error occurred (no process is on the other end of the pipe)（接続確立後にエラーが発生）","severity":"danger","meaning":"クライアントはサーバーに到達したが、ハンドシェイク中に接続が切断された。通常は Named Pipes/TCP の構成、プロトコル設定、またはサーバー側での拒否が原因。10054 (接続の強制切断) と関連する。","cause":"Shared Memory/Named Pipes/TCP プロトコルの無効化、リモート接続が許可されていない、アカウントがログインできない (18456 を参照)、ファイアウォール/ネットワーク障害、またはサーバーによる接続の強制切断 (10054)。","fix":"SQL Server 構成マネージャーで TCP/IP と、必要なら Named Pipes を有効にし、サービスを再起動する。リモート接続が許可されていることを確認する。ファイアウォールで SQL ポート (デフォルト 1433) を開放する。認証の問題では、エラーログの 18456 の State コードを調べる。ネットワークの安定性と TLS/暗号化の設定を確認する。","tags":["connection","connection error","pipe","10054","tcp","named pipes","233","network"]},{"code":"823","title":"The operating system returned error to SQL Server during a read/write at offset in file (I/O error)（読み取り/書き込み中に OS がエラーを返した）","severity":"danger","meaning":"SQL Server がデータ/ログファイルの読み取りまたは書き込み中に、オペレーティングシステムレベルの I/O エラーを受け取った。ディスクハードウェアまたはストレージサブシステムの問題を示す、深刻な整合性の警告である。","cause":"ディスクの不良セクタ、コントローラ/ドライバの故障、ストレージ/SAN の問題、ファイルシステムのエラー、またはまったく読み取れないページ (ハード I/O エラー)。通常はハードウェア関連。","fix":"(可能なら) 直ちに正常なバックアップを取得する。Windows イベントログとストレージのログを調べ、ハードウェア/ディスクの健全性をテストする。DBCC CHECKDB を実行して整合性を確認する。suspect_pages テーブル (msdb.dbo.suspect_pages) を確認する。破損がある場合は、正常なバックアップからリストアするか、ページ単位のリストアを行う。ハードウェアを交換/修理する。","tags":["io error","i/o error","disk","corruption","data corruption","823","checkdb"]},{"code":"824","title":"SQL Server detected a logical consistency-based I/O error (page corruption)（論理整合性ベースの I/O エラー）","severity":"danger","meaning":"SQL Server はページを読み取ったが、その内容が論理的に不整合である (不正なチェックサム、破損ページ (torn page)、または誤ったページ ID)。データページが破損している。","cause":"ストレージサブシステムのエラー、突然の電源断/破損ページ (torn page)、コントローラまたはドライバの問題、PAGE_VERIFY CHECKSUM で検出されたサイレント破損。823 と同様、主にハードウェア/ストレージ関連。","fix":"DBCC CHECKDB を実行して破損の範囲を特定する。最後の正常なバックアップからリストアするか、ページ単位のリストアで影響を受けたページを修復する。msdb.dbo.suspect_pages を調べる。PAGE_VERIFY = CHECKSUM が有効であることを確認する。ハードウェア/ストレージを点検する。REPAIR_ALLOW_DATA_LOSS は最後の手段であり、データ損失を伴う。","tags":["page corruption","corrupt page","consistency","824","checkdb","checksum","torn page"]},{"code":"701","title":"There is insufficient system memory in resource pool to run this query（リソースプールのシステムメモリ不足）","severity":"danger","meaning":"SQL Server が、該当するリソースプールからクエリの実行に必要なメモリを割り当てられなかった。メモリ不足により操作が失敗した。","cause":"サーバーメモリの不足、低い max server memory 設定、メモリを大量に消費するクエリ (大きなソート/ハッシュ)、メモリリーク、多数の同時要求、または Resource Governor のプール上限。","fix":"max server memory 設定を見直し、十分な物理 RAM を用意する。メモリを大量に消費するクエリを最適化する (適切なインデックス、ソート/ハッシュの削減)。メモリを監視する: sys.dm_os_memory_clerks、DBCC MEMORYSTATUS、パフォーマンスモニターのメモリカウンタ。Resource Governor のプール上限を調整する。必要なら同時実行数を減らす。","tags":["memory","memory pressure","insufficient memory","resource pool","701","oom"]},{"code":"845","title":"Time-out occurred while waiting for buffer latch（バッファラッチ待機中のタイムアウト）","severity":"danger","meaning":"データページのバッファラッチを待つ間にタイムアウトが発生した。SQL Server はページへのアクセスに必要な短時間の内部ロック (ラッチ) を妥当な時間内に取得できなかった。通常は高い I/O 負荷またはメモリ不足の兆候。","cause":"遅い/過負荷のディスクサブシステム、メモリ不足によりページが常にディスクから読み取られる、ハードウェアの問題、過剰なページング、またはストレージのボトルネック。","fix":"ディスク I/O の遅延を測定する (sys.dm_io_virtual_file_stats、パフォーマンスモニターのディスク遅延)。ストレージ性能とハードウェアの健全性を確認する。メモリの充足度と max server memory 設定を見直す。待機の種類を調べる (sys.dm_os_wait_stats、PAGEIOLATCH 待機)。ストレージのボトルネックを解消し、必要ならより高速なディスク/より多くの RAM を用意する。","tags":["buffer latch","latch timeout","845","io","pageiolatch","memory","memory pressure"]},{"code":"3201","title":"Cannot open backup device. Operating system error (backup device error)（バックアップデバイスを開けない）","severity":"caution","meaning":"バックアップまたはリストア中に、対象のバックアップデバイス/ファイルを開けなかった。SQL Server は指定されたパスにアクセスできなかった。","cause":"誤った/存在しないフォルダパス、SQL Server サービスアカウントに対象フォルダへの書き込み権限がない、ネットワーク共有 (UNC) にアクセスできない、ディスクの満杯、またはファイルが別プロセスにロックされている。","fix":"バックアップパスが存在し、正しく記述されていることを確認する。SQL Server サービスアカウントに対象フォルダへの書き込み権限を付与する。UNC 共有ではサービスアカウントのアクセス権を確認する。十分なディスク空き容量があることを確認する。ローカルパスでは、ドライブ文字がサーバーから見えること (クライアントのドライブではないこと) を確認する。","tags":["backup device","backup file","backup","restore","3201","permission denied","permission","os error"]}]},"errors/mongodb.json":{"engineId":"mongodb","engine":"MongoDB","order":5,"errors":[{"code":"E11000","title":"E11000 duplicate key error collection（E11000 重複キーエラー）","severity":"caution","meaning":"挿入または更新で、一意インデックスで保護されたフィールドに、コレクション内にすでに存在する値を書き込もうとした。MongoDB は重複キーを拒否する。","cause":"_id の衝突、一意インデックスを持つフィールドへの同じ値の再書き込み、upsert 中の競合状態、または一意インデックス (非 sparse インデックス) で複数ドキュメントの null 値が衝突。","fix":"書き込み前にドキュメントの存在を確認するか、upsert を使う: db.collection.updateOne(filter, {$set:{...}}, {upsert:true})。エラーメッセージのインデックス名と dup key の値を確認する。一意性が実際には不要ならインデックスを削除する。null が問題なら partial/sparse インデックスを使う。アプリケーションではエラーを捕捉して再試行するか、ユーザーに通知する。","tags":["duplicate key","duplicate key","unique index","unique","e11000","upsert","_id"]},{"code":"11000","title":"DuplicateKey (エラーコード 11000)","severity":"caution","meaning":"重複キーエラーの数値コード (E11000 のテキストとともに返される)。書き込み操作が一意インデックス制約に違反した。","cause":"同じ一意フィールドの再書き込み、同じキーを生成する同時 upsert、または一括書き込み内の重複ドキュメント。","fix":"アプリケーションコードでエラーコード 11000 を捕捉し、冪等な動作を実装する (存在すれば更新、なければ挿入)。一括操作では ordered:false を使い、重複以外のドキュメントが書き込まれるようにする。一意性ルールとインデックス定義を見直す。","tags":["duplicatekey","11000","duplicate","unique","unique","bulk write","write error"]},{"code":"13","title":"Unauthorized (エラーコード 13)","severity":"caution","meaning":"認証済みユーザーに、試行した操作またはリソースに対する権限がない。ユーザーはログインしているが、そのロールではこの操作が許可されていない。","cause":"必要なロール (例: readWrite、dbAdmin) がユーザーに付与されていない、操作が誤ったデータベースに対して実行されている、または管理コマンドに対する権限が不十分。RBAC 構成の不備。","fix":"ユーザーのロールを確認する: db.getUser(\"app_user\")。必要なロールを付与する: db.grantRolesToUser(\"app_user\", [{role:\"readWrite\", db:\"mydb\"}])。操作が正しいデータベースで実行されることを確認する。最小権限の原則に従い、適切な組込みロールまたはカスタムロールを割り当てる。接続文字列の authSource の値を確認する。","tags":["unauthorized","unauthorized","authorization","role","role","rbac","13","permission"]},{"code":"18","title":"AuthenticationFailed (エラーコード 18)","severity":"caution","meaning":"認証に失敗した。指定されたユーザー名、パスワード、または資格情報が無効で、ユーザーはログインできなかった。","cause":"ユーザー名/パスワードの誤り、誤った authSource データベース、認証メカニズムの不一致 (SCRAM-SHA-1/SCRAM-SHA-256)、またはユーザーが指定されたデータベースに定義されていない。","fix":"ユーザー名とパスワードを確認する。接続文字列に正しい authSource (ユーザーを作成したデータベース。通常は admin) を指定する: ...?authSource=admin。認証メカニズムがサーバーと互換であることを確認する。ユーザーが正しいデータベースに作成されていることを確認する。パスワードに特殊文字が含まれる場合は URL エンコードする。","tags":["authentication failed","authentication","password","password","authsource","18","scram"]},{"code":"11600","title":"InterruptedAtShutdown (エラーコード 11600)","severity":"danger","meaning":"サーバーがシャットダウンを開始したため、操作が中断された。mongod プロセスが停止中だったため、実行中の操作を完了できなかった。","cause":"mongod の再起動/シャットダウン、レプリカセットのプライマリ stepdown 中のシャットダウン、計画メンテナンス、クラッシュ、または OOM killer によるプロセスの強制終了。","fix":"サーバーの復帰を待って操作を再試行する。アプリケーションでは一時的エラーを捕捉して自動で再試行し、retryable writes を有効にする。予期しないシャットダウンでは mongod のログとシステムログ (OOM、クラッシュ) を確認する。高可用性のためにレプリカセットを使う。","tags":["interrupted","shutdown","shutdown","downtime","11600","retry","replica set"]},{"code":"50","title":"MaxTimeMSExpired (エラーコード 50)","severity":"caution","meaning":"maxTimeMS で設定した時間制限を超えたため、サーバーが操作を取り消した。クエリが割り当てられた時間内に完了しなかった。","cause":"長時間実行されるクエリ、インデックスの欠如によるコレクションスキャン (COLLSCAN)、大量のデータ、重い集計処理、または高いサーバー負荷。","fix":"クエリを最適化する: explain() で実行計画を確認し、適切なインデックスを追加する。本当により多くの時間が必要なら maxTimeMS を増やす。重い集計を簡素化するか、$match で早い段階で絞り込む。ページネーションで結果を分割する。サーバー負荷とリソース容量を確認する。","tags":["maxtimems","timeout","timeout","50","slow query","slow query","index"]},{"code":"251","title":"NoSuchTransaction (エラーコード 251)","severity":"caution","meaning":"参照されたマルチドキュメントトランザクションが見つからなかった。トランザクションはすでに終了したかタイムアウトしたか、無効なトランザクション番号が使われた。","cause":"トランザクションが transactionLifetimeLimitSeconds を超えて自動でアボートされた、セッションの終了、誤った/古い txnNumber、またはエラー後にすでにアボートされたトランザクションの続行。","fix":"トランザクションを最初からやり直す (新しいセッションで)。トランザクションを短く保ち、デフォルトの有効期間 (60 s) 内に終わるよう設計する。TransientTransactionError ラベルの付いたエラーでは、トランザクション全体を安全に再試行する。長いトランザクションが必要なら transactionLifetimeLimitSeconds の設定を見直す。","tags":["nosuchtransaction","transaction","transaction","251","session","abort","retry"]},{"code":"112","title":"WriteConflict (エラーコード 112)","severity":"caution","meaning":"2 つの同時操作が同じドキュメントを変更しようとしたときに発生する書き込み競合。楽観的同時実行制御のため、WiredTiger は一方の操作をロールバックする。","cause":"同じドキュメントへの高頻度の同時書き込み、長時間実行されるトランザクション中の競合する更新、ホットドキュメントへの激しい競合。","fix":"操作を再試行する。WriteConflict は通常一時的であり、再試行で解消する (TransientTransactionError ラベルが付く)。トランザクションを短く保ち、対象ドキュメント数を減らす。同じドキュメントへの競合を減らすようデータモデルを見直す。アプリケーションに指数バックオフ付きの再試行を実装する。","tags":["writeconflict","write conflict","112","concurrency","concurrency","retry","wiredtiger"]},{"code":"133","title":"FailedToSatisfyReadPreference (エラーコード 133)","severity":"danger","meaning":"指定された読み取り設定 (例: primary、secondary) を満たす適切なレプリカセットメンバーが見つからなかった。ドライバは要求をルーティングするノードを選択できなかった。","cause":"レプリカセットメンバーに到達できない/停止している、選出中でプライマリが存在しない、ネットワーク分断、タグセットの条件に一致するメンバーがない、または過半数 (クォーラム) に到達できない。","fix":"レプリカセットの状態を確認する: rs.status()。ノードの健全性とネットワーク接続を確認する。プライマリの選出完了を待って再試行する。読み取り設定を見直し、必要ならより柔軟な設定 (例: primaryPreferred) を使う。タグセットを使う場合は、一致するメンバーが存在することを確認する。","tags":["read preference","readpreference","133","replica set","election","secondary","primary"]},{"code":"6","title":"HostUnreachable (エラーコード 6)","severity":"danger","meaning":"ドライバ/クライアントが対象の MongoDB サーバー (ホスト) に到達できなかった。ネットワークレベルで接続を確立できなかった。","cause":"サーバーの停止、誤ったホスト/ポート、ファイアウォールによるブロック、DNS 解決の問題、ネットワーク障害、またはクライアントを除外する bindIp 設定。","fix":"ホスト名とポート (デフォルト 27017) が正しいことを確認する。mongod サービスが稼働していることを確認する。ファイアウォールとネットワークアクセスをテストする (ping/telnet)。mongod.conf の bindIp 設定がクライアントのアクセスを許可していることを確認する。DNS/SRV レコードを確認する (mongodb+srv 接続の場合)。","tags":["hostunreachable","host","connection","network","network","6","firewall","bindip"]},{"code":"89","title":"NetworkTimeout (エラーコード 89)","severity":"danger","meaning":"サーバーとの通信中のネットワーク操作が割り当てられた時間内に完了せず、タイムアウトした。接続は確立されていたが、応答が時間内に届かなかった。","cause":"遅い、または不安定なネットワーク、過負荷のサーバー、応答を遅らせる長時間実行の操作、低すぎるソケット/接続タイムアウト値、またはネットワークの輻輳。","fix":"ネットワークの遅延と安定性を測定する。サーバーの負荷とリソースを確認する。ドライバの connectTimeoutMS と socketTimeoutMS を現実的な値に設定する。一時的エラーを捕捉して再試行する。遅いクエリを最適化して応答時間を短縮する。","tags":["networktimeout","network timeout","89","timeout","socket","network","retry"]},{"code":"262","title":"ExceededTimeLimit (エラーコード 262)","severity":"caution","meaning":"操作がサーバー側で許可された時間制限を超え、終了された。maxTimeMS や内部の時間制限の超過がこのエラーの原因となる。","cause":"長時間実行されるクエリ/コマンド、インデックスの欠如による遅い実行、重い集計、大量データのスキャン、または高いサーバー負荷。","fix":"explain() でクエリを調べ、適切なインデックスを追加する。操作を小さな単位に分割する。実際の必要に応じて maxTimeMS を設定する。集計パイプラインでは $match/$project で早い段階でデータを減らす。サーバーリソースが十分であることを確認する。","tags":["exceededtimelimit","time limit","262","timeout","maxtimems","slow","index"]},{"code":"292","title":"QueryExceededMemoryLimitNoDiskUseAllowed (エラーコード 292)","severity":"caution","meaning":"クエリまたは集計ステージが許可されたメモリ上限 (デフォルト 100 MB) を超え、ディスクへの書き込みが許可されていなかったため失敗した。通常はソートまたはグループステージで見られる。","cause":"インデックスのない大量データのメモリ内ソート、大きな $group/$sort 集計ステージ、非常に大きな中間結果セット、allowDiskUse:false の設定。","fix":"allowDiskUse:true オプションで集計時のディスクへの書出しを許可する: db.collection.aggregate(pipeline, {allowDiskUse:true})。ソート対象フィールドにインデックスを作成してメモリ使用量を減らす。パイプラインの早い段階で $match により絞り込み、処理データ量を減らす。必要なら結果をページングする。MongoDB 6.0 以降では、ほとんどの場合ディスク使用がデフォルトで有効。","tags":["memory limit","memory limit","292","allowdiskuse","sort","aggregation","group"]},{"code":"26","title":"NamespaceNotFound (エラーコード 26)","severity":"safe","meaning":"参照された名前空間 (database.collection) が見つからなかった。指定されたコレクションまたはインデックスが存在しない。","cause":"コレクション名のつづりの誤り、未作成のコレクション、誤ったデータベースコンテキスト、または存在しないコレクションに対する drop/インデックス操作の試行。","fix":"コレクション名とデータベースを確認する: show collections。名前は大文字小文字を区別する点に注意する。MongoDB は最初の書き込み時にコレクションを自動作成する。必要なら db.createCollection() で明示的に作成する。drop などの操作では、事前にコレクションの存在を確認する。","tags":["namespacenotfound","namespace","collection missing","26","collection","not found","not found"]},{"code":"43","title":"CursorNotFound (エラーコード 43)","severity":"caution","meaning":"サーバー側のカーソルがもう存在しない。クライアントが次のバッチを要求した (getMore) ときにカーソルが見つからないため、エラーが返される。","cause":"カーソルのタイムアウト (デフォルトでは 10 分間の非アクティブ)、バッチ間の待機が長すぎる、サーバーの再起動、またはカーソルの明示的なクローズ。","fix":"カーソルの結果をより速く処理し、バッチ間で長く待たない。長時間の操作では noCursorTimeout オプションを慎重に使い (mongosh: cursor.noCursorTimeout(); PyMongo: no_cursor_timeout=True)、必ずカーソルをクローズする。セッション内のカーソルは、このオプションを指定してもセッションタイムアウト (localLogicalSessionTimeoutMinutes、デフォルト 30 分) でクローズされる。大きな結果セットでは、より小さい batchSize で反復するか、範囲ベースのページネーションを使う。操作を再開して再度照会する。","tags":["cursornotfound","cursor","cursor","43","getmore","timeout","batch","pagination"]},{"code":"211","title":"KeyNotFound (エラーコード 211)","severity":"caution","meaning":"想定されたキー/値が見つからなかった。通常は内部のキー管理、セッションキー、または oplog/keys コレクションに関する不整合を示す。","cause":"admin.system.keys コレクション内の署名キーの欠落/削除、レプリカセット/シャードクラスタでの時刻同期の問題、keyfile/キーローテーションの問題、または破損した内部状態。","fix":"レプリカセットメンバー間の時刻同期 (NTP) を確認する。admin.system.keys の内容とキー生成を確認する。クラスタの状態を見直す (rs.status()、sh.status())。解消しない場合は mongod のログを分析し、keyfile/認証の構成を見直す。キーを再生成できるよう、プライマリが正常に動作していることを確認する。","tags":["keynotfound","key","211","keys","session","ntp","cluster","cluster"]}]},"errors/redis.json":{"engineId":"redis","engine":"Redis","order":6,"errors":[{"code":"WRONGTYPE","title":"WRONGTYPE Operation against a key holding the wrong kind of value（キーの値の型が誤っている）","severity":"caution","meaning":"キーのデータ型に適さないコマンドがそのキーに対して実行された。例えば、文字列を保持するキーにリスト (LPUSH) やハッシュ (HSET) のコマンドを適用した場合。","cause":"キーの型が想定と異なる、同じキー名が異なるデータ型で使われている、アプリケーションロジックでの型の混同、または古い/残存キーの上書き。","fix":"キーの型を確認する: TYPE mykey。キーの実際の型に応じてコマンドを選ぶ。キーの命名で型を区別する (例: user:1:tags はセット、user:1:name は文字列)。必要なら古いキーを削除し (DEL)、正しい型で作り直す。アプリケーション層で型の一貫性を徹底する。","tags":["wrongtype","wrong type","type","data type","key","key"]},{"code":"OOM","title":"OOM command not allowed when used memory > 'maxmemory'（使用メモリが maxmemory を超えたためコマンド不可）","severity":"danger","meaning":"Redis の使用メモリが maxmemory の上限に達し、エビクション (eviction) ポリシーで新しいデータ用の領域を確保できないため、書き込みコマンドが拒否される。メモリが満杯で、書き込みができない。","cause":"maxmemory 上限の超過、noeviction ポリシーの選択 (キーが一切削除されない)、TTL のないデータの増加、メモリリーク、または上限に対して RAM が不足。","fix":"メモリ使用量を調べる: INFO memory と MEMORY USAGE。適切なエビクションポリシーを選ぶ (例: allkeys-lru または volatile-lru): CONFIG SET maxmemory-policy allkeys-lru。キーに TTL を設定して自動で削除されるようにする。maxmemory/RAM を増やす。大きなキーを見つけて縮小する (redis-cli --bigkeys)。不要なデータを削除する。","tags":["oom","out of memory","memory","maxmemory","eviction","memory","danger"]},{"code":"NOAUTH","title":"NOAUTH Authentication required（認証が必要）","severity":"caution","meaning":"Redis は認証を要求しているが、クライアントが認証前にコマンドを実行しようとした。先に AUTH でログインする必要がある。","cause":"サーバーに requirepass/ACL のパスワードが設定されているのにクライアントが AUTH コマンドを送っていない、接続文字列にパスワードがない、または接続の再確立後に AUTH が再実行されていない。","fix":"コマンド実行前に認証する: AUTH password (ACL の場合は AUTH app_user password)。クライアント/接続文字列にパスワードを追加する。接続プールを使う場合は、新しい接続ごとに AUTH が行われることを確認する。パスワードは安全に保管する (環境変数/シークレットマネージャー)。","tags":["noauth","authentication","authentication","auth","password","requirepass","acl"]},{"code":"WRONGPASS","title":"WRONGPASS invalid username-password pair or user is disabled（ユーザー名とパスワードの組が無効、またはユーザーが無効）","severity":"caution","meaning":"AUTH コマンドで指定したユーザー名/パスワードの組が無効か、ACL ユーザーが無効化されている。認証が拒否された。","cause":"パスワードの誤り、ACL ユーザー名の誤り、ACL でユーザーが無効化されている、requirepass の値の変更、またはパスワードのエスケープ/エンコーディングの問題。","fix":"正しいユーザー名とパスワードを入力する。ACL ユーザーを調べる: ACL LIST と ACL GETUSER app_user。ユーザーが無効化されていれば有効にする (ACL SETUSER app_user on ...)。requirepass で設定したパスワードを確認する (CONFIG GET requirepass)。パスワードをリセットする場合は、すべてのクライアントが更新されていることを確認する。","tags":["wrongpass","password","invalid password","auth","acl","user","invalid"]},{"code":"READONLY","title":"READONLY You can't write against a read only replica（読み取り専用レプリカには書き込めない）","severity":"caution","meaning":"書き込みコマンドがレプリカ (slave) ノードに送られた。レプリカはデフォルトで読み取り専用であり、書き込みはマスターでのみ実行できる。","cause":"クライアントがマスターではなくレプリカに接続している、フェイルオーバー後に旧マスターがレプリカになった、Sentinel/Cluster での誤ったノードへのルーティング、またはロードバランサーが書き込みをレプリカに転送している。","fix":"書き込み要求をマスターノードにルーティングする。Sentinel を使う場合は Sentinel に現在のマスターを照会する (SENTINEL get-master-addr-by-name)。Cluster では正しいシャードのマスターに書き込む。クライアントライブラリで読み取り/書き込みの分離を構成する。フェイルオーバー後は接続を更新し、新しいマスターを指すようにする。","tags":["readonly","read only","replica","slave","write","write","master","failover"]},{"code":"MASTERDOWN","title":"MASTERDOWN Link with MASTER is down and replica-serve-stale-data is set to 'no'（マスターとのリンクが切断）","severity":"danger","meaning":"レプリカとマスター間のリンクが切断されており、replica-serve-stale-data が 'no' に設定されているため、レプリカは古いデータで要求に応答することを拒否している。","cause":"マスターノードのクラッシュまたは到達不能、ネットワーク障害/分断、マスターとレプリカ間のレプリケーションリンクの切断、または高負荷でマスターが応答できない。","fix":"マスターノードの状態とネットワーク接続を確認する。レプリケーションの状態を調べる: INFO replication。マスターを復旧させるか、Sentinel/Cluster によるフェイルオーバーを行わせる。古いデータの提供が許容されるなら replica-serve-stale-data yes を検討する (一貫性のリスクに注意)。高可用性のために Sentinel/Cluster を使う。","tags":["masterdown","master down","replication","replication","stale","failover","sentinel","danger"]},{"code":"CLUSTERDOWN","title":"CLUSTERDOWN The cluster is down / Hash slot not served（クラスタ停止 / ハッシュスロット未提供）","severity":"danger","meaning":"Redis Cluster が完全には稼働していない。一部のハッシュスロットがどのノードからも提供されていないため、クラスタは要求を拒否する。","cause":"到達可能なマスターノードの不足、1 つ以上のスロットが未割り当て/未カバー、過半数 (クォーラム) の喪失、ノードのクラッシュ、または cluster-require-full-coverage が yes の状態で一部のスロットに到達できない。","fix":"クラスタの状態を確認する: CLUSTER INFO と CLUSTER NODES。停止したマスターを復旧させるか、レプリカを昇格させる。未割り当てのスロットを再割り当てする (redis-cli --cluster fix または CLUSTER ADDSLOTS)。すべてのスロットがカバーされていることを確認する。部分的な稼働が許容されるなら cluster-require-full-coverage no を検討する。","tags":["clusterdown","cluster","cluster","hash slot","slot","quorum","coverage","danger"]},{"code":"LOADING","title":"LOADING Redis is loading the dataset in memory（データセットをメモリにロード中）","severity":"caution","meaning":"Redis が起動中で、データセット (RDB/AOF) をディスクからメモリにロードしている。ロードが完了するまで、ほとんどのコマンドは一時的に拒否される。","cause":"サーバーが起動直後、大きな RDB/AOF ファイルのロード中、レプリカがマスターから完全同期を実行中、または再起動後のリカバリ処理。","fix":"ロードの完了を待つ。所要時間はデータサイズに依存する。状態を監視する: INFO persistence (loading:1 の間は待機し、0 になれば準備完了)。アプリケーションではこの一時的エラーを捕捉し、短い間隔で再試行する。ロード時間を短縮するには、データセット/永続化戦略 (RDB と AOF) を見直す。十分な RAM と高速なディスクを用意する。","tags":["loading","loading","startup","startup","rdb","aof","sync","persistence"]},{"code":"BUSY","title":"BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE（スクリプト実行中でビジー）","severity":"caution","meaning":"長時間実行される Lua スクリプトまたは関数が実行中で、busy-reply-threshold (Redis 7 より前は lua-time-limit。デフォルト 5000 ms) を超えた。Redis はシングルスレッドのため、この間は他のコマンドを処理できない。SCRIPT KILL (関数の場合は FUNCTION KILL) または SHUTDOWN NOSAVE のみ受け付けられる。","cause":"無限ループまたは非常に長時間実行される Lua スクリプト/関数、重い計算、大量データをループするスクリプト、または不適切に書かれた EVAL 呼出し。","fix":"スクリプトがデータを変更していなければ停止する: SCRIPT KILL。スクリプトがすでに書き込みを行っている場合 SCRIPT KILL は機能しない。データの一貫性を保つ最後の手段として SHUTDOWN NOSAVE が必要になることがある (保存されていないデータは失われる。注意すること)。スクリプトは短く決定的に書く。長い処理は分割する。busy-reply-threshold (旧 lua-time-limit) の設定を見直す。","tags":["busy","busy server","lua","script","script kill","eval","time limit"]},{"code":"MISCONF","title":"MISCONF Redis is configured to save RDB snapshots, but it's currently unable to persist to disk（RDB スナップショットをディスクに保存できない）","severity":"danger","meaning":"Redis は RDB スナップショットを取得するよう構成されているが、ディスクに書き込めない。この状態で stop-writes-on-bgsave-error が有効な場合、Redis はすべての書き込みコマンドを拒否する。","cause":"ディスクの満杯、ファイルシステムの権限の問題、書き込み不可のディレクトリ、バックグラウンド保存 (BGSAVE) のエラー、メモリ不足による fork の失敗、またはディスクハードウェアの問題。","fix":"ディスク領域を解放し、RDB ディレクトリ (dir) への書き込み権限を確認する。最新の BGSAVE エラーを調べる: INFO persistence と Redis のログ。問題が解決するまで一時的に書き込みを許可するには stop-writes-on-bgsave-error no を設定できる (耐久性のリスクに注意)。fork 用の十分なメモリと vm.overcommit_memory=1 の設定を確保する。永続化の構成 (save/appendonly) を確認する。","tags":["misconf","persist","durability","rdb","bgsave","disk","snapshot","danger"]},{"code":"CROSSSLOT","title":"CROSSSLOT Keys in request don't hash to the same slot（キーが同じスロットにハッシュされない）","severity":"caution","meaning":"Redis Cluster でマルチキーコマンド (例: MGET、MSET、SUNION) が使われたが、キーが異なるハッシュスロットに属している。マルチキー操作ではすべてのキーが同じスロットにある必要がある。","cause":"クラスタモードで、複数のキーに同時にアクセスするコマンドが、異なるスロットに分散したキーで呼び出されている。キーがハッシュタグを使っていないため、異なるノードに分散している。","fix":"ハッシュタグを使って関連キーを同じスロットに配置する: キー名の一部を波括弧で固定する (例: {user1}:profile と {user1}:settings は同じスロットに入る)。マルチキーコマンドは同じハッシュタグを共有するキーでのみ使う。代わりに、操作を単一キーのコマンドに分割する。","tags":["crossslot","cross slot","cluster","cluster","hash tag","slot","mget","mset"]},{"code":"MOVED","title":"MOVED slot ip:port (クラスタリダイレクト)","severity":"safe","meaning":"Redis Cluster で、要求されたキーを保持するハッシュスロットが別のノードに属している。サーバーはクライアントを正しいノードへ恒久的にリダイレクトする。これはエラーというよりリダイレクトである。","cause":"クラスタ非対応のクライアントが誤ったノードに要求を送っている、ノード間でスロットが再配置された (リシャーディング)、またはクライアントがキャッシュしているスロットマップが古い。","fix":"クラスタ対応のクライアントライブラリを使う。これらは MOVED 応答に自動で従い、正しいノードへリダイレクトし、スロットマップを更新する。redis-cli で接続するときは -c フラグを使う。クライアントがスロットトポロジーを定期的に更新することを確認する (CLUSTER SLOTS/SHARDS)。","tags":["moved","cluster","cluster","redirect","redirect","slot","resharding"]},{"code":"ASK","title":"ASK slot ip:port (クラスタリダイレクト)","severity":"safe","meaning":"Redis Cluster でスロットが別のノードへ移行中であり、要求されたキーが一時的に移行先ノードにある可能性がある。サーバーはこの要求に限りクライアントを移行先ノードへリダイレクトする (一時的なリダイレクト)。","cause":"リシャーディング中に移行中のスロット内ですでに転送されたキーへのアクセス。MOVED とは異なり恒久的ではなく、その時点でのみ適用される。","fix":"クラスタ対応のクライアントは ASK リダイレクトを自動で処理する: 移行先ノードに ASKING コマンドを送って要求を再試行するが、スロットマップは恒久的には更新しない。適切なクライアントライブラリを使い、redis-cli では -c フラグを使う。リシャーディングが完了すると、リダイレクトは MOVED となり恒久的になる。","tags":["ask","asking","cluster","cluster","migration","migration","redirect","redirect"]},{"code":"NOSCRIPT","title":"NOSCRIPT No matching script. Please use EVAL（一致するスクリプトがない）","severity":"caution","meaning":"EVALSHA で呼び出された Lua スクリプトの SHA1 ダイジェストがサーバーのスクリプトキャッシュに見つからなかった。Redis はこのハッシュに対応するスクリプトを知らない。","cause":"サーバーが再起動されたか SCRIPT FLUSH でスクリプトキャッシュがクリアされた、スクリプトが一度もロードされていない、またはフェイルオーバー後の新しいノードでキャッシュが空。","fix":"スクリプトを EVAL で本体ごと実行する (Redis が自動でキャッシュする) か、先に SCRIPT LOAD でロードし、返された SHA を EVALSHA で使う。アプリケーションでは NOSCRIPT エラーを捕捉し、EVALSHA から EVAL へのフォールバックロジックを実装する。多くの Redis クライアントライブラリはこれを自動で行う。","tags":["noscript","script","evalsha","eval","lua","sha","script load","cache"]},{"code":"EXECABORT","title":"EXECABORT Transaction discarded because of previous errors（以前のエラーによりトランザクションを破棄）","severity":"caution","meaning":"MULTI/EXEC ブロック内のトランザクションが、キューイング段階で発生したエラーのためにアボートされた。EXEC はコマンドを一切実行せずにトランザクションを拒否する。","cause":"MULTI と EXEC の間のコマンドに構文エラーがある、または存在しないコマンド名や引数の数の誤りなど、キューイング中に検出されたエラー。このようなエラーはトランザクション全体を無効にする。","fix":"MULTI ブロック内のコマンドの構文と引数を修正する。コマンドのキューイング中に応答を確認する。いずれかのコマンドが QUEUED ではなくエラーを返すと、トランザクションは EXEC 時にアボートされる。有効なコマンドでトランザクションを組み直す。注: Redis のトランザクションはロールバックしない。EXECABORT となるのはキューイングエラーのみで、実行時エラーは他のコマンドを停止させない。","tags":["execabort","transaction","transaction","multi","exec","discard","queue","queue"]}]},"errors/elasticsearch.json":{"engineId":"elasticsearch","engine":"Elasticsearch","order":7,"errors":[{"code":"cluster_block_exception","title":"ClusterBlockException[blocked by: [TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark, index has read-only-allow-delete block]] (7.x より前: FORBIDDEN/12/index read-only / allow delete (api))","severity":"danger","meaning":"ディスク使用量が flood stage ウォーターマーク (デフォルト 95%。大容量ディスクでは max_headroom で決定) を超えたため、Elasticsearch は、ディスクが完全に満杯になるのを防ぐ目的で、該当ノード上にシャードを持つインデックスに read_only_allow_delete ブロックを設定した。このブロックにより、インデックスへの書き込み (ドキュメントの index/update/delete) はできず、インデックス自体の削除のみ許可される。ES 8.x ではこのエラーは HTTP 429 で返される。","cause":"少なくとも 1 つのノードでディスク使用量が cluster.routing.allocation.disk.watermark.flood_stage のしきい値を超えた。ブロックを手動で解除しても、ディスクが満杯のままなら Elasticsearch は再びブロックを適用する。ログローテーションのない大きなインデックス、削除されていないスナップショット、またはディスク容量の不足が典型的な原因。","fix":"まずディスク領域を解放する: 古い/不要なインデックスを削除する (DELETE /old-index)、スナップショットを取得してインデックスを削除する、またはディスクを拡張する。7.4 以降では、ディスク使用量が high ウォーターマークを下回るとブロックは自動で解除される。待たずに即座に解除するには手動で削除する: PUT /_all/_settings {\"index.blocks.read_only_allow_delete\": null}。恒久対応として、ILM (Index Lifecycle Management) で古いデータを自動で削除/アーカイブし、ウォーターマーク設定 (disk.watermark.low/high/flood_stage) を見直す。","tags":["disk","read-only","watermark","flood-stage","cluster-block","danger"]},{"code":"index_read_only_allow_delete","title":"TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark, index has read-only-allow-delete block (旧形式: FORBIDDEN/12/index read-only / allow delete (api))","severity":"danger","meaning":"index.blocks.read_only_allow_delete が true のため、インデックスは読み取り専用である。新しいドキュメントの書き込みや更新はできず、インデックスの削除のみ可能。通常は、ディスクの flood stage ウォーターマークを超えたときに Elasticsearch が自動で設定する。ES 8.x では書き込み要求に HTTP 429 を返す。","cause":"ディスク使用量が flood stage のしきい値を超えたためブロックが自動で設定された、または設定が手動で true にされた。ディスク領域を解放せずにブロックを解除すると、Elasticsearch は再び適用する。","fix":"十分なディスク領域を解放する。7.4 以降では、自動で設定されたブロックはディスク使用量が high ウォーターマークを下回ると自動で解除される。手動で設定したブロックの場合、または待たずに解除する場合はブロックを削除する: PUT /_all/_settings {\"index.blocks.read_only_allow_delete\": null}。単一インデックスの場合: PUT /index-name/_settings {\"index.blocks.read_only_allow_delete\": null}。繰り返し発生する場合はディスク容量を増やし、ILM ポリシーを設定し、_cat/allocation でどのノードが満杯になりつつあるかを監視する。","tags":["read-only","disk","forbidden","watermark","block","danger"]},{"code":"high_disk_watermark_exceeded","title":"high disk watermark [90%] exceeded / flood stage disk watermark [95%] exceeded（ディスクウォーターマークの超過）","severity":"danger","meaning":"ノードのディスク使用量が high ウォーターマーク (デフォルト 90%) または flood stage (デフォルト 95%) のしきい値を超えた。high ウォーターマークを超えると、Elasticsearch はそのノードから他のノードへシャードの移動を試みる。flood stage を超えると、インデックスを読み取り専用にする。","cause":"ディスクが満杯になりつつある: 増え続けるログ/メトリクスのインデックス、削除されない古いインデックス、整理されていないスナップショットリポジトリ、小さすぎるディスク、または偏ったシャード配置による単一ノードの過剰な使用。","fix":"ディスク使用量を調べる: GET _cat/allocation?v。古いインデックスを削除するかスナップショットを取得して削除し、ディスクを拡張する。一時的にしきい値を引き上げることもできる (慎重に。8.x では max_headroom の検証があるため 3 つすべてを同時に設定する): PUT _cluster/settings {\"persistent\":{\"cluster.routing.allocation.disk.watermark.low\":\"88%\",\"cluster.routing.allocation.disk.watermark.high\":\"93%\",\"cluster.routing.allocation.disk.watermark.flood_stage\":\"96%\"}}。解決したら、同じ設定を null にしてデフォルトに戻す (transient 設定は非推奨のため使わない)。恒久対応: ILM によるライフサイクル管理、定期的なインデックスの整理、容量計画。flood stage によりインデックスが読み取り専用になった場合は、ブロックを別途解除する。","tags":["disk","watermark","flood-stage","allocation","capacity","danger"]},{"code":"circuit_breaking_exception","title":"CircuitBreakingException[[parent] Data too large, data for [<...>] would be [...], which is larger than the limit of [...]]（データが大きすぎる (サーキットブレーカー)）","severity":"danger","meaning":"要求がメモリ (ヒープ) のサーキットブレーカーの上限を超えるため拒否された。Elasticsearch は、ノードが OutOfMemoryError でクラッシュするのを防ぐため、要求を事前に停止する。[parent] ブレーカーはメモリ使用量全体を、[fielddata] ブレーカーは text フィールドの fielddata メモリを保護する。","cause":"JVM ヒープの不足、非常に大きい/複雑な集計、大きな結果セット、大きな bulk 要求、text フィールドにロードされた fielddata、またはヒープを圧迫する多数の重い同時クエリ。通常はヒープ圧迫の症状である。","fix":"クエリを小さくする: 集計サイズ、bulk のバッチサイズ、返すフィールドを減らす。text フィールドの fielddata ではなく keyword サブフィールド (.keyword) で集計する。JVM ヒープを増やす (サーバー RAM の約 50%、最大約 31GB)。ヒープ圧迫を監視する: GET _cat/nodes?v&h=name,heap.percent。ブレーカーの上限を一時的に引き上げるのではなく、根本原因 (メモリ/クエリ) を解消する。どのブレーカーが作動したかは GET _nodes/stats/breaker で確認する。","tags":["circuit-breaker","data-too-large","heap","memory","fielddata","oom","danger"]},{"code":"mapper_parsing_exception","title":"mapper_parsing_exception: failed to parse field [...] of type [...]（フィールドの解析に失敗）","severity":"caution","meaning":"ドキュメントのインデックス作成中に、フィールドに送られた値がマッピングで定義されたそのフィールドの型と一致せず、解析できなかった。例えば integer として定義されたフィールドへのテキストの送信や、date として定義されたフィールドへの無効な日付形式の送信。","cause":"フィールド型の不一致 (数値フィールドへの文字列、日付フィールドへの不正な形式)、想定される日付形式に合わない日付、不正/不完全な JSON、動的マッピングで誤った型になったフィールド、またはオブジェクトが期待される箇所へのスカラー値の送信。","fix":"エラーメッセージのフィールド名と想定される型を確認する: GET /index-name/_mapping。ドキュメント内の値をフィールド型に合わせるか、正しい型でマッピングを定義し直す。date フィールドでは format パラメータをドキュメントの形式に合わせる。既存フィールドの型は変更できないため、必要なら新しいインデックスを作成し _reindex でデータを移す。アプリケーション層でデータを検証する。","tags":["mapping","parse","mapper","field-type","indexing","caution"]},{"code":"strict_dynamic_mapping_exception","title":"strict_dynamic_mapping_exception: mapping set to strict, dynamic introduction of [...] within [...] is not allowed（strict マッピングで新しいフィールドの動的追加は不可）","severity":"caution","meaning":"インデックスまたはオブジェクトのマッピングが \"dynamic\": \"strict\" に設定されているため、マッピングに定義されていない新しいフィールドを含むドキュメントが拒否された。strict モードは、スキーマ外のフィールドが暗黙的に追加されるのを防ぐ。","cause":"マッピングが dynamic:strict の状態で、マッピングにないフィールド (誤字、新しいフィールド、想定外のフィールド) がドキュメントで送られた。通常はスキーマ管理を厳格に保つための意図的な安全策である。","fix":"ドキュメント内の余分な/つづりの誤ったフィールドを修正または削除する。そのフィールドが本当に必要なら、先にマッピングに追加する: PUT /index-name/_mapping {\"properties\": {\"new_field\": {\"type\": \"...\"}}}。新しいフィールドを自動で追加したい場合は dynamic を \"true\" に、保存するがインデックスしない場合は \"false\" に設定する。スキーマの規律を保つため、strict モードは意図して使う。","tags":["mapping","strict","dynamic","schema","field","caution"]},{"code":"illegal_argument_exception_fielddata","title":"illegal_argument_exception: Fielddata is disabled on text fields by default. Set fielddata=true on [your_field] in order to load fielddata in memory（text フィールドの fielddata はデフォルトで無効）","severity":"caution","meaning":"アナライズされた text フィールドに対して集計、ソート、またはスクリプトを試行した。これらの操作はメモリコストの高い fielddata を必要とするため、text フィールドではデフォルトで無効になっている。","cause":"text フィールドに直接集計/ソートを適用した。Elasticsearch では text は全文検索に、keyword は完全一致の集計/ソートに使う。両者を混同するとこのエラーが発生する。","fix":"集計/ソートにはフィールドの keyword サブフィールドを使う (例: \"my_field.keyword\")。フィールドが text のみの場合は、マッピングに keyword サブフィールドを追加し (マルチフィールド)、_reindex を実行する。text フィールドで fielddata を有効にする (fielddata=true) ことも可能だが、メモリ消費が大きくサーキットブレーカーのリスクがあるため推奨されない。やむを得ない場合にのみ使う。","tags":["fielddata","text","keyword","aggregation","sorting","mapping","caution"]},{"code":"search_phase_execution_exception","title":"search_phase_execution_exception: all shards failed / Failed to execute phase [query]（全シャードで検索フェーズの実行に失敗）","severity":"danger","meaning":"検索要求が必要なシャードの一部またはすべてで失敗した。これは実際の根本原因を包む汎用の検索エラーであり、\"caused by\" セクションに真の問題 (解析エラー、ブレーカー、不適切なフィールド型、シャードに到達できないなど) が示される。","cause":"無効なクエリ構文、誤ったフィールド型での集計、too_many_clauses、サーキットブレーカーの作動、未割り当て/到達不能なシャード、クエリのタイムアウト、またはノードのクラッシュ。根本原因は応答の内側の例外にある。","fix":"応答の \"caused by\" / \"failed_shards\" の詳細から実際の例外を特定し、それに応じて修正する (クエリの修正、keyword フィールドの使用、ブレーカー/ヒープの設定、シャード割り当て)。クラスタの健全性を確認する: GET _cluster/health と GET _cat/shards?v。部分的な結果が許可されていて一部のシャードが失敗した場合は、allow_partial_search_results の動作を見直す。","tags":["search","shard","search","all-shards-failed","query","danger"]},{"code":"too_many_clauses","title":"too_many_clauses: maxClauseCount is set to 1024 (query contains too many clauses)（クエリの句が多すぎる）","severity":"caution","meaning":"クエリが許可された Lucene 句の最大数を超えた。ES 8.x ではこの上限は固定ではなく、ノードのヒープサイズと検索スレッド数から自動で算出され (ヒープの小さいノードでは 1024 まで下がることがある)、エラーメッセージに現在の値が示される。非常に大きな bool クエリや多数の語に展開されるクエリが原因となる。","cause":"プログラムで生成された数千の should/must 句を持つ bool クエリ、多数の語に展開される wildcard/prefix/fuzzy/query_string クエリ、深くネストした bool 構造。注: terms クエリ (単一フィールドに対する値リスト) はこの上限の対象外であり、その上限は index.max_terms_count (デフォルト 65,536)。","fix":"クエリを簡素化する: 単一フィールドに対する多数の term 句を 1 つの terms クエリ (大きなリストには terms lookup) にまとめる。wildcard/prefix の代わりに、より具体的なクエリタイプや index_prefixes/keyword フィールドを使う。ES 8.x では indices.query.bool.max_clause_count 設定は非推奨で無視される。上限を上げるにはノードのヒープを増やす。クエリの生成ロジックを見直す。","tags":["too-many-clauses","max-clause-count","bool","terms","query","caution"]},{"code":"version_conflict_engine_exception","title":"version_conflict_engine_exception: [_doc][id]: version conflict, current version [x] is different than the one provided [y] (HTTP 409)（バージョンの競合）","severity":"caution","meaning":"ドキュメントの更新/削除要求が楽観的同時実行制御により拒否された。ドキュメントのバージョン (または _seq_no/_primary_term) が要求内のものと一致しない。つまり、読み取った後に別の誰かがドキュメントを変更した。HTTP 409 を返す。","cause":"同じドキュメントへの同時更新、古い version/seq_no での書き込み試行、既存ドキュメントの作成 (op_type=create) の試行、または _bulk 中の競合状態。","fix":"ドキュメントを再度読み取り、現在の _seq_no と _primary_term (または version) で要求を再試行する (read-modify-write ループ)。自動再試行には _update 要求の retry_on_conflict パラメータを使う。_update_by_query/_delete_by_query では conflicts=proceed を指定して競合するドキュメントをスキップして続行する。作成のみが目的なら競合は正常であり、アプリケーションで 409 を捕捉して適切に処理する (再試行またはスキップ)。","tags":["version-conflict","409","concurrency","optimistic","seq-no","caution"]},{"code":"document_missing_exception","title":"document_missing_exception: [_doc][id]: document missing（ドキュメントが存在しない）","severity":"caution","meaning":"更新 (_update) 対象のドキュメントがインデックスに見つからなかった。更新には既存のドキュメントが必要であり、ドキュメントが存在しない場合にこの例外が発生する。","cause":"ドキュメントが以前に削除された、作成されていない、誤った _id の使用、要求が誤ったインデックスに送られた、またはカスタムルーティングで書き込まれたドキュメントにルーティングなしでアクセスした。(GET と _update はリアルタイムであり、refresh の遅延はこのエラーの原因にならない。)","fix":"_id と対象インデックスが正しいことを確認する: GET /index-name/_doc/id。存在すれば更新、なければ作成という動作が必要なら、_update 要求で upsert (または doc_as_upsert:true) を使う。index (PUT) でドキュメントを直接作成する。アプリケーションではこの例外を捕捉し、upsert ロジックにフォールバックする。","tags":["document-missing","update","upsert","document","not-found","caution"]},{"code":"index_not_found_exception","title":"index_not_found_exception: no such index [index_name] (HTTP 404)（インデックスが存在しない）","severity":"caution","meaning":"要求されたインデックス (またはエイリアス) が存在しない。指定された名前のインデックスが見つからなかったため、操作は HTTP 404 で拒否された。","cause":"インデックスが作成されていない、削除された、インデックス/エイリアス名の誤字、クライアントが誤った環境 (クラスタ) に接続している、または action.auto_create_index が無効な状態で存在しないインデックスへの書き込みを試行した。","fix":"既存のインデックスを一覧表示する: GET _cat/indices?v。名前とエイリアスを確認する: GET _alias。インデックスを作成する: PUT /index-name (必要なマッピング/設定付きで)。またはインデックステンプレートで自動作成を構成する。自動作成が望ましい場合は action.auto_create_index の設定を確認する。誤ったクラスタに接続していないことを確認する。","tags":["index-not-found","404","index","alias","not-found","caution"]},{"code":"resource_already_exists_exception","title":"resource_already_exists_exception: index [index_name/uuid] already exists (HTTP 400)（インデックスがすでに存在する）","severity":"safe","meaning":"作成しようとしたインデックス (またはリソース) がすでに存在する。同じ名前のインデックスが存在するため、作成要求は拒否された。旧バージョンでは index_already_exists_exception としても現れる。","cause":"同じインデックスの 2 回目の作成試行、冪等でないセットアップスクリプト、同時の作成要求、または異なる設定で同じ名前を作り直そうとした。","fix":"インデックスがすでに存在するなら作成は不要であり、そのまま続行する。作り直す必要がある場合は、先に削除し (DELETE /index-name)、その後作成する (注意: データ損失)。セットアップスクリプトを冪等にする: 先に GET _cat/indices で存在を確認する。スキーマ管理にインデックステンプレートや ILM/rollover を使い、競合を防ぐ。","tags":["already-exists","resource-already-exists","index","create","idempotent","safe"]},{"code":"cluster_health_red","title":"cluster health status: RED / unassigned shards（クラスタの健全性 RED / 未割り当てシャード）","severity":"danger","meaning":"クラスタの健全性が RED であることは、少なくとも 1 つのプライマリシャードが未割り当てで利用できないことを意味する。一部のデータの読み取り/書き込みができず、部分的なデータ損失のリスクがある危機的な状態。(YELLOW はレプリカのみが未割り当てで、プライマリは無事であることを意味する。)","cause":"ノードがクラッシュ/離脱し、その上のプライマリシャードのコピーがなくなった、ディスクウォーターマークによる割り当ての阻止、破損したシャード、スナップショットのリストア中のエラー、またはシャードの割り当てを妨げる割り当て設定。","fix":"シャードが未割り当てである理由を確認する: GET _cluster/allocation/explain または GET _cat/shards?v&h=index,shard,prirep,state,unassigned.reason。クラッシュしたノードを復旧させる。ディスクの問題なら領域を解放する (ウォーターマーク)。割り当てが一時的に阻止されていた場合は再割り当てを起動する: POST _cluster/reroute?retry_failed=true。プライマリが完全に失われた場合はスナップショットからリストアする。RED 状態では、まずプライマリの復旧に注力する。","tags":["cluster-health","red","unassigned","shard","primary","danger"]},{"code":"no_shard_available_action_exception","title":"no_shard_available_action_exception: No shard available for [...]（利用可能なシャードがない）","severity":"danger","meaning":"要求を処理できるアクティブなシャードコピーが見つからなかった。該当シャードが未割り当て、リカバリ中、またはそれをホストするノードに到達できないため、要求を処理できない。","cause":"ノードのクラッシュ/ネットワーク分断、未割り当てのシャード、進行中のシャードリカバリ、ディスクウォーターマークによる割り当ての阻止、またはクラスタが RED/YELLOW 状態。","fix":"クラスタとシャードの状態を調べる: GET _cluster/health と GET _cat/shards?v。シャードが未割り当てである理由を確認する: GET _cluster/allocation/explain。クラッシュしたノードを復旧させ、ディスクの問題を解消し、リカバリの完了を待つ: GET _cat/recovery?v&active_only=true。必要なら POST _cluster/reroute?retry_failed=true で割り当てを再試行する。","tags":["no-shard-available","shard","unassigned","recovery","cluster","danger"]},{"code":"es_rejected_execution_exception","title":"es_rejected_execution_exception: rejected execution of ... on ... (queue capacity ...) (HTTP 429)（実行が拒否された (キュー容量超過)）","severity":"danger","meaning":"該当スレッドプール (search、write/bulk など) のキュー容量が満杯のため、操作が拒否された。過負荷時、Elasticsearch は要求を拒否して自身を保護し (バックプレッシャー)、HTTP 429 (Too Many Requests) を返す。","cause":"非常に多い同時要求、非常に大きい、または非常に頻繁な bulk 要求、重い集計/検索負荷、ノード/CPU リソースの不足、またはワークロードに対して小さすぎるスレッドプールのキュー。","fix":"クライアント側で指数バックオフにより再試行する。429 は通常一時的である。bulk のバッチサイズと送信レートを減らし、同時実行数を下げる。拒否された操作を監視する: GET _cat/thread_pool?v&h=node_name,name,active,queue,rejected。継続的な負荷にはノード/リソースを追加する (水平スケーリング)。キューサイズの拡大は最後の手段であり、根本原因は容量にある。","tags":["rejected-execution","429","thread-pool","queue","bulk","backpressure","danger"]},{"code":"master_not_discovered_exception","title":"master_not_discovered_exception / MasterNotDiscoveredException（マスターが見つからない）","severity":"danger","meaning":"クラスタがアクティブなマスターノードを選出/発見できなかった。マスターがないとシャードの割り当て、マッピングの変更、クラスタ状態の更新が行えず、クラスタは操作を処理できなくなる。","cause":"マスター適格ノードの過半数 (クォーラム) に到達できない、ネットワーク分断 (スプリットブレイン防止)、discovery.seed_hosts / cluster.initial_master_nodes の構成の誤り、新規インストールでのブートストラップの欠如、またはマスター適格ノードが少なすぎる。","fix":"マスター適格ノードが稼働し、互いに認識できていることを確認する: GET _cat/nodes?v と GET _cluster/state。discovery.seed_hosts と cluster.initial_master_nodes の設定を確認する (初回セットアップ時)。ネットワーク/ファイアウォールとノード間 (transport 9300) の接続を確認する。十分な数のマスター適格ノード (できれば 3 台) を稼働させる。ログでマスター選出のメッセージを調べる。","tags":["master","discovery","quorum","split-brain","cluster","danger"]},{"code":"security_exception","title":"security_exception: unable to authenticate / action [...] is unauthorized for user [...] (HTTP 401/403)（認証/認可の失敗）","severity":"danger","meaning":"認証 (401 Unauthorized) または認可 (403 Forbidden) に失敗した。401 は資格情報の欠如/誤りを示す。403 はユーザーは認証済みだが、この操作/インデックスに必要なロール/権限がないことを示す。","cause":"ユーザー名/パスワードまたは API キーの誤り、Authorization ヘッダーの欠如、期限切れ/無効なトークン、ユーザーに該当インデックスまたはクラスタの権限がない、またはロール割り当ての欠如/誤り。","fix":"401 の場合: 正しい資格情報/API キーを送り、Authorization ヘッダーを確認する。403 の場合: ユーザーのロールと権限を調べ (GET _security/user/app_user、GET _security/role/app_role)、必要なインデックス/クラスタ権限を追加する。最小権限の原則に従う。API キーを使う場合は有効期限と権限を確認する。","tags":["security","401","403","authentication","authorization","security","danger"]},{"code":"validation_exception","title":"validation_exception / illegal_argument_exception: Validation Failed: ...（検証の失敗）","severity":"caution","meaning":"要求のパラメータまたは設定が検証に失敗した。Elasticsearch は無効または矛盾した値を含む要求を実行せずに拒否した (例: 無効なシャード数、互換性のない設定の組合せ、必須フィールドの欠如)。","cause":"無効なインデックス設定 (例: 負/ゼロの number_of_shards)、既存インデックスで変更不可の設定を更新しようとした、互換性のないパラメータの組合せ、必須フィールドの欠如、または範囲外の値。","fix":"エラーメッセージの検証詳細を読む。どのパラメータがなぜ無効かが明確に示されている。値を有効な範囲/形式にする。変更不可 (static) の設定は既存インデックスではなく新規インデックスの作成時に指定する (必要なら _reindex)。API が要求する必須フィールドを指定する。設定のドキュメントに記載された有効な値を確認する。","tags":["validation","validation","settings","illegal-argument","invalid","caution"]},{"code":"task_cancelled_exception","title":"task_cancelled_exception: Task was cancelled / TaskCancelledException（タスクが取り消された）","severity":"caution","meaning":"実行中のタスク (search、_reindex、_update_by_query など) が取り消された。取り消しは、_tasks/_cancel へのユーザー要求、クライアントによる HTTP 接続のクローズ (クライアントのタイムアウト/中断。Elasticsearch は関連する検索を自動で取り消す)、親タスクの取り消し、または期限切れの非同期検索によって発生する。","cause":"ユーザーが POST _tasks/<task_id>/_cancel でタスクを取り消した (X-Opaque-Id はタスクの識別と検索に役立つだけで、取り消しは行わない)、クライアントのタイムアウトによる接続の切断、長時間実行される高コストなクエリ、またはアダプティブなリソース管理による重いタスクの停止。","fix":"タスクが予期せず取り消された場合は、クライアントのタイムアウトと接続設定を見直し、重いクエリを最適化する (データ量の削減、より具体的なフィルター)。長い操作では _reindex/_update_by_query を非同期 (wait_for_completion=false) で実行し、GET _tasks で監視する。アクティブなタスクを表示する: GET _tasks?detailed=true。必要なら高コストなクエリを分割するか、scroll/PIT を使う。","tags":["task-cancelled","task","timeout","reindex","cancel","caution"]}]},"errors/oracle-more.json":{"engineId":"oracle","engine":"Oracle","order":1,"errors":[{"code":"ORA-00604","title":"error occurred at recursive SQL level（再帰 SQL レベルでエラーが発生）","severity":"danger","meaning":"Oracle がバックグラウンドで内部的に実行する再帰 SQL の実行中にエラーが発生した。これは実際のエラーを隠すラッパー (外側の) エラーであり、真の原因はその直下に示される 2 つ目のエラーコードにある。","cause":"データディクショナリへのアクセス、失敗する DDL トリガー、満杯の SYSTEM 表領域、一時領域の不足、破損したデータディクショナリオブジェクト、またはセッションのログイン時に実行される LOGON トリガーの失敗。","fix":"エラースタックで ORA-00604 に続く 2 行目を読む。それが真の原因であり、それを修正する。例えば ORA-01653 が表示されていれば表領域を拡張する。DDL/LOGON トリガーが疑わしい場合は一時的に無効にする: ALTER TRIGGER trigger_name DISABLE; SYSTEM と TEMP 表領域の使用量を DBA_FREE_SPACE で確認する。","tags":["recursive","recursion","dictionary","data dictionary","trigger","wrapper"]},{"code":"ORA-01438","title":"value larger than specified precision allowed for this column（列の精度を超える値）","severity":"caution","meaning":"定義された精度と位取りの上限を超える数値が NUMBER 列に書き込まれた。例えば整数部が 3 桁の値は NUMBER(4,2) 列に収まらない。","cause":"列の NUMBER(p,s) 定義がデータに対して狭すぎる、計算結果が想定より大きい、小数の位取りにより整数部に使える桁が減る (NUMBER(5,3) では整数部は 2 桁のみ)。","fix":"実際のデータ範囲に合わせて列の容量を広げる: ALTER TABLE my_table MODIFY (my_column NUMBER(12,2)); アプリケーションで値を丸めるか、ROUND/TRUNC で位取りに合わせる。あふれた行を特定するにはテスト中にクエリを絞り込み、入力検証を追加する。","tags":["number","precision","precision","scale","scale","overflow","numeric"]},{"code":"ORA-01400","title":"cannot insert NULL into (column)（列に NULL は挿入できない）","severity":"caution","meaning":"NOT NULL 制約のある列に NULL 値が挿入または設定された。必須フィールドを空にすることはできない。","cause":"INSERT で必須列に値が指定されていない、UPDATE で列を NULL に設定した、列に DEFAULT が定義されていない、または副クエリ/アプリケーションから空の値が渡された。","fix":"エラーメッセージに示された列に有効な値を指定する。列に適切なデフォルトを定義する: ALTER TABLE my_table MODIFY (my_column DEFAULT 0); (DEFAULT は INSERT で列が完全に省略された場合にのみ適用される。明示的に送られた NULL 値には 12c 以降の DEFAULT ON NULL を使う: ALTER TABLE my_table MODIFY (my_column DEFAULT ON NULL 0);) ルールが本当に必須でなければ制約を削除する: ALTER TABLE my_table MODIFY (my_column NULL); 空の値は送信前にアプリケーションで検証する。","tags":["not null","null","empty","insert","constraint","constraint","mandatory"]},{"code":"ORA-02291","title":"integrity constraint violated - parent key not found（整合性制約違反 - 親キーがない）","severity":"danger","meaning":"外部キー制約に違反した。子テーブルに挿入された値に対応する親行が見つからなかった。つまり参照先のレコードが存在しない。","cause":"存在しない親レコードを参照する INSERT/UPDATE、親テーブルの行がまだ挿入されていない、誤ったロード順序 (親より先に子)、または大文字小文字や空白の違いによる照合の失敗。","fix":"先に親テーブルに該当レコードを挿入し、次に子テーブルに挿入する。参照の存在を確認する: SELECT * FROM parent_table WHERE key_col = value; 一括ロードではテーブルを正しい順序で処理する (親が先)。違反している行を特定するには、子テーブルの値を NOT IN / アンチ結合で親テーブルと比較する。","tags":["fk","foreign key","foreign key","constraint","constraint","parent","reference"]},{"code":"ORA-02292","title":"integrity constraint violated - child record found（整合性制約違反 - 子レコードがある）","severity":"danger","meaning":"親行を削除するかそのキーを変更しようとしたが、依存する子レコードが存在するため外部キー制約が許可しなかった。","cause":"子テーブルにレコードがある親行を DELETE しようとした、FK が ON DELETE CASCADE なしで定義されている、依存レコードを先に整理していない。","fix":"先に依存する子レコードを削除するか別の親レコードに移し、その後で親行を削除する。業務ルールが許すなら、外部キーを ON DELETE CASCADE で作り直す: ALTER TABLE child DROP CONSTRAINT fk_name; ALTER TABLE child ADD CONSTRAINT fk_name FOREIGN KEY (my_column) REFERENCES parent(key_col) ON DELETE CASCADE; 依存行を特定するには、親キーで子テーブルを照会する。","tags":["fk","foreign key","foreign key","child","child record","delete","cascade"]},{"code":"ORA-00979","title":"not a GROUP BY expression（GROUP BY の式ではない）","severity":"caution","meaning":"SELECT リストで集計関数 (SUM、COUNT など) とともに集計されていない列が使われたが、その列が GROUP BY 句に追加されていない。Oracle はその列をどうグループ化すべきかわからない。","cause":"SELECT にあるが GROUP BY にない列、集計関数の外にある式が GROUP BY リストにない、HAVING または SELECT 式での不整合。","fix":"集計されていないすべての列を GROUP BY リストに追加する: SELECT department, COUNT(*) FROM employee GROUP BY department; 代わりに、その列も集計関数 (MAX、MIN) で囲むか、分析関数 (OVER()) でグループ化を設計し直す。","tags":["group by","grouping","aggregate","aggregation","sum","count","query"]},{"code":"ORA-00918","title":"column ambiguously defined（列の定義が曖昧）","severity":"caution","meaning":"クエリ内の複数のテーブルに同じ名前の列があり、テーブル/別名の接頭辞なしで使われているため、Oracle はどのテーブルに属するか判断できない。","cause":"結合された両方のテーブルに同じ名前の列がある (例: 両方に ID)、その列が SELECT、WHERE、ORDER BY で修飾なし (接頭辞なし) で使われている。","fix":"曖昧な列はすべてテーブル名または別名で修飾する: SELECT a.id, b.id FROM tableA a JOIN tableB b ON a.id = b.a_id; テーブルに短い別名を付け、すべての列に接頭辞を付けて可読性と明確さを高める。","tags":["ambiguous","ambiguous column","column","column","join","alias","query"]},{"code":"ORA-06550","title":"line/column PLS-... PL/SQL コンパイルエラー","severity":"caution","meaning":"PL/SQL ブロック、プロシージャ、または無名ブロックのコンパイル中に構文エラーまたは意味エラーが見つかった。コードは実行前のコンパイル段階で失敗した。","cause":"誤字、宣言されていない変数やオブジェクトの参照、パラメータの数/型が誤った呼出し、セミコロンの欠落、存在しないプロシージャ/パッケージの呼出し、または権限の欠如。","fix":"エラーメッセージの行番号と列番号の箇所に移動し、PLS-XXXX のサブコードを読む。すべてのコンパイルエラーを表示する: SHOW ERRORS; または SELECT * FROM user_errors WHERE name = 'OBJECT_NAME'; オブジェクト名、パラメータのシグネチャ、必要な GRANT を確認してから再コンパイルする。","tags":["plsql","compilation","compile","pls","syntax","procedure","code"]},{"code":"ORA-04068","title":"existing state of packages has been discarded（パッケージの既存の状態が破棄された）","severity":"caution","meaning":"実行中のセッションがパッケージの状態を使用している間にパッケージが再コンパイルされたため、その状態が無効になった。セッションが保持するパッケージインスタンスはもはや有効ではない。","cause":"依存するセッションがアクティブな状態で、パッケージ本体または仕様が ALTER/CREATE OR REPLACE で再コンパイルされた。通常は稼働中のシステムへのアプリケーションのデプロイ時に発生する。ORA-04061/04065 とともに見られる。","fix":"呼出しを再実行 (再試行) すれば通常は解消する。2 回目の試行でパッケージが新しい形でロードされる。アプリケーションで ORA-04068 を捕捉して自動で再試行する。パッケージの変更はユーザーの活動が少ないメンテナンス時間帯に適用する。ステートレスなパッケージ設計によりこの問題を減らせる。","tags":["package","package","state","package state","recompile","compile","retry"]},{"code":"ORA-01427","title":"single-row subquery returns more than one row（単一行副クエリが複数行を返した）","severity":"caution","meaning":"1 行を返すことが期待される副クエリが複数行を返した。例えば等価 (=) 比較の右辺の副クエリが複数の値を生成した。","cause":"= や代入が期待される箇所での複数行を返す副クエリ、十分に絞り込まれていない WHERE 条件、相関での一意でない一致、SELECT リスト内のスカラー副クエリが複数行を返す。","fix":"副クエリが 1 行を返すよう絞り込む (追加の WHERE、一意キー)。本当に複数の値が想定されるなら = の代わりに IN を使う: WHERE id IN (SELECT id FROM ...)。または副クエリに集計 (MAX、MIN) を追加するか、ROWNUM = 1 で 1 行に絞る。まず副クエリを単独で実行し、返される行数を確認する。","tags":["subquery","subquery","single row","single row","in","scalar","query"]},{"code":"ORA-12899","title":"value too large for column（列に対して値が大きすぎる）","severity":"caution","meaning":"定義された最大長より長い値が文字/データ列に書き込まれた。例えば 15 文字のテキストは VARCHAR2(10) 列に収まらない。","cause":"列幅がデータに対して不足している、マルチバイト文字セット (UTF8) で文字数がバイト上限 (BYTE セマンティクス) を超える、データ移行時の異なる文字セット、連結結果が長くなる。","fix":"列を広げる: ALTER TABLE my_table MODIFY (my_column VARCHAR2(100)); マルチバイトの内容には CHAR セマンティクスを使う: my_column VARCHAR2(100 CHAR)。長い値を短くする必要がある場合は SUBSTR で切り詰める。エラーメッセージには実際の長さと許容長が示される。LENGTH/LENGTHB であふれたレコードを特定する。","tags":["varchar2","length","length","too large","column","column","charset"]},{"code":"ORA-30926","title":"unable to get a stable set of rows in the source tables（ソース表の安定した行セットを取得できない）","severity":"danger","meaning":"MERGE (または更新可能な結合) 文で、ソース側が同じターゲット行に対して複数の一致行を生成した。Oracle はどのソース値で更新すべきか判断できないため、操作を停止した。","cause":"MERGE ... USING のソースに ON 条件の重複一致が含まれる、ソースクエリがターゲットキーに対して一意でない、複数のソース行が同じターゲット行に対応する。","fix":"ソースクエリをターゲットキーに対して一意にする。重複一致を検出する: SELECT key_col, COUNT(*) FROM (source_query) GROUP BY key_col HAVING COUNT(*) > 1; DISTINCT または集計/分析関数 (ROW_NUMBER) でソースの重複を排除してから MERGE を再実行する。ON 条件の選択性が十分であることを確認する。","tags":["merge","merge","duplicate","duplicate rows","source","source","stable"]},{"code":"ORA-08103","title":"object no longer exists（オブジェクトがもう存在しない）","severity":"danger","meaning":"実行中のクエリがアクセスしているオブジェクト (テーブル、インデックス、LOB セグメント) がもう存在しないか、その物理構造が変わった。通常はクエリの実行中にそのオブジェクトに対して DDL/TRUNCATE が行われた。","cause":"クエリのオープン中に同じオブジェクトが TRUNCATE/DROP/SHRINK された、移動 (MOVE) またはパーティションメンテナンス、破損したインデックス/セグメント、LOB セグメントへのアクセス中に下位構造が消失、同時 DDL の競合。","fix":"オブジェクトがまだ存在し有効であることを確認する: SELECT status FROM user_objects WHERE object_name = 'NAME'; 該当するインデックス/オブジェクトを再構築する (REBUILD) か、クエリを再実行する。長時間のクエリが使用中のオブジェクトに TRUNCATE/DROP を行わない。破損が疑われる場合は ANALYZE ... VALIDATE STRUCTURE で確認する。","tags":["object","object","truncate","drop","ddl","corruption","segment"]},{"code":"ORA-01843","title":"not a valid month（月が無効）","severity":"caution","meaning":"テキストを DATE に変換する際に、月の部分を有効な月として解釈できなかった。通常は日付書式がデータの形式と一致していない。","cause":"TO_DATE に書式マスクが渡されておらず、セッションの NLS_DATE_FORMAT がデータと一致しない、日と月の入れ替わり (DD/MM と MM/DD の混同)、言語/ロケールの違い (月名)、破損した、または想定外の日付テキスト。","fix":"TO_DATE の呼出しでは常に明示的な書式を渡す: TO_DATE('2026-07-04', 'YYYY-MM-DD')。月名を含むテキストには言語を指定する: TO_DATE(str, 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE=ENGLISH')。必要ならセッションの書式を設定する: ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD'。無効な日付テキストはロード前に検証する。","tags":["date","date","to_date","nls","format","month","month"]},{"code":"ORA-14400","title":"inserted partition key does not map to any partition（パーティションキーがどのパーティションにも対応しない）","severity":"danger","meaning":"挿入された行のパーティションキー値が、テーブルに定義されたどのパーティションにも対応しない。その値をカバーするレンジまたはリストパーティションが存在しない。","cause":"RANGE パーティション化で最大レンジより上の日付/値が挿入され、MAXVALUE パーティションがない。LIST パーティション化で定義されていない新しい値。月/年の境界で新しいパーティションが事前に作成されていない。","fix":"不足しているパーティションを追加する: ALTER TABLE my_table ADD PARTITION p_2026_08 VALUES LESS THAN (TO_DATE('2026-09-01','YYYY-MM-DD')); RANGE には安全策として MAXVALUE パーティションを追加する。LIST には想定外の値を受け止める DEFAULT パーティションを定義する。新しいパーティションが自動で作成されるよう、自動パーティション化 (INTERVAL パーティション化) を使う。","tags":["partition","partition","partition key","range","list","maxvalue","insert"]},{"code":"ORA-01536","title":"space quota exceeded for tablespace（表領域の領域割り当て制限を超過）","severity":"danger","meaning":"指定された表領域に対するユーザーの領域割り当て制限 (クォータ) を使い切った。表領域に空き領域があっても、ユーザーに与えられた上限を超えたため新しい領域を割り当てられない。","cause":"ユーザーのクォータが制限付き (UNLIMITED ではない)、データの増加でクォータが満杯になった、テーブル/インデックスへの過剰なロード、誤った表領域への書き込み、セグメントが想定より速く増加した。","fix":"ユーザーのクォータを増やす: ALTER USER app_user QUOTA UNLIMITED ON tablespace_name; または特定の値を与える: QUOTA 500M ON users。現在の使用量を表示する: SELECT * FROM dba_ts_quotas WHERE username = 'APP_USER'。不必要に大きいセグメントをアーカイブ/削除するか、オブジェクトを適切な表領域に移す。","tags":["quota","quota","tablespace","space","space","user","user"]},{"code":"direct path read","title":"待機: バッファキャッシュを経由せず、セッションがブロックを直接 PGA に読み取っている","severity":"caution","meaning":"セッションが、データベースバッファキャッシュを経由せずにブロックを直接 PGA メモリに読み取る間、この待機イベントで時間を費やしている。通常は大規模な全表スキャンやパラレルクエリに関連する。","cause":"大きなテーブルの全スキャンによりディスクから多数のブロックを読み取る、パラレルクエリ、一時表領域に溢れるソート/ハッシュ操作、シリアル全スキャンでのシリアルダイレクトパス読み取りの判断、インデックスを使えないクエリ。","fix":"AWR/ASH で重い全スキャンを行う SQL を特定し、適切なインデックスを追加する。クエリのチューニングで大きなテーブルの不要なスキャンを減らす。ストレージの遅延 (I/O) を調査し、必要ならより高速なディスクに移す。並列度を見直す。TEMP に溢れる操作については PGA_AGGREGATE_TARGET のサイズを評価する。","tags":["wait","wait","direct path read","full scan","full table scan","io","pga"]},{"code":"latch: cache buffers chains","title":"待機: cache buffers chains ラッチの競合","severity":"danger","meaning":"バッファキャッシュ内のブロックを保護する cache buffers chains (CBC) ラッチで競合が発生している。この待機は、多数のセッションが頻繁にアクセスされる同じ (ホット) ブロックに到達しようとすると増加する。","cause":"頻繁に読み取られるホットブロック、大量の論理読み取りを発生させる非効率な SQL、ネステッドループ結合での同じインデックスルートブロックへの繰り返しアクセス、偏った大量の同時アクセス、小さいが頻繁に読み取られるテーブル。","fix":"最も多くの論理読み取りを発生させている SQL を特定し (V$SQL、ASH)、インデックス/アクセスプランを改善してバッファアクセスを減らす。ホットブロックを特定する (X$BH / 関連ビュー)。不要なネステッドループをハッシュ結合に変えることを検討する。小さく頻繁に読み取られる参照テーブルは、アクセスパターンを分散させるかキャッシュする。","tags":["latch","cache buffers chains","cbc","contention","contention","hot block","wait","wait"]}]},"errors/postgres-more.json":{"engineId":"postgres","engine":"PostgreSQL","order":2,"errors":[{"code":"42883","title":"undefined_function","severity":"caution","meaning":"クエリで呼び出された関数 (または演算子) が、この名前とこれらの引数型では見つからなかった。PostgreSQL は名前と引数型の両方で関数を解決するため、シグネチャが一致しないとこのエラーが発生する。","cause":"関数名のつづりの誤り、定義されたシグネチャと一致しない引数型 (例: テキストの代わりに数値)、明示的なキャストの欠如、関数のスキーマが search_path にない、必要な拡張機能がインストールされていない。","fix":"関数の存在を確認し、シグネチャを調べる: \\df function_name。引数を明示的にキャストする: SELECT fn(value::text)。スキーマ接頭辞を付けるか search_path を設定する。拡張機能が必要ならインストールする: CREATE EXTENSION extension_name; 演算子のエラーでは両辺の型を一致させる。","tags":["function","function not found","undefined","operator","cast","type conversion","42883"]},{"code":"42804","title":"datatype_mismatch","severity":"caution","meaning":"想定されるデータ型と指定されたデータ型が一致しない。例えば列への誤った型の値の代入、CASE の分岐が異なる型を返す、UNION の分岐の型が揃っていない。","cause":"列の型と互換性のない代入、CASE/COALESCE の分岐が異なる型を生成する、UNION の対応する列の型が異なる、RETURN した値が関数の戻り値の型と一致しない、boolean が期待される箇所に boolean でない値。","fix":"式を正しい型にキャストする: value::integer または CAST(value AS numeric)。CASE のすべての分岐が同じ型を返すようにする。UNION では両側の対応する列の型を揃える。WHERE 条件が boolean を返すことを確認する。","tags":["type","data type","mismatch","type mismatch","cast","union","42804"]},{"code":"22P02","title":"invalid_text_representation","severity":"caution","meaning":"変換時に、テキスト値が対象データ型の有効な表現ではなかった。例えばテキスト 'abc' を integer に変換しようとするとこのエラーが発生する。","cause":"数値列/パラメータへの非数値テキストの送信、空文字列 ('') の数値/日付への変換、UUID や enum に対する無効なテキスト、不正な形式の JSON、想定形式でない入力データ。","fix":"変換される値が実際に有効であることを確認する。型変換の前にアプリケーションで入力を検証する。空文字列を NULL に変換する: NULLIF(value, '')。PostgreSQL 16 以降で安全に変換するには、事前に pg_input_is_valid('abc', 'integer') で値をテストし、エラー詳細には pg_input_error_info() を使う。旧バージョンでは検証チェック (正規表現) を検討する。どの行が不正かを絞り込む。","tags":["cast","type conversion","invalid text","invalid input","integer","uuid","22P02"]},{"code":"22003","title":"numeric_value_out_of_range","severity":"caution","meaning":"数値が対象の型で許容される範囲外である。例えば integer 列への 20 億を超える値の書き込みや、numeric(5,2) 列には大きすぎる数値。","cause":"smallint/integer/bigint の上限超過、numeric(p,s) の精度/位取りの超過、算術オーバーフロー、合計/積が型の容量を超える、シーケンス が型の上限に到達。","fix":"列/パラメータをより広い型に変更する (integer の代わりに bigint、numeric の精度を上げる): ALTER TABLE my_table ALTER COLUMN my_column TYPE bigint; 業務ルールに従って値を丸める (ROUND) か検証する。中間計算がオーバーフローする場合は式を numeric で計算する。シーケンス のオーバーフローには型を広げる。","tags":["numeric","number","out of range","overflow","numeric overflow","integer","22003"]},{"code":"23514","title":"check_violation","severity":"caution","meaning":"CHECK 制約に違反した。挿入または更新された行が、テーブルに定義された論理条件 (例: price > 0) を満たさない。","cause":"業務ルールに違反するデータ (負の価格、無効なステータスコード、日付範囲の違反)、アプリケーション側の検証の欠如、データに対して厳しすぎる制約、一括ロード中のルール違反レコード。","fix":"エラーメッセージの制約名から違反した条件を特定する。定義を表示する: \\d table_name。条件を反転させて違反行を照会する。データを修正するか、ルールが本当に変わったなら制約を更新する: ALTER TABLE my_table DROP CONSTRAINT name; ALTER TABLE my_table ADD CONSTRAINT name CHECK (new_condition);","tags":["check","constraint","check constraint","violation","constraint violation","validation","23514"]},{"code":"22012","title":"division_by_zero","severity":"caution","meaning":"算術式でゼロによる除算 (または剰余) を試行した。PostgreSQL はゼロ除算を許可せず、クエリを中止する。","cause":"除数の列/式が 0 と評価される、比率/割合計算での分母がゼロ、ゼロである COUNT や SUM による除算、フィルタされていないデータ内の想定外のゼロ値。","fix":"分母がゼロのとき NULL を返すよう NULLIF を使う: numerator / NULLIF(denominator, 0)。必要なら COALESCE で結果をデフォルト値にする: COALESCE(numerator / NULLIF(denominator,0), 0)。または CASE WHEN denominator = 0 THEN NULL ELSE numerator/denominator END を使う。ゼロのケースは事前にデータから除外する。","tags":["division","divide","zero","divide by zero","nullif","arithmetic","22012"]},{"code":"42601","title":"syntax_error","severity":"caution","meaning":"SQL 文に構文エラーが見つかった。PostgreSQL はクエリを解析できず、エラーのおおよその位置 (position) を報告する。","cause":"カンマや括弧の欠落/余分、引用符なしで列名として使われた予約キーワード (user、order など)、セミコロンの欠落、コマンドのつづりの誤り、閉じられていない文字列リテラル、バージョン固有の構文の使用。","fix":"エラーメッセージの 'position' の値から問題箇所を特定し、その直前の部分を調べる。予約語は二重引用符で囲む: \"order\"。括弧と引用符の対応を確認する。複雑なクエリは分割してテストする。正しい構文は使用中のバージョンのドキュメントで確認する。","tags":["syntax","syntax error","parse","parser","keyword","position","42601"]},{"code":"42P07","title":"duplicate_table","severity":"caution","meaning":"作成しようとしたテーブル (または類似のオブジェクト) がすでに存在する。同じ名前のオブジェクトがあるため CREATE が失敗した。","cause":"既存のテーブルを CREATE TABLE で再作成した、スクリプトを 2 回実行した、マイグレーションを再適用した、または同名のビュー/シーケンス/インデックスとの名前の衝突。","fix":"オブジェクトがすでに存在する場合に作成をスキップするには IF NOT EXISTS を使う: CREATE TABLE IF NOT EXISTS my_table (...)。本当に作り直したい場合は先に削除する: DROP TABLE IF EXISTS my_table; マイグレーションを再実行しても安全 (冪等) にする。既存オブジェクトは \\dt で確認する。","tags":["duplicate","duplicate object","table","relation","create","already exists","42P07"]},{"code":"42701","title":"duplicate_column","severity":"caution","meaning":"テーブル定義または ALTER 操作で同じ列名が複数回使われた、またはすでに存在する列が再度追加された。","cause":"CREATE TABLE で同じ列名を 2 回記述した、ALTER TABLE ADD COLUMN で既存の列を追加した、コピー＆ペーストの誤り、マイグレーションの再実行。","fix":"テーブル定義内の重複した列名を削除するか名前を変更する。既存の列を再追加しないよう、事前に確認する: \\d table_name。バージョンが対応していれば安全に追加する: ALTER TABLE my_table ADD COLUMN IF NOT EXISTS my_column type; マイグレーションが冪等であることを確認する。","tags":["duplicate","duplicate column","column","column exists","alter","add column","42701"]},{"code":"3D000","title":"invalid_catalog_name","severity":"danger","meaning":"接続またはアクセスしようとしているデータベースが存在しない。指定された名前のデータベースが見つからなかった。","cause":"接続文字列のデータベース名のつづりの誤り、データベースが未作成または削除済み、大文字小文字の区別、誤ったサーバーへの接続、環境 (env) 設定での誤った名前。","fix":"既存のデータベースを一覧表示する: psql -l または SELECT datname FROM pg_database。接続文字列のデータベース名を修正する。必要なら作成する: CREATE DATABASE database_name; 正しいサーバー/ポートに接続していることを確認する。アプリケーション設定の DB 名を確認する。","tags":["database","database not found","catalog","does not exist","missing","connection","3D000"]},{"code":"3F000","title":"invalid_schema_name","severity":"caution","meaning":"参照されたスキーマが存在しないか、search_path 内に見つからない。指定された名前のスキーマがない。","cause":"スキーマ名のつづりの誤り、スキーマが作成されていない、search_path にスキーマが含まれていない、大文字小文字の違い、スキーマ接頭辞付きでオブジェクトにアクセスする際の誤った接頭辞。","fix":"既存のスキーマを一覧表示する: \\dn または SELECT schema_name FROM information_schema.schemata。スキーマ名を修正する。必要なら作成する: CREATE SCHEMA schema_name; search_path を設定する: SET search_path TO schema_name, public; 正しいスキーマ接頭辞でオブジェクトにアクセスする。","tags":["schema","schema not found","search_path","does not exist","missing","invalid","3F000"]},{"code":"0A000","title":"feature_not_supported","severity":"caution","meaning":"使用しようとしている機能は、このコンテキストまたはこの PostgreSQL バージョンではサポートされていない。要求された操作自体は妥当でも、現在の状況では適用できない。","cause":"そのバージョンでまだ利用できない構文/機能、特定の列/テーブル型でサポートされない ALTER、外部データラッパー (FDW) がサポートしない操作、論理レプリケーション/制約の組合せに関する制限、特定のデータ型で許可されない変換。","fix":"エラーメッセージ全体を読む。通常は何がサポートされていないかが明確に示されている。代替手段を使う (例: 列の型を直接変更する代わりに、新しい列の追加 + コピー + 名前変更)。新しいバージョンで機能が追加されている場合はアップグレードを検討する。FDW/拡張機能の制限に当たった場合はドキュメントを確認する。","tags":["not supported","unsupported","feature","unsupported feature","version","upgrade","0A000"]},{"code":"57P03","title":"cannot_connect_now","severity":"danger","meaning":"サーバーは現在接続を受け付けられない。通常はデータベースがまだ起動中か、リカバリを実行中である。システムの準備ができれば接続できる。","cause":"PostgreSQL が起動直後でまだ起動/リカバリ段階にある、クラッシュリカバリ、バックアップからのリストア中、スタンバイがまだクエリを受け付ける準備ができていない、シャットダウン中。","fix":"少し待ってから再接続する。起動が完了すればサーバーは接続を受け付ける。リカバリの進行状況をサーバーログで監視する。時間がかかる場合は、大量の WAL のリプレイまたはリカバリの問題がある可能性がある。アプリケーションに再試行ロジックを追加する。","tags":["connection","connection refused","starting up","startup","recovery","crash recovery","57P03"]},{"code":"2BP01","title":"dependent_objects_still_exist","severity":"caution","meaning":"削除対象のオブジェクトに他のオブジェクトが依存しているため、削除が阻止された。依存オブジェクトが存在する限り DROP は失敗する。","cause":"ビュー/外部キー/関数が依存しているテーブルの削除の試行、型やスキーマに依存するオブジェクト、CASCADE なしの DROP、他のオブジェクトから参照される列/シーケンス。","fix":"先に依存オブジェクトを削除するか、CASCADE 付きで削除する: DROP TABLE my_table CASCADE; (CASCADE は依存オブジェクトも削除する点に注意すること)。依存関係を確認するには、エラー詳細 (DETAIL 行) を読むか、pg_depend/関連カタログを調べる。削除の順序を正しく計画する。","tags":["dependency","dependent objects","cascade","drop","objects","object","2BP01"]},{"code":"55006","title":"object_in_use","severity":"danger","meaning":"対象オブジェクト (通常はデータベース) が他のセッションに使用されているため、操作を実行できない。例えばアクティブな接続があるデータベースは削除できない。","cause":"DROP DATABASE 時にデータベースへのオープン接続がある、使用中のオブジェクトに排他ロックが必要な操作、別のセッションがオブジェクトを保持している。","fix":"対象データベースへのオープン接続を特定して終了させる: SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'db_name' AND pid <> pg_backend_pid(); (必要なら) 新しい接続をブロックする。PostgreSQL 13 以降では接続を強制的に閉じながら削除する: DROP DATABASE db_name WITH (FORCE);","tags":["in use","being accessed","object","object in use","drop database","connection","55006"]},{"code":"22007","title":"invalid_datetime_format","severity":"caution","meaning":"日付/時刻型 (date、time、timestamp) への変換時に、テキスト値が有効な形式ではなかった。値が想定される日時形式と一致しない。","cause":"想定外の形式の日付テキスト (日/月/年の順序の混同)、無効な日/時の値、空文字列 ('') の日付への変換、要素の欠落または余分、ロケール/形式の不一致、to_timestamp/to_date の書式マスクの誤り。","fix":"正しい書式で日付テキストを変換する: to_date('2026-07-04', 'YYYY-MM-DD') または to_timestamp(str, 'YYYY-MM-DD HH24:MI:SS')。ISO 8601 形式 (YYYY-MM-DD) を優先する。空の値は NULLIF(value,'') で NULL にする。ロード前に入力データを検証し、不正な行を絞り込む。","tags":["date","date format","datetime","format","timestamp","to_date","22007"]}]},"errors/mysql-more.json":{"engineId":"mysql","engine":"MySQL","order":3,"errors":[{"code":"1052","title":"Column 'x' in field list is ambiguous（フィールドリストの列が曖昧）","severity":"caution","meaning":"クエリ内の複数のテーブルに同じ名前の列があり、テーブル/別名の接頭辞なしで使われているため、MySQL はどのテーブルに属するか判断できない。","cause":"結合された両方のテーブルに同じ名前の列がある (例: 両方に id)、その列が SELECT、WHERE、ON、GROUP BY、ORDER BY で修飾なし (接頭辞なし) で記述されている。","fix":"曖昧な列はすべてテーブル名または別名で修飾する: SELECT a.id, b.id FROM a JOIN b ON a.id = b.a_id; テーブルに短い別名を付け、競合するすべての列に接頭辞を付ける。共通列での結合では USING(my_column) で曖昧さを減らす。","tags":["ambiguous","ambiguous column","column","column name","join","alias","1052"]},{"code":"1136","title":"Column count doesn't match value count（列数と値の数が一致しない）","severity":"caution","meaning":"INSERT 文の列数が VALUES リストの値の数と一致しない。各列にはちょうど 1 つの値が必要である。","cause":"INSERT の列リストと値リストの長さが異なる、列リストなしの INSERT で値がテーブルの列数と一致しない、カンマの欠落/余分、テーブル構造が変わったがスクリプトが更新されていない。","fix":"列数と値の数を一致させる。常に明示的な列リストを使う: INSERT INTO my_table (a, b, c) VALUES (1, 2, 3); テーブル構造を確認する: DESCRIBE my_table; 値を列と 1 対 1 で対応させ、余分/不足しているカンマを修正する。","tags":["column count","column count mismatch","insert","values","mismatch","value count","1136"]},{"code":"1048","title":"Column 'x' cannot be null（列は NULL にできない）","severity":"caution","meaning":"NOT NULL として定義された列に NULL を挿入しようとした、またはその列を NULL に設定しようとした。必須フィールドを空にすることはできない。","cause":"INSERT で必須列に値が指定されていない、UPDATE で列を NULL に設定した、列に DEFAULT がない、アプリケーション/副クエリから空の値が渡された、厳格 SQL モードでは空の値が暗黙に補完されない。","fix":"必須列に有効な値を指定する。列に適切なデフォルトを定義する: ALTER TABLE my_table MODIFY my_column INT NOT NULL DEFAULT 0; ルールが不要なら NULL を許可する: ALTER TABLE my_table MODIFY my_column INT NULL; 空の値は送信前にアプリケーションで検証する。","tags":["not null","null","empty value","insert","cannot be null","mandatory","1048"]},{"code":"1292","title":"Incorrect datetime value / truncated incorrect value（日時の値が不正 / 不正な値の切詰め）","severity":"caution","meaning":"対象列の型 (特に日付/時刻や数値) への変換時に、値が無効または不正な形式だった。厳格モードでは MySQL はこれをエラーとして拒否する。","cause":"'0000-00-00' のような無効な日付や値、誤った日付形式、数値列への非数値テキスト、厳格 SQL モード (STRICT_TRANS_TABLES) が有効、異なる文字セット/照合順序による変換の問題。","fix":"値を列の型に対して有効な形式にする (日付は 'YYYY-MM-DD')。空/無効な日付の代わりに NULL を使う。必要なら STR_TO_DATE で明示的な書式を指定する: STR_TO_DATE(str, '%Y-%m-%d')。一時的な許容が必要なら sql_mode を見直すが、できればデータを修正する。絞り込んで問題の行を特定する。","tags":["datetime","date","truncated","incorrect value","strict mode","format","1292"]},{"code":"1406","title":"Data too long for column（列に対してデータが長すぎる）","severity":"caution","meaning":"列の定義された最大長より長い値が書き込まれた。例えば 20 文字の文字列は VARCHAR(10) 列に収まらない。","cause":"列幅がデータに対して小さすぎる、マルチバイト文字セット (utf8mb4) の文字が想定より多くの領域を使う、連結結果が長くなる、厳格 SQL モードが有効 (そうでなければ値は暗黙に切り詰められる)。","fix":"列を広げる: ALTER TABLE my_table MODIFY my_column VARCHAR(255); 非常に長い内容には TEXT 型を検討する。値を短くする必要がある場合は、アプリケーションまたは SUBSTRING で切り詰める。あふれた行を特定する: SELECT * FROM my_table WHERE CHAR_LENGTH(my_column) > 10; 入力検証を追加する。","tags":["data too long","length","varchar","column","column length","truncate","1406"]},{"code":"1071","title":"Specified key was too long; max key length is 767 bytes（キーが長すぎる）","severity":"caution","meaning":"作成しようとしたインデックス (またはキー) が許可される最大バイト長を超えた。特にマルチバイト文字セットでは、VARCHAR のインデックスはすぐにこの上限に達する。","cause":"utf8mb4 (1 文字 4 バイト) の幅の広い VARCHAR 列へのインデックス、古い InnoDB 行フォーマット (REDUNDANT/COMPACT。5.7 以前では innodb_large_prefix の無効化も)、複数列の複合インデックスの合計長が上限を超える、大きな主キー。","fix":"インデックス対象の列長を短くするか、プレフィックスインデックスを使う: CREATE INDEX idx ON my_table (my_column(191)); DYNAMIC/COMPRESSED 行フォーマットで 3072 バイトの上限に移行する (MySQL 8.0 では DYNAMIC がデフォルト。innodb_large_prefix は 8.0 で削除されており、必要なのは 5.7 以前のみ)。必要なら列の文字セット/長さを見直す。","tags":["index","index length","key too long","key","prefix","utf8mb4","1071"]},{"code":"1050","title":"Table already exists（テーブルがすでに存在する）","severity":"caution","meaning":"作成しようとしたテーブルがすでに存在する。同じ名前のテーブルがあるため CREATE TABLE が失敗した。","cause":"既存テーブルの再作成、スクリプトの 2 回実行、マイグレーションの再適用、別のオブジェクト (ビュー) が同じ名前を使用している。","fix":"テーブルがない場合にのみ作成するには IF NOT EXISTS を使う: CREATE TABLE IF NOT EXISTS my_table (...); 本当に作り直したい場合は先に削除する: DROP TABLE IF EXISTS my_table; 既存のテーブルを一覧表示する: SHOW TABLES; マイグレーションを再実行しても安全 (冪等) にする。","tags":["table exists","table already exists","duplicate","duplicate table","create table","1050"]},{"code":"1051","title":"Unknown table 'x'（不明なテーブル）","severity":"caution","meaning":"参照されたテーブルが存在しない。削除、変更、またはクエリの際に、指定された名前のテーブルが見つからなかった。","cause":"テーブル名のつづりの誤り、テーブルが作成されていないかすでに削除済み、誤ったデータベース (スキーマ) の選択、大文字小文字の区別 (Linux ではテーブル名は大文字小文字を区別する)、存在しないテーブルへの DROP TABLE。","fix":"既存のテーブルを一覧表示する: SHOW TABLES; 正しいデータベースを選択する: USE mydb; テーブル名とその大文字小文字を修正する。削除時のエラーを避けるには: DROP TABLE IF EXISTS my_table; 別スキーマにある場合は schema.table と修飾する。","tags":["unknown table","table not found","does not exist","drop","not exists","1051"]},{"code":"1091","title":"Can't DROP 'x'; check that column/key exists（DROP できない。列/キーの存在を確認）","severity":"caution","meaning":"ALTER TABLE で削除しようとした列、インデックス、または外部キーが存在しない。存在しないオブジェクトは削除できない。","cause":"DROP COLUMN/INDEX/FOREIGN KEY で存在しないオブジェクト名を指定した、名前のつづりの誤り、オブジェクトがすでに削除済み、外部キー名とインデックス名の混同、マイグレーションの 2 回目の実行。","fix":"オブジェクトの実際の名前を確認する: SHOW CREATE TABLE my_table; または SHOW INDEX FROM my_table; 正しい名前で削除する。外部キーにはそのシンボル名を使う: ALTER TABLE my_table DROP FOREIGN KEY fk_name; MySQL には DROP COLUMN IF EXISTS 構文はない (MariaDB のみ)。冪等なマイグレーションでは、先に information_schema.columns で列の存在を確認する: SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'my_table' AND column_name = 'my_column';","tags":["cant drop","cannot drop","column","index","foreign key","alter","1091"]},{"code":"1093","title":"You can't specify target table 'x' for update in FROM clause（FROM 句で更新対象テーブルは指定できない）","severity":"caution","meaning":"UPDATE または DELETE 文で、更新/削除対象のテーブル自体を副クエリ (FROM 内) のソースとして直接使うことはできない。MySQL は同じテーブルをこの形でターゲットとソースの両方にすることを許可しない。","cause":"UPDATE my_table ... WHERE id IN (SELECT ... FROM my_table ...) のように、副クエリが同じターゲットテーブルを直接読み取る。DELETE で同じテーブルを参照する副クエリ。","fix":"副クエリを導出テーブルで包んで新しい別名を付け、MySQL が別のコピーとして扱うようにする: UPDATE my_table SET c = 1 WHERE id IN (SELECT id FROM (SELECT id FROM my_table WHERE condition) AS t); 代わりに自己結合として記述する: UPDATE my_table a JOIN my_table b ON ... SET a.c = ...;","tags":["update","delete","target table","same table","subquery","derived table","1093"]},{"code":"1305","title":"PROCEDURE does not exist（プロシージャが存在しない）","severity":"caution","meaning":"呼び出されたストアドプロシージャまたは関数が、指定されたデータベースに見つからなかった。この名前のルーチンは定義されていない。","cause":"プロシージャ名のつづりの誤り、プロシージャが別のデータベースにあるか作成されていない、USE で誤ったスキーマを選択した、プロシージャを呼び出す EXECUTE 権限がない、大文字小文字の区別。","fix":"プロシージャの存在とスキーマを確認する: SHOW PROCEDURE STATUS WHERE Db = 'mydb'; 正しいデータベースを選択する: USE mydb; または完全修飾で呼び出す: CALL mydb.my_procedure(...); 必要な権限を付与する: GRANT EXECUTE ON PROCEDURE mydb.my_procedure TO app_user;","tags":["procedure","routine","does not exist","not found","stored procedure","call","1305"]},{"code":"1227","title":"Access denied; you need (at least one of) the PRIVILEGE（アクセス拒否。権限が必要）","severity":"danger","meaning":"ユーザーに、試行した操作に必要な権限がない。この操作には、アカウントに付与された権限を超える権利が必要である。","cause":"SUPER、PROCESS、RELOAD、CREATE USER などの管理権限の欠如、グローバルビュー/テーブルの読み取りに必要な権限が付与されていない、特定の操作 (SET GLOBAL、binlog へのアクセス) に昇格した権限が必要。","fix":"現在の権限を表示する: SHOW GRANTS FOR CURRENT_USER(); 権限のあるアカウントで必要な権限を付与する: GRANT PROCESS ON *.* TO 'app_user'@'host'; (GRANT は即座に有効になり、FLUSH PRIVILEGES は不要)。可能なら SUPER の代わりに動的権限 (例: SYSTEM_VARIABLES_ADMIN) を使う。最小権限の原則に従う。","tags":["access denied","privilege","missing privilege","permission","grant","access","1227"]},{"code":"3730","title":"Cannot drop table referenced by a foreign key constraint（外部キー制約で参照されているテーブルは削除できない）","severity":"danger","meaning":"別のテーブルの外部キーが参照しているため、テーブルを削除できない。参照が存在する限り DROP は阻止される。","cause":"FK で紐付いた子テーブルがまだ存在する状態で親テーブルを削除しようとした、依存関係の順序を守っていない、先に外部キーを削除していない。","fix":"先に参照している外部キーを削除する: ALTER TABLE child_table DROP FOREIGN KEY fk_name; その後テーブルを削除する。依存するテーブル/制約を特定する: SELECT * FROM information_schema.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_NAME = 'my_table'; 一括操作では SET FOREIGN_KEY_CHECKS = 0; を一時的に使えるが、注意して使い、終了後に 1 に戻す。","tags":["foreign key","fk","drop table","referenced","reference","constraint","3730"]},{"code":"2013","title":"Lost connection to MySQL server during query（クエリ中に MySQL サーバーとの接続が失われた）","severity":"danger","meaning":"クエリの実行中にクライアントと MySQL サーバー間の接続が切断された。サーバーが応答または結果を返す前に切れた。","cause":"長時間実行されるクエリによる net_read_timeout/net_write_timeout の超過、メモリ不足 (OOM) によるサーバーのクエリ/接続の終了、ネットワーク障害、max_allowed_packet の超過、サーバーのクラッシュまたは再起動、非常に大きな結果セット。","fix":"ネットワークの安定性とサーバーのエラーログを確認し、OOM やクラッシュがあったか調べる。タイムアウトを増やす: SET GLOBAL net_read_timeout = 120; 大きなクエリはバッチに分割する。max_allowed_packet を増やす。アプリケーションに接続の再試行ロジックを追加する。長いクエリを最適化する。","tags":["lost connection","connection dropped","timeout","network","network outage","oom","2013"]},{"code":"1153","title":"Got a packet bigger than 'max_allowed_packet' bytes（max_allowed_packet より大きいパケットを受信）","severity":"danger","meaning":"クライアントまたはサーバーが、許可される最大パケットサイズ (max_allowed_packet) より大きいデータパケットを送ろうとした。通常は大きな BLOB/TEXT 値や非常に大きな一括 INSERT で発生する。","cause":"非常に大きな BLOB/TEXT データの挿入、巨大な単一 INSERT または複数行の一括 INSERT、大きな結果を返すクエリ、小さい max_allowed_packet の値、mysqldump による大きな行のインポート。","fix":"max_allowed_packet を増やし (サーバーとクライアントの両方で): SET GLOBAL max_allowed_packet = 67108864; (64MB)、再接続する。恒久化するには my.cnf の [mysqld] に max_allowed_packet = 64M を追加する。大きな一括操作は小さなバッチに分割する。非常に大きな値を本当に格納する必要があるか評価する。","tags":["max_allowed_packet","packet","packet size","blob","large data","insert","1153"]},{"code":"1969","title":"MariaDB: Query execution was interrupted (max_statement_time exceeded)（クエリの実行が中断された）","severity":"caution","meaning":"MariaDB 固有 (ER_STATEMENT_TIMEOUT): クエリが max_statement_time で定義された最大実行時間を超えたため中断された。MySQL にはこのコードはなく、MySQL での相当はエラー 3024 (ER_QUERY_TIMEOUT、max_execution_time)。","cause":"MariaDB で、セッション/グローバルの max_statement_time の上限、または SET STATEMENT max_statement_time=N FOR ... で設定した上限の超過。非効率な実行計画、インデックスの欠如、大量データのスキャン、またはロック待機。","fix":"EXPLAIN でクエリを分析し、インデックスの追加と実行計画の改善で高速化する。クエリが本当に長時間実行される必要があるなら、MariaDB で上限を引き上げる: SET SESSION max_statement_time = 60; (秒) または SET STATEMENT max_statement_time = 60 FOR SELECT ...; MySQL を使う場合は 3024 の項目を参照する (max_execution_time、ミリ秒。MAX_EXECUTION_TIME ヒント)。大きな操作は分割する。","tags":["timeout","statement timeout","interrupted","query interrupted","max_execution_time","query","1969"]}]},"errors/mssql-more.json":{"engineId":"mssql","engine":"SQL Server","order":4,"errors":[{"code":"8134","title":"Divide by zero error encountered（ゼロ除算エラー）","severity":"caution","meaning":"算術式の除数がゼロのため、ゼロ除算エラーが発生した。SQL Server は除算を完了できず、クエリを停止する。","cause":"除数として使われる列または式が 0 と評価される、平均/比率計算での分母がゼロ、NULLIF なしの除算、データ内の想定外のゼロ値。","fix":"分母を NULLIF で保護する (例: value / NULLIF(denominator, 0))。結果は NULL となり、ISNULL/COALESCE でデフォルト値を指定できる。CASE WHEN denominator = 0 THEN NULL ELSE value/denominator END を使う。除算前に WHERE でゼロ値を除外する。必要なら SET ARITHABORT/ANSI_WARNINGS の動作を評価する。","tags":["math","arithmetic","divide by zero","division by zero","8134"]},{"code":"245","title":"Conversion failed when converting the value to data type（データ型への値の変換に失敗）","severity":"caution","meaning":"値を対象データ型に変換できなかった。例えば文字列値を int や date に変換する際、内容が不適切なため暗黙的/明示的な変換が失敗した。","cause":"非数値テキストの int/decimal への変換、無効な日付形式、列の比較での暗黙的な型変換、WHERE または JOIN 条件での互換性のない型、不正な形式の入力データ。","fix":"安全な変換関数を使う: TRY_CAST または TRY_CONVERT (失敗時に NULL を返す)。ISNUMERIC/TRY_CONVERT で不正な行を特定する。列の型を揃えて暗黙的な変換をなくす。入力を検証し、日付には明示的な書式 (例: CONVERT のスタイル) を使う。","tags":["conversion","type conversion","cast","convert","data type","245"]},{"code":"515","title":"Cannot insert the value NULL into column（列に NULL 値を挿入できない）","severity":"caution","meaning":"NOT NULL として定義された列に NULL 値を挿入または更新しようとした。列が NULL を許可しないため、操作は拒否された。","cause":"INSERT 文で必須列が省略されている、ソースデータの欠落/空のフィールド、デフォルト値のない NOT NULL 列、またはアプリケーションから送られた NULL。","fix":"必須列に有効な値を指定する。適切な列に DEFAULT 制約を追加する。ソースデータの欠落フィールドを検証し、ISNULL/COALESCE でデフォルト値を割り当てる。列が本当に必須である必要がなければ、NULL を許可するようスキーマを見直す。","tags":["null","not null","insert","constraint","constraint violation","515"]},{"code":"8115","title":"Arithmetic overflow error converting expression to data type（式のデータ型への変換で算術オーバーフロー）","severity":"caution","meaning":"算術演算または変換で生成された値が、対象データ型が保持できる範囲を超えた。数値が大きすぎるためオーバーフローが発生した。","cause":"int の範囲を超える合計/積 (SUM)、小さい型の列への大きな値の代入、decimal の精度/位取りの不足、または IDENTITY 値が型の上限に到達。","fix":"中間計算にはより広い型を使う (例: CAST(my_column AS bigint) で SUM する)。decimal の精度/位取りを増やす。データに合わせて列の型を大きくする。オーバーフローのおそれがある式は計算前に変換し、入力範囲を制限する。","tags":["overflow","arithmetic overflow","arithmetic","math","int","bigint","8115"]},{"code":"512","title":"Subquery returned more than 1 value（副クエリが複数の値を返した）","severity":"caution","meaning":"単一の値を期待するコンテキスト (=、<、>、比較または代入) で使われた副クエリが複数行を返した。SQL Server は単一のスカラー値を期待したが、複数の値に遭遇した。","cause":"比較のために単一値を返すと想定された副クエリが複数行を返す、一意でない一致条件、フィルターの欠如、または誤って構成された相関クエリ。","fix":"副クエリを 1 行に絞る (例: TOP 1、MAX/MIN、または適切な GROUP BY)。複数の値が想定されるなら = の代わりに IN または EXISTS を使う。JOIN で書き直す。副クエリが複数行を返す理由を調べ、フィルター/キーの条件を修正する。","tags":["subquery","scalar subquery","more than one","512","in","exists"]},{"code":"207","title":"Invalid column name（無効な列名）","severity":"caution","meaning":"クエリで参照された列名がテーブル/ビューに見つからなかった。その名前の列が存在しないか、スコープ外である。","cause":"つづり/大文字小文字の誤り、誤ったテーブル別名、まだ追加されていないか名前が変更された列、誤ったスキーマ/テーブルのコンテキスト、または引用符の代わりに角括弧を使うべきところで省略した。","fix":"列名とテーブルを確認する (sys.columns またはオブジェクト エクスプローラーで確認)。正しい別名とスキーマを使う。新しく追加した列については、オブジェクトが最新であることを確認し、必要ならストアドプロシージャを再コンパイルする。空白/特殊文字を含む名前には角括弧を使う。","tags":["column","column name","invalid column","invalid column name","alias","207"]},{"code":"156","title":"Incorrect syntax near the keyword（キーワード付近の構文が不正）","severity":"caution","meaning":"キーワード付近に構文エラーがある。予約語が想定外の位置で使われているため、SQL Server は文を解析できなかった。","cause":"予約語 (例: ORDER、USER、TABLE) を角括弧なしで列/オブジェクト名として使用した、カンマ/括弧の欠落、句の順序の誤り、または句 (WHERE、GROUP BY) の位置の誤り。","fix":"エラーが示すキーワードの周辺を調べる。予約語をオブジェクト名として使う場合は角括弧で囲む (例: [User])。カンマ、括弧の欠落、句の順序を修正する。クエリを部分に分けて構文をテストする。","tags":["syntax","syntax error","keyword","reserved word","156"]},{"code":"2812","title":"Could not find stored procedure（ストアドプロシージャが見つからない）","severity":"caution","meaning":"EXEC で呼び出されたストアドプロシージャが、現在のデータベース/スキーマのスコープで見つからなかった。その名前のプロシージャは存在しない。","cause":"プロシージャ名の誤字、スキーマ接頭辞の欠落または誤り (例: dbo. の省略)、プロシージャが別のデータベースにある、まだ作成されていない、または権限のため見えない。","fix":"プロシージャ名とスキーマを確認し、呼出しでは完全修飾名を使う (例: EXEC dbo.ProcedureName)。正しいデータベースにいることを確認する (USE DatabaseName)。プロシージャの存在を確認する (sys.procedures / OBJECT_ID)。必要な EXECUTE 権限を付与し、デプロイスクリプトが実行されたことを確認する。","tags":["stored procedure","procedure","sp","not found","procedure not found","2812"]},{"code":"8623","title":"The query processor ran out of internal resources and could not produce a query plan（クエリプロセッサの内部リソース不足で実行計画を生成できない）","severity":"danger","meaning":"過度に複雑なクエリのためにクエリプロセッサが内部リソースを使い果たし、実行計画を生成できなかった。クエリが大きすぎる/複雑すぎるため最適化できない。","cause":"非常に長い IN リストや多数の OR/UNION 句を持つクエリ、過剰な数の JOIN、自動生成された巨大なクエリ、パラメータが多すぎるクエリ、または過度に深い式ツリー。","fix":"クエリを簡素化する: 長い IN リストは一時テーブル/テーブル値パラメータに移し、OR 条件は UNION ALL や書き換えで減らし、複雑なクエリは分割する。JOIN の数を減らす。自動生成されるクエリはバッチに分ける。必要に応じてインデックスとクエリの設計を見直す。","tags":["query processor","internal resources","plan","complex query","8623","danger"]},{"code":"4104","title":"The multi-part identifier could not be bound（マルチパート識別子をバインドできない）","severity":"caution","meaning":"ドット区切りのマルチパート識別子 (例: table.column や alias.column) を解決できなかった。SQL Server はこの名前をクエリ内のテーブル/列にバインドできなかった。","cause":"誤った、または定義されていないテーブル別名、FROM/JOIN にないテーブルの参照、誤ったテーブルに帰属させた列、別名を定義した後に実際のテーブル名を使用、または誤字。","fix":"使用している別名が FROM/JOIN 句で定義されていることを確認する。列を正しいテーブル/別名で修飾する。テーブルに別名を付けた場合は、どこでも (実名ではなく) 別名を使う。不足しているテーブルを JOIN に追加し、名前を確認する。","tags":["identifier","multi-part","multi-part identifier","bind","alias","4104"]},{"code":"2714","title":"There is already an object named in the database（同名のオブジェクトがすでに存在する）","severity":"caution","meaning":"作成しようとしたものと同じ名前のオブジェクト (テーブル、ビュー、プロシージャなど) がデータベースにすでに存在する。名前の衝突により CREATE 文が失敗した。","cause":"同じ CREATE スクリプトの 2 回目の実行、既存オブジェクトを先に削除していない、異なるスキーマの想定、冪等でないデプロイ/マイグレーションスクリプト、または命名の衝突。","fix":"先にオブジェクトの存在を確認する: IF OBJECT_ID('dbo.Name') IS NULL で条件付きで作成するか、CREATE OR ALTER を使う (プロシージャ/ビュー/関数の場合)。必要なら既存オブジェクトを DROP して作り直す。マイグレーションスクリプトは冪等に記述する。正しいスキーマ/データベースで作業していることを確認する。","tags":["already exists","object exists","create","object","duplicate object","2714"]},{"code":"601","title":"Could not continue scan with NOLOCK due to data movement（データ移動のため NOLOCK でのスキャンを続行できない）","severity":"caution","meaning":"NOLOCK (READ UNCOMMITTED) でのスキャン中に、同時に発生したデータ移動 (ページ分割/移動) のためスキャンを続行できなかった。ロックなしの読み取りが不整合な状態に遭遇した。","cause":"NOLOCK ヒントまたは READ UNCOMMITTED 分離レベルでの読み取り中に、同時の更新/削除/ページ分割によってスキャン対象のページが移動した。","fix":"クエリを再実行する (通常は一時的)。可能な限り NOLOCK ヒントを避け、ブロックせずに一貫した読み取りを行うには READ COMMITTED SNAPSHOT (RCSI) 分離を使う。書き込みの多いテーブルでは、ダーティリードよりスナップショット分離を優先する。","tags":["nolock","scan","data movement","601","isolation","read uncommitted"]},{"code":"50000","title":"RAISERROR で発生させたカスタムエラー","severity":"caution","meaning":"メッセージ ID を指定せずに RAISERROR で発生させたカスタム (ユーザー定義) エラーのデフォルト番号 (50000)。アプリケーション/プロシージャのロジックが意図的にエラーを発生させた。","cause":"業務ルール違反、検証の失敗、意図的なフロー制御、またはカスタム例外メッセージのために、ストアドプロシージャやスクリプト内で RAISERROR または THROW によって発生させたカスタムエラー。","fix":"RAISERROR/THROW のメッセージテキストを読み、実際の業務ルール違反を把握する。アプリケーション側で TRY...CATCH によりこのエラーを捕捉し、ERROR_MESSAGE()/ERROR_NUMBER() で詳細を取得する。sp_addmessage でメッセージを定義し、カスタムエラーに意味のある番号を付ける。業務ロジック内の発生条件を修正する。","tags":["raiserror","custom error","user-defined error","throw","50000","try catch"]},{"code":"3902","title":"The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION（COMMIT に対応する BEGIN TRANSACTION がない）","severity":"caution","meaning":"COMMIT TRANSACTION が実行されたが、対応するオープンな BEGIN TRANSACTION がない。トランザクション数 (@@TRANCOUNT) がゼロのため、コミットするトランザクションが見つからなかった。","cause":"BEGIN/COMMIT/ROLLBACK の使用の不均衡、エラー後にトランザクションがすでにロールバックされている、ネストしたトランザクション数の管理の誤り、または CATCH ブロックで ROLLBACK 後に再度 COMMIT を呼び出した。","fix":"BEGIN と COMMIT の数を揃える。コミット前に @@TRANCOUNT を確認する (IF @@TRANCOUNT > 0 COMMIT)。TRY...CATCH では、エラー時に XACT_STATE()/@@TRANCOUNT に基づいて ROLLBACK し、不要な COMMIT を防ぐ。ネストしたトランザクションのロジックを見直す。","tags":["transaction","commit","begin","trancount","transaction count","3902"]}]},"errors/mongodb-more.json":{"engineId":"mongodb","engine":"MongoDB","order":5,"errors":[{"code":"121","title":"DocumentValidationFailure","severity":"caution","meaning":"挿入または更新されるドキュメントが、コレクションに定義された JSON Schema の検証ルール (validator) を満たさないため拒否された。","cause":"ドキュメントがスキーマに適合しない: 必須フィールドの欠落、誤った BSON 型、許容範囲/パターン外の値、追加フィールドの禁止、または validationAction が 'error' の状態でのルール違反。","fix":"エラー詳細 (errInfo) を調べ、どのルールに違反したかを確認する。ドキュメントをスキーマに適合させる: 必須フィールドを追加し、型を修正する。collMod でコレクションの validator を見直す。validationLevel/validationAction は一時的に緩和できるが、データ品質のためにはルールを維持するのが望ましい。","tags":["validation","validation","schema","schema","121","document"]},{"code":"40","title":"ConflictingUpdateOperators","severity":"caution","meaning":"更新で、同じフィールド (パス) に競合する複数の更新演算子が適用された。MongoDB は 1 回の操作で同じパスを 2 回変更できない。","cause":"1 つの更新ドキュメント内で同じフィールドを対象とする競合する演算子 (例: $set と $inc の両方、または親パスと子パスの同時変更)、誤って構成された更新、またはネストしたパスの競合。","fix":"同じフィールドに対する競合する演算子を 1 つの演算子にまとめるか、更新を別々の操作に分割する。親パスと子パス (例: a と a.b) を同時に変更しない。更新ドキュメントを見直し、各フィールドが 1 回だけ変更されるようにする。","tags":["update","update","operator","conflict","conflict","40"]},{"code":"66","title":"ImmutableField (_id は更新不可)","severity":"caution","meaning":"不変フィールド、通常はドキュメントの _id フィールドを更新しようとした。_id はドキュメント作成後に変更できない。","cause":"_id フィールドを変更しようとする更新、許可されない方法でのシャードキーフィールドの更新、または不変として扱われるフィールドへの新しい値の設定。","fix":"_id の値を更新しない。別の _id が必要なら、新しい _id でドキュメントを挿入し、古いものを削除する (insert + delete)。シャードキーの更新は MongoDB のルールに従う。更新ドキュメントから不変フィールドを除き、変更可能なフィールドのみを設定する。","tags":["immutable","_id","immutable","update","shard key","66"]},{"code":"2","title":"BadValue","severity":"caution","meaning":"コマンドまたはクエリに無効な、または想定外の値が渡された。MongoDB は引数を許容される値として解釈できなかった。","cause":"無効な演算子の引数、範囲外の数値、サポートされないオプション値、不正な形式のソート指定、不正な形式のクエリ式、またはパラメータの不適切な組合せ。","fix":"エラーメッセージのフィールド/値のヒントに基づいて引数を修正する。コマンドとクエリのオプションをドキュメントと照らして検証する。sort/projection/aggregate 式の形式を確認する。値の範囲と型を有効な範囲にする。","tags":["badvalue","invalid value","argument","2","query"]},{"code":"14","title":"TypeMismatch","severity":"caution","meaning":"指定された値の型が想定される BSON 型と一致しない。フィールドまたは引数には別のデータ型が想定されていた。","cause":"数値が想定される箇所にテキスト、日付の代わりに文字列、配列が想定される箇所に単一値を送信、aggregate/クエリ演算子に誤った型の引数を渡した、またはスキーマ内の型の不整合。","fix":"フィールド/引数に正しい BSON 型を指定する。データ保存前にアプリケーション層で型を変換する (例: 数値は実際の Number 値として書き込む)。クエリ演算子と aggregate 演算子が想定する型を確認する。スキーマ validator で型の一貫性を徹底する。","tags":["typemismatch","type mismatch","bson","type","14"]},{"code":"10334","title":"BSONObjectTooLarge","severity":"danger","meaning":"BSON ドキュメントが許可される最大サイズ (16 MB) を超えた。MongoDB はこの上限を超える単一ドキュメントを格納することも返すこともできない。","cause":"ドキュメントへのデータ/配列要素の継続的な追加による 16 MB 上限の超過、非常に大きな埋込み配列、集計で生成された巨大なドキュメント、またはドキュメントに直接格納された大きなバイナリデータ。","fix":"データモデルを見直す: 大きな配列は別のコレクションに分割し、参照モデルを使う。大きなバイナリファイルには GridFS を使う。際限なく増える配列に上限を設ける (例: capped/bucket パターン)。集計ステージではドキュメントサイズを管理する。","tags":["bson","16mb","too large","large document","gridfs","10334","danger"]},{"code":"46","title":"LockBusy","severity":"caution","meaning":"要求されたロックまたはリソースが別の操作に保持されていたため即座に取得できず、操作は待機せずに拒否された。タイムアウトで終わるロック待機は別のコード (24 LockTimeout) である。","cause":"同じコレクションやデータベースに対する同時の管理/DDL 操作 (例: 2 つの同時インデックス作成、collMod、drop、rename)、進行中のメンテナンス操作との競合、またはロックを短時間も待てない内部操作がビジーなリソースに当たった。","fix":"競合している操作を特定する: db.currentOp() で同じ名前空間で実行中の DDL やメンテナンス操作を調べる。競合する操作の終了後にコマンドを再試行する。管理/DDL 操作はシリアライズし、同じコレクションで並行実行しない。解消しない場合は、mongod のログでリソースを保持している操作を調査する。","tags":["lock","lock","lockbusy","busy","ddl","46"]},{"code":"96","title":"OperationFailed","severity":"danger","meaning":"汎用の操作失敗。コマンドの実行中に予期しないエラーが発生し、操作を完了できなかった。より具体的なコードがない場合に使われる汎用エラーである。","cause":"サーバー側の内部エラー、リソースの枯渇、不整合な状態、サブシステムの障害 (ストレージ、レプリケーション)、または特定のコマンド固有のさまざまな失敗条件。","fix":"エラーメッセージの全文とサーバーログ (mongod.log) を調べて根本原因を特定する。操作を再試行する。状態は一時的な可能性がある。リソース (ディスク、メモリ) とレプリカセットの健全性を確認する。問題が再発する場合は、コマンドとその入力データを見直す。","tags":["operationfailed","operation failed","generic error","96","danger"]},{"code":"72","title":"InvalidOptions","severity":"caution","meaning":"コマンドに無効な、または互いに互換性のないオプションが渡された。指定されたオプションの組合せはこのコマンドでサポートされていない。","cause":"サポートされないオプション名、相互に排他的なオプションの同時使用、実行中のバージョンで無効なオプション、無効な write concern/read concern の組合せ、またはインデックス/照合順序オプションの競合。","fix":"コマンドが受け付けるオプションをドキュメントで確認し、互換性のないものを削除する。使用中のバージョンがそのオプションをサポートしていることを確認する。write/read concern と照合順序の設定を見直す。有効なオプションの組合せのみを使う。","tags":["invalidoptions","invalid option","options","72","command"]},{"code":"9","title":"FailedToParse","severity":"caution","meaning":"送信されたコマンド、クエリ、または式をサーバーが解析できなかった。構造が構文的に無効か、想定された形式ではない。","cause":"不正な形式の JSON/BSON 構造、フィールドの欠落または余分、演算子の誤った使用、無効な集計パイプライン構文、または想定形式と一致しないコマンドドキュメント。","fix":"ドキュメントに従ってコマンド/クエリ/パイプラインの構造を修正する。JSON 構造を検証する (括弧/カンマの欠落、誤ったフィールド名)。集計ステージの構文を確認する。演算子が正しく使われ、引数が想定形式で指定されていることを確認する。","tags":["failedtoparse","parse","parsing","syntax","9","query"]},{"code":"134","title":"ReadConcernMajorityNotAvailableYet","severity":"caution","meaning":"majority の read concern での読み取りが要求されたが、過半数でコミットされたスナップショットがまだ利用できない。サーバーは現在この一貫性レベルを提供できない。","cause":"レプリカセットが起動直後または不安定、過半数への書き込みがまだコミットされていない、レプリケーションの遅延、到達可能なメンバーが不足、またはクラスタがまだ起動段階にある。","fix":"少し待って再試行する。過半数のスナップショットが利用可能になれば読み取りは成功する。レプリカセットの健全性とレプリケーションの遅延を確認する (rs.status())。十分なメンバーが稼働していることを確認する。必須でなければ、より低い read concern (例: local) を検討する。","tags":["readconcern","majority","majority","replica","134","consistency"]},{"code":"202","title":"NetworkInterfaceExceededTimeLimit","severity":"danger","meaning":"ネットワーク要求 (例: メンバー間の通信やクライアント接続) が時間制限を超えた。ネットワークのタイムアウトにより操作を完了できなかった。","cause":"ネットワークの遅延/障害、遅いまたは到達できない対象メンバー、過剰な負荷、誤って設定されたタイムアウト値、DNS/接続の問題、または地理的に離れたメンバー。","fix":"ネットワークの接続性と遅延を確認し、メンバー間の到達性を検証する。対象メンバーの健全性と負荷を調べる。環境に合わせてタイムアウト設定 (connect/socket timeout) を構成する。再試行ロジックを追加する。解消しない場合は、インフラ/ネットワーク構成を見直す。","tags":["network","network","timeout","timeout","202","danger"]}]},"errors/redis-more.json":{"engineId":"redis","engine":"Redis","order":6,"errors":[{"code":"NOPERM","title":"NOPERM this user has no permissions to run the command or access one of the keys（コマンド実行またはキーアクセスの権限がない）","severity":"caution","meaning":"認証済みの ACL ユーザーが、実行しようとしたコマンドまたはアクセスするキーに対する権限を持っていない。Redis は ACL ルールに従って操作を拒否する。","cause":"ACL ユーザーにコマンド/カテゴリの権限がない、キーパターンが許可リストにない、チャネル (pub/sub) の制限がある、またはユーザーに狭い範囲の権限しか与えられていない。","fix":"ユーザーの権限を調べる: ACL GETUSER app_user。必要なコマンド/カテゴリとキーパターンを追加する (例: ACL SETUSER app_user +get +set ~app:*)。最小権限に従い、必要な権限のみを付与する。正しいユーザーで接続していることを確認する。","tags":["noperm","acl","privilege","permission denied","permission","user"]},{"code":"ERR value is not an integer or out of range","title":"ERR value is not an integer or out of range（値が整数でないか範囲外）","severity":"caution","meaning":"整数を期待するコマンド (例: INCR、EXPIRE、LPOP の count) が、非数値または範囲外の値を受け取った。Redis はその値を整数として解釈できなかった。","cause":"INCR/DECR の対象キーがテキスト (整数でない) 値を保持している、引数が数値ではなくテキストで指定された、数値が範囲に対して大きすぎる/小さすぎる、または負の値が許可されない箇所での負の値。","fix":"キーの値を確認する: GET mykey と TYPE mykey。数値操作では、キーが整数値を保持していることを確認する。引数が正しい範囲内の有効な整数であることを確認する。必要なら値をリセットする (SET mykey 0) か、正しい型で作り直す。","tags":["err","integer","not an integer","range","incr","value"]},{"code":"ERR value is not a valid float","title":"ERR value is not a valid float（値が有効な float ではない）","severity":"caution","meaning":"小数 (float) を期待するコマンド (例: INCRBYFLOAT、ZADD のスコア) が、有効な浮動小数点数でない値を受け取った。Redis はその値を float として解析できなかった。","cause":"INCRBYFLOAT の対象キーが有効な float を保持していない、非数値の引数、誤った小数点記号 (カンマではなくドットが必要)、または不正な形式の数値。","fix":"GET でキーの値を確認し、有効な float が含まれていることを確認する。小数点記号にはドットを使う (例: 3.14)。引数が数値であり、正しい形式であることを確認する。必要なら値を有効な float にリセットする。","tags":["err","float","decimal","incrbyfloat","zadd","value"]},{"code":"ERR increment or decrement would overflow","title":"ERR increment or decrement would overflow（増減でオーバーフローする）","severity":"caution","meaning":"結果が 64 ビット符号付き整数の範囲をオーバーフローするため、INCR/DECR (または INCRBY/DECRBY) が拒否された。値が上限または下限を超えることになる。","cause":"キーの値が int64 の上限 (約 922 京) に非常に近く、増減でオーバーフローする、非常に大きな INCRBY の引数、またはカウンタが制御されずに増え続けている。","fix":"カウンタ値が int64 の範囲内に収まるよう設計する。大きなカウントにはスケーリングや定期的なリセットを適用する。増分 (INCRBY の引数) を妥当な範囲に保つ。非常に大きな値が必要なら、アプリケーション層で別のカウント方式を使う。","tags":["err","overflow","integer overflow","incr","decr","int64"]},{"code":"ERR max number of clients reached","title":"ERR max number of clients reached（クライアントの最大数に到達）","severity":"danger","meaning":"接続クライアント数が maxclients の上限に達し、新しい接続を受け付けられない。Redis はそれ以上のクライアント接続を拒否する。","cause":"接続リーク (接続がクローズされない)、不十分な maxclients の値、誤って構成された接続プール、クライアントの急増、またはオペレーティングシステムのファイルディスクリプタ上限が低い。","fix":"現在の接続を調べる: CLIENT LIST と INFO clients。接続リークを修正し、クライアントプールのサイズを適切に設定して接続を再利用する。必要なら maxclients (CONFIG SET maxclients) と OS の ulimit (ファイルディスクリプタ) の上限を引き上げる。アイドル接続にタイムアウトを設定する。","tags":["err","maxclients","connection","client","limit","danger"]},{"code":"BUSYKEY","title":"BUSYKEY Target key name already exists（対象キー名がすでに存在する）","severity":"caution","meaning":"対象キーがすでに存在するため、RESTORE (または類似のコマンド) が失敗した。Redis はデフォルトでは既存のキーを上書きしない。","cause":"RESTORE で復元しようとしたキー名がデータベースにすでに存在する、以前のデータが整理されていない、または同じキーへの複数回の復元試行。","fix":"既存のキーを上書きしたい場合は、RESTORE に REPLACE オプションを追加する。代わりに、先に対象キーを削除する (DEL mykey) か、別のキー名を使う。事前に EXISTS mykey で存在を確認する。","tags":["busykey","restore","already exists","target key","replace","key"]},{"code":"ERR no such key","title":"ERR no such key（キーが存在しない）","severity":"caution","meaning":"操作対象のキーがデータベースに見つからなかった。RENAME、DUMP、MOVE など既存のキーを必要とするコマンドは、存在しないキーには機能しない。","cause":"キーが作成されていない、TTL により期限切れで削除された、キー名の誤り/つづりの誤り、誤ったデータベース (SELECT) 番号、またはキーがすでに DEL で削除されている。","fix":"キーの存在を確認する: EXISTS mykey。正しいキー名と正しいデータベース (SELECT db) を使っていることを確認する。RENAME にはソースキーの存在が必要である。TTL で期限切れになるキーのロジックを見直す。必要ならキーを作り直す。","tags":["err","no such key","key not found","rename","dump","key"]},{"code":"ERR DUMP payload version or checksum are wrong","title":"ERR DUMP payload version or checksum are wrong（DUMP ペイロードのバージョンまたはチェックサムが不正）","severity":"caution","meaning":"RESTORE に渡されたシリアライズデータ (DUMP 出力) が無効である。バージョンに互換性がないか、チェックサムの検証に失敗した。Redis はデータを安全に復元できない。","cause":"DUMP データの破損/改変、互換性のない異なる Redis バージョン間での移動、エンコード/デコード時の破損 (例: 誤ったバイト処理)、またはペイロードの欠落/切詰め。","fix":"DUMP データが無傷 (バイナリセーフ) で転送されることを確認する。テキストエンコーディングを経由せず、生のバイトとして転送する。ソースとターゲットの Redis バージョンに互換性があることを確認する。新しく DUMP を取得して再転送する。移行には RESTORE の代わりに MIGRATE コマンドを検討する。","tags":["err","dump","restore","checksum","checksum mismatch","version"]},{"code":"NOREPLICAS","title":"NOREPLICAS Not enough good replicas to write（書き込みに十分な正常レプリカがない）","severity":"danger","meaning":"min-replicas-to-write の設定により、健全なレプリカが不足しているため書き込みが拒否される。Redis はデータの安全性のために書き込みをブロックする。","cause":"接続済み/最新のレプリカの不足、レプリカのクラッシュ、min-replicas-max-lag の上限を超えるレプリケーションの遅延、ネットワークの問題、またはフェイルオーバー後のレプリカの欠如。","fix":"レプリカの状態を確認する: INFO replication。停止したレプリカを復旧させ、レプリケーションの遅延を減らす。ネットワーク接続を修正する。環境に合わせて min-replicas-to-write / min-replicas-max-lag の設定を見直す (耐久性と可用性のバランス)。十分な数のレプリカを用意する。","tags":["noreplicas","replica","write","min-replicas","replication","danger"]},{"code":"ERR This instance has cluster support disabled","title":"ERR This instance has cluster support disabled（クラスタサポートが無効）","severity":"caution","meaning":"クラスタコマンド (CLUSTER ...) が実行されたが、この Redis インスタンスはクラスタモードで起動されていない。クラスタサポートが無効なため、コマンドは拒否された。","cause":"cluster-enabled yes が設定されていない、インスタンスがスタンドアロンモードで動作している、スタンドアロンサーバーにクラスタコマンドを送った、または誤ったサーバーへの接続。","fix":"クラスタ機能を使いたい場合は、インスタンスをクラスタモードで起動する: 構成で cluster-enabled yes を設定して再起動し、ノードからクラスタを構成する。スタンドアロンモードのままならクラスタコマンドを使わない。正しい (クラスタ) サーバーに接続していることを確認する。","tags":["err","cluster","cluster mode","disabled","standalone","config"]},{"code":"ERR unknown subcommand","title":"ERR unknown subcommand or wrong number of arguments（不明なサブコマンドまたは引数の数の誤り）","severity":"caution","meaning":"コンテナコマンド (例: CONFIG、CLIENT、ACL、XINFO) が無効なサブコマンドを受け取ったか、サブコマンドに誤った数の引数が送られた。Redis はサブコマンドを認識できなかった。","cause":"サブコマンド名の誤字、使用中の Redis バージョンに存在しないサブコマンド、引数の数の誤り/不足、またはサブコマンドの構文の誤り。","fix":"正しいサブコマンド名と引数を使う。コマンドの HELP サブコマンドを参照する (例: CONFIG HELP、CLIENT HELP)。使用中の Redis バージョンがそのサブコマンドをサポートしていることを確認する。ドキュメントに従って引数の数と構文を修正する。","tags":["err","subcommand","unknown subcommand","argument","config","client"]},{"code":"ERR Client sent AUTH, but no password is set","title":"ERR AUTH <password> called without any password configured for the default user (Redis 6+) / ERR Client sent AUTH, but no password is set (Redis <6)（パスワード未設定のサーバーへの AUTH）","severity":"caution","meaning":"クライアントが AUTH で認証しようとしたが、サーバーにパスワード (requirepass) も ACL パスワードも定義されていない。検証する資格情報がないため AUTH は拒否された。この場合 Redis 6 以降は \"ERR AUTH <password> called without any password configured for the default user. Are you sure your configuration is correct?\" を返す。\"Client sent AUTH, but no password is set\" は Redis 6 より前のメッセージである。","cause":"サーバーの requirepass が空、クライアントが不要な AUTH を送っている、サーバーにはパスワードがないのに接続文字列にパスワードが定義されている、または構成の不一致。","fix":"サーバーがパスワードを必要としない場合は、クライアントから AUTH コマンド/パスワード設定を削除する。パスワード保護が必要なら、サーバーで requirepass を設定する (CONFIG SET requirepass password) か、ACL ユーザーにパスワードを定義する。クライアントとサーバーの構成を一致させる。","tags":["err","auth","password","requirepass","authentication","acl"]}]},"errors/elasticsearch-more.json":{"engineId":"elasticsearch","engine":"Elasticsearch","order":7,"errors":[{"code":"action_request_validation_exception","title":"action_request_validation_exception","severity":"caution","meaning":"要求が実行前の検証に失敗した。必須フィールドが欠落しているかフィールドが無効なため、Elasticsearch は操作を拒否する。","cause":"必須パラメータの欠如 (例: インデックス名の未指定)、空のボディ、無効なフィールドの組合せ、または bulk/index 要求で必要な情報が指定されていない。","fix":"エラーメッセージの欠落/無効なフィールドの一覧を確認し、必須フィールドを指定する。API ドキュメントに従って要求のボディとパラメータを補う。bulk 要求では、各アクション行に正しいメタデータと正しいボディがあることを確認する。","tags":["validation","validation error","request","request error","action"]},{"code":"index_closed_exception","title":"index_closed_exception","severity":"caution","meaning":"対象インデックスがクローズされている。クローズされたインデックスは読み取り/書き込み要求を処理しないため、操作を実行できなかった。","cause":"インデックスが以前に close API でクローズされた、メンテナンス/ILM 操作中にクローズされた、またはリソース節約のために無効化された。","fix":"インデックスを再オープンする: POST /index_name/_open。オープン後、シャードが割り当てられる (green/yellow) まで待つ。インデックスがクローズされた理由 (ILM ポリシー、手動操作) を調査する。アクセス頻度の低いインデックスをクローズしておく戦略を見直す。","tags":["index closed","closed index","open","index","closed"]},{"code":"unavailable_shards_exception","title":"unavailable_shards_exception","severity":"danger","meaning":"操作に必要な 1 つ以上のシャードが利用できないため、要求 (通常は書き込み) を完了できなかった。十分なアクティブシャードコピーが見つからなかった。","cause":"ノードのクラッシュ/離脱による未割り当てのシャード、ディスクウォーターマークの超過、レプリカの欠如、満たされない wait_for_active_shards 条件、またはクラスタの健全性が red。","fix":"クラスタとシャードの健全性を確認する: GET _cluster/health と GET _cat/shards?v。シャードが未割り当てである理由を調査する: GET _cluster/allocation/explain。停止したノードを復旧させ、ディスク領域を解放し (ウォーターマーク)、レプリカ設定を見直す。必要なら wait_for_active_shards を適切に設定する。","tags":["shard","unavailable","inaccessible","cluster","allocation","danger"]},{"code":"query_shard_exception","title":"query_shard_exception","severity":"caution","meaning":"特定のシャードでの実行中にクエリが失敗した。通常はクエリがマッピングと互換性がないか、構造が無効であるために発生する。","cause":"存在しないフィールドや誤った型のフィールドへのクエリ、text フィールドでの集計/ソートの試行 (fielddata 無効)、無効なクエリ構文、誤った解析、または互換性のないフィールド型。","fix":"エラー詳細のフィールド/理由を確認する。照会したフィールドのマッピングを確認する: GET /index/_mapping。ソート/集計には text ではなく keyword サブフィールド (field.keyword) を使う。クエリ構文を修正し、フィールド型がクエリと互換であることを確認する。","tags":["query","query error","shard","mapping","fielddata","query shard"]},{"code":"script_exception","title":"script_exception","severity":"caution","meaning":"スクリプト (通常は Painless) のコンパイルまたは実行中にエラーが発生した。スクリプトの記述が誤っているか、実行時に例外を発生させた。","cause":"Painless の構文エラー、null 値へのアクセス、型の不一致、存在しないフィールド/変数の使用、スクリプトのコンパイル上限の超過、または許可されていない API の呼出し。","fix":"エラーメッセージのコンパイル/実行時の詳細を確認する。スクリプトの構文とフィールドアクセスを修正し、null チェックを追加する (例: doc['field'].size() > 0)。頻繁に使うスクリプトはパラメータ化して (stored/params) コンパイル上限を超えないようにする。正しいフィールド名と型を使う。","tags":["script","painless","compilation","runtime","script exception"]},{"code":"number_format_exception","title":"number_format_exception","severity":"caution","meaning":"数値であるべき値を数値に変換できなかった。フィールドまたはパラメータが数値を期待する箇所に、無効な/非数値の文字列が指定された。","cause":"数値 (integer/long/double) フィールドへの非数値テキストの送信、空文字列を数値に変換しようとした、誤った小数形式、またはマッピングと互換性のない入力データ。","fix":"フィールドに有効な数値を送る。インデックス作成前にソースデータを検証/変換する。空の値には null を使うか、フィールドを省略する。マッピングの coerce 設定とフィールド型を見直す。小数点記号にはピリオドを使う。","tags":["number format","number","conversion","numeric","format"]},{"code":"connect_transport_exception","title":"connect_transport_exception","severity":"danger","meaning":"transport (9300) 層でノードに接続できなかった。ノード間またはクライアントとクラスタ間の通信を確立できず、操作を実行できなかった。","cause":"対象ノードの停止/到達不能、ネットワーク/ファイアウォールの問題、誤った transport アドレス/ポート、TLS 構成の不一致、DNS の問題、またはクラスタ名/バージョンの不一致。","fix":"対象ノードが稼働しており、transport ポート (デフォルト 9300) にネットワーク経由で到達できることを確認する。ファイアウォール/ネットワークのルールと discovery の構成を確認する。TLS/証明書の設定がすべてのノードで一致していることを確認する。ノードのログを確認し、cluster.name/バージョンの互換性を確認する。","tags":["transport","connection","connect","network","node","danger"]},{"code":"repository_missing_exception","title":"repository_missing_exception","severity":"caution","meaning":"スナップショット/リストア操作で参照されたスナップショットリポジトリが見つからなかった。指定された名前で登録されたリポジトリがない。","cause":"リポジトリが登録されていない、名前の誤字、リポジトリが削除された、別のクラスタで定義されている、またはクラスタ状態のリセット後に再登録されていない。","fix":"登録済みのリポジトリを一覧表示する: GET _snapshot/_all。正しい名前と設定でリポジトリを再登録する: PUT _snapshot/repo_name (type と settings を指定)。リポジトリ名のつづりが正しいことを確認する。共有リポジトリ (fs/s3 など) へのアクセスがすべてのノードで機能することを確認する。","tags":["repository","snapshot repository","snapshot","missing","backup","restore"]},{"code":"concurrent_snapshot_execution_exception","title":"concurrent_snapshot_execution_exception","severity":"caution","meaning":"競合するスナップショット操作が同時に実行中のため、新しいスナップショット/リストア要求が拒否された。リポジトリまたはインデックスで別のスナップショット操作がまだ進行中である。","cause":"前回のスナップショットがまだ進行中、同じインデックスに影響する同時のスナップショット/リストアの競合、SLM (スナップショットライフサイクル) ポリシーと手動スナップショットの衝突、または短い間隔でのトリガー。","fix":"実行中のスナップショットを確認する: GET _snapshot/repo/_current と GET _snapshot/_status。現在の操作の完了を待つか、必要なら取り消す: DELETE _snapshot/repo/snapshot_name。スナップショットが重ならないようスケジュールする。手動操作を SLM と調整する。","tags":["snapshot","concurrent","conflict","simultaneous","slm","backup"]},{"code":"invalid_index_name_exception","title":"invalid_index_name_exception","severity":"caution","meaning":"指定されたインデックス名が Elasticsearch の命名規則に従っていない。名前に無効な文字が含まれているか、形式の規則に違反している。","cause":"大文字、許可されていない文字 (\\ / * ? \" < > | 空白 , #)、_、-、+ で始まる名前、長すぎる名前 (255 バイト超)、または . / ... などの予約名。(ドットで始まる名前は禁止ではないが、隠し/システムインデックス用に予約されており、警告が出る。)","fix":"インデックス名を規則に適合させる: 小文字のみを使う。禁止文字を避ける。名前を _、-、+ で始めず、システム/隠しインデックス以外ではドットで始まる名前を使わない。名前を 255 バイト未満に保つ。インデックス名を生成する際は、アプリケーションでこれらの規則を徹底する。","tags":["index name","index naming","invalid","invalid name","naming"]},{"code":"resource_not_found_exception","title":"resource_not_found_exception","severity":"caution","meaning":"要求されたリソース (ドキュメント、インデックス、タスク、パイプライン、モデルなど) が見つからなかった。指定された ID/名前のリソースが存在しない。","cause":"存在しないドキュメント ID、削除されたか作成されていないインデックス/パイプライン、名前のつづりの誤り、まだ完了していないかすでに整理されたタスク、または誤ったクラスタへの要求の送信。","fix":"リソースの名前/ID とその存在を確認する (例: GET /index/_doc/id、GET _ingest/pipeline/name)。正しいインデックスとクラスタに要求を送っていることを確認する。削除/作成操作の順序を見直す。タスクの場合は _tasks API で状態を確認する。","tags":["not found","resource not found","resource","missing resource","404"]},{"code":"process_cluster_event_timeout_exception","title":"process_cluster_event_timeout_exception","severity":"danger","meaning":"クラスタ状態の更新 (例: インデックスの作成、マッピングの変更) が割り当てられた時間内に完了せず、タイムアウトした。マスターノードが更新を時間内に処理できなかった。","cause":"高負荷のマスターノード、非常に大きい/複雑なクラスタ状態、頻繁かつ集中的なマッピング/テンプレートの変更、遅いマスター、またはマスター選出の問題。","fix":"マスターノードの負荷と健全性を確認する: GET _cluster/health、GET _cat/master、保留中のタスクには GET _cluster/pending_tasks。クラスタ状態を縮小する (不要なインデックス/マッピング/テンプレートを減らし、動的マッピングの爆発を防ぐ)。DDL のような重い操作は、トラフィックの少ない時間帯にバッチで実行する。必要ならマスターのリソースを増やす。","tags":["cluster event","timeout","timed out","master","cluster state","danger"]}]},"errors/oracle-more2.json":{"engineId":"oracle","engine":"Oracle","order":1,"errors":[{"code":"ORA-00955","title":"name is already used by an existing object（名前は既存のオブジェクトが使用している）","severity":"caution","meaning":"作成しようとしているオブジェクト (テーブル、インデックス、ビュー、シーケンス、シノニムなど) の名前が、同じスキーマ内の別のオブジェクトですでに使われている。Oracle ではオブジェクト名はスキーマ内で一意であり、テーブル、ビュー、順序といった異なる種類も同じ名前空間を共有する。","cause":"CREATE 文で選んだ名前が既存オブジェクトと衝突している。よくある落とし穴: テーブルと同じ名前で順序やビューを作成しようとする。または自動作成されたインデックス名 (例: 主キーインデックス) が指定した名前と衝突する。","fix":"別の名前を選ぶか、競合するオブジェクトを削除する。その名前を使っているオブジェクトを特定する: SELECT object_type, object_name FROM user_objects WHERE object_name = 'YOUR_NAME'; 本当に置き換えたい場合は古いオブジェクトを DROP する (先にデータをバックアップする)。CREATE OR REPLACE はビュー、シノニム、型、PL/SQL オブジェクト (プロシージャ、関数、パッケージ、トリガー) で使えるが、テーブル、インデックス、順序には存在しない。","tags":["ddl","create","name","conflict","duplicate","object"]},{"code":"ORA-02449","title":"unique/primary keys in table referenced by foreign keys（表の一意/主キーが外部キーにより参照されている）","severity":"caution","meaning":"削除しようとしているテーブルの主キーまたは一意キーが、他のテーブルの外部キーから参照されている。Oracle は、これらの依存関係を先に削除しない限りテーブルの削除を許可しない。","cause":"他のテーブルが FK でこのテーブルを参照している状態で、CASCADE CONSTRAINTS なしで DROP TABLE を実行した。Oracle は参照整合性を守るため、孤立した外部キーの発生を防ぐ。","fix":"依存する外部キーとともに削除するには: DROP TABLE table_name CASCADE CONSTRAINTS; これにより他のテーブルの関連する FK 制約も削除される (それらのテーブルのデータは削除されない)。どの制約が依存しているかを確認する: SELECT table_name, constraint_name FROM all_constraints WHERE r_constraint_name IN (SELECT constraint_name FROM user_constraints WHERE table_name = 'TABLE_NAME');","tags":["drop","foreign key","foreign key reference","constraint","cascade","reference"]},{"code":"ORA-01950","title":"no privileges on tablespace 'name'（表領域に対する権限がない）","severity":"danger","meaning":"ユーザーに、書き込もうとしている表領域のクォータがない。Oracle では、オブジェクトに領域を割り当てるには、ユーザーがその表領域のクォータを持っている必要がある。","cause":"ユーザーに表領域のクォータが付与されていない。典型的には UNLIMITED TABLESPACE システム権限を持たない新規ユーザーが、デフォルト表領域でテーブル/インデックスの作成やデータの挿入を試みる。INSERT、CREATE TABLE、またはインデックスの拡張時に発生する。","fix":"DBA としてユーザーにクォータを付与する: ALTER USER app_user QUOTA UNLIMITED ON tablespace_name; または特定の上限を付与する: ALTER USER app_user QUOTA 500M ON users; 代わりに (慎重に使うこと) GRANT UNLIMITED TABLESPACE TO app_user; を付与することもできるが、これはすべての表領域に対する無制限の権利を与えるため、一般には推奨されない。","tags":["tablespace","quota","tablespace quota","privilege","privilege","insert"]},{"code":"ORA-01110","title":"data file N: 'path'（データファイル N: 'path'）","severity":"danger","meaning":"指定された番号とパスのデータファイルに問題があることを示す補足 (二次) メッセージ。単独では出現せず、実際の問題を報告する別の ORA エラーが先行する。この行は影響を受けるデータファイルを示すだけである。","cause":"通常、データファイルのオフライン (ORA-00376)、メディアリカバリが必要 (ORA-01113)、ブロック破損 (ORA-01578)、ファイル読み取り不可などの一次エラーに付随する。ディスク障害、誤削除、ファイルの移動、バックアップからの不完全なリストアが原因となる。","fix":"この行の前にある実際の ORA エラーを確認し、解決する。影響を受けるファイルを確認: SELECT file#, name, status FROM v$datafile; リカバリが必要な場合: RECOVER DATAFILE 'path'; 続いて ALTER DATABASE DATAFILE 'path' ONLINE; ファイルが物理的に失われた場合は RMAN でリストアおよびリカバリする: RESTORE DATAFILE N; RECOVER DATAFILE N;","tags":["datafile","data file","recovery","media recovery","offline","rman"]},{"code":"ORA-16038","title":"log N sequence# M cannot be archived（ログ N (順序番号 M) をアーカイブできない）","severity":"danger","meaning":"Oracle がオンライン REDO ログファイルをアーカイブできず、そのロググループを再利用できない。ARCHIVELOG モードでアーカイブが停止すると、データベースは新しいトランザクションを受け付けなくなりハングすることがある。","cause":"通常、アーカイブログの出力先または高速リカバリ領域 (FRA) が満杯、ディスク容量の枯渇、アーカイブ先に到達不能、または権限/マウントの問題が原因。ORA-19809 (リカバリファイルの制限超過) や ORA-00312 と同時に発生することが多い。","fix":"アーカイブ先/FRA の空き領域を確保する: 古いアーカイブログを RMAN で FRA 外の出力先にバックアップしてから削除する (DELETE ARCHIVELOG ALL COMPLETED BEFORE ...; Data Guard 環境では、スタンバイへ未転送/未適用のアーカイブログを削除しない)、または db_recovery_file_dest_size を増やす。出力先の状態を確認: ARCHIVE LOG LIST; および SELECT dest_name, status, error FROM v$archive_dest WHERE status != 'INACTIVE'; 問題が解消されると、アーカイブは中断した位置から再開される。","tags":["archivelog","archive","redo","fra","recovery area","archiver stuck"]},{"code":"ORA-19809","title":"limit exceeded for recovery files（リカバリファイルの制限超過）","severity":"danger","meaning":"高速リカバリ領域 (FRA) に割り当てられた領域 (db_recovery_file_dest_size) が満杯。アーカイブログ、フラッシュバックログ、バックアップ用の空きがなくなり、Oracle は新しいリカバリファイルを作成できず、データベースがハングすることがある。","cause":"定期的にバックアップ・削除されなかったため FRA にアーカイブログが蓄積した、フラッシュバックログの使用量が増加した、または割り当てサイズが実際のワークロードに対して小さすぎる。ORA-16038 などのアーカイブエラーと同時に発生する。","fix":"FRA の使用状況を確認: SELECT * FROM v$recovery_file_dest; および SELECT * FROM v$flash_recovery_area_usage; 不要なアーカイブログを RMAN で削除する: DELETE ARCHIVELOG ALL BACKED UP 1 TIMES TO DISK; (Data Guard 環境では、まずスタンバイで適用済みであることを確認する。CONFIGURE ARCHIVELOG DELETION POLICY TO APPLIED ON ALL STANDBY を推奨) または恒久対策としてサイズを増やす: ALTER SYSTEM SET db_recovery_file_dest_size = 50G SCOPE=BOTH; アーカイブログを定期的にバックアップする RMAN ジョブを設定する。","tags":["fra","recovery area","db_recovery_file_dest_size","archivelog","space","rman"]},{"code":"ORA-00376","title":"file N cannot be read at this time（ファイル N は現在読み取れない）","severity":"danger","meaning":"指定された番号のデータファイルがオフラインまたはアクセス不能のため、現在読み取れない。該当表領域のデータにアクセスするクエリや操作はこのエラーで失敗する。","cause":"データファイルがエラー後に自動的に、または手動でオフラインにされた、メディアリカバリ待ちである、ディスクにアクセスできなくなった、または NOARCHIVELOG モードでリカバリできないファイルがオフラインのまま残されている。通常、ファイルを特定する ORA-01110 の行を伴う。","fix":"ファイルの状態を確認: SELECT file#, name, status FROM v$datafile WHERE status != 'ONLINE'; リカバリしてオンラインにする: RECOVER DATAFILE N; 続いて ALTER DATABASE DATAFILE N ONLINE; 物理的な破損/消失がある場合は RMAN でリストアおよびリカバリする: RESTORE DATAFILE N; RECOVER DATAFILE N; 根本原因であるディスク/ハードウェアの問題も解決する。","tags":["datafile","data file","offline","recovery","media recovery","read"]},{"code":"ORA-12520","title":"TNS:listener could not find available handler for requested type of server（要求されたサーバータイプに使用可能なハンドラがリスナーで見つからない）","severity":"danger","meaning":"リスナーが、要求された接続タイプ (専用またはシェアード) に適したサーバープロセス (ハンドラ) を見つけられなかった。クライアントはリスナーに到達できるが、接続をサーバープロセスに引き渡せない。","cause":"インスタンスがリスナーに登録されていない、または登録が壊れている、PROCESSES/SESSIONS の上限に達し新しい専用プロセスを生成できない、共有サーバー構成でディスパッチャがない/不足している、またはインスタンスが起動直後でまだリスナーに登録されていない。","fix":"リスナーが認識しているサービスを確認: lsnrctl services (ハンドラ数と状態)。インスタンスをリスナーに再登録: ALTER SYSTEM REGISTER; PROCESSES の上限を確認: SELECT resource_name, current_utilization, max_utilization, limit_value FROM v$resource_limit WHERE resource_name IN ('processes','sessions'); 必要に応じて ALTER SYSTEM SET processes=... SCOPE=SPFILE; で増やし、インスタンスを再起動する。","tags":["listener","tns","connection","handler","processes","dispatcher"]},{"code":"ORA-28001","title":"the password has expired（パスワードの期限切れ）","severity":"caution","meaning":"接続しようとしているデータベースユーザーのパスワードが、プロファイルの PASSWORD_LIFE_TIME の経過により期限切れになった。パスワードを変更するまでセッションを開けない。","cause":"ユーザーのプロファイルで定義されたパスワード有効期間が終了し、猶予期間も経過した。Oracle 11g 以降、DEFAULT プロファイルのパスワードは 180 日ごとに期限切れになり、特に長期間使用されるアプリケーションのサービスアカウントで予期しない停止を引き起こす。","fix":"パスワードを変更する: ALTER USER app_user IDENTIFIED BY new_password; アプリケーションアカウントでの再発を防ぐには、パスワード期限のないプロファイルを使用する: CREATE PROFILE app_profile LIMIT PASSWORD_LIFE_TIME UNLIMITED; 続いて ALTER USER app_user PROFILE app_profile; 期限切れ前に警告する監視も有用。状態は DBA_USERS の ACCOUNT_STATUS で確認する。","tags":["password","password expired","expired","profile","account","login"]},{"code":"ORA-38029","title":"object statistics are locked（オブジェクト統計がロックされている）","severity":"caution","meaning":"表 (またはスキーマ) のオプティマイザ統計がロックされているため、統計の収集/削除が拒否された。ロックされた統計は DBMS_STATS による再計算から保護される。","cause":"以前に DBMS_STATS.LOCK_TABLE_STATS または LOCK_SCHEMA_STATS が呼び出された (統計を固定するためなど)、または Data Pump インポート (特に CONTENT=METADATA_ONLY) によって意図せず統計がロックされたままになった。ロック中に GATHER_TABLE_STATS を実行するとこのエラーになる。","fix":"統計のロックを解除する: EXEC DBMS_STATS.UNLOCK_TABLE_STATS('APP_SCHEMA','MY_TABLE'); またはスキーマ単位で DBMS_STATS.UNLOCK_SCHEMA_STATS('APP_SCHEMA'); ロックを解除せずに収集したい場合は FORCE=>TRUE を使用する: EXEC DBMS_STATS.GATHER_TABLE_STATS('APP_SCHEMA','MY_TABLE', force=>TRUE); ロック状態の確認: SELECT table_name, stattype_locked FROM dba_tab_statistics WHERE stattype_locked IS NOT NULL;","tags":["statistics","optimizer statistics","dbms_stats","locked","lock","optimizer"]}]},"errors/postgres-more2.json":{"engineId":"postgres","engine":"PostgreSQL","order":2,"errors":[{"code":"54001","title":"statement_too_complex","severity":"caution","meaning":"文が PostgreSQL で処理できる複雑さを超えている。通常、非常に深くネストした式や多数のネストした演算子により、式ツリーがパーサー/プランナーのスタック上限を超える。Class 54 (program_limit_exceeded) に属する。","cause":"過度に深い括弧/ネストしたサブクエリや OR/AND の連鎖、自動生成された巨大な WHERE ... IN (...) リスト、または再帰ビューから生じる非常に大きな式ツリー。max_stack_depth の上限に達する。","fix":"クエリを簡素化する: 長い IN リストは一時テーブルや VALUES セットに移して JOIN する、ネストした式を分割する、ORM が生成した巨大なクエリを見直す。本当に必要で OS のスタック上限が許す場合は、max_stack_depth を慎重に引き上げる (例: SET max_stack_depth = '4MB';)。ただし OS の ulimit 未満に保つ。","tags":["program_limit","complex","stack","nested","query","max_stack_depth"]},{"code":"58030","title":"io_error","severity":"danger","meaning":"PostgreSQL がファイルの読み書き中に OS レベルの入出力 (I/O) エラーに遭遇した。データベースファイルへのアクセスにおける物理的またはファイルシステムの問題を示す。Class 58 (system_error) に属する。","cause":"ディスク障害や不良セクタ、ディスク満杯、ファイルシステムエラー、ネットワーク接続ストレージ (NFS/SAN) の障害、権限の問題、または OS のファイルディスクリプタ/inode 上限の枯渇。","fix":"ディスクの健全性と空き容量を確認する (df -h、dmesg、SMART データ)。PostgreSQL のログでどのファイルが影響を受けているか確認する。ファイルシステムエラーを修正し、必要ならハードウェアを交換する。データ破損が疑われる場合は直近の正常なバックアップからのリストアを計画し、今後はチェックサムを有効にしておく (initdb --data-checksums)。","tags":["system_error","io","disk","hardware","file","corruption"]},{"code":"22004","title":"null_value_not_allowed","severity":"caution","meaning":"NULL を受け付けない箇所に NULL が渡された。列の NOT NULL 制約 (23502) とは異なり、通常は関数やプロシージャのコンテキストで NULL を受け付けないパラメータや操作に NULL を渡したことで発生する。Class 22 (data_exception) に属する。","cause":"NOT NULL で宣言された PL/pgSQL 変数への NULL の代入、EXECUTE への NULL のクエリ文字列の受け渡し、または NULL を受け付けない組込み関数の引数への NULL の受け渡し。注: STRICT 指定の関数は NULL 入力でエラーにならず、実行せずに NULL を返す。","fix":"失敗した行 (CONTEXT) を特定し、そこに到達する値を NULL チェックで保護するか、COALESCE でデフォルト値を与える: COALESCE(value, default_value)。PL/pgSQL では NOT NULL 変数に代入する前に値を検証し、動的 SQL では EXECUTE に渡す文字列が NULL でないことを確認する。アプリケーション層で必須項目が NULL で送信されないようにする。","tags":["data_exception","null","function","strict","parameter","coalesce"]},{"code":"42P18","title":"indeterminate_datatype","severity":"caution","meaning":"PostgreSQL がコンテキストから式またはパラメータのデータ型を推論できなかった。型ヒントのない型未指定のプレースホルダ ($1 など) や裸の NULL を使用した場合に最もよく見られる。","cause":"プリペアド文の型未指定パラメータ、\"WHERE $1 = $2\" のように両辺とも型が不定の比較、またはコンテキストのない NULL/配列リテラルの使用。プランナーがどの型を使うか決定できない。","fix":"型が不定の式に明示的なキャストを追加する: $1::text、$1::integer、NULL::date など。例: SELECT $1::int + 1; ドライバ/ORM のパラメータに型を指定する。列の比較では、少なくとも一方の型が既知であることを確認する。","tags":["syntax","type","indeterminate","cast","parameter","prepared"]},{"code":"42P02","title":"undefined_parameter","severity":"caution","meaning":"クエリが存在しないパラメータを参照している。参照された位置パラメータ (例: $2) が定義されていないことを PostgreSQL が報告する。Class 42 (syntax_error_or_access_rule_violation) に属する。","cause":"PREPARE で準備した文で、与えた数より多くのパラメータを参照している (例: パラメータを 2 つ送って $3 を使用)、パラメータ番号の飛び、または動的に連結した SQL での誤った $N インデックス。","fix":"パラメータ番号が与える値の数と一致していること、$1 から始まり欠番なく続くことを確認する。PREPARE 文でパラメータ型を完全に定義する: PREPARE p(int, text) AS SELECT ... WHERE a=$1 AND b=$2; ORM/ドライバを使用している場合は、バインドされたパラメータ数とクエリ内のプレースホルダ数を比較する。","tags":["syntax","parameter","prepared","undefined","placeholder","sql"]},{"code":"2F003","title":"prohibited_sql_statement_attempted","severity":"caution","meaning":"SQL 関数/ルーチン内で、そのコンテキストでは禁止されている文が試行された。Class 2F (sql_routine_exception) に属する。例: 読み取り専用であるべき関数がデータを変更しようとした。","cause":"PostgreSQL 本体がこのコードを発生させることはまれで、通常は拡張機能や手続き言語のコードから発生する。注: IMMUTABLE/STABLE 指定の関数で INSERT/UPDATE/DELETE を実行しても 2F003 にはならず、コード 0A000 (feature_not_supported) で '... is not allowed in a non-volatile function' が発生する。","fix":"エラーメッセージでどの文が禁止されたかを確認し、該当するルーチン/拡張機能のドキュメントを確認する。non-volatile function エラー (0A000) の場合は、データを変更する関数を VOLATILE (デフォルト) で定義する: CREATE FUNCTION ... LANGUAGE plpgsql VOLATILE。読み取り専用であるべき箇所 (インデックス式、制約チェック) からデータ変更呼出しを取り除く。","tags":["sql_routine","function","volatile","prohibited","immutable","side effect"]},{"code":"40003","title":"statement_completion_unknown","severity":"danger","meaning":"トランザクションの結果が不明。トランザクションが完了したか判明する前に (特に COMMIT 中に) サーバーへの接続が切断された。クライアントは変更が永続化されたか確実には判断できない。Class 40 (transaction_rollback) に属する。","cause":"COMMIT 送信後、応答到着前にネットワーク切断、サーバークラッシュ、またはフェイルオーバーが発生した。トランザクションはサーバー上で完了している可能性も、ロールバックされた可能性もある。","fix":"トランザクションを盲目的に再試行しない。まず実際に適用されたか確認する (例: 想定される行を照会する)。トランザクションを冪等に設計し、一意な業務キー/冪等キーを使用する。コネクションプールに堅牢な再接続と検証のロジックを実装する。","tags":["transaction","commit","unknown","connection","idempotent","failover"]},{"code":"08003","title":"connection_does_not_exist","severity":"danger","meaning":"存在しない (既にクローズされた) データベース接続で操作が試行された。アプリケーションが無効な接続ハンドルでクエリを送信しようとした。Class 08 (connection_exception) に属する。","cause":"接続タイムアウト、サーバーによるクローズ、ネットワーク障害、または実際には切断済みの接続をプールから取得した。あるいはアプリケーションコードで close() した接続の再利用。","fix":"コネクションプールで死活チェックを有効にする (検証クエリ/keepalive)。切断された接続をプールから排除する設定を行う (例: HikariCP の connectionTestQuery/maxLifetime)。アプリケーションでは使用前に接続がオープンであることを確認し、切断時は自動で再接続する。TCP keepalive と idle_in_transaction_session_timeout の値を見直す。","tags":["connection","connection","closed","pool","pool","timeout"]},{"code":"25006","title":"read_only_sql_transaction","severity":"caution","meaning":"読み取り専用トランザクション内でデータ変更コマンド (INSERT/UPDATE/DELETE/DDL) が試行された。トランザクションは読み取り専用に設定されている。Class 25 (invalid_transaction_state) に属する。","cause":"SET TRANSACTION READ ONLY または default_transaction_read_only=on の設定。最も多いのは読み取りレプリカ (ホットスタンバイ/ストリーミングレプリカ) への書き込み試行。スタンバイサーバーは定義上読み取り専用である。","fix":"書き込みをプライマリサーバーに振り向け、読み書きを分離する接続ルーティングを確認する。誤って設定された場合: SET TRANSACTION READ WRITE; またはサーバー全体で default_transaction_read_only=off。アプリケーションが読み書きトラフィックを正しいノードに送ることを確認する。","tags":["transaction","read only","read only","replica","standby","primary"]},{"code":"21000","title":"cardinality_violation","severity":"caution","meaning":"1 行が想定される箇所で複数行が返された。スカラーサブクエリが複数行を返した、または MERGE/ON CONFLICT DO UPDATE が同じ対象行に 2 回目の変更を試みた。Class 21 に属する。","cause":"SELECT リストや WHERE = (subquery) の形式で使用したサブクエリが複数行を返す、単一の INSERT ... ON CONFLICT DO UPDATE で同じ競合キーが複数回提示される ('cannot affect row a second time')、または MERGE で複数のソース行が 1 つの対象行に一致する。UPDATE ... FROM は複数一致でエラーにならず、対象行はソース行のいずれか 1 行から予測不能に更新される。","fix":"サブクエリが 1 行を返すようにする: LIMIT 1 を追加する、集約 (MAX/MIN) を使用する、または一致を一意にする条件を与える。MERGE と ON CONFLICT のパターンではソース側を DISTINCT ON/集約で重複排除し、UPDATE ... FROM でも同様にして暗黙の誤った結果を防ぐ。想定外の複数一致を見つけるには、サブクエリを単独で実行して行数を確認する。","tags":["cardinality","subquery","subquery","single row","join","scalar"]}]},"errors/mysql-more2.json":{"engineId":"mysql","engine":"MySQL","order":3,"errors":[{"code":"1927","title":"MariaDB: ER_CONNECTION_KILLED: Connection was killed（接続が強制終了された）","severity":"danger","meaning":"MariaDB 固有: 実行中の接続/スレッドがサーバーによって終了され、実行中のクエリが中断し、クライアント接続が切断された。このコードは MySQL には存在せず、MySQL ではクエリの中断時に 1317 (ER_QUERY_INTERRUPTED)、接続切断時にクライアント側で 2013 (Lost connection) として現れる。","cause":"管理者または監視ツールによる KILL コマンドの送信、サーバーのシャットダウン開始、idle_transaction_timeout/wait_timeout などの MariaDB のアイドル接続制限、またはリソース逼迫によるサーバーの接続切断。クラウド/プロキシ環境のメンテナンス中にも発生する。","fix":"クエリが強制終了された理由を調査する: 長時間実行のクエリについて SHOW PROCESSLIST とスロークエリログ、サーバーのメンテナンス/再起動スケジュール、接続 kill ポリシー。アプリケーションでこのエラーを捕捉し、(冪等であれば) 安全に再試行する。長いクエリを最適化・分割し、コネクションプールで自動再接続を使用する。","tags":["connection","connection killed","kill","thread","shutdown","retry"]},{"code":"1290","title":"ER_OPTION_PREVENTS_STATEMENT: running with the --read-only option（--read-only オプションで稼働中）","severity":"caution","meaning":"MySQL サーバーが --read-only または --super-read-only オプションで稼働しているため、データ変更文 (INSERT/UPDATE/DELETE/DDL) を拒否した。read_only では CONNECTION_ADMIN/SUPER を持つユーザーは書き込み可能だが、super_read_only が有効な場合はそれも不可となり、メッセージは '--super-read-only option' となる。","cause":"read_only=ON または super_read_only=ON。最も多いのはレプリカへの誤った書き込み試行。レプリカと Group Replication のセカンダリはデータ整合性のため読み取り専用に保たれ、フェイルオーバー自動化は旧プライマリを super_read_only にする。フェイルオーバー/スイッチオーバー中に誤ったノードへ書き込んだ場合にも発生する。","fix":"書き込みをプライマリ (ソース) サーバーに振り向ける。このサーバーを本当に新しいプライマリにする場合: SET GLOBAL read_only = OFF; (read_only をオフにすると super_read_only も自動的にオフになり、super_read_only をオンにすると read_only もオンになる)。HA ツール (Orchestrator/Group Replication/InnoDB Cluster) が管理するノードでは手動で変更しない。状態の確認: SELECT @@read_only, @@super_read_only;","tags":["read only","super_read_only","read-only mode","replica","primary","write","failover","1290"]},{"code":"1836","title":"ER_READ_ONLY_MODE: Running in read-only mode（読み取り専用モードで稼働中）","severity":"caution","meaning":"InnoDB が読み取り専用モード (innodb_read_only=ON) で稼働している、またはデータディレクトリ/メディアが読み取り専用であり、InnoDB テーブルへの書き込みと DDL が拒否される。注: read_only/super_read_only 有効時の書き込み試行はこのコードではなく 1290 (ER_OPTION_PREVENTS_STATEMENT) を返す。","cause":"サーバーが innodb_read_only=ON で起動された (例: 読み取り専用メディア、共有データディレクトリ、分析用コピー)。このモードでは InnoDB テーブルに対して INSERT/UPDATE/DELETE や CREATE/DROP/ALTER TABLE などの変更を行えない。","fix":"書き込みが必要な場合は innodb_read_only なしでサーバーを起動する: my.cnf から innodb_read_only=ON の行を削除して再起動する (この変数は動的ではなく再起動が必要)。状態の確認: SELECT @@innodb_read_only; データディレクトリとファイルシステムが書き込み可能であることを確認する。レプリカ/HA セカンダリに書き込んでいる場合 (1290) は、書き込みをプライマリに振り向ける。","tags":["innodb_read_only","read only","read-only mode","innodb","1836"]},{"code":"3819","title":"ER_CHECK_CONSTRAINT_VIOLATED: Check constraint is violated（CHECK 制約違反）","severity":"caution","meaning":"挿入または更新しようとしている行が、テーブルに定義された CHECK 制約に違反している。MySQL 8.0.16 以降では CHECK 制約が実際に強制される (以前のバージョンでは無視されていた)。","cause":"列の値が CHECK 式の条件を満たさない (例: CHECK (price >= 0) があるのに負の価格を入力)。古い MySQL から 8.0.16 以降にアップグレードした後、以前は無視されていた制約が強制されるようになり、予期せず発生することがある。","fix":"値が制約条件を満たすようにし、アプリケーション側に検証を追加する。制約定義の確認: SHOW CREATE TABLE my_table; 制約が本当に不要な場合: ALTER TABLE my_table DROP CHECK constraint_name; または一時的に ALTER TABLE my_table ALTER CHECK constraint_name NOT ENFORCED; 不正データの発生源も修正する。","tags":["check","constraint","check constraint","validation","8.0","violation"]},{"code":"1118","title":"ER_TOO_BIG_ROWSIZE: Row size too large（行サイズが大きすぎる）","severity":"caution","meaning":"定義しようとしているテーブルの行サイズが、ストレージエンジンが許容する最大行サイズを超えている。BLOB/TEXT 以外の列の最大行サイズは 65535 バイトで、InnoDB にはページサイズに依存する追加の制限がある。","cause":"多数の幅の広い列 (特に長い VARCHAR/CHAR) の定義、utf8mb4 などのマルチバイト文字セットで 1 文字が最大 4 バイトを占めること、または InnoDB の COMPACT/REDUNDANT 行フォーマットで大きな列がインラインに格納されること。","fix":"一部の大きな列を TEXT/BLOB に変換する (これらはページ外に格納できる)。不要な列や非常に幅の広い列を縮小するか、テーブルを 2 つに分割する。InnoDB では ROW_FORMAT=DYNAMIC または COMPRESSED を使うと大きな列がページ外に移動するため有効: ALTER TABLE my_table ROW_FORMAT=DYNAMIC; innodb_page_size も考慮する。","tags":["row size","row size too large","innodb","varchar","row_format","limit"]},{"code":"1170","title":"ER_BLOB_KEY_WITHOUT_LENGTH: BLOB/TEXT column used in key specification without a key length（キー長を指定せずに BLOB/TEXT 列をキーに使用）","severity":"caution","meaning":"プレフィックス長を指定せずに BLOB または TEXT 列をインデックス/キー定義に使用した。これらの型は全体をインデックス化できず、先頭 N 文字/バイトのみインデックス化できる。","cause":"CREATE TABLE または CREATE INDEX で、長さを指定せずに TEXT/BLOB 列に INDEX/UNIQUE/PRIMARY KEY を定義した。MySQL はこうした非常に大きくなり得る値を全体ではインデックス化できないため、プレフィックス長を要求する。","fix":"INDEX (description(255)) のようにインデックスにプレフィックス長を指定する。例: ALTER TABLE my_table ADD INDEX idx_description (description(191)); (InnoDB のキープレフィックス制限のため、utf8mb4 では 191 がよく使われる)。全文検索が必要なら FULLTEXT インデックスを検討する。短く一意であるべき項目では、列を VARCHAR に変換するほうが適切な場合がある。","tags":["index","key","blob","text","prefix","prefix length"]},{"code":"1592","title":"ER_BINLOG_UNSAFE_STATEMENT: Unsafe statement written to the binary log（安全でない文がバイナリログに書き込まれた）","severity":"caution","meaning":"STATEMENT ベースの binlog フォーマット使用中に、結果が非決定的な文 (レプリカで異なる結果を生じ得る文) が実行された。ソースとレプリカ間でデータ不整合のリスクがあるため、MySQL は binlog への書き込み時に警告を出す。","cause":"binlog_format=STATEMENT の場合: UUID()、SYSDATE()、USER() などの非決定的関数 (NOW() は STATEMENT でも安全にレプリケートされる)、ORDER BY なしで LIMIT 付きの UPDATE/DELETE、AUTO_INCREMENT が絡む INSERT、または特定のユーザー定義/システム関数。これらの文はすべてのサーバーで同じ結果になるとは限らない。","fix":"binlog フォーマットを行ベースに切り替える (推奨。MySQL 5.7.7 以降は ROW がデフォルト): my.cnf で binlog_format=ROW、または SET PERSIST binlog_format = ROW; (binlog_format 変数は 8.0.34 以降非推奨。変更は新しいセッションから有効)。ROW フォーマットでは非決定的な文も安全にレプリケートされる。STATEMENT のままにする必要がある場合は、非決定的な関数/式を定数値に置き換え、LIMIT 付き DML に決定的な ORDER BY を追加する。","tags":["binlog","replication","unsafe","statement","row","nondeterministic"]},{"code":"3140","title":"ER_INVALID_JSON_TEXT: Invalid JSON text（無効な JSON テキスト）","severity":"caution","meaning":"JSON 列または JSON 関数に無効な (構文的に壊れた) JSON テキストが渡された。値を JSON として解析できないため、MySQL は操作を拒否する。","cause":"閉じられていない引用符/括弧、末尾のカンマ、単一引用符、エスケープ文字の誤り、または JSON 列へのプレーンテキストの送信。JSON_SET、JSON_INSERT などの関数や JSON 型の列に不正なテキストを渡した場合に発生する。","fix":"JSON テキストを正しい構文に修正する: 二重引用符を使い、末尾のカンマを削除し、エスケープを確認する。テキストが有効か検証する: SELECT JSON_VALID('{...}'); (有効なら 1 を返す)。アプリケーション層では信頼できるライブラリで JSON をシリアライズし、サーバーに送る前に検証する。","tags":["json","invalid","syntax","json_valid","parse","data"]},{"code":"1526","title":"ER_NO_PARTITION_FOR_GIVEN_VALUE: Table has no partition for value（値に対応するパーティションがない）","severity":"caution","meaning":"挿入しようとしている行のパーティションキー値が、定義済みのどのパーティションにも該当しない。RANGE または LIST パーティショニングで、受け取った値をカバーするパーティションがないため挿入が失敗する。","cause":"RANGE パーティショニングで MAXVALUE パーティションを定義せずに最上限を超える値 (例: 将来の日付) を挿入した、LIST パーティショニングで列挙されていない値が来た。新しい期間のパーティションが期限内に追加されなかった時間パーティション表でよく見られる。","fix":"値をカバーするパーティションを追加する。RANGE の新しい上位パーティション: ALTER TABLE my_table ADD PARTITION (PARTITION p2026 VALUES LESS THAN (2027)); 受け皿となるパーティションとして、RANGE では MAXVALUE を、LIST では該当する値を定義する。時間ベースのテーブルでは、パーティションを自動追加するメンテナンスジョブ (event/scheduler) を設定する。","tags":["partition","partitioning","range","list","maxvalue","insert"]}]},"errors/mssql-more2.json":{"engineId":"mssql","engine":"SQL Server","order":4,"errors":[{"code":"1101","title":"Could not allocate a new page because of insufficient disk space in filegroup（ファイルグループのディスク容量不足により新しいページを割り当てられない）","severity":"danger","meaning":"SQL Server がオブジェクトに新しいページを割り当てようとしたが、ファイルグループのディスク容量が不足している。データファイルは拡張できず空きページも見つからないため、書き込みが失敗する。","cause":"データファイルを格納するディスクが満杯、ファイルの自動拡張が無効または MAXSIZE に到達、あるいはファイルグループ内の全ファイルがサイズ上限に達した。大量の INSERT やインデックス構築中によく発生する。","fix":"ディスクの空き領域を確保するか、ファイルグループに領域を追加する。ファイルを拡張するか自動拡張を有効にする: ALTER DATABASE db MODIFY FILE (NAME = logical_name, SIZE = 20GB, MAXSIZE = UNLIMITED, FILEGROWTH = 512MB); または (別のディスク上に) 新しいファイルをファイルグループに追加する。ファイル使用量は sys.database_files で、空き領域は DBCC SQLPERF で確認する。","tags":["disk","filegroup","file group","autogrow","space","allocation"]},{"code":"3729","title":"Cannot DROP because it is being referenced by object（オブジェクトから参照されているため DROP できない）","severity":"caution","meaning":"削除しようとしているオブジェクト (テーブル、型、関数など) が別のオブジェクトから参照されており、その依存関係が削除を妨げている。特にスキーマバインドされたオブジェクトはこのように保護される。","cause":"WITH SCHEMABINDING で作成したビューや関数が依存するテーブル/オブジェクトの削除、外部キーで参照されているテーブルの削除、またはテーブル/パラメータがまだ使用しているユーザー定義型の削除。","fix":"先に参照元オブジェクトを削除するか、依存関係を解除する。依存関係の確認: SELECT referencing_schema_name, referencing_entity_name FROM sys.dm_sql_referencing_entities('app_schema.object', 'OBJECT'); スキーマバインドされたビューの場合は、まず ALTER VIEW で SCHEMABINDING を外すかビューを削除してから、テーブルを削除する。","tags":["drop","reference","schemabinding","view","dependencies","dependency"]},{"code":"3961","title":"Snapshot isolation transaction failed because the object was modified by a DDL statement（DDL 文でオブジェクトが変更されたためスナップショット分離トランザクションが失敗）","severity":"caution","meaning":"スナップショット分離で実行中のトランザクションが、アクセスしたオブジェクトが同時実行中の別トランザクションの DDL 文 (スキーマ変更) で変更されたため失敗した。メタデータはバージョン管理されないため、スナップショットトランザクションは続行できない。","cause":"SNAPSHOT 分離 (SET TRANSACTION ISOLATION LEVEL SNAPSHOT) で開始したトランザクションの実行中に、別セッションがそのトランザクションのアクセスするテーブルに ALTER TABLE/CREATE INDEX などの DDL を実行した。スナップショットトランザクションは行バージョンは参照できるが、スキーマバージョンは参照できない。このエラーは READ COMMITTED SNAPSHOT (RCSI) では発生しない。RCSI は文ごとに新しいスナップショットを取得する。","fix":"トランザクションを再試行する。通常、DDL の完了後は成功する。恒久対策として、スキーマ変更 (DDL) はスナップショットのワークロードが少ないメンテナンス時間帯に実施する。アプリケーションでこのエラーを捕捉し、自動再試行ロジックを実装する。長時間実行のスナップショットトランザクションを短くする。","tags":["snapshot","isolation level","ddl","concurrency","retry","isolation"]},{"code":"1785","title":"Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths（FOREIGN KEY 制約により循環または複数のカスケードパスが生じる可能性）","severity":"caution","meaning":"追加しようとしている外部キーが、カスケード (ON DELETE/UPDATE CASCADE) 操作において循環、または同じテーブルへの複数のカスケード削除/更新経路を生じる可能性がある。あいまいなカスケード動作を避けるため、SQL Server はこれを拒否する。","cause":"カスケード動作付きの FK がテーブル間の循環参照 (A->B->A) または 1 つのテーブルへの複数のカスケード経路を作る。あいまいなカスケード順序と無限ループを防ぐため、SQL Server はこれを禁止する。","fix":"外部キーを ON DELETE NO ACTION / ON UPDATE NO ACTION (カスケードなし) で定義する: ALTER TABLE child ADD CONSTRAINT fk ... FOREIGN KEY (...) REFERENCES parent(...) ON DELETE NO ACTION; 必要なカスケード削除は INSTEAD OF DELETE トリガーで実装する: トリガーで先に子行を削除し、次に親行を削除する (例: DELETE c FROM child c JOIN deleted d ON c.parent_id = d.id; DELETE e FROM parent e JOIN deleted d ON e.id = d.id;)。AFTER DELETE トリガーでは機能しない。FK チェックがトリガーより前に実行されるため、削除はエラー 547 で拒否される。データモデルの循環依存を見直す。","tags":["foreign key","fk","cascade","circular reference","cycle","constraint"]},{"code":"9421","title":"XML parsing: illegal xml character（XML 解析: 無効な XML 文字）","severity":"caution","meaning":"SQL Server がテキストを XML として解析中に、許可されない (無効な) 文字を検出した。この文字のために XML 型への変換、または XML 列/変数への代入が失敗した。","cause":"XML 1.0 で禁止されている制御文字 (例: 0x00-0x1F の範囲の一部の文字)、誤ったエンコーディング (エンコーディングの不一致)、または他のソースからの破損した/サニタイズされていないデータ。通常、CAST(... AS XML) や XML 列への INSERT 中に発生する。","fix":"XML に変換する前にテキストから無効な文字を除去する。ソースのエンコーディング (UTF-8/UTF-16) をターゲットと互換にし、XML 宣言に正しいエンコーディングを指定する。REPLACE/NCHAR で制御文字を削除するか、アプリケーション層で標準ライブラリを使って XML を生成・検証する。生のテキストを格納する必要がある場合は NVARCHAR(MAX) を検討する。","tags":["xml","parse","character","encoding","invalid","cast"]},{"code":"15151","title":"Cannot find the object/principal because it does not exist or you do not have permission（オブジェクト/プリンシパルが存在しないか権限がないため見つからない）","severity":"caution","meaning":"参照したオブジェクトまたはセキュリティプリンシパル (ユーザー、ロール、ログイン) が存在しないか、それにアクセス/操作する権限がない。セキュリティ上の理由から、SQL Server は両方のケースを 1 つのメッセージにまとめている。","cause":"GRANT/ALTER/DROP などのコマンドで存在しないユーザー、ロール、スキーマ、オブジェクト名を使用した、誤ったデータベースコンテキストで実行した (オブジェクトは別の DB にある)、または操作に必要な権限がない。タイプミス、大文字小文字、スキーマプレフィックスがよくある原因。","fix":"オブジェクト/プリンシパル名の綴りが正しいこと、正しいデータベースにいることを確認する。ユーザーの場合: SELECT name, type_desc FROM sys.database_principals; オブジェクトの場合は sys.objects を照会する。実行アカウントに必要な権限 (例: ALTER ANY USER、CONTROL) があることを確認する。正しいスキーマプレフィックス (dbo.object など) を使用する。","tags":["permission","principal","privilege","not found","grant","security"]},{"code":"4834","title":"You do not have permission to use the bulk load statement（一括読込み文を使用する権限がない）","severity":"caution","meaning":"BULK INSERT (または OPENROWSET BULK) で一括読込みを実行するのに必要な権限がない。一括読込みはファイルシステムとサーバーリソースに直接アクセスするため、別個の権限が必要となる。","cause":"ログインにサーバーレベルの ADMINISTER BULK OPERATIONS 権限がない、または bulkadmin サーバーロールのメンバーではない (Azure SQL Database では代わりにデータベースレベルの ADMINISTER DATABASE BULK OPERATIONS が必要)。対象テーブルへの INSERT 権限と、SQL Server サービスアカウントによるソースファイルの読み取りアクセスも必要。","fix":"必要な権限を付与する: GRANT ADMINISTER BULK OPERATIONS TO login_name; (サーバーレベル) またはユーザーを適切なロールに追加する。Azure SQL DB では ADMINISTER DATABASE BULK OPERATIONS を使用する。SQL Server サービスアカウントに対象ファイル/共有の読み取り権限があることも確認する。最小権限の原則に従い、必要なアカウントにのみ付与する。","tags":["bulk insert","privilege","permission","bulk load","bulkadmin","file"]},{"code":"10928","title":"Resource limit for the database has been reached (Azure SQL)（データベースのリソース上限に到達）","severity":"danger","meaning":"Azure SQL Database でデータベースがリソース上限 (同時要求/ワーカー数やセッション数など) に達し、新しい要求が拒否された。選択したサービスレベル (DTU または vCore) の上限に到達したことを示す。","cause":"選択したレベルで許可される最大同時要求数 (ワーカー) またはセッション数の超過、急激な負荷増大、ワーカースレッドを占有する非効率/長時間実行のクエリ、または大きすぎるコネクションプール。","fix":"同時実行数を減らす: クエリを最適化して実行時間を短縮し、不要な未完了トランザクションを閉じ、コネクションプールのサイズを適正に保つ。継続的な負荷にはサービスレベルをスケールアップする (より高い DTU/vCore)。リソース使用状況は sys.dm_db_resource_stats で監視する。再試行可能なエラーには、アプリケーションで指数バックオフ付きの再試行を実装する。","tags":["azure","limit","resource","dtu","vcore","concurrency"]},{"code":"40544","title":"The database has reached its size quota (Azure SQL)（データベースがサイズクォータに到達）","severity":"danger","meaning":"Azure SQL Database がサービスレベルで設定された最大データサイズのクォータに達した。データベースはこれ以上拡張できず、新しい書き込みが失敗する。","cause":"データがレベルの上限まで増加した、大きなインデックス/ログが領域を消費している、または選択したレベルで許容される MAXSIZE が小さい (例: Basic/Standard の S シリーズ)。アーカイブされていない履歴データもクォータを急速に埋める。","fix":"領域を確保する: 不要なデータを削除/アーカイブし、未使用のインデックスを削除し、テーブルを圧縮する (データ圧縮)。恒久対策として MAXSIZE を増やすか、上位のサービスレベルに移行する: ALTER DATABASE db MODIFY (MAXSIZE = 250 GB); サイズ使用量は sys.database_files および関連する DMV で監視する。増加傾向に基づいてスケーリングを事前に計画する。","tags":["azure","size","quota","maxsize","size quota","scaling"]},{"code":"40613","title":"Database is not currently available (Azure SQL)（データベースが現在利用できない）","severity":"danger","meaning":"Azure SQL で対象データベースに現在到達できない。通常は一時的で、プラットフォームがデータベースの移動、再構成、復旧を行っている間に短時間発生する。","cause":"Azure 側での自動スケーリング/フェイルオーバー、パッチ適用、負荷分散、リソース再配置。まれに、より長いプラットフォームイベント。データベースがオンラインに戻るまで接続は拒否される。","fix":"少し待ってから再試行する。これは一時的なエラーである。アプリケーションに指数バックオフ付きの自動再試行を実装する。Azure SDK/再試行ライブラリはこのエラーコードを一時的なものとして認識する。問題が続く場合は Azure Service Health とリージョンのインシデントを確認する。高可用性のため、geo レプリケーション/フェイルオーバーグループを検討する。","tags":["azure","temporary","transient","availability","retry","failover"]}]},"errors/mongodb-more2.json":{"engineId":"mongodb","engine":"MongoDB","order":5,"errors":[{"code":"31 RoleNotFound","title":"Role not found（ロールが見つからない）","severity":"caution","meaning":"参照されたロールが MongoDB で定義されていない。ユーザーへのロール付与、ロールの更新、ロールの権限照会の際に、存在しないロール名が使用された。","cause":"grantRolesToUser/createUser でのロール名の綴り誤りまたは未作成のロール名、誤ったデータベースでのロール検索 (ロールは特定の DB に紐付く)、または createRole でまだ定義されていないカスタム (非組込み) ロール。","fix":"ロール名と所属するデータベースを確認する。既存ロールの一覧: db.getRoles({showBuiltinRoles: false}) または全 DB を対象とした対応する管理クエリ。カスタムロールが存在しない場合は先に作成する: db.createRole({role:'reader', privileges:[...], roles:[]})。付与時に正しい db を指定する: db.grantRolesToUser('app_user', [{role:'reader', db:'app'}])。","tags":["role","roles","authorization","access control","createrole","user"]},{"code":"263 OperationNotSupportedInTransaction","title":"Operation not supported inside a multi-document transaction（マルチドキュメントトランザクション内でサポートされない操作）","severity":"caution","meaning":"マルチドキュメントトランザクション内で、そのコンテキストではサポートされない操作が試行された。一部のコマンド (特に特定の DDL やメタデータ操作) はトランザクション内で実行できない。","cause":"トランザクション内でサポートされない操作: コレクション/インデックスの作成 (バージョンによる)、特定の count/list 系コマンド、またはトランザクションセッションで無効な管理コマンド。古い MongoDB はトランザクション内の DDL をサポートしない (一部は 4.4+ で追加された)。","fix":"サポートされない操作をトランザクションの外に移す (例: 必要なコレクション/インデックスをトランザクション開始前に作成する)。MongoDB のバージョンを確認する。4.4+ ではトランザクション内で一部の DDL がサポートされる。ドライバで別セッションにより操作を実行する。トランザクションはサポートされる CRUD 操作に限定する。","tags":["transaction","multi-document transaction","ddl","unsupported","session","crud"]},{"code":"20 IllegalOperation","title":"Illegal operation（不正な操作）","severity":"caution","meaning":"要求された操作が、サーバーの現在の状態または対象オブジェクトの種類に対して無効/禁止されている。論理的に許可されない操作を拒否する際に MongoDB が返す汎用エラー。","cause":"ビューに対するコレクション専用操作の試行、2 つのデータベース間での無効な名前変更、システムコレクションに対する禁止された変更、またはレプリカセット/シャーディング構成で許可されない管理操作。コンテキストによって異なる。","fix":"エラーメッセージの詳細を読む。通常、どの操作がなぜ禁止されたかが明示されている。操作を対象オブジェクトの種類に合わせる (例: ビューではなく基になるコレクションに対して操作する)。名前変更/移動操作では MongoDB の制約 (同一 DB 内での renameCollection など) を確認する。クラスタの状態 (レプリカセット/シャーディング) を確認する。","tags":["illegal","invalid","operation","view","rename","system"]},{"code":"48 NamespaceExists","title":"Namespace (collection) already exists（名前空間 (コレクション) が既に存在する）","severity":"safe","meaning":"作成しようとしているコレクション (名前空間) は既に存在する。MongoDB は存在することを報告しており、同じ名前とオプションで新しいコレクションを作成する必要はない。","cause":"既存のコレクションを createCollection で (異なるオプションで) 再作成しようとした、スキーマ/セットアップスクリプトが複数回実行された、または既存の名前を capped コレクションや特別なオプションで再定義しようとした。","fix":"通常は無視して問題ない。コレクションが既に存在することを意味する。セットアップスクリプトを冪等にする: 作成前に存在を確認する (db.getCollectionNames().includes('name'))。オプションを変更するにはコレクションを削除して再作成する必要がある (先にデータをバックアップする): db.my_collection.drop() の後に createCollection。","tags":["namespace","collection","collection exists","createcollection","already exists","idempotent"]},{"code":"11601 Interrupted","title":"Operation was interrupted（操作が中断された）","severity":"caution","meaning":"実行中の操作が中断された。外部からの介入またはサーバー状態の変化により、MongoDB が完了前に操作を終了した。","cause":"管理者/ツールによる db.killOp() での操作の強制終了、サーバーのシャットダウン開始、レプリカセットのプライマリ変更 (stepdown/フェイルオーバー)。(maxTimeMS の超過ではこのエラーではなく 50 MaxTimeMSExpired が返される。) 長時間実行のクエリはこの方法で停止されることがある。","fix":"操作が中断された理由を調査する: currentOp/killOp の履歴、フェイルオーバーイベント、サーバーメンテナンス。操作が冪等であれば安全に再試行する。長いクエリを最適化・短縮し、適切なインデックスを追加する。ドライバで一時エラーの再試行ロジックを使用し、レプリカセットのフェイルオーバー時に自動再接続されるようにする。","tags":["interrupted","interruption","killop","failover","stepdown","retry"]},{"code":"85 IndexOptionsConflict","title":"Index already exists with different options / different name（異なるオプション/名前のインデックスが既に存在する）","severity":"caution","meaning":"作成しようとしているインデックスが既存のインデックスと競合している: 同名のインデックスのオプションが異なる、または同じキーとオプションを持つ同等のインデックスが別名で既に存在する。MongoDB は競合する定義で同じインデックスを再作成することを許可しない。","cause":"同じ名前とキーで異なるオプション (例: expireAfterSeconds、partialFilterExpression、collation) のインデックスを作成した、または既存インデックスと同等のものを別名で再定義した ('Index already exists with a different name')。アプリケーション/マイグレーションスクリプトでインデックス定義が時間とともにずれていくのが典型的な原因。同じ名前で異なるキーの場合は、代わりに 86 IndexKeySpecsConflict となる。","fix":"既存のインデックスを確認する: db.my_collection.getIndexes()。本当にオプションを変更したい場合は、古いインデックスを削除して新しいものを作成する: db.my_collection.dropIndex('index_name') の後に createIndex(...)。そうでなければ、定義を既存のインデックスと完全に一致させるか、新しいインデックスに別の名前を付ける。マイグレーションスクリプトを冪等にする。","tags":["index","indexes","options","conflict","unique","createindex"]},{"code":"67 CannotCreateIndex","title":"Cannot create index（インデックスを作成できない）","severity":"caution","meaning":"制約または上限によりインデックスの構築が失敗した。既存のデータまたは構成のため、MongoDB は要求されたインデックスを構築できなかった。","cause":"コレクションあたりの最大インデックス数 (64) の超過、大きすぎるキー、または互換性のないオプションの組合せ (例: TTL インデックスに不適切なフィールド型)。注: 既存データに重複がある状態で一意インデックスを構築すると、このコードではなく E11000 DuplicateKey が発生する。","fix":"インデックス数の上限に達した場合は、未使用のインデックスを削除する ($indexStats で使用状況を分析)。キーのサイズ/型の互換性とオプションの組合せを確認する。大きなコレクションでは低負荷時にインデックスを構築する (4.2 以降、インデックス構築は書き込みを長時間ブロックしない。background オプションは無視される)。","tags":["index","indexes","unique","duplicate","limit","ttl"]},{"code":"27 IndexNotFound","title":"Index not found（インデックスが見つからない）","severity":"safe","meaning":"参照されたインデックスがコレクション上に見つからなかった。通常、存在しないインデックスを削除または名前変更しようとした場合に発生する。","cause":"dropIndex/hideIndex などのコマンドで誤ったインデックス名やキー指定を与えた、インデックスが以前に削除された、または自動生成されたインデックス名が想定と異なる (MongoDB は field_1_field2_-1 のような名前を生成する)。","fix":"既存のインデックスと正確な名前を一覧表示する: db.my_collection.getIndexes()。正しい名前またはキードキュメントで操作をやり直す: db.my_collection.dropIndex({field: 1}) または db.my_collection.dropIndex('field_1')。インデックスが存在しない場合でも失敗しないよう、削除スクリプトを (存在チェック付きで) 記述する。","tags":["index","indexes","dropindex","not found","getindexes","name"]},{"code":"79 UnknownReplWriteConcern","title":"Unknown replica set write concern（不明なレプリカセット write concern）","severity":"caution","meaning":"指定された書き込み確認 (write concern) が認識されない。操作で使用された w の値 (カスタム/タグ付き write concern 名または数値) がレプリカセット構成で定義されていない。","cause":"getLastErrorModes で定義されていないカスタム write concern 名の使用 (例: 'majority' のタイプミス、またはカスタムタグ名)。構成と要求が一致していない。注: 投票メンバー数を超える数値の w を要求した場合は別のエラー (100 UnsatisfiableWriteConcern) となる。","fix":"使用する write concern 名がレプリカセットの設定で定義されていることを確認する。現在の構成を確認: rs.conf() (settings.getLastErrorModes)。カスタムモードを使用する場合は先に定義するか、標準値 ('majority' または有効な数値 w) に切り替える。ドライバ/アプリケーションの接続文字列にある writeConcern の設定を見直す。","tags":["write concern","write acknowledgement","replica set","majority","getlasterrormodes","config"]}]},"errors/redis-more2.json":{"engineId":"redis","engine":"Redis","order":6,"errors":[{"code":"ERR DEBUG command not allowed","title":"DEBUG command not allowed（DEBUG コマンドは許可されていない）","severity":"caution","meaning":"DEBUG コマンドを実行しようとしたが、サーバーが許可していない。DEBUG は低レベルで危険な診断コマンドであり、セキュリティ上の理由から新しい Redis バージョンではデフォルトで無効化または制限されている。","cause":"Redis 7+ では enable-debug-command の設定なしに DEBUG サブコマンドは実行されない。マネージドクラウド Redis サービスでは通常このコマンドが完全に無効化されている。または ACL によってコマンドが拒否されている。テスト/診断スクリプト (例: DEBUG SLEEP、DEBUG OBJECT) がよくこのエラーに遭遇する。","fix":"本番環境では DEBUG を避ける。ローカル/テスト環境で本当に必要な場合は設定で有効にする: redis.conf に enable-debug-command yes (または 'local')。クラウドサービスでは通常このコマンドは有効化できないため、同等の情報には MEMORY USAGE、OBJECT ENCODING、INFO などの安全なコマンドを使用する。ACL による制限がある場合は権限を見直す。","tags":["debug","command","prohibited","security","acl","config"]},{"code":"ERR Can't save in background: fork failed","title":"Background save failed: fork failed（バックグラウンド保存失敗: fork 失敗）","severity":"danger","meaning":"Redis がバックグラウンドの RDB スナップショットまたは AOF 書換えのための子プロセスを作成 (fork) できなかった。永続化が実行できないため、データをディスクに書き込めない。","cause":"OS が fork に十分なメモリを割り当てられない。通常は overcommit_memory が無効で、Redis が使用中のメモリのほぼコピー分を確保しようとするとシステムが拒否する。物理/仮想メモリの不足やプロセス数の上限も原因となる。","fix":"Linux でメモリのオーバーコミットを有効にする: sysctl vm.overcommit_memory=1 (恒久化するには /etc/sysctl.conf に追加する)。サーバーにメモリを追加するか、Redis のメモリ使用量を下げる (maxmemory)。十分なスワップ領域を用意する。プロセス/ファイルディスクリプタの上限を確認する (ulimit)。永続化が重要な場合、これらの設定なしで本番運用しない。","tags":["fork","rdb","aof","persistence","overcommit","memory"]},{"code":"NOPROTO unsupported protocol version","title":"Unsupported RESP protocol version（サポートされない RESP プロトコルバージョン）","severity":"caution","meaning":"クライアントが、サーバーがサポートしない RESP プロトコルバージョンを要求した。通常、HELLO コマンドで RESP3 (バージョン 3) を要求し、サーバーが RESP2 のみをサポートしている場合に返される。","cause":"HELLO 3 を送信したが、サーバーが古い Redis バージョン (6.0 より前) で稼働している、または RESP3 をサポートしていない。クライアントライブラリがデフォルトで RESP3 を要求するがサーバーが古い。バージョンの不一致。","fix":"クライアントが RESP2 を使用するよう設定するか、HELLO で有効なバージョンを要求する (HELLO 2)。サーバーを RESP3 をサポートするバージョン (Redis 6+) にアップグレードする。クライアントライブラリのプロトコルバージョン設定を見直す。ほとんどのライブラリは自動的に RESP2 にフォールバックできる。サーバーバージョンを確認する: INFO server (redis_version)。","tags":["resp","protocol","hello","resp3","version","compatibility"]},{"code":"ERR Unknown option or number of arguments for CONFIG SET","title":"Unknown option or number of arguments for CONFIG SET (older versions: Unsupported CONFIG parameter)（CONFIG SET の不明なオプションまたは引数の数）","severity":"caution","meaning":"CONFIG SET で変更しようとした構成パラメータがこの Redis バージョンで認識されない、または引数の数が誤っている。Redis 7 での完全なメッセージは \"ERR Unknown option or number of arguments for CONFIG SET - '<name>'\" で、古いバージョンでは \"ERR Unsupported CONFIG parameter\" が返される。CONFIG GET は不明なパラメータに対してエラーにならず、空のリストを返す。","cause":"パラメータ名の綴り誤り、別の Redis バージョンのパラメータの使用 (パラメータはバージョン間で追加・削除される)、またはマネージドクラウドサービスが特定のパラメータの変更を許可していない。古いスクリプトを新しい/古いバージョンで実行することが典型的な原因。","fix":"有効なパラメータ名を確認する。CONFIG GET 'maxmemory*' のようにパターンで現在の設定を一覧表示する。使用している Redis バージョンのドキュメントでパラメータ一覧を確認し、バージョンは INFO server で確認する。クラウドサービスで制限されている場合は、プロバイダが許可するパラメータセットを使用する。スクリプトを対象バージョンに合わせて更新する。","tags":["config","parameter","unsupported","version","config set","config get"]},{"code":"ERR MULTI calls can not be nested","title":"MULTI calls can not be nested（MULTI はネストできない）","severity":"caution","meaning":"MULTI (トランザクション) ブロックが既に開いている状態で再度 MULTI が送信された。Redis はネストしたトランザクションブロックをサポートせず、同時に有効にできる MULTI は 1 つだけである。","cause":"前の MULTI を EXEC/DISCARD で閉じずに新しい MULTI を開始するアプリケーションロジック、トランザクション状態を正しくリセットせずにコネクションプールから同じ接続を再利用、またはライブラリのラッパーが気付かないうちに MULTI を 2 回呼び出している。","fix":"すべての MULTI ブロックを 1 回の EXEC (取り消す場合は DISCARD) で閉じ、前のブロックが終了してから新しいブロックを開く。コードフローでトランザクションの開始/終了を明確に分離する。接続をプールに返す前に、トランザクションが開いたままでないことを確認する。ネストしたロジックが必要な場合は、Lua スクリプト (EVAL) でアトミックな操作を行うことを検討する。","tags":["multi","transaction","nested","nested","exec","discard"]},{"code":"ERR Lua script attempted to access nonexistent global variable","title":"Lua script attempted to access a nonexistent global variable（Lua スクリプトが存在しないグローバル変数にアクセスしようとした）","severity":"caution","meaning":"EVAL/EVALSHA で実行した Lua スクリプトが未定義のグローバル変数にアクセスしようとした。スクリプト環境を保護するため、Redis はグローバル変数の作成/読み取りを制限し、そうしたアクセスをエラーとして返す。","cause":"スクリプト内で誤ってローカル変数ではなくグローバル変数を使用した (local キーワードの付け忘れ)、タイプミスによる未定義の名前へのアクセス、またはグローバル変数で状態を保持しようとした。サンドボックス化された Redis の Lua 環境ではこれらは許可されない。","fix":"スクリプト内のすべての変数を local で宣言する: local x = ... タイプミスを修正し、すべての変数が使用前に定義されていることを確認する。スクリプトはステートレスにする。永続的な状態にはグローバルな Lua 変数ではなく Redis のキー (KEYS/redis.call) を使用する。スクリプトは短く決定的に保つ。","tags":["lua","eval","script","global","variable","local"]},{"code":"ERR unknown command","title":"Unknown command（不明なコマンド）","severity":"caution","meaning":"送信したコマンドを Redis が認識しない。コマンド名が誤っている、このバージョンで利用できない、または無効化/名前変更されている可能性がある。","cause":"コマンド名の綴り誤り、新しい Redis バージョンで追加されたコマンド (古いサーバーには存在しない)、モジュールを必要とするコマンド (例: RedisJSON、RediSearch) をモジュール未ロードで呼び出した、または rename-command/ACL でコマンドが無効化された。クライアントによる誤った引数分割でコマンド名が壊れて見えることもある。","fix":"コマンド名と構文を確認する (COMMAND DOCS コマンドまたはドキュメント)。サーバーバージョンを確認する: INFO server。モジュールのコマンドの場合は、モジュールがロードされていることを確認する: MODULE LIST。rename-command でコマンドが隠されている場合は構成を見直す。クライアントライブラリがコマンドを正しくエンコードしていることを確認する。","tags":["command","unknown","unknown","version","module","acl"]},{"code":"TRYAGAIN Multiple keys request during rehashing of slot","title":"Multiple keys request during rehashing of slot (cluster)（スロットの rehash 中の複数キー要求）","severity":"caution","meaning":"Redis Cluster で、ハッシュスロットがノード間で移動中 (rehashing/resharding) に、同じスロットに属する複数のキーを含む要求が行われ、一部のキーは移動済みで他は未移動だった。サーバーは少し後で操作を再試行するよう求めている。","cause":"スロット移行の進行中に複数キーのコマンド (MGET、MSET、複数キーの Lua、トランザクション) を実行した。移行中のスロットでは一部のキーがソースノードに、一部がターゲットノードにあるため、コマンドをアトミックに実行できない。","fix":"クライアントでこのエラーを捕捉し、短時間待ってから再試行する (TRYAGAIN は一時的で、resharding が終了すると解消する)。複数キーの操作では、{app_user123}.profile、{app_user123}.settings のようにハッシュタグを使ってすべてのキーが同じスロットにあることを保証する。クラスタのリバランス (resharding) はトラフィックの少ない時間帯に実施する。","tags":["cluster","slot","rehash","resharding","tryagain","hash tag"]},{"code":"ERR DISCARD without MULTI","title":"DISCARD without MULTI（MULTI なしの DISCARD）","severity":"caution","meaning":"MULTI ブロックが開いていない状態で DISCARD が送信された。DISCARD は進行中のトランザクションを取り消すためだけに使用され、取り消す対象がない場合にこのエラーを返す。","cause":"MULTI なしで、またはトランザクションが既に EXEC/DISCARD で閉じられた後に再度 DISCARD を呼び出した、エラー処理コードでの無条件の DISCARD 呼出し、または接続状態が想定と異なる (プールから取得した接続で MULTI が開いていない)。","fix":"MULTI が実際に開いている場合にのみ DISCARD を呼び出し、コード内でトランザクション状態を追跡する。エラーハンドラでは DISCARD を呼ぶ前にトランザクションが開いているか確認する。状態を自動管理するライブラリのトランザクションラッパーを使用する。コネクションプールでクリーンな状態を保証する。","tags":["discard","multi","transaction","cancel","state","error handling"]}]},"errors/elasticsearch-more2.json":{"engineId":"elasticsearch","engine":"Elasticsearch","order":7,"errors":[{"code":"search_context_missing_exception","title":"No search context found for id (scroll expired)（id に対応する検索コンテキストがない (scroll 期限切れ)）","severity":"caution","meaning":"scroll クエリが使用する検索コンテキストがサーバー上にもう存在しない。通常、scroll コンテキストがタイムアウトまたはクリアされた後に、保存した scroll_id で続行しようとした場合に発生する。","cause":"scroll に指定した keep-alive が期限切れになった (要求間の間隔が長すぎる)、コンテキストが手動でクリアされた (clear scroll)、またはノードの再起動でコンテキストが失われた。scroll コンテキストはノードのメモリに保持されるため、存続期間は限られている。","fix":"すべての scroll 要求で十分な keep-alive を渡し (例: scroll=5m)、ページ間の遅延を短くする。最新の Elasticsearch では、深いページングに scroll ではなく search_after + Point in Time (PIT) を使用する。よりスケーラブルで推奨される方法である。終了したらコンテキストを解放し (clear scroll)、メモリを無駄にしない。","tags":["scroll","search_after","pit","context","timeout","pagination"]},{"code":"aliases_not_found_exception","title":"Aliases missing（エイリアスが存在しない）","severity":"safe","meaning":"操作しようとしているエイリアスが存在しない。通常、存在しないエイリアスを削除または操作しようとした場合に返される。","cause":"エイリアス名の綴り誤り、エイリアスが以前に削除された、または _aliases API の remove アクションで一度も付与されていないエイリアスを指定した。ワイルドカードパターンに一致するエイリアスがない場合にも発生する。","fix":"既存のエイリアスを一覧表示する: GET _alias、または特定のインデックスについては GET my-index/_alias。正しい名前で操作をやり直す。エイリアスが存在しない場合でも失敗しないよう削除スクリプトを記述し、_aliases の一括操作ではアクションを条件付きで処理する。エイリアスをアトミックに付け替えるには、1 つの _aliases 要求で add と remove を使用する。","tags":["alias","alias name","not found","aliases","index","routing"]},{"code":"snapshot_missing_exception","title":"Snapshot is missing（スナップショットが存在しない）","severity":"caution","meaning":"参照されたスナップショットが指定のリポジトリに見つからなかった。リストア、削除、ステータス要求の際に、存在しないスナップショット名が使用されたことを示す。","cause":"スナップショット名の綴り誤り、スナップショットが以前に削除された、誤ったリポジトリを照会した、またはバックアップが完了しなかった。リポジトリ定義が変更された場合や到達できない場合も同様の結果になる。","fix":"リポジトリ内のスナップショットを一覧表示する: GET _snapshot/repo_name/_all (特定の名前については GET _snapshot/repo_name/snapshot_name)。正しいリポジトリ名とスナップショット名で再試行する。リポジトリ定義を確認する: GET _snapshot/repo_name。バックアップポリシー (SLM) が正常に実行され、スナップショットが作成されていることを確認する。","tags":["snapshot","backup","repository","repo","restore","not found"]},{"code":"index_template_missing_exception","title":"Index template is missing（インデックステンプレートが存在しない）","severity":"safe","meaning":"参照されたインデックステンプレートが見つからなかった。テンプレートの取得、削除、またはテンプレートに基づく操作の際に、存在しないテンプレート名が使用された。","cause":"テンプレート名の綴り誤り、テンプレートが以前に削除された、レガシーテンプレート API とコンポーザブルインデックステンプレート API を混同した、またはテンプレートが作成されていない。セットアップスクリプトが完了しなかった場合にも発生する。","fix":"既存のテンプレートを一覧表示する。コンポーザブルテンプレート: GET _index_template または GET _index_template/name。レガシーテンプレート: GET _template。正しい API と名前で再試行する。テンプレートが存在しない場合は作成する: PUT _index_template/name {...}。テンプレートがなくても失敗しないよう、削除/更新スクリプトを冪等にする。","tags":["index template","template","composable","legacy","not found","mapping"]},{"code":"settings_exception","title":"Invalid settings（無効な設定）","severity":"caution","meaning":"指定された設定が無効なため、操作が拒否された。インデックスまたはクラスタの設定を適用する際に、設定名、値、またはそのコンテキストで変更可能かどうかに問題がある。","cause":"不明/綴り誤りの設定名、誤った型または許容範囲外の値、インデックス作成時にのみ設定できる静的設定 (例: number_of_shards) を稼働中のインデックスで変更しようとした、または削除/名前変更された設定の使用。","fix":"設定名と値をドキュメントで確認する。動的設定は稼働中のインデックスで更新する: PUT my-index/_settings {\"index.number_of_replicas\": 2}。静的設定 (例: number_of_shards) は作成時にのみ設定され、変更には reindex が必要。現在の設定を確認する: GET my-index/_settings。","tags":["settings","setting","invalid","static","dynamic","reindex"]},{"code":"shard_not_found_exception","title":"Shard not found（シャードが見つからない）","severity":"danger","meaning":"対象のシャードが見つからなかった。指定インデックスの該当シャードに到達できなかったため、Elasticsearch は要求を完了できなかった。","cause":"シャードがまだ割り当てられていない (unassigned) かリカバリ中、ノードがクラスタから離脱したためシャードが一時的に欠落している、またはシャードに直接ルーティングされた低レベル要求が有効でなくなったルーティング情報を持っている。クラスタの健全性が低下している場合に発生する。","fix":"クラスタとシャードの健全性を確認する: GET _cluster/health および GET _cat/shards?v。シャードが未割り当ての理由を確認する: GET _cluster/allocation/explain。ノードが失われた場合は復旧させ、ディスク/割り当ての設定 (watermark) を見直す。リカバリ中であれば完了を待つ。単一ノードを失ってもデータが利用可能であるよう、十分なレプリカ数を維持する。","tags":["shard","shard","unassigned","unassigned shard","recovery","cluster health"]},{"code":"not_x_content_exception","title":"Compressor detection error / body is not valid content（圧縮形式検出エラー / ボディが有効なコンテンツではない）","severity":"caution","meaning":"Elasticsearch が要求ボディを有効な構造化コンテンツ (JSON などの XContent) として認識できなかった。送信されたデータが想定された形式でないか、破損している。","cause":"要求ボディが無効な JSON、Content-Type ヘッダーの誤りまたは欠落 (application/json が送信されていない)、ボディが誤って圧縮/バイナリで送信された、または改行区切り JSON (NDJSON) を想定する _bulk などのエンドポイントに通常の JSON を送信した。エスケープ/エンコーディングの誤りでも発生する。","fix":"要求ボディが有効な JSON であることを確認し、Content-Type: application/json ヘッダーを送信する。_bulk エンドポイントでは、各行が個別の JSON オブジェクトで最終行が改行で終わる NDJSON を使用する (Content-Type: application/x-ndjson)。クライアントライブラリがボディを正しくシリアライズしていることを確認する。圧縮を使用する場合は、適切な Content-Encoding ヘッダーを送信する。","tags":["json","xcontent","content-type","bulk","ndjson","request body"]},{"code":"document_source_missing_exception","title":"Document source is missing（ドキュメントの source がない）","severity":"caution","meaning":"操作にはドキュメントの _source フィールドが必要だが、格納されていない。source が無効化されたインデックスで、_source を必要とする操作 (例: 部分更新、source の取得) が試行された。","cause":"インデックスのマッピングで _source: {enabled: false} が設定されている。ドキュメントの元の JSON が格納されないため、部分更新、reindex、_source を返すクエリは機能しない。領域節約のため source を無効化した構成がこの問題を引き起こす。","fix":"_source を必要とする操作には、マッピングで source が有効である必要がある。新しいインデックスを作成する際は _source を有効のままにする (デフォルトで有効)。既存のインデックスで _source が無効の場合は、更新ではなくドキュメント全体を再インデックスする (index API で上書き)。領域を節約するには、source を完全に無効化する代わりに _source フィルタリング (includes/excludes) または synthetic _source を検討する。","tags":["_source","source","update","mapping","reindex","document source"]}]},"errors/oracle-more3.json":{"engineId":"oracle","engine":"Oracle","order":1,"errors":[{"code":"ORA-00845","title":"MEMORY_TARGET not supported on this system（このシステムでは MEMORY_TARGET はサポートされない）","severity":"danger","meaning":"MEMORY_TARGET / MEMORY_MAX_TARGET で要求された自動メモリ管理が OS の共有メモリ構成でサポートされないため、インスタンスを起動できない。Linux では通常、/dev/shm が要求されたメモリターゲットより小さいことが原因。","cause":"MEMORY_TARGET が (tmpfs としてマウントされた) /dev/shm より大きく設定されている。または HugePages が有効な状態で MEMORY_TARGET (AMM) を使用している。AMM は HugePages と互換性がないが、ASMM (SGA_TARGET) は互換性がある。Oracle の自動メモリ管理は /dev/shm 上にファイルを作成して動作するため、この領域が不足するとインスタンスは起動しない。","fix":"/dev/shm を MEMORY_TARGET より大きくする: tmpfs を再マウントし (mount -o remount,size=8G /dev/shm)、/etc/fstab で恒久化する。あるいは AMM の代わりに個別の設定を使用する: MEMORY_TARGET と MEMORY_MAX_TARGET を 0 にし、SGA_TARGET と PGA_AGGREGATE_TARGET を定義する。HugePages を使用する場合は AMM を無効化し、ASMM (SGA_TARGET) を優先する。","tags":["memory_target","memory","amm","dev/shm","hugepages","startup"]},{"code":"ORA-27102","title":"out of memory（メモリ不足）","severity":"danger","meaning":"起動時に、Oracle インスタンスが OS に要求した共有メモリ (SGA) セグメントを割り当てられなかった。通常、ORA-27102 および下位レベルの OSD/Linux エラーコード (例: Linux-x86_64 Error: 28: No space left on device) と同時に発生する。","cause":"SGA に要求したメモリがカーネルの共有メモリ上限 (shmmax、shmall) を超えている、サーバーの物理 RAM/スワップが不足している、または HugePages の構成が欠落/不足しているため大きな SGA を割り当てられない。SGA_MAX_SIZE を増やした後によく発生する。","fix":"カーネルの共有メモリパラメータを増やす: /etc/sysctl.conf の kernel.shmmax と kernel.shmall を SGA をカバーする値に設定し、sysctl -p を実行する。HugePages を使用する場合は SGA に基づいて vm.nr_hugepages を計算・設定する。サーバーの総 RAM とスワップを確認し、必要に応じて SGA_MAX_SIZE / SGA_TARGET を下げる。","tags":["sga","memory","shmmax","hugepages","startup","osd"]},{"code":"ORA-04030","title":"out of process memory when trying to allocate N bytes（N バイトの割り当て時にプロセスメモリ不足）","severity":"danger","meaning":"サーバープロセスが PGA (Program Global Area)、すなわちプロセス固有のプライベートメモリに領域を割り当てられなかった。SGA の共有メモリとは異なり、単一のセッション/プロセス自身のメモリの枯渇である。","cause":"非常に大きなソート/ハッシュ操作、過大な PL/SQL コレクション、制御されないループで蓄積する変数、または OS のプロセスメモリ上限 (ulimit -v/-d、vm.max_map_count、アドレス空間) によりプロセスメモリが枯渇した。32 ビットのインスタンスではアドレス空間の上限も原因となる。","fix":"エラーの 2 行目にある割り当てカテゴリ (例: 'pga heap'、'koh-kghu sessi') を調べ、何がメモリを消費しているかを特定する。PGA_AGGREGATE_LIMIT / PGA_AGGREGATE_TARGET を見直す。OS の上限を確認する (ulimit -a。oracle ユーザーの memlock、as、stack)。クエリ/PL/SQL を最適化し、一括処理のバッチサイズを小さくする。必要に応じて、トレースファイルを添えて Oracle サポートに照会する。","tags":["pga","process memory","memory","ulimit","sort","plsql"]},{"code":"ORA-12537","title":"TNS:connection closed（接続がクローズされた）","severity":"danger","meaning":"通信チャネルが予期せずクローズされたため、クライアントとサーバー間の TNS 接続が終了した。接続の確立中または確立直後にセッションが切断される。","cause":"リスナーはクライアントをサーバープロセスに引き渡したが、プロセスを作成できなかったか即座に終了した: インスタンスのクラッシュ、PROCESSES の上限到達、OS のリソース不足、ファイアウォール/中間層による接続切断、または sqlnet.ora の TCP.VALIDNODE_CHECKING/TCP.INVITED_NODES ルールによるクライアントの拒否。クライアントとサーバー間のアイドル状態のファイアウォールが接続を切断することもある。","fix":"listener.log と sqlnet.log を調べる。PROCESSES/SESSIONS の上限を確認する: SELECT * FROM v$resource_limit WHERE resource_name IN ('processes','sessions'); サーバー側 sqlnet.ora の TCP.INVITED_NODES/TCP.EXCLUDED_NODES リストがクライアント IP を拒否していないことを確認する (ログオンバージョンの不一致はこのエラーではなく ORA-28040 となる)。ファイアウォールのアイドルタイムアウトを延長するか、SQLNET.EXPIRE_TIME で keepalive を送信する。alert.log でインスタンスクラッシュの記録を確認する。","tags":["tns","connection","listener","processes","firewall","sqlnet"]},{"code":"ORA-03135","title":"connection lost contact（接続が通信を失った）","severity":"danger","meaning":"確立済みで正常に動作していたセッションがサーバーとの通信を失った。双方が互いに到達できなくなったため、長時間実行のクエリまたはアイドル接続が切断された。","cause":"サーバープロセスが予期せず終了した (ORA-00600/07445、kill、リソース上限)、RESOURCE_LIMIT プロファイルがセッションを終了した、アイドル接続がファイアウォール/ロードバランサによって切断された、またはネットワーク障害/パケットロスが発生した。通常、長時間応答しないクエリやアイドル接続で発生する。","fix":"alert.log と関連トレースファイルでプロセス終了の理由を調べる (ORA-00600/ORA-07445 か)。ネットワーク側では、ファイアウォールのアイドルタイムアウトを延長し、sqlnet.ora の SQLNET.EXPIRE_TIME で停止接続検出を有効にする。ユーザープロファイルの CONNECT_TIME/IDLE_TIME の上限を確認する。サーバーのリソース逼迫 (メモリ、CPU、PROCESSES) を調べる。","tags":["connection","sqlnet","idle","firewall","dead connection","network"]},{"code":"ORA-01033","title":"ORACLE initialization or shutdown in progress（ORACLE の初期化またはシャットダウン中）","severity":"danger","meaning":"接続先のデータベースインスタンスが起動 (mount/open) またはシャットダウンの途中である。この中間状態では通常のユーザー接続は受け付けられない。","cause":"インスタンスが NOMOUNT/MOUNT で停止している (例: メディアリカバリ待ち)、SHUTDOWN が進行中、またはエラーにより OPEN に到達する前にデータベースがハングしている。起動直後のインスタンスに起動完了前に接続した場合もこのエラーが返される。","fix":"SYSDBA で接続して状態を確認する: sqlplus / as sysdba; 続いて SELECT status FROM v$instance; および SELECT open_mode FROM v$database; インスタンスのオープンを試みる: ALTER DATABASE OPEN; リカバリが必要な場合は RECOVER DATABASE; を実行してからオープンする。オープンを妨げている根本エラーを alert.log で特定する (データファイル/REDO の欠落・破損)。シャットダウンがハングしている場合は SHUTDOWN ABORT の後に STARTUP を試す。","tags":["startup","shutdown","mount","open","recovery","instance"]},{"code":"ORA-00600","title":"internal error code, arguments: [...]（内部エラーコード、引数: [...]）","severity":"danger","meaning":"Oracle カーネルの内部整合性チェックが失敗した。カーネルコードが予期しない状態に遭遇したことを示す汎用の内部エラーであり、角括弧内の引数がどのコードパスが起動されたかを示す。","cause":"ブロック/データ破損、未修正の Oracle ソフトウェアのバグ、パッチレベルの不整合、メモリ/ハードウェアの問題、または予期しないエッジケースが原因となる。第 1 引数 (例: [ktbdchk1]) は問題に関係する層を示し、サポートの分析で重要となる。","fix":"このエラーはほぼ常に Oracle サポートとともに対処すべきである。生成されたトレースファイルと alert.log のエントリを保全し、My Oracle Support で ORA-600 Troubleshooter と 'ORA-600 Lookup Tool' を使って第 1 引数を検索する。適切なパッチ/PSU/RU を適用する。破損が疑われる場合は DBVERIFY/RMAN VALIDATE でブロックの整合性を検証する。重要な環境では、SR を起票せずに本番環境で試行錯誤しない。","tags":["internal","ora-600","kernel","bug","trace","support"]},{"code":"ORA-07445","title":"exception encountered: core dump（例外発生: コアダンプ）","severity":"danger","meaning":"Oracle サーバープロセスが OS レベルの例外 (例: SIGSEGV セグメンテーション違反、アクセス違反) を受けて予期せずクラッシュし、コアダンプを生成した。ORA-00600 とは異なり、このエラーは OS からのシグナルによって発生する。","cause":"通常、Oracle ソフトウェアのバグ、メモリ破損、データ/インデックスブロックの破損、互換性のないライブラリ、またはハードウェア/メモリ障害が原因。メッセージ内の関数名とシグナルの種類 (例: SIGSEGV) が、クラッシュしたコードパスを示す。","fix":"生成されたトレースファイル、インシデントファイル、alert.log を保全し、関数名とシグナルで My Oracle Support を検索する。通常はパッチが必要。ハードウェア/メモリのテストを行い、OS と Oracle のパッチレベルを揃える。破損が疑われる場合は RMAN VALIDATE / DBVERIFY を実行する。再発する場合は SR を起票し、コアダンプをサポートに送付する。","tags":["ora-7445","core dump","sigsegv","kernel","bug","trace"]},{"code":"ORA-01102","title":"cannot mount database in EXCLUSIVE mode（EXCLUSIVE モードでデータベースをマウントできない）","severity":"danger","meaning":"別のインスタンス (または古いインスタンスの残存ファイル) がまだロックを保持しているように見えるため、データベースを EXCLUSIVE モードでマウントできない。インスタンスは MOUNT 段階で停止する。","cause":"前のインスタンスが正常にシャットダウンされずロックファイル ($ORACLE_HOME/dbs 下の lk<SID>、または残存する共有メモリ/セマフォ) が残っている、別のインスタンスが既に同じデータベースに接続している、または非 RAC 環境で 2 つ目のインスタンスが起動された。前のインスタンスの残存プロセス/共有メモリや古い lk<SID> ファイルが最も一般的な原因。","fix":"他のインスタンスが実際に稼働していないことを確認する: ps -ef | grep pmon および ipcs -m (共有メモリセグメント)。残骸がある場合はインスタンスを ABORT してクリーンアップし、必要に応じて ipcrm で残存セグメント/セマフォを削除する。$ORACLE_HOME/dbs 下の lk<SID> ロックファイルを削除する (インスタンスが確実に停止している場合のみ)。その後 STARTUP MOUNT を試す。RAC では CLUSTER_DATABASE とノードの状態を確認する。","tags":["mount","exclusive","lock","startup","pmon","instance"]},{"code":"ORA-29913","title":"error in executing ODCIEXTTABLEOPEN callout（ODCIEXTTABLEOPEN コールアウトの実行エラー）","severity":"caution","meaning":"外部表へのアクセス時に、ソースファイルの読み取り/解析中にエラーが発生した。外部表データの取得のために Oracle が呼び出すアクセスドライバ (ORACLE_LOADER / ORACLE_DATAPUMP) のルーチンで失敗した。","cause":"通常、DIRECTORY オブジェクトが指すパスにファイルが存在しない、Oracle の OS ユーザーにファイル/ディレクトリの読み取り権限がない、ログ/bad ファイルの書き込み権限がない、またはアクセスパラメータ (フィールド区切り文字、レコード形式) が誤っている。ORA-29400 や KUP-04xxx などのサブエラーを伴うことが多い。","fix":"サブエラー (KUP-xxxx) を読んで根本原因を特定する。DIRECTORY のパスとファイルの存在を確認する: SELECT directory_name, directory_path FROM all_directories; Oracle の OS ユーザーにファイルとディレクトリの読み取り権限、ログ/bad ディレクトリの書き込み権限を付与する。外部表定義の ACCESS PARAMETERS セクションをソースファイルの形式に合わせる。必要に応じて DIRECTORY に対する READ/WRITE 権限を確認する。","tags":["external table","external table","directory","oracle_loader","permission","kup"]}]},"errors/postgres-more3.json":{"engineId":"postgres","engine":"PostgreSQL","order":2,"errors":[{"code":"08001","title":"sqlclient_unable_to_establish_sqlconnection","severity":"danger","meaning":"クライアントが PostgreSQL サーバーへの接続を確立できなかった。セッションになる前に、ネットワーク/アドレスのレベルで接続が失敗した。","cause":"誤ったホスト/ポート、サーバーがリッスンしていないアドレス (listen_addresses = 'localhost' の状態でリモートから接続)、サーバーの停止/到達不能、ファイアウォールによるポート (デフォルト 5432) のブロック、または DNS 名前解決の失敗。コネクションプールの設定誤りでも発生する。","fix":"サーバーが起動しており正しいアドレスでリッスンしていることを確認する: postgresql.conf の listen_addresses = '*' (または該当 IP) と port の設定を確認し、サーバーを再起動する (listen_addresses と port は再起動が必要で、リロードでは不十分)。クライアントからアクセスをテストする: psql -h host -p 5432 -U app_user。ファイアウォールで 5432/tcp を開放する。host/port/DNS の値と接続文字列を見直す。","tags":["connection","connection","network","listen_addresses","port","firewall"]},{"code":"08004","title":"sqlserver_rejected_establishment_of_sqlconnection","severity":"danger","meaning":"サーバーには到達したが、サーバーが接続の確立を拒否した。ネットワークアクセスは存在するが、サーバーはポリシーによりこの接続を受け付けなかった。","cause":"PostgreSQL サーバーがこのコードを生成することはまれで、主にクライアントドライバやコネクションプールが報告する。同様の拒否に対するサーバーの実際のコードは異なる: pg_hba.conf による拒否 ('no pg_hba.conf entry for host'、reject メソッド) は 28000 (invalid_authorization_specification)、max_connections の枯渇は 53300 (too_many_connections)、起動/シャットダウン中の接続拒否は 57P03 を返す。","fix":"サーバーログで実際の SQLSTATE と拒否理由を確認する。pg_hba による拒否 (28000) の場合は、クライアント IP、ユーザー、データベースに一致する行を追加し (例: host all all 10.0.0.0/24 scram-sha-256)、SELECT pg_reload_conf(); でリロードする。接続の飽和 (53300) の場合は、SELECT count(*) FROM pg_stat_activity WHERE backend_type = 'client backend'; でクライアント接続数を max_connections と比較する。","tags":["connection","pg_hba","rejected","authentication","max_connections","reject"]},{"code":"57P01","title":"admin_shutdown","severity":"danger","meaning":"管理者コマンドにより、アクティブな接続が終了された。サーバーのシャットダウン中、またはセッションが手動で終了された場合にクライアントがこのエラーを受け取る ('terminating connection due to administrator command')。","cause":"DBA が pg_terminate_backend() でセッションを強制終了した、サーバーが fast/immediate モードでシャットダウンされている (smart シャットダウンはセッションを強制終了せず終了を待つ)、または構成変更/計画メンテナンスのため既存の接続が切断された。一部のフェイルオーバーシナリオでは、旧プライマリもこの方法で接続を切断する。","fix":"通常は恒久的なエラーではなく、アプリケーションは再接続 (再試行) する必要がある。予期しない場合は、サーバーログでシャットダウン/終了の理由を調査する。計画メンテナンスに備え、アプリケーションに自動再接続とコネクションプールのヘルスチェックを実装する。サーバーログには誰がセッションを終了したかは記録されない。pg_terminate_backend の呼出しを追跡するには、log_statement (または pgaudit) で監査証跡を残す。","tags":["shutdown","terminate","connection","maintenance","failover","retry"]},{"code":"53400","title":"configuration_limit_exceeded","severity":"danger","meaning":"構成上の上限を超えたため操作が失敗した。定義された上限 (例: temp_file_limit、レプリケーションスロット数や WAL sender 数) のため、サーバーが要求を拒否した。","cause":"典型例: クエリの一時ファイル使用量が temp_file_limit を超えた ('temporary file size exceeds temp_file_limit')、すべてのレプリケーションスロットが使用中 ('all replication slots are in use'、max_replication_slots)、max_wal_senders の上限超過。注: max_prepared_transactions の枯渇は 53200 を、準備済みトランザクションが無効 (値 0) の場合は 55000 を返す。","fix":"エラーメッセージに、どの上限を超えたかが示される。temp_file_limit の場合はクエリを最適化し (EXPLAIN ANALYZE でディスクに溢れるソート/ハッシュのステップを特定)、必要に応じてセッションレベルで work_mem を増やすか、意図的に上限を引き上げる。スロットが枯渇した場合は、所有者を確認したうえで未使用のスロットを整理する: SELECT slot_name, slot_type, active FROM pg_replication_slots; または max_replication_slots / max_wal_senders を増やしてサーバーを再起動する。","tags":["limit","temp_file_limit","replication slot","max_wal_senders","configuration","resource"]},{"code":"XX001","title":"data_corrupted","severity":"danger","meaning":"PostgreSQL がテーブル/ヒープページでデータ破損を検出した。読み取ったブロックの内容に不整合があるため、クエリを安全に完了できない ('invalid page in block')。","cause":"ディスク/ストレージ障害、ファイルシステムの破損、突然の電源喪失時に fsync の保証が守られなかった、ハードウェアの故障 (RAM/コントローラ)、またはまれにソフトウェアのバグ。チェックサムを有効にしていれば、破損はより早期に検出される。","fix":"まずハードウェア/ストレージを確認し、可能であれば直ちに物理バックアップ (PITR) への切戻しを計画する。正常なバックアップがあればリストアする。復旧のため、データを失うリスクを承知のうえで最後の手段としてのみ、zero_damaged_pages = on で破損ページをゼロ化し、読み取れるデータをエクスポートできる (データ損失を伴う)。data_checksums を有効にし (既存クラスタでは PG12+ でサーバー停止中に pg_checksums --enable)、RAM テストを実施し、定期的に PITR バックアップを取得する。","tags":["corruption","corruption","checksum","page","hardware","pitr"]},{"code":"XX002","title":"index_corrupted","severity":"danger","meaning":"インデックス構造で破損が検出された。インデックスが指すデータがヒープ内の実際の行と整合しないため、インデックスを使用するクエリが誤った結果を返すか失敗する可能性がある。","cause":"ハードウェア/ストレージ障害、OS の glibc/ICU アップグレード後の照合順序 (ソート規則) の変更による B-tree の順序の崩れ、または突然の停止。特に OS の照合順序の更新は、テキストインデックスに暗黙の破損を引き起こす。","fix":"破損したインデックスを再構築する: REINDEX INDEX idx_name; または REINDEX TABLE my_table; 大きなテーブルではロックを減らすため REINDEX INDEX CONCURRENTLY を使用する。照合順序が原因の場合は、影響を受けるすべてのテキストインデックスを再構築し、amcheck 拡張 (bt_index_check) で検証する。根本原因がハードウェアの場合はストレージを交換する。","tags":["index","index","corruption","reindex","collation","amcheck"]},{"code":"25001","title":"active_sql_transaction","severity":"caution","meaning":"トランザクションの外、またはトランザクションの開始時にしか実行できないコマンドが、トランザクションがアクティブな状態で呼び出された。一部のコマンドはトランザクションブロック内で実行できない。","cause":"SET TRANSACTION ISOLATION LEVEL などの設定は、ブロック内の最初のクエリより前に発行する必要がある ('SET TRANSACTION ISOLATION LEVEL must be called before any query')。同様に、一部のコマンドは開いている BEGIN/トランザクション内で拒否される。通常、アプリケーションが autocommit を無効にして暗黙にトランザクションを開始していることが原因。","fix":"トランザクションレベルの設定は、クエリを実行する前のトランザクションの冒頭で発行する: BEGIN; SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; ... クライアントライブラリが暗黙のトランザクションを開いていないか (autocommit の設定) を確認する。トランザクションブロック内で実行できないコマンドの場合は、先に COMMIT/ROLLBACK で現在のトランザクションを閉じる。","tags":["transaction","transaction","isolation","set transaction","autocommit","begin"]},{"code":"42P16","title":"invalid_table_definition","severity":"caution","meaning":"テーブル定義が無効なため、DDL コマンドが拒否された。要求されたテーブル/列の構造が PostgreSQL の規則に違反している。","cause":"複数の主キーの定義 ('multiple primary keys for table are not allowed')、継承と矛盾する定義、生成列/identity 列の制約、または ALTER TABLE で生成できない構造への変更などの状況。自動生成されたマイグレーションスクリプトでよく見られる。","fix":"エラーメッセージで具体的な理由を確認する。PRIMARY KEY は 1 つだけ定義し、複数列のキーが必要な場合は PRIMARY KEY (a, b) 形式の複合キーを使用する。identity/生成列の規則を見直す。\\d my_table で現在のテーブル定義を確認し、マイグレーションスクリプトを修正する。","tags":["ddl","table","primary key","definition","alter table","migration"]},{"code":"P0001","title":"raise_exception","severity":"caution","meaning":"PL/pgSQL の関数またはトリガーが RAISE EXCEPTION で意図的にエラーを発生させた。このエラーはデータベースエンジンではなく、利用者 (またはライブラリ) が記述した業務ルールのコードによって生成される。","cause":"業務ロジックの検証が失敗した際に、開発者が RAISE EXCEPTION 'message' USING ERRCODE = ...; を呼び出した。例えば、トリガーが許可されない更新を阻止したり、整合性ルールを強制したりするためにカスタムエラーを発生させる。","fix":"エラーメッセージと HINT/DETAIL フィールドが、関数が何を拒否したかを説明している。それに従って業務ルールを満たす。発生源を特定するには、該当する関数/トリガーのコード (RAISE 文) を調べる。特定の SQLSTATE が必要な場合は、汎用の P0001 ではなく RAISE ... USING ERRCODE で意味のあるコードを割り当て、アプリケーションが区別できるようにする。","tags":["plpgsql","raise","trigger","function","business rule","exception"]}]},"errors/mysql-more3.json":{"engineId":"mysql","engine":"MySQL","order":3,"errors":[{"code":"1049","title":"Unknown database 'name'（不明なデータベース 'name'）","severity":"caution","meaning":"接続または使用しようとしているデータベース (スキーマ) がサーバー上に存在しない。USE 文または接続文字列のデフォルトデータベース名が存在しないスキーマを指している。","cause":"データベースが作成されていない、名前の綴りが誤っている (大文字小文字の区別は OS によって異なる)、削除された、またはアプリケーションが誤った環境 (dev/prod) に接続している。新しいサーバーへの移行時にスキーマが移行されていないこともよくある原因。","fix":"既存のデータベースを一覧表示する: SHOW DATABASES; 名前の綴りが正しく、大文字小文字が一致していることを確認する (lower_case_table_names の設定が影響する)。存在しない場合は作成する: CREATE DATABASE database_name CHARACTER SET utf8mb4; またはバックアップからリストアする。アプリケーションの接続設定で対象環境を確認する。","tags":["database","database","schema","use","name","connection"]},{"code":"1364","title":"Field 'name' doesn't have a default value（フィールド 'name' にデフォルト値がない）","severity":"caution","meaning":"DEFAULT のない NOT NULL として定義された列に値を指定せずに行が挿入された。厳密 SQL モードでは、欠落した必須列を自動的に補完できないため MySQL はエラーを発生させる。","cause":"必須 (NOT NULL、DEFAULT なし) 列が INSERT から省略されており、sql_mode で STRICT_TRANS_TABLES/STRICT_ALL_TABLES が有効になっている。古い寛容なモード向けに書かれたアプリケーションを、厳密モードが有効なサーバーに移行するとこのエラーに遭遇する。","fix":"INSERT に欠落した列の値を追加するか、列に適切な DEFAULT を定義する: ALTER TABLE my_table MODIFY my_column ... NOT NULL DEFAULT 'value'; 列が本当に任意であれば NULL を許可する。一時的/互換性のための回避策として sql_mode を緩和することもできるが、データ品質のため厳密モードの維持を推奨する。","tags":["insert","not null","default","strict mode","sql_mode","column"]},{"code":"1206","title":"The total number of locks exceeds the lock table size（ロックの総数がロックテーブルのサイズを超えた）","severity":"danger","meaning":"InnoDB が保持するロック用に割り当てられたメモリ (バッファプール内のロック構造) を使い果たした。単一のトランザクションが過剰な行ロック/ギャップロックを蓄積した場合に発生し、トランザクションはロールバックされる。","cause":"非常に大きな単一トランザクション: 数百万行の一括 UPDATE/DELETE、テーブル全体をロックするインデックスのない WHERE 句、またはワークロードに対して小さすぎる innodb_buffer_pool_size。大規模なバッチジョブが典型的なきっかけ。","fix":"大きな DML を小さなバッチに分割する (例: ループ内で LIMIT を使って 10,000 行ずつ削除/更新し、各バッチ後に COMMIT する)。WHERE の列にインデックスを作成し、ロックされる行数を減らす。恒久対策として innodb_buffer_pool_size を増やす (ロック構造はここから割り当てられる)。不必要に長いトランザクションを避ける。","tags":["innodb","lock","lock","buffer pool","batch","memory"]},{"code":"1236","title":"Got fatal error 1236 from master when reading data from binary log（バイナリログの読み取り中にマスターから致命的エラー 1236）","severity":"danger","meaning":"レプリカ (スレーブ) サーバーがソース (マスター) のバイナリログからデータを読み取る際に致命的なエラーを受け取り、レプリケーションが停止した。レプリカはソースの binlog 内で想定している位置を見つけられない。","cause":"必要なバイナリログファイルがソースで削除された (binlog_expire_logs_seconds — 8.0 より前は expire_logs_days で、8.4 で削除 — または PURGE BINARY LOGS)、GTID の欠落/不一致、ソースのクラッシュ後の binlog 位置の破損、またはレプリカの遅延が大きすぎて既に存在しないログを要求している。'Could not find first log file name in binary log index file' が典型的なサブメッセージ。","fix":"レプリケーションの状態を確認する: SHOW REPLICA STATUS\\G (8.0.22+。古いバージョンでは SHOW SLAVE STATUS で、旧構文は 8.4 で削除された)。ソースで利用可能な binlog を一覧表示する: SHOW BINARY LOGS; 欠落したログがパージされている場合は、新しいバックアップ/GTID 位置からレプリカを再構築する必要がある (mysqldump --source-data — 8.0.26 より前は --master-data で、8.0.26+ では非推奨の別名 — または CLONE プラグイン)。ワークロードに合わせてソースの binlog 保持期間を延長し、GTID を使用している場合は GTID の欠落を確認する。","tags":["replication","replication","binlog","master","gtid","slave"]},{"code":"1129","title":"Host 'host' is blocked because of many connection errors（接続エラーが多いためホスト 'host' がブロックされた）","severity":"danger","meaning":"クライアントホストからの連続した接続エラーがしきい値 (max_connect_errors) を超えたため、MySQL がそのホストをブロックした。それまでに失敗したハンドシェイクにより、ホストがブラックリストに登録された。","cause":"ロードバランサ/監視ツールが TCP ポートに不完全または不正なハンドシェイクを送信している、ネットワークの問題で接続が途中で切断される、または設定誤りのクライアントが失敗する接続を繰り返している。エラーカウンタが max_connect_errors に達するとホストがブロックされる。","fix":"直ちにブロックを解除する: SQL では TRUNCATE TABLE performance_schema.host_cache; (8.0.23+。FLUSH HOSTS は 8.0.23 で非推奨となり 8.4 で削除された)、コマンドラインでは mysqladmin flush-hosts。ブロックされたホストの確認: SELECT host, ip, sum_connect_errors FROM performance_schema.host_cache; 根本原因を修正する: ヘルスチェック/監視ツールが完全な MySQL ハンドシェイクを行うよう設定し、ネットワークの安定性を確認する。健全な環境では許容度を上げるため max_connect_errors を引き上げることもできるが、重要なのは実際の接続エラーを解決することである。","tags":["connection","host blocked","max_connect_errors","flush hosts","handshake","network"]},{"code":"1194","title":"Table 'name' is marked as crashed and should be repaired（テーブル 'name' がクラッシュとしてマークされ修復が必要）","severity":"danger","meaning":"通常 MyISAM エンジン (MariaDB では Aria も) で格納されたテーブルが破損/クラッシュとしてマークされ、修復されるまで使用できない。テーブルにアクセスするクエリはこのエラーで失敗する。","cause":"突然のサーバークラッシュ/電源喪失、ディスク満杯、ハードウェア障害、または mysqld プロセスの強制終了の際に MyISAM テーブルが正常にクローズされなかった。MyISAM はトランザクションもクラッシュ安全性も提供しないため、InnoDB よりもはるかに頻繁に発生する。","fix":"テーブルを修復する: REPAIR TABLE table_name; またはオフラインで myisamchk -r。修復前に必ずデータファイルをバックアップする。恒久対策としてテーブルを InnoDB に移行する: ALTER TABLE my_table ENGINE=InnoDB; これによりクラッシュセーフになる。ディスクの健全性と myisam_recover_options の設定を確認する。","tags":["myisam","crashed","repair","corruption","corruption","innodb"]},{"code":"1615","title":"Prepared statement needs to be re-prepared（プリペアド文の再準備が必要）","severity":"caution","meaning":"サーバー側のプリペアド文が、依存するメタデータ (テーブル/ビュー定義) の変更後に無効となったため、実行が拒否された。文を再度準備する必要がある。","cause":"文の準備後に基になるテーブルに対する DDL (ALTER TABLE)、テーブルの再作成、メタデータキャッシュが満杯になりエントリが追い出された、または table_definition_cache/table_open_cache の上限が小さすぎる。DDL の多いシステムや一部の ORM/プールのシナリオでよく見られる。","fix":"ほとんどのクライアントライブラリはこれを捕捉して自動的に文を再準備する。アプリケーションでは、このエラーを捕捉して prepare + execute を再試行する。頻繁に再発する場合は table_definition_cache と table_open_cache を増やす。アプリケーションのトラフィック中に不要な DDL を避ける。","tags":["prepared statement","re-prepare","ddl","metadata","cache","retry"]},{"code":"1553","title":"Cannot drop index needed in a foreign key constraint（外部キー制約で必要なインデックスは削除できない）","severity":"caution","meaning":"外部キー制約が必要とするインデックスを削除しようとしている。InnoDB は FK が依存するインデックスの削除を許可しない。","cause":"InnoDB では、すべての外部キーは参照元の列にインデックスを必要とする。DROP INDEX でそのインデックスを削除すると FK 制約の裏付けがなくなるため、拒否される。通常、テーブルの再編成 (インデックスの整理) 中に発生する。","fix":"先に外部キー制約を削除してから、インデックスを削除する: ALTER TABLE my_table DROP FOREIGN KEY fk_name; 続いて DROP INDEX idx_name ON my_table; 必要に応じて、別の適切なインデックスに依存するよう FK を再作成する。既存の FK の一覧: SELECT constraint_name, table_name FROM information_schema.key_column_usage WHERE referenced_table_name IS NOT NULL;","tags":["foreign key","foreign key","index","drop index","innodb","constraint"]},{"code":"3948","title":"Loading local data is disabled; this must be enabled on both the client and server sides（ローカルデータの読込みは無効。クライアントとサーバーの両側で有効化が必要）","severity":"caution","meaning":"LOAD DATA LOCAL INFILE でクライアント側のファイルからデータを読み込もうとしたが、クライアント側とサーバー側の一方または両方でこの機能が無効になっている。セキュリティ上の理由から、MySQL 8 では LOCAL はデフォルトで無効。","cause":"サーバーで local_infile システム変数が OFF になっている、およびクライアントドライバで LOCAL INFILE が有効になっていない、のいずれかまたは両方。悪意あるサーバーがクライアントのファイルを読み取れる可能性があるため、この機能はデフォルトで制限されている。","fix":"本当に必要な場合は両側で有効にする: サーバーで SET GLOBAL local_infile = 1; クライアントではドライバの LOCAL INFILE フラグを有効にする (例: 接続オプション allowLoadLocalInfile / --local-infile=1)。セキュリティの観点からは、ファイルをサーバー上に置いて LOCAL なしの LOAD DATA INFILE を使用するか、一括 INSERT/インポートツールを使用するのが望ましい。作業が終わったら local_infile を再度無効にする。","tags":["load data","local infile","local_infile","security","import","loading"]},{"code":"1075","title":"Incorrect table definition; there can be only one auto column and it must be defined as a key（不正なテーブル定義。自動採番列は 1 つのみでキーとして定義が必要）","severity":"caution","meaning":"AUTO_INCREMENT の規則に違反しているため、テーブル定義が無効。テーブルに持てる自動採番列は 1 つだけで、その列はキー (PRIMARY KEY または UNIQUE/インデックス) の一部でなければならない。","cause":"複数の AUTO_INCREMENT 列を定義した、または AUTO_INCREMENT 列をどのキー (インデックス) にも含めなかった。CREATE TABLE または ALTER TABLE の実行時に発生する。","fix":"AUTO_INCREMENT 列は 1 つに限定し、キーの一部にする: CREATE TABLE t (id INT AUTO_INCREMENT PRIMARY KEY, ...); 既存のテーブルを修正するには、先に列をキーに追加する: ALTER TABLE t ADD PRIMARY KEY (id); その後 AUTO_INCREMENT を定義する。複数の自動採番列が必要な場合は設計を見直す。MySQL はこれをサポートしない。","tags":["auto_increment","table","primary key","key","ddl","definition"]}]},"errors/mssql-more3.json":{"engineId":"mssql","engine":"SQL Server","order":4,"errors":[{"code":"102","title":"Incorrect syntax near 'token'（'token' 付近の構文が正しくない）","severity":"caution","meaning":"Transact-SQL パーサーが指定されたトークン付近で無効な構文を検出し、文をコンパイルできなかった。クエリは実行前に拒否される。","cause":"タイプミス、カンマ/括弧の欠落、角括弧で囲まずに使用した予約語 (例: USER、ORDER)、閉じられていない文字列リテラル、または別の SQL 方言からコピーした互換性のない構文。動的 SQL での連結の誤りもよくあるきっかけ。","fix":"報告されたトークン周辺を注意深く確認する。エラーは前の行にあることが多い。予約語は角括弧で囲み ([Order])、括弧とカンマの対応を確認する。動的 SQL を組み立てる場合は、PRINT @sql で生成されたテキストを確認して実行する。構文がバージョン/互換性レベルでサポートされていることを確認する。","tags":["syntax","syntax error","parse","tsql","dynamic sql","keyword"]},{"code":"8114","title":"Error converting data type X to Y（データ型 X から Y への変換エラー）","severity":"caution","meaning":"型に互換性がないため、値をあるデータ型から別のデータ型に変換できなかった。エラー 245 とは異なり、通常はパラメータ/式のレベルでの型変換の失敗である (例: varchar から numeric)。","cause":"数値以外または不正な形式のテキストを数値列/パラメータに送信した、スケール/精度のオーバーフロー、空文字列 ('') を数値に変換しようとした、またはパラメータ化クエリで誤った型の引数を渡した。ORM が生成する暗黙の変換でよく見られる。","fix":"変換される値が対象の型に適合することを確認する。安全な変換には TRY_CONVERT / TRY_CAST を使用する。失敗時に NULL を返すため、それらの行を WHERE で除外できる。パラメータの型を列の型に合わせる。ISNUMERIC/TRY_CAST でデータを走査して問題の行を見つけ、空文字列を整理する。","tags":["convert","cast","data type","conversion","numeric","try_convert"]},{"code":"1204","title":"The instance of the SQL Server Database Engine cannot obtain a LOCK resource（SQL Server データベースエンジンのインスタンスが LOCK リソースを取得できない）","severity":"danger","meaning":"SQL Server がロックマネージャに必要なメモリを割り当てられず、これ以上ロックを作成できない。ロックメモリプールが枯渇したため操作が失敗する。","cause":"同時に保持される細粒度 (行/ページ) ロックが多すぎる: 大規模、インデックスなし、または一括の DML、ロックエスカレーションが抑止されている、サーバー全体のメモリ逼迫、または長時間開いたままのトランザクション。外部からのメモリ逼迫がきっかけになることもある。","fix":"大きな操作を小さなバッチに分割し、同時ロック数を減らす。適切なインデックスを使用し、走査/ロックされる行数を減らす。ロックエスカレーションを無効化する構成を見直す: トレースフラグ 1211/1224 および ALTER TABLE ... SET (LOCK_ESCALATION = DISABLE)。SELECT name, lock_escalation_desc FROM sys.tables; と DBCC TRACESTATUS(-1); で確認する。サーバーメモリと max server memory の設定を確認し、メモリ逼迫を緩和する。","tags":["lock","lock memory","memory","lock escalation","batch","resource"]},{"code":"3906","title":"Failed to update database because the database is read-only（データベースが読み取り専用のため更新に失敗）","severity":"caution","meaning":"読み取り専用としてマークされたデータベースでデータを変更 (INSERT/UPDATE/DELETE/DDL) しようとした。SQL Server が書き込みを拒否した。","cause":"データベースが READ_ONLY に設定された、接続が可用性グループのセカンダリレプリカ (読み取り用) に向かった、スナップショットまたはリストア後にデータベースが読み取り専用のままになっている、またはファイルシステムが読み取り専用。誤ってセカンダリレプリカにルーティングされたアプリケーションが典型的な原因。","fix":"本当に書き込み可能にする必要がある場合: ALTER DATABASE mydb SET READ_WRITE; 可用性グループでは、アプリケーションをプライマリレプリカにルーティングする (ReadWrite 接続ルーティング / ApplicationIntent を確認)。読み取り専用のスナップショットには書き込めないため、ソースデータベースを対象にする。ファイルの権限とファイルシステムも確認する。","tags":["read only","read-only database","availability group","replica","read_write","write"]},{"code":"15023","title":"User already exists in the current database（ユーザーは現在のデータベースに既に存在する）","severity":"caution","meaning":"データベースに新しいユーザーを追加する際、同名のユーザーがそのデータベースに既に存在していた。ログインを既存のユーザーにマッピングする場合 (孤立ユーザー) にも発生する。","cause":"典型的には、データベースをバックアップから別のサーバーにリストアすると、ログインの SID がデータベースユーザーと一致しない (孤立ユーザー)。CREATE USER で同じ名前を再度追加しようとしたり、ログインとユーザーのマッピングを手動で設定しようとしたりすると、このエラーが発生する。","fix":"孤立ユーザーを既存のログインに再マッピングする: ALTER USER app_user WITH LOGIN = login_name; (旧来の sp_change_users_login より推奨)。ユーザーが本当に不要な場合: DROP USER app_user; 孤立ユーザーの検出: SELECT dp.name FROM sys.database_principals dp LEFT JOIN sys.server_principals sp ON dp.sid = sp.sid WHERE sp.sid IS NULL AND dp.type IN ('S','U');","tags":["user","database user","login","orphaned","restore","orphaned user"]},{"code":"18452","title":"Login failed. The login is from an untrusted domain and cannot be used with Windows authentication（ログイン失敗。信頼されていないドメインからのログインで Windows 認証に使用できない）","severity":"danger","meaning":"Windows 認証によるログイン試行が、信頼されていないドメインからのものであった (または SQL 認証が必要な箇所で Windows 認証が使用された) ため拒否された。サーバーはこの ID を信頼していない。","cause":"クライアントが SQL Server の信頼しないドメイン/ワークグループの Windows ID で接続している、マシンが異なる/信頼関係のないドメインにある、Kerberos/SPN の構成が誤っている、または SQL 認証が想定されているのに接続文字列で Integrated Security を使用している。混合モードが無効な状態での SQL ログイン試行でも同様の症状となる。","fix":"SQL 認証が必要な場合は、サーバーを混合モードに切り替え、接続文字列でユーザー名/パスワードを使用する (Integrated Security=false)。Windows 認証が必要な場合は、ドメインの信頼関係と DNS/Kerberos SPN の構成を確認する。クライアントとサーバーが同一または信頼されたドメインにあることを確認する。エラーログの 'state' 値で原因を絞り込む。","tags":["login","authentication","windows","domain","kerberos","mixed mode"]},{"code":"605","title":"Attempt to fetch logical page belongs to a different allocation unit（取得しようとした論理ページが別のアロケーションユニットに属する）","severity":"danger","meaning":"ページの読み取り中に、SQL Server が想定したオブジェクト/アロケーションユニットではなく別のオブジェクトに属するページを検出した。深刻な物理的/論理的データベース破損を強く示す。","cause":"ストレージ/ディスク障害、コントローラやドライバのバグ、突然の電源喪失時の書き込みキャッシュの破損、またはファイルシステムの損傷によるページリンクの破壊。'transient 605' はまれに一時的な I/O の問題に起因することがあるが、継続する場合は実際の破損である。","fix":"直ちに DBCC CHECKDB ('mydb') WITH NO_INFOMSGS, ALL_ERRORMSGS を実行して損傷の範囲を特定する。可能であれば、正常であることが確認済みのバックアップからリストアする (データ損失を最小化する PITR が望ましい)。ストレージ/ハードウェアをテストし、PAGE_VERIFY CHECKSUM の設定を確認する。REPAIR オプションはデータ損失を伴う可能性があるため、バックアップを取得したうえで最後の手段としてのみ使用する。重要な環境では Microsoft サポートに相談する。","tags":["corruption","database corruption","page","allocation unit","dbcc checkdb","storage"]},{"code":"4922","title":"ALTER TABLE ALTER COLUMN failed because one or more objects access this column（1 つ以上のオブジェクトがこの列にアクセスしているため ALTER TABLE ALTER COLUMN が失敗）","severity":"caution","meaning":"列の型/プロパティを変更しようとしたが、その列に依存するオブジェクト (インデックス、制約、計算列、統計、スキーマバインドされたビューなど) が妨げた。依存関係を解消するまで列は変更できない。","cause":"列がインデックス、PRIMARY KEY/UNIQUE/CHECK/DEFAULT 制約、計算列の式、WITH SCHEMABINDING で定義されたビュー/関数、または統計オブジェクトで使用されている。型/サイズの変更はそれらのオブジェクトを無効にするため、ALTER が拒否される。","fix":"まず依存オブジェクトを特定して一時的に削除または無効化し、列を変更してから再作成する。依存関係の確認には sys.sql_expression_dependencies と sys.indexes/sys.default_constraints を照会する。一般的な順序: DROP CONSTRAINT/INDEX -> ALTER COLUMN -> 再度 CREATE。スキーマバインドされたビューでは、一時的に SCHEMABINDING を外してから付け直す。","tags":["alter column","dependency","index","constraint","schemabinding","ddl"]},{"code":"7202","title":"Could not find server 'name' in sys.servers（sys.servers にサーバー 'name' が見つからない）","severity":"caution","meaning":"クエリでリンクサーバーまたは 4 部構成名 (server.database.schema.object) により参照されたサーバー名が、構成済みのリンクサーバーの中に見つからなかった。SQL Server は名前を解決できなかった。","cause":"リンクサーバーが定義されていない、名前の綴りが誤っている、別の環境 (dev/prod) に存在するリンクサーバーが本番環境にない、または OPENQUERY/4 部構成名が誤ったサーバー名を指している。スクリプトをサーバー間で移行した際によく発生する。","fix":"定義済みのリンクサーバーを一覧表示する: SELECT name FROM sys.servers; または EXEC sp_linkedservers。必要であれば追加する: EXEC sp_addlinkedserver @server='SERVER', ...; さらに sp_addlinkedsrvlogin でログインマッピングを設定する。クエリの 4 部構成名が正しいリンクサーバー名を使用していることを確認する。ローカルのオブジェクトにのみアクセスする場合は、サーバープレフィックスを削除する。","tags":["linked server","remote server","sys.servers","openquery","four-part name","configuration"]},{"code":"40501","title":"The service is currently busy. Retry the request after 10 seconds（サービスは現在ビジー。10 秒後に要求を再試行）","severity":"danger","meaning":"Azure SQL Database で、リソース逼迫 (エンジンのスロットリング) によりサービスが一時的に要求を拒否した。システムがビジー状態であり、クライアントは少し後で再試行することが求められる。","cause":"CPU、接続数、トランザクションログの書き込み速度、ワーカー数などのリソースが、選択したサービスレベル (DTU/vCore) の上限に達した、急激な負荷増大、またはリソースを消費する長時間実行/非効率なクエリ。エラーに付随する 'reason code' が、どのリソースがスロットリングされているかを示す。","fix":"アプリケーションに指数バックオフ付きの再試行ロジックを実装する。これは一時的なエラーに対する想定された動作である。リソース使用状況を確認する: sys.dm_db_resource_stats と Azure ポータルのメトリクス。クエリ/インデックスを最適化し、不要な同時実行を減らす。飽和が継続する場合はサービスレベル (DTU/vCore) をスケールアップする。","tags":["azure","throttling","busy","retry","resource","dtu"]}]},"errors/mongodb-more3.json":{"engineId":"mongodb","engine":"MongoDB","order":5,"errors":[{"code":"10107 NotWritablePrimary","title":"not master / not writable primary（マスターではない / 書き込み可能なプライマリではない）","severity":"danger","meaning":"書き込み (またはプライマリを必要とする他の操作) が、現在プライマリではないレプリカセットメンバーに送信された。書き込みを受け付けるのはプライマリのみであるため、操作は拒否された。","cause":"アプリケーションがセカンダリに書き込んでいる、フェイルオーバー (選出) 中に旧プライマリがセカンダリとなりクライアントがまだそこに接続している、またはドライバの読み書き設定とトポロジ情報が古い。接続文字列に replicaSet パラメータがないことが典型的な原因。","fix":"ドライバにレプリカセットの全メンバーとレプリカセット名を設定する (接続文字列に replicaSet=... と全ホスト)。これによりドライバがプライマリを自動検出し、フェイルオーバー時に再ルーティングする。書き込みをプライマリにルーティングするデフォルトの読み書き設定を使用する。一時的なエラーであるため、アプリケーションで retryable writes を有効にする。どのメンバーが PRIMARY かを rs.status() で確認する。","tags":["replica set","primary","failover","write","election","retryable"]},{"code":"91 ShutdownInProgress","title":"The server is in the process of shutting down（サーバーはシャットダウン処理中）","severity":"danger","meaning":"サーバー (mongod/mongos) がシャットダウン中のため、操作を完了できなかった。シャットダウン中のノードは新しい要求を拒否し、進行中の操作を終了する。","cause":"計画された再起動/メンテナンス、レプリカセットでのプライマリ stepdown に先立つシャットダウン、コンテナ/オーケストレーターから送信された終了シグナル、またはリソース枯渇によるプロセスの停止。ローリングアップグレード中には想定される。","fix":"通常は一時的である。アプリケーションで再試行ロジックとレプリカセット接続を使用し、要求が別の正常なメンバーにルーティングされるようにする。予期しない場合は、mongod のログでシャットダウンの理由 (シグナル、OOM killer、リソース) を確認する。ローリングメンテナンス中は、シャットダウン前にプライマリを正しく stepdown させる (rs.stepDown())。","tags":["shutdown","shutting down","maintenance","stepdown","replica set","retry"]},{"code":"189 PrimarySteppedDown","title":"Primary stepped down while operation was in progress（操作の進行中にプライマリが stepdown した）","severity":"danger","meaning":"操作の実行中にプライマリが stepdown し、書き込みを受け付けなくなった。そのため進行中のコマンドは中止された。","cause":"レプリカセットで選出が発生した: メンテナンスのためプライマリが手動で stepdown された、過半数との通信を失った、優先度が変更された、またはネットワーク分断が発生した。フェイルオーバー時点で実行中の操作がこのエラーを受け取る。","fix":"通常は再試行可能なエラーである。ドライバで retryable writes/reads を有効にすると、操作は新しいプライマリに自動的にルーティングされる。アプリケーションでこのエラーを捕捉して再試行する。頻繁に発生する場合はレプリカセットの健全性を調査する: rs.status() でメンバーの状態、ネットワーク遅延、oplog ラグを確認し、不要な選出を減らす (heartbeat/timeout の設定)。","tags":["stepdown","election","failover","primary","replica set","retry"]},{"code":"24 LockTimeout","title":"Operation exceeded time limit waiting for a lock（ロック待機中に操作が制限時間を超えた）","severity":"caution","meaning":"操作が必要なロック (例: データベース/コレクションレベル) を待機中に制限時間を超え、中止された。ロックを時間内に取得できなかった。","cause":"長時間実行の操作または DDL コマンド (例: コレクションに対する競合する管理操作) が必要なロックを保持している、高い同時書き込み、または maxTimeMS で制限された操作がロック待機中に期限切れとなった。競合するインデックス/コレクション操作で見られる。","fix":"ロックを保持している操作を特定する: db.currentOp() でアクティブおよび待機中の操作を調べ、必要に応じて db.killOp() で終了する。競合する管理コマンド (インデックス構築、collMod、compact) はオフピーク時間帯に移す。操作を短く保ち、不必要に長いトランザクションを避ける。必要であれば maxTimeMS をワークロードに合わせて調整する。","tags":["lock","lock wait","timeout","currentop","ddl","concurrency"]},{"code":"7 HostNotFound","title":"Could not find host（ホストが見つからない）","severity":"danger","meaning":"MongoDB が接続しようとしたホスト名を解決/検出できなかった。ドライバまたはレプリカセットメンバーが指定ホストに到達できないため、接続を確立できない。","cause":"DNS 名前解決の失敗、接続文字列の誤った/古いホスト名、クライアントが解決できないレプリカセットメンバーのホスト名 (rs.conf)、またはネットワーク/アクセスの問題。コンテナ環境では、外部から解決できない内部ホスト名が典型的な原因。","fix":"ホスト名が正しく解決可能であることを確認する (ping/nslookup で DNS をテスト)。接続文字列のホストを更新する。レプリカセットメンバー名がクライアントとメンバーの両方から解決可能であることを確認し、必要に応じて rs.conf() のホスト名を到達可能な FQDN/IP に更新する。SRV (mongodb+srv) を使用している場合は DNS の SRV レコードを確認する。","tags":["host","dns","connection","replica set","network","srv"]},{"code":"175 QueryPlanKilled","title":"Query plan killed during execution（実行中に実行計画が強制終了された）","severity":"caution","meaning":"基になるデータ/コレクションが変更されたため、実行中のクエリのプランが無効になり強制終了された。安全に続行できないためクエリは中止された。","cause":"クエリの実行中 (特にカーソルが開いている間) にコレクションが削除された、使用中のインデックスが削除された、または名前変更/再構成が行われた。長時間実行の getMore 呼出し中の基盤の変更が典型的なきっかけ。","fix":"クエリ/カーソルを再開する (再試行)。クエリの実行中にコレクションやインデックスに対して破壊的な DDL (drop、dropIndex、rename) が実行されないようにし、そうしたメンテナンスはクエリトラフィック外に計画する。長時間実行の読み取りを短縮し、必要なインデックスが恒久的に存在するようにする。","tags":["query","cursor","getmore","drop","index","plan"]},{"code":"11602 InterruptedDueToReplStateChange","title":"Operation interrupted due to a replication state change（レプリケーション状態の変化により操作が中断された）","severity":"danger","meaning":"レプリカセットの状態が変化した (例: プライマリが変わった) ため、操作が中断された。新しいトポロジでは安全に完了できないため、進行中のコマンドは終了された。","cause":"選出、プライマリの stepdown、メンバーのロール変更、または構成変更の際に、実行中の操作が中断される。189 PrimarySteppedDown と同じ根本原因を持ち、通常はフェイルオーバー時に発生する。","fix":"再試行可能なエラーである。ドライバで retryable writes/reads を有効にすると、新しいプライマリに対して操作を再試行できる。アプリケーションでこのエラーを捕捉して再試行する。頻繁に再発する場合は選出の原因を調査する: ネットワークの不安定、heartbeat のタイムアウト、過負荷、oplog ラグ。rs.status() でレプリカセットの健全性を監視する。","tags":["replica set","election","failover","interrupted","retry","state change"]},{"code":"136 CappedPositionLost","title":"Capped collection position lost（capped コレクションの位置を喪失）","severity":"caution","meaning":"capped (固定サイズ) コレクションを読み取るカーソル (通常は tailable カーソル) が位置を失った。コレクションが循環的に上書きしたため、カーソルが位置していたドキュメントはもう存在しない。","cause":"capped コレクションが満杯になると最も古いドキュメントが自動的に削除・上書きされる。消費速度を上回る速さで書き込まれるコレクションを追跡する tailable カーソルは遅れ、その位置が上書きされる。oplog などの capped 構造を tail するコンシューマで見られる。","fix":"カーソルの位置を再設定し (新しい tailable カーソルを開く)、tail を再開する。アプリケーションでこのエラーを捕捉し、読み取りをやり直す。根本原因が書き込み速度に追いつけないコンシューマの場合: capped コレクション/oplog のサイズを増やすか、コンシューマを高速化する。変更を確実に追跡するには、可能であれば tailable カーソルではなく change streams を使用する。","tags":["capped","tailable cursor","oplog","cursor","position","change stream"]},{"code":"28 PathNotViable","title":"Cannot use the part of the path to traverse the element（パスの一部を使って要素をたどれない）","severity":"caution","meaning":"更新でドット区切りのフィールドパス (例: a.b.c) をたどろうとしたが、パスの一部がサブフィールドを持てない型 (スカラー値や誤った型の要素) に当たった。そのためパスをたどれなかった。","cause":"ドキュメントのフィールド 'a' がオブジェクト/配列ではなくスカラー (例: 数値/文字列) であるのに a.b.c のようなネストしたパスに書き込んだ、または配列インデックスが想定される箇所にオブジェクトがあるなどの型の不一致。スキーマが一貫していないドキュメントで ($set で深いパスを更新する際に) よく見られる。","fix":"更新前に、パスが想定される型 (オブジェクト/配列) であることを確認する。互換性のないドキュメントを修正するか、ドキュメント構造に応じて更新を条件付きにする。必要に応じて、まずフィールドを正しい型に変換し (例: スカラー値をオブジェクトに置き換える)、その後ネストしたフィールドを書き込む。スキーマの一貫性のためにスキーマ検証を検討する。","tags":["update","path","dotted","type","set","schema"]}]},"errors/redis-more3.json":{"engineId":"redis","engine":"Redis","order":6,"errors":[{"code":"BUSYGROUP Consumer Group name already exists","title":"Consumer group already exists（コンシューマグループが既に存在する）","severity":"caution","meaning":"XGROUP CREATE でストリームにコンシューマグループを作成しようとしたが、そのストリームに同名のグループが既に存在する。Redis は既存のグループを上書きしない。","cause":"アプリケーションが起動時に無条件でグループを作成しようとし、前回の実行のグループが残っている、または複数のインスタンスが同じグループを並行して作成しようとしている。冪等でない起動ロジックの典型例。","fix":"グループの作成を冪等にする: エラーを捕捉して無視する (既存のグループで問題ない)。ストリームがまだ存在しない場合に自動作成するには XGROUP CREATE stream group $ MKSTREAM を使用する。既存のグループは XINFO GROUPS stream で確認する。本当にリセットしたい場合は、先に XGROUP DESTROY stream group で削除する。","tags":["stream","consumer group","xgroup","busygroup","idempotent","mkstream"]},{"code":"NOGROUP No such key or consumer group","title":"No such key or consumer group in stream（ストリームにそのキーまたはコンシューマグループがない）","severity":"caution","meaning":"ストリーム消費コマンド (XREADGROUP、XACK、XCLAIM など) を実行したが、指定したキー (ストリーム) またはコンシューマグループが存在しない。操作対象のグループ/ストリームが見つからなかった。","cause":"グループが作成されていない (XGROUP CREATE が省略された)、ストリームキーが削除されたか一度も書き込まれていない、グループ名/キーの綴りが誤っている、または XGROUP DESTROY でグループが削除された。グループ作成前にコンシューマが起動した場合によく発生する。","fix":"まずストリームとグループが存在することを確認する: XINFO STREAM stream および XINFO GROUPS stream。グループがない場合は作成する: XGROUP CREATE stream group $ MKSTREAM (必要に応じてストリームも作成する)。アプリケーション起動時にグループを作成するステップ (BUSYGROUP は無視) を追加する。キー名とグループ名の綴りが正しいことを確認する。","tags":["stream","consumer group","nogroup","xreadgroup","xgroup","key"]},{"code":"NOTBUSY No scripts in execution right now","title":"No scripts in execution right now（現在実行中のスクリプトはない）","severity":"safe","meaning":"SCRIPT KILL または FUNCTION KILL を送信したが、現在実行中 (かつ強制終了可能) の Lua スクリプト/関数がない。終了する対象がないため、コマンドは拒否された。","cause":"停止しようとした時点でスクリプトが既に終了していた、SCRIPT KILL を誤ったノードに送信した (スクリプトは別のインスタンスで実行中)、または SCRIPT KILL の前に BUSY 状態が自然に解消した。通常はタイミングの問題。","fix":"実際にスタックしたスクリプトがなければ、対処は不要である。これは安全な/情報提供的な応答である。BUSY エラー (スクリプトが busy-reply-threshold を超えた。Redis 7 より前は lua-time-limit という名前) が発生した場合は、スクリプトが実行されている正しいノードで SCRIPT KILL (関数の場合は FUNCTION KILL) を試す。スクリプトがデータを変更している場合 SCRIPT KILL は機能せず、最後の手段として SHUTDOWN NOSAVE が必要になることがある。長いスクリプトは分割し、時間制限を守る。","tags":["lua","script kill","notbusy","busy","script","function"]},{"code":"DENIED Redis is running in protected mode","title":"Redis is running in protected mode（Redis は保護モードで稼働中）","severity":"danger","meaning":"Redis が保護モードで稼働しており、外部 (ループバック以外のアドレス) からのパスワードなしの接続を拒否した。セキュリティのため、認証されていないリモートアクセスはブロックされる。","cause":"すべてのインターフェースにバインドされた (または bind 設定が緩い) Redis が、パスワード (requirepass) を設定しないまま外部クライアントからの接続を受けた。protected-mode はデフォルトで有効であり、この状況ではループバック以外からの要求をブロックする。保護されていない Redis が誤ってインターネットに公開されていることを示す。","fix":"正しい対処はセキュリティを確保することである: requirepass (または ACL ユーザー) で強力なパスワードを設定し、bind で信頼できるインターフェースでのみリッスンする。リモートアクセスが必要な場合はパスワード/TLS で保護し、ファイアウォールでポート 6379 を制限する。protected-mode no は閉じた/安全なネットワークでのみ一時的に設定してよいが、インターネットに面した環境では決して推奨されない。","tags":["protected mode","security","denied","requirepass","bind","auth"]},{"code":"ERR Can't execute '<cmd>': only (P|S)SUBSCRIBE / (P|S)UNSUBSCRIBE / PING / QUIT / RESET are allowed in this context","title":"Command not allowed in subscribe context（subscribe コンテキストでは許可されないコマンド）","severity":"caution","meaning":"接続が Pub/Sub の subscribe モードに入った後、このモードでは許可されない通常のコマンド (例: GET/SET) を実行しようとした。subscribe モードの接続は限られたコマンドのみを受け付ける。古いバージョンでのメッセージは \"ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / PING / QUIT allowed in this context\" であった。","cause":"SUBSCRIBE/PSUBSCRIBE/SSUBSCRIBE で subscribe モードに切り替わった接続でデータコマンドを送信した。RESP2 プロトコルでは、購読中の接続で許可されるのは (P|S)SUBSCRIBE、(P|S)UNSUBSCRIBE、PING、QUIT、RESET のみ。pub/sub と通常の処理で 1 つの接続を共有するのが典型的な誤り。","fix":"Pub/Sub 用に専用の接続を使用し、通常のコマンド用に別の接続を開く (ほとんどのクライアントライブラリは自動的にこれを行う)。subscribe モードを抜けるには UNSUBSCRIBE/PUNSUBSCRIBE を送信する。その後は通常のコマンドが機能する。RESP3 プロトコル (HELLO 3) では購読中の接続でも他のコマンドが許可されるため、ドライバが対応していれば RESP3 に切り替える。","tags":["pubsub","subscribe","context","resp","connection","hello"]},{"code":"ERR SELECT is not allowed in cluster mode","title":"SELECT is not allowed in cluster mode（クラスタモードでは SELECT は許可されない）","severity":"caution","meaning":"Redis Cluster モードで、SELECT により別の論理データベース (DB インデックス) に切り替えようとした。クラスタモードはデータベース 0 のみをサポートし、複数の DB は使用できない。","cause":"スタンドアロン Redis で SELECT により DB 0-15 を切り替えていたアプリケーションが、Redis Cluster への移行後も同じコマンドを送り続けている。クラスタアーキテクチャはデータをスロット単位で分散するため、複数 DB の概念はサポートされない。","fix":"クラスタモードでは SELECT の呼出しを削除する。使用されるのは DB 0 のみ。論理的な分離が必要な場合はキープレフィックス (名前空間) を使用する (例: app1:key)。特定のキーをまとめて処理する必要がある場合は、ハッシュタグ ({user123}) を使用して同じスロットに配置する。アプリケーションの構成をクラスタ対応にする。","tags":["cluster","select","database","namespace","hash tag","slot"]},{"code":"ERR wrong number of arguments for command","title":"Wrong number of arguments for command（コマンドの引数の数が誤っている）","severity":"caution","meaning":"Redis コマンドが想定より少ない、または多い引数で送信された。構文を満たしていないため、コマンドは処理されずに拒否された。","cause":"パラメータの欠落/過剰 (例: SET key value ではなく SET key のみ)、空/未定義として渡された変数、誤った引数順序でのコマンド呼出し、またはクライアントライブラリでの配列/引数展開 (spread) の誤り。動的に組み立てたコマンドでよく見られる。","fix":"コマンドの正しいシグネチャを確認する (例: SET key value [options])。公式のコマンドリファレンスを参照する。クライアントコードでは、引数 (特に配列から来るもの) が空/欠落していないことを確認する。ユーザー入力からコマンドを組み立てる場合は、事前に引数の数を検証する。redis-cli でコマンドを手動で試し、想定される引数の数を確認する。","tags":["syntax","arguments","argument","command","syntax","cli"]},{"code":"ERR Background save already in progress","title":"Background save already in progress（バックグラウンド保存が既に進行中）","severity":"caution","meaning":"新しいバックグラウンド保存 (BGSAVE) または AOF 書換えを開始しようとしたが、バックグラウンド保存が既に進行中である。Redis は同時に 2 つ目の保存プロセスを許可しない。","cause":"前回の完了前に新しい BGSAVE/BGREWRITEAOF がトリガーされた、または大規模なデータセットで fork/保存に時間がかかる間に監視スクリプトやアプリケーションが BGSAVE を繰り返し呼び出した。遅いディスクや大きな RDB ファイルは処理を長引かせる。","fix":"実行中の保存が終わるまで待つ。INFO persistence の rdb_bgsave_in_progress と aof_rewrite_in_progress フィールド、および LASTSAVE のタイムスタンプで状態を確認する。アプリケーション/自動化のロジックを条件付きにし、前回の保存が終わる前に新しい BGSAVE をトリガーしないようにする。保存に時間がかかりすぎる場合は、ディスク速度と RDB サイズを調査する。","tags":["bgsave","persistence","rdb","aof","background save","fork"]},{"code":"ERR bit offset is not an integer or out of range","title":"Bit offset is not an integer or out of range（ビットオフセットが整数でないか範囲外）","severity":"caution","meaning":"SETBIT/GETBIT/BITCOUNT などのビット操作に与えたビットオフセットが無効: 整数ではない、または許容範囲外である。Redis はそのオフセットでビット操作を実行できない。","cause":"オフセットとして数値以外の値を渡した、負のオフセットを使用した、または許容上限を超える非常に大きなオフセットを指定した (ビット文字列は最大 512 MB、すなわち約 2^32 ビット)。ビットマップベースのカウンタ/フラグ構造での計算誤りから生じる。","fix":"オフセットが許容範囲内 (0 ～ 約 2^32-1。文字列は最大 512 MB) の非負整数であることを確認する。オフセットの計算 (例: ユーザー ID から導出したもの) がオーバーフロー/負の値にならないか検証する。非常に大きなオフセットが必要な場合は、データを複数のキーに分割する設計 (シャーディング) にする。","tags":["bitmap","setbit","offset","integer","range","bit"]}]},"errors/elasticsearch-more3.json":{"engineId":"elasticsearch","engine":"Elasticsearch","order":7,"errors":[{"code":"node_not_connected_exception","title":"Node is not connected（ノードが接続されていない）","severity":"danger","meaning":"ノードが、通信が必要な別のノードと現在接続されていない。クラスタ内 (トランスポート層) の接続が失われたため、要求を対象ノードに転送できなかった。","cause":"ネットワーク障害またはパケットロス、対象ノードのクラッシュ/再起動、ファイアウォール/ポートのブロック (デフォルトのトランスポートポート 9300)、GC の一時停止によるノードの一時的な無応答、または DNS/ホスト解決の問題。ローリング再起動中に一時的に発生することがある。","fix":"クラスタとノードの健全性を調べる: GET _cluster/health と GET _cat/nodes?v でどのノードが欠けているかを確認する。トランスポートポート (9300) のノード間ネットワークアクセスとファイアウォールルールを確認する。影響を受けたノードのログでクラッシュ、GC の一時停止、OOM を確認する。ネットワークの安定性と discovery/seed host の構成を見直す。","tags":["transport","node","connection","network","9300","cluster"]},{"code":"receive_timeout_transport_exception","title":"Request timed out waiting for a response from another node（別のノードからの応答待ちで要求がタイムアウト）","severity":"danger","meaning":"ノードが別のノードに要求を送信したが、構成された時間内に応答が届かず、要求がタイムアウトした。ノード間 (トランスポート) の呼出しを完了できなかった。","cause":"高負荷の対象ノード、長い GC の一時停止、遅いディスク/CPU の逼迫、ネットワーク遅延/パケットロス、または対象ノードが多忙で応答できない。重いクエリ、大規模な一括操作、シャードのリバランス中によく発生する。","fix":"影響を受けたノードのリソース使用状況を調べる: GET _nodes/stats で JVM ヒープ、GC、スレッドプールの飽和を確認する。GET _cat/thread_pool?v で拒否/キュー中のタスクを確認する。ネットワーク遅延を測定する。負荷を減らし (クエリ/バルクのサイズを小さくする)、ヒープとハードウェアリソースを見直す。継続する場合はノードを追加して負荷を分散する。","tags":["transport","timeout","gc","load","network","thread pool"]},{"code":"routing_missing_exception","title":"Routing value is required for this document（このドキュメントにはルーティング値が必要）","severity":"caution","meaning":"ドキュメントへのアクセス/インデックス作成にルーティング値が必要だが、指定されていない。ルーティングがないため、Elasticsearch はドキュメントがどのシャードに属するか判断できなかった。","cause":"インデックスのマッピングで _routing required=true が定義されている、parent-join (親子) 関係を使用しており子ドキュメントにルーティングが必要、または index/get/update/delete 要求で routing パラメータが省略された。カスタムルーティングで書き込んだドキュメントをルーティングを指定せずに読み取るのが典型的な原因。","fix":"要求でルーティング値を明示的に指定する (例: index/get/update/delete 呼出しで ?routing=value)。parent-join では、子ドキュメントのルーティングとして親の id を渡す。読み取り/更新/削除には、ドキュメント書き込み時と同じルーティングを使用する。マッピングの _routing の必須設定 (required) を見直す。","tags":["routing","shard","parent-child","join","mapping","index"]},{"code":"too_many_buckets_exception","title":"Trying to create too many buckets（作成しようとしたバケットが多すぎる）","severity":"caution","meaning":"集計クエリが許容上限 (search.max_buckets、デフォルト 65,536) を超えるバケットを生成しようとした。メモリを保護するためクエリが拒否された。","cause":"カーディナリティの高いフィールドに対して非常に大きな size または非常に細かい interval で実行された terms/date_histogram などの集計、ネストした集計によるバケット数の増倍。過剰なバケット生成はノードのメモリを枯渇させ得るため、上限が強制される。","fix":"生成されるバケット数を減らす: terms 集計の size を下げる、date_histogram の interval を広げる、不要なネストした集計を削除する。多数の結果が必要な場合は composite 集計でページングする。上限の引き上げは最後の手段であり、メモリのリスクを伴う: search.max_buckets は PUT _cluster/settings で変更できるが、慎重に行う。","tags":["aggregation","bucket","max_buckets","terms","composite","memory"]},{"code":"shard_lock_obtain_failed_exception","title":"Obtaining shard lock timed out（シャードロックの取得がタイムアウト）","severity":"danger","meaning":"Elasticsearch がシャードを操作するために必要なローカルディレクトリロック (shard lock) をタイムアウト内に取得できなかった。シャードを起動または再割り当てできなかった。","cause":"同じシャードの以前のコピー (close/relocation 後) がまだロックを解放していない、遅い/ハングした I/O、ディスクの問題、またはノードの高速な再起動後にクリーンアップされていない古いシャード状態。通常は一時的だが、継続する場合シャードは UNASSIGNED のままとなる。","fix":"シャードが未割り当ての理由を確認する: GET _cluster/allocation/explain。ほとんどの場合ロックはまもなく解放され、クラスタが自動的に再試行する。必要に応じて POST _cluster/reroute?retry_failed=true で再割り当てをトリガーする。継続する場合は、影響を受けたノードのログで I/O/ディスクエラーを調べ、ディスクの健全性を確認する。問題のノードをクリーンに再起動するとロックが解消されることがある。","tags":["shard","lock","unassigned","allocation","io","reroute"]},{"code":"parsing_exception","title":"Failed to parse the search request / query DSL（検索要求 / query DSL の解析に失敗）","severity":"caution","meaning":"送信されたクエリボディ (query DSL) を解析できなかった。要求の JSON 構造またはクエリ構文が Elasticsearch の想定する形式と一致しないため、クエリを実行できなかった。","cause":"無効な JSON、位置の誤った/不明なクエリキー、誤った構造で使用されたクエリタイプ (例: bool、range)、バージョン間で削除/変更されたフィールド名、または括弧の過不足。手書きまたは動的に組み立てたクエリでよく見られる。","fix":"エラーメッセージの行/位置のヒントを使ってクエリボディを確認し、JSON が有効であることを確認する。query DSL の構造を公式リファレンスと比較する (bool/must/filter の配置など)。バージョンアップで削除された構文を更新する。クエリを段階的に単純化して誤った部分を切り分ける。可能であればクライアントライブラリのクエリビルダを使用する。","tags":["query dsl","parse","json","syntax","search","bool"]},{"code":"max_bytes_length_exceeded_exception","title":"Document contains at least one immense term that is too long（ドキュメントに長すぎる巨大な term が少なくとも 1 つ含まれる）","severity":"caution","meaning":"インデックス作成中のドキュメントで、ある term (特に keyword/非解析フィールドの値) が許容される最大バイト長 (32766 バイト) を超えた。Lucene はそれほど長い term をインデックス化できない。","cause":"keyword フィールドに (全体として) 書き込まれた非常に長いテキスト値。例: ドキュメント本文全体、base64 データ、長い URL/識別子を keyword フィールドに格納した。keyword フィールドは解析されないため、値は単一の term としてインデックス化され上限を超える。","fix":"長いテキストには text (解析対象) フィールドを使用する。keyword は完全一致が必要な短い値専用である。値に上限を設けるには、マッピングで ignore_above を使用する (これより長い値はインデックス化されないが格納はされる)。不要であれば、非常に長いフィールドを index:false に設定する。データ型に基づいてフィールド設計 (text と keyword) を見直す。","tags":["keyword","term","ignore_above","lucene","mapping","length"]},{"code":"illegal_argument_exception_total_fields","title":"Limit of total fields has been exceeded（フィールド総数の上限を超えた）","severity":"caution","meaning":"インデックスマッピングのフィールド総数が許容上限 (index.mapping.total_fields.limit、デフォルト 1000) を超えた。新しいフィールドを追加できないため、インデックス作成が失敗する。","cause":"通常はマッピング爆発: 動的マッピングが有効な状態で、非構造化/可変キーの JSON ドキュメント (例: キーがユーザーデータに由来するオブジェクト) が新しいフィールドをすべてマッピングに追加する。時間とともにフィールド数が急増し、上限に達する。","fix":"根本原因を修正するには、可変キーのデータをオブジェクトではなく flattened フィールドまたはキーと値のペアの配列としてモデル化し、動的マッピングを制限する (dynamic: false または strict)。本当にフィールドがさらに必要な場合は、慎重に上限を引き上げる: PUT idx/_settings {\"index.mapping.total_fields.limit\": 2000}。GET idx/_mapping でフィールド数を確認し、マッピング爆発を監視する。","tags":["mapping","total_fields","dynamic mapping","flattened","limit","field"]},{"code":"verification_exception","title":"verification_exception: Found N problem(s) — Unknown column / Unknown index (ES|QL, SQL, EQL)（検証例外: N 件の問題 — 不明な列 / 不明なインデックス）","severity":"caution","meaning":"ES|QL (_query)、SQL (_sql)、または EQL のクエリは構文的には解析されたが、意味検証に失敗した: 参照されたインデックス、フィールド (列)、または関数が見つからない、あるいは型に互換性がない。エラーテキストに問題のある行/列の位置が示される (例: \"line 1:18: Unknown column [field]\")。スナップショットリポジトリの検証失敗はこのコードではなく repository_verification_exception である。","cause":"フィールド名の綴り誤りまたはマッピングにないフィールド、存在しないかどのインデックスにも一致しないインデックスパターン、text フィールドに対するサポートされない操作 (例: keyword サブフィールドではなく text でのグループ化)、互換性のない型同士の比較、または不明な関数。","fix":"エラーメッセージの行:列の情報を使ってクエリを修正する。フィールド名と型を確認する: GET idx/_mapping (SQL では DESCRIBE idx / SHOW COLUMNS)。GET _cat/indices でインデックスパターンを確認する。グループ化/ソートには keyword サブフィールド (field.keyword) を使用し、型の不一致には明示的な変換を適用する (ES|QL: TO_STRING、TO_INTEGER など)。","tags":["esql","sql","eql","verification","unknown column","query"]}]},"errors/oracle-more4.json":{"engineId":"oracle","engine":"Oracle","order":1,"errors":[{"code":"ORA-19804","title":"cannot reclaim N bytes disk space from M bytes limit（M バイトの上限から N バイトのディスク領域を再利用できない）","severity":"danger","meaning":"Oracle が新しいファイル (アーカイブログ、バックアップ、フラッシュバックログ) のために高速リカバリ領域 (FRA) に空きを作ろうとしたが、DB_RECOVERY_FILE_DEST_SIZE で定義された論理上限に達しているため、必要な領域を再利用できなかった。","cause":"FRA のサイズ (DB_RECOVERY_FILE_DEST_SIZE) は物理ディスクとは独立した上限であり、アーカイブログ、RMAN バックアップ、フラッシュバックログがそれを埋め尽くした。根本原因は通常、アーカイブログが定期的にバックアップ・削除されていない、または不要になったバックアップが削除されていないことである。","fix":"FRA の使用状況を確認する: SELECT * FROM v$recovery_area_usage; および SELECT * FROM v$recovery_file_dest; アーカイブログを FRA 外の出力先にバックアップして削除する (RMAN: BACKUP ARCHIVELOG ALL FORMAT '/backup/arc_%U' DELETE INPUT;)、または不要になったバックアップを削除する (RMAN: DELETE OBSOLETE;)。Data Guard 環境では、スタンバイでまだ適用されていないアーカイブログを削除しない。恒久対策として、ディスク容量があれば DB_RECOVERY_FILE_DEST_SIZE を増やす。Flashback Database が不要であれば、無効化を検討する。","tags":["fra","recovery area","archived log","rman","db_recovery_file_dest_size","disk"]},{"code":"ORA-00494","title":"enqueue held for too long by 'inst N, osid M'（'inst N, osid M' がエンキューを長時間保持）","severity":"danger","meaning":"重要なリソースのエンキュー (例: CF - 制御ファイルのエンキュー) がプロセスによって許容時間をはるかに超えて保持されたため、システムのハングを防ぐために Oracle がそのプロセスを強制終了した。alert.log に 'killing enqueue blocker' のエントリとともに記録される。","cause":"I/O のボトルネック、高い CPU 負荷、または OS の停滞 (スワッピング、遅いディスク) のため、バックグラウンドまたはユーザープロセスが重要なエンキューを許容時間を超えて保持した。制御ファイル (CF) のエンキューでは、この時間は _controlfile_enqueue_timeout で設定される (デフォルト 900 s)。隠し (アンダースコア) パラメータは Oracle サポートの指示がある場合にのみ変更すべきである。通常、ストレージの遅延や LGWR/CKPT などの遅いプロセスがきっかけとなる。","fix":"alert.log と強制終了されたプロセスのトレースファイルを確認し、どのエンキュー (通常は制御ファイル) とどのバックグラウンドプロセスが関与しているかを特定する。真の原因は通常ストレージ/I/O の遅延である: ディスクの応答時間、マルチパス、コントローラの健全性を確認する。CPU/メモリの逼迫とスワップ使用量を減らす。再発する場合は、トレースの分析結果を Oracle サポートと共有する。","tags":["enqueue","control file","i-o","storage","hang","background process"]},{"code":"ORA-04021","title":"timeout occurred while waiting to lock object（オブジェクトのロック待機中にタイムアウト発生）","severity":"caution","meaning":"オブジェクト (パッケージ、プロシージャ、型など) のライブラリキャッシュロック/ピンの取得待機中にタイムアウトが発生した。通常、別のセッションが実行中またはロック中の PL/SQL オブジェクトをコンパイルまたは変更しようとした場合に発生する。","cause":"変更/コンパイル対象のオブジェクトが別のセッションで実行中、または別の DDL によってロックされているため、排他的なライブラリキャッシュロックを取得できない。長時間実行のプロシージャ呼出しやハングしたセッションがロックを保持している可能性がある。","fix":"オブジェクトをロックしているセッションを特定する: SELECT * FROM dba_kgllock WHERE kgllkhdl IN (SELECT p1raw FROM v$session WHERE event LIKE 'library cache%'); または v$access と v$session でオブジェクトを使用しているセッションを特定する。ワークロードの少ないメンテナンス時間帯に DDL/コンパイルを再試行する。必要に応じてセッションを安全に終了する。アプリケーションを短時間停止すると、ロックを取得しやすくなる。","tags":["library cache","lock","plsql","ddl","compile","timeout"]},{"code":"ORA-04061","title":"existing state of package/procedure has been invalidated（パッケージ/プロシージャの既存の状態が無効化された）","severity":"caution","meaning":"呼び出された PL/SQL オブジェクト (パッケージ、プロシージャ、関数) の既存の状態が、依存するオブジェクトの変更により無効化された。ORA-04068 を伴う状態喪失の一種であり、セッションが保持するパッケージ状態はもはや有効ではない。","cause":"セッションがパッケージを使用している間に、そのパッケージまたは依存オブジェクトに DDL が適用された (表構造の変更、再コンパイル、権限の変更)。その結果、セッションの既存のパッケージ状態が無効化された。アプリケーション稼働中にスキーマ変更を行う、デプロイ頻度の高い環境で見られる。","fix":"通常、同じ呼出しは 2 回目で成功する (状態がリセットされているため)。アプリケーションでこのエラーを捕捉し、安全に再試行する。スキーマ変更はアプリケーションのトラフィックが少ない時間帯/メンテナンス時間帯に行う。無効なオブジェクトを一括でコンパイルする: EXEC DBMS_UTILITY.COMPILE_SCHEMA('APP_SCHEMA'); パッケージ状態 (グローバル変数) を最小限にする設計により、この影響を軽減できる。","tags":["plsql","package","invalidate","ddl","state","recompile"]},{"code":"ORA-01466","title":"unable to read data - table definition has changed（データを読み取れない - 表定義が変更された）","severity":"caution","meaning":"過去の時点のデータを読み取るクエリ (Flashback Query、AS OF、または読み取り一貫性) が、照会した過去の時点から現在までの間に表定義 (DDL) が変更されたため失敗した。Oracle は現在の定義でその時点のデータを安全に読み取れない。","cause":"Flashback/AS OF クエリの対象タイムスタンプより後に、表に DDL (列の追加/削除、型の変更) が適用された。また、クライアントとサーバー間の時刻差や、ごく直近 (数秒前) の過去のクエリは、SCN/時刻の分解能によりこのエラーになることがある。","fix":"表の DDL 変更より前の時刻/SCN に対してフラッシュバッククエリを実行する。可能であれば、タイムスタンプではなく正確な SCN を使用する (AS OF SCN)。ごく直近の過去のクエリでは、数秒さかのぼる。恒久的な履歴アクセスが必要な場合は、DDL ではなくバージョン管理表やアーカイブ表の設計を検討する。","tags":["flashback","as of","ddl","consistent read","scn","query"]},{"code":"ORA-08176","title":"consistent read failure; rollback data not available（読み取り一貫性の失敗。ロールバックデータが利用できない）","severity":"danger","meaning":"読み取り一貫性イメージの構築中に、クエリが undo を生成しない操作で変更されたブロックに遭遇した。これらのブロックには undo/ロールバックデータが存在しないため、一貫性イメージを構築できなかった。ORA-01555 とは異なり、undo は上書きされたのではなく、そもそも生成されていない。(シリアライズ可能分離のエラーは別のコード: ORA-08177。)","cause":"クエリの実行中に、同じオブジェクトに対して undo を生成しない操作が実行された: ダイレクトパスロード (INSERT /*+ APPEND */、SQL*Loader DIRECT=TRUE)、CREATE INDEX / インデックスの再構築、またはディスクリートトランザクション。","fix":"ダイレクトパスロードまたはインデックス操作の完了後にクエリを再実行する (再試行)。長時間のレポートと、同じオブジェクトに対するダイレクトパスロード/インデックスメンテナンスのジョブを同じ時間帯にスケジュールしない。再発する場合は、アラートログと ASH で競合するジョブを特定し、スケジュールを分離する。","tags":["undo","consistent read","direct path","append","create index","retry"]},{"code":"ORA-00020","title":"maximum number of processes (N) exceeded（最大プロセス数 (N) を超えた）","severity":"danger","meaning":"インスタンスのプロセス数が PROCESSES 初期化パラメータで定義された上限に達し、新しい接続/プロセスを作成できない。新しいセッションは接続できず、管理者でさえ接続できない場合がある。","cause":"大きすぎるアプリケーションのコネクションプール、クローズされない接続 (リーク)、想定を超える同時ユーザー数、または低すぎる PROCESSES パラメータにより上限を超える。ハングしたバックグラウンドジョブやパラレルクエリのプロセスがプロセスを消費することもある。","fix":"sqlplus -prelim / as sysdba で接続できるが、この接続では SQL を実行できない (v$session を照会できない)。oradebug (例: hanganalyze) と SHUTDOWN ABORT にのみ使用できる。スロットを空けるには、OS レベルでアイドル状態のアプリケーションのサーバープロセスを慎重に kill する (ps -ef | grep 'LOCAL=NO')。その後、通常の SYSDBA 接続で v$session/v$process からリークしたセッションを特定し、ALTER SYSTEM KILL SESSION で終了する。恒久対策として PROCESSES を増やしてインスタンスを再起動する (spfile で SESSIONS が明示的に設定されている場合は再計算されないため、それも更新する)。アプリケーション側では、コネクションプールの最大数とアイドル接続のクリーンアップを修正する。","tags":["processes","process","connection","limit","pool","init parameter"]},{"code":"ORA-01113","title":"file N needs media recovery（ファイル N にメディアリカバリが必要）","severity":"danger","meaning":"データファイルをオンラインにしようとしている、またはデータベースをオープンしようとしているが、ファイルに不整合がある。続行する前にメディアリカバリを適用する必要がある。ファイルは制御ファイルが想定するより古い/不整合な SCN にある。","cause":"データファイルが古いバックアップからリストアされた、オフライン中に REDO が適用されなかった、またはインスタンス/ストレージのクラッシュ後にファイルが最新でない。典型的には、リストア後のリカバリ手順の省略、またはファイルが長時間オフラインのままであったことが原因。","fix":"ファイルまたはデータベースをリカバリする: RECOVER DATAFILE N; または RECOVER DATABASE; 続いて ALTER DATABASE DATAFILE N ONLINE; または ALTER DATABASE OPEN; 必要なアーカイブログにアクセスできることを確認する。RMAN の場合: 必要に応じて RESTORE の後、RECOVER DATAFILE N; を実行する。要求されるログは alert.log で確認する。","tags":["media recovery","datafile","redo","restore","recover","scn"]},{"code":"ORA-02393","title":"exceeded call limit on CPU usage（CPU 使用量の呼出し上限を超えた）","severity":"caution","meaning":"セッションに割り当てられたリソースプロファイルで定義された、1 回の呼出しで許容される CPU 時間 (CPU_PER_CALL) を超えたため、Oracle がその呼出しを終了した。リソース制限のための安全装置である。","cause":"ユーザーのプロファイルで CPU_PER_CALL の上限が定義され、RESOURCE_LIMIT=TRUE となっており、単一の SQL/PLSQL 呼出しがこの CPU しきい値を超えた。通常、想定をはるかに超える CPU を消費する非効率/制御されないクエリがきっかけとなる。","fix":"CPU 消費が上限を下回るようクエリを最適化する (適切なインデックス、正しい実行計画、不要な全表走査の排除)。業務要件が正当であれば、該当ユーザーのプロファイルで CPU_PER_CALL を増やすか UNLIMITED に設定する: ALTER PROFILE ... LIMIT CPU_PER_CALL ...; プロファイルではなく Database Resource Manager でより柔軟にリソースを管理することを検討する。","tags":["profile","cpu_per_call","resource_limit","resource","query","optimization"]},{"code":"ORA-12801","title":"error signaled in parallel query server Pnnn（パラレルクエリサーバー Pnnn でエラーが通知された）","severity":"danger","meaning":"パラレル実行中のクエリで、パラレル実行サーバー (パラレル実行サーバー) の 1 つがエラーに遭遇し、そのエラーがクエリコーディネータに渡された。ORA-12801 はラッパーであり、実際のエラーはその次の 2 行目にある。","cause":"パラレル操作中にスレーブプロセスが実際のエラーに遭遇した: TEMP 表領域の不足 (ORA-01652)、PGA メモリの枯渇 (ORA-04030)、データ破損、パラレルプロセスの上限、または基になる別の SQL エラー。ORA-12801 は、それがパラレルのコンテキストで発生したことを報告するだけである。","fix":"ORA-12801 の直後にある実際のエラーコードに注目して解決する (例: TEMP の拡張、PGA のチューニング、破損ブロックの修復)。必要に応じて、クエリをシリアルで実行する、PARALLEL ヒントを削除する、または並列度を下げることで実際のエラーを切り分ける。PARALLEL_MAX_SERVERS とリソース使用状況を見直す。","tags":["parallel","parallel query","slave","temp","pga","wrapper"]}]},"errors/postgres-more4.json":{"engineId":"postgres","engine":"PostgreSQL","order":2,"errors":[{"code":"23P01","title":"exclusion_violation","severity":"danger","meaning":"EXCLUDE (排他) 制約に違反した。この制約タイプは、特定の演算子 (例: 範囲の重なり &&) に従って 2 つの行が競合することを防ぐ。挿入/更新された行が既存の行と競合するため拒否された。","cause":"典型的には GiST ベースの EXCLUDE 制約が定義されており (例: 予約/会議室の予約で tstzrange && による時間の重なりを禁止)、新しい行が既存の行と重なる範囲/値を持つ。2 つの同時実行トランザクションが重なる範囲を挿入した場合にも発生する。","fix":"挿入前にクエリで重なりを確認するか、アプリケーションでエラーを捕捉してユーザーに分かりやすいメッセージを表示する。該当する範囲/条件を照会し、競合する既存の行を特定する。業務ルールが重なりを許容する場合は制約を緩和し、そうでなければ入力を修正する。同時実行時には、トランザクションを安全に再試行して直列化する。","tags":["exclude","constraint violation","gist","range","overlap","constraint"]},{"code":"23001","title":"restrict_violation","severity":"danger","meaning":"SQL 標準の restrict_violation コード。重要: PostgreSQL は ON DELETE/ON UPDATE RESTRICT または NO ACTION で定義された外部キーの違反を、このコードではなく 23503 (foreign_key_violation) で報告する。実際には PostgreSQL 本体からこのコードを見ることはない。","cause":"依存する子行を持つ親行を削除した、またはそのキーを変更した場合、PostgreSQL は 23503 を返す。23001 は通常、別のデータベースから移植したアプリケーションコードや、拡張機能のカスタムエラーとして現れる。NO ACTION とは異なり、RESTRICT はチェックをトランザクションの終了まで遅延できず、即座に失敗する。","fix":"まず依存する子行を削除/更新するか、別の親に移す。その後、親行を処理する。業務ルールが許す場合は、外部キーを ON DELETE CASCADE または SET NULL で再定義することを検討する。一括削除では削除の順序 (先に子、次に親) を正しくする。","tags":["foreign key","restrict","fk","delete","reference","constraint"]},{"code":"42P17","title":"invalid_object_definition","severity":"danger","meaning":"オブジェクトの定義 (関数、照合順序、トリガー、ルールなど) が無効である。PostgreSQL は、与えられた定義が内部的に矛盾しているか受け入れられないことを示しており、記述どおりにオブジェクトを作成/変更できない。","cause":"よくある原因: 関数の矛盾する属性の組合せ (例: IMMUTABLE と指定されているが volatile として動作する)、無効な照合順序/文字セットの定義、または不適切なトリガー/ルールの定義。行レベルセキュリティ (RLS) や一部の DDL での矛盾するオプションでも発生する。","fix":"エラーの詳細 (DETAIL/HINT) を読み、定義のどの部分が拒否されたかを特定する。関数の volatility ラベルを実際の動作に合わせる (VOLATILE/STABLE/IMMUTABLE)。照合順序名が pg_collation に存在することを確認する。ドキュメントの構文/規則に従って定義を修正し、再実行する。","tags":["function","collation","definition","volatility","ddl","object"]},{"code":"42710","title":"duplicate_object","severity":"caution","meaning":"作成しようとしているオブジェクト (ロール、型、制約、拡張機能、スキーマ、インデックス名など) は既に存在する。PostgreSQL は同じ名前/定義の 2 つ目のオブジェクトを許可しない。","cause":"同名のオブジェクトが既に存在する状態で、CREATE ROLE、CREATE TYPE、CREATE EXTENSION、ADD CONSTRAINT などのコマンドが実行された。通常、スクリプトの 2 回実行、冪等でないマイグレーション、または 2 つの同時セッションが同じオブジェクトを作成しようとしたことが原因。","fix":"オブジェクトが存在するか確認する (ロールは pg_roles、型は pg_type、拡張機能は pg_extension)。マイグレーションを冪等に記述する: 利用可能であれば CREATE ... IF NOT EXISTS を使用するか、先に DROP ... IF EXISTS を実行する。制約の競合の場合は、既存の制約の名前を変更するか、削除して再作成する。","tags":["duplicate","role","type","extension","constraint","migration"]},{"code":"22008","title":"datetime_field_overflow","severity":"caution","meaning":"日付/時刻値の計算または解析中に、いずれかのフィールドが有効範囲外になった。例えば、13 月や 32 日のようなあり得ない構成要素、またはサポートされる時刻範囲を超える結果が生成された。","cause":"無効な日付入力 (例: '2026-02-30')、範囲外の構成要素、またはサポートされる日付範囲を超える INTERVAL の加算。誤った書式/ロケールでの解析や、検証されていないユーザー入力の挿入が典型的な原因。","fix":"挿入前にアプリケーションで日付入力を検証し、正しい書式 (できれば ISO 8601: YYYY-MM-DD) で送信する。TO_DATE/TO_TIMESTAMP で解析する際は、書式マスクを入力に合わせる。演算結果をサポートされる日付範囲内に保ち、疑わしい値には範囲チェックを行う。","tags":["date","time","overflow","interval","validation","format"]},{"code":"22026","title":"string_data_length_mismatch","severity":"caution","meaning":"ビット列の長さが、操作で要求される固定長と一致しない。PostgreSQL では、固定長の bit(n) 型に異なる長さのビット列を書き込んだ場合や、長さの異なるビット列にビット単位の AND/OR/XOR を適用した場合に最もよく発生する。","cause":"bit(n) 列に n より短い/長いビット列を書き込んだ (例: bit(4) 列に B'101': 'bit string length 3 does not match type bit(4)')、または長さの異なるビット列に &、|、# を適用した ('cannot AND bit strings of different sizes')。テキストや文字エンコーディングが原因ではない。char(n)/varchar(n) に長すぎる値を入れた場合は代わりに 22001 となる。","fix":"値を目的の長さにする: 明示的なキャストを使用する (B'101'::bit(4) は右側をゼロで埋め、超過分を切り捨てる)。長さが可変であれば列を bit varying(n) として定義する。ビット演算の前にオペランドを同じ長さにキャストし、length() で長さを確認する。","tags":["bit","length","bit string","varbit","conversion","validation"]},{"code":"2201B","title":"invalid_regular_expression","severity":"caution","meaning":"正規表現操作 (~、~*、SIMILAR TO、regexp_matches、substring など) に与えたパターンが無効である。構文が誤っているため、PostgreSQL はパターンをコンパイルできなかった。","cause":"括弧の不一致、無効な文字クラス、誤ったエスケープシーケンス、またはサポートされない構文を含む正規表現パターン。よくある原因は、特殊文字をエスケープせずにユーザー入力をそのままパターンとして使用することである。","fix":"POSIX/ARE の構文に従って正規表現パターンを修正し、括弧、角括弧、エスケープシーケンスを確認する。ユーザー入力をパターンではなくリテラルテキストとして検索する場合: PostgreSQL には組込みの regexp_quote 関数がないため、regexp_replace で特殊文字の前にバックスラッシュを付けてエスケープするか、正規表現を使わず strpos()/position() や LIKE ... ESCAPE を使用する。別のツールでテストしてパターンを検証する。","tags":["regex","regular expression","pattern","similar to","escape","syntax"]},{"code":"44000","title":"with_check_option_violation","severity":"danger","meaning":"WITH CHECK OPTION で定義されたビューを通じた INSERT/UPDATE が、結果の行がビューの WHERE 条件を満たさなくなるため拒否された。ビューは自身のフィルタから外れる行の書き込みを防ぐ。","cause":"更新可能なビューが WITH CHECK OPTION で定義されており、書き込みによって行がビューの定義条件から外れる (例: ビューが status='active' でフィルタしているのに行を 'inactive' に設定する)。行レベルセキュリティ (RLS) のポリシーでも同様のチェックが発生することがある。","fix":"書き込む値がビューの WHERE 条件を満たすようにするか、(権限が許せば) ビューではなくベーステーブルに対して直接操作を行う。業務ルールで行がフィルタから外れることを許容する場合は、WITH CHECK OPTION なしでビューを再定義する。RLS の場合は、ポリシーの WITH CHECK 式を見直す。","tags":["view","check option","updatable view","rls","insert","update"]},{"code":"40002","title":"transaction_integrity_constraint_violation","severity":"danger","meaning":"トランザクション終了時にチェックされる整合性制約が COMMIT 時に違反されたことを示す SQL 標準のコード。重要: PostgreSQL は実際にはこのコードを生成せず、COMMIT 時の遅延 (DEFERRED) 制約違反を制約自身のコードで返す: 外部キーは 23503、一意性は 23505。","cause":"DEFERRABLE INITIALLY DEFERRED で定義された外部キーまたは一意制約が、トランザクションの途中のステップで一時的に破られ、COMMIT 時までに修正されなかった。PostgreSQL ではこれは 23503/23505 として報告される。例えば、相互に参照する行を誤った順序で挿入し、修正しなかった場合に発生する。","fix":"COMMIT 前にすべての遅延制約が満たされるようトランザクションのロジックを修正する (欠けている参照を追加し、競合を解消する)。必要に応じて、トランザクション内で SET CONSTRAINTS ... IMMEDIATE により制約を早期にチェックし、問題のあるステップを早く検出する。相互参照の場合は挿入/更新の順序を入れ替える。","tags":["deferred","constraint violation","commit","foreign key","transaction","constraint"]}]},"errors/mysql-more4.json":{"engineId":"mysql","engine":"MySQL","order":3,"errors":[{"code":"1055","title":"Expression not in GROUP BY (only_full_group_by)（GROUP BY にない式）","severity":"caution","meaning":"GROUP BY にも集約関数にも含まれていない列が、SELECT リストまたは HAVING/ORDER BY で使用された。ONLY_FULL_GROUP_BY SQL モードが有効なため、MySQL はこの非決定的な式を拒否する。","cause":"クエリがグループ化列以外の列を直接選択しているが、その列はグループごとに単一の値を持つとは限らない。MySQL 5.7+ では ONLY_FULL_GROUP_BY がデフォルトで有効であり、古い寛容な GROUP BY の動作に依存するクエリはこのエラーになる。","fix":"列を GROUP BY リストに追加するか、集約関数 (MAX()、MIN()、ANY_VALUE()) で囲む。値がグループ内で本当に一意であると分かっている場合、ANY_VALUE() で意図的にあいまいさを抑止できる。クエリを修正せずにモードを無効にする (sql_mode から ONLY_FULL_GROUP_BY を削除する) と、誤った結果のリスクが戻るため避ける。","tags":["group by","only_full_group_by","sql_mode","any_value","aggregate","query"]},{"code":"1267","title":"Illegal mix of collations（照合順序の不正な混在）","severity":"caution","meaning":"比較または結合の操作 (JOIN、WHERE、UNION、CONCAT) で、照合順序の異なる 2 つの文字列が組み合わされ、MySQL はどの照合規則を適用すべきか判断できなかった。","cause":"通常、文字セット/照合順序の異なる列の比較 (例: utf8mb4_general_ci と utf8mb4_unicode_ci、または latin1 と utf8mb4)、または列と接続の照合順序の不一致。テーブル/データベースが異なるデフォルトで作成された場合によく見られる。","fix":"比較の両辺を同じ照合順序に揃える: COLLATE で明示的に照合順序を指定するか (例: col1 = col2 COLLATE utf8mb4_unicode_ci)、CONVERT(... USING ...) を使用する。恒久対策として、影響を受ける列/テーブルを一貫した単一の文字セットと照合順序に変換する。接続の照合順序 (collation_connection) も揃える。","tags":["collation","collation mismatch","character set","join","utf8mb4","convert"]},{"code":"1030","title":"Got error N from storage engine（ストレージエンジンからエラー N を受け取った）","severity":"danger","meaning":"ストレージエンジン (InnoDB/MyISAM) が操作を完了できず、低レベルのエラーコードを返した。SQL 層より下のディスク、ファイルシステム、またはエンジン内部の問題を示す汎用的な報告である。括弧内/メッセージ内のサブコードが実際の原因を示す。","cause":"よくある原因: ディスク/一時領域の満杯 (例: errno 28 - No space left on device)、ファイル権限の問題、破損したテーブルファイル、InnoDB 表領域の問題、または OS レベルの I/O エラー。大きな一時テーブルを生成するソート/グループ化のクエリでも発生する。","fix":"サブエラーコードを解読する (Linux では perror N で意味を表示できる。例: perror 28)。ディスク使用量と tmpdir の領域を確認し、空き領域を確保する。ファイルの所有者/権限を確認する。InnoDB の場合はエラーログで詳細を確認し、破損が疑われる場合は CHECK TABLE を実行し、必要に応じて復旧する。巨大な一時結果を生成するクエリを最適化する。","tags":["storage engine","innodb","disk","errno","tmpdir","i-o"]},{"code":"1197","title":"Multi-statement transaction required more than 'max_binlog_cache_size'（複数文トランザクションが 'max_binlog_cache_size' を超える領域を必要とした）","severity":"danger","meaning":"単一のトランザクションが生成した binlog データが、max_binlog_cache_size で定義されたメモリ/キャッシュの上限を超えた。トランザクションがバイナリログに収まらないため、失敗してロールバックされた。","cause":"非常に大きなトランザクション (数百万行の単一の INSERT/UPDATE/DELETE や巨大な一括ロード) が binlog キャッシュを満たした。バイナリログが有効な場合 (レプリケーション/ポイントインタイムリカバリ)、大きなトランザクションは容易にこの上限を超える。","fix":"大きなトランザクションを小さなバッチに分割し、各バッチ後に COMMIT する。本当に大きなトランザクションが避けられない場合は、max_binlog_cache_size (必要に応じて binlog_cache_size も) を増やす。ETL/一括ロードでは、途中で COMMIT を挟む分割ロードにより、このエラーとロックの長時間保持の両方を防げる。","tags":["binlog","max_binlog_cache_size","transaction","batch","replication","bulk"]},{"code":"1785","title":"Statement violates GTID consistency（文が GTID 整合性に違反）","severity":"danger","meaning":"GTID (Global Transaction Identifier) ベースのレプリケーションが有効な状態で、実行された文が GTID 整合性の規則に違反している。GTID モードでは、単一の GTID に安全に割り当てられない特定の種類の文は許可されない。","cause":"1785 (ER_GTID_UNSAFE_NON_TRANSACTIONAL_TABLE) は、具体的には非トランザクション (例: MyISAM) テーブルがトランザクション (InnoDB) テーブルと同じトランザクション内で更新された場合、または autocommit なしの複数文トランザクション内で更新された場合に発生する。古いバージョンでは、CREATE TABLE ... SELECT (8.0.21 より前。8.0.21+ ではアトミック DDL をサポートするエンジンで許可) とトランザクション内の CREATE/DROP TEMPORARY TABLE (8.0.13 より前。8.0.13+ では binlog_format が ROW/MIXED の場合に許可) も GTID 整合性に違反する (これらは別のエラーコードで報告される)。enforce_gtid_consistency=ON の場合に拒否される。","fix":"同じトランザクション内で非トランザクションエンジンのテーブルとトランザクションテーブルを混在させない。MyISAM テーブルは autocommit の単一文で更新するか、すべてのテーブルを InnoDB に移行する: ALTER TABLE my_table ENGINE=InnoDB; 古いバージョン (8.0.21 より前) では CREATE TABLE ... SELECT を 2 段階 (CREATE TABLE の後に INSERT ... SELECT) に分割し、8.0.13 より前では一時テーブルの作成と削除を明示的なトランザクションの外で行う。","tags":["gtid","replication","consistency","temporary table","myisam","innodb"]},{"code":"3024","title":"Query execution was interrupted, maximum statement execution time exceeded（最大文実行時間を超えたためクエリの実行が中断された）","severity":"caution","meaning":"SELECT クエリが、定義された最大実行時間 (max_execution_time / MAX_EXECUTION_TIME ヒント) を超えたため MySQL によって中断された。長時間実行のクエリがリソースを占有するのを防ぐタイムアウトの安全装置である。","cause":"クエリがセッション/グローバルの max_execution_time の値、または SELECT の MAX_EXECUTION_TIME(N) オプティマイザヒントより長く実行された。通常、非効率な実行計画、インデックスの欠如、大規模な走査、または高い同時実行時の速度低下が原因。(読み取り専用の SELECT にのみ適用される。)","fix":"EXPLAIN でクエリを分析して最適化する (適切なインデックス、より選択性の高い条件、全表走査の削減)。クエリが正当に長時間の実行を必要とする場合は、その SELECT の MAX_EXECUTION_TIME ヒントまたはセッションの max_execution_time を増やす。重い分析クエリはオフライン/レプリカで実行する。","tags":["timeout","max_execution_time","query","explain","index","select"]},{"code":"1298","title":"Unknown or incorrect time zone（不明または誤ったタイムゾーン）","severity":"caution","meaning":"指定されたタイムゾーン名が MySQL に認識されなかった。CONVERT_TZ() の呼出し、time_zone の設定、または名前付きタイムゾーン (例: 'Europe/Istanbul') を参照する操作が、そのタイムゾーンがサーバーで定義されていないため失敗した。","cause":"MySQL が名前付きタイムゾーンを使用するには、mysql スキーマのタイムゾーンテーブル (time_zone、time_zone_name など) がロードされている必要がある。これらのテーブルが空の場合は数値オフセット ('+03:00') のみが機能し、名前付きゾーンは不明となりこのエラーが発生する。","fix":"タイムゾーンテーブルをロードする。Linux では、mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql でシステムの zoneinfo データをインポートし、サーバーを再起動するか FLUSH TABLES を実行する。名前付きゾーンをロードできない場合は数値オフセット ('+03:00') を使用する。名前の綴り (大文字小文字、'Europe/Istanbul') を確認する。","tags":["time zone","timezone","convert_tz","zoneinfo","mysql_tzinfo_to_sql","offset"]},{"code":"1418","title":"Function has none of DETERMINISTIC, NO SQL, or READS SQL DATA (binary logging enabled)（関数に DETERMINISTIC、NO SQL、READS SQL DATA のいずれもない (バイナリログ有効)）","severity":"caution","meaning":"ストアドファンクションを作成しようとしたが、バイナリログが有効で、関数が決定性/データアクセスのいずれの特性も宣言されていない。レプリケーションの安全性の観点からあいまいなため、MySQL はそのような関数を拒否する。","cause":"log_bin が ON かつ log_bin_trust_function_creators=OFF の状態で、DETERMINISTIC、NO SQL、READS SQL DATA のいずれの特性もなしに関数が定義された。これらの特性がないと、MySQL は関数がレプリカで同じ結果を生成すると確信できない。","fix":"関数の動作を正しい特性で宣言する: 本当に決定的であれば DETERMINISTIC を、データにアクセスしなければ NO SQL を、読み取りのみであれば READS SQL DATA を追加する。関数が安全であると確信できる場合は、一元的なポリシーとして log_bin_trust_function_creators=1 を設定することもできる。ただし、特性を正しく宣言するのが最も安全な方法である。特性が関数の実際の動作と一致していることを確認する。","tags":["stored function","deterministic","binary log","replication","log_bin_trust_function_creators","reads sql data"]},{"code":"1231","title":"Variable can't be set to the value of ...（変数を ... の値に設定できない）","severity":"caution","meaning":"(SET で) システム/セッション変数に代入しようとしている値が無効である。許容される集合の範囲外、誤った型、または不適切な書式のため値が拒否された。","cause":"よくある例: sql_mode への無効/綴り誤りのモード名の代入、enum 変数への未定義のオプションの指定、または NULL を受け付けない変数への NULL の代入。誤った単位/範囲の数値でも発生する。","fix":"変数が受け付ける有効な値と型を確認する。ENUM/SET 型の変数 (例: SET 型である sql_mode) では、値/モード名を正確に綴り、複数の値はカンマで区切る。有効な値の範囲をドキュメントで確認する。sql_mode のようなリストでは、現在の値を読み取り (SELECT @@sql_mode)、その上で安全に項目を追加/削除する。","tags":["set","variable","sql_mode","enum","value","invalid"]}]},"errors/mssql-more4.json":{"engineId":"mssql","engine":"SQL Server","order":4,"errors":[{"code":"8645","title":"A time out occurred while waiting for memory resources to execute the query（クエリ実行用のメモリリソース待機中にタイムアウト発生）","severity":"danger","meaning":"クエリの実行に必要なメモリ許可 (memory grant) を待ってリソースセマフォで待機中にタイムアウトした。メモリ逼迫により許可を割り当てられなかったため、操作は取り消された。","cause":"同時実行されるメモリ集約型のクエリ (大規模なソート、ハッシュ結合、ハッシュ集約) がクエリメモリプール全体を消費し、新しいクエリがセマフォで待機してタイムアウトした。過大なメモリ許可の見積り (古い統計、不適切な実行計画) またはサーバーメモリの不足が根本原因。","fix":"sys.dm_exec_query_memory_grants とリソースセマフォの DMV で、メモリを待機中または保持中のクエリを特定する。統計を更新し、メモリ許可の膨張を引き起こす実行計画を修正する (適切なインデックス、より正確な見積り)。メモリ集約型のクエリの同時実行数を減らし、必要に応じて Resource Governor でメモリ許可に上限を設ける。サーバーのメモリ構成 (max server memory) を見直す。","tags":["memory grant","resource semaphore","memory","timeout","hash join","statistics"]},{"code":"8651","title":"Could not perform the operation because the requested memory grant was not available（要求されたメモリ許可が利用できないため操作を実行できない）","severity":"danger","meaning":"クエリに必要なメモリ許可が利用できず、操作を実行できなかった。8645 とは異なり、これは待機ではなく、要求された大きなメモリブロックを提供できないという即時の失敗であり、通常は深刻なメモリ逼迫を示す。","cause":"サーバー上の利用可能なクエリメモリが、単一の演算子 (例: 非常に大きなソート/ハッシュ) が要求する許可を満たせない。過度に高いメモリ見積り、低い max server memory、外部からのメモリ逼迫、または Resource Governor の低い上限 (ワークロードグループの REQUEST_MAX_MEMORY_GRANT_PERCENT やリソースプールの MAX_MEMORY_PERCENT) が原因となる。","fix":"メモリ許可を膨張させるクエリを最適化する (統計の更新、適切なインデックス作成、クエリの分割)。総メモリと利用可能メモリを監視し、max server memory の設定と外部アプリケーションによるメモリ逼迫を確認する。Resource Governor を使用している場合は、ワークロードグループの REQUEST_MAX_MEMORY_GRANT_PERCENT とプールの MAX_MEMORY_PERCENT の設定を見直す。メモリ集約型のバッチジョブはオフピーク時間帯に移す。","tags":["memory grant","memory","resource governor","statistics","hash","pressure"]},{"code":"5061","title":"ALTER DATABASE failed because a lock could not be placed on database（データベースにロックを設定できないため ALTER DATABASE が失敗）","severity":"danger","meaning":"他のアクティブな接続/セッションがデータベースを使用しているため、ALTER DATABASE 操作 (例: シングルユーザーモードへの切り替え、ファイルの変更、オプションの設定) がデータベースに必要なロックを取得できなかった。","cause":"データベースの使用中に操作が試行された。アクティブなユーザー接続のため、SET SINGLE_USER、RESTRICTED_USER などのオプション変更に必要な排他ロックを取得できなかった。アプリケーション接続が開いたまま頻繁にデプロイ/メンテナンスを行う場合によく発生する。","fix":"データベースに接続している他のセッションを特定し (sys.dm_exec_sessions、sp_who2)、安全に終了する。メンテナンスでは、ROLLBACK オプションで開いているトランザクションをロールバックしながらモードを変更する: ALTER DATABASE [db] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; アプリケーションのトラフィックが少ないとき、またはメンテナンス時間帯に操作を行う。終了後は MULTI_USER に戻すことを忘れない。","tags":["alter database","lock","single_user","connection","maintenance","rollback"]},{"code":"3702","title":"Cannot drop database because it is currently in use（データベースは使用中のため削除できない）","severity":"caution","meaning":"データベースの削除または名前変更を試みたが、データベースがまだアクティブな接続で使用中のため拒否された。SQL Server は使用中のデータベースを削除できない。","cause":"削除対象のデータベースに他のセッション (アプリケーションプール、開いたままの SSMS タブ、バックグラウンドジョブ) が接続している。自身のセッションのコンテキスト (USE) がそのデータベースである場合でも発生する。監視/バックアップツールの開いた接続もよくある原因。","fix":"削除前に別のデータベースに切り替える (USE master;)。接続中のセッションを特定して終了するか、先にデータベースをシングルユーザーモードにする: ALTER DATABASE [db] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; 続いて DROP DATABASE [db]; を実行する。アプリケーションのコネクションプールを停止し、監視ツールが接続を開いていないことを確認する。","tags":["drop database","connection","in use","single_user","use","maintenance"]},{"code":"15138","title":"The database principal owns a schema in the database, and cannot be dropped（データベースプリンシパルがスキーマを所有しているため削除できない）","severity":"caution","meaning":"データベースユーザー/ロール (データベースプリンシパル) を削除しようとしたが、そのプリンシパルがデータベース内の 1 つ以上のスキーマを所有しているため削除できなかった。所有するスキーマを別のプリンシパルに移すまで削除できない。","cause":"削除しようとしているユーザーが少なくとも 1 つのスキーマの OWNER である (例: デフォルトで自身の名前で作成されたスキーマ、または AUTHORIZATION で割り当てられたスキーマ)。SQL Server は孤立したスキーマが残るのを避けるため削除をブロックする。","fix":"ユーザーが所有するスキーマを特定する: SELECT name FROM sys.schemas WHERE principal_id = USER_ID('app_user'); これらのスキーマの所有権を別のプリンシパル (例: dbo) に移す: ALTER AUTHORIZATION ON SCHEMA::[app_schema] TO dbo; スキーマが不要 (かつ空) であれば DROP SCHEMA を実行する。所有権を移した後、DROP USER を再実行する。","tags":["schema","principal","user","owner","alter authorization","drop user"]},{"code":"1934","title":"INSERT/UPDATE failed because the following SET options have incorrect settings（次の SET オプションの設定が誤っているため INSERT/UPDATE が失敗）","severity":"danger","meaning":"必要な SET オプションが誤って設定されていたため、DML 操作 (INSERT/UPDATE/DELETE) が失敗した。典型的には、インデックス付きビュー、計算列のインデックス、フィルター選択されたインデックス、空間/XML インデックスに必須の SET 設定が満たされていない場合に発生する。","cause":"対象のテーブル/ビューに特定の SET オプション (特に QUOTED_IDENTIFIER と ANSI_NULLS が ON、NUMERIC_ROUNDABORT が OFF など) を必要とするオブジェクトがあるが、セッションの現在の SET オプションがその要件を満たしていない。古いクライアントドライバや、誤った SET オプションを明示的に設定するスクリプトがきっかけとなる。","fix":"接続/セッションで必要なオプションを設定する: SET QUOTED_IDENTIFIER ON; SET ANSI_NULLS ON; SET ANSI_PADDING ON; SET ANSI_WARNINGS ON; SET CONCAT_NULL_YIELDS_NULL ON; SET ARITHABORT ON; SET NUMERIC_ROUNDABORT OFF; アプリケーションのドライバが接続時にこれらのオプションを正しく送信していることを確認する。エラーメッセージに誤ったオプションの名前が示されるので、それらを修正する。","tags":["set options","indexed view","computed column","quoted_identifier","ansi_nulls","dml"]},{"code":"468","title":"Cannot resolve the collation conflict（照合順序の競合を解決できない）","severity":"caution","meaning":"操作 (JOIN、UNION、WHERE の比較または等価) で照合順序の異なる 2 つの文字列式が出会い、SQL Server はどの照合順序を適用すべきか解決できなかった。あいまいさのため操作は取り消された。","cause":"比較される列が異なる照合順序で定義されている。データベースの照合順序がサーバー/tempdb の照合順序と異なる場合や、照合順序の異なるデータベースのテーブルを結合した場合に最もよく見られる。一時テーブル (tempdb の照合順序) と永続テーブルの結合は典型的なきっかけ。","fix":"比較で照合順序を明示的に指定する: ... WHERE a.col = b.col COLLATE DATABASE_DEFAULT (または具体的な照合順序名)。一時テーブルの列を作成する際に COLLATE DATABASE_DEFAULT を使用する。恒久対策として、影響を受ける列/データベースを一貫した単一の照合順序に揃える。tempdb との不一致が頻繁な場合は、DATABASE_DEFAULT が最も実用的な対処法である。","tags":["collation","collation","join","tempdb","database_default","conflict"]},{"code":"4864","title":"Bulk load data conversion error (type mismatch or invalid character)（一括読込みのデータ変換エラー (型の不一致または無効な文字)）","severity":"caution","meaning":"一括読込み (BULK INSERT、bcp、または OPENROWSET(BULK...)) の際に、ソースファイルのフィールドを対象列のデータ型に変換できなかった。報告された行/列のデータが想定された型と一致しない。","cause":"ソースデータファイルの値が対象列の型に適合しない: 数値列へのテキスト、誤った日付書式、想定外の小数点/桁区切り記号、誤った文字エンコーディング (UTF-8/UTF-16)、または誤ったフィールド/行ターミネータによる列のずれ。ヘッダー行をスキップしていないこともよくある原因。","fix":"エラーが報告した行と列に移動し、ソースデータを調べる。フィールド (FIELDTERMINATOR) と行 (ROWTERMINATOR) のターミネータをファイルに合わせ、FIRSTROW=2 でヘッダー行をスキップする。正しいコードページ/エンコーディングのため CODEPAGE または DATAFILETYPE を設定する。日付/数値の書式を対象の型と互換にする。フォーマットファイルを使用するとマッピングが確実になる。","tags":["bulk insert","bcp","conversion","fieldterminator","encoding","format file"]},{"code":"916","title":"The server principal is not able to access the database under the current security context（サーバープリンシパルは現在のセキュリティコンテキストでデータベースにアクセスできない）","severity":"caution","meaning":"ログインが特定のデータベースへのアクセスを試みたが、現在のセキュリティコンテキストではアクセス権がない。ログインはサーバーに接続できるが、対象データベースに対応するユーザー/権限がない。","cause":"ログインにデータベース内のマッピングされたユーザーがない (孤立しているか作成されていない)、データベースへのアクセスが制限されている、または guest アカウントが無効になっている。よくあるケースは、SSMS のオブジェクトエクスプローラーが、ログインにアクセス権のないデータベースのメタデータを読み取ろうとすることである。","fix":"対象データベースにログイン用のユーザーを作成し、必要な権限を付与する: USE [db]; CREATE USER [login] FOR LOGIN [login]; 続いて適切なロール/権限を割り当てる。孤立ユーザーが存在する場合は ALTER USER ... WITH LOGIN = ... でマッピングする。アクセスが本当に必要であれば適切なデータベースロールに追加する。そうでなければ、このエラーは想定された動作である (そのデータベースへのアクセス権がない)。","tags":["login","user","access","privilege","security context","orphaned user"]}]},"errors/mongodb-more4.json":{"engineId":"mongodb","engine":"MongoDB","order":5,"errors":[{"code":"216 ElectionInProgress","title":"ElectionInProgress","severity":"caution","meaning":"レプリカセットで現在プライマリの選出が進行中である。選出が完了するまでプライマリが確定しないため、書き込み (および一部の読み取り) は一時的に受け付けられない。","cause":"現在のプライマリのダウン、ネットワーク分断、メンテナンスのための stepdown、またはノードの再起動の後に、クラスタが新しいプライマリを選出している。選出には通常数秒かかり、この間に到着した操作がこの状態に遭遇する。","fix":"これは一時的なものである。ドライバの再試行機能 (retryable writes/reads) を有効にすると、選出の完了後に操作が自動的に再試行される。選出が頻繁または長い場合は根本原因を調査する: ネットワークの安定性、ノードの健全性、投票の構成、選出タイムアウトの設定 (settings.electionTimeoutMillis)。rs.status() でクラスタの状態を調べる。","tags":["replica set","election","primary","retry","step-down","high availability"]},{"code":"225 TransactionTooOld","title":"TransactionTooOld","severity":"caution","meaning":"マルチドキュメントトランザクション内でコマンドが実行されたが、そのトランザクション番号が、サーバーがそのセッションで認識している最新のトランザクション番号より古い。つまり新しいトランザクションが開始されているため、この古いトランザクションはもはや有効ではない。","cause":"古いトランザクションの完了前に同じセッションで新しいトランザクションが開始された、または同時実行によりトランザクション番号が順不同に進んだ。通常、セッションオブジェクトが誤って共有されている場合や、複数のスレッドが同じセッションを使用している場合に発生する。","fix":"論理トランザクションごとにセッションのライフサイクルを正しく管理し、セッションを複数のスレッド間で同時に共有しない。ドライバが推奨する withTransaction/コールバック API でトランザクションを実行する (再試行と番号管理を処理する)。新しいトランザクションを開始する前に、前のトランザクションを commit/abort で閉じる。","tags":["transaction","session","session misuse","concurrency","withtransaction","multi-document transaction"]},{"code":"246 SnapshotUnavailable","title":"SnapshotUnavailable","severity":"caution","meaning":"要求されたスナップショット読み取り確認 (readConcern: snapshot) での読み取りを実行できなかった。サーバーがその時点の一貫したスナップショットを提供できないためである。通常、読み取りタイムスタンプが十分に進んでいない、または遅れていることに関連する。","cause":"readConcern 'snapshot' が (主にマルチドキュメントトランザクションで) 使用されたが、要求された atLeast/at タイムスタンプに対する一貫したビューがまだ利用できない。例: 新しく作成されたコレクション/インデックス、カタログの変更、またはレプリケーションラグ。この場合サーバーは読み取りを拒否する。","fix":"通常は一時的である。少し待ってから操作を再試行する (ドライバの一時トランザクションエラーの再試行メカニズムがこれをカバーする)。最近 DDL (コレクション/インデックスの作成) を実行した場合は、その後にトランザクションを開始する。レプリケーションラグとノードの健全性を確認する。スナップショット読み取りが本当に必要でなければ、より適切な readConcern を選択する。","tags":["snapshot","readconcern","transaction","timestamp","retry","replication"]},{"code":"257 TransactionTooLarge","title":"TransactionTooLarge","severity":"danger","meaning":"マルチドキュメントトランザクションが許容されるサイズ/操作数の上限を超えた。トランザクションに蓄積された変更 (oplog エントリまたはメモリ使用量) が上限を超えたため、トランザクションは拒否された。","cause":"単一のトランザクションで多数のドキュメントを変更/挿入したため、トランザクションが生成するデータの総量が大きくなりすぎた (例: WiredTiger キャッシュに保持すべき変更量、または transactionLimitBytes などのサーバーの上限)。4.2 以降、トランザクションは複数の oplog エントリに分割できるため、16 MB の oplog エントリ上限だけが決定的なわけではない。一括データ移行/ETL にトランザクションを使用すると容易にこの上限に達する。","fix":"トランザクションを小さく分割し、各バッチを別々のトランザクションでコミットする。マルチドキュメントトランザクションは短く小さく使うよう設計されている。大規模な一括更新はトランザクションなしで (冪等に、チャンクごとに) 行うか、bulk write で分割することを優先する。単一のトランザクションで数千のドキュメントを変更することを避ける。","tags":["transaction","size","oplog","batch","bulk","bulk write"]},{"code":"276 IndexBuildAborted","title":"IndexBuildAborted","severity":"danger","meaning":"進行中のインデックス構築が完了前に中止/停止された。対象のインデックスは正常に作成されなかった。","cause":"ノードのディスク/メモリ不足、dropIndexes による明示的な中止、プライマリの stepdown/レプリカ状態の変化、一意性違反 (一意インデックス構築中の競合ドキュメント)、またはノードの再起動により、インデックス構築が中止された可能性がある。","fix":"mongod のログで中止の理由 (ディスク容量、メモリ、一意性の競合など) を特定し、解決する。一意インデックスを構築する場合は、先に競合するドキュメントを整理する。十分なディスク/メモリを確保し、レプリカの状態が安定していることを確認する。問題を修正した後、createIndex でインデックスを再構築する。大きなコレクションでは低負荷の時間帯を選ぶ。","tags":["index","index build","aborted","unique","disk","replica set"]},{"code":"86 IndexKeySpecsConflict","title":"IndexKeySpecsConflict","severity":"caution","meaning":"作成しようとしているインデックスが既存のインデックスと同じキー指定 (同じフィールド/順序) を持つが、オプションまたは名前が異なる。MongoDB は同じキーで競合する 2 つのインデックス定義を許可しない。","cause":"同じフィールドに、異なる名前または異なるオプション (例: 異なる collation、partialFilterExpression、unique の設定) で 2 つ目のインデックスを作成しようとした。通常、マイグレーション/コードでインデックス定義を変更して再実行した場合に発生する。","fix":"既存のインデックスを調べる: db.collection.getIndexes() 同じキーを持つ競合インデックスを特定する。目的のオプションに切り替えるには、先に古いインデックスを削除し (dropIndex)、新しい定義で再作成する。名前だけが異なる場合は既存のインデックスをそのまま使用し、不要な 2 つ目の定義を作成しない。","tags":["index","getindexes","collation","unique","conflict","createindex"]},{"code":"166 CommandNotSupportedOnView","title":"CommandNotSupportedOnView","severity":"caution","meaning":"このコマンドはビューではサポートされない。MongoDB のビューは読み取り専用であり、特定の読み取り操作のみを受け付ける。書き込みやサポートされないコマンドは拒否される。","cause":"ビューに対して insert/update/delete などの書き込み操作、またはビューでサポートされない特定のコマンド (例: 一部のテキスト/地理空間操作、直接のインデックス作成) が試行された。アプリケーションがビューをコレクションと思い込んで書き込もうとした場合に見られる。","fix":"書き込みはビューの基になる (ソース) コレクションに対して行う。ビューは読み取り専用である。コマンドがビューでサポートされているか確認し、サポートされる読み取り/集計操作を使用する。書き込み可能な構造が必要な場合は、ビューではなくマテリアライズドコレクション ($merge/$out) を設計する。","tags":["view","read-only view","read only","aggregation","write","collection"]},{"code":"168 InvalidPipelineOperator","title":"InvalidPipelineOperator","severity":"caution","meaning":"集計パイプラインで認識されない、または無効な演算子/ステージが使用された。MongoDB は指定された演算子名を解決できず、パイプラインを拒否した。","cause":"演算子名の綴り誤り (例: '$group' ではなく '$groups')、使用中の MongoDB バージョンで利用できない新しい演算子、または誤ったコンテキストで使用された式。$ プレフィックスの欠落や無効な位置での演算子の使用でも発生する。","fix":"演算子/ステージ名の綴りと $ プレフィックスを確認する。演算子がサーバーの MongoDB バージョンでサポートされていることを確認する (新しい演算子は古いバージョンには存在しない)。パイプラインをドキュメントの構文と比較し、式を正しいステージ内で使用する (例: $expr、$project)。ステージを切り分け、小さなサンプルでテストする。","tags":["aggregation","pipeline","operator","syntax","version","expr"]},{"code":"118 NamespaceNotSharded","title":"NamespaceNotSharded","severity":"caution","meaning":"シャード化されたコレクションでのみ意味を持つ操作が、まだシャード化されていないコレクション/名前空間に対して実行された。対象のコレクションがシャード化されていないため、コマンドを適用できなかった。","cause":"シャーディングが有効でないコレクションに対して、moveChunk、split、または特定のシャードキーに基づく管理コマンドが呼び出された。通常、コレクションが shardCollection でシャード化されていない、または誤った名前空間を対象にしたことが原因。","fix":"コレクションのシャーディング状態を確認する: sh.status() または config.collections。操作に本当にシャーディングが必要であれば、先にデータベースでシャーディングを有効にし (sh.enableSharding)、コレクションをシャード化する (適切なシャードキーで sh.shardCollection)。そうでなければ、シャード化されていないコレクションにこれらの管理コマンドは不要である。正しい名前空間を対象にしていることを確認する。","tags":["sharding","shard","namespace","shardcollection","movechunk","cluster"]}]},"errors/redis-more4.json":{"engineId":"redis","engine":"Redis","order":6,"errors":[{"code":"ERR Protocol error: invalid multibulk length","title":"Protocol error: invalid multibulk length（プロトコルエラー: 無効な multibulk 長）","severity":"danger","meaning":"Redis サーバーがクライアントからのバイトストリームを RESP (Redis Serialization Protocol) に従って解析できなかった。multibulk コマンドで宣言された要素数が無効だったため、プロトコルエラーで接続がクローズされた。","cause":"通常、Redis 以外のクライアント (例: HTTP 要求、誤ったポートに接続したアプリケーション) が Redis のポートに生データを送信した、壊れた/不完全なクライアントライブラリ、パイプラインでの誤ったフレーミング、またはプロトコルの上限 (proto-max-bulk-len) を超える巨大な要求がきっかけとなる。","fix":"Redis のポートに実際の Redis クライアントのみが接続していることを確認する (紛れ込んだ HTTP/他プロトコルのトラフィックがないこと)。クライアントライブラリを更新し、RESP のフレーミングを壊す独自/手動のコマンド生成を避ける。非常に大きな値を送信する場合は、proto-max-bulk-len の上限と要求サイズを見直す。ネットワーク上の中間プロキシがデータを破損していないことを確認する。","tags":["protocol","resp","multibulk","client","pipeline","connection"]},{"code":"ERR Number of keys can't be greater than number of args","title":"EVAL/EVALSHA: numkeys exceeds argument count（numkeys が引数の数を超えている）","severity":"caution","meaning":"Lua スクリプト (EVAL/EVALSHA/FCALL) の実行時に、指定されたキー数 (numkeys) がコマンドに実際に渡された引数の数より大きい。KEYS と ARGV の配列を分割できないため、Redis はコマンドを拒否する。","cause":"EVAL の構文は 'EVAL script numkeys key [key ...] arg [arg ...]' である。numkeys の値が誤って計算された (大きすぎる値に設定された)、または想定されたキーがコマンドに追加されていない。よくあるプログラミングの誤り。","fix":"numkeys をコマンドに実際に渡すキーの数と正確に一致させる。numkeys が自動計算されるよう、クライアントライブラリの EVAL ラッパー (通常 KEYS と ARGV を別々のリストとして受け取る) を使用する。スクリプトを呼び出す際は、キーを KEYS に、その他のパラメータを ARGV に正しく分ける。","tags":["lua","eval","evalsha","numkeys","keys","script"]},{"code":"ERR WATCH inside MULTI is not allowed","title":"WATCH inside MULTI is not allowed（MULTI 内の WATCH は許可されない）","severity":"caution","meaning":"開いている MULTI ブロック内で WATCH が送信された。楽観的ロックのため、WATCH はトランザクション開始前にキーを監視対象にする必要があり、MULTI の後に呼び出すと拒否される。このエラーでトランザクションは中止されず、WATCH のみが失敗し、何も監視されない。","cause":"コード内で WATCH と MULTI の順序が逆になっている (先に MULTI、次に WATCH)、クライアントライブラリのパイプライン/トランザクションラッパー内で WATCH を呼び出している、または MULTI 状態のまま残されたプール接続を使用している。この場合、監視されるはずのキーが変更されても EXEC が実行され、想定した競合保護が働かない。","fix":"正しい順序: WATCH key -> (値を読み取る) -> MULTI -> コマンド -> EXEC。EXEC が nil を返した場合は監視対象のキーが変更されたので、操作を最初からやり直す。クライアントライブラリの WATCH/トランザクション API (例: watch + パイプラインのヘルパー) を使用する。注: SUBSCRIBE などの pub/sub コマンドは MULTI 内で拒否されず、キューに入れられ、EXEC 後に接続が subscribe モードに切り替わる。これも推奨されないため、pub/sub には専用の接続を使用する。","tags":["multi","watch","transaction","optimistic locking","exec","connection"]},{"code":"ERR WAIT cannot be used with replica instances","title":"WAIT cannot be used with replica instances（WAIT はレプリカインスタンスでは使用できない）","severity":"caution","meaning":"レプリカ (replica/slave) インスタンスで WAIT が実行された。書き込みが指定数のレプリカに到達するのを待つ WAIT は、プライマリ (master) でのみ意味を持ち、レプリカでは使用できない。","cause":"アプリケーションが誤ってレプリカへの接続で WAIT を送信した。通常、接続が読み取りレプリカにルーティングされている、またはロール変更 (フェイルオーバー) 後もクライアントがレプリカに接続したままであることが原因。","fix":"WAIT はプライマリノードにのみ送信する。クライアント/プロキシの構成で、書き込みと WAIT の呼出しが master にルーティングされることを確認する。フェイルオーバー後のロール変更を検出し、接続を新しいプライマリに振り向ける (ROLE コマンドでロールを確認できる)。","tags":["wait","replica","master","write","failover","replication"]},{"code":"ERR Background append only file rewriting already in progress","title":"AOF rewrite already in progress（AOF 書換えが既に進行中）","severity":"caution","meaning":"AOF (Append Only File) の書換え (BGREWRITEAOF) を開始しようとしたが、AOF の書換えが既に進行中である。2 つの AOF 書換えを同時に実行することはできない。","cause":"以前の BGREWRITEAOF (手動、または auto-aof-rewrite-percentage トリガーによる自動) がまだ実行中に、新しい書換え要求が到着した。大規模なデータセットでは AOF の書換えに長時間かかり、この競合を引き起こすことがある。","fix":"実行中の書換えが終わるまで待つ。INFO persistence の出力の aof_rewrite_in_progress フィールドを監視する。操作が正当に実行中であれば、別の要求を送信しない。競合が頻繁な場合は、自動書換えのしきい値 (auto-aof-rewrite-percentage/min-size) とディスク I/O の性能を見直す。","tags":["aof","bgrewriteaof","persistence","rewrite","info","disk"]},{"code":"IOERR error or timeout reading from target instance","title":"MIGRATE: I/O error or timeout to target（ターゲットへの I/O エラーまたはタイムアウト）","severity":"danger","meaning":"MIGRATE コマンド (通常は Redis Cluster でのスロット/キーの移動中) が、対象インスタンスへの接続またはその応答の読み取り中に I/O エラーまたはタイムアウトに遭遇した。キーの移行を安全に完了できなかった。","cause":"ソースノードとターゲットノード間のネットワーク遅延/障害、ターゲットノードの過負荷または無応答、短すぎる MIGRATE のタイムアウト、または指定時間内に転送できない大きなキー。クラスタのリバランス (resharding) 中によく発生する。","fix":"ソースノードとターゲットノード間のネットワーク接続と遅延を確認する。MIGRATE により長いタイムアウトを指定する (特に大きなキーの場合)。ターゲットノードの健全性/負荷とメモリの状態を確認する。resharding 中に大きなキーを移動する場合は低負荷の時間帯を選び、必要に応じて移行を再試行する。","tags":["migrate","cluster","resharding","timeout","network","i-o"]},{"code":"ERR Error compiling script (new function)","title":"Error compiling Lua script（Lua スクリプトのコンパイルエラー）","severity":"caution","meaning":"EVAL で送信した Lua スクリプトを、Redis の組込み Lua インタプリタがコンパイルできなかった。スクリプトに構文エラーがあるため、実行開始前に拒否された。","cause":"Lua スクリプトの構文エラー: 閉じられていない括弧/引用符、キーワードの綴り誤り、'end' の欠落、無効な演算子、またはサポートされない Lua の構文。クライアント側でのスクリプトの誤った連結/エスケープでも発生する。","fix":"エラーメッセージの行/文字の情報を使って Lua の構文を修正する (括弧、引用符、'end' の対応を確認する)。別の Lua 環境でコンパイルしてスクリプトを検証する。クライアントがスクリプトを正しく組み立てていること (エスケープ/連結の誤りがないこと) を確認する。検証済みのスクリプトを SCRIPT LOAD で事前にロードし、EVALSHA で呼び出す。","tags":["lua","eval","compilation","syntax","script load","script"]},{"code":"ERR FAILOVER requires connected replicas.","title":"FAILOVER requires connected replicas（FAILOVER には接続されたレプリカが必要）","severity":"caution","meaning":"協調的な (グレースフル) フェイルオーバーを開始するために FAILOVER を実行したが、プライマリに接続されていて役割を引き継げる適切なレプリカがないため拒否された。役割を引き渡す対象がなければフェイルオーバーは行えない。","cause":"現在プライマリに接続されたレプリカがない (レプリカが停止している、ネットワークから切断されている、または同期していない)、または指定したターゲットレプリカが適格でない/接続されていない。手動の FAILOVER (Redis 6.2+) を呼び出した際に、レプリケーショントポロジが必要な条件を満たしていない。注: FAILOVER はスタンドアロン (master/replica) のレプリケーションでのみ機能する。Redis Cluster ではレプリカで CLUSTER FAILOVER を使用する。","fix":"正常で、接続され、最新の状態のレプリカが少なくとも 1 つ存在することを確認する (INFO replication で connected_slaves と同期状態を確認)。レプリカのネットワーク/アクセスの問題を修正し、プライマリに接続させる。特定のターゲットにフェイルオーバーするには FAILOVER TO host port を使用し、そのレプリカが適格であることを確認する。","tags":["failover","replica","master","replication","info replication","high availability"]},{"code":"ERR invalid expire time in 'set' command","title":"invalid expire time in SET（SET の有効期限が無効）","severity":"caution","meaning":"SET (EX/PX/EXAT/PXAT オプション付き) に無効な有効期限が与えられた。ゼロや負の値などの意味のない有効期間 (TTL) を受け付けないため、Redis はコマンドを拒否した。","cause":"EX/PX で 0 または負の値を送信した、またはアプリケーションが有効期限を誤って計算して無効な数値を生成した。SETEX/GETEX などのコマンドも、正でない期間に対して同様にこのエラーを返す。一部のクライアントのバグは秒とミリ秒の混同に起因する。","fix":"有効期限は常に厳密に正の整数で送信する。EX は秒、PX はミリ秒を想定する。アプリケーションで期間の計算を検証し (負/ゼロの結果にならないこと)、単位 (秒とミリ秒) を混同しない。キーを即座に削除するには、有効期限を設定するのではなく DEL/UNLINK を使用する。絶対時刻の場合は、EXAT/PXAT に有効な将来の Unix タイムスタンプを渡す。","tags":["set","expire","ttl","ex","px","expiration"]}]},"errors/elasticsearch-more4.json":{"engineId":"elasticsearch","engine":"Elasticsearch","order":7,"errors":[{"code":"bind_transport_exception","title":"bind_transport_exception (Address already in use)（アドレスは既に使用中）","severity":"danger","meaning":"Elasticsearch ノードが起動時に、トランスポート (ノード間通信) または HTTP のポートでリッスンするためのソケットをバインドできなかった。通常 'Address already in use' のサブエラーを伴い、ノードは起動できない。","cause":"要求されたポート (デフォルトはトランスポート 9300、HTTP 9200) が既に別のプロセスで使用されている。最も多いのは同じノードの以前のインスタンスが正常にシャットダウンしなかった場合で、同じホスト上の別の ES インスタンス/サービスとの競合や、network.host/port の設定誤りもある。権限/アクセスの制限がバインドを妨げることもある。","fix":"ポートを保持しているプロセスを特定し (Linux: ss -ltnp | grep 9300 または lsof -i:9300)、競合するプロセスを終了するか、ノードに別のポートを割り当てる (transport.port / http.port)。以前の ES プロセスが実際に終了していることを確認する。network.host とポート範囲の設定が正しくバインド可能であることを確認する。その後ノードを再起動する。","tags":["transport","port","9300","bind","network.host","startup"]},{"code":"translog_corrupted_exception","title":"translog_corrupted_exception","severity":"danger","meaning":"シャードのトランザクションログ (translog) が破損しているため読み取れなかった。リカバリ中に Elasticsearch が translog の整合性チェックの失敗を検出し、シャードを起動できなかった。","cause":"translog ファイルは通常、突然の電源喪失、ディスク満杯、ファイルシステムエラー、ハードウェア/ディスク障害、またはデータディレクトリに対する外部操作 (コピー、手動介入) によって破損する。強制シャットダウン (kill -9) 中の部分的に完了した書き込みも原因となる。","fix":"まずレプリカまたはスナップショットからデータの復旧を試みる。正常なコピーが存在すれば、そこから破損したシャードを再構築するのが最も安全である。他のコピーがなくデータ損失を受け入れる場合は、ノードを停止し、bin/elasticsearch-shard remove-corrupted-data --index <index> --shard-id <n> で破損した translog/データを整理する (これによりまだコミットされていないデータは永久に失われる。旧来の elasticsearch-translog ツールは 7.0 で削除された)。ツールは、ノード再起動後にシャードを割り当てるために必要な POST _cluster/reroute コマンド (allocate_stale_primary、accept_data_loss: true) を出力する。操作前にデータディレクトリをバックアップする。ディスクの健全性と空き容量を確認する。","tags":["translog","shard","recovery","corruption","snapshot","disk"]},{"code":"recovery_engine_exception","title":"recovery_engine_exception","severity":"danger","meaning":"シャードのリカバリ中にエンジンレベルのエラーが発生し、シャードを正常にオープンできなかった。リカバリは、ノードの再起動、レプリカの割り当て、またはスナップショットのリストアの際に実行されるステップである。","cause":"リカバリ中の根本的な問題: 破損した Lucene セグメントや translog、ディスク容量の不足、ファイル権限、ソースノードとターゲットノード間のネットワーク中断、またはバージョン/互換性の問題。通常、より具体的なサブエラー (破損、I/O) をラップしている。","fix":"根本的な (caused_by) エラーを調べ、実際の問題 (破損、ディスク、ネットワークなど) を特定する。ディスク容量とファイル権限を確認する。レプリカの割り当てが失敗する場合は、_cluster/allocation/explain で理由を確認し、必要に応じて再割り当てをトリガーする。破損がある場合は、正常なレプリカ/スナップショットから復旧する。ネットワーク関連であれば、ノード間の接続とリカバリの設定を確認する。","tags":["recovery","shard","engine","allocation","corruption","disk"]},{"code":"snapshot_in_progress_exception","title":"snapshot_in_progress_exception","severity":"caution","meaning":"要求された操作が、現在進行中のスナップショットと競合するため拒否された。例えば、スナップショットの取得中にインデックスを削除/クローズしたり、リポジトリを変更したりする試みはブロックされる。","cause":"スナップショットがまだ実行中に、そのスナップショットに含まれるインデックスの削除/クローズ、リポジトリの削除/変更、または競合する別のスナップショット/リストア操作の開始が試行された。Elasticsearch は整合性を保つため、これらの競合する操作を許可しない。","fix":"実行中のスナップショットが終わるまで待つ: GET _snapshot/_status で進捗を監視する。操作を本当に取り消す必要がある場合は、スナップショットを削除して停止する: DELETE _snapshot/repo/snapshot_name (実行中のスナップショットが中止される)。スナップショットが完了または取り消された後、元の操作 (インデックスの削除、リポジトリの変更) を再実行する。","tags":["snapshot","repository","restore","index deletion","conflict","backup"]},{"code":"repository_verification_exception","title":"repository_verification_exception","severity":"danger","meaning":"スナップショットリポジトリの登録または検証中に、すべてのノードがリポジトリにアクセスできるかのチェックが失敗した。リポジトリの検証に合格しなかったため、スナップショット/リストア操作を確実に実行できない。","cause":"共有ファイルシステム (fs) リポジトリがすべてのノードで同じパスにマウントされていない/アクセスできない、構成に path.repo がない、ファイル権限が不足している、またはクラウド/オブジェクトストア (S3、GCS、Azure) の認証情報/ネットワークアクセスが誤っている。一部のノードがリポジトリに書き込めないことが典型的な原因。","fix":"共有 fs リポジトリの場合は、すべてのノードの elasticsearch.yml で path.repo が定義され、すべてのノードで同じパスが読み書き可能にマウントされていることを確認する。ファイル権限 (elasticsearch ユーザー) を修正する。クラウドリポジトリの場合は、認証情報 (keystore)、バケット名、ネットワーク/アクセス権限を確認する。POST _snapshot/repo/_verify でリポジトリを再検証する。","tags":["repository","snapshot","path.repo","permission","s3","verification"]},{"code":"reduce_search_phase_exception","title":"reduce_search_phase_exception","severity":"danger","meaning":"検索の reduce フェーズでエラーが発生した。コーディネーティングノードが、異なるシャードからの部分的な結果/集計をマージ (reduce) する際に問題に遭遇し、最終結果を生成できなかった。","cause":"通常、結果のマージ中にメモリ/リソースの上限を超えた (例: 非常に大きな集計、サーキットブレーカーの作動)、互換性のない/無効な集計構造、またはシャードが返した部分的な結果をマージできない。非常にカーディナリティの高い集計でよく見られる。","fix":"caused_by の詳細を読み、根本原因を特定する。重い集計を軽量化する: カーディナリティの高い terms 集計の size を下げ、composite 集計でページングし、不要なサブ集計を減らす。メモリ逼迫を監視し、必要に応じてクエリを小さな部分に分割する。サーキットブレーカーが作動する場合は、クエリのコストを下げる。","tags":["search","reduce","aggregation","coordinating node","memory","cardinality"]},{"code":"aggregation_execution_exception","title":"aggregation_execution_exception","severity":"caution","meaning":"集計の実行中にエラーが発生した。集計の定義は解析されたが、対象のフィールド/値の処理中に実行時の問題が発生した。","cause":"集計がフィールドの型と互換性がない (例: fielddata なしでの text フィールドの集計)、ソート/計算中の無効な値、存在しないパス (bucket path) を参照するパイプライン集計、またはサポートされないフィールド型の組合せ。スクリプトベースの集計での実行時エラーでも発生する。","fix":"エラーの詳細にあるフィールド/集計名を調べる。集計対象のフィールドが適切な型であることを確認する (text ではなく keyword/数値。必要に応じて doc_values が有効なフィールドを使用する)。パイプライン集計では、buckets_path が実際のバケット名と一致していることを確認する。スクリプト集計には null/型のチェックを追加する。適切なフィールド型でマッピングを修正する。","tags":["aggregation","execution","fielddata","keyword","pipeline","mapping"]},{"code":"failed_node_exception","title":"failed_node_exception","severity":"danger","meaning":"クラスタ全体の操作 (例: 検索、統計、管理コマンド) の際に、クラスタ内の特定のノードが要求を処理または応答できなかった。コーディネーティングノードは、そのノードからの失敗をこの例外でラップする。","cause":"ノードのクラッシュ、ネットワークからの離脱、過負荷/GC の一時停止による無応答、ディスク/リソースの問題、またはそのノード上のシャードエラー。クラスタの再構成 (ノードの離脱/参加) 中に一時的に発生することもある。","fix":"caused_by を使って、どのノードでなぜ失敗したかを特定する。ノードの健全性を確認する: GET _cat/nodes、GET _nodes/stats (CPU、メモリ、GC、ディスク)。ノードがリソース逼迫状態にある場合は負荷/ヒープの設定を見直し、ネットワーク接続を確認する。ノードがクラスタから離脱した場合は、再参加とシャード割り当ての回復を待つ (GET _cluster/health)。","tags":["node","cluster","network","gc","shard","resources"]},{"code":"elasticsearch_parse_exception","title":"elasticsearch_parse_exception","severity":"caution","meaning":"Elasticsearch が要求ボディ (JSON クエリ、設定、または構成) の解析中に汎用的な解析エラーに遭遇した。要求が構造的に想定された形式と一致しない。","cause":"不正な形式/無効な JSON (カンマの欠落、閉じられていない括弧)、位置の誤ったフィールド、想定外の値の型 (例: 数値が想定される箇所にテキスト)、または無効な時刻/範囲の式。DSL クエリの誤ったネストでもこの例外が発生する。","fix":"要求ボディを JSON バリデータにかけ、括弧、引用符、カンマを確認する。Elasticsearch DSL のドキュメントと照らし合わせ、フィールドが正しい位置にあり正しい型であることを確認する。エラーメッセージの位置/フィールドのヒントを使って問題の部分を修正する。クライアントライブラリを使用している場合は、シリアライズが有効な JSON を生成していることを確認する。","tags":["parse","json","dsl","query","parsing","request"]}]},"health/oracle.json":{"engineId":"oracle","engine":"Oracle","order":1,"checks":[{"id":"version-uptime","group":"一般","title":"バージョンと稼働時間","command":"SELECT i.instance_name, i.version_full, i.status, i.startup_time, ROUND(SYSDATE - i.startup_time, 2) AS uptime_days FROM v$instance i;","expect":"インスタンスの状態は OPEN であるべき。startup_time が予想外に最近(起動直後)の場合、計画外の再起動が発生した可能性があるため調査する。version_full 列は 18c+。12c 以前では version 列を使用する。","severity":"safe"},{"id":"alertlog-errors","group":"一般","title":"アラートログ内の最近の重大なエラー(ORA-)","command":"SELECT originating_timestamp, message_text FROM v$diag_alert_ext WHERE message_text LIKE '%ORA-%' AND originating_timestamp > SYSTIMESTAMP - INTERVAL '1' DAY ORDER BY originating_timestamp DESC FETCH FIRST 50 ROWS ONLY;","expect":"直近 24 時間で ORA- エラーが返されないことが望ましい。ORA-00600、ORA-07445、ORA-01578(ブロック破損)などのエントリは即時の対応が必要。","severity":"danger"},{"id":"invalid-objects","group":"一般","title":"INVALID オブジェクト","command":"SELECT owner, object_type, COUNT(*) AS invalid_count FROM dba_objects WHERE status = 'INVALID' GROUP BY owner, object_type ORDER BY invalid_count DESC;","expect":"理想的には INVALID オブジェクトは存在しないこと。存在する場合は EXEC DBMS_UTILITY.COMPILE_SCHEMA または utlrp.sql で再コンパイルする。SYS/SYSTEM 配下の無効なオブジェクトを優先する。","severity":"caution"},{"id":"tablespace-usage","group":"容量","title":"表領域の使用率","command":"SELECT df.tablespace_name, ROUND(df.total_mb, 1) AS total_mb, ROUND(df.total_mb - NVL(fs.free_mb, 0), 1) AS used_mb, ROUND((df.total_mb - NVL(fs.free_mb, 0)) / df.total_mb * 100, 1) AS pct_used FROM (SELECT tablespace_name, SUM(bytes)/1024/1024 total_mb FROM dba_data_files GROUP BY tablespace_name) df LEFT JOIN (SELECT tablespace_name, SUM(bytes)/1024/1024 free_mb FROM dba_free_space GROUP BY tablespace_name) fs ON df.tablespace_name = fs.tablespace_name ORDER BY pct_used DESC;","expect":"pct_used が 85% を超えると警告、90% を超えると重大のしきい値。autoextend が無効な表領域は満杯になるリスクが高い。データファイルを追加するか autoextend を有効にする。","severity":"danger"},{"id":"largest-segments","group":"容量","title":"最大のセグメント(テーブル/インデックス)","command":"SELECT owner, segment_name, segment_type, ROUND(bytes/1024/1024/1024, 2) AS size_gb FROM dba_segments ORDER BY bytes DESC FETCH FIRST 20 ROWS ONLY;","expect":"最も多くの領域を消費しているセグメントを示す。予期しない増加は、アーカイブ/パージやパーティショニングが必要であることを示している可能性がある。","severity":"safe"},{"id":"undo-temp-usage","group":"容量","title":"UNDO と TEMP 表領域の使用率","command":"SELECT ts.tablespace_name, ts.contents, ROUND(SUM(ss.used_blocks) * ts.block_size / 1024 / 1024, 1) AS used_mb FROM v$sort_segment ss JOIN (SELECT tablespace_name, contents, block_size FROM dba_tablespaces WHERE contents = 'TEMPORARY') ts ON ss.tablespace_name = ts.tablespace_name GROUP BY ts.tablespace_name, ts.contents, ts.block_size UNION ALL SELECT tablespace_name, 'UNDO', ROUND(SUM(bytes)/1024/1024, 1) FROM dba_undo_extents WHERE status = 'ACTIVE' GROUP BY tablespace_name;","expect":"TEMP の使用量が常に上限に達している場合は、大きなソート/ハッシュ操作がある。アクティブな UNDO 領域が保存期間を満たせない場合は、ORA-01555(snapshot too old)のリスクがある。","severity":"caution"},{"id":"sessions-vs-limit","group":"容量","title":"セッション数と上限","command":"SELECT resource_name, current_utilization, max_utilization, limit_value FROM v$resource_limit WHERE resource_name IN ('sessions','processes','transactions');","expect":"current_utilization が limit_value に近づくと(特に 85% 超)、新しい接続が拒否される場合がある。max_utilization は過去のピークを示す。processes パラメータを見直す。","severity":"caution"},{"id":"fra-usage","group":"容量","title":"フラッシュリカバリ領域(FRA)の使用率","command":"SELECT name, ROUND(space_limit/1024/1024/1024, 2) AS limit_gb, ROUND(space_used/1024/1024/1024, 2) AS used_gb, ROUND(space_used/space_limit*100, 1) AS pct_used FROM v$recovery_file_dest;","expect":"FRA が 85% に達するとアラートログに警告が書き込まれ、100% になるとアーカイブログの書き込みが停止してデータベースがハングする(archiver hung、ORA-00257)。RMAN のバックアップ/アーカイブを整理するか、db_recovery_file_dest_size を増やす。","severity":"danger"},{"id":"buffer-cache-hit","group":"パフォーマンス","title":"バッファキャッシュヒット率","command":"SELECT ROUND((1 - (phy.value - dir.value) / (con.value + cur.value)) * 100, 2) AS buffer_hit_ratio FROM v$sysstat con, v$sysstat cur, v$sysstat phy, v$sysstat dir WHERE con.name = 'consistent gets' AND cur.name = 'db block gets' AND phy.name = 'physical reads' AND dir.name = 'physical reads direct';","expect":"OLTP システムでは通常 90% 以上が期待される。継続的に低い値は、SGA/バッファキャッシュのサイズ不足や不適切なインデックス設計を示す可能性がある。単独ではなく待機イベントと合わせて解釈すること。","severity":"safe"},{"id":"top-sql","group":"パフォーマンス","title":"最も高コストな SQL 文(経過時間)","command":"SELECT sql_id, ROUND(elapsed_time/1000000, 1) AS elapsed_sec, executions, ROUND(elapsed_time/1000000/GREATEST(executions,1), 3) AS sec_per_exec, SUBSTR(sql_text, 1, 100) AS sql_text FROM v$sqlarea ORDER BY elapsed_time DESC FETCH FIRST 15 ROWS ONLY;","expect":"合計経過時間が最も長いクエリ。sec_per_exec が高いもの、または実行回数が非常に多いものがチューニング候補。AWR/SQL Tuning Advisor で調査する。","severity":"safe"},{"id":"long-active-sessions","group":"パフォーマンス","title":"長時間実行中のアクティブセッション","command":"SELECT s.sid, s.serial#, s.username, s.status, s.last_call_et AS active_seconds, s.event, SUBSTR(q.sql_text, 1, 80) AS sql_text FROM v$session s LEFT JOIN v$sqlarea q ON s.sql_id = q.sql_id WHERE s.status = 'ACTIVE' AND s.type = 'USER' AND s.last_call_et > 60 ORDER BY s.last_call_et DESC;","expect":"last_call_et(秒)が非常に大きいアクティブセッションは、停止しているか重いクエリを実行している可能性がある。event 列は待機しているリソースを示す。","severity":"caution"},{"id":"blocking-sessions","group":"パフォーマンス","title":"ブロックしているセッションと待機中のセッション(ロック)","command":"SELECT bs.sid AS blocker_sid, bs.username AS blocker_user, ws.sid AS waiter_sid, ws.username AS waiter_user, ws.seconds_in_wait, ws.event FROM v$session ws JOIN v$session bs ON ws.blocking_session = bs.sid WHERE ws.blocking_session IS NOT NULL ORDER BY ws.seconds_in_wait DESC;","expect":"行が返されないことが望ましい。ブロックしているセッションはアプリケーションの遅延/デッドロックを引き起こす。blocker_sid が長時間ロックを保持している(seconds_in_wait が大きい)場合は、アプリケーションチームと評価し、必要に応じて ALTER SYSTEM KILL SESSION を実行する。","severity":"danger"},{"id":"rman-last-backup","group":"バックアップとリカバリ","title":"最後に成功した RMAN バックアップの状態","command":"SELECT input_type, status, start_time, end_time, ROUND(output_bytes/1024/1024/1024, 2) AS output_gb FROM v$rman_backup_job_details ORDER BY start_time DESC FETCH FIRST 10 ROWS ONLY;","expect":"最新のバックアップは status = COMPLETED で、start_time が RPO ポリシーに対して十分新しい(例: 直近 24 時間以内)必要がある。FAILED または 'COMPLETED WITH WARNINGS' のエントリは調査が必要。","severity":"danger"},{"id":"archivelog-mode","group":"バックアップとリカバリ","title":"アーカイブログモードとアーカイバの状態","command":"SELECT log_mode, force_logging, (SELECT COUNT(*) FROM v$archived_log WHERE first_time > SYSDATE - 1) AS logs_last_24h FROM v$database;","expect":"本番データベースは log_mode = ARCHIVELOG である必要がある(そうでないとポイントインタイムリカバリができない)。直近 24 時間にアーカイブが生成されていない場合、アーカイバが停止している可能性がある。","severity":"danger"},{"id":"locked-expired-accounts","group":"セキュリティ","title":"ロック済みまたは期限切れのアカウント","command":"SELECT username, account_status, lock_date, expiry_date, profile FROM dba_users WHERE account_status != 'OPEN' ORDER BY username;","expect":"LOCKED/EXPIRED の重要なアプリケーションアカウントは予期しない停止を引き起こす。デフォルトのアカウント(SCOTT、HR など)がロック/無効化されているのは良い状態。EXPIRED(GRACE) はパスワードの期限切れが近いことを示す。","severity":"caution"},{"id":"privileged-users","group":"セキュリティ","title":"高権限ユーザー(DBA ロール)","command":"SELECT grantee, granted_role, admin_option FROM dba_role_privs WHERE granted_role IN ('DBA','PDB_DBA') AND grantee NOT IN ('SYS','SYSTEM') ORDER BY grantee;","expect":"DBA ロールは必要かつ既知のアカウントのみが保持すべき。予期しない被付与者や admin_option = YES のものは権限昇格のリスクとなるため、最小権限の原則に従って見直す。SYSDBA/SYSOPER 権限を持つアカウントも確認する: SELECT username, sysdba, sysoper FROM v$pwfile_users;","severity":"caution"},{"id":"default-password-users","group":"セキュリティ","title":"デフォルトパスワードが未変更のオープンアカウント","command":"SELECT du.username, du.account_status, du.profile, CASE WHEN dp.username IS NOT NULL THEN 'YES' ELSE 'NO' END AS has_default_password FROM dba_users du LEFT JOIN (SELECT username FROM dba_users_with_defpwd) dp ON du.username = dp.username WHERE du.account_status = 'OPEN' ORDER BY du.username;","expect":"has_default_password = YES のアカウントは、直ちにパスワードを変更するかロックする必要がある(ALTER USER ... ACCOUNT LOCK)。パスワードの有効期間ポリシーについては、DBA_PROFILES の PASSWORD_LIFE_TIME も確認する。","severity":"caution"},{"id":"dataguard-lag","group":"レプリケーション","title":"Data Guard スタンバイの遅延","command":"SELECT name, value, unit, time_computed FROM v$dataguard_stats WHERE name IN ('apply lag','transport lag');","expect":"apply lag と transport lag は可能な限り 0 に近いことが望ましい。分/時間単位の遅延はネットワークまたは MRP(Managed Recovery Process)の問題を示し、フェイルオーバー先が危険な状態にある。","severity":"danger"},{"id":"dataguard-mrp","group":"レプリケーション","title":"スタンバイ適用プロセス(MRP)の状態","command":"SELECT name, role, action, thread#, sequence#, block# FROM v$dataguard_process WHERE name LIKE 'MRP%' OR role LIKE 'RFS%' ORDER BY name;","expect":"フィジカルスタンバイでは、MRP0 プロセスが action APPLYING_LOG または WAIT_FOR_LOG で表示されるはず。MRP がなければ適用が停止しており、RFS がなければプライマリからログが届いていない。v$dataguard_process は 12.2+。12.1 以前では(現在は非推奨の)v$managed_standby(process、status 列)を使用する。","severity":"danger"}]},"health/postgres.json":{"engineId":"postgres","engine":"PostgreSQL","order":2,"checks":[{"id":"version-uptime","group":"一般","title":"バージョンと稼働時間","command":"SELECT version() AS pg_version, pg_postmaster_start_time() AS started_at, date_trunc('second', now() - pg_postmaster_start_time()) AS uptime;","expect":"バージョンと起動時刻を示す。稼働時間が予想外に短い(最近起動した)場合は、計画外の再起動またはクラッシュが発生した可能性があるため、ログを確認する。","severity":"safe"},{"id":"recent-errors","group":"一般","title":"チェックポイント統計","command":"-- PG17+:\nSELECT num_timed, num_requested, buffers_written, stats_reset FROM pg_stat_checkpointer;\n-- PG16 and earlier:\nSELECT checkpoints_timed, checkpoints_req, buffers_checkpoint, buffers_backend, stats_reset FROM pg_stat_bgwriter;","expect":"要求されたチェックポイント数(num_requested / checkpoints_req)が時間指定のもの(num_timed / checkpoints_timed)に比べて多い場合、WAL が速く埋まりすぎている。max_wal_size を増やす。PG17 ではカウンタが pg_stat_bgwriter から pg_stat_checkpointer に移動した。","severity":"caution"},{"id":"table-bloat","group":"一般","title":"肥大化したテーブルとデッドタプルの割合","command":"SELECT schemaname, relname, n_live_tup, n_dead_tup, CASE WHEN n_live_tup > 0 THEN round(n_dead_tup * 100.0 / n_live_tup, 1) ELSE 0 END AS dead_pct, last_autovacuum FROM pg_stat_user_tables WHERE n_dead_tup > 1000 ORDER BY n_dead_tup DESC LIMIT 20;","expect":"dead_pct が高い(例: 20% 超)テーブルは肥大化しており、VACUUM の性能とディスク使用量に影響する。last_autovacuum が非常に古い場合は、autovacuum の設定を見直すか、手動で VACUUM (ANALYZE) を実行する。","severity":"caution"},{"id":"database-size","group":"容量","title":"データベースのサイズ","command":"SELECT datname, pg_size_pretty(pg_database_size(datname)) AS size, pg_database_size(datname) AS size_bytes FROM pg_database WHERE datistemplate = false ORDER BY pg_database_size(datname) DESC;","expect":"データベースのサイズを示す。予期しない増加はディスク容量(df -h)と合わせて評価する。PostgreSQL はディスクが満杯になると書き込み操作を停止する。","severity":"danger"},{"id":"largest-tables","group":"容量","title":"最大のテーブル(インデックスを含む)","command":"SELECT schemaname, relname, pg_size_pretty(pg_total_relation_size(relid)) AS total_size, pg_size_pretty(pg_relation_size(relid)) AS table_size, pg_size_pretty(pg_total_relation_size(relid) - pg_relation_size(relid)) AS index_toast_size FROM pg_catalog.pg_statio_user_tables ORDER BY pg_total_relation_size(relid) DESC LIMIT 20;","expect":"最も多くの領域を占めるテーブルを示す。index_toast_size がテーブルサイズよりはるかに大きい場合は、過剰/未使用のインデックスがある可能性がある。アーカイブやパーティショニングを検討する。","severity":"safe"},{"id":"temp-files","group":"容量","title":"一時ファイルの使用状況","command":"SELECT datname, temp_files, pg_size_pretty(temp_bytes) AS temp_size, stats_reset FROM pg_stat_database WHERE temp_files > 0 ORDER BY temp_bytes DESC;","expect":"temp_files/temp_bytes が多い場合は、work_mem が不足しており、ソート/ハッシュ操作がディスクにあふれていることを示す。work_mem の増加またはクエリの最適化を検討する。","severity":"caution"},{"id":"connections-vs-limit","group":"容量","title":"接続数と max_connections","command":"SELECT (SELECT count(*) FROM pg_stat_activity WHERE backend_type = 'client backend') AS current_connections, (SELECT setting::int FROM pg_settings WHERE name = 'max_connections') AS max_connections, round((SELECT count(*) FROM pg_stat_activity WHERE backend_type = 'client backend') * 100.0 / (SELECT setting::int FROM pg_settings WHERE name = 'max_connections'), 1) AS pct_used;","expect":"クライアント接続のみをカウントする(pg_stat_activity にはバックグラウンドプロセスも含まれるため、backend_type = 'client backend' のフィルタが必要)。pct_used が 80% を超えると、新しい接続が拒否されるリスクがある(特に superuser_reserved_connections に達した場合)。コネクションプーラ(PgBouncer)が推奨される。","severity":"caution"},{"id":"wal-directory-size","group":"容量","title":"WAL ディレクトリのサイズとレプリケーションスロットの保持","command":"SELECT (SELECT count(*) FROM pg_ls_waldir()) AS wal_file_count, pg_size_pretty((SELECT sum(size) FROM pg_ls_waldir())) AS wal_total_size, slot_name, active, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal FROM pg_replication_slots ORDER BY slot_name;","expect":"非アクティブ(active = false)のレプリケーションスロットは WAL を蓄積させ、pg_wal ディレクトリを満杯にする。retained_wal が大きい場合は、スロットの所有者(slot_type、database、plugin)を確認する。active = false は一時的に切断されたスタンバイや、論理サブスクライバ/CDC(例: Debezium)のスロットを示す場合もある。本当に未使用であれば pg_drop_replication_slot で削除する。削除したスロットに依存していたスタンバイは再構築が必要で、サブスクライバ/CDC 側は再同期が必要。恒久的な保護には max_slot_wal_keep_size(PG13+)で上限を設定する。","severity":"danger"},{"id":"cache-hit-ratio","group":"パフォーマンス","title":"バッファキャッシュヒット率","command":"SELECT sum(heap_blks_read) AS heap_read, sum(heap_blks_hit) AS heap_hit, round(sum(heap_blks_hit) * 100.0 / NULLIF(sum(heap_blks_hit) + sum(heap_blks_read), 0), 2) AS cache_hit_ratio FROM pg_statio_user_tables;","expect":"OLTP ワークロードでは通常 99% 以上が目標。継続的に低い値は、shared_buffers が小さすぎるか、ワーキングセットがメモリに収まっていないことを示す可能性がある。","severity":"safe"},{"id":"top-queries","group":"パフォーマンス","title":"最も高コストなクエリ(pg_stat_statements)","command":"SELECT round(total_exec_time::numeric, 1) AS total_ms, calls, round(mean_exec_time::numeric, 2) AS mean_ms, round((100 * total_exec_time / sum(total_exec_time) OVER ())::numeric, 1) AS pct, left(query, 100) AS query FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 15;","expect":"pg_stat_statements は shared_preload_libraries に含め(再起動が必要)、データベースにインストールする必要がある(CREATE EXTENSION pg_stat_statements)。total_exec_time/mean_exec_time の名前は PG13+ のもので、PG12 では total_time/mean_time を使用する。合計時間を最も消費しているクエリがチューニング候補。mean_ms が大きいものには EXPLAIN ANALYZE を実行する。","severity":"safe"},{"id":"long-running-queries","group":"パフォーマンス","title":"長時間実行中のアクティブなクエリ","command":"SELECT pid, usename, state, now() - query_start AS duration, wait_event_type, wait_event, left(query, 80) AS query FROM pg_stat_activity WHERE state = 'active' AND now() - query_start > interval '1 minute' AND backend_type = 'client backend' ORDER BY duration DESC;","expect":"1 分を超えて実行中のアクティブなクエリは、停止しているか重い可能性がある。wait_event は待機している対象を示す。このクエリはアクティブなクエリのみを一覧表示する。'idle in transaction' セッション(VACUUM によるデッドタプルの除去を妨げる)は、state = 'idle in transaction' と xact_start で別途確認する。","severity":"caution"},{"id":"blocking-locks","group":"パフォーマンス","title":"ブロックしているセッションと待機中のロック","command":"SELECT blocked.pid AS blocked_pid, blocked.usename AS blocked_user, blocking.pid AS blocking_pid, blocking.usename AS blocking_user, now() - blocked.query_start AS blocked_duration, left(blocked.query, 60) AS blocked_query FROM pg_stat_activity blocked JOIN pg_stat_activity blocking ON blocking.pid = ANY(pg_blocking_pids(blocked.pid)) WHERE cardinality(pg_blocking_pids(blocked.pid)) > 0;","expect":"行が返されないことが望ましい。ブロックしているセッション(blocking_pid)はアプリケーションの遅延とタイムアウトを引き起こす。長時間ブロックしているトランザクションを調査し、必要に応じて pg_terminate_backend で終了する。","severity":"danger"},{"id":"archiver-status","group":"バックアップとリカバリ","title":"WAL アーカイブの健全性(pg_stat_archiver)","command":"SELECT archived_count, last_archived_wal, last_archived_time, failed_count, last_failed_wal, last_failed_time, now() - last_archived_time AS since_last_archive FROM pg_stat_archiver;","expect":"failed_count は 0 で、last_failed_time は last_archived_time より古いことが望ましい。since_last_archive が非常に大きい場合はアーカイブが停止しており(archive_command の失敗)、PITR のバックアップチェーンが途切れている。","severity":"danger"},{"id":"last-basebackup","group":"バックアップとリカバリ","title":"最終バックアップと WAL アーカイブの鮮度","command":"-- Base backup time is not stored in the database; read it from the backup tool: pgbackrest info / barman list-backup <server>\nSELECT pg_is_in_recovery() AS in_recovery, last_archived_wal, last_archived_time, now() - last_archived_time AS since_last_archive, failed_count, last_failed_time FROM pg_stat_archiver;","expect":"最後のベースバックアップの時刻をバックアップツール(pgBackRest / Barman / pg_basebackup のジョブログ)で確認する。RPO ポリシーに対して十分新しい必要がある。PITR には WAL アーカイブも連続している必要がある。since_last_archive が大きいか failed_count が増加している場合、アーカイブチェーンが途切れている可能性がある。","severity":"danger"},{"id":"locked-expired-roles","group":"セキュリティ","title":"期限切れまたは期限切れ間近のログインロール","command":"SELECT rolname, rolcanlogin, rolvaliduntil, rolconnlimit FROM pg_roles WHERE rolcanlogin = true AND (rolvaliduntil IS NOT NULL AND rolvaliduntil < now() + interval '7 days') ORDER BY rolvaliduntil;","expect":"rolvaliduntil を過ぎたアプリケーションロールはログインがブロックされ、停止を引き起こす。今後 7 日以内に期限切れとなるパスワードは、事前に更新を計画する。","severity":"caution"},{"id":"superuser-roles","group":"セキュリティ","title":"高権限ロール(SUPERUSER / 作成権限)","command":"SELECT rolname, rolsuper, rolcreaterole, rolcreatedb, rolbypassrls FROM pg_roles WHERE rolsuper = true OR rolcreaterole = true OR rolbypassrls = true ORDER BY rolsuper DESC, rolname;","expect":"SUPERUSER は必要かつ既知のアカウントにのみ存在すべき。rolbypassrls = true のロールは行レベルセキュリティ(RLS)を回避する。予期しない高権限は最小権限の原則に従って取り消す。","severity":"caution"},{"id":"hba-trust-auth","group":"セキュリティ","title":"脆弱な認証(trust)ルール","command":"SELECT type, database, user_name, address, auth_method FROM pg_hba_file_rules WHERE auth_method IN ('trust','password') ORDER BY line_number;","expect":"auth_method = trust はパスワードなしのアクセスを許可し、本番環境では危険。'password' はパスワードを平文で送信する。scram-sha-256 に置き換える。(PG 10+ が必要。)","severity":"danger"},{"id":"replication-lag","group":"レプリケーション","title":"ストリーミングレプリケーションの遅延(プライマリ側)","command":"SELECT client_addr, state, sync_state, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), sent_lsn)) AS sent_lag, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn)) AS replay_lag, write_lag, flush_lag, replay_lag AS replay_time_lag FROM pg_stat_replication ORDER BY client_addr;","expect":"プライマリで実行する。state は streaming で、replay_lag(バイト/時間)は小さいことが望ましい。スタンバイがまったく表示されない場合は接続が切れている。sync_state = async の場合、同期レプリケーションが想定どおりに機能していない。","severity":"danger"},{"id":"replica-lag-standby","group":"レプリケーション","title":"レプリケーションの遅延(スタンバイ側)","command":"SELECT pg_is_in_recovery() AS in_recovery, CASE WHEN pg_is_in_recovery() THEN date_trunc('second', now() - pg_last_xact_replay_timestamp()) ELSE NULL END AS replication_delay, pg_last_wal_receive_lsn() AS receive_lsn, pg_last_wal_replay_lsn() AS replay_lsn;","expect":"スタンバイサーバーで実行する。in_recovery は true であるべき。replication_delay が分/時間の範囲であれば適用の遅延がある可能性がある。ただし、プライマリで書き込みがない場合もこの値は増加する(誤検知)ため、LSN の差と合わせて解釈する。receive_lsn と replay_lsn の差が大きい場合は、WAL の再生が追いついていない。","severity":"danger"}]},"health/mysql.json":{"engineId":"mysql","engine":"MySQL","order":3,"checks":[{"id":"version-uptime","group":"一般","title":"バージョンと稼働時間","command":"SELECT VERSION() AS mysql_version, VARIABLE_VALUE AS uptime_seconds, ROUND(VARIABLE_VALUE/86400, 2) AS uptime_days FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Uptime';","expect":"バージョンと稼働時間(秒)を示す。uptime_seconds が予想外に小さい場合は、計画外の再起動またはクラッシュが発生した可能性があるため、エラーログを確認する。","severity":"safe"},{"id":"error-log-status","group":"一般","title":"最近のエラーログのエントリ(performance_schema)","command":"SELECT logged, prio, error_code, subsystem, LEFT(data, 120) AS message FROM performance_schema.error_log WHERE prio IN ('Error','Warning') ORDER BY logged DESC LIMIT 30;","expect":"最近のエラーと警告を示す(MySQL 8.0+ が必要)。prio = 'Error' のエントリ(特に InnoDB、ロック、ディスクのエラー)を調査する。古いバージョンでは、サーバーの log_error ファイルを確認する。","severity":"danger"},{"id":"crashed-tables","group":"一般","title":"破損したテーブル/確認対象のテーブル","command":"SELECT table_schema, table_name, engine, table_rows, update_time FROM information_schema.tables WHERE table_schema NOT IN ('mysql','information_schema','performance_schema','sys') AND engine IS NOT NULL ORDER BY table_schema, table_name;","expect":"各テーブルのエンジンと最終更新時刻を一覧表示する。MyISAM テーブルはクラッシュすることがある。疑わしい場合は CHECK TABLE ... または mysqlcheck で整合性を検証する。重要なデータには InnoDB が推奨される。","severity":"caution"},{"id":"schema-sizes","group":"容量","title":"スキーマ(データベース)のサイズ","command":"SELECT table_schema, ROUND(SUM(data_length + index_length)/1024/1024, 1) AS size_mb, ROUND(SUM(data_free)/1024/1024, 1) AS free_mb FROM information_schema.tables GROUP BY table_schema ORDER BY SUM(data_length + index_length) DESC;","expect":"スキーマのサイズと再利用可能な data_free 領域を示す。ディスク容量と合わせて評価する。free_mb が大きい場合は OPTIMIZE TABLE で領域を回収できる。","severity":"danger"},{"id":"largest-tables","group":"容量","title":"最大のテーブル(data_free / 断片化を含む)","command":"SELECT table_schema, table_name, engine, ROUND((data_length + index_length)/1024/1024, 1) AS total_mb, ROUND(data_free/1024/1024, 1) AS data_free_mb, table_rows FROM information_schema.tables WHERE table_schema NOT IN ('mysql','information_schema','performance_schema','sys') ORDER BY (data_length + index_length) DESC LIMIT 20;","expect":"最大のテーブルを示す。data_free_mb が大きいテーブルは断片化しており、OPTIMIZE TABLE で領域を回収できる。非常に大きなテーブルにはパーティショニングを検討する。","severity":"safe"},{"id":"innodb-tablespace","group":"容量","title":"InnoDB 表領域と一時領域の使用状況","command":"SELECT FILE_NAME, TABLESPACE_NAME, ROUND(TOTAL_EXTENTS * EXTENT_SIZE / 1024 / 1024, 1) AS total_mb, ROUND((TOTAL_EXTENTS - FREE_EXTENTS) * EXTENT_SIZE / 1024 / 1024, 1) AS used_mb FROM information_schema.files WHERE FILE_TYPE = 'TABLESPACE' ORDER BY TOTAL_EXTENTS DESC LIMIT 20;","expect":"InnoDB のデータファイルの使用率を示す。innodb_file_per_table が無効の場合、ibdata1 は増え続け、縮小しない。一時表領域の肥大化については、SHOW ENGINE INNODB STATUS の出力も確認する。","severity":"caution"},{"id":"connections-vs-limit","group":"容量","title":"接続数と max_connections の上限","command":"SELECT (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Threads_connected') AS connected, (SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'max_connections') AS max_connections, (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Max_used_connections') AS max_used, (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Aborted_connects') AS aborted_connects;","expect":"max_used が max_connections に近づく(85% 超)と、'Too many connections' エラーのリスクがある。aborted_connects が多い場合は認証/ネットワークの問題を示す。コネクションプールを使用する。","severity":"caution"},{"id":"binlog-size","group":"容量","title":"バイナリログファイルと合計サイズ","command":"SHOW BINARY LOGS;","expect":"binlog ファイルとそのサイズを一覧表示する。合計サイズがディスク領域を圧迫している場合は binlog_expire_logs_seconds を見直す(8.0 より前は expire_logs_days。この変数は 8.0 で非推奨となり 8.4 で削除)。レプリケーションを使用している場合は、レプリカが読み取る前にパージしないこと。","severity":"caution"},{"id":"buffer-pool-hit","group":"パフォーマンス","title":"InnoDB バッファプールのヒット率","command":"SELECT (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests') AS read_requests, (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads') AS disk_reads, ROUND((1 - (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads') / (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests')) * 100, 3) AS hit_ratio_pct;","expect":"hit_ratio_pct は通常 99% 以上が目標。低いままの場合は innodb_buffer_pool_size が不足している。専用サーバーでは RAM の約 70-80% まで(共有サーバーではそれ以下)増やすことを検討する。","severity":"safe"},{"id":"top-queries","group":"パフォーマンス","title":"最も高コストなクエリ(sys.statement_analysis)","command":"SELECT query, db, exec_count, total_latency, avg_latency, rows_sent_avg, rows_examined_avg FROM sys.statement_analysis ORDER BY total_latency DESC LIMIT 15;","expect":"sys スキーマと performance_schema が有効である必要がある。total_latency を最も消費しているクエリがチューニング候補。rows_examined_avg が rows_sent_avg よりはるかに大きい場合はインデックスが不足しているため、EXPLAIN で調査する。","severity":"safe"},{"id":"long-running-queries","group":"パフォーマンス","title":"長時間実行中のアクティブなクエリ","command":"SELECT id, user, host, db, command, time AS seconds, state, LEFT(info, 80) AS query FROM information_schema.processlist WHERE command != 'Sleep' AND time > 60 ORDER BY time DESC;","expect":"60 秒を超えて実行中のクエリは、停止しているか重い可能性がある。state 列は待機している対象を示す。'Sleep' 状態の長いセッションもコネクションプールを枯渇させる。必要に応じて KILL <id> を使用する。","severity":"caution"},{"id":"blocking-locks","group":"パフォーマンス","title":"ブロックしているセッションと待機中のロック","command":"SELECT r.trx_id AS waiting_trx, r.trx_mysql_thread_id AS waiting_thread, TIMESTAMPDIFF(SECOND, r.trx_wait_started, NOW()) AS wait_seconds, LEFT(r.trx_query, 60) AS waiting_query, b.trx_mysql_thread_id AS blocking_thread, LEFT(b.trx_query, 60) AS blocking_query FROM performance_schema.data_lock_waits w JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_engine_transaction_id JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_engine_transaction_id ORDER BY wait_seconds DESC;","expect":"行が返されないことが望ましい。ブロックしているトランザクション(blocking_thread)は、アプリケーションの遅延と lock wait timeout エラーを引き起こす。長時間ブロックしているトランザクションを調査し、必要に応じて KILL で終了する。(MySQL 8.0 の構文。)","severity":"danger"},{"id":"binlog-enabled","group":"バックアップとリカバリ","title":"バイナリログとリカバリの設定","command":"SELECT (SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'log_bin') AS log_bin, (SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'binlog_format') AS binlog_format, (SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'sync_binlog') AS sync_binlog, (SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'innodb_flush_log_at_trx_commit') AS flush_log_commit;","expect":"ポイントインタイムリカバリには log_bin が ON である必要がある。永続性のために sync_binlog = 1 と innodb_flush_log_at_trx_commit = 1 が推奨される(そうでないとクラッシュ時にトランザクションが失われる可能性がある)。レプリケーションには binlog_format = ROW が最も安全。","severity":"danger"},{"id":"last-backup-note","group":"バックアップとリカバリ","title":"最終バックアップ時刻(binlog / ツールの指標)","command":"SELECT (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Uptime') AS uptime_seconds, (SELECT MAX(update_time) FROM information_schema.tables WHERE table_schema NOT IN ('mysql','information_schema','performance_schema','sys')) AS last_data_change;","expect":"MySQL はバックアップの状態を自ら追跡しない。最後に成功したバックアップの時刻を mysqldump / MySQL Shell dump / Percona XtraBackup ツールのログで確認する(mysqlpump は 8.0.34 で非推奨となり 8.4 で削除)。バックアップは RPO ポリシーが要求する鮮度(例: 直近 24 時間以内)である必要がある。","severity":"danger"},{"id":"locked-expired-accounts","group":"セキュリティ","title":"ロック済みまたはパスワードが期限切れのアカウント","command":"SELECT user, host, account_locked, password_expired, password_lifetime FROM mysql.user ORDER BY user, host;","expect":"account_locked = 'Y' または password_expired = 'Y' の重要なアプリケーションアカウントは停止を引き起こす。password_lifetime が NULL でグローバルな期限設定が無効の場合、パスワードは期限切れにならない。これはポリシー上の抜けである可能性がある。","severity":"caution"},{"id":"anonymous-nopassword-users","group":"セキュリティ","title":"匿名ユーザーとパスワードのないユーザー","command":"SELECT user, host, plugin, IF(authentication_string = '', 'EMPTY_PASSWORD', 'set') AS password_status FROM mysql.user WHERE user = '' OR authentication_string = '' ORDER BY host;","expect":"行が返されないことが望ましい。匿名ユーザー(user = '')とパスワードのないアカウントは重大なセキュリティホール。mysql_secure_installation で削除するか、強力なパスワードを設定する。","severity":"danger"},{"id":"super-privilege-users","group":"セキュリティ","title":"高権限(SUPER / GRANT)ユーザー","command":"SELECT grantee, privilege_type FROM information_schema.user_privileges WHERE privilege_type IN ('SUPER','GRANT OPTION','SHUTDOWN','FILE','CREATE USER') ORDER BY grantee, privilege_type;","expect":"SUPER、FILE、GRANT OPTION などの権限は、必要かつ既知のアカウントにのみ存在すべき。予期しない被付与者は権限昇格のリスクとなる。% (任意のホスト)で定義された高権限アカウントには特に注意する。","severity":"caution"},{"id":"replica-status","group":"レプリケーション","title":"レプリカ(スタンバイ)の状態と遅延","command":"SHOW REPLICA STATUS;","expect":"レプリカで実行する(MySQL 8.0.22+)。Replica_IO_Running と Replica_SQL_Running は両方とも 'Yes' である必要がある。Seconds_Behind_Source は小さいことが望ましく、NULL の場合はレプリケーションが停止している。Last_Error フィールドを確認する。(古いバージョンでは SHOW SLAVE STATUS。)","severity":"danger"},{"id":"replication-threads","group":"レプリケーション","title":"レプリケーションの接続とアプライヤの状態(performance_schema)","command":"SELECT c.channel_name, c.service_state AS io_state, a.service_state AS sql_state, c.last_error_message AS io_error, w.last_error_message AS sql_error FROM performance_schema.replication_connection_status c JOIN performance_schema.replication_applier_status a ON c.channel_name = a.channel_name LEFT JOIN performance_schema.replication_applier_status_by_coordinator w ON w.channel_name = a.channel_name;","expect":"io_state と sql_state は 'ON' である必要がある。io_error/sql_error に値がある場合は、レプリケーションが失敗して停止している。マルチソース構成では、各 channel_name が個別に正常である必要がある。","severity":"danger"}]},"health/mssql.json":{"engineId":"mssql","engine":"SQL Server","order":4,"checks":[{"id":"version-uptime","group":"一般","title":"バージョンと稼働時間","command":"SELECT @@VERSION AS version, sqlserver_start_time AS start_time, DATEDIFF(HOUR, sqlserver_start_time, GETDATE()) AS uptime_hours FROM sys.dm_os_sys_info;","expect":"バージョンとパッチレベルを確認する。稼働時間が非常に短い(数時間未満)場合は、予期しない再起動が発生した可能性があるため、SQL Server のエラーログを確認する。","severity":"safe"},{"id":"database-states","group":"一般","title":"問題のある状態のデータベース(SUSPECT / RECOVERY_PENDING)","command":"SELECT name AS database_name, state_desc AS state, recovery_model_desc AS recovery_model FROM sys.databases WHERE state_desc <> N'ONLINE' ORDER BY name;","expect":"すべての本番データベースは ONLINE である必要がある。SUSPECT、RECOVERY_PENDING、EMERGENCY は即時の対応が必要。リカバリを開始し、エラーログを確認する。","severity":"danger"},{"id":"recent-errors","group":"一般","title":"最近の重要なエラー(メモリ/エラーのリングバッファ)","command":"SELECT TOP 20 CAST(record AS XML).value('(//Record/@id)[1]', 'int') AS record_id, DATEADD(ms, timestamp - (SELECT ms_ticks FROM sys.dm_os_sys_info), GETDATE()) AS event_time, CAST(record AS XML) AS record_xml FROM sys.dm_os_ring_buffers WHERE ring_buffer_type = N'RING_BUFFER_EXCEPTION' ORDER BY timestamp DESC;","expect":"最近の例外/エラーの記録を確認する。頻繁に繰り返される 823/824/825(I/O 整合性)エラーはディスクの破損を示す。詳細については、xp_readerrorlog でサーバー上のエラーログも読む。","severity":"caution"},{"id":"data-log-file-usage","group":"容量","title":"データファイルとログファイルの使用状況","command":"SELECT DB_NAME() AS database_name, name AS logical_name, type_desc AS file_type, size/128.0 AS allocated_mb, CAST(FILEPROPERTY(name, 'SpaceUsed') AS INT)/128.0 AS used_mb, (size - CAST(FILEPROPERTY(name, 'SpaceUsed') AS INT))/128.0 AS free_mb, CASE WHEN max_size = -1 THEN N'Unlimited' WHEN max_size = 268435456 THEN N'2 TB (log)' ELSE CAST(max_size/128 AS VARCHAR(20)) + N' MB' END AS max_size_limit FROM sys.database_files;","expect":"各データベースで実行する。使用領域が割り当て領域に非常に近く(85% 以上)、自動拡張に上限がある場合は、拡張を計画するかディスクを追加する。ログファイルが常に満杯の場合は、バックアップ/復旧モデルの設定を見直す。","severity":"caution"},{"id":"largest-tables","group":"容量","title":"最大のテーブル(サイズと行数)","command":"SELECT TOP 20 s.name AS schema_name, t.name AS table_name, p.rows AS row_count, SUM(a.total_pages)*8/1024 AS total_mb, SUM(a.used_pages)*8/1024 AS used_mb FROM sys.tables t JOIN sys.schemas s ON t.schema_id = s.schema_id JOIN sys.indexes i ON t.object_id = i.object_id JOIN sys.partitions p ON i.object_id = p.object_id AND i.index_id = p.index_id JOIN sys.allocation_units a ON p.partition_id = a.container_id WHERE i.index_id <= 1 GROUP BY s.name, t.name, p.rows ORDER BY total_mb DESC;","expect":"最も多くの領域を消費しているテーブルを特定する。予期しない増加は、アーカイブ、インデックスメンテナンス、またはパーティショニングが必要であることを示している可能性がある。","severity":"safe"},{"id":"tempdb-usage","group":"容量","title":"tempdb の領域使用状況","command":"SELECT SUM(user_object_reserved_page_count)*8/1024 AS user_objects_mb, SUM(internal_object_reserved_page_count)*8/1024 AS internal_objects_mb, SUM(version_store_reserved_page_count)*8/1024 AS version_store_mb, SUM(unallocated_extent_page_count)*8/1024 AS free_mb FROM sys.dm_db_file_space_usage;","expect":"tempdb の空き領域が尽きかけている(unallocated が少ない)場合、クエリが失敗する可能性がある。バージョンストアが増え続けている場合は、長時間オープン中のトランザクションがある。sys.dm_tran_active_snapshot_database_transactions で調査する。","severity":"caution"},{"id":"connection-count","group":"容量","title":"接続数と分布","command":"SELECT DB_NAME(dbid) AS database_name, COUNT(*) AS connection_count, SUM(CASE WHEN status = 'running' THEN 1 ELSE 0 END) AS active FROM sys.sysprocesses WHERE dbid > 0 GROUP BY dbid ORDER BY connection_count DESC;","expect":"アプリケーション/データベースごとの接続数を追跡する。単一のアプリケーションからの異常に多い接続は、コネクションプールのリークを示す可能性がある。最大ワーカースレッド数の上限に近づかないようにする。","severity":"safe"},{"id":"vlf-count","group":"容量","title":"ログファイルの VLF 数(断片化)","command":"SELECT DB_NAME(database_id) AS database_name, COUNT(*) AS vlf_count FROM sys.dm_db_log_info(DB_ID()) GROUP BY database_id;","expect":"VLF 数が多い(数百を超える、例: 500+)場合、ログファイルが非常に小さな単位で拡張されたことを意味する。これはリカバリとバックアップの性能を低下させる。ログを縮小し、一度に大きく再拡張する。","severity":"caution"},{"id":"buffer-cache-ple","group":"パフォーマンス","title":"Buffer Cache Hit Ratio と Page Life Expectancy","command":"SELECT (SELECT cntr_value FROM sys.dm_os_performance_counters WHERE counter_name = 'Buffer cache hit ratio') AS hit_ratio_raw, (SELECT cntr_value FROM sys.dm_os_performance_counters WHERE counter_name = 'Buffer cache hit ratio base') AS hit_ratio_base, (SELECT cntr_value FROM sys.dm_os_performance_counters WHERE counter_name = 'Page life expectancy' AND object_name LIKE '%Buffer Manager%') AS page_life_expectancy_sec;","expect":"バッファキャッシュヒット率は理想的には 99% 以上(hit_ratio_raw / hit_ratio_base)。Page Life Expectancy が継続的に低い場合(経験則: NUMA ノードあたり 4 GB ごとに 300 s 未満)、メモリ圧迫がある。RAM の追加またはクエリの最適化が必要。","severity":"caution"},{"id":"expensive-queries","group":"パフォーマンス","title":"最も高コストなクエリ(CPU と読み取り)","command":"SELECT TOP 15 qs.total_worker_time/1000 AS total_cpu_ms, qs.execution_count AS execution_count, qs.total_logical_reads AS total_logical_reads, qs.total_worker_time/qs.execution_count/1000 AS avg_cpu_ms, SUBSTRING(st.text, (qs.statement_start_offset/2)+1, ((CASE qs.statement_end_offset WHEN -1 THEN DATALENGTH(st.text) ELSE qs.statement_end_offset END - qs.statement_start_offset)/2)+1) AS query_text FROM sys.dm_exec_query_stats qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st ORDER BY qs.total_worker_time DESC;","expect":"CPU と論理読み取りで最も高コストなクエリを特定する。読み取りが多いクエリはインデックス不足の兆候。実行計画を確認し、インデックスを追加するかクエリを書き直す。","severity":"safe"},{"id":"blocking-sessions","group":"パフォーマンス","title":"ブロックしているセッション","command":"SELECT r.session_id AS blocked_session, r.blocking_session_id AS blocking_session, r.wait_type AS wait_type, r.wait_time/1000 AS wait_sec, r.status AS status, t.text AS query FROM sys.dm_exec_requests r CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t WHERE r.blocking_session_id <> 0 ORDER BY r.wait_time DESC;","expect":"ブロックしているセッション(blocking_session_id <> 0)は、クエリが互いに待機させていることを意味する。長時間のブロッキングはアプリケーションのタイムアウトを引き起こす。先頭のブロッカーを特定し、長いトランザクションの終了を検討する。","severity":"danger"},{"id":"wait-stats","group":"パフォーマンス","title":"上位の待機統計(wait stats)","command":"SELECT TOP 15 wait_type AS wait_type, waiting_tasks_count AS waiting_tasks, wait_time_ms/1000 AS total_wait_sec, (wait_time_ms - signal_wait_time_ms)/1000 AS resource_wait_sec, signal_wait_time_ms/1000 AS cpu_wait_sec FROM sys.dm_os_wait_stats WHERE wait_type NOT IN (N'CLR_SEMAPHORE', N'CLR_AUTO_EVENT', N'CLR_MANUAL_EVENT', N'LAZYWRITER_SLEEP', N'SQLTRACE_BUFFER_FLUSH', N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP', N'WAITFOR', N'BROKER_TASK_STOP', N'BROKER_EVENTHANDLER', N'BROKER_RECEIVE_WAITFOR', N'BROKER_TRANSMITTER', N'CHECKPOINT_QUEUE', N'CHKPT', N'REQUEST_FOR_DEADLOCK_SEARCH', N'XE_TIMER_EVENT', N'XE_DISPATCHER_WAIT', N'XE_LIVE_TARGET_TVF', N'BROKER_TO_FLUSH', N'DISPATCHER_QUEUE_SEMAPHORE', N'HADR_FILESTREAM_IOMGR_IOCOMPLETION', N'HADR_WORK_QUEUE', N'HADR_TIMER_TASK', N'HADR_CLUSAPI_CALL', N'HADR_LOGCAPTURE_WAIT', N'HADR_NOTIFICATION_DEQUEUE', N'DIRTY_PAGE_POLL', N'SP_SERVER_DIAGNOSTICS_SLEEP', N'SOS_WORK_DISPATCHER', N'LOGMGR_QUEUE', N'ONDEMAND_TASK_QUEUE', N'FT_IFTS_SCHEDULER_IDLE_WAIT', N'PWAIT_EXTENSIBILITY_CLEANUP_TASK', N'PWAIT_ALL_COMPONENTS_INITIALIZED', N'STARTUP_DEPENDENCY_MANAGER', N'PREEMPTIVE_XE_DISPATCHER', N'PVS_PREALLOCATE', N'WAIT_XTP_OFFLINE_CKPT_NEW_LOG', N'WAIT_XTP_CKPT_CLOSE', N'WAIT_XTP_HOST_WAIT', N'PARALLEL_REDO_DRAIN_WORKER', N'PARALLEL_REDO_LOG_CACHE', N'PARALLEL_REDO_TRAN_LIST', N'PARALLEL_REDO_WORKER_SYNC', N'PARALLEL_REDO_WORKER_WAIT_WORK') AND wait_type NOT LIKE N'SLEEP[_]%' AND wait_type NOT LIKE N'QDS[_]%' AND waiting_tasks_count > 0 ORDER BY wait_time_ms DESC;","expect":"支配的な待機タイプを解釈する: PAGEIOLATCH = ディスク I/O のボトルネック、CXPACKET/CXCONSUMER = 並列処理、LCK_M = ロック、WRITELOG = ログディスク、RESOURCE_SEMAPHORE = メモリ。シグナル待機の割合が高い場合は CPU の圧迫を示す。","severity":"safe"},{"id":"last-backup","group":"バックアップとリカバリ","title":"最終バックアップ時刻(完全 / 差分 / ログ)","command":"SELECT d.name AS database_name, d.recovery_model_desc AS recovery_model, MAX(CASE WHEN b.type = 'D' THEN b.backup_finish_date END) AS last_full_backup, MAX(CASE WHEN b.type = 'I' THEN b.backup_finish_date END) AS last_differential, MAX(CASE WHEN b.type = 'L' THEN b.backup_finish_date END) AS last_log_backup FROM sys.databases d LEFT JOIN msdb.dbo.backupset b ON d.name = b.database_name WHERE d.database_id > 4 GROUP BY d.name, d.recovery_model_desc ORDER BY last_full_backup;","expect":"すべての本番データベースには最近の完全バックアップが必要。last_full_backup が NULL または非常に古い(RPO を超える)場合は、バックアップジョブが失敗している。FULL 復旧モデルでは、ログバックアップがないとログファイルが増え続ける。","severity":"danger"},{"id":"recovery-model","group":"バックアップとリカバリ","title":"復旧モデルの一貫性","command":"SELECT name AS database_name, recovery_model_desc AS recovery_model, log_reuse_wait_desc AS log_reuse_wait FROM sys.databases WHERE database_id > 4 ORDER BY name;","expect":"重要なデータベースは、ポイントインタイムリカバリのために FULL を使用する必要がある。log_reuse_wait_desc = LOG_BACKUP はログバックアップが保留中であることを意味し、ACTIVE_TRANSACTION は長時間実行中のトランザクションを示す。","severity":"caution"},{"id":"sysadmin-members","group":"セキュリティ","title":"sysadmin ロールのメンバー","command":"SELECT p.name AS login_name, p.type_desc AS type, p.is_disabled AS disabled FROM sys.server_role_members rm JOIN sys.server_principals r ON rm.role_principal_id = r.principal_id JOIN sys.server_principals p ON rm.member_principal_id = p.principal_id WHERE r.name = N'sysadmin' ORDER BY p.name;","expect":"sysadmin のメンバーシップは最小限にする必要がある。予期しないログイン(特にアプリケーションアカウントや個人ユーザー)は権限昇格のリスクとなる。最小権限の原則を適用する。","severity":"danger"},{"id":"sa-and-password-policy","group":"セキュリティ","title":"sa アカウントとパスワードポリシーが無効なログイン","command":"SELECT name AS login_name, is_disabled AS disabled, is_policy_checked AS password_policy_on, is_expiration_checked AS expiration_check, LOGINPROPERTY(name, 'PasswordLastSetTime') AS last_password_change FROM sys.sql_logins WHERE is_policy_checked = 0 OR name = N'sa' ORDER BY name;","expect":"sa アカウントは無効化するか名前を変更すべき。is_policy_checked = 0 の SQL ログインは脆弱/古いパスワードのリスクを伴う。パスワードポリシー(CHECK_POLICY)を有効にする。","severity":"caution"},{"id":"alwayson-sync","group":"レプリケーション","title":"Always On の同期状態とキュー","command":"SELECT ag.name AS availability_group, ar.replica_server_name AS replica_server, DB_NAME(drs.database_id) AS database_name, drs.synchronization_state_desc AS sync_state, drs.synchronization_health_desc AS health, drs.log_send_queue_size AS log_send_queue_kb, drs.redo_queue_size AS redo_queue_kb FROM sys.dm_hadr_database_replica_states drs JOIN sys.availability_replicas ar ON drs.replica_id = ar.replica_id JOIN sys.availability_groups ag ON ar.group_id = ag.group_id ORDER BY ag.name, replica_server;","expect":"synchronization_state_desc は SYNCHRONIZED(同期)または SYNCHRONIZING(非同期)で、synchronization_health は HEALTHY であることが望ましい。log_send_queue または redo_queue が増加している場合、レプリカが遅れており、フェイルオーバー時のデータ損失/RTO のリスクが高まる。","severity":"caution"}]},"health/mongodb.json":{"engineId":"mongodb","engine":"MongoDB","order":5,"checks":[{"id":"version-uptime","group":"一般","title":"バージョンと稼働時間","command":"db.serverStatus().version; db.serverStatus().uptime","expect":"バージョンがサポート対象でパッチ適用済みであることを確認する。uptime は秒単位。非常に小さい(数千秒)場合は予期しない再起動が発生しているため、mongod のログを確認する。","severity":"safe"},{"id":"replset-status","group":"一般","title":"レプリカセットのメンバーの状態(health)","command":"rs.status().members.forEach(function(m) { print(m.name + \" | \" + m.stateStr + \" | health=\" + m.health); })","expect":"すべてのメンバーが health=1 で、PRIMARY がちょうど 1 つ存在する必要がある。health=0 または(not reachable/healthy)、DOWN、RECOVERING の状態は障害を示す。PRIMARY が複数ある場合や存在しない場合は、選出に問題がある。","severity":"danger"},{"id":"dbstats-sizes","group":"容量","title":"データベースのサイズ(データ / ストレージ / インデックス)","command":"db.stats(1024*1024)","expect":"dataSize、storageSize、indexSize(MB)を監視する。storageSize が dataSize よりはるかに大きい場合は断片化の可能性がある。indexSize を RAM(WiredTiger キャッシュ)内に収めることがパフォーマンスにとって重要。","severity":"safe"},{"id":"disk-space","group":"容量","title":"ディスク領域の使用状況(fsUsedSize / fsTotalSize)","command":"var st = db.stats(); printjson({fsUsedSize_MB: (st.fsUsedSize/1048576).toFixed(0), fsTotalSize_MB: (st.fsTotalSize/1048576).toFixed(0), usedPct: (100*st.fsUsedSize/st.fsTotalSize).toFixed(1)})","expect":"fsUsedSize の fsTotalSize に対する比率が 85% を超えると、ディスクが満杯に近づいている。MongoDB はディスクが満杯になると書き込みを停止する。ディスクの追加またはデータのアーカイブを計画する。","severity":"caution"},{"id":"largest-collections","group":"容量","title":"最大のコレクション","command":"db.getCollectionNames().map(function(c) { var s = db.getCollection(c).stats(); return {collection: c, size_MB: (s.size/1048576).toFixed(1), storage_MB: (s.storageSize/1048576).toFixed(1), index_MB: (s.totalIndexSize/1048576).toFixed(1), docs: s.count}; }).sort(function(a,b){return b.size_MB - a.size_MB;})","expect":"最も多くの領域を使用しているコレクションを特定する。予期しない増加は、アーカイブ、TTL インデックス、またはシャーディングが必要であることを示している可能性がある。インデックスサイズがデータサイズを超えるコレクションを見直す。","severity":"safe"},{"id":"connections","group":"容量","title":"接続数(current / available)","command":"db.serverStatus().connections","expect":"current が available に近づくと、接続数の上限に達しつつあり、新しい接続が拒否される。アプリケーションのコネクションプールの設定と、リークの可能性を確認する。","severity":"caution"},{"id":"wiredtiger-cache","group":"パフォーマンス","title":"WiredTiger キャッシュの使用状況と eviction","command":"var wt = db.serverStatus().wiredTiger.cache; printjson({used_MB: (wt['bytes currently in the cache']/1048576).toFixed(0), max_MB: (wt['maximum bytes configured']/1048576).toFixed(0), dirty_MB: (wt['tracked dirty bytes in the cache']/1048576).toFixed(0), pages_evicted: wt['unmodified pages evicted']})","expect":"使用メモリがキャッシュ最大値の 80% を超えると eviction が開始される。95% を超えるとアプリケーションスレッドが eviction を強制され、性能が低下する。ダーティページの割合が高い場合は書き込みの圧迫を示す。","severity":"caution"},{"id":"slow-queries-profiler","group":"パフォーマンス","title":"遅いクエリ(プロファイラ)と COLLSCAN","command":"printjson(db.getProfilingStatus()); db.system.profile.find({millis: {$gt: 100}}).sort({ts: -1}).limit(10).forEach(function(d){ print(d.ts + \" | \" + d.millis + \"ms | \" + (d.planSummary || '') + \" | \" + JSON.stringify(d.command)); })","expect":"このチェックは読み取り専用。まずプロファイラの状態(was: 0 オフ、1 遅い操作のみ、2 すべて)を表示し、次に記録された遅い操作を一覧表示する。プロファイラがオフ(was: 0)の場合 system.profile は空のまま。診断のためには、別の手順として db.setProfilingLevel(1, {slowms: 100}) で有効にし、終了後は db.setProfilingLevel(0) で無効にする。planSummary に COLLSCAN が表示されるクエリはコレクション全体をスキャンしており、インデックスが不足している。millis 値が大きいクエリはインデックス作成で最適化する。プロファイラはオーバーヘッドを伴うため、本番環境では慎重に使用する。","severity":"caution"},{"id":"long-running-ops","group":"パフォーマンス","title":"長時間実行中の操作(currentOp)","command":"db.getSiblingDB('admin').aggregate([{$currentOp: {}}, {$match: {active: true, secs_running: {$gt: 5}}}, {$project: {opid: 1, secs_running: 1, ns: 1, op: 1, planSummary: 1, waitingForLock: 1}}])","expect":"secs_running 値が大きいアクティブな操作はブロッキングを引き起こす可能性がある。必要に応じて db.killOp(opid) で終了する。waitingForLock=true の操作はロックを待機している。根本となる操作を調査する。","severity":"danger"},{"id":"oplog-window","group":"バックアップとリカバリ","title":"oplog ウィンドウ(レプリケーション履歴)","command":"rs.printReplicationInfo()","expect":"oplog ウィンドウ(構成された oplog サイズと時間単位のログの長さ)は十分に長い必要がある。ウィンドウが短い(数時間)場合、遅いセカンダリが完全な再同期(initial sync)に陥る可能性がある。バックアップとポイントインタイムリカバリの戦略は oplog に依存する。","severity":"caution"},{"id":"backup-note","group":"バックアップとリカバリ","title":"バックアップの状態と最終バックアップに関する注記","command":"var r = db.getSiblingDB('local').getCollectionNames().includes('oplog.rs') ? db.getReplicationInfo() : null; printjson(r ? {oplogWindowHours: r.timeDiffHours, tFirst: r.tFirst, tLast: r.tLast} : 'standalone: no oplog'); print('Backup verification: check mongodump/mongorestore or Ops Manager / Percona Backup (PBM) status externally.')","expect":"MongoDB には組み込みのスケジュールバックアップがなく、mongodump、ファイルシステムのスナップショット、Ops Manager、または PBM を使用する。最後に成功したバックアップの時刻とリストアテストを外部ツールで確認する。レプリカセットでは、oplog ウィンドウ(oplogWindowHours)が oplog ベースの PITR でどこまで遡れるかを決める。バックアップ間隔より短くてはならない。RPO/RTO の目標が満たされていることを確認する。","severity":"danger"},{"id":"users-roles","group":"セキュリティ","title":"ユーザーとロールの一覧","command":"db.getSiblingDB('admin').system.users.find({}, {user: 1, db: 1, roles: 1, _id: 0}).forEach(printjson)","expect":"定義済みのユーザーとそのロールを確認する。予期しないアカウントや過度に広いロール(root、__system、dbOwner)は権限昇格のリスクとなる。最小権限の原則を適用する。","severity":"caution"},{"id":"auth-enabled","group":"セキュリティ","title":"認証(authorization)が有効か","command":"db.getSiblingDB('admin').runCommand({getCmdLineOpts: 1}).parsed.security","expect":"security.authorization は 'enabled' である必要がある。無効の場合(または security ブロックがない場合)、データベースは認証なしでアクセス可能な状態にある。これは重大なセキュリティホールであり、直ちに有効にすること。","severity":"danger"},{"id":"secondary-lag","group":"レプリケーション","title":"セカンダリのレプリケーション遅延","command":"rs.printSecondaryReplicationInfo()","expect":"各セカンダリの 'replication lag' の値は低い(数秒)ことが望ましい。遅延が大きい(分単位)場合、セカンダリが負荷に追いつけないか、ネットワーク/ディスクの問題がある。フェイルオーバー時のデータ損失と読み取りの不整合のリスクが高まる。","severity":"caution"},{"id":"member-health","group":"レプリケーション","title":"メンバーの健全性と選出の状態","command":"rs.status().members.map(function(m){ return {member: m.name, state: m.stateStr, health: m.health, configVersion: m.configVersion, last_heartbeat: m.lastHeartbeatMessage || 'OK'}; })","expect":"すべてのメンバーが正常(health=1)で、想定どおりの状態(PRIMARY/SECONDARY)であることが望ましい。lastHeartbeatMessage にエラーメッセージがある場合は、ネットワーク分断または到達不能なメンバーを示す。過半数を失うと書き込みが停止する。","severity":"caution"}]},"health/redis.json":{"engineId":"redis","engine":"Redis","order":6,"checks":[{"id":"server-version-uptime","group":"一般","title":"バージョンと稼働時間","command":"redis-cli INFO server | grep -E \"redis_version|uptime_in_days|redis_mode|os\"","expect":"redis_version はサポート対象でパッチ適用済みのリリースであることが望ましい。uptime_in_days が非常に小さい場合は予期しない再起動が発生している。redis_mode(standalone/sentinel/cluster)で構成を確認する。","severity":"safe"},{"id":"persistence-status","group":"一般","title":"永続化の状態(RDB / AOF)","command":"redis-cli INFO persistence | grep -E \"rdb_last_bgsave_status|aof_enabled|aof_last_bgrewrite_status|aof_last_write_status|rdb_bgsave_in_progress|loading\"","expect":"rdb_last_bgsave_status と aof_last_write_status は 'ok' である必要がある。'err' はディスク/権限の問題またはディスク満杯を示し、データ損失のリスクを伴う。loading:1 はサーバーがまだデータをロード中であることを意味する。","severity":"danger"},{"id":"memory-usage","group":"容量","title":"メモリ使用量(used_memory / maxmemory)","command":"redis-cli INFO memory | grep -E \"used_memory_human|used_memory:|maxmemory_human|maxmemory:|maxmemory_policy\"","expect":"used_memory が maxmemory に近づく(85% 以上)と、eviction または OOM のリスクがある。maxmemory=0 の場合は上限がなく、Redis がすべての RAM を消費してシステムを停止させる可能性がある。必ず上限と適切な maxmemory_policy を設定すること。","severity":"caution"},{"id":"memory-fragmentation","group":"容量","title":"メモリ断片化率","command":"redis-cli INFO memory | grep -E \"mem_fragmentation_ratio|mem_allocator\"","expect":"mem_fragmentation_ratio は理想的には 1.0 から 1.5 の間。1.5 を超えると断片化が大きい(メモリの浪費)。1.0 未満は Redis がディスクにスワップされていることを示す(重大な性能問題)。システムの RAM を確認する。","severity":"caution"},{"id":"evicted-keys","group":"容量","title":"eviction されたキー(evicted_keys)","command":"redis-cli INFO stats | grep -E \"evicted_keys|expired_keys|keyspace_misses\"","expect":"evicted_keys が増え続けている場合、Redis はメモリ上限に達してデータを破棄している。これは意図しないデータ損失を引き起こす可能性がある。メモリの追加、TTL の使用、または maxmemory_policy の見直しを検討する。","severity":"caution"},{"id":"dbsize-keyspace","group":"容量","title":"キー数とキースペースの分布","command":"redis-cli DBSIZE; redis-cli INFO keyspace","expect":"総キー数(DBSIZE)とデータベースごとの分布(INFO keyspace: keys、expires、avg_ttl)を監視する。TTL のない(expires が少ない)キースペースの増加はメモリの肥大化を引き起こす。キー数の急増は異常な挙動の兆候である可能性がある。","severity":"safe"},{"id":"hit-ratio","group":"パフォーマンス","title":"キャッシュヒット率(keyspace hits/misses)","command":"redis-cli INFO stats | grep -E \"keyspace_hits|keyspace_misses\"","expect":"ヒット率 = hits / (hits + misses)。キャッシュ用途では高い比率(80% 以上)が望ましい。低い比率は非効率なキャッシュ、誤った TTL、またはキャッシュミスのパターンを示す。頻繁に要求されるデータがキャッシュされていることを確認する。","severity":"safe"},{"id":"slowlog","group":"パフォーマンス","title":"遅いコマンドのログ(SLOWLOG)","command":"redis-cli SLOWLOG GET 10","expect":"遅いコマンド(デフォルトのしきい値 10ms)を調査する。O(N) のコマンド(KEYS、SMEMBERS、大きな HGETALL、SORT)はシングルスレッドの Redis をブロックし、すべてのリクエストを遅延させる。SCAN などの代替手段に置き換える。","severity":"caution"},{"id":"clients","group":"パフォーマンス","title":"接続中およびブロックされたクライアント(clients)","command":"redis-cli INFO clients | grep -E \"connected_clients|blocked_clients|maxclients|client_recent_max_input_buffer\"","expect":"connected_clients が maxclients に近づくと、新しい接続が拒否される。blocked_clients の数が多い(BLPOP/BRPOP で待機中)のは設計上の場合もあるが、予期しない増加は輻輳の兆候。接続のリークを確認する。","severity":"safe"},{"id":"ops-per-sec","group":"パフォーマンス","title":"瞬間スループット(ops/sec)","command":"redis-cli INFO stats | grep -E \"instantaneous_ops_per_sec|total_commands_processed|rejected_connections|total_net_input_bytes\"","expect":"instantaneous_ops_per_sec は現在のワークロードを示す。急な低下/急増は異常の兆候。rejected_connections > 0 の場合、maxclients の上限に達している。シングルスレッドのため、非常に高い ops は CPU のボトルネックを生む可能性がある。","severity":"safe"},{"id":"rdb-last-save","group":"バックアップとリカバリ","title":"最後の RDB 保存と保留中の変更","command":"redis-cli INFO persistence | grep -E \"rdb_last_save_time|rdb_changes_since_last_save|rdb_last_bgsave_status\"; redis-cli LASTSAVE","expect":"rdb_changes_since_last_save が非常に大きい場合、最後のスナップショット以降に多くのデータが蓄積されており、これらの変更はクラッシュ時に失われる。rdb_last_save_time(LASTSAVE、Unix 時刻)が非常に古い場合は、保存間隔またはバックアップ頻度を見直す。","severity":"caution"},{"id":"aof-rewrite","group":"バックアップとリカバリ","title":"AOF 書き換えの状態","command":"redis-cli INFO persistence | grep -E \"aof_enabled|aof_last_bgrewrite_status|aof_rewrite_in_progress|aof_current_size|aof_base_size\"","expect":"永続性が必要なシナリオでは aof_enabled=1 を設定する必要がある。aof_last_bgrewrite_status は 'ok' である必要があり、'err' はディスク/永続化の問題を示す。aof_current_size が base_size よりはるかに大きい場合は書き換えが必要。","severity":"caution"},{"id":"acl-auth","group":"セキュリティ","title":"ACL / 認証(requirepass)の設定","command":"redis-cli ACL LIST; redis-cli ACL GETUSER default","expect":"パスワードで保護されたユーザーが少なくとも 1 つ必要。ACL GETUSER default の出力のフラグに 'on' と 'nopass' が表示される場合(requirepass もこのユーザーのパスワード)、Redis は認証なしでアクセス可能な状態にある。これは重大なセキュリティホール。パスワードはハッシュとしてのみ表示される。CONFIG GET requirepass はパスワードを平文で出力するため、このチェックには使用しないこと。ACL で最小権限のユーザーを定義する。","severity":"danger"},{"id":"dangerous-commands","group":"セキュリティ","title":"危険なコマンドと protected-mode","command":"redis-cli CONFIG GET protected-mode; redis-cli CONFIG GET bind; redis-cli COMMAND INFO flushall flushdb config keys","expect":"protected-mode は 'yes' で、bind は安全なインターフェースに限定することが望ましい。FLUSHALL、FLUSHDB、CONFIG、KEYS、DEBUG などの危険なコマンドは、本番環境では rename-command で無効にするか ACL で制限する。","severity":"caution"},{"id":"replication-status","group":"レプリケーション","title":"レプリケーションの状態(role、master link)","command":"redis-cli INFO replication","expect":"role(master/slave)、connected_slaves、各レプリカの状態を確認する。レプリカでは master_link_status が 'up' である必要があり、'down' はリンクが切れていることを意味する。master_last_io_seconds_ago が大きい(遅延)場合、データ損失と不整合のリスクが高まる。","severity":"danger"}]},"health/elasticsearch.json":{"engineId":"elasticsearch","engine":"Elasticsearch","order":7,"checks":[{"id":"cluster-health","group":"一般","title":"クラスタの健全性(green / yellow / red)","command":"GET _cluster/health","expect":"status は 'green' であることが望ましい: すべてのプライマリシャードとレプリカシャードが割り当てられている。'yellow' はプライマリは正常だが一部のレプリカが未割り当て(冗長性のリスク)、'red' は少なくとも 1 つのプライマリシャードが失われた/未割り当て(データの一部が利用不可、即時の対応が必要)であることを意味する。unassigned_shards は 0 であることが望ましい。","severity":"danger"},{"id":"cluster-version","group":"一般","title":"バージョンとクラスタの情報","command":"GET /","expect":"version.number はセキュリティパッチが適用されたサポート対象のバージョンであることが望ましい。古い/EOL(サポート終了)のバージョンはセキュリティと安定性のリスクを伴う。GET _cat/nodes?v&h=name,version ですべてのノードが同じバージョンで稼働していることも確認する(ローリングアップグレード中の一時的な混在は正常)。","severity":"safe"},{"id":"pending-tasks","group":"一般","title":"保留中のクラスタタスク","command":"GET _cluster/pending_tasks","expect":"一覧は空か非常に短いことが望ましい。積み上がり続けて長時間待機している(time_in_queue が大きい)タスクは、マスターノードが過負荷であるか、クラスタ状態の更新が停滞していることを示す。これはクラスタ全体の応答時間を悪化させる。","severity":"caution"},{"id":"disk-allocation-watermark","group":"容量","title":"ディスクの割り当てとウォーターマークの状態","command":"GET _cat/allocation?v","expect":"各ノードの disk.percent は high ウォーターマーク(デフォルト 90%)未満であることが望ましい。85% 超は警告、90%(high)はシャードの再配置を引き起こし、95%(flood_stage)はインデックスを読み取り専用にする。shards 列がノード間で均衡していることを確認する。偏った分布は単一のノードを早期に満杯にする。","severity":"danger"},{"id":"largest-indices","group":"容量","title":"最大のインデックス(ストアサイズ)","command":"GET _cat/indices?v&s=store.size:desc","expect":"最も多くの領域を消費しているインデックスとその doc.count 値を追跡する。ログ/メトリクスのインデックスの無秩序な増加がディスク満杯の主な原因。ILM(Index Lifecycle Management)でロールオーバーと削除のポリシーを定義する。status が 'close' のインデックスや、health が yellow/red のインデックスには特に注意する。","severity":"caution"},{"id":"jvm-heap-usage","group":"容量","title":"JVM ヒープと RAM の使用状況(ノードごと)","command":"GET _cat/nodes?v&h=name,heap.percent,ram.percent,cpu,load_1m","expect":"heap.percent は継続的に 75% 未満であることが望ましい。85% 以上が続く場合はメモリ圧迫、頻繁な GC の停止、サーキットブレーカーのリスクを意味する。JVM ヒープはサーバーの RAM の約 50% で、最大約 31GB(compressed oops の上限)にする。下がらない高いヒープには、クエリを最適化するかノードを追加する。","severity":"caution"},{"id":"shard-count-limits","group":"容量","title":"シャード数とノードあたりのシャード上限","command":"GET _cluster/health?level=shards","expect":"active_shards とノードあたりのシャード数は妥当であることが望ましい。デフォルトの上限は cluster.max_shards_per_node = 1000(データノードあたり)。この上限に近づくことや、合計で数千の小さなシャードを持つこと(オーバーシャーディング)は、マスターへの圧迫とメモリの浪費を生む。旧来の「ヒープ 1GB あたり約 20 シャード」のルールは 8.3+ には当てはまらない。現在のガイダンスはシャードあたり 10-50GB で、ヒープはノードあたりのフィールド(マッピング)数に基づいて計画する。initializing_shards / relocating_shards が長時間高いままであってはならない。シャードが多すぎる場合は、より大きく少ないシャードやロールオーバーを使用する。","severity":"caution"},{"id":"http-connections","group":"容量","title":"HTTP 接続数","command":"GET _nodes/stats/http","expect":"http.current_open は妥当な範囲内であることが望ましい。http.total_opened が非常に速く増加する場合、クライアントがコネクションプールを使用せず、リクエストごとに新しい接続を開いている(非効率)。異常に高い current_open は接続のリークまたはリソース枯渇の可能性を示す。","severity":"safe"},{"id":"thread-pool-rejections","group":"パフォーマンス","title":"スレッドプールの拒否とキューの飽和","command":"GET _cat/thread_pool?v&h=node_name,name,active,queue,rejected","expect":"rejected 列は 0 であることが望ましい。write/bulk および search プールで rejected の値が増加している場合、クラスタが過負荷で HTTP 429(es_rejected_execution_exception)を返していることを示す。常に満杯のキューは輻輳の兆候。クライアントでバックオフを適用するか、バッチサイズを減らすか、容量を追加する。","severity":"danger"},{"id":"query-cache-hit","group":"パフォーマンス","title":"クエリキャッシュのヒット率","command":"GET _nodes/stats/indices/query_cache","expect":"繰り返しのフィルタクエリでは、hit_count / (hit_count + miss_count) の比率が高いことが望ましい。ヒット率が低く eviction が多い場合は、キャッシュサイズが不足しているか、クエリの変動が大きすぎてキャッシュできないことを示す。安定したフィルタ(filter context)を使用するとヒット率が向上する。","severity":"safe"},{"id":"slowlog-config","group":"パフォーマンス","title":"スロークエリログ(slowlog)の設定","command":"GET /_all/_settings?filter_path=**.search.slowlog,**.indexing.slowlog","expect":"重要なインデックスには検索とインデックス作成の slowlog のしきい値を定義することが望ましい(例: index.search.slowlog.threshold.query.warn: 10s)。slowlog が無効だと遅いクエリの診断が難しくなる。しきい値を有効にしてログを監視し、高コストなクエリ(広範な集計、ワイルドカード、深いページング)を特定する。","severity":"safe"},{"id":"hot-threads","group":"パフォーマンス","title":"ホットスレッド","command":"GET _nodes/hot_threads","expect":"CPU を最も消費しているスレッドを示す。CPU 高負荷/遅延の発生時に、どの操作(重い集計、マージ、GC、スクリプト)がボトルネックかを判断するのに使用する。同じ高コストなクエリ/マージが繰り返し現れる場合は、そのクエリまたはインデックス作成の戦略を最適化する。","severity":"safe"},{"id":"fielddata-memory","group":"パフォーマンス","title":"fielddata のメモリ使用量","command":"GET _cat/fielddata?v","expect":"fielddata のメモリ使用量は低く抑えることが望ましい。text フィールドでの集計/ソートは fielddata をメモリにロードし、サーキットブレーカー(Data too large)エラーと OOM のリスクを高める。fielddata が多いフィールドは keyword サブフィールド(doc_values)に切り替える。","severity":"caution"},{"id":"snapshot-status","group":"バックアップとリカバリ","title":"スナップショットリポジトリと最新スナップショットの状態","command":"GET _snapshot/_all","expect":"少なくとも 1 つのスナップショットリポジトリが定義されていることが望ましい。リポジトリの存在を確認した後、最新のスナップショットの状態を確認する(下記の verify チェックと合わせて)。リポジトリがない場合、クラスタにはバックアップがなく、RED 状態でデータが永久に失われる可能性がある。定期的な自動スナップショットのために SLM(Snapshot Lifecycle Management)を設定する。","severity":"danger"},{"id":"snapshot-latest-state","group":"バックアップとリカバリ","title":"最新スナップショットの成功状態","command":"GET _snapshot/<repo>/_all?verbose=false","expect":"最新のスナップショットの state は 'SUCCESS' であることが望ましい。'PARTIAL' は一部のシャードがバックアップできなかったこと、'FAILED' はバックアップが失敗したことを意味し、どちらもリストア時のデータ損失を意味する。最新のスナップショットの日付(end_time)が古すぎてはならない(RPO 目標を満たす頻度でバックアップを取得する)。","severity":"danger"},{"id":"snapshot-repo-verify","group":"バックアップとリカバリ","title":"スナップショットリポジトリの検証","command":"POST _snapshot/<repo>/_verify","expect":"検証により、すべてのノードがリポジトリ(共有ファイルシステム、S3、HDFS など)にアクセスできることを確認し、アクセス可能なノードをレスポンスで一覧表示する。エラーが返る場合、一部のノードがバックアップリポジトリに書き込めず、スナップショットは不完全/失敗となる。リポジトリへのアクセスと認証情報を修正する。","severity":"caution"},{"id":"security-enabled","group":"セキュリティ","title":"セキュリティ(X-Pack security)が有効か","command":"GET _xpack/usage","expect":"security.enabled と security.available は true であることが望ましい。セキュリティが無効だとクラスタは認証なしでアクセス可能になる。そのようなクラスタがインターネットや信頼できないネットワークに公開されていると、重大な脆弱性(データ漏えい/削除)となる。認証、ロールベースのアクセス、TLS を有効にする必要がある。","severity":"danger"},{"id":"users-roles","group":"セキュリティ","title":"ユーザーとロール","command":"GET _security/user","expect":"定義済みのユーザーとロールの割り当てを確認する。組み込みアカウント(elastic、kibana_system など)が強力なパスワードで保護されていることを確認する。最小権限の原則に従い、アプリケーションごとに限定的なロールを持つ個別のユーザーを定義する。superuser ロールの不必要な広範囲の使用は避ける。ロールには GET _security/role を使用する。","severity":"caution"},{"id":"tls-transport-http","group":"セキュリティ","title":"TLS / HTTPS の状態(トランスポートと HTTP)","command":"GET _nodes/settings?filter_path=**.xpack.security.transport.ssl.enabled,**.xpack.security.http.ssl.enabled","expect":"xpack.security.transport.ssl.enabled は true であることが望ましい(ノード間の暗号化、必須)。理想的には http.ssl.enabled も true であるべき(クライアントからクラスタへの HTTPS)。TLS が無効だと、認証情報とデータが平文でネットワークを流れる。証明書の有効期限と検証モード(verification_mode: certificate/full)も確認する。","severity":"danger"},{"id":"unassigned-shards","group":"レプリケーション","title":"未割り当てのシャードとその理由","command":"GET _cat/shards?v&h=index,shard,prirep,state,unassigned.reason","expect":"すべてのシャードの state は 'STARTED' であることが望ましい。UNASSIGNED 状態のシャードとその unassigned.reason(NODE_LEFT、ALLOCATION_FAILED、DISK_THRESHOLD など)を調査する。プライマリが未割り当てなら health は RED、レプリカが未割り当てなら YELLOW。根本原因の特定には GET _cluster/allocation/explain を使用する。","severity":"danger"},{"id":"recovery-active","group":"レプリケーション","title":"進行中のシャードリカバリ","command":"GET _cat/recovery?v&active_only=true","expect":"通常はアクティブなリカバリがない(空の一覧)ことが望ましい。ノードの追加/削除やフェイルオーバー後の一時的なリカバリは正常だが、進捗なしで長時間停止したままのリカバリ(%progress が増加しない)はネットワーク/ディスクのボトルネックを示す。リバランス(再配置)がワークロードに影響する場合は、リカバリのスロットリング設定(indices.recovery.max_bytes_per_sec)を見直す。","severity":"caution"},{"id":"replica-count","group":"レプリケーション","title":"インデックスごとのレプリカ数","command":"GET _cat/indices?v&h=index,health,pri,rep,docs.count","expect":"本番環境のインデックスでは rep(number_of_replicas)は少なくとも 1 であることが望ましい。レプリカ 0 のインデックスではノードの喪失が永久的なデータ損失を意味する。ただし、マルチノードのクラスタではレプリカ数が(データノード数 - 1)を超えてはならない。超えると余分なレプリカは割り当てられず、health は YELLOW のままになる。health 列が green でないインデックスを調査する。","severity":"danger"}]},"recipes/oracle.json":{"engineId":"oracle","engine":"Oracle","order":1,"recipes":[{"id":"redo-switch","task":"REDO ログスイッチ(現在のログファイルを切り替え)","category":"REDO とアーカイブ","command":"ALTER SYSTEM SWITCH LOGFILE;","what":"現在の REDO ロググループを閉じて次のグループに移る。アーカイブログモードではアーカイブを開始させる。","when":"アーカイブを手動で生成する場合、ログスイッチを強制する場合、またはテスト用。","caution":"頻繁なスイッチは性能を低下させる。ログファイルが小さすぎる場合は、サイズ設定を見直す。","tags":["redo","switch","logfile","archive","archive","alter system"]},{"id":"redo-add-group","task":"新しい REDO ロググループを追加","category":"REDO とアーカイブ","command":"ALTER DATABASE ADD LOGFILE GROUP 4\n  ('/u01/oradata/ORCL/redo04a.log',\n   '/u02/oradata/ORCL/redo04b.log') SIZE 512M;","what":"指定したサイズとメンバーで新しい REDO ロググループを作成する(複数のメンバー = ミラー)。","when":"REDO のスループットが不足している場合、またはグループ数を増やしたい場合。","caution":"グループ番号が既存のグループと衝突しないことを確認する。V$LOG で確認する。","tags":["redo","logfile","group","add","add","alter database"]},{"id":"redo-resize","task":"REDO ロググループのサイズを変更(drop + add)","category":"REDO とアーカイブ","command":"-- 1) The group to be resized must be INACTIVE; if not, switch:\nALTER SYSTEM SWITCH LOGFILE;\nALTER SYSTEM CHECKPOINT;\n-- 2) Drop the old group:\nALTER DATABASE DROP LOGFILE GROUP 1;\n-- 3) Add it again with the new size:\nALTER DATABASE ADD LOGFILE GROUP 1\n  ('/u01/oradata/ORCL/redo01a.log',\n   '/u02/oradata/ORCL/redo01b.log') SIZE 1G REUSE;","what":"REDO ログのサイズは直接変更できない。グループを削除して新しいサイズで再追加することで行う。","when":"REDO ファイルが小さすぎる/大きすぎる場合、チェックポイントの頻度を調整するため。","caution":"削除できるのは INACTIVE または UNUSED のグループのみ。CURRENT/ACTIVE のグループは削除しないこと。常に少なくとも 2 つのグループが残っている必要がある。REUSE は既存のファイルを再利用する。","tags":["redo","resize","size","drop","add","logfile","reuse"]},{"id":"enable-archivelog","task":"データベースを ARCHIVELOG モードにする","category":"REDO とアーカイブ","command":"SHUTDOWN IMMEDIATE;\nSTARTUP MOUNT;\nALTER DATABASE ARCHIVELOG;\nALTER DATABASE OPEN;\n-- Verify:\nARCHIVE LOG LIST;","what":"データベースをアーカイブログモードにする。満杯になった REDO ログがアーカイブされ、ホットバックアップとポイントインタイムリカバリが可能になる。","when":"本番データベースのバックアップとリカバリの戦略のため(RMAN、Data Guard の前に必須)。","caution":"インスタンスの再起動が必要なため、ダウンタイムを計画する。アーカイブ先(FRA または LOG_ARCHIVE_DEST)に十分な領域があることを確認する。満杯になると DB が停止する。RAC の場合: srvctl stop database -d DB で全インスタンスを停止し、STARTUP MOUNT で単一のインスタンスをオープンして ARCHIVELOG に切り替え、シャットダウンしてから srvctl start database -d DB で起動する(11gR2+ では cluster_database=false は不要)。","tags":["archivelog","archive","mode","mount","recovery","recovery"]},{"id":"fra-full-fix","task":"満杯の FRA / アーカイブ先を解消","category":"REDO とアーカイブ","command":"-- Check usage:\nSELECT name, space_limit/1024/1024/1024 AS limit_gb,\n       space_used/1024/1024/1024  AS used_gb,\n       ROUND(space_used/space_limit*100,1) AS pct_used\nFROM   v$recovery_file_dest;\n\n-- Fix A) Increase the FRA size:\nALTER SYSTEM SET db_recovery_file_dest_size=100G SCOPE=BOTH;\n\n-- Fix B) Clean up already backed-up archives with RMAN:\n-- RMAN> DELETE ARCHIVELOG ALL BACKED UP 1 TIMES TO DISK COMPLETED BEFORE 'SYSDATE-3';\n-- If there is no backup (CAREFUL): RMAN> DELETE ARCHIVELOG ALL COMPLETED BEFORE 'SYSDATE-1';","what":"高速リカバリ領域またはアーカイブ先が満杯になると、データベースがハングする(ORA-00257)。領域の拡大またはアーカイブの整理で解消する。","when":"ORA-00257 アーカイバエラーが発生し、DB が新しいトランザクションを受け付けなくなった場合。","caution":"バックアップされていないアーカイブを削除するとリカバリ可能性が失われる。先に RMAN バックアップを取得してから削除する。OS から rm で削除しないこと。その場合は RMAN の CROSSCHECK が必要になる。FRA が満杯の間は、FRA 外の宛先にアーカイブをバックアップする(FORMAT '/backup/arc_%U')。Data Guard では、まだスタンバイに転送/適用されていないアーカイブを削除しないこと。そうしないとスタンバイにギャップが生じる。CONFIGURE ARCHIVELOG DELETION POLICY TO APPLIED ON ALL STANDBY を使用する。","tags":["fra","recovery area","ora-00257","archiver","archive","full","cleanup"]},{"id":"redo-status","task":"REDO ログの状態を表示","category":"REDO とアーカイブ","command":"SELECT l.group#, l.thread#, l.sequence#,\n       ROUND(l.bytes/1024/1024) AS mb,\n       l.members, l.archived, l.status,\n       lf.member AS file_path\nFROM   v$log l\n  JOIN v$logfile lf ON lf.group# = l.group#\nORDER BY l.group#, lf.member;","what":"REDO ロググループの状態(CURRENT/ACTIVE/INACTIVE)、サイズ、メンバーファイル、アーカイブ状態を示す。","when":"REDO の構成を確認する場合、またはサイズ変更の前にどのグループがアクティブかを確認するため。","caution":"照会のみ。リスクなし。","tags":["redo","status","status","v$log","v$logfile","logfile"]},{"id":"asm-add-disk","task":"ASM ディスクグループにディスクを追加","category":"ASM","command":"-- Connect to the ASM instance (sqlplus / as sysasm)\nALTER DISKGROUP DATA ADD DISK\n  '/dev/oracleasm/disks/DATA05' NAME DATA_0005,\n  '/dev/oracleasm/disks/DATA06' NAME DATA_0006\n  REBALANCE POWER 4;","what":"DATA ディスクグループに新しいディスクを追加し、自動リバランスを開始する。容量が増加する。","when":"ASM ディスクグループが満杯に近づいた場合、またはストレージを拡張する場合。","caution":"SYSASM 権限が必要。ディスクのサイズは同程度であることが望ましい。リバランスは I/O 負荷を生むため、繁忙時間帯には低い POWER を使用する。","tags":["asm","diskgroup","add disk","add disk","rebalance","alter diskgroup"]},{"id":"asm-drop-disk","task":"ASM ディスクグループからディスクを削除","category":"ASM","command":"ALTER DISKGROUP DATA DROP DISK DATA_0005 REBALANCE POWER 4;\n\n-- WAIT until the drop completes (the disk can be physically removed once V$ASM_OPERATION is empty):\nSELECT group_number, operation, state, power,\n       sofar, est_work, est_minutes\nFROM   v$asm_operation;","what":"ディスクグループからディスクを削除する。そのエクステントは残りのディスクに移動される(リバランス)。完了するとディスクの HDR_STATUS は FORMER になる。","when":"故障したディスクの交換、容量の削減、またはストレージの移行の場合。","caution":"リバランスが完了する前にディスクを物理的に取り外さないこと。データが失われる。残りのディスクに十分な空き領域があることを確認する。","tags":["asm","drop disk","remove disk","rebalance","v$asm_operation","alter diskgroup"]},{"id":"asm-rebalance-power","task":"ASM リバランスの POWER を設定","category":"ASM","command":"-- Change the power of a running rebalance (1-1024, 0 stops it):\nALTER DISKGROUP DATA REBALANCE POWER 8;\n\n-- Stop the rebalance completely:\nALTER DISKGROUP DATA REBALANCE POWER 0;","what":"進行中のリバランスの並列度/速度を設定する。POWER が高いほど高速だが I/O も増える。","when":"遅すぎるリバランスを高速化する場合、または本番環境に影響しているリバランスを減速/停止する場合。","caution":"POWER 0 はリバランスを一時停止する(ディスクの削除は完了しない)。高い値は本番環境の I/O に影響する。","tags":["asm","rebalance","power","power","diskgroup","tuning"]},{"id":"asm-diskgroup-space","task":"ASM ディスクグループの空き領域を表示","category":"ASM","command":"SELECT name,\n       state,\n       type,\n       total_mb/1024                 AS total_gb,\n       free_mb/1024                  AS free_gb,\n       ROUND((1-free_mb/total_mb)*100,1) AS pct_used,\n       usable_file_mb/1024           AS usable_gb\nFROM   v$asm_diskgroup\nORDER BY name;","what":"各ディスクグループの合計、空き、使用可能(冗長性考慮後)の領域を示す。","when":"容量計画のため、領域が不足してきた場合、ディスク追加を決定する前。","caution":"usable_file_mb は冗長性を考慮した値。NORMAL/HIGH 冗長性ではこの列が実際の使用可能領域となる。照会のみ。リスクなし。","tags":["asm","diskgroup","space","space","free","v$asm_diskgroup","capacity"]},{"id":"asm-monitor-rebalance","task":"ASM リバランスを監視","category":"ASM","command":"SELECT group_number, operation, pass, state, power,\n       sofar, est_work,\n       ROUND(sofar/NULLIF(est_work,0)*100,1) AS pct_done,\n       est_minutes\nFROM   v$asm_operation\nORDER BY group_number;","what":"進行中のリバランス/再同期操作の進捗、POWER、推定残り時間を示す。","when":"ディスクの追加/削除後にリバランスが完了したかを追跡する場合。","caution":"結果が空 = アクティブな操作なし(完了)。照会のみ。リスクなし。","tags":["asm","rebalance","monitor","monitor","v$asm_operation","progress"]},{"id":"add-tablespace","task":"新しい表領域を追加","category":"ストレージ","command":"-- File system:\nCREATE TABLESPACE customer_data\n  DATAFILE '/u01/oradata/ORCL/customer_data01.dbf'\n  SIZE 1G AUTOEXTEND ON NEXT 256M MAXSIZE 20G\n  EXTENT MANAGEMENT LOCAL\n  SEGMENT SPACE MANAGEMENT AUTO;\n\n-- If you use ASM:\nCREATE TABLESPACE customer_data\n  DATAFILE '+DATA' SIZE 1G AUTOEXTEND ON NEXT 256M MAXSIZE 20G;","what":"テーブル/インデックスのセグメントを配置できる新しい永続表領域を作成する。","when":"新しいアプリケーション/スキーマ用に個別のストレージを割り当てる場合。","caution":"MAXSIZE を指定すること。そうしないとディスクが満杯になる可能性がある。ASM ではファイル名は自動的に生成される。","tags":["tablespace","create","create","datafile","storage","storage","autoextend"]},{"id":"add-datafile","task":"既存の表領域にデータファイルを追加","category":"ストレージ","command":"ALTER TABLESPACE customer_data\n  ADD DATAFILE '/u01/oradata/ORCL/customer_data02.dbf'\n  SIZE 2G AUTOEXTEND ON NEXT 256M MAXSIZE 30G;\n\n-- ASM:\nALTER TABLESPACE customer_data\n  ADD DATAFILE '+DATA' SIZE 2G AUTOEXTEND ON NEXT 256M MAXSIZE 30G;","what":"新しいデータファイルを追加して既存の表領域の容量を拡大する。","when":"表領域が満杯で、単一のファイルがスモールファイルの上限(32G/64G)に近づいている場合。","caution":"スモールファイル表領域にはファイルごとのブロック数の上限がある。必要に応じて新しいファイルを追加する。MAXSIZE を指定する。","tags":["datafile","add","add","tablespace","alter tablespace","storage"]},{"id":"resize-datafile","task":"データファイルのサイズ変更/autoextend の設定","category":"ストレージ","command":"-- Grow/shrink to a fixed size:\nALTER DATABASE DATAFILE '/u01/oradata/ORCL/customer_data01.dbf' RESIZE 5G;\n\n-- Enable autoextend:\nALTER DATABASE DATAFILE '/u01/oradata/ORCL/customer_data01.dbf'\n  AUTOEXTEND ON NEXT 256M MAXSIZE 30G;\n\n-- Disable autoextend:\nALTER DATABASE DATAFILE '/u01/oradata/ORCL/customer_data01.dbf' AUTOEXTEND OFF;","what":"データファイルを固定サイズに設定するか、自動拡張の挙動を構成する。","when":"領域の回収(縮小)、領域の事前割り当て、または無秩序な拡張を止めるため。","caution":"RESIZE による縮小は、ファイル末尾の使用中ブロックより小さくできない(ORA-03297)。先にセグメントを移動する。","tags":["datafile","resize","size","autoextend","maxsize","alter database"]},{"id":"move-datafile-online","task":"データファイルをオンラインで移動","category":"ストレージ","command":"ALTER DATABASE MOVE DATAFILE\n  '/u01/oradata/ORCL/customer_data01.dbf'\n  TO '/u03/oradata/ORCL/customer_data01.dbf';\n\n-- Move into ASM:\nALTER DATABASE MOVE DATAFILE\n  '/u01/oradata/ORCL/customer_data01.dbf' TO '+DATA';\n\n-- Use KEEP to retain the old file instead of deleting it:\n-- ALTER DATABASE MOVE DATAFILE '...' TO '...' KEEP;","what":"データベースのオープン中にデータファイルを新しい場所に移動する(12c+)。ダウンタイムなしでストレージを変更できる。","when":"ディスク/マウントポイントの変更、ASM への移行、または高速ストレージへの移動の場合。","caution":"12c 以降かつ Enterprise Edition が必要。移動は追加の I/O を生む。KEEP を使用しない場合、旧ファイルは削除される。","since":"Oracle 12c","note":"データファイルのオンライン移動(ALTER DATABASE MOVE DATAFILE)は Oracle 12c(12.1)で導入された。それ以前は、表領域/データファイルを OFFLINE にし、OS レベルでコピーして ALTER DATABASE RENAME FILE で再マッピングする必要があった。","tags":["datafile","move","move","online","alter database move datafile","asm"]},{"id":"temp-tablespace","task":"一時表領域を追加/デフォルトを変更","category":"ストレージ","command":"-- Create a new temp tablespace:\nCREATE TEMPORARY TABLESPACE temp2\n  TEMPFILE '/u01/oradata/ORCL/temp2_01.dbf'\n  SIZE 2G AUTOEXTEND ON NEXT 256M MAXSIZE 20G;\n\n-- Change the database default temp:\nALTER DATABASE DEFAULT TEMPORARY TABLESPACE temp2;\n\n-- Add a tempfile to the old temp:\nALTER TABLESPACE temp ADD TEMPFILE '/u01/oradata/ORCL/temp_02.dbf' SIZE 2G;","what":"ソート/ハッシュ/グローバル一時表の操作に一時領域を提供する。デフォルトを新しい表領域に変更できる。","when":"ORA-01652(一時セグメントを拡張できない)、一時領域のボトルネック、または一時領域のサイズ変更の場合。","caution":"デフォルトを変更した後、旧一時表領域が使用中であれば直ちに DROP しないこと。セッションがなくなってから削除する。","tags":["temp","tablespace","tempfile","ora-01652","default temporary","storage"]},{"id":"tablespace-space","task":"表領域の空き領域の照会","category":"ストレージ","command":"SELECT df.tablespace_name,\n       ROUND(df.total_mb/1024,2)                 AS total_gb,\n       ROUND(NVL(fs.free_mb,0)/1024,2)           AS free_gb,\n       ROUND((df.total_mb-NVL(fs.free_mb,0))/df.total_mb*100,1) AS pct_used\nFROM  (SELECT tablespace_name, SUM(bytes)/1024/1024 total_mb\n         FROM dba_data_files GROUP BY tablespace_name) df\n  LEFT JOIN\n       (SELECT tablespace_name, SUM(bytes)/1024/1024 free_mb\n          FROM dba_free_space GROUP BY tablespace_name) fs\n    ON df.tablespace_name = fs.tablespace_name\nORDER BY pct_used DESC;","what":"各表領域の合計領域、空き領域、使用率を示す(現在割り当てられている領域に基づき、autoextend による拡張の余地は含まない)。","when":"領域の監視、どの表領域を拡張する必要があるかの特定。","caution":"このクエリは現在のデータファイルサイズに基づく。autoextend でさらに拡張できる。一時表領域には DBA_TEMP_FREE_SPACE を使用する。照会のみ。リスクなし。","tags":["tablespace","space","space","free","dba_free_space","usage","storage"]},{"id":"alter-parameter","task":"パラメータを変更(SCOPE 指定)","category":"メモリとパラメータ","command":"-- Both the running instance and the spfile (default, dynamic parameters):\nALTER SYSTEM SET open_cursors=500 SCOPE=BOTH;\n\n-- Only for the next restart (static parameters):\nALTER SYSTEM SET processes=1000 SCOPE=SPFILE;\n\n-- Immediate only, do not write to the spfile:\nALTER SYSTEM SET optimizer_mode='ALL_ROWS' SCOPE=MEMORY;\n\n-- View the current value:\nSHOW PARAMETER open_cursors;","what":"実行中のインスタンスと spfile のいずれかまたは両方で初期化パラメータを変更する。SCOPE が挙動を決める。","when":"パラメータの変更が必要なチューニング、容量調整、エラー修正の場合。","caution":"静的パラメータ(processes、sga_max_size...)は SCOPE=SPFILE のみ受け付け、再起動が必要。誤った値によりインスタンスが起動できなくなる場合がある。重要なパラメータでは先に pfile のバックアップを取得する。","tags":["parameter","parameter","alter system","scope","spfile","tuning"]},{"id":"flush-pool","task":"共有プール/バッファキャッシュのフラッシュ","category":"メモリとパラメータ","command":"-- Clear the SQL plan/cursor cache:\nALTER SYSTEM FLUSH SHARED_POOL;\n\n-- Clear the buffer cache (usually only for test/benchmark):\nALTER SYSTEM FLUSH BUFFER_CACHE;","what":"共有プールをフラッシュすると、キャッシュされたすべての SQL/PL-SQL とディクショナリ情報がメモリから追い出される。バッファキャッシュをフラッシュすると、すべてのデータブロックが追い出される。","when":"実行計画の問題のテスト、単発の大規模な操作の後、または一貫したベンチマークの開始のため。","caution":"本番環境では注意すること!フラッシュ後はすべての SQL が再解析され(ハードパースの嵐)、ブロックはディスクから読み込まれるため、一時的に深刻な性能低下が発生する。","tags":["flush","shared pool","buffer cache","memory","alter system","cache"]},{"id":"spfile-pfile","task":"spfile から pfile を作成、およびその逆","category":"メモリとパラメータ","command":"-- spfile -> pfile (for backup/editing):\nCREATE PFILE='/tmp/init_orcl_backup.ora' FROM SPFILE;\n\n-- pfile -> spfile (make the edited pfile permanent; effective after restart):\nCREATE SPFILE FROM PFILE='/tmp/init_orcl_backup.ora';\n\n-- Create a pfile from the running instance values (11g+):\nCREATE PFILE='/tmp/init_current.ora' FROM MEMORY;","what":"バイナリの spfile とテキストの pfile を相互に変換する。pfile は手作業で編集できる。","when":"パラメータ変更前のバックアップ、破損した spfile の修復、静的パラメータの手作業での修正。","caution":"CREATE SPFILE FROM PFILE の後、変更は再起動後にのみ有効になる。既存の spfile を上書きする前にパスを確認する。","tags":["spfile","pfile","create pfile","create spfile","parameter","backup"]},{"id":"sga-pga-target","task":"SGA / PGA のターゲットを変更","category":"メモリとパラメータ","command":"-- Automatic memory management (ASMM) targets:\nALTER SYSTEM SET sga_target=8G   SCOPE=BOTH;\nALTER SYSTEM SET pga_aggregate_target=4G SCOPE=BOTH;\n\n-- Upper limit (static, requires restart):\nALTER SYSTEM SET sga_max_size=12G SCOPE=SPFILE;\n\n-- View the current memory distribution:\nSELECT component, current_size/1024/1024 AS mb\nFROM   v$sga_dynamic_components ORDER BY component;","what":"SGA と PGA のメモリターゲットを設定する。Oracle がコンポーネントを自動的に管理する(ASMM/AMM)。","when":"サーバーに RAM を追加した場合、メモリのボトルネックやメモリ圧迫の発生時。","caution":"sga_target は sga_max_size を超えられない。sga_max_size は静的で再起動が必要。OS と他のインスタンスのために RAM を残すこと。過剰な割り当てはスワップ/OOM を引き起こす。","tags":["sga","pga","memory","memory","target","sga_target","pga_aggregate_target"]},{"id":"kill-session","task":"セッションを終了(kill session)","category":"セッションとプロセス","command":"-- First find the session to kill:\nSELECT sid, serial#, username, status, machine, program\nFROM   v$session\nWHERE  username = 'CUSTOMER_APP' AND status = 'ACTIVE';\n\n-- Kill it (starts rollback immediately):\nALTER SYSTEM KILL SESSION '145,12345' IMMEDIATE;\n\n-- If it hangs, the OS process can be terminated:\n-- ALTER SYSTEM DISCONNECT SESSION '145,12345' IMMEDIATE;","what":"指定した SID,SERIAL# のセッションを終了する。オープン中のトランザクションはロールバックされる。","when":"ロックを保持している、暴走クエリを実行している、または接続をリークしているセッションを止めるため。","caution":"オープン中のトランザクションがある場合、ロールバックに長時間かかることがある(作業量が少なければすぐに終わる)。誤った SID を終了しないよう、先にクエリで確認する。大規模な DML のロールバックは I/O 負荷を生む。","tags":["kill session","kill session","v$session","alter system","sid","serial"]},{"id":"long-running-queries","task":"長時間実行中のクエリ/セッションを表示","category":"セッションとプロセス","command":"-- Active, long-running SQL:\nSELECT s.sid, s.serial#, s.username, s.status,\n       s.last_call_et AS seconds_active,\n       s.sql_id, q.sql_text,\n       s.event, s.machine, s.program\nFROM   v$session s\n  LEFT JOIN v$sql q ON q.sql_id = s.sql_id\n                   AND q.child_number = s.sql_child_number\nWHERE  s.type = 'USER'\n  AND  s.status = 'ACTIVE'\n  AND  s.last_call_et > 60\nORDER BY s.last_call_et DESC;\n\n-- Long operations with percentage progress:\nSELECT sid, serial#, opname, sofar, totalwork,\n       ROUND(sofar/NULLIF(totalwork,0)*100,1) AS pct, time_remaining\nFROM   v$session_longops\nWHERE  sofar < totalwork ORDER BY start_time DESC;","what":"60 秒を超えて実行中のアクティブセッションと、長時間実行中のバッチ操作の進捗を一覧表示する。","when":"遅延の苦情があった場合に、どのクエリがシステムを占有しているかを特定するため。","caution":"last_call_et は最後の呼び出しからの経過時間。アイドル状態のセッションでも大きくなり得るため、status='ACTIVE' のフィルタが重要。照会のみ。リスクなし。","tags":["long running","long query","v$session","v$sql","v$session_longops","active"]},{"id":"find-blocking","task":"ブロックしているセッションを特定","category":"セッションとプロセス","command":"SELECT bl.sid       AS blocker_sid,\n       bl.serial#   AS blocker_serial,\n       bl.username  AS blocker_user,\n       w.sid        AS waiter_sid,\n       w.serial#    AS waiter_serial,\n       w.username   AS waiter_user,\n       w.seconds_in_wait AS wait_sec,\n       w.event\nFROM   v$session w\n  JOIN v$session bl ON bl.sid = w.blocking_session\nWHERE  w.blocking_session IS NOT NULL\nORDER BY w.seconds_in_wait DESC;","what":"ブロッカーと待機側のセッションの組を、待機時間とイベントとともに一覧表示する。","when":"「アプリケーションがハングした / enq: TX の待機」などのロックの問題で原因を特定するため。","caution":"ブロッカーを終了する前に業務担当者に確認すること。重要な処理である可能性がある。照会のみ。リスクなし。","tags":["blocking","lock","lock","blocker","waiter","v$session","blocking_session"]},{"id":"gather-stats","task":"統計を収集(DBMS_STATS)","category":"メンテナンス","command":"-- Single table (including cascaded indexes):\nEXEC DBMS_STATS.GATHER_TABLE_STATS(ownname => 'CUSTOMER_APP', tabname => 'CUSTOMER', cascade => TRUE, estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, degree => 4);\n\n-- Whole schema:\nEXEC DBMS_STATS.GATHER_SCHEMA_STATS(ownname => 'CUSTOMER_APP', estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, cascade => TRUE, degree => 4);\n\n-- Whole database (run only in a maintenance window / off-peak hours):\nEXEC DBMS_STATS.GATHER_DATABASE_STATS(estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, degree => 4);","what":"オプティマイザ用にテーブル/インデックスの統計を収集し、正しい実行計画が生成されるようにする。","when":"大量のDML/ロード後、実行計画が劣化したとき、新しいインデックス/表の作成後。","caution":"統計の変更は実行計画を変える可能性がある。重要なシステムでは事前にAWRでテスト/比較する。DEGREEの並列度はCPUを消費する。GATHER_DATABASE_STATSは業務ピーク時には負荷が高い。","tags":["dbms_stats","statistics","statistics","gather","optimizer","maintenance"]},{"id":"rebuild-index-online","task":"インデックスをオンラインで再構築","category":"メンテナンス","command":"-- Regular index:\nALTER INDEX customer_app.idx_customer_email REBUILD ONLINE PARALLEL 4;\n\n-- Moving it to a different tablespace:\nALTER INDEX customer_app.idx_customer_email\n  REBUILD ONLINE TABLESPACE customer_idx PARALLEL 4;\n\n-- Reset parallelism after the rebuild (so plans are not affected):\nALTER INDEX customer_app.idx_customer_email NOPARALLEL;","what":"DMLをブロックせずにインデックスを再構築する(ONLINE)。断片化を解消し、表領域の変更も可能。","when":"インデックスの肥大化/断片化、インデックスの別表領域への移動、UNUSABLEインデックスの修復。","caution":"ONLINEは追加の一時領域とI/Oを使用する。PARALLELは設定が残るため、再構築後にNOPARALLELで戻す。戻さないとクエリが意図せずパラレル実行される。ビットマップインデックスのONLINEはすべてのバージョンでサポートされるわけではない。ONLINE再構築はEnterprise Editionでのみ使用可能。","tags":["index","rebuild","online","rebuild","alter index","fragmentation","maintenance"]},{"id":"rman-full-backup","task":"RMANによるクイック全体バックアップ","category":"メンテナンス","command":"# From the shell: rman target /\nRUN {\n  ALLOCATE CHANNEL c1 DEVICE TYPE DISK;\n  ALLOCATE CHANNEL c2 DEVICE TYPE DISK;\n  BACKUP AS COMPRESSED BACKUPSET\n    DATABASE\n    PLUS ARCHIVELOG\n    TAG 'FULL_DAILY';\n  BACKUP CURRENT CONTROLFILE;\n  DELETE NOPROMPT OBSOLETE;\n  RELEASE CHANNEL c1;\n  RELEASE CHANNEL c2;\n}","what":"2チャネルでデータベース全体とアーカイブログの圧縮全体バックアップを並列に取得し、制御ファイルをバックアップし、不要になったバックアップを削除する。","when":"日次/週次の全体バックアップ、リカバリポイントの作成。","caution":"COMPRESSEDはCPUを消費する。DELETE OBSOLETEは保存ポリシーに従い古いバックアップを削除するため、ポリシー(CONFIGURE RETENTION POLICY)を正しく設定する。ARCHIVELOGにはDBがARCHIVELOGモードである必要がある。バックアップ先に十分な空き領域があることを確認する。","tags":["rman","backup","backup","full","compressed","archivelog","maintenance"]},{"id":"controlfile-trace","task":"制御ファイルのトレースバックアップを取得","category":"メンテナンス","command":"-- Generate a trace (CREATE CONTROLFILE script):\nALTER DATABASE BACKUP CONTROLFILE TO TRACE\n  AS '/tmp/create_controlfile.sql' REUSE;\n\n-- Binary controlfile copy:\nALTER DATABASE BACKUP CONTROLFILE TO '/backup/controlfile_orcl.ctl' REUSE;","what":"制御ファイルを再作成するSQLスクリプト(トレース)および/またはそのバイナリコピーを作成する。","when":"構造変更(データファイル/REDOの追加)後、災害復旧の準備時、またはすべてのコピーを失った場合の制御ファイル再作成用。","caution":"構造が変わるたびにトレースファイルを更新する。古いスクリプトでは誤った構造が作成される。REUSEは既存ファイルを上書きする。システムへのリスクはないが、生成したファイルは安全に保管する。","tags":["controlfile","trace","backup","backup","alter database","recovery","maintenance"]}]},"recipes/oracle-ha.json":{"engineId":"oracle","engine":"Oracle","order":1,"recipes":[{"id":"rac-srvctl-db-status","task":"srvctlでRACのデータベース、インスタンス、サービスの状態を確認","category":"RAC & Grid","command":"# Which node each instance runs on, and in what state:\nsrvctl status database -db <db_unique_name> -verbose\n# Configuration registered in Clusterware (Oracle home, spfile, disk group, policy, role):\nsrvctl config database -db <db_unique_name>\n# A single instance:\nsrvctl status instance -db <db_unique_name> -instance <instance>\n# Which instances the services are running on:\nsrvctl status service -db <db_unique_name>","what":"Clusterware(CRS)から見たデータベース、各インスタンスとそのサービスの実行時状態、および登録済み構成を表示する。-verboseでインスタンスのオープンモードも表示。","when":"RAC作業の前後に最初に行う確認として。障害時に影響を受けているノード/インスタンスの特定に。","caution":"読み取り専用。データベースのOracleホーム(oracleユーザー)から実行する。異なるバージョンのGridホームのsrvctlでは誤解を招く結果やエラーが返ることがある。","since":"12c","note":"長形式オプション -db/-instance/-service は12c以降。11gの短縮オプション(-d、-i、-s)は19cでも動作するが非推奨。","tags":["rac","srvctl","status","instance","service","cluster","config"],"untested":true},{"id":"rac-srvctl-start-stop","task":"srvctlでRACデータベースまたは単一インスタンスを停止/起動(ローリング)","category":"RAC & Grid","command":"# Whole database (all instances):\nsrvctl stop database -db <db_unique_name> -stopoption immediate\nsrvctl start database -db <db_unique_name>\n# Rolling maintenance: stop one instance, moving its services to the other instances\nsrvctl stop instance -db <db_unique_name> -instance <instance> \\\n  -stopoption immediate -drain_timeout 300 -failover\nsrvctl start instance -db <db_unique_name> -instance <instance>\n# By node:\nsrvctl stop instance -db <db_unique_name> -node <node> -stopoption immediate\n# Start in a specific open mode (e.g. a physical standby in mount):\nsrvctl start database -db <db_unique_name> -startoption mount","what":"Clusterware経由でデータベースまたは選択したインスタンスを制御された方法で停止/起動する。-failoverで停止インスタンス上のサービスを使用可能なインスタンスへ移動し、-drain_timeoutでセッションのドレインを待機する。","when":"パッチ適用、OSメンテナンス、パラメータ変更時のローリング(ノード単位)再起動に。計画的な全体停止に。","caution":"RACではSQL*PlusのSHUTDOWNではなくsrvctlを使用する。そうしないとClusterwareがリソースのTARGETを把握できず、インスタンスを再起動する場合がある。stop databaseは全インスタンスを停止する=完全停止。サービスに使用可能インスタンスが定義されていない場合、-failoverで接続を移動できない。","since":"12c","note":"-drain_timeoutと-failoverは12.2以降。-stopoption abortは緊急時のみ使用する。次回起動時にインスタンスリカバリが必要になる。","tags":["rac","srvctl","stop","start","rolling","drain","shutdown"],"untested":true},{"id":"rac-service-add","task":"優先/使用可能インスタンスを指定してRACサービスを追加(Application Continuityを含む)","category":"RAC & Grid","command":"srvctl add service -db <db_unique_name> -service <service> \\\n  -preferred <inst1>,<inst2> -available <inst3> \\\n  -pdb <pdb> -role PRIMARY -policy AUTOMATIC \\\n  -failovertype TRANSACTION -commit_outcome TRUE \\\n  -failoverretry 30 -failoverdelay 10 \\\n  -clbgoal SHORT -rlbgoal SERVICE_TIME -notification TRUE \\\n  -drain_timeout 300 -stopoption IMMEDIATE\nsrvctl start service -db <db_unique_name> -service <service>\n# Verify:\nsrvctl config service -db <db_unique_name> -service <service>\nsrvctl status service -db <db_unique_name> -service <service>","what":"通常は優先インスタンスで稼働し、障害時に使用可能インスタンスへ移動するアプリケーション用サービスを定義する。-role PRIMARYを指定すると、Data Guard環境でプライマリロールのときのみ起動する。","when":"アプリケーションをインスタンスではなくサービスに接続させる、ワークロードをノード間で分割する、計画メンテナンス時にシームレスなフェイルオーバー(drain/failover)を可能にするため。","caution":"アプリケーションはSIDやインスタンス名ではなく、このサービス名で(SCAN経由で)接続する必要がある。-failovertype TRANSACTION(Application Continuity)にはアプリケーション/ドライバの対応が必要。不明な場合は-failovertype SELECT(TAF)またはNONEから始める。SYS$サービスやdb_unique_name名のデフォルトサービスをアプリケーションに使用しない。","since":"12c","note":"-pdbは12c以降、-drain_timeoutと-stopoptionは12.2以降。変更はsrvctl modify serviceで行う。優先インスタンスを恒久的に変更するには-modifyconfigが必要。","tags":["rac","service","srvctl","preferred","available","taf","application continuity"],"untested":true},{"id":"rac-service-relocate","task":"RACサービスを別インスタンスに再配置","category":"RAC & Grid","command":"# First check the current placement:\nsrvctl status service -db <db_unique_name> -service <service>\n# Relocate by instance (sessions are drained):\nsrvctl relocate service -db <db_unique_name> -service <service> \\\n  -oldinst <inst1> -newinst <inst3> -drain_timeout 120 -wait YES\n# By node (policy-managed / singleton service):\nsrvctl relocate service -db <db_unique_name> -service <service> \\\n  -currentnode <node1> -targetnode <node2>\n# Session distribution per instance (SQL):\nSELECT inst_id, service_name, COUNT(*) AS sessions\nFROM   gv$session\nWHERE  type = 'USER'\nGROUP  BY inst_id, service_name\nORDER  BY service_name, inst_id;","what":"稼働中のサービスをあるインスタンス/ノードから別のインスタンス/ノードへ移動する。新規接続はターゲットインスタンスへ向かい、既存セッションはdrain_timeoutの間に自然に終了するのを待つ。","when":"メンテナンス前のノードの空け、フェイルオーバー後のサービスの優先インスタンスへの戻し、負荷の再分散に。","caution":"再配置は一時的であり、サービス構成(preferred/available)は変わらない。インスタンスが再起動するとサービスは優先インスタンスに戻る。-forceは既存セッションを強制終了する。アプリケーションが再接続できない場合、ユーザーには停止として見える。","since":"12c","note":"-drain_timeoutと-waitは12.2以降。SQLクエリは単一インスタンスでも実行できるが、srvctlの部分はRACが必要。","tags":["rac","service","relocate","move","srvctl","drain","gv$session"],"untested":true},{"id":"rac-crsctl-stat-res","task":"クラスタリソースの状態を確認(crsctl stat res -t)","category":"RAC & Grid","command":"# From the Grid home, as the grid user:\ncrsctl stat res -t\n# OHASD (init) layer: ora.cssd, ora.crsd, ora.asm, ora.ctssd...\ncrsctl stat res -t -init\n# Only problem resources (TARGET is ONLINE but STATE is not):\ncrsctl stat res -t -w \"((TARGET = ONLINE) and (STATE != ONLINE))\"\n# Profile and runtime details of a single resource:\ncrsctl stat res ora.<db_unique_name>.db -p\ncrsctl stat res ora.<db_unique_name>.db -v","what":"Clusterwareが管理するすべてのリソース(データベース、インスタンス、リスナー、SCAN、VIP、ASM、ディスクグループ、ネットワーク)をノードごとにTARGET/STATEとともに表形式で一覧表示する。","when":"ノード起動後、パッチ適用後、あらゆる障害調査時に。OFFLINE、INTERMEDIATE、UNKNOWNのリソースの特定に。","caution":"読み取り専用。ora.*リソースをcrsctl start/stop/modifyで直接管理しない。データベースリソースにはsrvctlを使用する(サポートされる方法)。","note":"リソース名には小文字のdb_unique_nameが含まれる(ora.orcl.db)。-initの出力はroot/gridでのみ完全に表示される。","tags":["rac","grid","crsctl","resource","resource","clusterware","status"],"untested":true},{"id":"rac-crsctl-check-cluster","task":"クラスタスタックの健全性、ノード一覧、Clusterwareバージョンを確認","category":"RAC & Grid","command":"# CRS, CSS, EVM health check on all nodes:\ncrsctl check cluster -all\n# Full stack on this node, including OHASD:\ncrsctl check crs\n# Node list: number, status (Active/Inactive), pinned:\nolsnodes -n -s -t\n# Active version, patch level and upgrade state (after a rolling patch):\ncrsctl query crs activeversion -f\ncrsctl query crs softwareversion -all","what":"Cluster Ready Services、Cluster Synchronization Services、Event Managerの各デーモンが全ノードで稼働していること、クラスタメンバー、Clusterwareのアクティブ/ソフトウェアバージョンを表示する。","when":"朝のヘルスチェック、ノードエビクションや再起動の後、ローリングパッチ/アップグレード後に全ノードが同じレベルであることの確認に。","caution":"読み取り専用。activeversion -fが「ROLLING PATCH」または異なるパッチレベルを示す場合、ローリング操作が未完了である。新たな変更を行う前に完了させる(crsctl stop rollingpatch / rootcrs -postpatch)。","since":"12c","note":"activeversion -fとsoftwareversion -allは12c以降。","tags":["rac","grid","crsctl","olsnodes","health","cluster","version"],"untested":true},{"id":"rac-ocr-backup","task":"OCRの整合性を確認し、OCRバックアップを取得(ocrcheck / ocrconfig)","category":"RAC & Grid","command":"# OCR integrity and capacity check (run as root for the logical check):\nocrcheck\nocrcheck -config\n# Automatic backups (every 4 hours, daily, weekly):\nocrconfig -showbackup\n# Manual backup before a risky change (root):\nocrconfig -manualbackup\nocrconfig -showbackup manual\n# Move the backup location to a disk group (root):\nocrconfig -backuploc +<diskgroup>","what":"Oracle Cluster Registry(クラスタ構成リポジトリ)の整合性、格納場所、バックアップを表示する。-manualbackupで即時に物理OCRバックアップを取得する。","when":"ノードの追加/削除、Gridのパッチ適用/アップグレード、投票ディスクやネットワーク(oifcfg)の変更など、クラスタ構成変更の直前に。","caution":"ocrconfig -restoreは全ノードでCRSを停止し、排他モードで実行する必要がある。誤ったバックアップをリストアするとクラスタが起動できなくなる可能性があるため、Oracle Supportとともに実施する。自動バックアップはデフォルトで単一ノードのローカルディスクに残る場合がある。格納場所を共有ディスクグループに移す。","note":"gridユーザーで実行すると、ocrcheckは論理破損チェックをスキップする(「Logical corruption check bypassed」)。ディスクグループへのバックアップは12c以降。","tags":["rac","ocr","ocrcheck","ocrconfig","backup","backup","grid"],"untested":true},{"id":"rac-votedisk-query","task":"投票ディスクとCSSタイムアウトを確認","category":"RAC & Grid","command":"# Voting disks, their state and disk group:\ncrsctl query css votedisk\n# Node eviction thresholds (seconds):\ncrsctl get css misscount\ncrsctl get css disktimeout\ncrsctl get css reboottime\n# Move the voting disks to another ASM disk group (root/grid):\ncrsctl replace votedisk +<diskgroup>","what":"クラスタメンバーシップに使用される投票ディスク(投票ファイル)の状態と、ネットワーク/ディスクハートビートのタイムアウトを表示する。replace votediskはすべての投票ファイルをターゲットディスクグループへ移動する。","when":"ストレージ変更、ディスクグループの再設計、ノードエビクション調査時に。投票ディスクの過半数(クォーラム)にアクセスできることの確認に。","caution":"投票ディスクの半数を超えてアクセスできないノードは自ら再起動する。ターゲットディスクグループには十分な障害グループが必要(normal冗長性: 3、high: 5。必要に応じてquorum failgroupを使用)。Oracle Supportの承認なしにmisscount/disktimeoutを変更しない。","note":"デフォルト: misscount 30 s、disktimeout 200 s(Linux)。","tags":["rac","voting disk","votedisk","css","misscount","quorum","eviction"],"untested":true},{"id":"rac-cluvfy-checks","task":"Cluster Verification Utility(cluvfy)で事前/事後チェックを実行","category":"RAC & Grid","command":"# Full check after a Grid installation/change:\ncluvfy stage -post crsinst -n all -verbose\n# Before adding a node:\ncluvfy stage -pre nodeadd -n <new_node> -verbose\n# Component checks:\ncluvfy comp nodecon -n all -verbose\ncluvfy comp clocksync -n all -verbose\ncluvfy comp ocr -n all -verbose\ncluvfy comp asm -n all -verbose\n# Report only failed checks:\ncluvfy stage -post crsinst -n all -verbose | grep -iE \"failed|warning\"","what":"全ノードのネットワーク接続、時刻同期、OCR、ASM、ユーザー等価性、OS前提条件を検証し、問題を修正案とともに報告する。","when":"Gridのインストール、ノード追加、アップグレードの前後に。原因不明のクラスタ問題に対するベースライン検証として。","caution":"読み取り専用だが、ssh経由で全ノードに接続する。gridユーザーにはssh等価性が必要。-fixupスクリプト(root)は内容を確認せずに実行しない。OSパラメータを変更する。","note":"より広範なベストプラクティス検査にはAHFのorachk/exachkを使用する。My Oracle Supportから最新のcluvfyをダウンロードすると、より多くのチェックが利用できる。","tags":["rac","cluvfy","check","verification","precheck","grid","orachk"],"untested":true},{"id":"rac-node-eviction-diag","task":"ノードエビクション/予期しないノード再起動の原因を診断","category":"RAC & Grid","command":"# 1) When, which node, evicted by whom: CRS alert log (on every node)\ngrep -E \"CRS-1601|CRS-1607|CRS-1608|CRS-1609|CRS-1610|CRS-1611|CRS-1612|CRS-8011\" \\\n  $ORACLE_BASE/diag/crs/$(hostname -s)/crs/trace/alert.log\n# 2) CSS details: was the network heartbeat or the disk heartbeat lost\ngrep -iE \"evict|misscount|heartbeat|disk HB|network HB\" \\\n  $ORACLE_BASE/diag/crs/$(hostname -s)/crs/trace/ocssd.trc | tail -100\n# 3) Who triggered the reboot (cssdagent/cssdmonitor):\nls -lt $ORACLE_BASE/diag/crs/$(hostname -s)/crs/trace/ohasd_cssd*.trc\n# 4) OS resources at the time of the event (Cluster Health Monitor):\noclumon dumpnodeview -allnodes -s \"2026-01-15 03:10:00\" -e \"2026-01-15 03:20:00\"\n# 5) Diagnostic collection from all nodes (AHF/TFA):\ntfactl diagcollect -crs -os -last 4h\n# 6) OS side: /var/log/messages, journalctl -k (OOM, NIC, multipath, I/O errors)","what":"ノードエビクションの連鎖を順に追う: CRSアラートログのCRS-16xxメッセージ、ocssd.trcのハートビート喪失、CHMのOSメトリック、TFAで収集した全ノードのログ。","when":"ノードが予期せず再起動した、またはクラスタからエビクトされたときの根本原因分析(RCA)とOracle Support SRのために。","caution":"全ノードから、イベント発生時刻を含むログを収集する。トレースファイルはローテーションされ、証拠が失われる可能性がある。ノード間でタイムゾーンが同じであることを確認する(CTSS/NTP)。証拠を収集する前にmisscountの引上げなどの「修正」を適用しない。","note":"典型的な原因: プライベートインターコネクトの停止/パケット損失、投票ディスクのI/Oレイテンシ、CPU/メモリ枯渇(OOM、スワップ)、時刻ジャンプ。パスは12c以降のADRレイアウト。11gでは$GRID_HOME/log/<host>/配下。","tags":["rac","eviction","reboot","ocssd","tfactl","oclumon","rca"],"untested":true},{"id":"rac-gv-cluster-waits","task":"GV$でクラスタ全体の待機イベント(gc待機)をインスタンスごとに分析","category":"RAC & Grid","command":"-- Cluster-class waits per instance (since startup):\nSELECT inst_id, event, total_waits,\n       ROUND(time_waited_micro/1e6) AS time_waited_s,\n       ROUND(time_waited_micro/NULLIF(total_waits,0)/1000, 2) AS avg_ms\nFROM   gv$system_event\nWHERE  wait_class = 'Cluster'\nORDER  BY time_waited_micro DESC\nFETCH FIRST 15 ROWS ONLY;\n\n-- Sessions waiting right now, by instance and event:\nSELECT inst_id, event, COUNT(*) AS sessions\nFROM   gv$session\nWHERE  wait_class <> 'Idle' AND state = 'WAITING'\nGROUP  BY inst_id, event\nORDER  BY sessions DESC;\n\n-- ASH for the last 15 minutes: which instance is waiting on gc\nSELECT inst_id, event, COUNT(*) AS samples\nFROM   gv$active_session_history\nWHERE  sample_time > SYSTIMESTAMP - INTERVAL '15' MINUTE\n  AND  wait_class = 'Cluster'\nGROUP  BY inst_id, event\nORDER  BY samples DESC\nFETCH FIRST 10 ROWS ONLY;","what":"GV$ビューを使用し、Clusterクラスの待機(gc cr/current block 2-way/3-way、gc buffer busy、gc cr request)とその平均レイテンシを全インスタンスについて1つのクエリで表示する。","when":"RACでユーザーから遅延が報告されたときに、問題がインターコネクト/グローバルキャッシュに起因するか、どのインスタンスに集中しているかを判別するため。","caution":"gv$active_session_historyにはDiagnostics Packライセンスが必要。avg_msが数msを超える場合、まずインターコネクト(MTU、パケット損失、netstat -s)とLMSのCPUを確認する。gc buffer busyは通常アプリケーションのホットブロック(順序、右肩上がりインデックス)を示す。","note":"単一インスタンスでも実行可能(inst_id = 1を返す)。","tags":["rac","gv$","gc","wait","wait event","interconnect","global cache"]},{"id":"asm-asmcmd-lsdg-du","task":"asmcmdでディスクグループ、ディスク、ディレクトリの使用量を表示(lsdg / lsdsk / du)","category":"ASM","command":"# As the grid user, with ORACLE_SID=+ASM1 (or +ASM):\nasmcmd lsdg\n# Disks in the disk group: -k sizes, -p state (header/mount/mode):\nasmcmd lsdsk -k -G <diskgroup>\nasmcmd lsdsk -p -G <diskgroup>\n# I/O error and timing statistics:\nasmcmd lsdsk --statistics -G <diskgroup>\n# Disks that can be added (CANDIDATE/PROVISIONED/FORMER):\nasmcmd lsdsk --candidate -p\n# Space used by a database directory (MB):\nasmcmd du +<diskgroup>/<db_unique_name>\nasmcmd ls -l -s +<diskgroup>/<db_unique_name>/DATAFILE","what":"ディスクグループの冗長性、合計/空き領域、Usable_file_MB、ディスクの状態、データベースがASM上で占有する領域をコマンドラインから表示する。","when":"容量確認、ディスク追加前の候補ディスクの特定、「disk group full」アラート発生時にどのデータベースが領域を消費しているかの特定に。","caution":"読み取り専用。lsdgのUsable_file_MBが負の場合、ディスク/障害グループを失った後に冗長性を回復できない。直ちに領域を解放するかディスクを追加する。duは2つの値を返す: Used_MBとMirror_used_MB(ミラー分を含む使用量)。","note":"SQLでの同等の方法はasm-diskgroup-spaceおよびasm-disk-healthレシピを参照。","tags":["asm","asmcmd","lsdg","lsdsk","du","space","disk group"],"untested":true},{"id":"asm-disk-health","task":"SQLでASMディスクの状態、エラーカウンタ、候補ディスクを確認","category":"ASM","command":"-- On the ASM instance (or from a DB instance; there only the disk groups in use are visible):\nSELECT dg.name AS diskgroup, d.disk_number, d.name AS disk_name, d.path,\n       d.header_status, d.mount_status, d.mode_status, d.state,\n       d.failgroup, d.total_mb, d.free_mb, d.read_errs, d.write_errs\nFROM   v$asm_disk d\nLEFT   JOIN v$asm_diskgroup dg ON dg.group_number = d.group_number\nORDER  BY dg.name, d.disk_number;\n\n-- Disk group summary: AU size, offline disks, voting files:\nSELECT name, type, allocation_unit_size/1048576 AS au_mb,\n       compatibility, database_compatibility, offline_disks, voting_files\nFROM   v$asm_diskgroup;\n\n-- Databases using this ASM:\nSELECT instance_name, db_name, status, software_version, compatible_version\nFROM   v$asm_client;","what":"各ディスクのheader_status(MEMBER、CANDIDATE、PROVISIONED、FORMER)、マウント/モード状態、障害グループ、読み取り/書き込みエラーカウンタ、ディスクグループごとのオフラインディスク数、ASMクライアントを一覧表示する。","when":"ディスク追加前に新しいLUNがCANDIDATE/PROVISIONEDとして表示されることの確認に。ディスク障害時にOFFLINEのディスクとI/Oエラーの確認に。","caution":"読み取り専用。v$asm_diskは呼出しごとにディスク検出を実行するため、ディスクが多いシステムでは遅い。頻繁な監視にはv$asm_disk_statを使用する(検出なし、新しいディスクは表示されない)。header_statusがMEMBERのディスクをFORCEで別のディスクグループに追加しない。既存データが破壊される。","note":"ASMがない場合は行を返さない。意味のある出力にはASMインスタンスが必要。","tags":["asm","v$asm_disk","disk","header_status","error","candidate","failgroup"]},{"id":"asm-diskgroup-attributes","task":"ASMディスクグループ属性の表示と変更(compatible、disk_repair_time)","category":"ASM","command":"-- Current attributes:\nSELECT dg.name AS diskgroup, a.name, a.value\nFROM   v$asm_attribute a\nJOIN   v$asm_diskgroup dg ON dg.group_number = a.group_number\nWHERE  a.name IN ('compatible.asm','compatible.rdbms','au_size','disk_repair_time',\n                  'failgroup_repair_time','content.type','sector_size')\nORDER  BY dg.name, a.name;\n\n-- Change (ASM instance, as SYSASM):\nALTER DISKGROUP <diskgroup> SET ATTRIBUTE 'disk_repair_time' = '8h';\nALTER DISKGROUP <diskgroup> SET ATTRIBUTE 'compatible.asm'   = '19.0.0.0.0';\nALTER DISKGROUP <diskgroup> SET ATTRIBUTE 'compatible.rdbms' = '19.0.0.0.0';\n\n-- asmcmd equivalent:\n-- asmcmd lsattr -l -G <diskgroup>\n-- asmcmd setattr -G <diskgroup> disk_repair_time '8h'","what":"ディスクグループの互換性レベル(compatible.asm/rdbms)、AUサイズ、一時的に障害が発生したディスクを削除するまでの保持時間(disk_repair_time)を表示・変更する。","when":"Gridアップグレード後のASM新機能(フレックスディスクグループ、より大きなファイル上限)の有効化、計画的なストレージメンテナンス時のdisk_repair_timeの延長に。","caution":"compatible.asmとcompatible.rdbmsは一度引き上げると引き下げられない。compatible.rdbmsがこのディスクグループを使用する最も古いデータベースのCOMPATIBLE設定より高い場合、そのデータベースはマウントできない。先にcompatible.asmを、次にcompatible.rdbmsを引き上げる。au_sizeはディスクグループ作成時にのみ設定できる。","note":"ASMがない場合、クエリは行を返さない。disk_repair_timeのデフォルトは12h。","tags":["asm","attribute","compatible","disk_repair_time","disk group","au_size","v$asm_attribute"],"untested":true},{"id":"dg-show-configuration","task":"Data Guard Broker構成とデータベースの状態を表示(DGMGRL)","category":"Data Guard","command":"# From the shell (connect with a password; also required for switchover/failover):\ndgmgrl sys@<primary_db_unique_name>\nSHOW CONFIGURATION VERBOSE;\nSHOW DATABASE VERBOSE '<standby_db_unique_name>';\n# Monitorable properties:\nSHOW DATABASE '<primary_db_unique_name>' 'LogXptStatus';\nSHOW DATABASE '<standby_db_unique_name>' 'RecvQEntries';\nSHOW DATABASE '<primary_db_unique_name>' 'InconsistentLogXptProps';\nSHOW DATABASE '<standby_db_unique_name>' 'StatusReport';","what":"Broker構成全体の状態(SUCCESS/WARNING/ERROR)、保護モード、各データベースのロール、転送/適用ラグ、Brokerとspfileの不整合を表示する。","when":"すべてのData Guard操作(スイッチオーバー、フェイルオーバー、パラメータ変更)の前後に。日次ヘルスチェックに。","caution":"読み取り専用。Brokerが有効な間は、log_archive_dest_nやlog_archive_configなどのData GuardパラメータをSQLで変更しない。Brokerが独自の値で上書きする。変更はEDIT DATABASE ... SET PROPERTYで行い、19c以降の初期化パラメータにはEDIT DATABASE ... SET PARAMETERを使用する。","note":"StatusReportはデータベースごとのORA-エラーを一覧表示し、WARNING状態の原因を特定する最速の方法である。InconsistentPropertiesは19cで非推奨となり、常に値を返さない。REDO転送の不整合にはInconsistentLogXptPropsを使用する。","tags":["data guard","dgmgrl","broker","configuration","standby","status","lag"],"untested":true},{"id":"dg-readiness-sql","task":"SQLでプライマリ/スタンバイのロールとスイッチオーバー可否を確認","category":"Data Guard","command":"SELECT name, db_unique_name, database_role, open_mode, protection_mode,\n       switchover_status, force_logging, flashback_on, dataguard_broker\nFROM   v$database;\n\n-- State of redo destinations and gaps (on the primary):\nSELECT dest_id, dest_name, status, type, database_mode,\n       recovery_mode, gap_status, error\nFROM   v$archive_dest_status\nWHERE  status <> 'INACTIVE';\n\n-- Missing archivelog range on the standby:\nSELECT thread#, low_sequence#, high_sequence# FROM v$archive_gap;","what":"データベースロール、オープンモード、保護モード、switchover_status(TO STANDBY / TO PRIMARY / SESSIONS ACTIVE / NOT ALLOWED)、FORCE LOGGINGとフラッシュバックの状態、REDO転送先のエラーとギャップを表示する。","when":"スイッチオーバー/フェイルオーバー前の事前チェック、新規スタンバイ構築後、Brokerを使用しない環境での基本監視に。","caution":"読み取り専用。FORCE_LOGGING=NOの場合、NOLOGGING操作によりスタンバイに破損ブロックが残る。Data GuardのプライマリではALTER DATABASE FORCE LOGGINGを有効にする必要がある。FLASHBACK_ON=NOの場合、フェイルオーバー後に旧プライマリを回復(reinstate)できず、再構築が必要になる。","note":"プライマリでも実行可能。v$archive_gapはフィジカルスタンバイでのみ意味を持つ。","tags":["data guard","v$database","switchover_status","force logging","gap","role","standby"]},{"id":"dg-lag-apply-rate","task":"スタンバイで転送/適用ラグ、適用速度、Data Guardプロセスを測定","category":"Data Guard","command":"-- Run on the standby:\nSELECT name, value, unit, time_computed, datum_time\nFROM   v$dataguard_stats\nWHERE  name IN ('transport lag','apply lag','apply finish time','estimated startup time');\n\n-- Redo apply rate (KB/s):\nSELECT item, units, sofar, total, TO_CHAR(timestamp,'YYYY-MM-DD HH24:MI:SS') AS ts\nFROM   v$recovery_progress\nWHERE  item IN ('Active Apply Rate','Average Apply Rate','Maximum Apply Rate','Last Applied Redo')\nORDER  BY start_time DESC, item;\n\n-- Transport and apply processes (12.2+; replaces v$managed_standby):\nSELECT name, role, action, thread#, sequence#, block#, delay_mins\nFROM   v$dataguard_process\nORDER  BY role;","what":"スタンバイがプライマリからどれだけ遅れているか(転送ラグ=未受信のREDO、適用ラグ=未適用のREDO)、バックログがいつ適用されるか、適用速度、どのプロセスがどのシーケンスを処理しているかを表示する。","when":"RPO/RTO監視に。ラグアラート時に問題がネットワーク(転送)にあるか、スタンバイのI/O/CPU(適用)にあるかの判別に。","caution":"読み取り専用。datum_timeが古い(time_computedより大きく遅れている)場合、スタンバイはプライマリからデータを受信しておらず、ラグの値は信頼できない。DelayMinsが設定されているか確認する。意図的な遅延は適用ラグとして見える。","since":"12c","note":"v$dataguard_processは12.2以降。スタンバイがない場合、v$dataguard_statsは行を返さない。","tags":["data guard","lag","lag","apply","transport","v$dataguard_stats","rpo"]},{"id":"dg-validate-database","task":"スイッチオーバー/フェイルオーバー前にBrokerでスタンバイを検証(VALIDATE DATABASE)","category":"Data Guard","command":"VALIDATE DATABASE '<standby_db_unique_name>';\nVALIDATE DATABASE VERBOSE '<standby_db_unique_name>';\n# spfile parameter differences between the two sides:\nVALIDATE DATABASE '<standby_db_unique_name>' SPFILE;\n# Network and static listener registrations (18c+):\nVALIDATE NETWORK CONFIGURATION FOR ALL;\nVALIDATE STATIC CONNECT IDENTIFIER FOR ALL;","what":"スタンバイがロール変更の準備ができているか(「Ready for Switchover / Failover: Yes」)、スタンバイREDOログの数/サイズ、フラッシュバックと適用の状態、spfileの差異、Brokerがインスタンスを再起動するために必要な静的サービスを確認する。","when":"計画的なスイッチオーバーの前に必須の手順として。新規スタンバイ構築後、ネットワーク/リスナー変更後に。","caution":"読み取り専用。「Ready for Switchover: No」またはスタンバイREDOログの警告が表示された場合は、スイッチオーバーを進めない。静的接続識別子のエラーは、スイッチオーバー中にBrokerがインスタンスを起動できないことを意味し、手動介入が必要になる。","since":"12c","note":"VALIDATE DATABASEは12.1以降、SPFILEオプションは12.2以降、NETWORK CONFIGURATIONとSTATIC CONNECT IDENTIFIERは18c以降。","tags":["data guard","dgmgrl","validate","validate","switchover","standby redo log","broker"],"untested":true},{"id":"dg-switchover","task":"計画的スイッチオーバーを実行(DGMGRL、データ損失なしのロール変更)","category":"Data Guard","command":"# Connect with a password (with OS authentication \"/\" the broker cannot restart the remote instance):\ndgmgrl sys@<primary_db_unique_name>\n# 1) Precheck:\nSHOW CONFIGURATION;\nVALIDATE DATABASE '<standby_db_unique_name>';\n# 2) Role change:\nSWITCHOVER TO '<standby_db_unique_name>';\n# 3) Verify: new primary and new standby\nSHOW CONFIGURATION;\nSHOW DATABASE '<primary_db_unique_name>';","what":"プライマリとスタンバイのロールを制御された方法で入れ替える。プライマリのREDOはすべて転送されてスタンバイで適用され、旧プライマリはスタンバイとして再起動し、REDO適用が自動的に開始される。","when":"プライマリサイトの計画メンテナンス(OS、ハードウェア、ローリングアップグレード)、DR訓練、データセンター移転に。","caution":"プライマリには短時間の停止が発生する。アプリケーション接続は、-role PRIMARYで定義したサービスとFAN/TAF/ACを通じて新プライマリへルーティングする必要がある。長時間実行トランザクションと大きな適用ラグはスイッチオーバーを長引かせるため、事前にラグをゼロ近くまで下げる。RACではBrokerがインスタンスを自ら管理するため、srvctlで介入しない。","since":"12c","note":"12.1以降はBrokerが1コマンドですべての手順を実行する。Brokerなしの11gではSQLでALTER DATABASE COMMIT TO SWITCHOVERを使用した(12c以降: ALTER DATABASE SWITCHOVER TO <db> VERIFY)。","tags":["data guard","switchover","dgmgrl","role change","planned","standby","primary"],"untested":true},{"id":"dg-failover","task":"プライマリ喪失後にフェイルオーバーを実行(DGMGRL)","category":"Data Guard","command":"# Connect to the standby (the primary is unreachable):\ndgmgrl sys@<standby_db_unique_name>\n# 1) Assess the data that will be lost (Transport Lag / Apply Lag):\nSHOW DATABASE '<standby_db_unique_name>';\n# 2) Complete failover: all received redo is applied, then the role changes (recommended)\nFAILOVER TO '<standby_db_unique_name>';\n# 3) Emergency: immediately, without applying redo (more data loss)\n# FAILOVER TO '<standby_db_unique_name>' IMMEDIATE;\nSHOW CONFIGURATION;","what":"プライマリが使用不能なときにスタンバイをプライマリロールに昇格する。完全フェイルオーバーはまず受信済みREDOをすべて適用し、IMMEDIATEは適用をスキップする。","when":"プライマリサイト、ストレージ、データベースが回復不能なほど失われ、RTOがスイッチオーバーを待つ余裕を許さない場合。","caution":"このロール変更は元に戻せない。まずプライマリが本当に停止していることを確認する。旧プライマリが開いたままアプリケーションが書き込み続けると、スプリットブレインとデータの分岐が発生する(旧プライマリを停止/隔離する)。MaxPerformanceモードでは転送ラグ分のデータが失われる。実施後、新プライマリに対するすべてのスタンバイとバックアップ戦略を見直す。","note":"旧プライマリの回復はdg-reinstate-databaseレシピを参照(フラッシュバックが必要)。","tags":["data guard","failover","dgmgrl","disaster","disaster recovery","data loss","split-brain"],"untested":true},{"id":"dg-reinstate-database","task":"フェイルオーバー後に旧プライマリをスタンバイとして回復(REINSTATE)","category":"Data Guard","command":"# 1) Bring the old primary to MOUNT (sqlplus / as sysdba):\n#    SQL> STARTUP MOUNT;\n#    (RAC: srvctl start database -db <old_primary_db_unique_name> -startoption mount)\n# 2) From DGMGRL connected to the new primary:\ndgmgrl sys@<new_primary_db_unique_name>\nREINSTATE DATABASE '<old_primary_db_unique_name>';\n# 3) Verify:\nSHOW CONFIGURATION;\nSHOW DATABASE '<old_primary_db_unique_name>';","what":"flashback databaseで旧プライマリをフェイルオーバーSCN以前に戻し、フィジカルスタンバイに変換して新プライマリからのREDO受信を開始する。スタンバイを一から再構築する必要はない。","when":"フェイルオーバー後、旧プライマリのサーバー/ストレージに再びアクセスできるようになったときに。FSFOの自動フェイルオーバー後(通常はObserverが自動的にreinstateする)。","caution":"フェイルオーバーの前に旧プライマリでフラッシュバックが有効化されており、フラッシュバックログがフェイルオーバーSCNをカバーしている必要がある(db_flashback_retention_target、FRAサイズ)。そうでない場合reinstateは失敗し、RMAN duplicateでスタンバイを再構築する必要がある。フェイルオーバー後に旧プライマリに書き込まれたデータは完全に失われる。","note":"前提条件の確認: dg-readiness-sqlレシピのflashback_on列。","tags":["data guard","reinstate","flashback","failover","old primary","standby","dgmgrl"],"untested":true},{"id":"dg-apply-transport-state","task":"BrokerでREDO適用またはREDO転送を停止/開始し、遅延適用を構成","category":"Data Guard","command":"# Redo apply on the standby:\nEDIT DATABASE '<standby_db_unique_name>' SET STATE='APPLY-OFF';\nEDIT DATABASE '<standby_db_unique_name>' SET STATE='APPLY-ON';\n# Redo transport on the primary (to all standbys):\nEDIT DATABASE '<primary_db_unique_name>' SET STATE='TRANSPORT-OFF';\nEDIT DATABASE '<primary_db_unique_name>' SET STATE='TRANSPORT-ON';\n# Delayed apply (minutes; protection against logical errors):\nEDIT DATABASE '<standby_db_unique_name>' SET PROPERTY DelayMins=240;\nSHOW DATABASE '<standby_db_unique_name>' DelayMins;","what":"Brokerを通じて、スタンバイのREDO適用(MRP)またはプライマリのREDO転送を永続的に停止/開始する。DelayMinsは指定時間REDOを保持してから適用する。","when":"スタンバイでのメンテナンスやバックアップ、計画的なネットワーク停止、プライマリでの大量一括ロード時の転送制御、誤削除対策としての遅延スタンバイ構築に。","caution":"Brokerが有効な間は、SQLでALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCELを使用しない。Brokerが状態を元に戻す。APPLY-OFFの間は適用ラグとフェイルオーバー時間(RTO)が増大し、TRANSPORT-OFFの間はプライマリで生成されたデータが保護されない(RPO)。FSFOが有効な場合、これらの操作はフェイルオーバーを妨げる可能性がある。","note":"DelayMins > 0の場合、REDOはリアルタイム適用ではなく、遅延後にアーカイブログから適用される。遅延中もスタンバイはREDOの受信を継続する。","tags":["data guard","apply","transport","mrp","delaymins","stop","dgmgrl"],"untested":true},{"id":"dg-fsfo-observer","task":"Fast-Start Failover(FSFO)を有効化し、Observerを起動","category":"Data Guard","command":"# 1) Targets and threshold (seconds):\nEDIT DATABASE '<primary_db_unique_name>' SET PROPERTY FastStartFailoverTarget='<standby_db_unique_name>';\nEDIT DATABASE '<standby_db_unique_name>' SET PROPERTY FastStartFailoverTarget='<primary_db_unique_name>';\nEDIT CONFIGURATION SET PROPERTY FastStartFailoverThreshold=30;\n# 2) MaxAvailability for zero data loss (SYNC/FASTSYNC transport):\nEDIT DATABASE '<primary_db_unique_name>' SET PROPERTY LogXptMode='FASTSYNC';\nEDIT DATABASE '<standby_db_unique_name>' SET PROPERTY LogXptMode='FASTSYNC';\nEDIT CONFIGURATION SET PROTECTION MODE AS MAXAVAILABILITY;\n# Acceptable loss in MaxPerformance: EDIT CONFIGURATION SET PROPERTY FastStartFailoverLagLimit=30;\nENABLE FAST_START FAILOVER;\n# 3) Observer: on a third server, separate from primary and standby (passwordless connection via wallet)\ndgmgrl /@<primary_tns> \"START OBSERVER obs1 IN BACKGROUND FILE IS '/u01/app/oracle/dg/fsfo_obs1.dat' LOGFILE IS '/u01/app/oracle/dg/obs1.log' CONNECT IDENTIFIER IS <primary_tns>\"\n# 4) Verify:\nSHOW FAST_START FAILOVER;\nSHOW OBSERVER;","what":"プライマリに到達できない場合にしきい値経過後、Observerが自動的にスタンバイへフェイルオーバーし、旧プライマリが復帰したときに自動的にreinstateできるようにする。","when":"RTO目標が分単位で、人による介入を待てない重要システムに。","caution":"Observerはプライマリやスタンバイと同じサーバー/データセンターで実行してはならない。そうでないとサイト喪失時にFSFOが機能しない、またはネットワーク分断時に誤った判断を下す可能性がある。両データベースでフラッシュバックを有効にする必要がある。しきい値が低すぎると、短いネットワーク瞬断が不要なフェイルオーバーになる。計画メンテナンスでは、プライマリ停止前にDISABLE FAST_START FAILOVERを実行するか、Observerを考慮する。","since":"12c","note":"FASTSYNCは12.2以降、IN BACKGROUNDと複数Observer(SHOW OBSERVER)は12.2以降。IN BACKGROUNDにはOracle Wallet(mkstore)の資格証明が必要。","tags":["data guard","fsfo","fast-start failover","observer","automatic failover","maxavailability","dgmgrl"],"untested":true},{"id":"dg-snapshot-standby","task":"フィジカルスタンバイをスナップショットスタンバイに変換し、元に戻す(テスト環境)","category":"Data Guard","command":"# Make the standby read-write (redo is still received, apply stops):\nCONVERT DATABASE '<standby_db_unique_name>' TO SNAPSHOT STANDBY;\nSHOW DATABASE '<standby_db_unique_name>';\n# ... testing / application validation ...\n# Convert back: all test changes are discarded, accumulated redo is applied\nCONVERT DATABASE '<standby_db_unique_name>' TO PHYSICAL STANDBY;\nSHOW CONFIGURATION;","what":"スタンバイに自動的に保証付きリストアポイントを作成し、読み取り/書き込みでオープンする。元に戻すときはそのポイントまでフラッシュバックし、プライマリから蓄積されたREDOを適用する。","when":"別のコピーを作成せずに、本番データでアップグレードのリハーサル、アプリケーションリリースのテスト、Real Application Testing(DB Replay)を実行するため。","caution":"スナップショットスタンバイの間はREDOが適用されない。RPOは保たれるが、フェイルオーバー時間(RTO)は蓄積REDOとともに増大し、FSFOのターゲットにもなれない。フラッシュバックログがFRAを使い切る可能性があるため、FRA領域を監視する。スナップショットで行った変更は、元に戻すときに完全に破棄される。","note":"SQLでの同等の方法: ALTER DATABASE CONVERT TO SNAPSHOT STANDBY / CONVERT TO PHYSICAL STANDBY(Brokerなし)。","tags":["data guard","snapshot standby","test","restore point","flashback","convert","dgmgrl"],"untested":true},{"id":"rman-catalog-create","task":"RMANリカバリカタログを作成し、データベースを登録","category":"RMAN","command":"-- 1) In the catalog database (separate DB/PDB), with sqlplus:\nCREATE TABLESPACE rcat_ts DATAFILE '/u02/oradata/RCAT/rcat01.dbf' SIZE 1G AUTOEXTEND ON NEXT 256M;\nCREATE USER rcat IDENTIFIED BY \"<password>\"\n  DEFAULT TABLESPACE rcat_ts QUOTA UNLIMITED ON rcat_ts;\nGRANT RECOVERY_CATALOG_OWNER TO rcat;\n# 2) From the shell: create the catalog schema\nrman catalog rcat@<rcat_tns>\nCREATE CATALOG;\n# 3) Register the target database and verify:\nrman target / catalog rcat@<rcat_tns>\nREGISTER DATABASE;\nREPORT SCHEMA;\n# Resync controlfile records into the catalog (done automatically after backups):\nRESYNC CATALOG;","what":"制御ファイルの保持期間(control_file_record_keep_time)に依存せず、バックアップメタデータを中央スキーマに格納するリカバリカタログを構築し、ターゲットデータベースを登録する。","when":"多数のデータベースのバックアップ履歴を一元管理する、Data Guardでプライマリ/スタンバイのバックアップを相互に利用する、長期(KEEP)バックアップやストアドスクリプトを使用するため。","caution":"カタログデータベースは保護対象データベースとは別のサーバーに置き、それ自体もバックアップする。カタログスキーマのバージョンは使用中の最新RMANクライアントより低くできない。新しいクライアントにはUPGRADE CATALOGが必要。Data Guardではプライマリのみを登録し、スタンバイはCONFIGURE DB_UNIQUE_NAME ... CONNECT IDENTIFIERでDB_UNIQUE_NAMEにより定義する。","note":"カタログスキーマは別のデータベースに置く。ターゲットと同居させると、災害時にカタログも失われる。","tags":["rman","catalog","catalog","recovery catalog","register","backup","backup"],"untested":true},{"id":"rman-duplicate-standby","task":"RMAN DUPLICATEでアクティブデータベースからフィジカルスタンバイを作成","category":"RMAN","command":"# Prerequisites: standby instance in NOMOUNT with a pfile containing only db_name,\n# primary password file copied, static listener entries and tnsnames on both sides.\nrman target sys@<primary_tns> auxiliary sys@<standby_tns>\nRUN {\n  ALLOCATE CHANNEL p1 DEVICE TYPE DISK;\n  ALLOCATE CHANNEL p2 DEVICE TYPE DISK;\n  ALLOCATE AUXILIARY CHANNEL s1 DEVICE TYPE DISK;\n  ALLOCATE AUXILIARY CHANNEL s2 DEVICE TYPE DISK;\n  DUPLICATE TARGET DATABASE FOR STANDBY FROM ACTIVE DATABASE\n    USING COMPRESSED BACKUPSET SECTION SIZE 32G\n    DORECOVER\n    SPFILE\n      SET db_unique_name='<standby_db_unique_name>'\n      SET control_files='+DATA','+FRA'\n      SET db_create_file_dest='+DATA'\n      SET db_recovery_file_dest='+FRA'\n      SET fal_server='<primary_tns>'\n      SET log_archive_dest_2=''\n      SET dg_broker_start='FALSE'\n    NOFILENAMECHECK;\n}","what":"プライマリのデータファイルをネットワーク経由でスタンバイサーバーへコピーし(中間バックアップファイルなし)、スタンバイ用に調整したspfileを作成し、DORECOVERで利用可能なアーカイブログを適用する。","when":"新しいData Guardスタンバイの構築時、またはreinstateできないスタンバイの再構築時に。","caution":"プライマリにネットワークとI/Oの負荷がかかる。ピーク時間帯に実行しない、またはチャネル数を制限する。NOFILENAMECHECKはスタンバイが別のサーバーにある場合にのみ安全。同じサーバーではプライマリのファイルを上書きする可能性がある。前後にスタンバイREDOログ(プライマリのオンラインREDOと同サイズ、スレッドごとに1グループ追加)を追加し、Brokerを構成する。","since":"12c","note":"USING [COMPRESSED] BACKUPSETとSECTION SIZEを使用したアクティブ複製は12c以降。11gはイメージコピーを使用する。ASMではなくファイルシステムを使用する場合は、db_file_name_convert/log_file_name_convertを設定する。","tags":["rman","duplicate","standby","active database","data guard","setup","clone"],"untested":true},{"id":"rman-crosscheck-cleanup","task":"RMANバックアップレコードの検証とクリーンアップ(CROSSCHECK、EXPIRED、OBSOLETE)","category":"RMAN","command":"SHOW RETENTION POLICY;\n# 1) Compare records with the physical files (missing ones become EXPIRED):\nCROSSCHECK BACKUP;\nCROSSCHECK COPY;\nCROSSCHECK ARCHIVELOG ALL;\n# 2) Review before deleting:\nLIST EXPIRED BACKUP;\nLIST EXPIRED ARCHIVELOG ALL;\nREPORT OBSOLETE;\n# 3) Clean up:\nDELETE NOPROMPT EXPIRED BACKUP;\nDELETE NOPROMPT EXPIRED COPY;\nDELETE NOPROMPT EXPIRED ARCHIVELOG ALL;\nDELETE NOPROMPT OBSOLETE;","what":"CROSSCHECKはRMANレコード上のバックアップがディスク/テープ上にまだ存在するかを確認する。DELETE EXPIREDは存在しないファイルのレコードを削除し、DELETE OBSOLETEは保存ポリシー上不要になったバックアップをレコードとディスクの両方から削除する。","when":"OSレベルでバックアップファイルが削除/移動されたとき、FRAが満杯になったとき、定期的なバックアップメンテナンスジョブの一部として。","caution":"DELETE OBSOLETEはファイルを物理的に削除する。まずREPORT OBSOLETEで一覧を確認し、保存ポリシー(RECOVERY WINDOW / REDUNDANCY)が想定どおりであることを確認する。テープ/メディアマネージャに一時的に到達できないときにCROSSCHECKを実行すると、有効なバックアップがEXPIREDと表示される。その時点でDELETE EXPIREDを実行しない。","note":"Data Guardでは、アーカイブログの削除にCONFIGURE ARCHIVELOG DELETION POLICY TO APPLIED ON ALL STANDBYを使用する。","tags":["rman","crosscheck","expired","obsolete","cleanup","retention","backup"],"untested":true},{"id":"rman-validate","task":"データベースとバックアップの破損を検証(VALIDATE)","category":"RMAN","command":"# Physical + logical block check (without producing a backup):\nVALIDATE CHECK LOGICAL DATABASE;\n# Scan large datafiles in parallel (11g+, needs multiple channels):\nVALIDATE CHECK LOGICAL DATABASE SECTION SIZE 16G;\n# A single datafile / tablespace:\nVALIDATE DATAFILE 7;\nVALIDATE TABLESPACE users;\n# Read as if taking a backup and check (including archivelogs):\nBACKUP VALIDATE CHECK LOGICAL DATABASE ARCHIVELOG ALL;\n# Readability of a specific backup set:\nLIST BACKUP SUMMARY;\nVALIDATE BACKUPSET <bs_key>;\n-- Corrupt blocks found and the affected segment (SQL):\nSELECT file#, block#, blocks, corruption_change#, corruption_type\nFROM   v$database_block_corruption ORDER BY file#, block#;\nSELECT DISTINCT e.owner, e.segment_name, e.segment_type\nFROM   dba_extents e\nJOIN   v$database_block_corruption c\n  ON   e.file_id = c.file#\n AND   c.block# BETWEEN e.block_id AND e.block_id + e.blocks - 1;","what":"データファイルとバックアップセットを読み取り、物理的なブロック破損および(CHECK LOGICALで)論理的なブロック破損を検出し、結果をv$database_block_corruptionに記録する。SQLクエリで破損ブロックがどの表/インデックスに属するかを表示する。","when":"ORA-01578/ORA-08103などの破損エラーの後、ストレージ問題の後、定期的な(週次)整合性チェックとして。バックアップが実際にリストア可能であることの証明に。","caution":"全体を読み取るため、大規模データベースでは大量のI/Oが発生する。ピーク時間帯以外に実行する。dba_extentsのクエリは大規模データベースでは遅い場合がある。破損ブロックが一時(TEMP)領域や空き領域にある場合、オブジェクトは一致しない。","since":"11g","note":"破損がない場合、クエリは行を返さない。SECTION SIZEを指定したVALIDATEは11g以降。","tags":["rman","validate","corruption","corruption","check logical","block","ora-01578"],"untested":true},{"id":"rman-restore-preview","task":"リストアで使用されるバックアップを確認し検証(PREVIEW / VALIDATE)","category":"RMAN","command":"# Backups and archivelogs a restore needs (without reading the files):\nRESTORE DATABASE PREVIEW SUMMARY;\n# For a return to a point in time:\nRESTORE DATABASE UNTIL TIME \"TO_DATE('2026-01-15 03:00:00','YYYY-MM-DD HH24:MI:SS')\" PREVIEW;\n# Validate the backups by actually reading them (without restoring):\nRESTORE DATABASE VALIDATE;\nRESTORE ARCHIVELOG FROM TIME 'SYSDATE-1' VALIDATE;\nRESTORE CONTROLFILE VALIDATE;\nRESTORE SPFILE VALIDATE;","what":"PREVIEWは、リストアで使用されるバックアップセット/コピーとアーカイブログの範囲をカタログ/制御ファイルから報告する。VALIDATEはそれらのバックアップを実際に読み取り、破損や欠落ファイルがないことを検証する。","when":"実際のリストア前の計画、バックアップ戦略がRPO目標を満たすことの証明、定期的なリストアテストとして。","caution":"PREVIEWはレコードのみを参照する。ファイルが削除されている場合は誤解を招くため、先にCROSSCHECKを実行するかRESTORE ... VALIDATEを使用する。VALIDATEはバックアップ全体を読み取るため、テープ/ネットワーク経由では時間がかかる場合がある。日付はセッションのNLS設定ではなくTO_DATEのマスクに依存させる。","note":"PREVIEW RECALLはテープから呼び戻す必要のあるバックアップの要求も可能(メディアマネージャの対応が必要)。","tags":["rman","restore","preview","validate","restore test","backup","rpo"],"untested":true},{"id":"rman-block-media-recovery","task":"破損ブロックをオンラインで修復(ブロックメディアリカバリ、RECOVER CORRUPTION LIST)","category":"RMAN","command":"# 1) Detect corrupt blocks (populates v$database_block_corruption):\nVALIDATE CHECK LOGICAL DATABASE;\n# 2) Repair all blocks in the list (the datafile stays online):\nRECOVER CORRUPTION LIST;\n# or the file/block from the error message (ORA-01578: file# 7, block# 233):\nRECOVER DATAFILE 7 BLOCK 233;\nRECOVER DATAFILE 7 BLOCK 233 DATAFILE 9 BLOCK 1001;\n# 3) Verify:\nVALIDATE DATAFILE 7;\nSELECT * FROM v$database_block_corruption;","what":"破損ブロックのみをバックアップ(またはフラッシュバックログ/Active Data Guardスタンバイ)からリストアし、REDOでロールフォワードする。データファイルと表領域はオンラインのままで、アプリケーションはそのブロックに触れたときのみエラーになる。","when":"ORA-01578 / ORA-01110で局所的なブロック破損が発生したとき。データファイル全体のリストアでは不要な停止時間が発生するとき。","caution":"そのブロックを含むクリーンなバックアップと、それ以降現在までのすべてのアーカイブログが必要。NOLOGGING操作による破損(ORA-26040)はこの方法では修復できず、オブジェクトを再構築する必要がある。Enterprise Editionの機能。破損の原因(ストレージ、HBA、ファームウェア)を特定しなければ再発する。","note":"Active Data Guardでは、11.2以降の自動ブロックメディアリカバリがスタンバイから破損ブロックを自動的に修復する。","tags":["rman","block recovery","corrupt block","corruption","ora-01578","recover","repair"],"untested":true},{"id":"rman-tspitr","task":"表領域を過去の時点に戻す(TSPITR)","category":"RMAN","command":"-- 1) Is the tablespace self-contained (SQL, on the target DB):\nEXEC DBMS_TTS.TRANSPORT_SET_CHECK(ts_list => 'USERS', incl_constraints => TRUE, full_check => TRUE);\nSELECT * FROM transport_set_violations;\n-- 2) Objects created AFTER the target time that TSPITR will lose:\nSELECT owner, name, tablespace_name,\n       TO_CHAR(creation_time,'YYYY-MM-DD HH24:MI:SS') AS created\nFROM   ts_pitr_objects_to_be_dropped\nWHERE  tablespace_name = 'USERS'\n  AND  creation_time > TO_DATE('2026-01-15 03:00:00','YYYY-MM-DD HH24:MI:SS');\n# 3) RMAN: with an automatic auxiliary instance\nRECOVER TABLESPACE users\n  UNTIL TIME \"TO_DATE('2026-01-15 03:00:00','YYYY-MM-DD HH24:MI:SS')\"\n  AUXILIARY DESTINATION '/u03/aux';\n# 4) The tablespace is left OFFLINE: take a backup first, then bring it online\nBACKUP TABLESPACE users;\nALTER TABLESPACE users ONLINE;","what":"RMANが一時的な補助インスタンスでSYSTEM/UNDO/SYSAUXとターゲット表領域を指定時刻までリカバリし、トランスポータブル表領域でターゲットデータベースに戻す。データベースの他の部分は最新のまま。","when":"誤ったバッチジョブや誤ったDROP/TRUNCATEが1つの表領域(または自己完結した表領域セット)のデータのみを損傷し、フラッシュバックの選択肢では不十分な場合。","caution":"その表領域で行われたすべての変更と、ターゲット時刻以降に作成されたすべてのオブジェクトが失われる。表領域セットは自己完結している必要がある(他の表領域にインデックス/表、パーティション、LOB、FKがないこと)。SYSTEM、UNDO、SYSオブジェクトを含む表領域には使用できない。TSPITR後、その表領域の以前のバックアップは使用できないため、直ちにバックアップを取得する。AUXILIARY DESTINATIONにはSYSTEM+SYSAUX+UNDO+ターゲット表領域分の空き領域が必要。","note":"単一の表であれば、rman-recover-tableの方が影響が小さい。","tags":["rman","tspitr","tablespace","pitr","point-in-time","auxiliary","rollback"],"untested":true},{"id":"rman-recover-table","task":"RMANバックアップから単一の表を過去の時点にリカバリ(RECOVER TABLE)","category":"RMAN","command":"# Restore under a new name (the original table is not touched):\nRECOVER TABLE hr.employees\n  UNTIL TIME \"TO_DATE('2026-01-15 03:00:00','YYYY-MM-DD HH24:MI:SS')\"\n  AUXILIARY DESTINATION '/u03/aux'\n  REMAP TABLE hr.employees:employees_rec;\n# Multitenant: a table inside a PDB\nRECOVER TABLE hr.employees OF PLUGGABLE DATABASE <pdb>\n  UNTIL SCN 12345678\n  AUXILIARY DESTINATION '/u03/aux'\n  REMAP TABLE hr.employees:employees_rec;\n# Only produce a Data Pump dump, do not import:\nRECOVER TABLE hr.employees\n  UNTIL SCN 12345678\n  AUXILIARY DESTINATION '/u03/aux'\n  DATAPUMP DESTINATION '/u03/dump'\n  DUMP FILE 'employees_rec.dmp'\n  NOTABLEIMPORT;","what":"RMANが自動補助インスタンスを指定時刻までリカバリし、表(またはパーティション)をData Pumpでエクスポートし、REMAPで別名としてターゲットデータベースにインポートする。その後、補助インスタンスは削除される。","when":"誤って削除/更新された、またはPURGE付きで削除された単一表のデータを、Flashback Table/QueryのUNDO保存期間を超えてリカバリするため。","caution":"AUXILIARY DESTINATIONにはSYSTEM、SYSAUX、UNDO、および表の表領域分の空き領域が必要。操作には数時間かかる場合がある。REMAP TABLEなしでは同名の表が存在すると操作は失敗する。元の表の上書きを避けるため、常にREMAPまたはNOTABLEIMPORTを使用する。SYS/SYSTEMスキーマの表、およびSYSTEM/SYSAUX表領域の表はこの方法ではリカバリできない。Enterprise Editionが必要。","since":"12c","note":"必要なもの: 全体バックアップと、ターゲット時刻をカバーするアーカイブログ。パーティションの場合: RECOVER TABLE hr.sales:p2025 ... REMAP TABLE hr.sales:p2025:sales_p2025_rec。","tags":["rman","recover table","table recovery","pitr","auxiliary","remap","accidental delete"],"untested":true},{"id":"pdb-create-from-seed","task":"PDB$SEEDから新しいPDBを作成","category":"Multitenant","command":"-- In CDB$ROOT, as SYSDBA:\nCREATE PLUGGABLE DATABASE <pdb>\n  ADMIN USER pdbadmin IDENTIFIED BY \"<password>\" ROLES = (DBA)\n  DEFAULT TABLESPACE users\n    DATAFILE '/u02/oradata/<cdb>/<pdb>/users01.dbf' SIZE 512M AUTOEXTEND ON NEXT 64M\n  FILE_NAME_CONVERT = ('/u02/oradata/<cdb>/pdbseed/', '/u02/oradata/<cdb>/<pdb>/')\n  STORAGE (MAXSIZE 50G);\n-- With OMF/ASM, instead of FILE_NAME_CONVERT: CREATE_FILE_DEST = '+DATA'\nALTER PLUGGABLE DATABASE <pdb> OPEN;\nALTER PLUGGABLE DATABASE <pdb> SAVE STATE;\nSELECT con_id, name, open_mode, restricted FROM v$pdbs ORDER BY con_id;","what":"シードテンプレートから空の新しいプラガブルデータベースを作成する。同じコマンドでローカル管理ユーザー、デフォルト表領域、合計サイズ上限を定義する。","when":"新しいアプリケーション/スキーマ用に分離されたデータベースを用意するとき。テスト・開発環境の準備時。","caution":"新しいPDBはMOUNTEDで起動するため、OPENとSAVE STATE(CDB再起動後もオープン状態を維持するため)が必要。FILE_NAME_CONVERTのパスが誤っているとファイルが誤ったディレクトリに書き込まれる。OMFなしではDATAFILEに完全なファイルパスが必須(ORA-02236)。ライセンス: 19c EEではMultitenantオプションなしでCDBあたり3つのユーザーPDBを使用できる。","since":"12c","note":"RACではsrvctl add service -pdbでPDBにアプリケーションサービスを追加する。","tags":["multitenant","pdb","create","create pluggable database","seed","cdb","pdb$seed"]},{"id":"pdb-clone-local","task":"同じCDB内でPDBをクローン(ローカル/ホットクローン)","category":"Multitenant","command":"-- Hot clone prerequisites: local undo + ARCHIVELOG\nSELECT property_value AS local_undo\nFROM   database_properties WHERE property_name = 'LOCAL_UNDO_ENABLED';\nSELECT log_mode FROM v$database;\n\nCREATE PLUGGABLE DATABASE <new_pdb> FROM <pdb>\n  FILE_NAME_CONVERT = ('/<pdb>/', '/<new_pdb>/');\n-- OMF/ASM: CREATE PLUGGABLE DATABASE <new_pdb> FROM <pdb> CREATE_FILE_DEST = '+DATA';\nALTER PLUGGABLE DATABASE <new_pdb> OPEN;\nSELECT name, open_mode FROM v$pdbs WHERE name = UPPER('<new_pdb>');","what":"ソースPDBのデータファイルをコピーして同じCDB内に新しいPDBを作成する。ローカルUNDOとARCHIVELOGがあれば、ソースが読み取り/書き込みでオープン中でも実行できる(ホットクローン)。","when":"本番PDBのテスト/開発用コピーの作成、アップグレードやパッチのリハーサル、リスクのある変更前の迅速なコピー取得に。","caution":"コピーはソースに追加のI/Oを発生させ、ターゲットにはソースと同じだけの領域が必要。共有UNDOモードまたはNOARCHIVELOGでは、ソースはREAD ONLYである必要がある(19cドキュメント)。クローンには本番データが含まれる。オープン前にマスキング、DBリンク、ジョブ(DBMS_SCHEDULER)、外部システムへの接続を確認する。","since":"12c","note":"ソースが読み取り/書き込みのままのホットクローンには、19cではローカルUNDO + ARCHIVELOGが必要。高速なシンコピーにはSNAPSHOT COPYを使用する(対応するストレージが必要)。","tags":["multitenant","pdb","clone","clone","hot clone","copy","local undo"]},{"id":"pdb-clone-remote","task":"DBリンク経由で別のCDBからPDBをクローン(リモートクローン)","category":"Multitenant","command":"-- 1) In the SOURCE CDB, a common user:\nCREATE USER c##clone_user IDENTIFIED BY \"<password>\" CONTAINER = ALL;\nGRANT CREATE SESSION, CREATE PLUGGABLE DATABASE TO c##clone_user CONTAINER = ALL;\n\n-- 2) In the TARGET CDB root, DB link and test:\nCREATE DATABASE LINK clone_link\n  CONNECT TO c##clone_user IDENTIFIED BY \"<password>\"\n  USING '//<source_host>:1521/<source_cdb_service>';\nSELECT * FROM dual@clone_link;\n\n-- 3) Clone and open:\nCREATE PLUGGABLE DATABASE <new_pdb> FROM <pdb>@clone_link\n  FILE_NAME_CONVERT = ('/<pdb>/', '/<new_pdb>/');\nALTER PLUGGABLE DATABASE <new_pdb> OPEN;\n\n-- 4) Violations (version, options, parameters, patches):\nSELECT name, cause, type, message\nFROM   pdb_plug_in_violations\nWHERE  name = UPPER('<new_pdb>') AND status <> 'RESOLVED';","what":"DBリンクを通じてネットワーク経由でソースCDBからターゲットCDBへPDBをコピーする。中間ファイルやアンプラグは不要。","when":"PDBを別のサーバー/CDBへ移動する、別サーバーに本番のテストコピーを作成する、新しいリリースのCDBへ移行するため。","caution":"ソースとターゲットのCDBは、エンディアン、キャラクタセット(またはターゲットがAL32UTF8)、オプションで互換性がある必要がある。新しいリリースにクローンしたPDBは最初RESTRICTEDでオープンし、datapatch/upgradeが必要。クローン完了後はDBリンクと共通ユーザーを削除する。ホットクローンにはソースでローカルUNDO + ARCHIVELOGが必要。","since":"12c","note":"移動する(ソースを削除する)場合は12.2以降のRELOCATEオプションを使用する: CREATE PLUGGABLE DATABASE <pdb> FROM <pdb>@clone_link RELOCATE。","tags":["multitenant","pdb","remote clone","db link","clone","migration","relocate"]},{"id":"pdb-unplug-plug","task":"PDBをアンプラグし、別の(または同じ)CDBにプラグイン","category":"Multitenant","command":"-- SOURCE CDB: close and unplug to an XML manifest\nALTER PLUGGABLE DATABASE <pdb> CLOSE IMMEDIATE;\nALTER PLUGGABLE DATABASE <pdb> UNPLUG INTO '/u01/stage/<pdb>.xml';\n-- (Single-file archive: UNPLUG INTO '/u01/stage/<pdb>.pdb' - includes datafiles, 12.2+)\nDROP PLUGGABLE DATABASE <pdb> KEEP DATAFILES;\n\n-- TARGET CDB: check compatibility first\nSET SERVEROUTPUT ON\nDECLARE\n  l_ok BOOLEAN;\nBEGIN\n  l_ok := DBMS_PDB.CHECK_PLUG_COMPATIBILITY(\n            pdb_descr_file => '/u01/stage/<pdb>.xml',\n            pdb_name       => '<pdb>');\n  DBMS_OUTPUT.PUT_LINE(CASE WHEN l_ok THEN 'COMPATIBLE' ELSE 'NOT COMPATIBLE - see PDB_PLUG_IN_VIOLATIONS' END);\nEND;\n/\nSELECT name, cause, type, status, message\nFROM   pdb_plug_in_violations\nWHERE  name = UPPER('<pdb>') AND status <> 'RESOLVED';\n\n-- NOCOPY if the files stay in place, COPY FILE_NAME_CONVERT if they move:\nCREATE PLUGGABLE DATABASE <pdb> USING '/u01/stage/<pdb>.xml' NOCOPY TEMPFILE REUSE;\n-- From a .pdb archive: CREATE PLUGGABLE DATABASE <pdb> USING '/u01/stage/<pdb>.pdb'\n--                    FILE_NAME_CONVERT = ('/u01/stage/', '/u02/oradata/<cdb>/<pdb>/');\nALTER PLUGGABLE DATABASE <pdb> OPEN;","what":"PDBをCDBから切り離し、メタデータをXMLマニフェスト(またはデータファイルを含む単一の.pdbアーカイブ)に書き出す。互換性チェック後、同じファイルでターゲットCDBにプラグインする。","when":"同じサーバー上の新しいリリースのCDBへPDBを移動する(アンプラグ/プラグによるアップグレード)、CDBの統合、ネットワーク経由のクローンができない移動に。","caution":"アンプラグ後、PDBはソースCDBで使用できない(停止時間)。NOCOPYでプラグインしたファイルはターゲットCDBに属するため、失敗時に切り戻せるよう事前にファイルレベルのコピーまたはRMANバックアップを取得する。ERRORタイプの違反が解決されるまでPDBはRESTRICTEDでオープンする。同じCDBに再度プラグインする場合、AS CLONEを省略するとGUIDの競合が発生する可能性がある。","since":"12c","note":".pdbアーカイブ(12.2以降)はデータファイルを含むため単一ファイルとして移動できる。XML方式ではデータファイルを別途コピーする。","tags":["multitenant","pdb","unplug","plug","migration","xml manifest","check_plug_compatibility"]},{"id":"pdb-open-save-state","task":"PDBをオープンし、CDB再起動後もオープン状態を維持(SAVE STATE)","category":"Multitenant","command":"-- Open all PDBs (RAC: INSTANCES = ALL):\nALTER PLUGGABLE DATABASE ALL OPEN;\n-- ALTER PLUGGABLE DATABASE <pdb> OPEN INSTANCES = ALL;\n-- Save the current open state (opens automatically after a CDB restart):\nALTER PLUGGABLE DATABASE <pdb> SAVE STATE;\n-- Saved states:\nSELECT con_name, instance_name, state, restricted FROM dba_pdb_saved_states;\n-- Remove the saved state:\nALTER PLUGGABLE DATABASE <pdb> DISCARD STATE;\n-- If it opens RESTRICTED, find the reason:\nSELECT name, cause, type, message\nFROM   pdb_plug_in_violations\nWHERE  status <> 'RESOLVED';","what":"PDBをREAD WRITEでオープンし、現在のオープン状態を保存して、CDB再起動時にPDBが同じモードで自動的にオープンするようにする。","when":"PDBの作成、プラグイン、クローン後。CDB再起動後にPDBがMOUNTEDのままになることに気付いたとき。","caution":"SAVE STATEはコマンド実行時の状態を記録する。PDBがクローズ中に実行すると「クローズ」状態が記録される(またはレコードが削除される)。RACでは状態はインスタンスごと。サービスベースの管理(srvctlによるPDBサービス)では、SAVE STATEよりClusterwareによる起動が推奨される。Data Guardスタンバイではオープンモードはロールに依存する。","since":"12c","note":"12.1.0.2+.","tags":["multitenant","pdb","open","save state","auto open","restricted","dba_pdb_saved_states"]},{"id":"pdb-resource-limits","task":"PDBごとのCPU、メモリ、I/O、ストレージの上限を設定","category":"Multitenant","command":"ALTER SESSION SET CONTAINER = <pdb>;\n-- CPU (instance caging with Resource Manager; at PDB level in 19c):\nALTER SYSTEM SET cpu_count = 2 SCOPE = BOTH;\n-- Memory (sga_min_size guarantee, sga_target upper limit):\nALTER SYSTEM SET sga_target = 512M SCOPE = BOTH;\nALTER SYSTEM SET sga_min_size = 96M SCOPE = BOTH;\nALTER SYSTEM SET pga_aggregate_limit = 2G SCOPE = BOTH;\n-- I/O (non-Exadata):\nALTER SYSTEM SET max_iops = 5000 SCOPE = BOTH;\nALTER SYSTEM SET max_mbps = 200 SCOPE = BOTH;\n-- Number of sessions (after the PDB is reopened):\nALTER SYSTEM SET sessions = 200 SCOPE = SPFILE;\n-- Storage:\nALTER PLUGGABLE DATABASE STORAGE (MAXSIZE 10G MAX_SHARED_TEMP_SIZE 2G);\n\n-- Settings across all PDBs, from the root:\nALTER SESSION SET CONTAINER = CDB$ROOT;\nSELECT p.name AS pdb, sp.name, sp.value\nFROM   v$system_parameter sp JOIN v$pdbs p ON p.con_id = sp.con_id\nWHERE  sp.name IN ('cpu_count','sga_target','sga_min_size','max_iops','max_mbps','pga_aggregate_limit')\nORDER  BY p.name, sp.name;","what":"PDBレベルのパラメータにより、PDBがCDBから使用できるCPU、SGA/PGA、IOPS/MBPS、合計ストレージを制限する。「うるさい隣人」となるPDBが他に影響するのを防ぐ。","when":"統合CDBで、異なるSLAのアプリケーションを同じCDBで実行するとき、またはPDBがサーバー全体を使い切っているのが見られるとき。","caution":"PDBのsga_targetはCDBのsga_targetより小さくする必要がある。値が低すぎるとORA-04031や性能問題が発生する。sga_min_sizeの合計がCDBのSGA全体を確保してはならない。PDBのcpu_countを有効にするには、CDBでリソースマネージャプランが有効である必要がある。MAXSIZEに達するとPDBでORA-65114が発生する。","since":"12c","note":"23aiではsga_min_sizeをsga_targetの20%未満にする必要がある(ORA-56746)。19cでの上限は50%。MAX_IOPS/MAX_MBPSは12.2以降、PDBのメモリパラメータは12.2以降。","tags":["multitenant","pdb","resource","resource","cpu_count","sga_target","maxsize"]},{"id":"pdb-container-context","task":"現在のコンテナを確認し、ルートから全PDBを照会する(CDB_ / CONTAINERS)","category":"Multitenant","command":"-- Current container:\nSHOW CON_NAME\nSHOW CON_ID\nSHOW PDBS\nSELECT SYS_CONTEXT('USERENV','CON_NAME') AS con_name,\n       SYS_CONTEXT('USERENV','CON_ID')   AS con_id\nFROM   dual;\n\n-- All containers, from the root:\nSELECT con_id, name, open_mode FROM v$containers ORDER BY con_id;\n\n-- CDB_ views combine all open PDBs with CON_ID:\nSELECT c.name AS container, t.tablespace_name, t.status\nFROM   cdb_tablespaces t JOIN v$containers c ON c.con_id = t.con_id\nORDER  BY c.name, t.tablespace_name;\n\n-- Query any table/view across all PDBs with CONTAINERS():\nSELECT con_id, COUNT(*) AS users\nFROM   CONTAINERS(dba_users)\nGROUP  BY con_id ORDER BY con_id;","what":"セッションが接続しているコンテナを表示する。ルートからは、CDB_ビューとCONTAINERS()句により、オープン中の全PDBのディクショナリ情報を1つのクエリで収集する。","when":"DDL/パラメータ変更前に正しいコンテナにいることの確認、全PDBにわたる領域、ユーザー、オブジェクトの棚卸しに。","caution":"読み取り専用。ルート(CDB$ROOT)にアプリケーションオブジェクトやローカルユーザーを誤って作成しない。ルートでのALTER SYSTEMはCDB全体に影響する。CDB_ビューとCONTAINERS()はオープン中のPDBのみを返し、MOUNTEDのPDBは結果に表示されない。","since":"12c","note":"コンテナの切り替え: ALTER SESSION SET CONTAINER = <pdb>;(rosettaの「Change the active database」を参照)。","tags":["multitenant","container","con_name","cdb_","containers","pdb","root"]},{"id":"pdb-refreshable-clone","task":"リフレッシュ可能PDBを作成・リフレッシュし、独立したPDBに変換","category":"Multitenant","command":"-- In the target CDB root (DB link to the source ready: see pdb-clone-remote):\nCREATE PLUGGABLE DATABASE <new_pdb> FROM <pdb>@clone_link\n  FILE_NAME_CONVERT = ('/<pdb>/', '/<new_pdb>/')\n  REFRESH MODE EVERY 60 MINUTES;\nSELECT pdb_name, status, refresh_mode, refresh_interval, last_refresh_scn\nFROM   dba_pdbs WHERE pdb_name = UPPER('<new_pdb>');\n\n-- Can only be opened READ ONLY; close it first to refresh manually:\nALTER PLUGGABLE DATABASE <new_pdb> OPEN READ ONLY;\nALTER PLUGGABLE DATABASE <new_pdb> CLOSE IMMEDIATE;\nALTER PLUGGABLE DATABASE <new_pdb> REFRESH;\n\n-- Change the mode (MANUAL) or convert to an independent, writable PDB (irreversible):\nALTER PLUGGABLE DATABASE <new_pdb> REFRESH MODE MANUAL;\nALTER PLUGGABLE DATABASE <new_pdb> REFRESH MODE NONE;\nALTER PLUGGABLE DATABASE <new_pdb> OPEN;","what":"ソースPDBのREDOを定期的またはオンデマンドで適用して最新に保たれるコピーを作成する。レポート用にREAD ONLYでオープンし、REFRESH MODE NONEで独立した読み取り/書き込みPDBになる。","when":"定期的にリフレッシュされる本番のレポート/テスト用コピー、短い停止時間でのPDB移行(最終リフレッシュ + REFRESH MODE NONE)、「安価なPDBレベルのスタンバイ」に。","caution":"リフレッシュ中はPDBをクローズしておく必要がある。READ ONLYでオープン中は自動リフレッシュが待機する。リフレッシュに必要なアーカイブログにソースでアクセスできる必要がある。REFRESH MODE NONEは元に戻せず、以後コピーをリフレッシュできない。ソースでローカルUNDO + ARCHIVELOGが必要。本来のDRとしてのData Guardの代替にはならない。","since":"12c","note":"12.2以降。REFRESH MODE NONEの後、クローンは通常のPDBとなりREAD WRITEでオープンできる。これは元に戻せない。","tags":["multitenant","pdb","refreshable","refresh","refresh","reporting","clone"]}]},"recipes/oracle-ops.json":{"engineId":"oracle","engine":"Oracle","order":2,"recipes":[{"id":"awr-snapshot-report","task":"AWRスナップショットを取得し、2つのスナップショット間のAWRレポートを生成","category":"パフォーマンス","command":"-- 1) Manual snapshot before and after the event (run in CDB root):\nEXEC DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT;\n\n-- 2) List snapshots:\nSELECT snap_id,\n       TO_CHAR(begin_interval_time,'YYYY-MM-DD HH24:MI') AS begin_time,\n       TO_CHAR(end_interval_time,'YYYY-MM-DD HH24:MI')   AS end_time\nFROM   dba_hist_snapshot\nWHERE  dbid = (SELECT dbid FROM v$database)\nORDER  BY snap_id DESC\nFETCH FIRST 24 ROWS ONLY;\n\n-- 3a) Interactive report (prompts for HTML/TEXT and snapshot range):\n-- @?/rdbms/admin/awrrpt.sql      (RAC: awrgrpt.sql, specific instance: awrrpti.sql)\n\n-- 3b) TEXT report from a script:\nSET LINESIZE 8000 PAGESIZE 0 TRIMSPOOL ON HEADING OFF FEEDBACK OFF\nSPOOL /tmp/awr_<begin_snap>_<end_snap>.txt\nSELECT output\nFROM   TABLE(DBMS_WORKLOAD_REPOSITORY.AWR_REPORT_TEXT(\n         l_dbid     => (SELECT dbid FROM v$database),\n         l_inst_num => (SELECT instance_number FROM v$instance),\n         l_bid      => <begin_snap>,\n         l_eid      => <end_snap>));\nSPOOL OFF\n-- For HTML: DBMS_WORKLOAD_REPOSITORY.AWR_REPORT_HTML (same parameters)","what":"問題の時間帯をカバーする2つのAWRスナップショット間のレポートを生成する: ロードプロファイル、上位待機イベント、上位SQL、インスタンス統計。表関数を使用すると、スクリプトやスケジューラジョブからレポートを取得できる。","when":"特定の時間帯の性能低下の分析、負荷テストやバッチ前後の比較、キャパシティレポートに。","caution":"Diagnostics Packライセンスが必要(CONTROL_MANAGEMENT_PACK_ACCESS='DIAGNOSTIC'または'DIAGNOSTIC+TUNING')。ライセンスがない場合はパラメータを'NONE'に設定し、Statspackを使用する。レポートはインスタンス再起動をまたげない。1時間を超える範囲は平均化されて短いスパイクが隠れるため、時間帯は狭く取る。","note":"PDBレベルのAWR(12.2以降)では、AWR_PDB_AUTOFLUSH_ENABLED=TRUEとAWR_SNAPSHOT_TIME_OFFSET/AWR_PDB_MAX_PARALLEL_SLAVESを確認する。PDB内で取得したレポートにはそのPDBのデータのみが表示される。間隔/保存期間: DBMS_WORKLOAD_REPOSITORY.MODIFY_SNAPSHOT_SETTINGS(interval => 30, retention => 43200)。","tags":["awr","awr report","snapshot","awrrpt","dbms_workload_repository","performance report","diagnostics pack"]},{"id":"awr-diff-report","task":"2つの期間のAWR差分(期間比較)レポート","category":"パフォーマンス","command":"-- Interactive: @?/rdbms/admin/awrddrpt.sql   (RAC: awrgdrpt.sql)\n\n-- From a script: period 1 (good) = <bid1>-<eid1>, period 2 (bad) = <bid2>-<eid2>\nSET LINESIZE 8000 PAGESIZE 0 TRIMSPOOL ON HEADING OFF FEEDBACK OFF\nSPOOL /tmp/awr_diff.txt\nSELECT output\nFROM   TABLE(DBMS_WORKLOAD_REPOSITORY.AWR_DIFF_REPORT_TEXT(\n         dbid1 => (SELECT dbid FROM v$database), inst_num1 => 1,\n         bid1  => <bid1>, eid1 => <eid1>,\n         dbid2 => (SELECT dbid FROM v$database), inst_num2 => 1,\n         bid2  => <bid2>, eid2 => <eid2>));\nSPOOL OFF\n-- HTML: DBMS_WORKLOAD_REPOSITORY.AWR_DIFF_REPORT_HTML","what":"2つのスナップショット範囲を並べ、DB時間、待機イベント、ロードプロファイル、SQLごとの統計の差を百分率で表示する。「昨日は問題なかったが今日は遅い」に直接答える。","when":"アップグレード/パッチ、パラメータ変更、デプロイ、統計収集後の劣化分析。2日間の同じ時間帯の比較に。","caution":"Diagnostics Packライセンスが必要。比較する期間は同じ長さで同程度のワークロードである必要があり、そうでないと差分が誤解を招く。異なるデータベース(例: 本番とテスト)を比較するには、awrextr.sql/awrload.sqlでAWRデータを移動し、対応するdbid2を指定する。","tags":["awr diff","comparison","compare period","awrddrpt","regression","performance","diagnostics pack"]},{"id":"ash-top-activity","task":"直近数分間のASHから上位待機イベントと上位SQLを取得","category":"パフォーマンス","command":"-- Last 30 min: wait event breakdown (each sample ~1 s of active session time)\nSELECT NVL(event, 'ON CPU') AS event, wait_class,\n       COUNT(*) AS samples,\n       ROUND(RATIO_TO_REPORT(COUNT(*)) OVER () * 100, 1) AS pct\nFROM   v$active_session_history\nWHERE  sample_time > SYSTIMESTAMP - INTERVAL '30' MINUTE\nGROUP  BY NVL(event, 'ON CPU'), wait_class\nORDER  BY samples DESC\nFETCH FIRST 10 ROWS ONLY;\n\n-- Last 30 min: top SQL (with CPU / User I/O breakdown)\nSELECT sql_id, sql_opname,\n       COUNT(*) AS samples,\n       SUM(CASE WHEN session_state = 'ON CPU' THEN 1 ELSE 0 END) AS cpu,\n       SUM(CASE WHEN wait_class = 'User I/O' THEN 1 ELSE 0 END)  AS user_io,\n       ROUND(RATIO_TO_REPORT(COUNT(*)) OVER () * 100, 1) AS pct\nFROM   v$active_session_history\nWHERE  sample_time > SYSTIMESTAMP - INTERVAL '30' MINUTE\n  AND  sql_id IS NOT NULL\nGROUP  BY sql_id, sql_opname\nORDER  BY samples DESC\nFETCH FIRST 10 ROWS ONLY;\n\n-- Older periods: DBA_HIST_ACTIVE_SESS_HISTORY (one sample every 10 s; COUNT(*)*10 = seconds)\n\n-- Ready-made ASH report (last 30 min):\nSET LINESIZE 8000 PAGESIZE 0 TRIMSPOOL ON HEADING OFF FEEDBACK OFF\nSELECT output\nFROM   TABLE(DBMS_WORKLOAD_REPOSITORY.ASH_REPORT_TEXT(\n         l_dbid     => (SELECT dbid FROM v$database),\n         l_inst_num => (SELECT instance_number FROM v$instance),\n         l_btime    => SYSDATE - 30/1440,\n         l_etime    => SYSDATE));\n-- Interactive: @?/rdbms/admin/ashrpt.sql","what":"Active Session Historyのサンプルを使用し、直近数分間にどの待機イベントとどのSQL文がDB時間を消費したかを百分率で表示する。AWRスナップショットを待たずにインシデントを診断できる。","when":"性能低下が進行中のとき、AWRの平均では消える短いスパイク、特定のセッションやSQLが何を待っていたかの確認に。","caution":"V$ACTIVE_SESSION_HISTORYとDBA_HIST_ACTIVE_SESS_HISTORYのクエリにはDiagnostics Packライセンスが必要。ASHはサンプリングであり、サンプル数は時間の推定値で正確な測定値ではない。非常に短いSQLは表示されない場合がある。メモリ上のASHバッファは、高負荷システムでは数時間分しか保持しない。","tags":["ash","active session history","top wait","top sql","wait","ashrpt","real-time analysis","diagnostics pack"]},{"id":"addm-task-report","task":"ADDM分析を実行し、レポートを取得","category":"パフォーマンス","command":"-- Analyze the range between two snapshots (in CDB root):\nVAR tname VARCHAR2(60)\nBEGIN\n  :tname := 'ADDM_<begin_snap>_<end_snap>';\n  DBMS_ADDM.ANALYZE_DB(\n    task_name      => :tname,\n    begin_snapshot => <begin_snap>,\n    end_snapshot   => <end_snap>);\nEND;\n/\n\nSET LONG 1000000 LONGCHUNKSIZE 1000000 LINESIZE 200 PAGESIZE 0\nSELECT DBMS_ADDM.GET_REPORT(task_name => :tname) FROM dual;\n\n-- Findings summary (by impact):\nSET PAGESIZE 100\nSELECT finding_name, type, ROUND(impact/1e6) AS impact_sec, message\nFROM   dba_advisor_findings\nWHERE  task_name = :tname\nORDER  BY impact DESC;\n\n-- Interactive alternative: @?/rdbms/admin/addmrpt.sql\n-- Clean up the task when done:\nEXEC DBMS_ADDM.DELETE(task_name => :tname);","what":"Automatic Database Diagnostic Monitorが2つのAWRスナップショット間のDB時間を分析し、ボトルネックとその影響(検出結果)、具体的な推奨事項を報告する。","when":"AWRレポートを読む前に「どこを見るべきか」の要約を素早く得るため、またはスナップショットごとの自動ADDM実行以外の任意の範囲を分析するため。","caution":"Diagnostics Packライセンスが必要。ADDMの推奨事項(パラメータの引上げ、SQL Tuning Advisorの実行など)を盲目的に適用しない。メモリ関連の推奨はAWRのアドバイザセクションと照らして検証する。範囲は再起動をまたげない。","tags":["addm","dbms_addm","advisor","finding","finding","recommendation","diagnostics pack","performance"]},{"id":"sql-monitor-report","task":"SQL Monitorレポートを取得(実行中または完了した長時間SQL)","category":"パフォーマンス","command":"-- List monitored SQL (longer than 5 s, parallel, or /*+ MONITOR */):\nSELECT sql_id, status, username, sql_exec_id,\n       TO_CHAR(sql_exec_start,'YYYY-MM-DD HH24:MI:SS') AS exec_start,\n       ROUND(elapsed_time/1e6,1) AS elapsed_s,\n       ROUND(cpu_time/1e6,1)     AS cpu_s,\n       buffer_gets, px_servers_allocated\nFROM   v$sql_monitor\nORDER  BY sql_exec_start DESC\nFETCH FIRST 20 ROWS ONLY;\n\n-- TEXT report (actual rows, time and activity per plan line):\nSET LONG 10000000 LONGCHUNKSIZE 10000000 LINESIZE 300 PAGESIZE 0 TRIMSPOOL ON\nSELECT DBMS_SQLTUNE.REPORT_SQL_MONITOR(\n         sql_id       => '<sql_id>',\n         type         => 'TEXT',\n         report_level => 'ALL') AS report\nFROM   dual;\n\n-- Shareable HTML (interactive in a browser):\nSPOOL /tmp/sqlmon_<sql_id>.html\nSELECT DBMS_SQLTUNE.REPORT_SQL_MONITOR(\n         sql_id => '<sql_id>', type => 'ACTIVE', report_level => 'ALL')\nFROM   dual;\nSPOOL OFF","what":"Real-Time SQL Monitoringは、長時間実行またはパラレルSQLの実行計画の各ステップについて、実際の行数、経過時間、メモリ/一時領域の使用量、ASHアクティビティを表示する。SQLの実行中に進捗を確認できる。","when":"バッチ/レポートクエリが停止しているか、残りはどれくらいかを確認するとき、パラレルクエリの分散(PXスキュー)分析、推定行数(E-Rows)と実際の行数の乖離の特定に。","caution":"Tuning Packライセンスが必要(Diagnostics Packが前提)。デフォルトでは、CPU/I-Oを5 s消費したSQLまたはパラレル実行のSQLのみが監視される。それ以外には/*+ MONITOR */ヒントを使用する。非常に大きな計画(_sqlmon_max_planlines、デフォルト300)は監視されない。エントリは限られた時間しかメモリに残らない。12c以降では古いレポートもDBA_HIST_REPORTSから取得できる。","tags":["sql monitor","report_sql_monitor","v$sql_monitor","real-time","long running query","parallel","tuning pack"]},{"id":"sql-trace-10046-tkprof","task":"セッションの10046トレースを有効化/無効化し、TKPROFで要約","category":"パフォーマンス","command":"-- 1) Find the target session and its trace file:\nSELECT s.sid, s.serial#, s.username, s.module, p.tracefile\nFROM   v$session s\n  JOIN v$process p ON p.addr = s.paddr\nWHERE  s.username = 'CUSTOMER_APP';\n\n-- 2) Enable trace (waits + binds = equivalent of level 12):\nBEGIN\n  DBMS_MONITOR.SESSION_TRACE_ENABLE(\n    session_id => <sid>,\n    serial_num => <serial#>,\n    waits      => TRUE,\n    binds      => TRUE,\n    plan_stat  => 'ALL_EXECUTIONS');\nEND;\n/\n-- Verify: SELECT sql_trace, sql_trace_waits, sql_trace_binds FROM v$session WHERE sid = <sid>;\n\n-- 3) Disable once the problem operation completes:\nEXEC DBMS_MONITOR.SESSION_TRACE_DISABLE(session_id => <sid>, serial_num => <serial#>);\n\n-- Alternatives:\n-- Your own session: ALTER SESSION SET EVENTS '10046 trace name context forever, level 12';\n-- Single SQL_ID, all sessions: ALTER SYSTEM SET EVENTS 'sql_trace[SQL: <sql_id>] wait=true, bind=true';\n--   disable: ALTER SYSTEM SET EVENTS 'sql_trace[SQL: <sql_id>] off';\n-- For a connection pool: DBMS_MONITOR.CLIENT_ID_TRACE_ENABLE / SERV_MOD_ACT_TRACE_ENABLE\n\n-- 4) Summarize with TKPROF on the OS (most expensive SQL first):\n-- $ tkprof /u01/app/oracle/diag/rdbms/orcl/ORCL/trace/ORCL_ora_12345.trc /tmp/ora_12345.prf \\\n--     sys=no sort=exeela,fchela,prsela waits=yes aggregate=yes","what":"拡張SQLトレース(10046)は、セッションが実行するすべてのSQLのparse/execute/fetch時間、待機イベント、バインド値をトレースファイルに書き込む。TKPROFはこれをSQLごとに集計した読みやすいレポートに変換する。","when":"AWR/ASHでは不十分で、単一のユーザー操作がどこで時間を費やしているかをエンドツーエンドで証明する必要があるとき。アプリケーションとデータベース間のラウンドトリップ(SQL*Net)の問題に。","caution":"ライセンス不要。トレースファイルは急速に肥大化し、対象セッションにオーバーヘッドを加える。短時間にとどめ、必ず無効化する(DBA_ENABLED_TRACESで残存を確認する)。binds=TRUEは機密データ(個人番号、カード番号など)をトレースファイルに書き込む。ALTER SESSION SET EVENTSにはALTER SESSION権限が必要(ない場合はORA-01031)。TKPROFはデフォルトでバインド値を表示しないため、元の.trcファイルを保持する。","note":"接続プールやサービスレベルのトレースでは複数のファイルが生成される。trcsessでマージしてから(trcsess output=combined.trc clientid=<id> *.trc)TKPROFを実行する。","tags":["10046","trace","tkprof","dbms_monitor","sql trace","wait","bind","session tracing"]},{"id":"xplan-allstats-last","task":"行ソース統計付きで実際の実行計画を表示(ALLSTATS LAST)","category":"パフォーマンス","command":"-- 1) Collect row source statistics (for this query only):\nSET SERVEROUTPUT OFF\nSELECT /*+ gather_plan_statistics */ customer_id, SUM(amount)\nFROM   customer_app.sales\nWHERE  created_at >= DATE '2026-06-01'\nGROUP  BY customer_id;\n-- or for the whole session: ALTER SESSION SET statistics_level = ALL;\n\n-- 2) Plan of the last cursor run in the same session (E-Rows vs A-Rows):\nSELECT *\nFROM   TABLE(DBMS_XPLAN.DISPLAY_CURSOR(\n         sql_id          => NULL,\n         cursor_child_no => NULL,\n         format          => 'ALLSTATS LAST +PEEKED_BINDS +OUTLINE'));\n\n-- 3) A cursor from another session / from earlier:\nSELECT *\nFROM   TABLE(DBMS_XPLAN.DISPLAY_CURSOR('<sql_id>', NULL, 'ALLSTATS LAST +PEEKED_BINDS'));","what":"EXPLAIN PLANは推定である。これは実際に実行された計画を、ステップごとのStarts、E-Rows(推定)、A-Rows(実際)、A-Time、Buffers、メモリ使用量とともに表示する。カーディナリティの見積り誤りが始まるステップを特定する最も直接的な方法。","when":"単一の遅いSQLのチューニング、統計/ヒストグラムの必要性の証明、ヒントやインデックス変更の効果測定に。","caution":"ライセンス不要。SET SERVEROUTPUT ONの状態では、sql_id=>NULLで最後のカーソルとしてDBMS_OUTPUTの呼出しが表示されるため、先にOFFにする。statistics_level=ALLをシステム全体で有効にしない。顕著なCPUオーバーヘッドが発生する。ヒントはSQLテキストを変えるため、新しいsql_idになる。ユーザーにはV$SQL_PLAN_STATISTICS_ALLの読み取りアクセス(SELECT_CATALOG_ROLE)が必要。","tags":["dbms_xplan","display_cursor","allstats last","gather_plan_statistics","actual plan","execution plan","a-rows","cardinality"]},{"id":"sql-tuning-advisor-task","task":"SQL Tuning Advisorタスクを作成・実行し、推奨事項を確認","category":"パフォーマンス","command":"-- 1) Create and run a task for a SQL in the cursor cache:\nVAR task VARCHAR2(64)\nBEGIN\n  :task := DBMS_SQLTUNE.CREATE_TUNING_TASK(\n             sql_id      => '<sql_id>',\n             scope       => DBMS_SQLTUNE.SCOPE_COMPREHENSIVE,\n             time_limit  => 300,\n             task_name   => 'STA_<sql_id>',\n             description => 'Slow report query');\n  DBMS_SQLTUNE.EXECUTE_TUNING_TASK(task_name => :task);\nEND;\n/\n-- For a historical SQL in AWR: begin_snap => <b>, end_snap => <e>, sql_id => '<sql_id>'\n\n-- 2) Status and report:\nSELECT task_name, status FROM dba_advisor_log WHERE task_name = :task;\n\nSET LONG 1000000 LONGCHUNKSIZE 1000000 LINESIZE 200 PAGESIZE 0\nSELECT DBMS_SQLTUNE.REPORT_TUNING_TASK(:task) FROM dual;\n\n-- 3) Get the recommendations as an executable script:\nSELECT DBMS_SQLTUNE.SCRIPT_TUNING_TASK(:task) FROM dual;\n\n-- 4) When done:\nEXEC DBMS_SQLTUNE.DROP_TUNING_TASK(task_name => :task);","what":"SQLに対してオプティマイザを拡張「チューニングモード」で実行し、不足している統計、新しいインデックス、SQLプロファイル、代替計画、SQLの再構成に関する推奨事項を生成する。プロファイルの推奨はテスト実行で検証する。","when":"問題のある単一SQLについて素早くセカンドオピニオンが必要なとき、またはコードを変更せずに計画劣化をSQLプロファイルで修正したいとき。","caution":"Tuning Packライセンスが必要。COMPREHENSIVEスコープはテストのためにSQLを実行する場合がある(DMLではクエリ部分のみ)。本番ではtime_limitを設定する。インデックスの推奨は他のワークロードを考慮しないため、DMLコストは別途評価する。ユーザーにはADVISOR権限が必要。","tags":["sql tuning advisor","dbms_sqltune","tuning task","recommendation","sql profile","index recommendation","tuning pack"]},{"id":"sql-profile-accept","task":"SQLプロファイルの受入れ、無効化、削除","category":"パフォーマンス","command":"-- 1) Accept the profile recommended by the tuning task:\nDECLARE\n  l_name VARCHAR2(128);\nBEGIN\n  l_name := DBMS_SQLTUNE.ACCEPT_SQL_PROFILE(\n              task_name   => '<task_name>',\n              name        => 'PROF_<sql_id>',\n              description => 'STA recommendation, CHG-1234',\n              force_match => TRUE,     -- also matches statements differing only in literals\n              replace     => TRUE);\n  DBMS_OUTPUT.PUT_LINE('Profile: ' || l_name);\nEND;\n/\n\n-- 2) Profiles and the cursors using them:\nSELECT name, category, status, force_matching,\n       TO_CHAR(created,'YYYY-MM-DD HH24:MI') AS created\nFROM   dba_sql_profiles\nORDER  BY created DESC;\n\nSELECT sql_id, child_number, plan_hash_value, sql_profile\nFROM   v$sql\nWHERE  sql_profile IS NOT NULL;\n\n-- 3) Temporarily disable / drop:\nEXEC DBMS_SQLTUNE.ALTER_SQL_PROFILE(name => 'PROF_<sql_id>', attribute_name => 'STATUS', value => 'DISABLED');\nEXEC DBMS_SQLTUNE.DROP_SQL_PROFILE(name => 'PROF_<sql_id>', ignore => TRUE);","what":"SQLプロファイルはオプティマイザに追加のカーディナリティ/選択性の補正(OPT_ESTIMATEなど)を与え、SQLテキストを変更せずにより良い計画を生成させる。FORCE_MATCHを指定すると、リテラルのみが異なる文にも適用される。","when":"SQLを変更できないとき(パッケージアプリケーション)、STAが検証済みの改善を推奨したとき、計画劣化の迅速な修正として。","caution":"Tuning Packライセンスが必要。プロファイルは計画を「固定」しない。見積りを補正するため、データ分布が変われば計画は変わり得る。計画の安定性が必須ならSQL計画ベースラインを使用する。両方が存在する場合、オプティマイザはベースラインの受入れ済み計画の中から選択する。受入れ前に必ず検証結果(レポートの'Validation results'セクション)を確認する。","tags":["sql profile","accept_sql_profile","dbms_sqltune","force_match","plan fix","dba_sql_profiles","tuning pack"]},{"id":"spm-load-from-cursor-cache","task":"カーソルキャッシュから良好な計画をSQL計画ベースラインとしてロード","category":"パフォーマンス","command":"-- 1) Compare the SQL's plans and their performance:\nSELECT sql_id, child_number, plan_hash_value, executions,\n       ROUND(elapsed_time/1e3/NULLIF(executions,0),1) AS ms_per_exec,\n       sql_plan_baseline\nFROM   v$sql\nWHERE  sql_id = '<sql_id>';\n\n-- 2) Load the chosen plan as a baseline:\nSET SERVEROUTPUT ON\nDECLARE\n  n PLS_INTEGER;\nBEGIN\n  n := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(\n         sql_id          => '<sql_id>',\n         plan_hash_value => <plan_hash_value>,\n         fixed           => 'NO',\n         enabled         => 'YES');\n  DBMS_OUTPUT.PUT_LINE(n || ' plan(s) loaded');\nEND;\n/\n\n-- 3) Verify the baseline:\nSELECT sql_handle, plan_name, origin, enabled, accepted, fixed, reproduced,\n       TO_CHAR(last_executed,'YYYY-MM-DD HH24:MI') AS last_exec\nFROM   dba_sql_plan_baselines\nWHERE  signature = (SELECT exact_matching_signature FROM v$sql\n                    WHERE sql_id = '<sql_id>' AND ROWNUM = 1);\n-- On subsequent executions v$sql.sql_plan_baseline should be populated.","what":"SQL計画管理を使用して選択した計画をACCEPTEDのベースラインにする。以降オプティマイザは受入れ済みのベースライン計画のみを使用し、新たに見つかった計画は展開(evolve)されるまで保留する。","when":"計画劣化時に既知の良好な計画へ戻すため、アップグレードや統計変更の前に重要なSQLの計画を保護するため。","caution":"Enterprise Editionでは追加ライセンス不要(SE2ではSQLごとに1つのベースライン計画に制限)。ADMINISTER SQL MANAGEMENT OBJECTが必要。ベースラインは完全に同一のSQLテキスト(シグネチャ)に適用され、リテラルを使用するSQLには効果がない。計画で使用されるインデックスが削除されると計画を再現できず(REPRODUCED=NO)、オプティマイザはコストベースの選択に戻る。OPTIMIZER_USE_SQL_PLAN_BASELINESはTRUE(デフォルト)である必要がある。","note":"良好な計画がカーソルキャッシュにもうない場合はAWRからロードする: 12.2以降はDBMS_SPM.LOAD_PLANS_FROM_AWR(begin_snap, end_snap, basic_filter => q'[sql_id='<sql_id>']')。それ以前のリリースではSQLチューニングセットを経由してLOAD_PLANS_FROM_SQLSETを使用する。","tags":["spm","sql plan baseline","dbms_spm","load_plans_from_cursor_cache","plan pinning","plan regression","plan_hash_value"]},{"id":"spm-evolve-baseline","task":"未受入れのSQL計画ベースライン計画を展開(evolve)","category":"パフォーマンス","command":"-- 1) Plans waiting for acceptance:\nSELECT sql_handle, plan_name, origin, enabled, accepted, fixed,\n       TO_CHAR(created,'YYYY-MM-DD HH24:MI') AS created\nFROM   dba_sql_plan_baselines\nWHERE  accepted = 'NO'\nORDER  BY created DESC;\n\n-- 2) Evolve task: test-executes the candidate plan against the accepted plan\nVAR tname VARCHAR2(128)\nVAR ename VARCHAR2(128)\nBEGIN\n  :tname := DBMS_SPM.CREATE_EVOLVE_TASK(\n              sql_handle => '<sql_handle>',\n              time_limit => 600,\n              task_name  => 'EVOLVE_<sql_handle>');\n  :ename := DBMS_SPM.EXECUTE_EVOLVE_TASK(task_name => :tname);\nEND;\n/\n\nSET LONG 1000000 LONGCHUNKSIZE 1000000 LINESIZE 200 PAGESIZE 0\nSELECT DBMS_SPM.REPORT_EVOLVE_TASK(\n         task_name => :tname, execution_name => :ename,\n         type => 'TEXT', level => 'TYPICAL', section => 'ALL')\nFROM   dual;\n\n-- 3) If the report has recommendations (plans proven better), accept them:\nSET SERVEROUTPUT ON\nDECLARE\n  n PLS_INTEGER;\nBEGIN\n  n := DBMS_SPM.IMPLEMENT_EVOLVE_TASK(task_name => :tname);\n  DBMS_OUTPUT.PUT_LINE(n || ' plan(s) accepted');\nEND;\n/\nEXEC DBMS_SPM.DROP_EVOLVE_TASK(task_name => :tname);","what":"ベースラインが存在する場合、オプティマイザが見つけた新しい計画はACCEPTED=NOで格納される。evolveタスクはこれらの候補を受入れ済み計画と比較してテスト実行し、明らかに優れたもののみを受け入れる。","when":"新しいインデックスや新しい統計によってより良い計画が生まれた可能性がある、ベースライン設定済みのSQLに。自動のSYS_AUTO_SPM_EVOLVE_TASK(12c以降)を待たずに手動で判断するため。","caution":"Enterprise Editionが必要。evolveは実際にSQLを実行する(DMLではクエリ部分のみ)。重いSQLにはtime_limitを設定し、ピーク時間帯を避ける。ADMINISTER SQL MANAGEMENT OBJECTとADVISORが必要。SYSで解析されたSQLはevolveできない(ORA-16963)。アプリケーションユーザーで実行する。","since":"Oracle 12c","note":"12c以前のDBMS_SPM.EVOLVE_SQL_PLAN_BASELINE関数は非推奨。12c以降はタスクベースのAPI(CREATE/EXECUTE/IMPLEMENT_EVOLVE_TASK)を使用する。自動タスクの動作: DBMS_SPM.SET_EVOLVE_TASK_PARAMETER('SYS_AUTO_SPM_EVOLVE_TASK', 'ACCEPT_PLANS', 'FALSE')。","tags":["spm","evolve","create_evolve_task","baseline","plan acceptance","dbms_spm","accepted"]},{"id":"spm-alter-drop-baseline","task":"SQL計画ベースラインの計画を固定、無効化、削除","category":"パフォーマンス","command":"-- Show the plan content:\nSELECT *\nFROM   TABLE(DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINE(\n         sql_handle => '<sql_handle>',\n         plan_name  => '<plan_name>',\n         format     => 'TYPICAL'));\n\nSET SERVEROUTPUT ON\nDECLARE\n  n PLS_INTEGER;\nBEGIN\n  -- FIXED: this plan is preferred, new plans are not evolved automatically\n  n := DBMS_SPM.ALTER_SQL_PLAN_BASELINE(\n         sql_handle => '<sql_handle>', plan_name => '<plan_name>',\n         attribute_name => 'fixed', attribute_value => 'YES');\n\n  -- Take the bad plan out of use (without dropping it):\n  n := DBMS_SPM.ALTER_SQL_PLAN_BASELINE(\n         sql_handle => '<sql_handle>', plan_name => '<bad_plan_name>',\n         attribute_name => 'enabled', attribute_value => 'NO');\nEND;\n/\n\n-- Drop one plan or the SQL's entire baseline:\nDECLARE\n  n PLS_INTEGER;\nBEGIN\n  n := DBMS_SPM.DROP_SQL_PLAN_BASELINE(sql_handle => '<sql_handle>', plan_name => '<plan_name>');\n  -- without plan_name, all plans of the SQL are dropped:\n  -- n := DBMS_SPM.DROP_SQL_PLAN_BASELINE(sql_handle => '<sql_handle>');\n  DBMS_OUTPUT.PUT_LINE(n || ' plan(s) dropped');\nEND;\n/","what":"ベースライン計画の属性を管理する: FIXEDの計画は他の受入れ済み計画より優先され、新しい計画の自動展開を停止する。ENABLED=NOは計画を削除せずに無効化する。DROPは完全に削除する。","when":"重要なSQLの計画を確実に固定する、誤って受け入れた悪い計画を無効化する、不要になったベースラインを整理するため。","caution":"Enterprise Editionが必要。FIXEDの計画はデータ増加に伴い劣化し、オプティマイザがより良い計画を使用するのを妨げる可能性があるため、定期的に見直す。すべての計画がENABLED=NOのSQLは自由に最適化される。DROPは元に戻せない。先にDBMS_SPM.PACK_STGTAB_BASELINEでステージング表にバックアップする。","tags":["spm","baseline","fixed","alter_sql_plan_baseline","drop_sql_plan_baseline","disable plan","display_sql_plan_baseline"]},{"id":"bind-sensitivity-acs-check","task":"バインドピークと適応カーソル共有の状態を確認","category":"パフォーマンス","command":"-- 1) Child cursors: bind-sensitive / bind-aware / shareable?\nSELECT sql_id, child_number, executions, plan_hash_value,\n       is_bind_sensitive, is_bind_aware, is_shareable,\n       ROUND(buffer_gets/NULLIF(executions,0)) AS gets_per_exec\nFROM   v$sql\nWHERE  sql_id = '<sql_id>'\nORDER  BY child_number;\n\n-- 2) ACS histogram and selectivity ranges:\nSELECT child_number, bucket_id, count\nFROM   v$sql_cs_histogram\nWHERE  sql_id = '<sql_id>'\nORDER  BY child_number, bucket_id;\n\nSELECT child_number, predicate, range_id, low, high\nFROM   v$sql_cs_selectivity\nWHERE  sql_id = '<sql_id>';\n\n-- 3) Peeked / captured bind values:\nSELECT child_number, name, position, datatype_string, value_string,\n       TO_CHAR(last_captured,'YYYY-MM-DD HH24:MI:SS') AS captured\nFROM   v$sql_bind_capture\nWHERE  sql_id = '<sql_id>'\nORDER  BY child_number, position;\n\nSELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('<sql_id>', NULL, 'TYPICAL +PEEKED_BINDS'));\n\n-- 4) Why was a new child created?\nSELECT child_number, bind_mismatch, bind_equiv_failure,\n       optimizer_mismatch, load_optimizer_stats\nFROM   v$sql_shared_cursor\nWHERE  sql_id = '<sql_id>';","what":"オプティマイザは最初のハード解析時にバインド値をピークして計画を選択する。適応カーソル共有は、ヒストグラムのある列でバインド値ごとに異なる子カーソル/計画を作成できる。これらのクエリで、カーソルがbind-sensitive/awareか、どの値がピークされたか、子カーソルが作成された理由を表示する。","when":"「同じSQLが速いときと遅いときがある」という苦情、偏ったデータ分布、子カーソル数の急増(高いバージョン数)に。","caution":"ライセンス不要、読み取り専用。V$SQL_BIND_CAPTUREはサンプリング(デフォルトで約15分ごと)であり、WHERE/HAVINGのバインドのみを保持する。すべての実行の値ではない。ACSは数回の悪い実行の後にのみカーソルをbind-awareにする。重要なSQLでは、ACSに頼るよりSQL計画ベースラインに複数の計画をロードする方が確実。","since":"Oracle 11g","note":"適応カーソル共有は11gで導入された。高いバージョン数の分析では、V$SQL_SHARED_CURSORのREASON列(XML)が詳細な原因を示す。","tags":["bind peeking","adaptive cursor sharing","acs","bind variable","v$sql_bind_capture","child cursor","version count"]},{"id":"top-sql-awr-history","task":"過去の期間の経過時間/CPU上位SQLを特定(AWR + V$SQLAREA)","category":"パフォーマンス","command":"-- AWR: top 20 by elapsed time within a snapshot range (per plan)\nSELECT *\nFROM  (SELECT st.sql_id,\n              st.plan_hash_value,\n              SUM(st.executions_delta)                       AS execs,\n              ROUND(SUM(st.elapsed_time_delta)/1e6, 1)       AS elapsed_s,\n              ROUND(SUM(st.cpu_time_delta)/1e6, 1)           AS cpu_s,\n              ROUND(SUM(st.iowait_delta)/1e6, 1)             AS io_wait_s,\n              SUM(st.buffer_gets_delta)                      AS buffer_gets,\n              ROUND(SUM(st.elapsed_time_delta)/1e3\n                    / NULLIF(SUM(st.executions_delta),0), 2) AS ms_per_exec,\n              MAX(st.parsing_schema_name)                    AS parsing_schema\n       FROM   dba_hist_sqlstat st\n       WHERE  st.dbid = (SELECT dbid FROM v$database)\n         AND  st.snap_id BETWEEN <begin_snap> AND <end_snap>\n       GROUP  BY st.sql_id, st.plan_hash_value\n       ORDER  BY elapsed_s DESC)\nWHERE ROWNUM <= 20;\n-- For CPU ranking: ORDER BY cpu_s DESC\n-- SQL text: SELECT DBMS_LOB.SUBSTR(sql_text, 4000, 1) FROM dba_hist_sqltext WHERE sql_id = '<sql_id>';\n-- Plan history of a single SQL: @?/rdbms/admin/awrsqrpt.sql\n\n-- Current (since instance startup, still in cache) by CPU:\nSELECT sql_id,\n       ROUND(cpu_time/1e6,1)     AS cpu_s,\n       ROUND(elapsed_time/1e6,1) AS elapsed_s,\n       executions, buffer_gets, disk_reads,\n       ROUND(cpu_time/1e3/NULLIF(executions,0),2) AS cpu_ms_per_exec,\n       parsing_schema_name,\n       SUBSTR(sql_text,1,80) AS sql_text\nFROM   v$sqlarea\nWHERE  parsing_schema_name NOT IN ('SYS','SYSTEM')\nORDER  BY cpu_time DESC\nFETCH FIRST 20 ROWS ONLY;","what":"DBA_HIST_SQLSTATの*_DELTA列を合計し、スナップショット範囲で最もコストの高いSQLをplan_hash_value別に一覧表示する。同じSQLの計画変更も判明する。V$SQLAREAのクエリは、キャッシュに残っているものの累積値を示す。","when":"「昨夜02:00から04:00にシステムに負荷をかけたのは何か」の調査、計画変更の検出(同じsql_id、異なるplan_hash_value)、チューニング候補リストの作成に。","caution":"DBA_HIST_*のクエリにはDiagnostics Packライセンスが必要。V$SQLAREAは不要。AWRは上位SQL(デフォルトで上位N件)のみを保持するため、小さいが非常に頻繁な文は欠落する場合がある。V$SQLAREAの値はカーソルがエージアウトすると失われる。差分は再起動をまたいでも正しいが、キャッシュベースのクエリはゼロから始まる。","tags":["top sql","dba_hist_sqlstat","v$sqlarea","elapsed","cpu","most expensive query","plan change","diagnostics pack"]},{"id":"stats-stale-prefs","task":"古くなった統計を特定し、表ごとの統計設定(prefs)を設定","category":"統計情報","command":"-- 1) Flush DML counters to the dictionary and list stale objects:\nEXEC DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO;\n\nSELECT owner, table_name, partition_name, num_rows,\n       TO_CHAR(last_analyzed,'YYYY-MM-DD HH24:MI') AS last_analyzed,\n       stale_stats, stattype_locked\nFROM   dba_tab_statistics\nWHERE  owner = 'CUSTOMER_APP'\n  AND  (stale_stats = 'YES' OR last_analyzed IS NULL)\nORDER  BY table_name, partition_name;\n\nSELECT table_name, partition_name, inserts, updates, deletes, truncated\nFROM   dba_tab_modifications\nWHERE  table_owner = 'CUSTOMER_APP';\n\n-- 2) Per-table preferences (used by the auto stats job and manual GATHER calls):\nEXEC DBMS_STATS.SET_TABLE_PREFS('CUSTOMER_APP', 'SALES', 'STALE_PERCENT', '5');\nEXEC DBMS_STATS.SET_TABLE_PREFS('CUSTOMER_APP', 'SALES', 'METHOD_OPT', 'FOR ALL COLUMNS SIZE AUTO FOR COLUMNS SIZE 254 CUSTOMER_ID');\nEXEC DBMS_STATS.SET_TABLE_PREFS('CUSTOMER_APP', 'SALES', 'DEGREE', '4');\n\nSELECT DBMS_STATS.GET_PREFS('STALE_PERCENT', 'CUSTOMER_APP', 'SALES') AS stale_pct FROM dual;\nSELECT table_name, preference_name, preference_value\nFROM   dba_tab_stat_prefs WHERE owner = 'CUSTOMER_APP';\n\n-- 3) Gather only stale objects:\nEXEC DBMS_STATS.GATHER_SCHEMA_STATS(ownname => 'CUSTOMER_APP', options => 'GATHER STALE');\n-- Revert a preference: EXEC DBMS_STATS.DELETE_TABLE_PREFS('CUSTOMER_APP', 'SALES', 'STALE_PERCENT');","what":"変更率がSTALE_PERCENT(デフォルト10%)を超えると統計は古い(stale)と見なされる。設定(preferences)は表ごとのサンプリング、ヒストグラム、並列度、stale判定しきい値を永続化し、夜間の自動統計タスクが同じルールを適用するようにする。","when":"大規模な表で10%のしきい値の発動が遅すぎるとき、特定の列に常にヒストグラムが必要なとき、収集戦略をスクリプトではなくディクショナリで定義するため。","caution":"ライセンス不要。手動GATHER呼出しの明示的なパラメータは設定より優先される。METHOD_OPTを変更するとヒストグラムが追加/削除され、計画が変わる可能性がある。DBA_TAB_MODIFICATIONSはフラッシュ後にのみ最新になる(自動フラッシュは約15分ごと)。","tags":["stale stats","stale_percent","set_table_prefs","dba_tab_statistics","dba_tab_modifications","statistics preference","gather stale"]},{"id":"stats-lock-unlock","task":"表/スキーマの統計をロック/ロック解除","category":"統計情報","command":"-- Lock (the auto stats job and normal GATHER calls no longer touch them):\nEXEC DBMS_STATS.LOCK_TABLE_STATS(ownname => 'CUSTOMER_APP', tabname => 'ORDERS');\nEXEC DBMS_STATS.LOCK_SCHEMA_STATS(ownname => 'CUSTOMER_APP');\n-- A single partition only: DBMS_STATS.LOCK_PARTITION_STATS('CUSTOMER_APP', 'SALE_PART', 'P2026_H1');\n\n-- Locked objects:\nSELECT owner, table_name, partition_name, stattype_locked\nFROM   dba_tab_statistics\nWHERE  owner = 'CUSTOMER_APP' AND stattype_locked IS NOT NULL;\n\n-- Deliberate gathering while locked (instead of ORA-20005):\nEXEC DBMS_STATS.GATHER_TABLE_STATS('CUSTOMER_APP', 'ORDERS', force => TRUE);\n\n-- Unlock:\nEXEC DBMS_STATS.UNLOCK_SCHEMA_STATS(ownname => 'CUSTOMER_APP');\nEXEC DBMS_STATS.UNLOCK_TABLE_STATS(ownname => 'CUSTOMER_APP', tabname => 'ORDERS');","what":"統計を変更からロックする。自動タスクはロックされたオブジェクトをスキップし、表レベルのGATHER呼出しはORA-20005を発生させる。force=>TRUEでロックを解除せずに収集する。","when":"日中に空にされ再投入されるステージング/揮発性の表で代表的な統計を維持する、重要な表の計画を統計変更から保護する、DBMS_STATS.SET_TABLE_STATSで設定した値を保持するため。","caution":"ライセンス不要。ロックされた統計は時間とともに実態から乖離し、カーディナリティ誤差の原因になるため、ロックされたオブジェクトを定期的に報告する。スキーマのロックは後でスキーマに追加された表には適用されない。ロックされた表では、CREATE/REBUILD INDEXもインデックス統計を自動収集しない。","tags":["lock stats","lock statistics","unlock_table_stats","lock_schema_stats","ora-20005","stattype_locked","dbms_stats"]},{"id":"stats-restore-history","task":"統計を過去の時点に戻す","category":"統計情報","command":"-- 1) Retention and the oldest point you can return to:\nSELECT DBMS_STATS.GET_STATS_HISTORY_RETENTION    AS retention_days,\n       DBMS_STATS.GET_STATS_HISTORY_AVAILABILITY AS oldest_available\nFROM   dual;\n\n-- 2) Statistics history of the table:\nSELECT table_name, partition_name,\n       TO_CHAR(stats_update_time,'YYYY-MM-DD HH24:MI:SS TZH:TZM') AS stats_update_time\nFROM   dba_tab_stats_history\nWHERE  owner = 'CUSTOMER_APP' AND table_name = 'SALES'\nORDER  BY stats_update_time DESC;\n\n-- 3) Return to the point before the plan regressed:\nBEGIN\n  DBMS_STATS.RESTORE_TABLE_STATS(\n    ownname         => 'CUSTOMER_APP',\n    tabname         => 'SALES',\n    as_of_timestamp => TIMESTAMP '2026-10-07 22:00:00 +03:00',\n    no_invalidate   => FALSE);\nEND;\n/\n-- Whole schema: DBMS_STATS.RESTORE_SCHEMA_STATS('CUSTOMER_APP', <timestamp>)\n\n-- Change the retention (days):\n-- EXEC DBMS_STATS.ALTER_STATS_HISTORY_RETENTION(31);","what":"DBMS_STATSは収集のたびに以前の統計をSYSAUXに保存する(デフォルト31日)。RESTORE_*プロシージャは表/スキーマの統計を指定時刻の状態に戻す。no_invalidate=>FALSEでカーソルが直ちに再解析される。","when":"夜間の統計収集後に計画劣化が発生したときの最速のロールバックとして。変更が統計に起因するかのテストに。","caution":"ライセンス不要。ロックされた統計はリストアできない(先にロック解除する)。リストア後、次の自動収集で新しい統計が戻る。恒久的な修正には表の設定、統計のロック、またはSQL計画ベースラインを使用する。保存期間が長いとSYSAUX(WRI$_OPTSTAT_*表)が肥大化する。","tags":["restore stats","restore statistics","restore_table_stats","dba_tab_stats_history","stats history","plan regression","dbms_stats"]},{"id":"stats-pending-publish","task":"統計を保留(pending)として収集し、テストして公開","category":"統計情報","command":"-- 1) Disable publishing for the table (new statistics go to pending):\nEXEC DBMS_STATS.SET_TABLE_PREFS('CUSTOMER_APP', 'ORDERS', 'PUBLISH', 'FALSE');\nEXEC DBMS_STATS.GATHER_TABLE_STATS('CUSTOMER_APP', 'ORDERS');\n\n-- 2) Compare pending and published values:\nSELECT owner, table_name, partition_name, num_rows,\n       TO_CHAR(last_analyzed,'YYYY-MM-DD HH24:MI') AS last_analyzed\nFROM   dba_tab_pending_stats\nWHERE  owner = 'CUSTOMER_APP';\nSELECT num_rows, last_analyzed FROM dba_tables\nWHERE  owner = 'CUSTOMER_APP' AND table_name = 'ORDERS';\n\n-- 3) Try plans with pending statistics in this session only:\nALTER SESSION SET optimizer_use_pending_statistics = TRUE;\nEXPLAIN PLAN FOR SELECT COUNT(*) FROM customer_app.orders WHERE status = 7;\nSELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(format => 'BASIC +ROWS'));\nALTER SESSION SET optimizer_use_pending_statistics = FALSE;\n\n-- 4a) If good, publish:\nEXEC DBMS_STATS.PUBLISH_PENDING_STATS('CUSTOMER_APP', 'ORDERS', no_invalidate => FALSE);\n-- 4b) If bad, discard:\n-- EXEC DBMS_STATS.DELETE_PENDING_STATS('CUSTOMER_APP', 'ORDERS');\n\n-- 5) Return to normal behavior:\nEXEC DBMS_STATS.SET_TABLE_PREFS('CUSTOMER_APP', 'ORDERS', 'PUBLISH', 'TRUE');","what":"PUBLISH=FALSE設定では、収集した統計はディクショナリではなく保留領域に書き込まれるため、他のセッションに影響しない。optimizer_use_pending_statisticsを使用したテストセッションで計画を検証し、1コマンドで公開または破棄する。","when":"本番の重要なOLTP表で、更新した統計の計画への影響をリスクなくテストするため。大量データロード後の制御された切り替えに。","caution":"ライセンス不要。PUBLISH=FALSEのままだと、自動タスクが収集した統計も保留として蓄積され、公開されない。設定をTRUEに戻すのを忘れない。EXPLAIN PLANは推定であるため、可能であればクエリを実行してDISPLAY_CURSORを確認する。","since":"Oracle 11g","tags":["pending stats","publish","publish_pending_stats","optimizer_use_pending_statistics","statistics testing","dbms_stats","dba_tab_pending_stats"]},{"id":"stats-incremental-partitioned","task":"パーティション表の増分統計を構成","category":"統計情報","command":"-- 1) Enable incremental mode (global statistics are derived from partition synopses):\nEXEC DBMS_STATS.SET_TABLE_PREFS('CUSTOMER_APP', 'SALE_PART', 'INCREMENTAL', 'TRUE');\nEXEC DBMS_STATS.SET_TABLE_PREFS('CUSTOMER_APP', 'SALE_PART', 'INCREMENTAL_STALENESS', 'USE_STALE_PERCENT');\nEXEC DBMS_STATS.SET_TABLE_PREFS('CUSTOMER_APP', 'SALE_PART', 'GRANULARITY', 'AUTO');\n\n-- 2) The first gather scans everything and builds synopses; later ones read only changed partitions:\nEXEC DBMS_STATS.GATHER_TABLE_STATS(ownname => 'CUSTOMER_APP', tabname => 'SALE_PART');\n\n-- 3) Verify:\nSELECT DBMS_STATS.GET_PREFS('INCREMENTAL', 'CUSTOMER_APP', 'SALE_PART') AS incremental FROM dual;\nSELECT partition_name, num_rows,\n       TO_CHAR(last_analyzed,'YYYY-MM-DD HH24:MI:SS') AS last_analyzed, stale_stats\nFROM   dba_tab_statistics\nWHERE  owner = 'CUSTOMER_APP' AND table_name = 'SALE_PART'\nORDER  BY partition_position NULLS FIRST;\n\n-- 4) Pre-build synopses on a staging table to be loaded via exchange (12c+):\n-- EXEC DBMS_STATS.SET_TABLE_PREFS('CUSTOMER_APP', 'SALE_STAGE', 'INCREMENTAL', 'TRUE');\n-- EXEC DBMS_STATS.SET_TABLE_PREFS('CUSTOMER_APP', 'SALE_STAGE', 'INCREMENTAL_LEVEL', 'TABLE');\n-- EXEC DBMS_STATS.GATHER_TABLE_STATS('CUSTOMER_APP', 'SALE_STAGE');","what":"増分モードではパーティションごとにシノプシスが格納され、グローバル(表レベル)統計、特にNDVは、表全体を再スキャンせずにシノプシスのマージで計算される。変更されたパーティションのみが再度読み取られる。","when":"新しいデータが最近のパーティションにのみ入る大規模(TB規模)なレンジ/インターバルパーティション表で、グローバル統計の収集がメンテナンスウィンドウを超えるとき。","caution":"それ自体のライセンスは不要だが、Partitioningオプション(EEの有償オプション)がすでに必要。シノプシスはSYSAUX領域を消費する(12.2以降のHyperLogLog形式ははるかに小さい)。最初の収集はフルスキャンになるため、メンテナンスウィンドウで開始する。ESTIMATE_PERCENTをAUTO_SAMPLE_SIZE以外に設定すると増分が無効になる。","since":"Oracle 11g","note":"INCREMENTAL_STALENESSとINCREMENTAL_LEVEL設定は12cで追加された。12.2以降、シノプシス形式はAPPROXIMATE_NDV_ALGORITHM(HYPERLOGLOG)で制御される。","tags":["incremental stats","synopsis","partition statistics","global stats","incremental_staleness","dbms_stats","large table"]},{"id":"partition-split-merge-online","task":"パーティションをオンラインで分割・マージ","category":"パーティション化","command":"-- SPLIT: split a range partition in two, keep indexes usable\nALTER TABLE customer_app.sale_part\n  SPLIT PARTITION p2026_h2 AT (DATE '2026-10-01')\n  INTO (PARTITION p2026_q3, PARTITION p2026_q4)\n  UPDATE INDEXES ONLINE;\n\n-- MERGE: merge two adjacent partitions\nALTER TABLE customer_app.sale_part\n  MERGE PARTITIONS p2026_q3, p2026_q4 INTO PARTITION p2026_h2\n  UPDATE INDEXES ONLINE;\n\n-- ADD: new partition at the end (when there is no MAXVALUE)\nALTER TABLE customer_app.sale_part\n  ADD PARTITION p2027 VALUES LESS THAN (DATE '2028-01-01');\n\n-- Check: partition bounds and UNUSABLE index partitions\nSELECT partition_name, partition_position, high_value, num_rows\nFROM   dba_tab_partitions\nWHERE  table_owner = 'CUSTOMER_APP' AND table_name = 'SALE_PART'\nORDER  BY partition_position;\n\nSELECT index_name, partition_name, status\nFROM   dba_ind_partitions\nWHERE  index_owner = 'CUSTOMER_APP' AND status <> 'USABLE';","what":"SPLITはパーティションを境界値で2つに(12c以降: 複数に)分割し、MERGEは隣接するパーティションを結合する。ONLINEを指定すると操作中もDMLが継続し、UPDATE INDEXESを指定するとローカルインデックスとグローバルインデックスがUNUSABLEにならない。","when":"肥大化したMAXVALUE/「その他」パーティションの分割、アーカイブ前の古い小パーティションのマージ、パーティション化方式の変更(月次から四半期)に。","caution":"Partitioningオプション(EEの有償オプション)が必要。ONLINEにはEnterprise Editionが必要。SPLIT/MERGEはデータを物理的に書き直すため、大きなパーティションでは遅く、REDO/UNDOと一時領域を生成する。ONLINEなしでは操作中に表がDMLに対してロックされ、UPDATE INDEXESなしではグローバルインデックスがUNUSABLEになる。空のパーティションの分割は高速(fast split)。","since":"Oracle 12.2","note":"ONLINE SPLITは12.2、ONLINE MERGEは18cで導入され、どちらも19cで使用可能。古いリリースではONLINEキーワードを外し、メンテナンスウィンドウで実行する。","tags":["split partition","merge partition","add partition","split a partition","merge partitions","update indexes","online","partitioning"]},{"id":"partition-exchange","task":"パーティション交換で一括ロードまたはデータをアーカイブ","category":"パーティション化","command":"-- 1) Staging table that exactly matches the target (12.2+):\nCREATE TABLE customer_app.sale_stage\n  FOR EXCHANGE WITH TABLE customer_app.sale_part;\n\n-- 2) Load the staging table and build indexes matching the local indexes:\nINSERT /*+ APPEND */ INTO customer_app.sale_stage\nSELECT * FROM customer_app.sale_load WHERE created_at >= DATE '2027-01-01';\nCOMMIT;\nCREATE INDEX customer_app.sale_stage_customer_ix ON customer_app.sale_stage (customer_id);\n\n-- 3) Swap (dictionary-only operation, no data movement):\nALTER TABLE customer_app.sale_part\n  EXCHANGE PARTITION p2027 WITH TABLE customer_app.sale_stage\n  INCLUDING INDEXES WITHOUT VALIDATION\n  UPDATE GLOBAL INDEXES;\n\n-- 4) Verify:\nSELECT COUNT(*) FROM customer_app.sale_part PARTITION (p2027);\nSELECT index_name, partition_name, status\nFROM   dba_ind_partitions\nWHERE  index_owner = 'CUSTOMER_APP' AND status <> 'USABLE';","what":"パーティションのセグメントと通常の表のセグメントをディクショナリ上で入れ替える。数百万行が数秒で表に「入る」、またはアーカイブのために表から「出る」。FOR EXCHANGE WITH TABLEは列と隠し列の互換性を保証するステージング表を作成する。","when":"DWH/ETLの一括ロード、古いパーティションのアーカイブ表への移動、ロード中にライブの表に影響を与えずにインデックスと統計を準備するために。","caution":"Partitioningオプション(EEの有償オプション)が必要。WITHOUT VALIDATIONはステージングの行がパーティション境界に収まるかを確認しない。誤ったデータは誤ったパーティションに残り、クエリが誤った結果を返す可能性がある。不明な場合はWITH VALIDATION(フルスキャン)を使用する。UPDATE GLOBAL INDEXESなしではグローバルインデックスがUNUSABLEになる。一意/PK制約の状態は両側で一致している必要がある。","note":"CREATE TABLE ... FOR EXCHANGE WITH TABLEは12.2で導入された。それ以前は、CREATE TABLE ... AS SELECT * FROM <table> WHERE 1=0でステージング表を作成し、隠し列/仮想列の差異を手動で確認する。","tags":["exchange partition","staging","for exchange with table","bulk load","archive","update global indexes","partitioning"]},{"id":"partition-drop-truncate-gidx","task":"グローバルインデックスを使用可能なままパーティションをTRUNCATE/DROP","category":"パーティション化","command":"-- Empty a partition / remove a partition (global indexes stay maintained):\nALTER TABLE customer_app.sale_part TRUNCATE PARTITION p2025 UPDATE INDEXES;\nALTER TABLE customer_app.sale_part DROP PARTITION p2025 UPDATE INDEXES;\n\n-- 12c+ asynchronous global index maintenance: index is VALID but carries orphaned entries\nSELECT index_name, status, orphaned_entries\nFROM   dba_indexes\nWHERE  owner = 'CUSTOMER_APP' AND table_name = 'SALE_PART';\n\n-- Clean orphaned entries now (normally SYS.PMO_DEFERRED_GIDX_MAINT_JOB does it at night):\nEXEC DBMS_PART.CLEANUP_GIDX(schema_name_in => 'CUSTOMER_APP', table_name_in => 'SALE_PART');\n-- or a single index: ALTER INDEX customer_app.sale_part_id_gidx COALESCE CLEANUP;\n\n-- Target the partition by value instead of name:\n-- ALTER TABLE customer_app.sale_part DROP PARTITION FOR (DATE '2025-06-15') UPDATE INDEXES;","what":"行単位のDELETEではなく、パーティションレベルで古いデータを即座に削除する。12c以降、UPDATE INDEXESはすべてのエントリを更新する代わりにディクショナリ上でグローバルインデックスにマークを付けるのみ(非同期メンテナンス)。インデックスは直ちに使用可能なままで、孤立エントリは後でクリーンアップされる。","when":"データ保存ポリシーに基づく古い期間のパージ、ILM/パージジョブ、大規模な表でのDELETEによるUNDO/REDO負荷の回避に。","caution":"Partitioningオプション(EEの有償オプション)が必要。DROP/TRUNCATEは元に戻せない(flashback tableではパーティションは戻らない)。先にバックアップするか交換でアーカイブする。UPDATE INDEXESを忘れるとグローバルインデックスがUNUSABLEになり、クエリでORA-01502が発生する場合がある。子表が参照している(FK)場合、操作は失敗する。インターバル表では最後のレンジ(遷移)パーティションは削除できない。","since":"Oracle 12c","tags":["drop partition","truncate partition","update indexes","orphaned_entries","cleanup_gidx","global index","data purge","partitioning"]},{"id":"interval-partitioning","task":"インターバルパーティション化を作成し、既存のレンジ表をインターバルに変換","category":"パーティション化","command":"-- New table: a partition is created automatically for each month\nCREATE TABLE customer_app.measurements (\n  ts        DATE   NOT NULL,\n  sensor_id NUMBER,\n  value     NUMBER)\nPARTITION BY RANGE (ts) INTERVAL (NUMTOYMINTERVAL(1, 'MONTH'))\n( PARTITION p_first VALUES LESS THAN (DATE '2026-01-01') );\n\n-- Convert an existing range table to interval (there must be no MAXVALUE partition):\nALTER TABLE customer_app.sale_part SET INTERVAL (NUMTOYMINTERVAL(1, 'MONTH'));\n-- Back to range: ALTER TABLE customer_app.sale_part SET INTERVAL ();\n\n-- Rename a system-named partition to a meaningful name:\nALTER TABLE customer_app.measurements RENAME PARTITION FOR (DATE '2026-03-15') TO p2026_03;\n\n-- Check:\nSELECT partition_name, partition_position, interval, high_value\nFROM   dba_tab_partitions\nWHERE  table_owner = 'CUSTOMER_APP' AND table_name = 'MEASUREMENTS'\nORDER  BY partition_position;\n\nSELECT table_name, partitioning_type, interval\nFROM   dba_part_tables\nWHERE  owner = 'CUSTOMER_APP';","what":"インターバルパーティション化は、最後の境界を超える最初の行が到着すると新しいパーティションを自動的に作成し、翌月のパーティション作成忘れによるORA-14400エラーをなくす。SET INTERVALはデータを移動せずに既存のレンジ表を変換する。","when":"時系列、ログ、注文など日付で増加する表に。パーティションメンテナンススクリプトの削減に。","caution":"Partitioningオプション(EEの有償オプション)が必要。パーティションキーは単一のNUMBER/DATE/TIMESTAMP列である必要があり、MAXVALUEパーティションは先に削除する必要がある。不正または極端な日付(例: 9999年)は遠い先のパーティションを作成し、パーティション番号付けを歪める。狭い間隔では1,048,575パーティションの上限(ORA-14300)に近づく可能性があるため、アプリケーションで日付を検証する。自動パーティションは表のデフォルト表領域に作成される(STORE INで指定する)。","since":"Oracle 11g","tags":["interval partitioning","interval","automatic partition","numtoyminterval","ora-14400","set interval","range partition","partitioning"]},{"id":"partition-wise-join-check","task":"パーティションキーとパーティション単位結合の使用を確認","category":"パーティション化","command":"-- 1) Do both tables have the same partitioning type, key and count?\nSELECT p.owner, p.table_name, p.partitioning_type, k.column_name,\n       p.partition_count, p.subpartitioning_type\nFROM   dba_part_tables p\n  JOIN dba_part_key_columns k\n    ON k.owner = p.owner AND k.name = p.table_name AND k.object_type = 'TABLE'\nWHERE  p.owner = 'CUSTOMER_APP'\n  AND  p.table_name IN ('CUSTOMER_H', 'ORDERS_H');\n\n-- 2) Explain the join and inspect the plan shape:\nEXPLAIN PLAN FOR\nSELECT /*+ PARALLEL(4) */ m.city, SUM(s.amount)\nFROM   customer_app.customer_h m\n  JOIN customer_app.orders_h s ON s.customer_id = m.id\nGROUP  BY m.city;\n\nSELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(format => 'BASIC +PARALLEL +PARTITION'));\n-- Full PWJ: HASH JOIN sits BELOW the PARTITION HASH ALL line (PX PARTITION HASH ALL in parallel)\n-- Partial PWJ: PX SEND PARTITION (KEY) on one side only\n-- No PWJ: PX SEND HASH / BROADCAST on both sides","what":"結合キーで等価パーティション化された2つの表は、パーティションのペアごとに結合でき(フルパーティション単位結合)、パラレルクエリでの再分散トラフィックとメモリが大幅に削減される。計画の形からPWJが使用されているかがわかる。","when":"DWHで大規模なファクト対ファクトまたはファクト対ディメンション結合を設計するとき、パラレルクエリで大量のPX再分散(PX Deq Credit: send blkd)が見られるとき、パーティション化戦略の検証に。","caution":"ライセンス: Partitioningオプション(EEの有償オプション)。パラレルクエリにはEnterprise Editionが必要。EXPLAIN PLANは推定であり、実際の計画にはDISPLAY_CURSOR/SQL Monitorを使用する。フルPWJには同じパーティション数(ハッシュでは2の累乗を推奨)と一致するキーデータ型が必要。PWJはシリアル計画にも現れるが、実際の効果はパラレル実行で得られる。","tags":["partition-wise join","pwj","equi-partitioning","hash partition","parallel query","dba_part_key_columns","partitioning"]},{"id":"online-redefinition-flow","task":"DBMS_REDEFINITIONで表をオンライン再定義(全手順)","category":"オンライン操作","command":"-- 1) Is it eligible? (use CONS_USE_ROWID if there is no PK)\nEXEC DBMS_REDEFINITION.CAN_REDEF_TABLE('CUSTOMER_APP', 'CUSTOMER', DBMS_REDEFINITION.CONS_USE_PK);\n\n-- 2) Interim table with the target structure: hash partitioned in this example\nCREATE TABLE customer_app.customer_int (\n  id NUMBER, name VARCHAR2(100), city VARCHAR2(30))\nPARTITION BY HASH (id) PARTITIONS 8;\n\n-- 3) Start: initial copy + change tracking through an MV log\nBEGIN\n  DBMS_REDEFINITION.START_REDEF_TABLE(\n    uname        => 'CUSTOMER_APP',\n    orig_table   => 'CUSTOMER',\n    int_table    => 'CUSTOMER_INT',\n    col_mapping  => NULL,\n    options_flag => DBMS_REDEFINITION.CONS_USE_PK);\nEND;\n/\n\n-- 4) Copy indexes, constraints, triggers, grants and statistics:\nSET SERVEROUTPUT ON\nDECLARE\n  l_errors PLS_INTEGER;\nBEGIN\n  DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(\n    uname            => 'CUSTOMER_APP',\n    orig_table       => 'CUSTOMER',\n    int_table        => 'CUSTOMER_INT',\n    copy_indexes     => DBMS_REDEFINITION.CONS_ORIG_PARAMS,\n    copy_triggers    => TRUE,\n    copy_constraints => TRUE,\n    copy_privileges  => TRUE,\n    ignore_errors    => FALSE,\n    num_errors       => l_errors,\n    copy_statistics  => TRUE);\n  DBMS_OUTPUT.PUT_LINE('Error count: ' || l_errors);\nEND;\n/\nSELECT object_name, base_table_name, ddl_txt FROM dba_redefinition_errors;\n\n-- 5) Close the gap before finishing (shortens finish; can be run several times):\nEXEC DBMS_REDEFINITION.SYNC_INTERIM_TABLE('CUSTOMER_APP', 'CUSTOMER', 'CUSTOMER_INT');\n\n-- 6) Swap under a short lock:\nEXEC DBMS_REDEFINITION.FINISH_REDEF_TABLE('CUSTOMER_APP', 'CUSTOMER', 'CUSTOMER_INT', dml_lock_timeout => 60);\n\n-- 7) Drop the interim table, which now holds the old structure:\nDROP TABLE customer_app.customer_int PURGE;\n\n-- On problems: EXEC DBMS_REDEFINITION.ABORT_REDEF_TABLE('CUSTOMER_APP', 'CUSTOMER', 'CUSTOMER_INT');\n-- Status: SELECT * FROM dba_redefinition_status WHERE base_table_owner = 'CUSTOMER_APP';","what":"アプリケーションの稼働を続けたまま表の構造(パーティション化、列の型/順序、表領域、圧縮、LOB設定)を変更する。データは中間表にコピーされ、変更はMVログで同期され、最後にごく短いロックの下で名前が入れ替えられる。","when":"大規模な非パーティション表を停止なしでパーティション化する、列の型を変更する、BasicFile LOBをSecureFilesに変換するなど、ALTER TABLEではオンラインで行えない変更に。","caution":"Enterprise Editionが必要(ターゲットがパーティション化されている場合はPartitioningオプションも)。処理には表の2倍の領域が必要で、REDOとMVログのオーバーヘッドが加わる。FINISHは短時間の排他ロックを取得し、長時間実行トランザクションがあると待機する(dml_lock_timeout)。COPY_TABLE_DEPENDENTSのエラーは必ずDBA_REDEFINITION_ERRORSで確認する。FKはNOVALIDATEでコピーされる場合がある。まずテスト環境でリハーサルする。","note":"dml_lock_timeoutパラメータは12cで追加された。12.2以降はV$ONLINE_REDEFで進捗を監視する。単純な移動/圧縮の変更であれば、DBMS_REDEFINITIONではなくALTER TABLE ... MOVE ONLINEで十分。","tags":["dbms_redefinition","online redefinition","redefinition","zero downtime","convert to partitioned","can_redef_table","finish_redef_table","enterprise edition"]},{"id":"table-move-online","task":"表またはパーティションをオンラインで移動(ALTER TABLE MOVE ONLINE)","category":"オンライン操作","command":"-- Move the table to another tablespace / reorganize it (DML continues):\nALTER TABLE customer_app.orders MOVE ONLINE TABLESPACE customer_data;\n\n-- Compress while moving (BASIC; for OLTP compression use ROW STORE COMPRESS ADVANCED):\nALTER TABLE customer_app.orders MOVE ONLINE COMPRESS;\n\n-- A single partition:\nALTER TABLE customer_app.sale_part\n  MOVE PARTITION p2026_h1 ONLINE TABLESPACE customer_archive UPDATE INDEXES;\n\n-- Verify: indexes must stay VALID\nSELECT index_name, status FROM dba_indexes\nWHERE  owner = 'CUSTOMER_APP' AND table_name = 'ORDERS';\nSELECT table_name, tablespace_name, compression, compress_for\nFROM   dba_tables\nWHERE  owner = 'CUSTOMER_APP' AND table_name = 'ORDERS';","what":"表セグメントを書き直す: 断片化と最高水位標(HWM)を削減し、表領域を変更し、圧縮を適用する。ONLINEを指定すると操作中もDMLはブロックされず、インデックスは自動的にメンテナンスされVALIDのまま保たれる。","when":"大量削除後の領域の回収、新しい表領域/ストレージへの表の移動、古いパーティションを圧縮してアーカイブ表領域へ移すために。","caution":"Enterprise Editionが必要。ROW STORE COMPRESS ADVANCEDにはAdvanced Compressionオプション(有償)が必要。操作には表サイズと同じ追加領域が必要で、大量のREDOが生成される。開始時と終了時に短いロックが取得され、長時間オープンのトランザクションがあると待機する。ONLINEまたはUPDATE INDEXESなしのMOVEはすべてのインデックスをUNUSABLEにする。","since":"Oracle 12.2","note":"表レベルのMOVE ONLINEは12.2で導入された。パーティションレベルのMOVE PARTITION ONLINEは12.1から存在する。12.1以前では表にはDBMS_REDEFINITIONを使用する。","tags":["move online","alter table move","move table","reorganization","high water mark","compression","enterprise edition"]},{"id":"tde-keystore-setup","task":"TDEキーストアの作成、オープン、マスターキーの設定、バックアップ(19c以降)","category":"セキュリティ","command":"-- 1) Keystore location (static parameter, restart required), then keystore type:\nALTER SYSTEM SET WALLET_ROOT = '/u01/app/oracle/admin/ORCL/wallet' SCOPE = SPFILE;\n-- SHUTDOWN IMMEDIATE;  STARTUP;\nALTER SYSTEM SET TDE_CONFIGURATION = 'KEYSTORE_CONFIGURATION=FILE' SCOPE = BOTH;\n\n-- 2) In CDB root: create a software keystore (under WALLET_ROOT/tde), open it, set the master key\nADMINISTER KEY MANAGEMENT CREATE KEYSTORE IDENTIFIED BY \"<keystore_pwd>\";\nADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN\n  IDENTIFIED BY \"<keystore_pwd>\" CONTAINER = ALL;\nADMINISTER KEY MANAGEMENT SET KEY USING TAG 'mk_2026_10'\n  IDENTIFIED BY \"<keystore_pwd>\" WITH BACKUP USING 'mk_before' CONTAINER = ALL;\n\n-- 3) Open automatically after restart (auto-login, cwallet.sso):\nADMINISTER KEY MANAGEMENT CREATE AUTO_LOGIN KEYSTORE\n  FROM KEYSTORE IDENTIFIED BY \"<keystore_pwd>\";\n\n-- 4) Backup (repeat after every SET KEY / rekey, store SEPARATELY from database backups):\nADMINISTER KEY MANAGEMENT BACKUP KEYSTORE USING 'daily'\n  FORCE KEYSTORE IDENTIFIED BY \"<keystore_pwd>\" TO '/backup/tde/';\n\n-- 5) Status:\nSELECT con_id, wrl_type, wrl_parameter, status, wallet_type, keystore_mode\nFROM   v$encryption_wallet;\nSELECT con_id, key_id, tag, creation_time, activation_time\nFROM   v$encryption_keys ORDER BY creation_time;","what":"Transparent Data Encryption用のソフトウェアキーストアを統合モード(全PDBがCDBのキーストアを共有)で設定し、マスター暗号化キーを作成し、再起動後にオープンされるよう自動ログインを有効にする。19c以降は、sqlnet.oraのENCRYPTION_WALLET_LOCATIONではなくWALLET_ROOT/TDE_CONFIGURATIONが推奨される方法。","when":"保存データの暗号化を求めるコンプライアンスプロジェクト(GDPR、PCI-DSS、ISO 27001)で、表領域/列の暗号化前の最初の手順として。","caution":"オンプレミスではAdvanced Securityオプション(有償)が必要。Oracle Cloud(OCI/Autonomous)のライセンスには含まれる。WALLET_ROOTは静的であり、インスタンスの再起動(停止時間)が必要。キーストアとそのパスワードを失うと、暗号化データは永久に読めなくなる。キーストアのバックアップはデータベースバックアップとは別に安全に保管する。自動ログインファイル(cwallet.sso)を持つ者は誰でもデータベースをオープンできるため、ファイル権限を制限し、必要に応じてLOCAL AUTO_LOGINを使用する。Data Guardではキーストアをスタンバイにもコピーする。","since":"Oracle 18c","note":"WALLET_ROOTとTDE_CONFIGURATIONは18cで導入され、19cでは標準。12c-18cのsqlnet.ora ENCRYPTION_WALLET_LOCATION方式は19cで非推奨、23aiでサポート終了。23aiではデフォルトのアルゴリズムはAES256。GOSTとSEEDによる暗号化はサポート終了、復号は非推奨。WALLET_ROOTは静的パラメータであり、インスタンスの再起動が必要。","tags":["tde","keystore","wallet","master key","encryption","advanced security","wallet_root","administer key management"],"untested":true},{"id":"tde-tablespace-encryption","task":"TDEで表領域を暗号化(新規および既存、オンライン/オフライン)","category":"セキュリティ","command":"-- Prerequisite: keystore OPEN and master key set (v$encryption_wallet.status = 'OPEN')\n\n-- 1) New encrypted tablespace:\nCREATE TABLESPACE customer_enc\n  DATAFILE '+DATA' SIZE 1G AUTOEXTEND ON NEXT 256M MAXSIZE 20G\n  ENCRYPTION USING 'AES256' ENCRYPT;\n\n-- 2a) Encrypt an existing tablespace ONLINE (12.2+, needs extra space temporarily):\nALTER TABLESPACE customer_data ENCRYPTION ONLINE USING 'AES256' ENCRYPT;\n-- If not OMF: ... ENCRYPT FILE_NAME_CONVERT = ('customer_data01.dbf', 'customer_data01_enc.dbf');\n\n-- 2b) OFFLINE conversion (no extra space, tablespace unavailable meanwhile):\nALTER TABLESPACE customer_data OFFLINE NORMAL;\nALTER TABLESPACE customer_data ENCRYPTION OFFLINE ENCRYPT;\nALTER TABLESPACE customer_data ONLINE;\n\n-- 3) Progress and status:\nSELECT t.name AS tablespace_name, e.encryptionalg, e.status, e.con_id\nFROM   v$encrypted_tablespaces e\n  JOIN v$tablespace t ON t.ts# = e.ts# AND t.con_id = e.con_id;\nSELECT tablespace_name, encrypted FROM dba_tablespaces ORDER BY tablespace_name;","what":"表領域暗号化はデータファイルに書き込まれるすべてのブロックを暗号化する。バッファキャッシュ内のデータは平文であるため、アプリケーションやSQLの変更は不要。オンライン変換はDMLを継続したままデータファイルの暗号化コピーを作成して切り替え、オフライン変換はブロックをその場で暗号化する。","when":"機密データを保持するアプリケーション表領域の保存時暗号化、新しい暗号化表領域へのデータ移動、監査指摘の解消に。","caution":"オンプレミスではAdvanced Securityオプション(有償)が必要。オンライン変換には暗号化対象のデータファイルと同じ追加領域が必要で、大量のI/OとREDOが発生する。Data Guardスタンバイも同じ処理を行う。オフライン変換はData Guardスタンバイで別途実行する必要がある。SYSTEM/SYSAUX/UNDOは12.2以降オンラインで暗号化できるが、特に注意が必要。暗号化表領域のバックアップはキーストアなしではリストアできない。","since":"Oracle 12.2","note":"表領域のオンライン/オフライン変換は12.2で導入された。新しい表領域を自動的に暗号化するには、19cではTABLESPACE_ENCRYPTION=AUTO_ENABLE(19.16以降のRU)またはENCRYPT_NEW_TABLESPACES=ALWAYSを使用する。先にキーストアをオープンし、マスターキーを設定しておく必要がある(tde-keystore-setupを参照)。","tags":["tde","tablespace encryption","encryption online","aes256","v$encrypted_tablespaces","advanced security","at-rest"],"untested":true},{"id":"unified-audit-policy-lifecycle","task":"Unified Auditingポリシーを作成し、条件付きで有効化、レコードを確認、削除","category":"セキュリティ","command":"-- 1) Object + condition based policy (excluding the batch module):\nCREATE AUDIT POLICY pol_customer_dml\n  ACTIONS SELECT ON customer_app.customer,\n          UPDATE ON customer_app.customer,\n          DELETE ON customer_app.customer\n  WHEN 'SYS_CONTEXT(''USERENV'',''MODULE'') NOT LIKE ''batch%'''\n  EVALUATE PER SESSION;\n\n-- 2) Privileged operations policy:\nCREATE AUDIT POLICY pol_ddl_priv\n  PRIVILEGES DROP ANY TABLE, ALTER SYSTEM\n  ACTIONS DROP USER, ALTER USER, CREATE USER;\n\n-- 3) Enable:\nAUDIT POLICY pol_customer_dml EXCEPT customer_app;   -- everyone except the schema owner\nAUDIT POLICY pol_ddl_priv WHENEVER SUCCESSFUL;\nAUDIT POLICY ORA_LOGON_FAILURES WHENEVER NOT SUCCESSFUL;\n\n-- 4) Which policy is enabled for whom?\nSELECT policy_name, enabled_option, entity_name, success, failure\nFROM   audit_unified_enabled_policies ORDER BY policy_name;\nSELECT policy_name, audit_option, object_schema, object_name, audit_condition\nFROM   audit_unified_policies WHERE policy_name LIKE 'POL_%';\n\n-- 5) Records:\nSELECT event_timestamp, dbusername, action_name, object_schema, object_name,\n       return_code, unified_audit_policies, os_username, userhost\nFROM   unified_audit_trail\nWHERE  event_timestamp > SYSTIMESTAMP - INTERVAL '1' DAY\n  AND  unified_audit_policies LIKE '%POL_%'\nORDER  BY event_timestamp DESC;\n-- 19c (queued-write): EXEC DBMS_AUDIT_MGMT.FLUSH_UNIFIED_AUDIT_TRAIL;  (not in 23ai)\n\n-- 6) Disable and remove:\nNOAUDIT POLICY pol_customer_dml;\nNOAUDIT POLICY pol_ddl_priv;\nDROP AUDIT POLICY pol_customer_dml;\nDROP AUDIT POLICY pol_ddl_priv;","what":"Unified Auditingはすべての監査レコードを単一の証跡(AUDSYSスキーマ、UNIFIED_AUDIT_TRAIL)に収集する。ポリシーはオブジェクトアクション、システム権限、アクションごとに定義され、WHEN条件とBY/EXCEPTユーザーリストでノイズを減らす。","when":"機密表へのアクセスの記録、特権DDLと権限変更の監視、ログオン失敗の確認、監査要件への対応に。","caution":"追加ライセンス不要。高負荷の表でSELECTを監査すると大量のレコードが生成されSYSAUXが肥大化する。条件とEXCEPTで絞り込み、DBMS_AUDIT_MGMT(CLEAN_AUDIT_TRAIL、SET_LAST_ARCHIVE_TIMESTAMP)でアーカイブ/クリーンアップをスケジュールする。有効なポリシーは削除できない(ORA-46361)。先にNOAUDITを実行する。ポリシーの変更は新しいセッションで有効になる。19cはデフォルトで混合モードで動作するため、従来のAUDIT_TRAILのレコードも書き込まれる場合がある。","since":"Oracle 12c","note":"23aiでは従来の監査はサポート終了となり、統合監査のみが存在する。レコードは表に直接書き込まれるため、FLUSH_UNIFIED_AUDIT_TRAILは削除された。19cで純粋な統合モードに切り替えるには、uniaud_onでoracleバイナリを再リンクする必要がある。","tags":["unified auditing","audit policy","auditing","unified_audit_trail","create audit policy","noaudit","ora_logon_failures","security"]},{"id":"vpd-row-level-policy","task":"VPD(DBMS_RLS)で行レベルのアクセスポリシーを追加","category":"セキュリティ","command":"-- 1) Policy function returning the predicate:\nCREATE OR REPLACE FUNCTION customer_app.customer_vpd_fn (\n  p_schema IN VARCHAR2,\n  p_object IN VARCHAR2\n) RETURN VARCHAR2\nAS\nBEGIN\n  -- The schema owner sees all rows (NULL = no restriction)\n  IF SYS_CONTEXT('USERENV', 'SESSION_USER') = 'CUSTOMER_APP' THEN\n    RETURN NULL;\n  END IF;\n  -- Other users see only their own city\n  RETURN 'city = SYS_CONTEXT(''USERENV'', ''CLIENT_IDENTIFIER'')';\nEND;\n/\n\n-- 2) Attach the policy to the table:\nBEGIN\n  DBMS_RLS.ADD_POLICY(\n    object_schema   => 'CUSTOMER_APP',\n    object_name     => 'CUSTOMER',\n    policy_name     => 'CUSTOMER_CITY_VPD',\n    function_schema => 'CUSTOMER_APP',\n    policy_function => 'CUSTOMER_VPD_FN',\n    statement_types => 'SELECT, UPDATE, DELETE',\n    update_check    => TRUE,\n    policy_type     => DBMS_RLS.CONTEXT_SENSITIVE);\nEND;\n/\n\n-- 3) Check:\nSELECT object_owner, object_name, policy_name, function,\n       sel, upd, del, chk_option, enable, policy_type\nFROM   dba_policies WHERE object_owner = 'CUSTOMER_APP';\n-- Test (as the application user): EXEC DBMS_SESSION.SET_IDENTIFIER('Ankara');\n\n-- 4) Temporarily disable / drop:\nEXEC DBMS_RLS.ENABLE_POLICY('CUSTOMER_APP', 'CUSTOMER', 'CUSTOMER_CITY_VPD', FALSE);\nEXEC DBMS_RLS.DROP_POLICY('CUSTOMER_APP', 'CUSTOMER', 'CUSTOMER_CITY_VPD');","what":"Virtual Private Databaseは、ポリシー関数が返すWHERE述語を表に対するすべてのSQLに自動的に追加し、同じ表のユーザーが権限のある行のみを参照/変更できるようにする。update_check=>TRUEは、ユーザーが自分では参照できない値に行を更新することを防ぐ。","when":"マルチテナントアプリケーション、地域/支店ベースのデータ分離、アプリケーションコードに手を加えずに行セキュリティを追加するために。","caution":"Enterprise Editionに含まれ、追加ライセンス不要。CLIENT_IDENTIFIERはクライアントが自由に設定できるため、本番では信頼できるパッケージで設定するアプリケーションコンテキスト(CREATE CONTEXT ... USING)を使用する。SYSおよびEXEMPT ACCESS POLICYを持つユーザーはポリシーをバイパスする。その権限のないData Pumpエクスポートは警告なしに一部のデータのみをエクスポートする。関数内のエラーはORA-28112ですべてのアクセスをブロックする。誤ったpolicy_type(例: STATIC)は述語をキャッシュし、誤った結果を返す。","tags":["vpd","virtual private database","dbms_rls","row security","row level security","add_policy","policy function","security"]},{"id":"password-profile-hardening","task":"パスワードポリシープロファイルを作成し、ユーザーに割り当て","category":"セキュリティ","command":"-- Hardened profile for application/human users:\nCREATE PROFILE app_user_prf LIMIT\n  FAILED_LOGIN_ATTEMPTS    5\n  PASSWORD_LOCK_TIME       1/24          -- 1 hour lock\n  PASSWORD_LIFE_TIME       90\n  PASSWORD_GRACE_TIME      7\n  PASSWORD_REUSE_TIME      365\n  PASSWORD_REUSE_MAX       10\n  INACTIVE_ACCOUNT_TIME    60            -- accounts unused for 60 days are locked\n  PASSWORD_VERIFY_FUNCTION ora12c_strong_verify_function;\n\n-- Service accounts: password never expires, gradual password rollover enabled:\nCREATE PROFILE service_account_prf LIMIT\n  FAILED_LOGIN_ATTEMPTS    UNLIMITED\n  PASSWORD_LIFE_TIME       UNLIMITED\n  PASSWORD_ROLLOVER_TIME   1;            -- old and new password both valid for 1 day\n\nALTER USER customer_app PROFILE app_user_prf;\n\n-- Check:\nSELECT username, profile, account_status,\n       TO_CHAR(expiry_date,'YYYY-MM-DD') AS expiry_date, lock_date\nFROM   dba_users\nWHERE  profile IN ('APP_USER_PRF', 'SERVICE_ACCOUNT_PRF');\n\nSELECT profile, resource_name, limit\nFROM   dba_profiles\nWHERE  profile = 'APP_USER_PRF' AND resource_type = 'PASSWORD'\nORDER  BY resource_name;","what":"プロファイルは、ログイン失敗時のロック、パスワードの有効期間、再利用、複雑度(検証関数)、非アクティブアカウントのロックの各ルールをユーザーグループに適用する。PASSWORD_ROLLOVER_TIMEを使用すると、サービスアカウントのパスワード変更中もアプリケーションは停止なしで切り替えられる。","when":"セキュリティ監査/CISベンチマークの要件、新しいアプリケーションユーザーの作成時、DEFAULTプロファイルの緩い値をユーザーグループごとに分離するために。","caution":"追加ライセンス不要。サービスアカウントにFAILED_LOGIN_ATTEMPTSの制限があると、誤ったパスワードを持つ1台のアプリケーションサーバーがアカウントをロックし、本番停止を引き起こす可能性がある。アプリケーションアカウントのPASSWORD_LIFE_TIMEは予期しないEXPIRED状態を引き起こす場合がある。検証関数はSYSの下に存在する必要がある(ない場合は@?/rdbms/admin/utlpwdmg.sql。このスクリプトはDEFAULTプロファイルも変更する)。プロファイルを変更しても既存のパスワードは再検証されない。","note":"INACTIVE_ACCOUNT_TIMEは12.2で追加された。PASSWORD_ROLLOVER_TIMEは21cで導入され、19.12 RUで19cにバックポートされた。ロールオーバー期間中に旧パスワードでログインしたセッションは監査レコードで追跡できる。","tags":["profile","password policy","password_verify_function","failed_login_attempts","inactive_account_time","password_rollover_time","account lock","security"]},{"id":"privilege-analysis-capture","task":"権限分析で未使用の権限を特定","category":"セキュリティ","command":"-- 1) Capture privilege usage for a specific user:\nBEGIN\n  DBMS_PRIVILEGE_CAPTURE.CREATE_CAPTURE(\n    name        => 'CAP_APP_USER',\n    description => 'Actual privilege usage of the application user',\n    type        => DBMS_PRIVILEGE_CAPTURE.G_CONTEXT,\n    condition   => 'SYS_CONTEXT(''USERENV'',''SESSION_USER'') = ''CUSTOMER_APP''');\n  DBMS_PRIVILEGE_CAPTURE.ENABLE_CAPTURE(name => 'CAP_APP_USER', run_name => 'RUN_2026_10');\nEND;\n/\n-- Other types: G_DATABASE (whole DB), G_ROLE (roles => role_name_list('DBA')), G_ROLE_AND_CONTEXT\n\n-- 2) After a representative workload (including month end), stop and generate results:\nBEGIN\n  DBMS_PRIVILEGE_CAPTURE.DISABLE_CAPTURE(name => 'CAP_APP_USER');\n  DBMS_PRIVILEGE_CAPTURE.GENERATE_RESULT(name => 'CAP_APP_USER', run_name => 'RUN_2026_10');\nEND;\n/\n\n-- 3) Used and never-used privileges:\nSELECT username, sys_priv, obj_priv, object_owner, object_name, used_role\nFROM   dba_used_privs   WHERE capture = 'CAP_APP_USER';\nSELECT username, sys_priv, obj_priv, object_owner, object_name\nFROM   dba_unused_privs WHERE capture = 'CAP_APP_USER';\n\n-- 4) Through which role chain was the privilege used?\nSELECT username, sys_priv, used_role, path\nFROM   dba_used_sysprivs_path WHERE capture = 'CAP_APP_USER';\n\n-- 5) Cleanup:\nEXEC DBMS_PRIVILEGE_CAPTURE.DROP_CAPTURE(name => 'CAP_APP_USER');","what":"権限分析は、選択した範囲(データベース全体、ロール、条件)内で実際に使用されたシステム/オブジェクト権限を実行時に記録する。結果として未使用の権限が一覧表示され、最小権限の原則に基づいてREVOKEを計画できる。","when":"DBA/ANY権限を持つアプリケーションアカウントの整理、監査前の権限レビュー、パッケージアプリケーションが本当に必要とする権限の把握に。","caution":"2018年からEnterprise Editionに含まれる(以前はDatabase Vaultライセンスが必要)。追加ライセンス不要。取得中はわずかなオーバーヘッドがある。結果は取得期間中のワークロードのみを反映する。月末、年末、緊急時のジョブが実行されていなければ、「未使用」と表示された権限も必要な場合があるため、段階的に取り消す。一度に有効にできる取得は1つのみ。唯一の例外として、G_DATABASE取得は1つのロールまたはコンテキスト取得と並行して有効にできる。","since":"Oracle 12c","tags":["privilege analysis","dbms_privilege_capture","unused privileges","least privilege","dba_unused_privs","privilege cleanup","security"]},{"id":"opatch-inventory-prereq","task":"OPatchでインベントリを確認し、パッチ適用前チェックを実行","category":"パッチ適用とライフサイクル","command":"# OPatch version (must meet the minimum in the patch README; update with patch 6880880 if needed)\n$ORACLE_HOME/OPatch/opatch version\n\n# Installed patches: short list / detailed inventory\n$ORACLE_HOME/OPatch/opatch lspatches\n$ORACLE_HOME/OPatch/opatch lsinventory -detail -oh $ORACLE_HOME\n\n# Pre-apply checks (in the unzipped patch directory):\ncd /u01/stage/<patch_id>\n$ORACLE_HOME/OPatch/opatch prereq CheckConflictAgainstOHWithDetail -ph ./\n$ORACLE_HOME/OPatch/opatch prereq CheckSystemSpace -ph ./\n\n# For Grid Infrastructure / RAC homes (as root), analyze mode:\n# opatchauto apply /u01/stage/<patch_id> -analyze","what":"Oracleホームに適用されたバイナリパッチ(RU、個別パッチ)を一覧表示し、新しいパッチの適用前に既存のパッチとの競合や十分なディスク領域があるかを確認する。","when":"四半期ごとのRU/セキュリティパッチの前、サポートからSRでインベントリ出力を求められたとき、2つの環境のパッチレベルの比較に。","caution":"コマンドはOracleホームを所有するOSユーザー(oracle)で実行する。opatchautoにはrootが必要。前提条件チェックは読み取り専用でデータベースに影響しないが、競合が報告された場合は、Oracle Supportからマージ/オーバーレイパッチを入手するまで適用しない。適用前にOracleホーム(tar)とインベントリをバックアップする。","note":"SQLからインベントリを表示するには、DBMS_QOPATCH.GET_OPATCH_LSINVENTORYを使用できる(OPatchインベントリのあるインストール環境)。","tags":["opatch","lsinventory","lspatches","prereq","patch","patch conflict","opatchauto","release update"],"untested":true},{"id":"datapatch-apply-verify","task":"バイナリパッチ後にdatapatch -verboseでSQLレイヤーを更新","category":"パッチ適用とライフサイクル","command":"# 1) After the binary patch (opatch apply), start the DB; all PDBs must be open:\nsqlplus / as sysdba <<EOF\nSTARTUP;\nALTER PLUGGABLE DATABASE ALL OPEN;\nEXIT;\nEOF\n\n# 2) Check only first, then apply:\ncd $ORACLE_HOME/OPatch\n./datapatch -prereq\n./datapatch -verbose\n# For specific PDBs: ./datapatch -verbose -pdbs PDB1,PDB2\n\n# 3) Recompile invalid objects:\nsqlplus / as sysdba @?/rdbms/admin/utlrp.sql\n\n# Logs: $ORACLE_BASE/cfgtoollogs/sqlpatch/","what":"datapatchは、Oracleホーム内のバイナリパッチのSQL/PL-SQLコンポーネント(ディクショナリ、パッケージ)をCDBルート、PDB$SEED、オープン中の全PDBに適用し、結果をDBA_REGISTRY_SQLPATCHに記録する。ロールバックされたパッチのSQL部分も元に戻す。","when":"すべてのRU/RUR/個別バイナリパッチ適用またはロールバックの後。新しくパッチ適用したホームに移動またはアンプラグ/プラグインしたPDBに。DBA_REGISTRY_SQLPATCHがWITH ERRORSを示す場合の再実行に。","caution":"クローズまたはMOUNTEDのPDBにはパッチが適用されず、RESTRICTEDモードでオープンする場合がある。先にすべてオープンする。高負荷時に実行しない(ディクショナリロック、パッケージの無効化)。RACでは1つのノードから1回だけ実行する。Data Guardではdatapatchはプライマリでのみ実行する。変更はREDOを通じてスタンバイに反映される(先にスタンバイのバイナリにパッチを適用する)。","note":"最近の19c RUに含まれるdatapatchは-sanity_checksを提供し、パッチ適用前にディクショナリと環境の健全性(無効なオブジェクト、PDB違反、表領域/TEMPの状態)を検証する。","tags":["datapatch","sql patch","release update","dba_registry_sqlpatch","post-patch","utlrp","pdb","patching"],"untested":true},{"id":"sqlpatch-registry-check","task":"SQLパッチ履歴、コンポーネントの状態、無効なオブジェクトを確認","category":"パッチ適用とライフサイクル","command":"-- 1) datapatch history (most recent at the bottom):\nSELECT patch_id, patch_type, action, status, source_version, target_version,\n       TO_CHAR(action_time,'YYYY-MM-DD HH24:MI') AS action_time, description\nFROM   dba_registry_sqlpatch\nORDER  BY action_time;\n\n-- Failed entries and their log files:\nSELECT install_id, patch_id, action, status, logfile\nFROM   dba_registry_sqlpatch\nWHERE  status <> 'SUCCESS';\n\n-- In a CDB, for all PDBs (from root):\nSELECT con_id, patch_id, action, status\nFROM   cdb_registry_sqlpatch ORDER BY con_id, action_time;\n\n-- 2) Components must be VALID:\nSELECT comp_id, comp_name, version_full, status\nFROM   dba_registry ORDER BY comp_id;\n\n-- 3) Invalid object summary (compare before/after utlrp):\nSELECT owner, object_type, COUNT(*) AS invalid_cnt\nFROM   dba_objects\nWHERE  status = 'INVALID'\nGROUP  BY owner, object_type\nORDER  BY invalid_cnt DESC;","what":"パッチ適用後にSQLレイヤーが実際に更新されたか(ディクショナリがバイナリと一致しているか)、どのPDBでどのパッチが失敗したか、ディクショナリコンポーネントがVALIDか、無効なオブジェクトの数を一目で表示する。","when":"すべてのdatapatchの後の検証手順として。パッチ適用やアップグレード前のベースライン取得、PDBのプラグイン後に不一致が疑われるときに。","caution":"読み取り専用、ライセンス不要。SOURCE_VERSION/TARGET_VERSIONは18c以降のRUモデルで設定される。STATUS='WITH ERRORS'の場合は、LOGFILEのエラーを修正してdatapatchを再実行する。一部のコンポーネント(例: 未使用のXDB/JAVA)はINVALID/REMOVEDと表示される場合があるため、パッチ適用前の状態と比較する。","note":"SQLからバイナリインベントリを表示するには、SELECT XMLTRANSFORM(DBMS_QOPATCH.GET_OPATCH_LIST, DBMS_QOPATCH.GET_OPATCH_XSLT) FROM dual;を使用する。OPatchインベントリのないインストール環境ではORA-20013が発生する。","tags":["dba_registry_sqlpatch","patch history","datapatch","dba_registry","invalid objects","invalid object","patch verification"]},{"id":"scheduler-job-lifecycle","task":"スケジューラジョブの作成、手動実行、無効化、削除","category":"スケジューラ","command":"-- 1) Create disabled, set attributes, then enable:\nBEGIN\n  DBMS_SCHEDULER.CREATE_JOB(\n    job_name        => 'CUSTOMER_APP.NIGHTLY_STATS',\n    job_type        => 'PLSQL_BLOCK',\n    job_action      => q'[BEGIN DBMS_STATS.GATHER_SCHEMA_STATS(ownname => 'CUSTOMER_APP', options => 'GATHER STALE'); END;]',\n    start_date      => SYSTIMESTAMP,\n    repeat_interval => 'FREQ=DAILY; BYHOUR=2; BYMINUTE=30; BYSECOND=0',\n    enabled         => FALSE,\n    auto_drop       => FALSE,\n    comments        => 'Nightly stale statistics gathering');\n  DBMS_SCHEDULER.SET_ATTRIBUTE('CUSTOMER_APP.NIGHTLY_STATS', 'max_run_duration', INTERVAL '2' HOUR);\n  DBMS_SCHEDULER.SET_ATTRIBUTE('CUSTOMER_APP.NIGHTLY_STATS', 'logging_level', DBMS_SCHEDULER.LOGGING_FULL);\n  DBMS_SCHEDULER.ENABLE('CUSTOMER_APP.NIGHTLY_STATS');\nEND;\n/\n\n-- 2) Validate the calendar expression (next run time):\nSET SERVEROUTPUT ON\nDECLARE\n  l_next TIMESTAMP WITH TIME ZONE;\nBEGIN\n  DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING(\n    calendar_string   => 'FREQ=DAILY; BYHOUR=2; BYMINUTE=30; BYSECOND=0',\n    start_date        => SYSTIMESTAMP,\n    return_date_after => SYSTIMESTAMP,\n    next_run_date     => l_next);\n  DBMS_OUTPUT.PUT_LINE('Next run: ' || l_next);\nEND;\n/\n\n-- 3) Run now in the background (does not affect the schedule):\nEXEC DBMS_SCHEDULER.RUN_JOB('CUSTOMER_APP.NIGHTLY_STATS', use_current_session => FALSE);\n\n-- 4) Status:\nSELECT owner, job_name, enabled, state, run_count, failure_count,\n       last_start_date, next_run_date\nFROM   dba_scheduler_jobs WHERE owner = 'CUSTOMER_APP';\n\n-- 5) Stop (if running) / disable / drop:\n-- EXEC DBMS_SCHEDULER.STOP_JOB('CUSTOMER_APP.NIGHTLY_STATS', force => FALSE);\nEXEC DBMS_SCHEDULER.DISABLE('CUSTOMER_APP.NIGHTLY_STATS', force => TRUE);\nEXEC DBMS_SCHEDULER.DROP_JOB('CUSTOMER_APP.NIGHTLY_STATS', force => TRUE);","what":"DBMS_SCHEDULERでスケジュール済みのPL/SQLジョブを定義する。max_run_duration(超過時にイベントを発生)と詳細なロギングレベルを設定し、カレンダ式を事前に検証し、スケジュールを乱さずに手動実行できる。","when":"メンテナンス、ETL、クリーンアップなどの定期的なデータベース作業を、cronではなくデータベース内でRAC/Data Guardを考慮して実行するために。","caution":"追加ライセンス不要。start_dateのタイムゾーンが重要: SYSTIMESTAMPはデータベースサーバーのTZを使用する。夏時間の切り替え時のずれを避けるため、明示的なリージョン(例: 'Europe/Istanbul')を使用する。JOB_QUEUE_PROCESSES=0の場合、ジョブは実行されない。force=>TRUEでのDISABLEは実行中のインスタンスを停止せず、今後の実行を防ぐのみ。中断するにはSTOP_JOBを使用する。別のスキーマにジョブを作成するにはCREATE ANY JOBが必要。","tags":["dbms_scheduler","job","scheduled job","create_job","run_job","repeat_interval","disable job","scheduler"]},{"id":"scheduler-job-history","task":"スケジューラジョブの実行履歴と失敗を監視","category":"スケジューラ","command":"-- 1) Recent runs: duration, CPU, error code and message\nSELECT owner, job_name, status, error#,\n       TO_CHAR(actual_start_date,'YYYY-MM-DD HH24:MI:SS') AS started,\n       run_duration, cpu_used,\n       SUBSTR(additional_info, 1, 200) AS info\nFROM   dba_scheduler_job_run_details\nWHERE  owner = 'CUSTOMER_APP'\nORDER  BY actual_start_date DESC\nFETCH FIRST 20 ROWS ONLY;\n\n-- 2) Failures in the last 24 hours (whole DB):\nSELECT owner, job_name, error#, actual_start_date, SUBSTR(errors, 1, 300) AS errors\nFROM   dba_scheduler_job_run_details\nWHERE  status <> 'SUCCEEDED'\n  AND  log_date > SYSTIMESTAMP - INTERVAL '1' DAY\nORDER  BY log_date DESC;\n\n-- 3) Currently running:\nSELECT owner, job_name, session_id, running_instance, elapsed_time, cpu_used\nFROM   dba_scheduler_running_jobs;\n\n-- 4) Lifecycle events (ENABLE/DISABLE/RUN/STOP...):\nSELECT log_date, owner, job_name, operation, status\nFROM   dba_scheduler_job_log\nWHERE  owner = 'CUSTOMER_APP'\nORDER  BY log_date DESC\nFETCH FIRST 20 ROWS ONLY;\n\n-- Log retention (days): EXEC DBMS_SCHEDULER.SET_SCHEDULER_ATTRIBUTE('log_history', '30');","what":"スケジューラのログビューから、各実行の開始時刻、所要時間、CPU使用量、ステータス、エラーメッセージ、および実行中のジョブとジョブのライフサイクルイベントを一覧表示する。","when":"夜間ジョブが実行されなかった、または長時間かかったとき、ジョブのSLA追跡、監視システム(OEM/Zabbix/Prometheus)での失敗ルール定義に。","caution":"読み取り専用、ライセンス不要。デフォルトのログ保存期間は30日で、logging_levelがOFFのジョブはレコードを生成しない。ERRORS列は12c以降に存在する。古いリリースではADDITIONAL_INFOを確認する。RACでは、RUNNING_INSTANCEがどのノードでジョブが実行されたかを示す。","tags":["scheduler","job history","dba_scheduler_job_run_details","failed job","dba_scheduler_running_jobs","job log","monitoring"]},{"id":"resource-plan-basic","task":"シンプルなResource Managerプランを作成し、有効化","category":"スケジューラ","command":"-- 1) Define groups, plan, directives and mapping inside a pending area (PDB or non-CDB):\nBEGIN\n  DBMS_RESOURCE_MANAGER.CLEAR_PENDING_AREA;\n  DBMS_RESOURCE_MANAGER.CREATE_PENDING_AREA;\n\n  DBMS_RESOURCE_MANAGER.CREATE_CONSUMER_GROUP('OLTP_GRP',  'Online transactions');\n  DBMS_RESOURCE_MANAGER.CREATE_CONSUMER_GROUP('REPORT_GRP', 'Reporting / batch');\n  DBMS_RESOURCE_MANAGER.CREATE_PLAN('DAYTIME_PLAN', 'Business hours plan');\n\n  DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE(\n    plan => 'DAYTIME_PLAN', group_or_subplan => 'OLTP_GRP',\n    comment => 'OLTP first', mgmt_p1 => 70);\n  DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE(\n    plan => 'DAYTIME_PLAN', group_or_subplan => 'REPORT_GRP',\n    comment => 'Reports limited', mgmt_p1 => 20,\n    parallel_degree_limit_p1 => 4,\n    switch_group => 'CANCEL_SQL', switch_time => 1800, switch_for_call => TRUE);\n  DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE(\n    plan => 'DAYTIME_PLAN', group_or_subplan => 'OTHER_GROUPS',\n    comment => 'Everyone else (mandatory)', mgmt_p1 => 10);\n\n  DBMS_RESOURCE_MANAGER.SET_CONSUMER_GROUP_MAPPING(\n    attribute      => DBMS_RESOURCE_MANAGER.ORACLE_USER,\n    value          => 'REPORT_USER',\n    consumer_group => 'REPORT_GRP');\n\n  DBMS_RESOURCE_MANAGER.VALIDATE_PENDING_AREA;\n  DBMS_RESOURCE_MANAGER.SUBMIT_PENDING_AREA;\nEND;\n/\n-- Switch privilege required for the mapping to take effect:\nEXEC DBMS_RESOURCE_MANAGER_PRIVS.GRANT_SWITCH_CONSUMER_GROUP('REPORT_USER', 'REPORT_GRP', FALSE);\n\n-- 2) Activate (FORCE: prevents maintenance windows from switching the plan):\nALTER SYSTEM SET resource_manager_plan = 'FORCE:DAYTIME_PLAN' SCOPE = BOTH;\n\n-- 3) Monitor:\nSELECT sid, username, resource_consumer_group FROM v$session WHERE username IS NOT NULL;\nSELECT name, active_sessions, execution_waiters, consumed_cpu_time, cpu_wait_time\nFROM   v$rsrc_consumer_group;\n\n-- 4) Roll back: deactivate the plan, then delete it\n-- ALTER SYSTEM SET resource_manager_plan = '' SCOPE = BOTH;\n-- BEGIN DBMS_RESOURCE_MANAGER.CREATE_PENDING_AREA;\n--       DBMS_RESOURCE_MANAGER.DELETE_PLAN_CASCADE('DAYTIME_PLAN');\n--       DBMS_RESOURCE_MANAGER.SUBMIT_PENDING_AREA; END;\n-- /","what":"CPU競合時にどのワークロードを優先するかを決める: OLTPグループにCPUの70%、レポートグループに20%を割り当て、レポートグループの並列度を4に制限し、30分を超える呼出しを取り消す(CANCEL_SQL)。ユーザーは自動的にコンシューマグループにマッピングされる。","when":"日中のレポートがOLTPを遅くする混在ワークロード、制御されないパラレルクエリの上限設定、暴走したクエリの自動取り消しに。","caution":"Resource ManagerにはEnterprise Editionが必要(SE2では非常に限定的)。追加ライセンス不要。mgmt_p1の割合はCPU競合時のみ適用され、1つのレベルで合計100%を超えられない。CANCEL_SQLは実行中の文をORA-00040で強制終了する。誤ったマッピングは重要な処理を終了させる可能性があるため、しきい値は慎重にテストする。プランが有効な間、CPUの抑制は'resmgr:cpu quantum'待機イベントとして現れる。CDBレベルでのPDB間の配分にはCREATE_CDB_PLANを使用する。","tags":["resource manager","dbms_resource_manager","resource plan","consumer group","cpu priority","cancel_sql","resmgr:cpu quantum","resource management"]}]},"recipes/postgres.json":{"engineId":"postgres","engine":"PostgreSQL","order":2,"recipes":[{"id":"wal-switch","task":"WALセグメントを切り替える","category":"WALとチェックポイント","command":"SELECT pg_switch_wal();","what":"現在のWALセグメントを閉じて新しいセグメントに切り替え、アーカイブをトリガーする。","when":"アーカイブファイルを生成する、またはバックアップ後にWALを強制的に出力するため。","caution":"PostgreSQL 10より前はpg_switch_xlog()だった。","since":"PostgreSQL 10","note":"この関数はPostgreSQL 10でpg_switch_wal()に名前が変更された。それ以前はpg_switch_xlog()だった(WALはかつて'xlog'と呼ばれていた)。","tags":["wal","switch","checkpoint","archive"]},{"id":"manual-checkpoint","task":"手動CHECKPOINTを実行","category":"WALとチェックポイント","command":"CHECKPOINT;","what":"ダーティバッファをディスクに書き込み、チェックポイントレコードを作成する。リカバリの開始点を前進させる。","when":"バックアップ前、メンテナンスウィンドウ中、サーバー停止前にディスクと同期するために。","caution":"大量のI/Oが発生する場合がある。本番のピーク時間帯には実行しない。スーパーユーザーまたは(PG15以降)pg_checkpointロールのみが実行できる。","tags":["checkpoint","wal","io","flush"]},{"id":"wal-status-size","task":"WALサイズと現在のLSNを表示","category":"WALとチェックポイント","command":"SELECT pg_current_wal_lsn() AS current_lsn, pg_walfile_name(pg_current_wal_lsn()) AS current_wal_file, pg_size_pretty(sum(size)) AS wal_dir_size FROM pg_ls_waldir();","what":"現在のWAL LSN、書き込み中のWALファイル名、pg_walディレクトリの合計サイズを返す。","when":"WALの蓄積、ディスク使用量、チェックポイント間隔の監視に。","caution":"pg_ls_waldirとpg_walfile_nameはPostgreSQL 10以降で使用可能。アクセスにはpg_monitorロールが必要な場合がある。","tags":["wal","lsn","size","monitor"]},{"id":"archive-lag","task":"アーカイブ遅延(未アーカイブのWAL)を表示","category":"WALとチェックポイント","command":"SELECT last_archived_wal, last_failed_wal, archived_count, failed_count, pg_walfile_name(pg_current_wal_lsn()) AS current_wal FROM pg_stat_archiver;","what":"最後にアーカイブされたWALファイル、現在書き込み中のWAL、アーカイブ失敗カウンタを比較してアーカイブ遅延を表示する。","when":"archive_commandが遅れていないかの監視、アーカイブ失敗の検出に。","caution":"failed_countが増え続ける場合、archive_commandが失敗しておりpg_walが満杯になる可能性がある。ディスクのあふれを防ぐため直ちに対処する。","tags":["archive","wal","lag","monitor"]},{"id":"create-tablespace","task":"新しい表領域を追加","category":"ストレージ","command":"CREATE TABLESPACE ssd_ts OWNER postgres LOCATION '/mnt/ssd/pgdata';","what":"指定したディレクトリに新しい表領域を定義する。表とインデックスをそのディスクに配置できる。","when":"データを別のディスク(例: 高速SSD)に分散し、I/Oを分離するため。","caution":"ディレクトリはすでに存在し、空で、postgresユーザーが所有している必要がある。シンボリックリンクでデータを他のディスクに分散しない。PostgreSQL独自の表領域機構を使用する。","tags":["tablespace","storage","disk","create"]},{"id":"move-table-tablespace","task":"表を別の表領域に移動","category":"ストレージ","command":"ALTER TABLE customer SET TABLESPACE ssd_ts;","what":"表のすべてのデータを新しい表領域(ディスク)に物理的に移動する。","when":"表をより高速な/別のディスクに移動するため。","caution":"移動中は表にACCESS EXCLUSIVEロックが取得され、移動が完了するまで表にアクセスできない。大きな表ではメンテナンスウィンドウで実施する。","tags":["tablespace","table","move","storage"]},{"id":"move-index-tablespace","task":"インデックスを別の表領域に移動","category":"ストレージ","command":"ALTER INDEX customer_email_idx SET TABLESPACE ssd_ts;","what":"インデックスを指定した表領域に移動する。","when":"インデックスをデータとは別のディスクに配置し、I/Oを分散するため。","caution":"移動中はACCESS EXCLUSIVEロックが取得され、インデックスは使用できない。ALTER TABLE ... SET TABLESPACEは表のインデックスを対象としないため、一括では移動できない。インデックスごとに個別に移動する。","tags":["tablespace","index","move","storage"]},{"id":"db-table-size","task":"データベースと表のサイズを照会する","category":"ストレージ","command":"SELECT relname AS table_name, pg_size_pretty(pg_total_relation_size(relid)) AS total_size, pg_size_pretty(pg_relation_size(relid)) AS data_only FROM pg_catalog.pg_statio_user_tables ORDER BY pg_total_relation_size(relid) DESC LIMIT 20;","what":"インデックスとTOASTを含む合計サイズで、最も大きい20の表を一覧表示する。","when":"ディスク使用量を分析し、どの表が領域を占めているかを特定するため。","caution":"データベース全体のサイズ: SELECT pg_size_pretty(pg_database_size(current_database()));","tags":["size","table","database","storage"]},{"id":"table-bloat","task":"表の肥大化(bloat)を推定","category":"ストレージ","command":"SELECT schemaname, relname AS table_name, n_dead_tup AS dead_rows, n_live_tup AS live_rows, round(n_dead_tup::numeric / NULLIF(n_live_tup + n_dead_tup, 0) * 100, 1) AS dead_pct, last_autovacuum FROM pg_stat_user_tables WHERE n_dead_tup > 0 ORDER BY n_dead_tup DESC LIMIT 20;","what":"デッドタプル数と最後のautovacuum時刻に基づいて肥大化率を表示する。","when":"VACUUMの必要性と、autovacuumが追いついているかの判断に。","caution":"n_dead_tupはDMLカウンタから継続的に更新される推定値である(VACUUM後に減少し、ANALYZEは推定値を補正するのみ)。正確な物理的肥大化にはpgstattuple拡張(pgstattuple('customer'))の方が正確。","tags":["bloat","dead-tuple","vacuum","storage"]},{"id":"vacuum-analyze-table","task":"特定の表をVACUUM ANALYZE","category":"メンテナンス","command":"VACUUM (ANALYZE, VERBOSE) customer;","what":"表のデッドタプルをクリーンアップして領域を再利用可能にし、プランナ統計を更新する。","when":"大量のDELETE/UPDATEの後、または実行計画が劣化したときに。","caution":"VACUUMはディスク領域をOSに返さない。領域の回収にはVACUUM FULLが必要で、ACCESS EXCLUSIVEロックを取得する。通常のVACUUMは表をブロックしない。","tags":["vacuum","analyze","maintenance","cleanup"]},{"id":"vacuum-freeze","task":"積極的なVACUUM FREEZEを実行","category":"メンテナンス","command":"VACUUM (FREEZE, VERBOSE, ANALYZE) customer;","what":"表内の対象となるすべてのタプルを直ちに'frozen'としてマークし、トランザクションIDの周回(wraparound)のリスクを減らす。","when":"周回の警告が表示されたとき、またはアーカイブ/読み取り専用化される大きな表に予防的に。","caution":"表全体をスキャンするため大量のI/Oが発生する。周回の緊急時にはデータベースが事実上読み取り専用になる可能性があるため、事前にdatfrozenxidを監視する。","tags":["vacuum","freeze","wraparound","maintenance"]},{"id":"reindex-concurrently","task":"ロックなしでインデックスを再構築(REINDEX CONCURRENTLY)","category":"メンテナンス","command":"REINDEX INDEX CONCURRENTLY customer_email_idx;","what":"書き込みをブロックせずにインデックスを再構築し、インデックスの肥大化を解消する。","when":"インデックスが肥大化/破損したとき、メンテナンスウィンドウのない稼働中のシステムで。","caution":"PostgreSQL 12以降が必要。失敗すると_ccnewサフィックスの付いたINVALIDなインデックスが残る場合がある。pg_index.indisvalidを確認し、必要に応じてDROP INDEXでクリーンアップする。表全体を再構築するには: REINDEX TABLE CONCURRENTLY customer;","since":"PostgreSQL 12","note":"REINDEX ... CONCURRENTLYはPostgreSQL 12で導入された。それ以前のREINDEXはインデックスをACCESS EXCLUSIVEロックでロックしていた(ロックなしの再構築にはCREATE INDEX CONCURRENTLY + DROPが必要だった)。","tags":["reindex","concurrently","index","maintenance"]},{"id":"autovacuum-per-table","task":"特定の表のautovacuumをチューニング","category":"メンテナンス","command":"ALTER TABLE customer SET (autovacuum_vacuum_scale_factor = 0.02, autovacuum_vacuum_threshold = 5000, autovacuum_analyze_scale_factor = 0.01);","what":"この表に限ってautovacuumの起動しきい値を下げ、大きい/高負荷の表がより頻繁にvacuumされるようにする。","when":"UPDATE/DELETEの多い大きな表でautovacuumが追いつかないときに。","caution":"積極的すぎる設定は、autovacuumの常時実行とI/O負荷につながる可能性がある。設定を戻すには: ALTER TABLE customer RESET (autovacuum_vacuum_scale_factor);","tags":["autovacuum","tuning","table","maintenance"]},{"id":"statistics-target","task":"列の統計ターゲットを引き上げる","category":"メンテナンス","command":"ALTER TABLE customer ALTER COLUMN city SET STATISTICS 500; ANALYZE customer;","what":"特定の列について収集するヒストグラム/サンプルの詳細度を上げ、プランナの推定を改善する。","when":"分布の偏った列で悪い実行計画が発生するときに。","caution":"高い値(デフォルト100、最大10000)はANALYZE時間と計画作成時間を増加させる。変更はANALYZEの後にのみ有効になる。","tags":["statistics","planner","analyze","tuning"]},{"id":"alter-system-reload","task":"パラメータを変更してリロード(ALTER SYSTEM)","category":"パラメータ","command":"ALTER SYSTEM SET work_mem = '64MB'; SELECT pg_reload_conf();","what":"パラメータをpostgresql.auto.confに書き込み、構成をリロードする(再起動不要のパラメータは直ちに有効)。","when":"work_memやログ設定など、リロードで適用できるパラメータを永続的に変更するため。","caution":"shared_buffersやmax_connectionsなど一部のパラメータは、リロードではなく再起動時にのみ有効になる。pg_settings.context = 'postmaster'のものは再起動が必要。","tags":["alter-system","reload","parameter","config"]},{"id":"session-set","task":"セッションのパラメータを変更(SET)","category":"パラメータ","command":"SET work_mem = '256MB';","what":"現在の接続/セッションに限りパラメータを変更する。セッション終了時に元に戻る。","when":"単一の重いクエリやバッチジョブのために、一時的に設定を引き上げる必要があるときに。","caution":"単一のトランザクションに限定するにはSET LOCALを使用する。グローバルな変更にはALTER SYSTEMが必要。","tags":["set","session","parameter","work-mem"]},{"id":"show-setting","task":"現在のパラメータ値を表示","category":"パラメータ","command":"SELECT name, setting, unit, context, source FROM pg_settings WHERE name = 'shared_buffers';","what":"パラメータの有効値、単位、適用方法(context)、設定元を表示する。","when":"パラメータの実行時の値と、再起動とリロードのどちらが必要かを確認するため。","caution":"ショートカット: SHOW shared_buffers; または SELECT current_setting('shared_buffers'); context列が'postmaster'の場合、再起動が必要。","tags":["show","pg_settings","parameter","current-setting"]},{"id":"physical-replica-basebackup","task":"物理レプリカを構築(pg_basebackup)","category":"レプリケーション","command":"pg_basebackup -h primary_host -U replicator -D /var/lib/postgresql/16/main -Fp -Xs -P -R --slot=replica_slot_1 -C","what":"プライマリから物理的な全体バックアップを取得し、WALをストリーミングし(-Xs)、standby.signalとprimary_conninfoを書き込み(-R)、レプリケーションスロットを作成する(-C)。","when":"新しいストリーミングスタンバイ(読み取りレプリカまたはフェイルオーバー先)を構築するため。","caution":"ターゲットディレクトリ(-D)は空である必要がある。プライマリでは、pg_hba.confでreplicatorユーザーに'replication'アクセスを許可し、十分なwal_keep_size/スロットが必要。PostgreSQL 12以降では、-Rはrecovery.confではなくstandby.signalを生成する。","tags":["replication","basebackup","standby","physical"]},{"id":"promote-replica","task":"レプリカをプライマリに昇格","category":"レプリケーション","command":"SELECT pg_promote(wait := true, wait_seconds := 60);","what":"スタンバイサーバーをリカバリモードから抜け出させ、書き込み可能なプライマリにする。","when":"計画的または緊急のフェイルオーバーで、スタンバイを新しいプライマリにするため。","caution":"昇格は元に戻せず、サーバーは旧プライマリに追従できなくなる。スプリットブレインを防ぐため、旧プライマリが本当に停止していることを確認する。代替手段: pg_ctl promote。","since":"PostgreSQL 12","note":"pg_promote() SQL関数はPostgreSQL 12で導入された。それ以前は、トリガーファイル(promote_trigger_file)またはpg_ctl promoteでスタンバイを昇格していた。","tags":["replication","promote","failover","standby"]},{"id":"replication-lag","task":"レプリケーション遅延を表示","category":"レプリケーション","command":"SELECT client_addr, state, sent_lsn, replay_lsn, pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS replay_lag_bytes, write_lag, flush_lag, replay_lag FROM pg_stat_replication;","what":"プライマリ上で、プライマリの現在のWAL位置に対する各スタンバイのリプレイ差をバイト単位で表示し、write/flush/replayの遅延も表示する。","when":"ストリーミングレプリケーションの遅れを監視するため(プライマリで実行)。","caution":"スタンバイでの秒単位の遅延: SELECT now() - pg_last_xact_replay_timestamp(); この値はプライマリで書き込みがない場合も増加するため、LSN差と併せて解釈する。結果が空の場合、スタンバイは接続されていない。","tags":["replication","lag","lsn","monitor"]},{"id":"replication-slot","task":"レプリケーションスロットを作成・削除","category":"レプリケーション","command":"SELECT pg_create_physical_replication_slot('replica_slot_1'); -- To drop: SELECT pg_drop_replication_slot('replica_slot_1');","what":"スタンバイが確認するまでプライマリが必要なWALを削除しないことを保証する物理スロットを作成する。2つ目のコマンドはスロットを削除する。","when":"短時間の停止中にスタンバイがWALを失わないようにするため。","caution":"未使用/放置されたスロットはWALの蓄積とディスク満杯の原因になる。スロットの状態を監視する: SELECT slot_name, active, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained FROM pg_replication_slots; アクティブなスロットは削除できない。","tags":["replication","slot","wal","cleanup"]},{"id":"logical-replication","task":"論理レプリケーションのパブリケーションとサブスクリプションを設定","category":"レプリケーション","command":"-- Source (publisher): CREATE PUBLICATION pub_customer FOR TABLE customer; -- Target (subscriber): CREATE SUBSCRIPTION sub_customer CONNECTION 'host=primary_host dbname=appdb user=replicator password=secret' PUBLICATION pub_customer;","what":"ソースで特定の表のパブリケーションを作成し、ターゲットでそれに接続するサブスクリプションを作成して、表レベルの論理レプリケーションを開始する。","when":"バージョンアップグレード、選択した表の別サーバーへのレプリケーション、一方向のデータ配信に。","caution":"PostgreSQL 10以降が必要。ターゲットの表のスキーマは事前に存在している必要がある。サブスクリプションは初期COPYを自動的に実行する。wal_levelはlogicalである必要がある(再起動が必要)。DDLの変更とシーケンス値はレプリケートされない。スキーマ変更は両側に個別に適用し、切り替え時にsetvalでシーケンスを同期する。","since":"PostgreSQL 10","note":"組込みの論理レプリケーション(CREATE PUBLICATION / CREATE SUBSCRIPTION)はPostgreSQL 10で導入された。それ以前は、同じ用途にpglogicalなどの外部拡張が必要だった。","tags":["logical","replication","publication","subscription"]},{"id":"terminate-backend","task":"バックエンドを終了(pg_terminate_backend)","category":"セッション","command":"SELECT pg_terminate_backend(12345);","what":"指定したPIDのバックエンドプロセスを強制終了し、接続と実行中のトランザクションを切断する。","when":"停止/ハングした接続やロックを保持しているセッションを閉じるため。","caution":"実行中のトランザクションはロールバックされ、未コミットの作業は失われる。まず穏やかなpg_cancel_backendを試す。pg_stat_activityでPIDを確認する。","tags":["terminate","backend","session","kill"]},{"id":"cancel-backend","task":"実行中のクエリを取り消す(pg_cancel_backend)","category":"セッション","command":"SELECT pg_cancel_backend(12345);","what":"指定したPIDで現在実行中のクエリを取り消す。接続は開いたまま。","when":"接続を切らずに長時間実行のクエリを停止するため。","caution":"アクティブなクエリを取り消すのみで、idle in transaction状態のセッションは閉じない。それにはpg_terminate_backendが必要。","tags":["cancel","backend","query","session"]},{"id":"active-blocking-queries","task":"アクティブなクエリとブロックしているクエリを表示","category":"セッション","command":"SELECT pid, usename, state, wait_event_type, wait_event, pg_blocking_pids(pid) AS blocking_pids, now() - query_start AS duration, left(query, 100) AS query FROM pg_stat_activity WHERE state <> 'idle' AND pid <> pg_backend_pid() ORDER BY duration DESC;","what":"idle以外のすべてのバックエンド、それらをブロックしているPID、実行時間を一覧表示する。","when":"ロック/ブロッキングの問題と長時間実行のクエリを診断するため。","caution":"pg_blocking_pidsはPostgreSQL 9.6以降で使用可能。blocking_pids配列が空でない場合、それらのPIDがロックを保持している。必要に応じてそのPIDを取り消し/終了する。","since":"PostgreSQL 9.6","note":"pg_blocking_pids()関数はPostgreSQL 9.6で導入された。それ以前は、ブロックしているプロセスを特定するにはpg_locksを手動で結合する必要があった。","tags":["activity","blocking","lock","session"]},{"id":"create-extension","task":"拡張を追加","category":"拡張機能","command":"CREATE EXTENSION IF NOT EXISTS pg_stat_statements;","what":"指定した拡張を現在のデータベースにインストールする(関数、ビュー、型などを追加する)。","when":"pg_stat_statements、pgcrypto、postgisなどの追加機能が必要なときに。","caution":"pg_stat_statementsなどshared_preload_librariesが必要な拡張は、先にpostgresql.confに追加してサーバーを再起動する。拡張のファイル(contribパッケージ)がサーバーにインストールされている必要がある。","tags":["extension","create","pg_stat_statements","plugin"]},{"id":"list-extensions","task":"インストール済みの拡張を一覧表示","category":"拡張機能","command":"SELECT extname AS extension, extversion AS version FROM pg_extension ORDER BY extname;","what":"現在のデータベースにインストールされているすべての拡張とそのバージョンを一覧表示する。","when":"どの拡張がインストールされているか、更新が必要かを確認するため。","caution":"インストール可能な(未インストールの)拡張を確認するには: SELECT * FROM pg_available_extensions; アップグレード: ALTER EXTENSION pg_stat_statements UPDATE;","tags":["extension","list","pg_extension","plugin"]}]},"recipes/postgres-ha.json":{"engineId":"postgres","engine":"PostgreSQL","order":1,"recipes":[{"id":"patroni-cluster-status","task":"Patroniクラスタの状態、トポロジ、履歴を表示","category":"Patroni","command":"# Members, roles, state, timeline and lag (MB):\npatronictl -c /etc/patroni/patroni.yml list <cluster>\n# Extended info (pending restart, tags) + timestamp, refresh every 5 s:\npatronictl -c /etc/patroni/patroni.yml list <cluster> -e -t -w 5\n# Leader -> replica tree (including cascading replicas):\npatronictl -c /etc/patroni/patroni.yml topology <cluster>\n# Past failovers/switchovers (timeline, LSN, reason, time):\npatronictl -c /etc/patroni/patroni.yml history <cluster>","what":"DCSから見たPatroniのクラスタ情報を表示する: リーダー/レプリカのロール、メンバーの状態(running/streaming)、タイムライン、レプリケーション遅延、保留中の再起動。historyはタイムラインの変更とその発生LSNを一覧表示する。","when":"すべてのスイッチオーバー/フェイルオーバー/メンテナンスの前後に。アラート発生時の最初の診断手順として。","caution":"出力はDCSに格納されている内容を反映する。DCSに到達できない場合、コマンドは失敗するか古いデータを表示する場合がある。すべてのメンバーが同じタイムラインにあり、Lag in MBがmaximum_lag_on_failoverを下回っていることを確認するまでスイッチオーバーを開始しない。","untested":true,"tags":["patroni","cluster status","topology","history","lag"]},{"id":"patroni-switchover","task":"Patroniで計画的スイッチオーバーを実行","category":"Patroni","command":"# Immediate switchover without confirmation:\npatronictl -c /etc/patroni/patroni.yml switchover <cluster> --leader <leader_member> --candidate <member> --force\n# Scheduled switchover (ISO 8601 timestamp with time zone):\npatronictl -c /etc/patroni/patroni.yml switchover <cluster> --leader <leader_member> --candidate <member> --scheduled '2026-10-10T02:00:00+03:00' --force\n# Cancel a pending scheduled switchover:\npatronictl -c /etc/patroni/patroni.yml flush <cluster> switchover","what":"正常なリーダーを制御された方法で降格し、選択したレプリカ(--candidate)を昇格する。旧リーダーは新リーダーのレプリカとして自動的に再参加する。--scheduledは操作を指定時刻まで延期する。","when":"メンテナンス(OSパッチ、ハードウェア交換、マイナーバージョンアップグレード)前にプライマリを別ノードへ移す、またはフェイルオーバー後に元のロールに戻すため。","caution":"リーダーが変わるとすべての接続が切断されるため、アプリケーションは再接続できる必要がある。候補の遅延がmaximum_lag_on_failoverを超える場合、Patroniはスイッチオーバーを拒否する。synchronous_modeが有効な場合、候補は同期スタンバイである必要がある。","note":"古いPatroniリリースでは--leaderオプションは--masterという名前だった。Patroni 4で--masterは削除された。--primaryは--leaderと同等。","untested":true,"tags":["patroni","switchover","planned switchover","maintenance","leader"]},{"id":"patroni-failover","task":"Patroniで手動フェイルオーバーを実行","category":"Patroni","command":"# Manual failover while the leader is unhealthy (candidate is mandatory):\npatronictl -c /etc/patroni/patroni.yml failover <cluster> --candidate <member> --force\n# Verify the result and the new timeline:\npatronictl -c /etc/patroni/patroni.yml list <cluster>\npatronictl -c /etc/patroni/patroni.yml history <cluster>","what":"リーダーの状態にかかわらず指定したレプリカを昇格する。自動フェイルオーバーが発生しなかった、または誤ったノードを選択した場合を想定している。","when":"リーダーに到達できない/異常であり、自動フェイルオーバーが作動しなかったとき(例: pauseモード)、または特定のノードへの移動を強制する必要があるときに。","caution":"非同期レプリケーションでは、候補がまだ受信していないトランザクションは失われる(RPO > 0)。リーダーが正常な場合は、フェイルオーバーではなくスイッチオーバーを使用する。旧リーダーが復帰したとき、pg_rewind(use_pg_rewindが有効な場合)またはreinitが必要になる場合がある。","note":"Patroni 3.2以降、フェイルオーバーでは--candidateが必須。failoverの--leader/--primaryオプションは3.2で非推奨となり、Patroni 4.0で削除された。リーダーを指定する必要がある場合はswitchoverを使用する。","untested":true,"tags":["patroni","failover","manual failover","promote","rpo"]},{"id":"patroni-reinit-replica","task":"Patroniで壊れたレプリカを再構築(reinit)","category":"Patroni","command":"# Wipe the replica's PGDATA and rebuild it (create_replica_methods: pgbackrest/basebackup):\npatronictl -c /etc/patroni/patroni.yml reinit <cluster> <member> --wait --force\n# Take the basebackup directly from the leader instead of the backup repository:\npatronictl -c /etc/patroni/patroni.yml reinit <cluster> <member> --from-leader --wait --force","what":"指定したレプリカのデータディレクトリを削除し、Patroniのcreate_replica_methods(pgBackRestのリストアまたはpg_basebackup)に従って一から再構築する。","when":"タイムラインの不一致、pg_rewindの失敗、WALの欠落、データ破損によりレプリカがレプリケーションに再参加できないときに。","caution":"メンバーのローカルデータはすべて削除される。コマンドが正しいメンバーを対象としていることを再確認する(Patroniはリーダーでのreinitを拒否する)。大規模データベースでは数時間かかる場合があり、リーダーにI/O/ネットワーク負荷がかかる。その間、クラスタはレプリカが1つ少ない状態で稼働する。--from-leaderは最近のPatroni 4.xリリースにのみ存在し(patronictl reinit --helpで確認する)、create_replica_methodsをスキップしてリーダーからpg_basebackupを取得する。","untested":true,"tags":["patroni","reinit","rebuild replica","rebuild","basebackup"]},{"id":"patroni-edit-config","task":"Patroniでクラスタ全体のパラメータを変更(edit-config)し、保留中の再起動を適用","category":"Patroni","command":"# Show the current dynamic configuration stored in the DCS:\npatronictl -c /etc/patroni/patroni.yml show-config <cluster>\n# Cluster-wide PostgreSQL parameter (distributed to all members):\npatronictl -c /etc/patroni/patroni.yml edit-config <cluster> -p 'work_mem=64MB' -p 'max_connections=500' --force\n# Patroni behavior parameter:\npatronictl -c /etc/patroni/patroni.yml edit-config <cluster> -s 'maximum_lag_on_failover=1048576' --force\n# Parameters requiring a restart are flagged as 'Pending restart':\npatronictl -c /etc/patroni/patroni.yml list <cluster> -e\n# Restart replicas first, then the leader:\npatronictl -c /etc/patroni/patroni.yml restart <cluster> --role replica --pending --force\npatronictl -c /etc/patroni/patroni.yml restart <cluster> --role leader --pending --force","what":"PostgreSQLとPatroniのパラメータをDCSの動的構成に書き込む。Patroniは変更を全メンバーに適用し、リロード可能なものは直ちに有効化し、再起動が必要なものは'Pending restart'としてマークする。","when":"Patroni管理下のクラスタの全ノードで、max_connections、shared_buffers、work_memなどのパラメータを一貫して変更するため。","caution":"Patroni管理下では、postgresql.confを手動で編集したりALTER SYSTEMを使用したりしない。Patroniはpostgresql.confを書き換え、postgresql.auto.confはPatroniの設定を上書きするため、ノード間でずれが生じる。スタンバイのmax_connections、max_worker_processes、max_wal_senders、max_prepared_transactions、max_locks_per_transactionはプライマリより低くできないため、再起動の順序をそれに応じて計画する。","untested":true,"tags":["patroni","edit-config","parameter","pending restart","dcs"]},{"id":"patroni-pause-resume","task":"Patroniをメンテナンスモードにし、元に戻す(pause/resume)","category":"Patroni","command":"# Maintenance mode: automatic failover and Patroni's control over PostgreSQL stop\npatronictl -c /etc/patroni/patroni.yml pause <cluster> --wait\npatronictl -c /etc/patroni/patroni.yml list <cluster>          # should show 'Maintenance mode: on'\n# ... maintenance work (e.g. manual PostgreSQL restart, DCS maintenance) ...\npatronictl -c /etc/patroni/patroni.yml resume <cluster> --wait","what":"クラスタをメンテナンスモードにする: Patroniは自動フェイルオーバーを行わず、停止したPostgreSQLを再起動しない。resumeで通常の管理に戻る。","when":"DCS(etcd/Consul)のメンテナンス、Patroniのアップグレード、Patroniの介入なしにPostgreSQLを手動で管理する必要があるときに。","caution":"pause中にプライマリがクラッシュすると自動フェイルオーバーは行われず、停止が続く。メンテナンス後のresumeを忘れない。アラートに'Maintenance mode'のチェックを追加する。pause中にPostgreSQLを手動でプライマリとして起動すると、スプリットブレインが発生する可能性がある。","untested":true,"tags":["patroni","pause","resume","maintenance mode","maintenance"]},{"id":"patroni-dcs-health","task":"Patroni DCS(etcd/Consul)とREST APIの健全性を確認","category":"Patroni","command":"# etcd v3 (default API in etcd 3.4+): member health, leader, raft term and DB size\netcdctl --endpoints=https://<etcd1>:2379,https://<etcd2>:2379,https://<etcd3>:2379 --cacert=/etc/etcd/ca.crt endpoint health --cluster -w table\netcdctl --endpoints=https://<etcd1>:2379 --cacert=/etc/etcd/ca.crt endpoint status --cluster -w table\netcdctl --endpoints=https://<etcd1>:2379 --cacert=/etc/etcd/ca.crt alarm list\n# Consul:\nconsul members\nconsul operator raft list-peers\n# Patroni REST API (on each member):\ncurl -s http://<member>:8008/cluster | python3 -m json.tool\ncurl -s -o /dev/null -w '%{http_code}\\n' http://<member>:8008/primary   # 200 = leader, 503 = not leader","what":"Patroniがリーダーロックを保持するDCSのクォーラム、リーダー、容量と、Patroni REST APIを通じた各メンバー自身のロール認識を確認する。/primaryエンドポイントはロードバランサ(HAProxy)のヘルスチェックの基礎となる。","when":"Patroniが'DCS is not accessible'をログに出したとき、予期しない降格/フェイルオーバーの後、定期的なヘルスチェックとして。","caution":"DCSがクォーラムを失うと、Patroniはリーダーロックを更新できず、プライマリを読み取り専用に降格する(failsafe_mode、Patroni 3.0以降が有効な場合を除く)。したがってetcdの停止はデータベースの書き込み停止となる。etcdのDBサイズがクォータ(デフォルト2 GB)に達すると、NOSPACEアラームが書き込みを停止する。DCSは別々のディスク上の少なくとも3ノードで実行する。","untested":true,"tags":["patroni","etcd","consul","dcs health","rest api"]},{"id":"pgbackrest-archive-config","task":"pgBackRest用にWALアーカイブを構成(archive-push/archive-get)","category":"バックアップとPITR","command":"# postgresql.conf (changing archive_mode requires a restart):\nwal_level = replica\narchive_mode = on\narchive_command = 'pgbackrest --stanza=<stanza> archive-push %p'\n# On the restore/standby side (in postgresql.conf on PG12+):\nrestore_command = 'pgbackrest --stanza=<stanza> archive-get %f \"%p\"'\n\n# /etc/pgbackrest/pgbackrest.conf (database host, local repo example):\n[global]\nrepo1-path=/var/lib/pgbackrest\nrepo1-retention-full=2\narchive-async=y\nspool-path=/var/spool/pgbackrest\nprocess-max=4\ncompress-type=zst\nstart-fast=y\n\n[<stanza>]\npg1-path=/var/lib/pgsql/16/data","what":"PostgreSQLが完了した各WALセグメントをpgBackRestリポジトリに送信し(archive-push)、リカバリ時にそこから取得する(archive-get)ようにする。archive-asyncはスプールディレクトリを介して送信を並列・非同期にする。","when":"pgBackRestで物理バックアップとPITRを設定する最初の手順として、stanza-createの前に。","caution":"archive_commandが失敗している間はWALがpg_walに蓄積し、ディスクが満杯になるとプライマリが停止する。pg_stat_archiver.failed_countを監視する。Patroniでは、これらのパラメータはpostgresql.confではなくpatroni.yml / edit-configで設定する。2つの異なるクラスタから同じstanzaにアーカイブするとリポジトリが破損する。","untested":true,"tags":["pgbackrest","archiving","archive_command","wal archive","configuration"]},{"id":"pgbackrest-stanza-create-check","task":"pgBackRestのstanzaを作成し、アーカイブを検証(stanza-create/check)","category":"バックアップとPITR","command":"# Create the stanza in the repository (once):\nsudo -u postgres pgbackrest --stanza=<stanza> --log-level-console=info stanza-create\n# Verify configuration and archiving end to end (switches WAL and waits for the segment to reach the repo):\nsudo -u postgres pgbackrest --stanza=<stanza> --log-level-console=info check","what":"stanza-createはリポジトリにクラスタのメタデータ(システム識別子、バージョン)を作成する。checkは実際のWALスイッチによって、PostgreSQL接続、archive_command、リポジトリへのWAL到着をテストする。","when":"初期設定時、archive_commandやリポジトリの変更後、監視/cronのヘルスチェックとして。","caution":"コマンドはpostgres(またはリポジトリ所有者)で実行する。rootで実行するとファイル所有権が壊れる。メジャーバージョンアップグレード後は、stanza-createではなくstanza-upgradeが必要。checkが失敗した場合、バックアップが完了してもPITRが不可能な場合がある。","untested":true,"tags":["pgbackrest","stanza","stanza-create","check","archive verification"]},{"id":"pgbackrest-backup-full-diff-incr","task":"pgBackRestで全体、差分、増分バックアップを取得","category":"バックアップとPITR","command":"sudo -u postgres pgbackrest --stanza=<stanza> --type=full backup\nsudo -u postgres pgbackrest --stanza=<stanza> --type=diff backup   # changes since the last full\nsudo -u postgres pgbackrest --stanza=<stanza> --type=incr backup   # changes since the last backup of any type\n# cron example (postgres user): full on Sunday, diff on other days\n# 30 1 * * 0   pgbackrest --stanza=<stanza> --type=full backup\n# 30 1 * * 1-6 pgbackrest --stanza=<stanza> --type=diff backup","what":"fullはクラスタ全体を、diffは最後のfull以降に変更されたファイルを、incrは種類を問わず最後のバックアップ以降に変更されたファイルをコピーする。最後に必要なWALがアーカイブ済みであることが検証され、保存期間に従ってexpireが自動的に実行される。","when":"定期的なバックアップスケジュールで: 一般的には週次full + 日次diff/incr、大規模クラスタではより頻繁なincr。","caution":"以前のfullがない場合、diff/incrの要求は自動的にfullに昇格される。incrのチェーンが長いほどリストア時間と依存関係が増える。チェーン内の1つのバックアップを失うと、それ以降のバックアップは使用できなくなる。プライマリの負荷を軽減するには、backup-standby=yでスタンバイからバックアップする(調整のためにプライマリは引き続き必要)。","untested":true,"tags":["pgbackrest","backup","full","differential","incremental"]},{"id":"pgbackrest-info","task":"pgBackRestのバックアップカタログとWALアーカイブ範囲を表示(info)","category":"バックアップとPITR","command":"sudo -u postgres pgbackrest --stanza=<stanza> info\n# JSON for monitoring/automation:\nsudo -u postgres pgbackrest --stanza=<stanza> --output=json info\n# Details of a single backup (databases, LSN range):\nsudo -u postgres pgbackrest --stanza=<stanza> --set=<backup_label> info","what":"stanzaの状態、各バックアップのラベル、種類、開始/終了時刻、サイズ、依存するバックアップ、リポジトリ内のWALアーカイブのmin/max範囲を一覧表示する。","when":"リストア/PITRの前にターゲット時刻がカバーされていることを確認するため、バックアップが定期的に実行されていることの監視、保存期間の確認に。","caution":"infoはバックアップが存在することを示すのみで、リストア可能であることは示さない。定期的なテストリストアとpgbackrest verifyで検証する。WALのmin/max範囲にギャップがある場合、PITRはそれを越えられない。","untested":true,"tags":["pgbackrest","info","backup list","catalog","monitoring"]},{"id":"pgbackrest-restore-latest","task":"pgBackRestで最新のバックアップをリストア","category":"バックアップとPITR","command":"# PostgreSQL must be stopped and PGDATA empty (otherwise use --delta)\nsudo systemctl stop postgresql-16\nsudo -u postgres pgbackrest --stanza=<stanza> --log-level-console=info restore\n# From a specific backup: --set=<backup_label>\n# When restoring to another server for testing, disable archiving:\n# sudo -u postgres pgbackrest --stanza=<stanza> --archive-mode=off restore\nsudo systemctl start postgresql-16","what":"最新のバックアップをリストアし、recovery.signalとrestore_commandを書き込む。起動時にPostgreSQLはアーカイブされたすべてのWALを最新の一貫性のある時点まで再生し、新しいタイムラインで昇格する。","when":"プライマリのデータディレクトリが失われた/破損したとき、またはバックアップがリストア可能であることを定期的にテストするときに。","caution":"リストアしたクラスタと旧クラスタが同時に同じstanzaにアーカイブすると、リポジトリが破損する。テストリストアには--archive-mode=offを使用する。Patroni管理下では、先にクラスタをpauseするかPatroniを停止する。そうしないとPatroniが介入する。PGDATA外の表領域やパスが存在する場合は、--tablespace-mapとlinkのオプションを確認する。","untested":true,"tags":["pgbackrest","restore","restore","recovery","disaster recovery"]},{"id":"pgbackrest-pitr-restore","task":"pgBackRestで特定時点にリストア(PITR、--type=time)","category":"バックアップとPITR","command":"sudo systemctl stop postgresql-16\nsudo -u postgres pgbackrest --stanza=<stanza> --delta --type=time \"--target=2026-10-08 14:30:00+03\" --target-action=pause restore\nsudo systemctl start postgresql-16\n# Recovery stops at the target (read-only); validate the data:\npsql -X -c \"SELECT pg_is_in_recovery(), pg_last_xact_replay_timestamp();\"\n# If correct, end recovery and open read-write on a new timeline:\npsql -X -c \"SELECT pg_wal_replay_resume();\"","what":"ターゲット時刻より前に完了したバックアップをリストアし、ターゲットまでのWALのみを再生する。target-action=pauseはターゲットで停止してデータを検証できるようにし、pg_wal_replay_resume()で昇格する。","when":"誤ったDELETE/DROP/UPDATEなどの論理エラーの直前の時点に戻すため。","caution":"このクラスタではターゲット以降のすべての変更が失われる。可能であれば別のサーバーでPITRを実行し、影響を受けたデータのみをpg_dumpで戻す。ターゲットにはタイムゾーンを明示する。pgBackRest 2.24以降はターゲット以前の適切なバックアップを自動的に選択する。古いリリースでは--setでターゲットより前に完了したバックアップを指定する。ターゲットがバックアップの終了時刻より前の場合、リストアは一貫性に到達できない。","untested":true,"tags":["pgbackrest","pitr","point in time recovery","point in time","recovery"]},{"id":"pgbackrest-delta-restore-standby","task":"pgBackRestのデルタリストアでスタンバイを迅速に再構築","category":"バックアップとPITR","command":"sudo systemctl stop postgresql-16\n# Keeps the existing PGDATA and fetches only differing files; writes standby.signal:\nsudo -u postgres pgbackrest --stanza=<stanza> --delta --type=standby \"--recovery-option=primary_conninfo=host=<primary_host> port=5432 user=replicator application_name=<standby_name>\" restore\nsudo systemctl start postgresql-16\npsql -X -c \"SELECT status, sender_host FROM pg_stat_wal_receiver;\"","what":"--deltaは既存のPGDATA内のファイルをバックアップと比較し(サイズ/タイムスタンプとチェックサム)、差異のあるファイルのみをコピーする。--type=standbyはstandby.signalを書き込み、recovery-optionはprimary_conninfoを追加する。スタンバイはまずアーカイブから追いつき、その後ストリーミングに切り替わる。","when":"遅延したスタンバイ、タイムラインが分岐したスタンバイ、pg_rewindが失敗した旧プライマリを、フルコピーなしでレプリカに戻すため。","caution":"デルタはターゲットディレクトリ内の差異のあるファイルや余分なファイルをバックアップのもので置換/削除する。誤ったサーバーで実行するとそのサーバーのデータが破壊される。pgBackRestは稼働中のPostgreSQLへのリストアを拒否するが、サービスが停止していることを自分でも確認する。パスワードはprimary_conninfoではなく.pgpassに保存する。","untested":true,"tags":["pgbackrest","delta restore","rebuild standby","rebuild","replica"]},{"id":"pgbackrest-retention-expire","task":"pgBackRestの保存期間を構成し、expireを実行","category":"バックアップとPITR","command":"# /etc/pgbackrest/pgbackrest.conf [global] - count based:\nrepo1-retention-full-type=count\nrepo1-retention-full=2\nrepo1-retention-diff=6\n# Time-based alternative (at least a 14-day PITR window):\n# repo1-retention-full-type=time\n# repo1-retention-full=14\n\n# Expire runs automatically after each backup; to trigger it manually:\nsudo -u postgres pgbackrest --stanza=<stanza> --log-level-console=info expire","what":"保持するfull/diffバックアップの数(count)またはfullバックアップの日数(time)を定義する。expireはポリシー外のバックアップ、それに依存するdiff/incrバックアップ、不要になったWALアーカイブを削除する。","when":"リポジトリサイズを管理し、RPO/PITRウィンドウの要件(例: 14日前まで戻れること)を保証するため。","caution":"PITRウィンドウは保持されている最も古いfullバックアップによって制限される。週次fullとretention-full=2では、最大約2週間前までしか戻れない。repo1-retention-archiveはデフォルトでfullの保存期間に従う。これより低く設定すると、古いバックアップは一貫性ポイントまでしか使用できなくなる。expireは元に戻せない。","untested":true,"tags":["pgbackrest","retention","retention period","expire","backup cleanup"]},{"id":"standby-manual-config","task":"スタンバイを手動で構成(standby.signal + primary_conninfo)","category":"レプリケーション","command":"# On the standby, with PostgreSQL stopped (PGDATA came from a backup/copy):\ntouch $PGDATA/standby.signal\ncat >> $PGDATA/postgresql.auto.conf <<'EOF'\nprimary_conninfo = 'host=<primary_host> port=5432 user=replicator application_name=<standby_name>'\nprimary_slot_name = '<slot>'\nEOF\npg_ctl -D $PGDATA start\n# PG13+: change the connection on a running standby without restart (e.g. point it to a new primary):\npsql -X -c \"ALTER SYSTEM SET primary_conninfo = 'host=<new_primary_host> port=5432 user=replicator application_name=<standby_name>'\" -c \"SELECT pg_reload_conf();\"","what":"standby.signalファイルによりサーバーはスタンバイとして起動する。primary_conninfoはストリーミング接続を、primary_slot_nameは使用するレプリケーションスロットを定義する。PG13以降では、primary_conninfoとprimary_slot_nameはリロードで変更できる。","when":"pg_basebackup -Rを使わずに準備したデータディレクトリ(pgBackRest、スナップショット、rsync)をスタンバイにする、または既存のスタンバイを新しいプライマリに向けるため。","caution":"スロットは事前にプライマリで作成しておく必要がある(pg_create_physical_replication_slot)。そうでないとwalreceiverが失敗し続ける。パスワードはconninfoではなく~/.pgpassに置く。application_nameはsynchronous_standby_names内の名前と完全に一致する必要がある。standby.signalを忘れると、サーバーはプライマリとして起動し、別のタイムラインに移る。","since":"PostgreSQL 12","note":"PostgreSQL 12より前は、これらの設定はrecovery.conf(standby_mode = on)にあった。PG12でstandby.signalとpostgresql.confに移された。PG13より前は、primary_conninfoの変更に再起動が必要だった。","tags":["standby","standby.signal","primary_conninfo","replica setup","streaming"]},{"id":"standby-wal-receiver-lag","task":"スタンバイでWALの受信遅延と再生遅延を監視(pg_stat_wal_receiver)","category":"レプリケーション","command":"-- Run on the standby:\nSELECT pg_is_in_recovery() AS in_recovery,\n       pg_last_wal_receive_lsn() AS receive_lsn,\n       pg_last_wal_replay_lsn() AS replay_lsn,\n       pg_size_pretty(pg_wal_lsn_diff(pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn())) AS replay_backlog,\n       now() - pg_last_xact_replay_timestamp() AS last_replay_age,\n       pg_get_wal_replay_pause_state() AS pause_state;\nSELECT pid, status, sender_host, sender_port, slot_name, received_tli, flushed_lsn, latest_end_lsn, now() - last_msg_receipt_time AS since_last_msg FROM pg_stat_wal_receiver;","what":"スタンバイが受信したWAL量と適用したWAL量(再生バックログ)、最後に再生されたトランザクションの経過時間、再生が一時停止しているか、walreceiverの接続状態(どのプライマリ、スロット、タイムライン、最終メッセージ時刻)を表示する。","when":"プライマリに到達できない場合やカスケードスタンバイでの遅延診断に。「スタンバイ遅延」アラート時に、ネットワーク(受信)の問題と再生(I/O、競合)の問題を切り分けるため。","caution":"pg_stat_wal_receiverが行を返さない場合、スタンバイはストリーミングしていない(アーカイブから供給されているか切断されている)。last_replay_ageはプライマリで書き込みがなくても増加するため、receive_lsn/replay_lsnの差と併せて解釈する。受信が進む一方で再生バックログが増える場合、スタンバイに長時間のクエリ(max_standby_streaming_delay)があるか、I/Oのボトルネックがある。","since":"PostgreSQL 14","note":"pg_get_wal_replay_pause_state()はPostgreSQL 14で追加された。それ以前はpg_is_wal_replay_paused()のみが存在した。クエリの他の部分はPG10以降で動作する。","tags":["standby","replication lag","wal receiver","replay","lag"]},{"id":"pg-rewind-old-primary","task":"フェイルオーバー後にpg_rewindで旧プライマリをレプリカとして再参加させる","category":"レプリケーション","command":"# Prerequisite (must be set BEFORE the incident): wal_log_hints = on OR data checksums; full_page_writes = on\npg_controldata $PGDATA | grep -E 'wal_log_hints|checksum'\n# 1) The old primary must be stopped:\npg_ctl -D $PGDATA stop -m fast\n# 2) Dry run first:\npg_rewind --target-pgdata=$PGDATA --source-server='host=<new_primary_host> port=5432 user=postgres dbname=postgres' --progress --dry-run\n# 3) Actual rewind + standby configuration (standby.signal + primary_conninfo):\npg_rewind --target-pgdata=$PGDATA --source-server='host=<new_primary_host> port=5432 user=postgres dbname=postgres' --progress --write-recovery-conf\n# 4) Review postgresql.auto.conf copied from the source (port, primary_slot_name), then start:\npg_ctl -D $PGDATA start","what":"タイムラインの分岐点以降に変更されたブロックを新プライマリからコピーし、旧プライマリのデータディレクトリを新プライマリと一貫させる。フルのbasebackupなしで数分でレプリカにする。","when":"フェイルオーバー/昇格の後に旧プライマリが復帰し、分岐した変更を持ったまま新しいタイムラインから遅れているときに。","caution":"フェイルオーバー後に旧プライマリに残り、新プライマリに届かなかったトランザクションは完全に削除される。pg_rewindは構成ファイル(postgresql.conf、postgresql.auto.conf、pg_hba.conf)もソースからコピーするため、起動前にポートとスロットの設定を修正する。分岐点以降に必要なWALがソースにもう存在しない場合は、-c(--restore-target-wal)でアーカイブから取得する。ソース接続にはスーパーユーザー、またはドキュメントに記載された関数権限を持つロールが必要。Patroniではuse_pg_rewind: trueで自動的に行われる。","since":"PostgreSQL 13","note":"-R/--write-recovery-confと-c/--restore-target-walはPostgreSQL 13で追加された。PG13以降、pg_rewindは正常に停止されていないターゲットに対して自らクラッシュリカバリを実行する(--no-ensure-shutdownで無効化)。pg_rewindは9.5から存在する。","tags":["pg_rewind","after failover","old primary","timeline","rejoin"]},{"id":"sync-standby-quorum","task":"クォーラム(ANY)または優先順位(FIRST)で同期レプリケーションを構成","category":"レプリケーション","command":"-- Quorum: commit completes once any 1 standby in the list confirms\nALTER SYSTEM SET synchronous_standby_names = 'ANY 1 (stby_a, stby_b)';\n-- Priority based: the first connected standby in the list is sync, the others 'potential'\n-- ALTER SYSTEM SET synchronous_standby_names = 'FIRST 1 (stby_a, stby_b)';\nSELECT pg_reload_conf();\nSELECT application_name, state, sync_state, sync_priority FROM pg_stat_replication ORDER BY application_name;","what":"コミット完了前に確認が必要なスタンバイを定義する: ANY Nはクォーラムベース(sync_state = quorum)、FIRST Nはリスト順で最初に接続したN台のスタンバイを同期(sync)とし、残りを待機スタンバイ(potential)とする。確認レベルはsynchronous_commit(remote_write、on、remote_apply)で設定する。","when":"フェイルオーバー時にデータ損失が許されない(RPO = 0)システムで。複数のスタンバイがある場合、単一のスタンバイ障害で書き込みが止まらないようANYが推奨される。","caution":"必要な数の同期スタンバイが接続されていない場合、コミットはエラーなしでハングし、アプリケーションが停止する。リスト内の名前はスタンバイのapplication_nameと一致する必要がある。緊急時には、単一セッションでSET synchronous_commit = localにより回避できる。Patroni管理下では、手動設定ではなくsynchronous_modeで管理する。","since":"PostgreSQL 10","note":"FIRST構文はPostgreSQL 9.6、ANY(クォーラムコミット)はPostgreSQL 10で追加された。キーワードなしの'N (a, b)'形式はFIRSTを意味する。","tags":["synchronous replication","synchronous_standby_names","quorum","rpo","sync"]},{"id":"slot-retained-wal-monitor","task":"レプリケーションスロットが保持するWALを監視し、放置されたスロットを安全に削除","category":"レプリケーション","command":"SELECT slot_name, slot_type, database, active, active_pid, wal_status,\n       pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal,\n       pg_size_pretty(safe_wal_size) AS safe_wal_size,\n       xmin, catalog_xmin\nFROM pg_replication_slots\nORDER BY pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) DESC NULLS LAST;\n-- Safe drop: drops only if not active (returns 0 rows if active)\nSELECT pg_drop_replication_slot(slot_name) FROM pg_replication_slots WHERE slot_name = '<slot>' AND NOT active;","what":"プライマリ上で各スロットが保持するWAL量、wal_status(reserved/extended/unreserved/lost)、max_slot_wal_keep_size内の残りの安全マージン(safe_wal_size)、VACUUMを妨げるxmin/catalog_xminの値を表示する。2つ目のクエリは使用中でない場合のみスロットを削除する。","when":"pg_walディレクトリが増大したとき、ディスクアラート時、定期監視で。スタンバイやサブスクライバを恒久的に削除した後のスロット整理に。","caution":"非アクティブなスロットは無制限にWALを保持し、ディスクを満杯にしてプライマリを停止させる可能性がある。xmin/catalog_xminを保持するスロットはデッドタプルのクリーンアップも妨げ、肥大化/周回のリスクを生む。スロットを削除すると、そのスタンバイ/サブスクライバは中断した位置から再開できなくなる(再構築が必要)。削除前に所有者を確認する。プライマリで実行する(スタンバイではpg_current_wal_lsn()が失敗する)。","since":"PostgreSQL 13","note":"wal_statusとsafe_wal_sizeはPostgreSQL 13で追加された。PG16では論理スロットにconflictingが、PG17ではinactive_sinceが追加された。inactive_sinceは放置されたスロットの最も直接的な指標である。","tags":["replication slot","wal accumulation","disk full","drop slot","retained wal"]},{"id":"slot-max-wal-keep-size","task":"スロットが保持できるWALを制限(max_slot_wal_keep_size)","category":"レプリケーション","command":"ALTER SYSTEM SET max_slot_wal_keep_size = '100GB';\nSELECT pg_reload_conf();\nSELECT slot_name, active, wal_status, pg_size_pretty(safe_wal_size) AS safe_wal_size FROM pg_replication_slots;","what":"レプリケーションスロットがpg_walに保持できるWALの上限を設定する(デフォルト-1 = 無制限)。超過するとチェックポイントが古いWALを削除し、スロットはwal_status = 'lost'になる。パラメータはリロードで有効になる。","when":"スロットを使用するすべてのクラスタで、切断されたスタンバイやサブスクライバがプライマリのディスクを満杯にしてシステム全体を停止させるリスクへの安全策として。","caution":"この上限はスロット所有者を犠牲にしてプライマリの稼働維持を優先する: 'lost'スロットを持つスタンバイは再構築が必要になり、論理サブスクリプションは再作成が必要になる。pg_walディスクの空き領域より小さく、想定される最長の停止中に生成されるWALより大きな値を選ぶ。wal_statusが'unreserved'の場合、スロットは失われる寸前であるため、アラートを発生させる。","since":"PostgreSQL 13","note":"max_slot_wal_keep_sizeはPostgreSQL 13で追加された。それ以前はスロットが保持するWALに上限を設ける方法がなく、唯一の保護策は監視と手動でのスロット削除だった。","tags":["max_slot_wal_keep_size","slot limit","wal accumulation","disk protection","replication slot"]},{"id":"logical-add-table-refresh","task":"パブリケーションに表を追加し、サブスクリプションをリフレッシュ(REFRESH PUBLICATION)","category":"論理レプリケーション","command":"-- Publisher:\nALTER PUBLICATION pub_app ADD TABLE orders;\n-- PG15+: all tables in a schema: ALTER PUBLICATION pub_app ADD TABLES IN SCHEMA app_schema;\nSELECT pubname, schemaname, tablename FROM pg_publication_tables WHERE pubname = 'pub_app';\n-- Subscriber (the table structure must already exist):\nALTER SUBSCRIPTION sub_app REFRESH PUBLICATION WITH (copy_data = true);\nSELECT srrelid::regclass AS table_name, srsubstate FROM pg_subscription_rel ORDER BY 1;","what":"パブリッシャでパブリケーションに新しい表を追加する。サブスクライバでは、REFRESH PUBLICATIONが新しい表をサブスクリプションに含め、copy_data = trueで初期コピー(tablesync)を開始する。srsubstate: i = init、d = データコピー、f = コピー完了、s = 同期済み、r = ready。","when":"稼働中の論理レプリケーションに新しい表を追加するとき、またはパブリケーションから表を削除するときに。","caution":"FOR ALL TABLESやTABLES IN SCHEMAのパブリケーションでも、REFRESHを実行するまでサブスクライバは新しい表を取り込まない。サブスクライバに表が存在しない場合REFRESHは失敗する。DDLはレプリケートされない。パブリッシュされた表にPRIMARY KEYまたはREPLICA IDENTITYがない場合、パブリッシャでUPDATE/DELETEが失敗する。大きな表の初期コピーは、パブリッシャ上でスロットとスナップショットを長時間保持する。","since":"PostgreSQL 10","note":"ADD TABLES IN SCHEMAはPostgreSQL 15で追加された(PG15ではWHEREによる行フィルタと列リストも追加された)。","tags":["logical replication","publication","add table","refresh publication","subscription"]},{"id":"logical-subscription-monitor","task":"論理レプリケーションを監視(pg_stat_subscription、適用エラー、スロット遅延)","category":"論理レプリケーション","command":"-- Subscriber:\nSELECT subname, pid, leader_pid, relid::regclass AS syncing_table, received_lsn, latest_end_lsn, now() - last_msg_receipt_time AS since_last_msg, latest_end_time FROM pg_stat_subscription;\nSELECT subname, apply_error_count, sync_error_count, stats_reset FROM pg_stat_subscription_stats;\n-- Publisher:\nSELECT slot_name, plugin, database, active, wal_status,\n       pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn)) AS confirmed_lag,\n       pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal\nFROM pg_replication_slots WHERE slot_type = 'logical';","what":"サブスクライバでは、apply/tablesyncワーカー、受信済みおよび確認済みLSN、最終メッセージ時刻、累積のapply/syncエラー数を表示する。パブリッシャでは、論理スロットの未確認(confirmed_flush)WALと保持している合計WALを表示する。","when":"論理レプリケーションの設定中、アップグレード/移行の切り替え時に遅延がゼロに近づくことの確認、エラーアラートに。","caution":"pidがNULLの場合、applyワーカーは実行されていない(サブスクリプションが無効、または失敗と再起動を繰り返している)。サーバーログを確認する。apply_error_countの増加は競合を示す。停止したサブスクリプションはパブリッシャ上でWALとcatalog_xminを蓄積させるため、パブリッシャのディスクとカタログの肥大化を監視する。","since":"PostgreSQL 15","note":"pg_stat_subscription_statsはPostgreSQL 15、pg_stat_subscription.leader_pidはPG16(パラレルapply)で追加された。PG17ではworker_type列が追加された。pg_stat_subscriptionの基本的な列はPG10から存在する。","tags":["logical replication","subscription monitoring","pg_stat_subscription","apply error","lag"]},{"id":"logical-conflict-skip","task":"論理レプリケーションの競合を解決(disable_on_error、SKIP)","category":"論理レプリケーション","command":"-- 1) Prevent a failing apply worker from looping forever:\nALTER SUBSCRIPTION sub_app SET (disable_on_error = true);\n-- 2) Find the finish LSN of the conflicting transaction in the subscriber log:\n--    CONTEXT: ... in transaction 749, finished at 0/5035378\n-- 3a) Preferred: fix/delete the conflicting row on the subscriber, then re-enable:\nALTER SUBSCRIPTION sub_app ENABLE;\n-- 3b) Or skip the whole remote transaction (NONE of its changes are applied on the subscriber):\nALTER SUBSCRIPTION sub_app SKIP (lsn = '0/5035378');\nALTER SUBSCRIPTION sub_app ENABLE;\nSELECT subname, subenabled, subskiplsn FROM pg_subscription;","what":"重複キー、行の欠落、権限の問題などのエラーでサブスクライバのapplyが停止した場合: disable_on_errorはサブスクリプションを自動的に無効化する。競合するデータを修正してENABLEするか、ログの'finished at' LSNで特定されるリモートトランザクション全体をSKIPする。","when":"サブスクライバへの直接書き込み、不完全な初期コピー、双方向の書き込みが原因で、applyワーカーが失敗し再起動を繰り返すときに。","caution":"SKIPはそのトランザクション内の競合していない変更も破棄し、両側は恒久的に乖離する。データの修正を優先し、SKIP後は表を比較する。競合が解決されるまで、パブリッシャ上のスロットはWALを蓄積し続ける。権限によりサブスクライバの表へのアプリケーションの書き込みを防ぐ。","since":"PostgreSQL 15","note":"SKIPとdisable_on_errorはPostgreSQL 15で追加された。それ以前は、サブスクライバでpg_replication_origin_advance()によりoriginを進めて同じことを行っていた(よりリスクが高い)。","tags":["logical replication","conflict","conflict","skip","duplicate key"]},{"id":"logical-sync-sequences","task":"論理レプリケーションでシーケンス値をサブスクライバに同期","category":"論理レプリケーション","command":"# Generate the setval script on the publisher and apply it on the subscriber (at cutover, after writes are stopped):\npsql -h <publisher_host> -d <db> -XAtc \"SELECT format('SELECT setval(%L, %s, %s);', quote_ident(schemaname) || '.' || quote_ident(sequencename), COALESCE(last_value, start_value), (last_value IS NOT NULL)::text) FROM pg_sequences;\" | psql -h <subscriber_host> -d <db> -X","what":"論理レプリケーションはシーケンス(identityを含む)の値を転送しないため、パブリッシャ上のすべてのシーケンスの最終値を読み取り、サブスクライバで同じ値を設定するsetvalコマンドを生成して直接適用する。","when":"論理レプリケーションによるアップグレード/移行の切り替え時、アプリケーションをサブスクライバに向ける直前に。","caution":"パブリッシャがまだ書き込みを受け付けている間に実行すると、値は直ちに古くなり、切り替え後に重複キーエラーが発生する。書き込みを停止してから実行するか、安全マージンを加える。DDLもレプリケートされない: スキーマ変更(ALTER TABLE、新しいインデックス)は両側に個別に、サブスクライバから先に適用する。pg_sequencesは読み取り権限のないシーケンスのlast_valueにNULLを返すため、所有者またはスーパーユーザーとしてコマンドを実行する。","since":"PostgreSQL 10","tags":["logical replication","sequence","setval","ddl not replicated","cutover"]},{"id":"logical-orphan-slot-cleanup","task":"サブスクリプションを削除し、パブリッシャ上の孤立した論理スロットをクリーンアップ","category":"論理レプリケーション","command":"-- Subscriber: while the publisher is unreachable DROP SUBSCRIPTION cannot drop the remote slot and fails; detach the slot first:\nALTER SUBSCRIPTION sub_app DISABLE;\nALTER SUBSCRIPTION sub_app SET (slot_name = NONE);\nDROP SUBSCRIPTION sub_app;\n-- Publisher: find and drop orphaned logical slots (including tablesync slots pg_<suboid>_sync_<relid>_<sysid>):\nSELECT slot_name, active, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal FROM pg_replication_slots WHERE slot_type = 'logical' AND NOT active;\nSELECT pg_drop_replication_slot('sub_app');","what":"リモートのスロットに触れずにサブスクリプションを削除する(slot_name = NONE)。その後、パブリッシャ上でコンシューマのなくなった論理スロットと、残存するtablesyncスロットを特定して削除する。","when":"パブリッシャに到達できない状態でサブスクリプションを削除する必要があるとき、移行完了後、active = falseの論理スロットがパブリッシャでWALを蓄積しているときに。","caution":"孤立した論理スロットはWALとcatalog_xminの両方を保持する: ディスクが満杯になり、システムカタログが肥大化する。ただし、スロットを削除するとそのサブスクリプションは再開できなくなる。削除前に、どのサブスクライバ(別サーバーのものを含む)もこのスロットを使用していないことを確認する。アクティブなスロットは削除できないため、先に接続中のwalsenderを終了する必要がある。","since":"PostgreSQL 10","tags":["logical replication","slot cleanup","drop subscription","orphaned slot","catalog_xmin"]},{"id":"pg-upgrade-link-runbook","task":"pg_upgrade --linkによるメジャーバージョンアップグレード(エンドツーエンドの手順書)","category":"アップグレード","command":"# As the postgres user, in a writable directory; example 16 -> 17\nexport OLD_BIN=/usr/pgsql-16/bin NEW_BIN=/usr/pgsql-17/bin\nexport OLD_DATA=/var/lib/pgsql/16/data NEW_DATA=/var/lib/pgsql/17/data\n# 0) initdb the new cluster with the same encoding/locale and checksum setting as the old one (-k if the old cluster has checksums)\n# 1) Compatibility check (can run while the old cluster is up, changes no data):\n$NEW_BIN/pg_upgrade --old-bindir=$OLD_BIN --new-bindir=$NEW_BIN --old-datadir=$OLD_DATA --new-datadir=$NEW_DATA --check\n# 2) Stop the old cluster and upgrade with hard links:\n$OLD_BIN/pg_ctl -D $OLD_DATA stop -m fast\n$NEW_BIN/pg_upgrade --old-bindir=$OLD_BIN --new-bindir=$NEW_BIN --old-datadir=$OLD_DATA --new-datadir=$NEW_DATA --link --jobs=4\n# 3) Carry postgresql.conf/pg_hba.conf customizations over to the new cluster, start it:\n$NEW_BIN/pg_ctl -D $NEW_DATA -l /tmp/pg17_start.log start\n# 4) Gather statistics, run generated scripts if any:\n$NEW_BIN/vacuumdb --all --analyze-in-stages\n# psql -X -f update_extensions.sql   (if pg_upgrade generated it)\n# 5) After validation and a fresh backup, delete the old cluster:\n./delete_old_cluster.sh","what":"まず--checkで互換性を検証し、旧クラスタのデータファイルをコピーせずに新しいバージョンにハードリンクすることで、データサイズにかかわらず数分でメジャーアップグレードを実行する。その後、統計を段階的に収集し、旧クラスタを削除する。","when":"大規模なクラスタを、許容できる短い停止時間(数分)でその場で新しいメジャーバージョンに移行するため。","caution":"--linkでは、新クラスタを起動した後は旧クラスタを安全に使用できなくなる。戻る唯一の方法はアップグレード前に取得したバックアップ。旧と新のデータディレクトリは同じファイルシステム上にある必要がある。analyzeが完了するまで、新クラスタでは計画が悪い場合がある。pgBackRestを使用している場合は、stanza-upgradeを実行し直ちに新しいfullバックアップを取得する。旧バージョンのバックアップは新クラスタにリストアできない。","note":"フィジカルスタンバイはpg_upgradeではアップグレードされない: プライマリのアップグレード後、ドキュメントのrsync --hard-links --size-only方式で更新するか、再構築する。PG17より前は論理スロットは移行されない(旧クラスタがPG17以降の場合は移行される)。PG18より前はプランナ統計は移行されない。","tags":["pg_upgrade","major upgrade","version upgrade","link","check"]},{"id":"logical-upgrade-near-zero-downtime","task":"論理レプリケーションによるほぼ無停止のメジャーバージョンアップグレード","category":"アップグレード","command":"# 0) On the old version wal_level = logical (restart); every table needs a PRIMARY KEY or REPLICA IDENTITY\n# 1) Move roles and schema to the new version (a 'role postgres already exists' error is expected):\npg_dumpall -h <old_host> --globals-only | psql -h <new_host> -X -d postgres\npg_dump -h <old_host> --schema-only --create -d <db> | psql -h <new_host> -X -d postgres\n# 2) Publication on the old version, subscription on the new version (initial copy + continuous stream):\npsql -h <old_host> -d <db> -X -c \"CREATE PUBLICATION upg_pub FOR ALL TABLES;\"\npsql -h <new_host> -d <db> -X -c \"CREATE SUBSCRIPTION upg_sub CONNECTION 'host=<old_host> dbname=<db> user=<repl_user>' PUBLICATION upg_pub;\"\n# 3) Wait until all tables are 'r' (ready) and lag is ~0:\npsql -h <new_host> -d <db> -X -c \"SELECT srsubstate, count(*) FROM pg_subscription_rel GROUP BY 1;\"\npsql -h <old_host> -d <db> -X -c \"SELECT slot_name, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn)) AS lag FROM pg_replication_slots WHERE slot_name = 'upg_sub';\"\n# 4) Cutover: stop application writes, confirm lag = 0, synchronize sequences (logical-sync-sequences)\n# 5) Drop the subscription (the remote slot is dropped too), point the application to the new server:\npsql -h <new_host> -d <db> -X -c \"DROP SUBSCRIPTION upg_sub;\"","what":"新しいバージョンで空のクラスタを構築し、スキーマを移し、論理レプリケーションで旧バージョンからデータを継続的にストリーミングする。最終の切り替え手順(書き込み停止、シーケンス同期、接続先の変更)のみが短い停止を引き起こす。逆方向の2つ目のレプリケーションで切り戻しの経路を確保できる。","when":"pg_upgradeに必要な停止時間が許容できないとき、新しいハードウェア/OSへの移行を同時に行うとき、複数のメジャーバージョンを飛び越えるときに。","caution":"DDL、シーケンス、ラージオブジェクト、マテリアライズドビューの内容はレプリケートされないため、移行中はスキーマを凍結する。主キー/replica identityのない表では、パブリッシャでUPDATE/DELETEが失敗する。大規模データベースでは初期コピーに時間がかかり、旧サーバーでWALとcatalog_xminを保持する。データベースごとに個別のパブリケーション/サブスクリプションが必要。切り替え前に行数/チェックサムを比較する。","since":"PostgreSQL 10","note":"PostgreSQL 17で追加されたpg_createsubscriberは、初期コピーなしでフィジカルスタンバイを論理サブスクライバに変換し、大規模データベースでの初期コピー時間をなくす。","tags":["upgrade","logical replication","zero downtime migration","major upgrade","cutover"]},{"id":"pgbouncer-show-pools-stats","task":"PgBouncerのプール、統計、接続を表示(SHOW POOLS/STATS/CLIENTS/SERVERS)","category":"PgBouncer","command":"# Connect to the PgBouncer admin console (user must be in admin_users/stats_users):\npsql -h 127.0.0.1 -p 6432 -U pgbouncer -d pgbouncer -X\nSHOW POOLS;    -- if cl_waiting > 0 and maxwait grows, the pool is saturated\nSHOW STATS;    -- per-database total/average query, transaction and wait times\nSHOW CLIENTS;  -- client connections (state, source address, linked server connection)\nSHOW SERVERS;  -- server connections opened to PostgreSQL\nSHOW CONFIG;","what":"各データベース/ユーザーのプールについて、アクティブおよび待機中のクライアント(cl_active、cl_waiting)、アクティブ/アイドルのサーバー接続(sv_active、sv_idle)、最長待機時間(maxwait)、クエリ/トランザクションのカウンタを表示する。","when":"アプリケーションが接続失敗/タイムアウトを報告したとき、プールのサイジング、メンテナンス前のアクティブ接続の確認に。","caution":"管理コンソールはSQLを受け付けず、PgBouncerのコマンドのみを実行する。cl_waitingが高いままの場合、まずサーバー側で長時間のトランザクションやロックを確認する。default_pool_sizeを闇雲に引き上げると、PostgreSQLはmax_connectionsの上限とメモリ圧迫に近づく。SHOW STATSの値は累積値で、平均はstats_periodの間隔に基づく。","untested":true,"tags":["pgbouncer","show pools","connection pooling","statistics","connection pool"]},{"id":"pgbouncer-pause-resume-reload","task":"メンテナンス中にPgBouncerで接続を保持(PAUSE/RESUME)し、構成をリロード(RELOAD)","category":"PgBouncer","command":"psql -h 127.0.0.1 -p 6432 -U pgbouncer -d pgbouncer -X\nRELOAD;            -- apply pgbouncer.ini and auth_file changes without dropping connections\nPAUSE <db>;        -- closes server connections once running queries/transactions finish; new requests are queued\n-- ... maintenance: switchover, PostgreSQL restart, etc. ...\nRESUME <db>;\n-- If the host in [databases] was changed (after RELOAD), gradually refresh server connections:\nRECONNECT <db>;","what":"PAUSEはクライアント接続を切断せずにPostgreSQL側の接続をドレインし、新しいクエリをキューに入れる。RESUMEでキューが再び流れる。これにより、短時間のプライマリ再起動やスイッチオーバーは、アプリケーションにはエラーではなく短い遅延として見える。","when":"短時間のメンテナンスウィンドウ(スイッチオーバー、マイナーバージョンの再起動、パラメータ変更による再起動)中、およびpgbouncer.ini/userlistの変更適用時に。","caution":"PAUSEはすべてのアクティブなトランザクションが終了した後にのみ戻る。長時間実行のクエリはPAUSEを保留させる(必要に応じてPostgreSQLでそのセッションを終了する)。待機中のクライアントはquery_wait_timeout(デフォルト120 s)が経過するとエラーになるため、その時間内にメンテナンスを終える。PAUSE後にRESUMEを忘れると完全な停止になる。一部の設定(listen_addr、listen_portなど)はRELOADでは変更されず、再起動が必要。","untested":true,"tags":["pgbouncer","pause","resume","reload","maintenance"]},{"id":"pgbouncer-pool-mode","task":"PgBouncerのpool_modeの選択と基本的なサイジング","category":"PgBouncer","command":"; /etc/pgbouncer/pgbouncer.ini\n[databases]\nappdb = host=<primary_host> port=5432 dbname=appdb pool_mode=transaction\nreportdb = host=<primary_host> port=5432 dbname=appdb pool_mode=session\n\n[pgbouncer]\nlisten_addr = 0.0.0.0\nlisten_port = 6432\nauth_type = scram-sha-256\nauth_file = /etc/pgbouncer/userlist.txt\npool_mode = transaction\nmax_client_conn = 5000\ndefault_pool_size = 20\nreserve_pool_size = 5\nmax_prepared_statements = 200\nquery_wait_timeout = 120","what":"sessionモードはクライアントを接続の存続期間中1つのサーバー接続に結び付ける。transactionモードはトランザクションの間だけサーバー接続を割り当て、数十のPostgreSQL接続で数千のクライアントに対応する。statementモードはクエリごとに接続を返却し、複数文のトランザクションを許可しない。pool_modeはデータベースごとに上書きすることもできる。","when":"多数の短命な接続を開くOLTP/マイクロサービスアプリケーションにはtransactionモード。セッション状態に依存する処理(レポート、マイグレーション、LISTENを使用するサービス)にはsessionモード。","caution":"transactionモードでは、トランザクション間でセッション状態が保持されない: SET(SET LOCALを除く)、セッションレベルのアドバイザリロック、LISTEN、WITH HOLDカーソル、トランザクションをまたぐ一時表、SQLレベルのPREPAREは信頼できない。プロトコルレベルのプリペアドステートメントは、PgBouncer 1.21以降かつmax_prepared_statements > 0(1.24以降デフォルト200、それ以前は0)の場合のみサポートされる。default_pool_sizeに(データベース、ユーザー)ペア数を掛けた値が、PostgreSQLのmax_connections(superuser_reserved_connectionsのマージンを除く)を超えてはならない。","untested":true,"tags":["pgbouncer","pool_mode","transaction mode","connection pooling","sizing"]}]},"recipes/postgres-ops.json":{"engineId":"postgres","engine":"PostgreSQL","order":2,"recipes":[{"id":"pgss-top-queries","task":"最もコストの高いクエリを特定(pg_stat_statements: 合計時間と平均時間)","category":"パフォーマンス","command":"-- By total time: queries consuming the most server time\nSELECT queryid,\n       calls,\n       round(total_exec_time::numeric, 1) AS total_ms,\n       round(mean_exec_time::numeric, 2) AS mean_ms,\n       round(stddev_exec_time::numeric, 2) AS stddev_ms,\n       round((100 * total_exec_time / sum(total_exec_time) OVER ())::numeric, 1) AS pct_total,\n       rows / NULLIF(calls, 0) AS rows_per_call,\n       left(regexp_replace(query, '\\s+', ' ', 'g'), 120) AS query\nFROM pg_stat_statements\nWHERE dbid = (SELECT oid FROM pg_database WHERE datname = current_database())\nORDER BY total_exec_time DESC\nLIMIT 20;\n\n-- By mean time per call: individually slow queries\nSELECT queryid,\n       calls,\n       round(mean_exec_time::numeric, 2) AS mean_ms,\n       round(max_exec_time::numeric, 2) AS max_ms,\n       round(mean_plan_time::numeric, 2) AS mean_plan_ms,\n       left(regexp_replace(query, '\\s+', ' ', 'g'), 120) AS query\nFROM pg_stat_statements\nWHERE calls >= 50\nORDER BY mean_exec_time DESC\nLIMIT 20;","what":"現在のデータベースで最も多くのサーバー時間を消費している正規化されたクエリを、合計に対する割合とともに一覧表示する。2つ目のクエリは呼出しあたりで最も遅いものを一覧表示する。","when":"CPU/IO負荷が上昇したとき、またはユーザーが「データベースが遅い」と報告したときの最初の確認先として。チューニングをどこから始めるかの判断に。","caution":"pg_stat_statementsは、shared_preload_librariesに追加してサーバーを再起動し、データベースでCREATE EXTENSIONを実行するまで何も収集しない。値は最後のリセット以降の累積値。mean_msに比べてstddev_msが高い場合、呼出しごとに計画またはデータ分布が変動していることを示す。mean_plan_timeはpg_stat_statements.track_planning = on(デフォルトoff、有効化するとオーバーヘッドが加わる)の場合のみ設定される。他のユーザーのクエリテキストを見るには、スーパーユーザーまたはpg_read_all_statsロールが必要。","since":"PostgreSQL 13","note":"PostgreSQL 13でtotal_time/mean_time列はtotal_exec_time/mean_exec_timeに名前が変更され、計画時間(total_plan_time)は別の列になった。PG12以前では旧名を使用する。","tags":["pg_stat_statements","slow query","most expensive query","top sql","performance","query tuning"]},{"id":"pgss-io-temp-heavy","task":"ディスクI/O、一時ファイル、WALを引き起こしているクエリを特定(pg_stat_statements)","category":"パフォーマンス","command":"SELECT queryid,\n       calls,\n       shared_blks_hit,\n       shared_blks_read,\n       round(100.0 * shared_blks_hit / NULLIF(shared_blks_hit + shared_blks_read, 0), 1) AS hit_pct,\n       pg_size_pretty(temp_blks_written * current_setting('block_size')::bigint) AS temp_written,\n       pg_size_pretty(wal_bytes) AS wal,\n       left(regexp_replace(query, '\\s+', ' ', 'g'), 120) AS query\nFROM pg_stat_statements\nORDER BY shared_blks_read + temp_blks_read + temp_blks_written DESC\nLIMIT 20;","what":"共有バッファ外から最も多くのブロックを読み取るクエリ、一時ファイルに最も多く書き込むクエリ(work_memに収まらないソート/ハッシュ)、最も多くのWALを生成するクエリを、キャッシュヒット率とともに表示する。","when":"ディスク読み取りレイテンシが上昇したとき、一時ファイルのアラート(log_temp_files)が発生したとき、WAL量が急増したときに原因となるクエリを特定するため。","caution":"shared_blks_readはOSのページキャッシュから提供された読み取りも数える。実際のディスク時間にはtrack_io_timing = onが必要(先にpg_test_timingでオーバーヘッドを測定する)。temp_writtenが高い場合、通常の対策はロール/セッション単位でのwork_memの引上げ、またはクエリ/インデックスの修正。work_memをグローバルに引き上げるとメモリのリスクが増す。","since":"PostgreSQL 13","note":"wal_bytes/wal_records列はPG13で導入された。PG17ではblk_read_time/blk_write_timeがshared_blk_read_time/shared_blk_write_timeに名前が変更され、local_blk_*_timeが追加された。","tags":["pg_stat_statements","io","temp files","temp_blks_written","work_mem","wal"]},{"id":"pgss-reset","task":"pg_stat_statementsの統計をリセット(全体または単一のクエリ)","category":"パフォーマンス","command":"-- Last reset time and number of entries evicted because the table was full (dealloc)\nSELECT dealloc, stats_reset FROM pg_stat_statements_info;\n\n-- Reset a single query only (userid, dbid, queryid; 0 = all)\nSELECT pg_stat_statements_reset(0, 0, 5927525816675996975);\n\n-- Reset all statistics\nSELECT pg_stat_statements_reset();","what":"pg_stat_statementsのカウンタを全体、またはユーザー/データベース/queryid単位でリセットする。pg_stat_statements_infoは最後のリセット時刻と、領域不足で追い出されたエントリ数を表示する。","when":"チューニング変更(インデックス、パラメータ、デプロイ)の前にクリーンな測定を開始するため、または単一のクエリの新しい計画を個別に測定するため。","caution":"リセットは元に戻せない。累積カウンタに依存する監視/APMツールにはギャップが表示されるため、先にスナップショットを取得する(計画劣化のレシピを参照)。deallocが増え続ける場合、pg_stat_statements.maxが小さすぎる(変更には再起動が必要)。デフォルトではスーパーユーザーのみが実行できる。GRANT EXECUTE ON FUNCTIONで権限を付与する。","since":"PostgreSQL 14","note":"パラメータ指定のリセット(userid、dbid、queryid)はPG12、pg_stat_statements_infoビューはPG14で導入された。PG17では4番目のパラメータminmax_onlyが追加された: pg_stat_statements_reset(0, 0, 0, true)はmin/max時間のみをリセットする。stats_sinceとminmax_stats_since列もPG17。","tags":["pg_stat_statements","reset","clear statistics","queryid","statistics","baseline"]},{"id":"auto-explain-setup","task":"auto_explainで遅いクエリの実行計画をログ出力","category":"パフォーマンス","command":"-- 1) Per session: effective immediately, no restart (superuser)\nLOAD 'auto_explain';\nSET auto_explain.log_min_duration = '500ms';\nSET auto_explain.log_analyze = on;\nSET auto_explain.log_buffers = on;\nSET auto_explain.log_timing = off;\nSET auto_explain.log_nested_statements = on;\n\n-- 2) Persistent: loaded by new sessions, a reload is enough.\n--    The module must be LOADed in this session before ALTER SYSTEM accepts auto_explain.* parameters.\nLOAD 'auto_explain';\nALTER SYSTEM SET session_preload_libraries = 'auto_explain';\nALTER SYSTEM SET auto_explain.log_min_duration = '2s';\nALTER SYSTEM SET auto_explain.log_analyze = on;\nALTER SYSTEM SET auto_explain.log_buffers = on;\nALTER SYSTEM SET auto_explain.log_timing = off;\nALTER SYSTEM SET auto_explain.sample_rate = 0.1;\nSELECT pg_reload_conf();","what":"しきい値を超えたクエリの実行計画をサーバーログに書き込む(log_analyzeがonの場合は実際の行数とバッファデータ付き)。アプリケーションの実際のパラメータで生成された計画を取得できる。","when":"クエリがアプリケーションから、または特定のパラメータでのみ遅く、手動のEXPLAINで再現できないときに。断続的な計画変更の検出に。","caution":"log_analyze = onは、しきい値未満のものを含め、サンプリングされたすべてのクエリに計測のオーバーヘッドを加える。log_timing = offとsample_rate < 1でこれを減らせる。log_min_duration = 0は本番でログをあふれさせる。ALTER SYSTEM SET session_preload_librariesは既存の値を上書きするため、先にSHOW session_preload_librariesを確認する。session_preload_librariesは既存のセッションには影響しない。すべてのプロセスでロードするにはshared_preload_librariesと再起動が必要。","note":"auto_explainはcontribモジュールであり、CREATE EXTENSIONは不要。log_wal(PG13以降)とlog_settings(PG12以降)のオプションも使用できる。","tags":["auto_explain","execution plan","slow query","log","plan capture","explain"]},{"id":"explain-analyze-buffers-wal","task":"EXPLAIN (ANALYZE, BUFFERS, SETTINGS, WAL)で計画を詳細に読む","category":"パフォーマンス","command":"-- ANALYZE really executes the statement: run DML inside a transaction and roll it back\nBEGIN;\nEXPLAIN (ANALYZE, BUFFERS, SETTINGS, WAL, VERBOSE)\nUPDATE customer SET balance = balance + 1 WHERE city = 'Ankara';\nROLLBACK;\n\n-- For SELECT\nEXPLAIN (ANALYZE, BUFFERS, SETTINGS)\nSELECT name FROM customer ORDER BY name DESC LIMIT 10 OFFSET 1000;","what":"実際の実行統計付きで計画を返す: BUFFERSはノードごとの共有ブロックのhit/read/dirtiedと一時ブロックを、SETTINGSは計画に影響するデフォルト以外のパラメータを、WALは生成されたWALレコード/バイト数を表示する。","when":"推定行数と実際の行数の乖離、ディスクにあふれるソート/ハッシュ(Sort Method: external merge、temp read/written)、DMLのWALコストの分析に。","caution":"ANALYZEは文を実際に実行するため、DMLは必ずBEGIN/ROLLBACK内で実行する(トリガーとシーケンスの増分は発生する)。読み方のヒント: 推定'rows'と'actual rows'の間に10倍以上の差がある場合は統計の問題を示す。ループ内のノードでは時間と行数はループあたりの値であり、合計にはloopsを掛ける。Index Only Scanで'Heap Fetches'が多い場合は可視性マップが古く、'Workers Planned' > 'Workers Launched'の場合はワーカープールが枯渇している。計時のオーバーヘッドが大きい場合はTIMING OFFを使用する。COSTS OFFはJITセクションも非表示にする。","since":"PostgreSQL 13","note":"SETTINGSオプションはPG12、WALはPG13で導入された。PG16でGENERIC_PLAN、PG17でSERIALIZEとMEMORYが追加された。PG18ではANALYZE指定時にBUFFERSがデフォルトでonになる。","tags":["explain analyze","buffers","execution plan","reading plans","wal","performance"]},{"id":"plan-regression-queryid","task":"queryidで計画劣化を検出(pg_stat_statementsのスナップショット比較)","category":"パフォーマンス","command":"-- 1) Take a reference snapshot (before deploy/upgrade/ANALYZE)\nCREATE TABLE IF NOT EXISTS pgss_snapshot AS\n  SELECT now() AS snap_time, userid, dbid, queryid, calls, total_exec_time,\n         shared_blks_hit, shared_blks_read, left(query, 200) AS query\n  FROM pg_stat_statements WITH NO DATA;\nINSERT INTO pgss_snapshot\n  SELECT now(), userid, dbid, queryid, calls, total_exec_time,\n         shared_blks_hit, shared_blks_read, left(query, 200)\n  FROM pg_stat_statements;\n\n-- 2) Later: queries whose time per call grew the most since the snapshot\nWITH base AS (\n  SELECT DISTINCT ON (userid, dbid, queryid) *\n  FROM pgss_snapshot\n  ORDER BY userid, dbid, queryid, snap_time DESC\n)\nSELECT s.queryid,\n       s.calls - b.calls AS new_calls,\n       round((b.total_exec_time / b.calls)::numeric, 2) AS old_mean_ms,\n       round(((s.total_exec_time - b.total_exec_time) / (s.calls - b.calls))::numeric, 2) AS new_mean_ms,\n       round((b.shared_blks_hit + b.shared_blks_read)::numeric / b.calls, 0) AS old_blks_per_call,\n       round((s.shared_blks_hit + s.shared_blks_read - b.shared_blks_hit - b.shared_blks_read)::numeric\n             / (s.calls - b.calls), 0) AS new_blks_per_call,\n       left(regexp_replace(s.query, '\\s+', ' ', 'g'), 100) AS query\nFROM pg_stat_statements s\nJOIN base b USING (userid, dbid, queryid)\nWHERE s.calls - b.calls >= 10\n  AND b.calls > 0\nORDER BY ((s.total_exec_time - b.total_exec_time) / (s.calls - b.calls))\n         / NULLIF(b.total_exec_time / b.calls, 0) DESC NULLS LAST\nLIMIT 20;\n\n-- 3) Is the suspicious queryid running right now?\nSELECT pid, state, now() - query_start AS runtime, left(query, 100) AS query\nFROM pg_stat_activity\nWHERE query_id = -4094682686355101727;","what":"pg_stat_statementsの累積カウンタを表に保存し、後の状態とqueryidごとに比較する。スナップショット後の呼出しについて、呼出しあたりの平均時間とバッファを旧値と並べて表示する。","when":"デプロイ、メジャーアップグレード、統計の更新、パラメータ変更の後に計画が変わったクエリを特定するため(「昨日は速かったが今日は遅い」)。","caution":"スナップショットと比較の間にpg_stat_statements_reset()が実行された場合、またはエントリが領域不足で追い出された場合(dealloc)、差分は無意味になる。pg_stat_statements_info.stats_resetを確認する。呼出しあたりのバッファの増加は、キャッシュに依存しないため、時間の増加よりも計画変更の信頼できる兆候である。計画を確認するには、実際のパラメータでクエリをEXPLAINするかauto_explainを使用する。PostgreSQLには組込みの計画固定機能はない(pg_hint_plan拡張が必要)。終了後はスナップショット表を削除する。","since":"PostgreSQL 14","note":"pg_stat_activity.query_idとcompute_query_idパラメータはPG14で導入された(デフォルトauto: pg_stat_statementsがロードされている場合に計算される)。EXPLAIN VERBOSEの出力の'Query Identifier'行は同じ値を示す。手順1と2はPG13でも動作する。","tags":["plan regression","queryid","pg_stat_statements","snapshot","plan change","performance"]},{"id":"parallel-query-usage","task":"パラレルクエリの容量と現在のワーカー使用状況を確認","category":"パフォーマンス","command":"-- Parallel worker pool settings\nSELECT name, current_setting(name) AS value\nFROM pg_settings\nWHERE name IN ('max_worker_processes', 'max_parallel_workers', 'max_parallel_workers_per_gather',\n               'max_parallel_maintenance_workers', 'parallel_setup_cost', 'parallel_tuple_cost',\n               'min_parallel_table_scan_size', 'min_parallel_index_scan_size')\nORDER BY name;\n\n-- Queries currently running in parallel and their worker counts\nSELECT a.pid AS leader_pid,\n       count(w.pid) AS workers_running,\n       current_setting('max_parallel_workers')::int AS max_parallel_workers,\n       now() - a.query_start AS runtime,\n       left(a.query, 80) AS query\nFROM pg_stat_activity a\nJOIN pg_stat_activity w ON w.leader_pid = a.pid AND w.pid <> a.pid\nGROUP BY a.pid, a.query_start, a.query\nORDER BY workers_running DESC;\n\n-- Pin / reset the planned worker count for a single table\nALTER TABLE orders SET (parallel_workers = 4);\nALTER TABLE orders RESET (parallel_workers);","what":"パラレルクエリの上限と、各リーダープロセスが現在使用しているパラレルワーカー数を表示する。表ごとのワーカー数の設定例を示す。","when":"分析クエリが想定より遅いとき、計画が'Workers Planned' > 'Workers Launched'を示すとき、CPUコアが遊んでいるときに。","caution":"max_parallel_workersはmax_worker_processes(再起動が必要)で上限が決まり、そのプールは論理レプリケーションワーカーや他のバックグラウンドワーカーと共有される。OLTPでは、max_parallel_workers_per_gatherが高いと同時実行時にCPUが飽和する。各ワーカーは独自のwork_memも使用する。データを書き込むクエリや行をロックするクエリ(CREATE TABLE AS / SELECT INTOを除く)、カーソル、PARALLEL UNSAFE関数を呼び出すクエリにはパラレル計画は作成されない。ALTER TABLE ... SET (parallel_workers)は短時間のShareUpdateExclusiveLockを取得する。","since":"PostgreSQL 13","note":"pg_stat_activity.leader_pidはPG13で導入された。それ以前は、パラレルワーカーはbackend_type = 'parallel worker'として表示されるのみで、リーダーと関連付けられない。","tags":["parallel query","parallel worker","leader_pid","max_parallel_workers","gather","cpu"]},{"id":"jit-impact-check","task":"JITコンパイルがクエリ時間に与える影響を測定","category":"パフォーマンス","command":"-- Share of JIT time in total execution time (PG15+)\nSELECT queryid,\n       calls,\n       jit_functions,\n       round((jit_generation_time + jit_inlining_time + jit_optimization_time + jit_emission_time)::numeric, 1) AS jit_ms,\n       round(total_exec_time::numeric, 1) AS total_ms,\n       round((100 * (jit_generation_time + jit_inlining_time + jit_optimization_time + jit_emission_time)\n             / NULLIF(total_exec_time, 0))::numeric, 1) AS jit_pct,\n       left(regexp_replace(query, '\\s+', ' ', 'g'), 100) AS query\nFROM pg_stat_statements\nWHERE jit_functions > 0\nORDER BY jit_pct DESC NULLS LAST\nLIMIT 20;\n\n-- Compare on a single query: check the \"JIT:\" section at the end of the output and Execution Time\nSET jit = on;\nEXPLAIN (ANALYZE) SELECT city, sum(balance) FROM customer GROUP BY city;\nSET jit = off;\nEXPLAIN (ANALYZE) SELECT city, sum(balance) FROM customer GROUP BY city;\nRESET jit;","what":"クエリごとに、実行時間に占めるJITコンパイル時間(generation、inlining、optimization、emission)の割合を表示する。同じクエリをJITのon/offで実行して正味の効果を測定する。","when":"短いOLTPやレポートのクエリで、数十から数百msの説明のつかない遅延が見られるときに。特に、コスト推定の過大化がJITを誘発する多数のパーティションを持つ表で。","caution":"JITは計画コストがjit_above_cost(デフォルト100000)を超えた場合にのみ作動する。コスト推定が過大な場合、短いクエリではコンパイルが実行より長くかかることがある。グローバルに無効化する前に、該当するロール/データベースに対するALTER ROLE ... SET jit = off、またはjit_above_costの引上げを検討する。EXPLAIN (ANALYZE, COSTS OFF)はJITセクションを出力しない。PostgreSQLがLLVMサポートなしでビルドされている場合、JITは使用されない。SELECT pg_jit_available();で確認する。","since":"PostgreSQL 15","note":"jit_*列はPG15でpg_stat_statementsに追加された。PG17ではjit_deform_count/jit_deform_timeが追加された。JITはPG11で導入され、PG12からデフォルトでonになっている。","tags":["jit","llvm","jit_above_cost","pg_stat_statements","compilation time","performance"]},{"id":"blocking-tree","task":"ブロッキングツリーを構築(根本のブロッカーを特定)","category":"セッション","command":"WITH RECURSIVE tree AS (\n  SELECT a.pid, a.pid AS root_pid, 0 AS level, ARRAY[a.pid] AS path\n  FROM pg_stat_activity a\n  WHERE cardinality(pg_blocking_pids(a.pid)) = 0\n    AND EXISTS (SELECT 1 FROM pg_stat_activity w WHERE a.pid = ANY (pg_blocking_pids(w.pid)))\n  UNION ALL\n  SELECT w.pid, t.root_pid, t.level + 1, t.path || w.pid\n  FROM tree t\n  JOIN pg_stat_activity w ON t.pid = ANY (pg_blocking_pids(w.pid))\n  WHERE w.pid <> ALL (t.path)\n), node AS (\n  SELECT DISTINCT ON (pid) pid, root_pid, level\n  FROM tree\n  ORDER BY pid, level DESC\n)\nSELECT repeat('  ', n.level) || n.pid AS pid_tree,\n       n.root_pid,\n       pg_blocking_pids(n.pid) AS blocked_by,\n       a.usename,\n       a.state,\n       a.wait_event_type || ':' || a.wait_event AS wait,\n       now() - a.xact_start AS xact_age,\n       left(regexp_replace(a.query, '\\s+', ' ', 'g'), 80) AS query\nFROM node n\nJOIN pg_stat_activity a USING (pid)\nORDER BY n.root_pid, n.level, n.pid;","what":"pg_blocking_pids()で待機チェーンを再帰的にたどり、根本のブロッカー(誰も待っていないセッション)から始めて、待機中のすべてのセッションを、直接ブロックしているPIDとトランザクション経過時間とともにインデントされたツリーとして表示する。","when":"アプリケーションで大量のタイムアウトやキューの滞留が発生したときに。数十の待機セッションの中から介入が必要な単一の根本セッションを特定するため。","caution":"根本は多くの場合、ロックを保持したまま忘れられた'idle in transaction'セッションである。query列はそのセッションの最後の文を示し、ロックを取得した文ではない。ACCESS EXCLUSIVEを待つDDLは、その後ろに並んだ単純なSELECTもブロックし、中間ノードとして表示される。pg_blocking_pids()はロックマネージャを短時間ロックするため、このクエリを短い間隔のループで実行しない。複数の分岐から到達できるセッションは、最も深いレベルで1回表示される。","since":"PostgreSQL 9.6","tags":["blocking","lock tree","lock chain","pg_blocking_pids","blocking session","lock"]},{"id":"lock-wait-detail","task":"オブジェクトとロックモード別にロック待機を詳細に調査(pg_locks)","category":"セッション","command":"SELECT DISTINCT\n       w.pid AS waiting_pid,\n       w.locktype,\n       coalesce(w.relation::regclass::text, 'xid ' || w.transactionid, w.virtualxid, w.objid::text) AS target,\n       w.mode AS wanted_mode,\n       b.pid AS blocker_pid,\n       b.mode AS blocker_mode,\n       b.granted AS blocker_holds,\n       now() - wa.state_change AS waiting_for,\n       left(wa.query, 60) AS waiting_query,\n       left(ba.query, 60) AS blocker_query\nFROM pg_locks w\nJOIN pg_locks b\n  ON b.pid = ANY (pg_blocking_pids(w.pid))\n AND b.locktype = w.locktype\n AND b.database IS NOT DISTINCT FROM w.database\n AND b.relation IS NOT DISTINCT FROM w.relation\n AND b.page IS NOT DISTINCT FROM w.page\n AND b.tuple IS NOT DISTINCT FROM w.tuple\n AND b.virtualxid IS NOT DISTINCT FROM w.virtualxid\n AND b.transactionid IS NOT DISTINCT FROM w.transactionid\n AND b.classid IS NOT DISTINCT FROM w.classid\n AND b.objid IS NOT DISTINCT FROM w.objid\n AND b.objsubid IS NOT DISTINCT FROM w.objsubid\nJOIN pg_stat_activity wa ON wa.pid = w.pid\nJOIN pg_stat_activity ba ON ba.pid = b.pid\nWHERE NOT w.granted\nORDER BY waiting_for DESC, waiting_pid;","what":"許可されていないすべてのロック要求(granted = false)について、対象オブジェクト(表、トランザクションIDなど)、要求モード、ブロックしているPIDとそのモード、ブロッカーが実際にロックを保持しているか、おおよその待機時間を表示する。","when":"どの表とロックモードの競合がブロッキングの原因かを把握するため。例: AccessExclusiveLockを待つDDL、transactionid待機として現れる行ロック。","caution":"照合にpg_blocking_pids()を使用するため、実際に競合する要求のみが一覧表示される。blocker_holds = falseは、ブロッカーがまだロックを保持していないが、競合するモードで先にキューに並んでいることを意味する(ロックキュー)。locktype = 'transactionid'は行レベルの競合: 待機側は行を変更したトランザクションが終了するまで待機する。行そのものはpg_locksには表示されない。大規模システムではpg_locksに数千行が含まれる場合があるため、頻繁に実行しない。waiting_forはstate_changeに基づく近似値。","since":"PostgreSQL 9.6","tags":["pg_locks","lock wait","lock waiting","accessexclusivelock","transactionid","lock"]},{"id":"long-idle-transactions","task":"長時間実行のトランザクションと'idle in transaction'のトランザクションを特定","category":"セッション","command":"SELECT pid,\n       usename,\n       datname,\n       application_name,\n       client_addr,\n       state,\n       now() - xact_start AS xact_age,\n       now() - state_change AS in_state_for,\n       backend_xid,\n       age(backend_xmin) AS xmin_age,\n       left(regexp_replace(query, '\\s+', ' ', 'g'), 100) AS last_query\nFROM pg_stat_activity\nWHERE xact_start IS NOT NULL\n  AND backend_type = 'client backend'\n  AND pid <> pg_backend_pid()\n  AND (now() - xact_start > interval '5 minutes' OR state LIKE 'idle in transaction%')\nORDER BY xact_start;","what":"オープン中のトランザクションが5分より古いセッション、またはトランザクション内でidleのままのセッションを、トランザクション経過時間、現在の状態での経過時間、割り当てられたXID、保持しているxminの経過時間とともに表示する。","when":"肥大化が進むとき、VACUUMが'dead row versions cannot be removed yet'を報告するとき、ロック待機時、接続プールのリークが疑われるときに。","caution":"長いトランザクション(特にREPEATABLE READ/SERIALIZABLE、またはオープンカーソルを保持するもの)はbackend_xminを通じてVACUUMのクリーンアップホライズン(xmin horizon)を引き止め、データベース全体で肥大化とXIDの経年を引き起こす。'idle in transaction (aborted)'はエラーが発生してROLLBACKを待っているセッション。恒久的な対策: ロールごとのidle_in_transaction_session_timeoutと、アプリケーションでの正しいトランザクション境界。","tags":["long transaction","idle in transaction","xmin","bloat","session","long running"]},{"id":"terminate-idle-in-transaction","task":"長時間の'idle in transaction'セッションを制御された方法で一括終了","category":"セッション","command":"-- 1) Dry run first: who will be affected?\nSELECT pid, usename, application_name, client_addr,\n       now() - state_change AS idle_for, left(query, 80) AS last_query\nFROM pg_stat_activity\nWHERE state IN ('idle in transaction', 'idle in transaction (aborted)')\n  AND now() - state_change > interval '15 minutes'\n  AND backend_type = 'client backend'\n  AND pid <> pg_backend_pid();\n\n-- 2) Terminate; wait up to 5 s for each process to exit\nSELECT pid, usename, now() - state_change AS idle_for,\n       pg_terminate_backend(pid, 5000) AS terminated\nFROM pg_stat_activity\nWHERE state IN ('idle in transaction', 'idle in transaction (aborted)')\n  AND now() - state_change > interval '15 minutes'\n  AND backend_type = 'client backend'\n  AND pid <> pg_backend_pid();","what":"まず一定時間トランザクションを開いたままidleになっているセッションを一覧表示し、その後終了する。timeoutパラメータはプロセスが実際に終了するまで(またはタイムアウトが経過するまで)待機する。","when":"ロックを保持したまま忘れられたセッションがブロッキングを引き起こす、またはxmin horizonを引き止めてVACUUMを停滞させるときの緊急介入に。","caution":"pg_cancel_backendは'idle in transaction'セッションには何もしない(取り消す実行中のクエリがない)。pg_terminate_backendが必要で、未コミットの変更はすべてロールバックされる。usename/application_nameでフィルタを絞り込み、レプリケーション、バックアップ、監視のセッションを除外する。接続プールは終了された接続を再度開く。タイムアウトが経過すると、関数は警告を出してfalseを返す。恒久的な対策として、ロールごとにidle_in_transaction_session_timeoutを設定する。","since":"PostgreSQL 14","note":"2引数のpg_terminate_backend(pid, timeout)はPG14で導入された。それ以前はpg_terminate_backend(pid)のみが存在し、シグナル送信直後に戻る。","tags":["pg_terminate_backend","idle in transaction","terminate session","kill session","bulk","lock"]},{"id":"role-timeouts","task":"ロールとデータベースごとにstatement_timeout / lock_timeoutを設定","category":"セッション","command":"-- Application role: short queries, short lock waits, a limit on forgotten transactions\nALTER ROLE web_app SET statement_timeout = '30s';\nALTER ROLE web_app SET lock_timeout = '5s';\nALTER ROLE web_app SET idle_in_transaction_session_timeout = '10min';\n\n-- Let the reporting role run longer, only in this database\nALTER ROLE report_app IN DATABASE mydb SET statement_timeout = '15min';\n\n-- Show configured role/database settings\nSELECT coalesce(r.rolname, '(all)') AS role,\n       coalesce(d.datname, '(all)') AS database,\n       s.setconfig\nFROM pg_db_role_setting s\nLEFT JOIN pg_roles r ON r.oid = s.setrole\nLEFT JOIN pg_database d ON d.oid = s.setdatabase\nORDER BY 1, 2;\n\n-- Revert\nALTER ROLE web_app RESET lock_timeout;","what":"タイムアウトパラメータをロール(および任意でデータベース)レベルで永続化し、グローバル設定に触れずに各ワークロードが独自の上限で実行されるようにする。","when":"暴走したクエリによるリソースの枯渇、DDL/ロックキューによるアプリケーションの停止、忘れられたトランザクションによる肥大化を防ぐため。","caution":"設定は新しいセッションにのみ適用されるため、既存のプール接続を再接続させる。ユーザーはセッション内でSETにより値を上書きできるため、これはセキュリティ境界ではない。statement_timeoutをpostgresql.confでグローバルに設定しない: pg_dump、VACUUM、CREATE INDEXなどのメンテナンスジョブも取り消される。優先順位: ロール+データベース > ロール > データベース > postgresql.conf。","note":"idle_in_transaction_session_timeoutはPG9.6、idle_session_timeoutはPG14、transaction_timeoutはPG17で導入された。","tags":["statement_timeout","lock_timeout","idle_in_transaction_session_timeout","alter role","query timeout","timeout"]},{"id":"ddl-lock-timeout-retry","task":"lock_timeoutとリトライでDDLを安全に適用(ロックキューの回避)","category":"セッション","command":"-- Single attempt: give up if the lock is not acquired within 3 s instead of queueing and blocking traffic\nSET lock_timeout = '3s';\nALTER TABLE customer ADD COLUMN IF NOT EXISTS segment text;\nRESET lock_timeout;\n\n-- Automatic retry: up to 5 attempts, 3 s apart\nDO $$\nDECLARE\n  attempt int := 0;\nBEGIN\n  LOOP\n    attempt := attempt + 1;\n    BEGIN\n      SET LOCAL lock_timeout = '2s';\n      ALTER TABLE customer ADD COLUMN IF NOT EXISTS segment text;\n      RAISE NOTICE 'OK, attempt %', attempt;\n      EXIT;\n    EXCEPTION WHEN lock_not_available THEN\n      RAISE NOTICE 'lock not acquired, attempt %', attempt;\n      IF attempt >= 5 THEN RAISE; END IF;\n      PERFORM pg_sleep(3);\n    END;\n  END LOOP;\nEND $$;","what":"ACCESS EXCLUSIVEを必要とするDDLが、ロックを取得できない場合に無期限に待機し、その後ろに並ぶすべてのクエリをブロックする(ロックキュー)ことを防ぐ。短い間隔でリトライする。","when":"本番の高負荷の表に、ALTER TABLE、CREATE/DROP TRIGGER、ATTACH PARTITION、RENAMEなど、短時間だが強いロックを伴う変更を適用するときに。","caution":"lock_timeoutがない場合、1つの長いSELECTの後ろに並んだALTER TABLEは、後続のすべての読み取り/書き込みも待機させ、数分で接続プールを枯渇させる可能性がある。lock_timeoutはロック待機のみを制限し、表を書き直すDDL(例: 列の型の変更)の実行時間は制限しない。DOブロックは単一のトランザクションであり、試行をまたいでスナップショットを保持する。長いリトライシナリオでは外部のシェルループを推奨する。","tags":["lock_timeout","ddl","alter table","lock queue","retry","lock"]},{"id":"connection-usage","task":"max_connectionsに対する接続使用量を測定","category":"セッション","command":"-- Capacity: used slots and slots left for regular users\nSELECT max_conn,\n       reserved,\n       used,\n       max_conn - reserved - used AS free_for_normal_users,\n       round(100.0 * used / max_conn, 1) AS used_pct\nFROM (SELECT current_setting('max_connections')::int AS max_conn,\n             current_setting('superuser_reserved_connections')::int\n             + coalesce(current_setting('reserved_connections', true)::int, 0) AS reserved,\n             (SELECT count(*) FROM pg_stat_activity WHERE backend_type = 'client backend') AS used) x;\n\n-- Breakdown by database, user, application and state\nSELECT datname, usename, application_name, state,\n       count(*) AS sessions,\n       max(now() - state_change) AS longest_in_state\nFROM pg_stat_activity\nWHERE backend_type = 'client backend'\nGROUP BY datname, usename, application_name, state\nORDER BY sessions DESC;\n\n-- Role and database connection limits\nSELECT rolname, rolconnlimit FROM pg_roles WHERE rolconnlimit <> -1;\nSELECT datname, datconnlimit FROM pg_database WHERE datconnlimit <> -1;","what":"max_connectionsに対して使用中の接続スロットと一般ユーザーに残っているスロット、データベース/ユーザー/アプリケーション/状態別の内訳、設定されたCONNECTION LIMITを表示する。","when":"'too many clients already' / 'remaining connection slots are reserved'エラー時、キャパシティ計画時、プーラーの必要性の評価時に。","caution":"max_connectionsはクライアントバックエンドのみを制限する。autovacuumワーカー、バックグラウンドワーカー、walsenderは別のスロットを使用する。最後のsuperuser_reserved_connectionsのスロット(PG16以降はreserved_connectionsも)は一般ユーザーには使用できない。max_connectionsを数百から数千に引き上げる代わりに、PgBouncerなどのプーラーを使用する: 各接続は個別のプロセスであり、メモリとスナップショットのコストは接続数とともに増加する。多数の'idle'セッションはアプリケーションプールが大きすぎることを示す。ALTER ROLE ... CONNECTION LIMITで暴走したアプリケーションがすべてのスロットを消費するのを防ぐ。max_connectionsの変更には再起動が必要。","note":"reserved_connectionsパラメータとpg_use_reserved_connectionsロールはPG16で導入された。クエリは古いバージョンでも動作する(パラメータがない場合は0として扱われる)。","tags":["max_connections","connection count","connection","pooler","superuser_reserved_connections","session"]},{"id":"autovacuum-progress","task":"実行中のautovacuum/VACUUM操作の進捗を監視","category":"メンテナンス","command":"SELECT p.pid,\n       a.backend_type,\n       p.datname,\n       p.relid::regclass AS table_name,\n       p.phase,\n       pg_size_pretty(p.heap_blks_total * current_setting('block_size')::bigint) AS table_size,\n       round(100.0 * p.heap_blks_scanned / NULLIF(p.heap_blks_total, 0), 1) AS scanned_pct,\n       round(100.0 * p.heap_blks_vacuumed / NULLIF(p.heap_blks_total, 0), 1) AS vacuumed_pct,\n       p.index_vacuum_count,\n       now() - a.xact_start AS running_for,\n       a.wait_event_type || ':' || a.wait_event AS wait,\n       left(a.query, 80) AS query\nFROM pg_stat_progress_vacuum p\nJOIN pg_stat_activity a USING (pid)\nORDER BY running_for DESC;\n\n-- Busy autovacuum workers / upper limit\nSELECT count(*) FILTER (WHERE backend_type = 'autovacuum worker') AS av_workers_busy,\n       current_setting('autovacuum_max_workers') AS av_max_workers\nFROM pg_stat_activity;","what":"実行中のすべてのVACUUM(autovacuumワーカーまたは手動)について、表、フェーズ、スキャン/vacuum済みのヒープの割合、インデックスvacuumのパス数、待機イベントを表示する。稼働中のautovacuumワーカー数も表示する。","when":"大きな表のVACUUMがいつ終わるか、すべてのautovacuumワーカーが使用中か(キューで待機している表)、vacuumがスロットリングにより待機しているかを見積もるため。","caution":"index_vacuum_count > 1は、デッドタプルのリストがメモリに収まらず、インデックスが複数回スキャンされたことを意味する。maintenance_work_mem/autovacuum_work_memを引き上げる(PG17より前は、この用途に最大1GBまでしか使用されない)。wait = Timeout:VacuumDelayはコストベースのスロットリング(autovacuum_vacuum_cost_delay/cost_limit)。クエリテキストに'to prevent wraparound'とあるautovacuumは終了させない。直ちに再起動する。VACUUM FULLとCLUSTERはこのビューではなくpg_stat_progress_clusterに表示される。","since":"PostgreSQL 9.6","note":"PG17ではmax_dead_tuples/num_dead_tuples列がmax_dead_tuple_bytes/num_dead_item_idsに変わり、indexes_total/indexes_processedが追加された。そのため、クエリはバージョンに依存しない列を使用している。","tags":["autovacuum","vacuum progress","pg_stat_progress_vacuum","vacuum","maintenance","progress"]},{"id":"xid-wraparound-risk","task":"トランザクションIDの周回リスクを測定(データベースおよび表ごとのXID経過)","category":"メンテナンス","command":"-- Per database: distance to autovacuum_freeze_max_age and the ~2^31 limit\nSELECT datname,\n       age(datfrozenxid) AS xid_age,\n       mxid_age(datminmxid) AS mxid_age,\n       round(100.0 * age(datfrozenxid) / current_setting('autovacuum_freeze_max_age')::int, 1) AS pct_of_freeze_max_age,\n       round(100.0 * age(datfrozenxid) / 2147483647, 1) AS pct_of_wraparound\nFROM pg_database\nORDER BY age(datfrozenxid) DESC;\n\n-- Oldest tables in the current database (including TOAST)\nSELECT c.oid::regclass AS table_name,\n       greatest(age(c.relfrozenxid), age(t.relfrozenxid)) AS xid_age,\n       mxid_age(c.relminmxid) AS mxid_age,\n       pg_size_pretty(pg_total_relation_size(c.oid)) AS total_size,\n       s.last_autovacuum,\n       s.last_vacuum\nFROM pg_class c\nLEFT JOIN pg_class t ON t.oid = c.reltoastrelid\nLEFT JOIN pg_stat_all_tables s ON s.relid = c.oid\nWHERE c.relkind IN ('r', 'm')\nORDER BY 2 DESC\nLIMIT 20;","what":"各データベースの最も古い未凍結XIDとmultixactの経過を、autovacuum_freeze_max_ageと周回上限に対する割合で表示する。現在のデータベースでは、最も古い表(TOASTを含む)をサイズと最終vacuum時刻とともに表示する。","when":"定期監視(一般的なしきい値: pct_of_wraparound 50%で警告 / 75%で重大)、ログに'must be vacuumed within N transactions'が表示されたとき、凍結作業の優先順位付けに。","caution":"pct_of_freeze_max_ageが100を超える表では、autovacuumが強制(周回防止)vacuumを開始する。I/O負荷が高く、終了させても再起動する。経過が減らない場合、原因はほぼ常にxmin horizonを引き止めているもの(長いトランザクション、プリペアドトランザクション、レプリケーションスロット、hot_standby_feedback)である。先にそれを解消しないと、VACUUM FREEZEでも経過を下げられない。上限に近づくとサーバーはまず警告し、残りが数百万になると新しいXIDの割り当て(書き込み)を拒否する。対象を絞った凍結: VACUUM (FREEZE, VERBOSE) <table>;","note":"PG14ではvacuum_failsafe_age / vacuum_multixact_failsafe_age(デフォルト16億)が追加された: 表がその経過に達すると、VACUUMはコスト遅延とインデックスクリーンアップをスキップする緊急モードに切り替わる。","tags":["wraparound","xid age","datfrozenxid","relfrozenxid","freeze","multixact"]},{"id":"xmin-horizon-holders","task":"VACUUMによるデッドタプル削除を妨げているxmin horizonの保持者を特定","category":"メンテナンス","command":"SELECT 'session' AS source, pid::text AS id, usename::text AS owner, state AS detail,\n       age(backend_xmin) AS xmin_age\nFROM pg_stat_activity\nWHERE backend_xmin IS NOT NULL AND pid <> pg_backend_pid()\nUNION ALL\nSELECT 'prepared_xact', gid, owner::text, prepared::text, age(transaction)\nFROM pg_prepared_xacts\nUNION ALL\nSELECT 'replication_slot', slot_name::text, slot_type, active::text,\n       greatest(age(xmin), age(catalog_xmin))\nFROM pg_replication_slots\nWHERE xmin IS NOT NULL OR catalog_xmin IS NOT NULL\nUNION ALL\nSELECT 'standby_feedback', application_name, usename::text, state, age(backend_xmin)\nFROM pg_stat_replication\nWHERE backend_xmin IS NOT NULL\nORDER BY xmin_age DESC NULLS LAST;","what":"デッドタプルのクリーンアップを妨げる可能性のある4つの要因を、xminの経過順に一覧表示する: スナップショットを保持するセッション、プリペアドトランザクション、レプリケーションスロット、hot_standby_feedbackを送信するスタンバイ。","when":"VACUUM VERBOSEが'dead row versions cannot be removed yet'を報告し、肥大化が進み続け、XIDの経過が減らないときに。","caution":"最も古いxminがクリーンアップのホライズンを決める。レプリケーションスロットとスタンバイのフィードバックはすべてのデータベースに影響する。プリペアドトランザクションは再起動後も残るため、所有者を確認し、COMMIT PREPARED / ROLLBACK PREPARED '<gid>'で終了する。未使用のスロットを削除するとその下流(スタンバイ、CDC)が壊れるため、先に所有者を確認する。スタンバイで実行すると、そのスタンバイのセッションのみが表示される。","tags":["xmin horizon","vacuum blocker","dead tuple","prepared transaction","replication slot","bloat"]},{"id":"pgstattuple-bloat","task":"pgstattupleで表とインデックスの肥大化を測定","category":"メンテナンス","command":"CREATE EXTENSION IF NOT EXISTS pgstattuple;\n\n-- Fast estimate: skips pages marked all-visible in the visibility map\nSELECT pg_size_pretty(table_len) AS table_size,\n       round(approx_tuple_percent::numeric, 1) AS live_pct,\n       round(dead_tuple_percent::numeric, 1) AS dead_pct,\n       round(approx_free_percent::numeric, 1) AS free_pct\nFROM pgstattuple_approx('orders');\n\n-- Exact measurement: reads the whole table\nSELECT pg_size_pretty(table_len) AS table_size,\n       round(dead_tuple_percent::numeric, 1) AS dead_pct,\n       round(free_percent::numeric, 1) AS free_pct,\n       pg_size_pretty(dead_tuple_len + free_space) AS reclaimable\nFROM pgstattuple('orders');\n\n-- B-tree indexes: leaf density (~90 when freshly built; below 50 is bloated)\nWITH idx AS MATERIALIZED (\n  SELECT i.indexrelid\n  FROM pg_index i\n  JOIN pg_class c ON c.oid = i.indexrelid\n  JOIN pg_am am ON am.oid = c.relam\n  WHERE am.amname = 'btree' AND i.indrelid = 'orders'::regclass\n)\nSELECT idx.indexrelid::regclass AS index_name,\n       pg_size_pretty(s.index_size) AS index_size,\n       s.avg_leaf_density,\n       s.leaf_fragmentation\nFROM idx\nCROSS JOIN LATERAL pgstatindex(idx.indexrelid) s;","what":"表のライブ/デッドタプルと空き領域の割合(高速な推定値と正確な値)、および回収可能な領域を表示する。B-treeインデックスではリーフ密度と断片化を表示する。","when":"pg_stat_user_tablesのn_dead_tupの推定値では不十分なときに。pg_repack、VACUUM FULL、REINDEXの判断をデータで裏付けるため。","caution":"pgstattupleとpgstatindexはリレーション全体を読み取るため、大きな表では大量のI/Oが発生する(取得するのはAccessShareLockのみ)。先にpgstattuple_approxを使用する。デフォルトではスーパーユーザーまたはpg_stat_scan_tablesロールが必要。ある程度の空き領域は正常(fillfactor、HOT更新用の余地)。VACUUMは領域を再利用可能にするがファイルは縮小しない。回収にはpg_repackまたはVACUUM FULL(ACCESS EXCLUSIVEロック!)が必要。avg_leaf_densityの低いインデックスはREINDEX CONCURRENTLYで再構築する。","since":"PostgreSQL 12","note":"pgstattupleはcontrib拡張で、pgstattuple_approxはPG9.5で導入された。CTEのMATERIALIZED(PG12以降)により、B-tree以外のインデックスに対してpgstatindexが呼び出されて失敗するのを防ぐ。","tags":["bloat","pgstattuple","pgstatindex","index bloat","dead tuple","free space"]},{"id":"pg-repack-online","task":"長時間のロックなしで肥大化した表を再編成(pg_repack)","category":"メンテナンス","command":"-- Once per target database (the pg_repack package must be installed on the server)\nCREATE EXTENSION pg_repack;\n\n# Dry run: show what would be done\npg_repack -h localhost -U postgres -d mydb --table=public.orders --dry-run\n\n# Rewrite the table and its indexes: 2 parallel index builds, wait at most 60 s for locks\npg_repack -h localhost -U postgres -d mydb --table=public.orders --jobs=2 --wait-timeout=60 --no-kill-backend\n\n# Rebuild indexes only\npg_repack -h localhost -U postgres -d mydb --table=public.orders --only-indexes","what":"バックグラウンドで表の圧縮コピーを作成し、トリガーで同時実行の変更をログ表に取り込み、最後に短時間のACCESS EXCLUSIVEロックの下で表を入れ替える。VACUUM FULLと異なり、処理中に読み取り/書き込みをブロックしない。","when":"VACUUMでは回収できない深刻な肥大化(pgstattupleで確認済み)を、稼働中のシステムで回収する必要があるときに。","caution":"表にはPRIMARY KEY、またはNOT NULL列のUNIQUEインデックスが必要。表とインデックスの合計と同じ追加ディスク領域が一時的に必要で、大量のWALを生成する(レプリカ遅延、アーカイブ量)。開始時と終了時にACCESS EXCLUSIVEロックが必要。--wait-timeoutが経過すると、デフォルトでは競合するクエリを取り消し、必要に応じてそのセッションを終了する。--no-kill-backendを指定するとその表をスキップする。実行中は対象の表でDDLを実行しない。クライアントと拡張のバージョンは一致している必要がある。中断した場合は、DROP EXTENSION pg_repack CASCADE; CREATE EXTENSION pg_repack;で残存物をクリーンアップする。","note":"pg_repackはPostgreSQL本体には含まれない(別パッケージ、例: postgresql-17-repack)。","tags":["pg_repack","bloat","online","vacuum full alternative","table reorganization","repack"]},{"id":"invalid-indexes","task":"INVALIDなインデックスを特定してクリーンアップ","category":"メンテナンス","command":"SELECT n.nspname AS schema_name,\n       c.relname AS index_name,\n       t.relname AS table_name,\n       pg_size_pretty(pg_relation_size(c.oid)) AS index_size,\n       i.indisvalid,\n       i.indisready,\n       format('DROP INDEX CONCURRENTLY %I.%I;', n.nspname, c.relname) AS fix\nFROM pg_index i\nJOIN pg_class c ON c.oid = i.indexrelid\nJOIN pg_class t ON t.oid = i.indrelid\nJOIN pg_namespace n ON n.oid = c.relnamespace\nWHERE NOT i.indisvalid OR NOT i.indisready;\n\n-- Before dropping: is an index build still in progress?\nSELECT pid, relid::regclass AS table_name, index_relid::regclass AS index_name, command, phase\nFROM pg_stat_progress_create_index;","what":"失敗したCREATE INDEX CONCURRENTLYやREINDEX CONCURRENTLYで残された無効なインデックスをサイズとともに一覧表示し、削除コマンドを生成する。","when":"失敗または取り消されたオンラインインデックス操作の後、定期的なヘルスチェック、メジャーアップグレードの前に。","caution":"実行中のCREATE INDEX CONCURRENTLY / REINDEX CONCURRENTLYもINVALIDと表示されるため、削除前にpg_stat_progress_create_indexを確認する。INVALIDなインデックスはクエリに使用されないが、indisready = trueの場合はすべてのINSERT/UPDATEで引き続きメンテナンスされ、純粋なオーバーヘッドとなる。REINDEX INDEX CONCURRENTLYで再構築できるが、原因(例: 一意性違反)を修正しないと再び失敗する。REINDEX CONCURRENTLYの残存物には_ccnew/_ccoldのサフィックスが付く。DROP INDEX CONCURRENTLYはトランザクションブロック内では実行できない。","tags":["invalid index","indisvalid","create index concurrently","broken index","_ccnew","index"]},{"id":"extended-statistics","task":"相関のある列に拡張統計を作成(CREATE STATISTICS)","category":"メンテナンス","command":"-- city and district are correlated: the planner assumes independence and underestimates rows\nCREATE STATISTICS customer_city_district_stx (dependencies, ndistinct, mcv) ON city, district FROM customer;\nANALYZE customer;\n\n-- Collected statistics\nSELECT statistics_name, attnames, kinds, n_distinct, dependencies\nFROM pg_stats_ext\nWHERE tablename = 'customer';\n\n-- Verify: estimated rows should now be close to actual rows\nEXPLAIN (ANALYZE, TIMING OFF)\nSELECT * FROM customer WHERE city = 'Ankara' AND district = 'Cankaya';","what":"列間の相関(関数従属性、組み合わせの異なり数、組み合わせの最頻値)をプランナに教え、複数列のWHEREおよびGROUP BY条件の行数推定を修正する。","when":"EXPLAIN ANALYZEで複数列フィルタの推定行数が実際よりはるかに少なく(例: 12対570)、その結果として誤った結合方法/インデックスが選択されるときに。","caution":"ANALYZEの後にのみ有効になる。列の組み合わせ数が統計ターゲット(デフォルト100)をはるかに上回る場合、mcvリストはその大部分をカバーできず、dependenciesなら修正できる推定をmcvが修正できないことがある。EXPLAINで確認し、必要に応じて定義からmcvを外すか、ALTER STATISTICS customer_city_district_stx SET STATISTICS 1000;でターゲットを引き上げる。dependenciesは等価/IN条件にのみ、ndistinctはGROUP BYの推定に使用される。定義ごとにANALYZEが長くなるため、見積り誤りが実証された列グループにのみ追加する。","since":"PostgreSQL 12","note":"CREATE STATISTICSはPG10(ndistinct、dependencies)、mcvの種類はPG12、ALTER STATISTICS ... SET STATISTICSはPG13、式の統計はPG14で導入された。","tags":["extended statistics","create statistics","correlation","row estimate","cardinality","analyze"]},{"id":"analyze-staleness","task":"統計が古くなった表を特定(ANALYZE戦略)","category":"メンテナンス","command":"SELECT schemaname,\n       relname AS table_name,\n       n_live_tup,\n       n_mod_since_analyze,\n       round(100.0 * n_mod_since_analyze / NULLIF(n_live_tup, 0), 1) AS mod_pct,\n       greatest(last_analyze, last_autoanalyze) AS last_analyzed,\n       round(current_setting('autovacuum_analyze_threshold')::int\n             + current_setting('autovacuum_analyze_scale_factor')::numeric * n_live_tup) AS autoanalyze_at\nFROM pg_stat_user_tables\nWHERE n_mod_since_analyze > 0\nORDER BY mod_pct DESC NULLS LAST\nLIMIT 20;\n\n-- After a bulk load, without waiting for autovacuum\nANALYZE (VERBOSE) orders;","what":"最後のANALYZE以降に変更された行数、ライブ行に対するその割合、autovacuumがANALYZEを起動するおおよその変更しきい値を表示する。","when":"大量のロード/削除の後、計画が誤った行数推定を示すとき、大きな表でautoanalyzeの遅れが疑われるときに。","caution":"計算されたしきい値はグローバル設定を使用する。表固有のautovacuum_analyze_*のreloptions(pg_class.reloptions)が存在する場合、実際のしきい値は異なる。大きな表ではデフォルトのscale_factor(0.1)では起動が遅すぎるため、表ごとに下げる。autovacuumはパーティション表の親をANALYZEしないため、親レベルの統計には手動のANALYZEが必要。一時表はautovacuumから見えない。ANALYZEはサンプルを読み取り、ShareUpdateExclusiveLockを取得する(DMLはブロックしない)。","tags":["analyze","stale statistics","n_mod_since_analyze","autoanalyze","statistics","planner"]},{"id":"visibility-map-index-only","task":"可視性マップのカバー率とIndex Only Scanの効率を確認","category":"メンテナンス","command":"-- Tables with a low all-visible page ratio: Index Only Scans must visit the heap\nSELECT c.oid::regclass AS table_name,\n       c.relpages,\n       c.relallvisible,\n       round(100.0 * c.relallvisible / NULLIF(c.relpages, 0), 1) AS all_visible_pct,\n       pg_size_pretty(pg_relation_size(c.oid)) AS heap_size,\n       s.n_ins_since_vacuum,\n       s.last_autovacuum\nFROM pg_class c\nJOIN pg_stat_user_tables s ON s.relid = c.oid\nWHERE c.relpages > 1000\nORDER BY all_visible_pct NULLS FIRST\nLIMIT 20;\n\n-- If \"Heap Fetches\" in the plan is close to the returned rows, the visibility map is stale\nEXPLAIN (ANALYZE, BUFFERS) SELECT id FROM customer WHERE id BETWEEN 1 AND 50000;\n\n-- Exact count (pg_visibility extension)\nCREATE EXTENSION IF NOT EXISTS pg_visibility;\nSELECT * FROM pg_visibility_map_summary('customer');","what":"表のall-visibleページの割合、最後のvacuum以降に挿入された行数、Index Only Scanがヒープにアクセスする必要があった頻度(Heap Fetches)を表示する。","when":"Index Only Scanの性能が低いとき。挿入中心/追記のみの表、カバリング(INCLUDE)インデックス設計の検証時に。","caution":"relpages/relallvisibleは最後のVACUUM/ANALYZEで記録された推定値。可視性マップのビットを設定するのはVACUUMのみで、UPDATE/DELETEのたびに該当ページのビットがクリアされる。頻繁に更新される表で割合が低い場合は、表ごとにautovacuum_vacuum_scale_factorを下げる。pg_visibility_map_summaryはヒープではなく小さなVMフォークを読み取る。","since":"PostgreSQL 13","note":"n_ins_since_vacuumと挿入起因のautovacuum(autovacuum_vacuum_insert_threshold/scale_factor)はPG13で導入された。それ以前は、追記のみの表では周回防止vacuumまでvacuumが行われず、可視性マップが設定されない場合がある。","tags":["visibility map","index only scan","heap fetches","relallvisible","pg_visibility","vacuum"]},{"id":"range-partition-monthly","task":"月次のレンジパーティション表を作成(ループでパーティションを生成)","category":"パーティション化","command":"CREATE TABLE sales (\n  id         bigint GENERATED ALWAYS AS IDENTITY,\n  created_at      date   NOT NULL,\n  customer_id bigint NOT NULL,\n  amount      numeric(12,2),\n  PRIMARY KEY (id, created_at)\n) PARTITION BY RANGE (created_at);\n\n-- An index defined on the parent propagates to all partitions automatically\nCREATE INDEX sales_customer_id_idx ON sales (customer_id);\n\n-- 12 monthly partitions for 2026\nDO $$\nDECLARE\n  m date;\nBEGIN\n  FOR m IN SELECT generate_series(date '2026-01-01', date '2026-12-01', interval '1 month')::date LOOP\n    EXECUTE format(\n      'CREATE TABLE IF NOT EXISTS %I PARTITION OF sales FOR VALUES FROM (%L) TO (%L)',\n      'sales_' || to_char(m, 'YYYY_MM'), m, (m + interval '1 month')::date);\n  END LOOP;\nEND $$;\n\n-- Hierarchy, bounds and sizes\nSELECT t.relid::regclass AS partition_name,\n       t.parentrelid::regclass AS parent,\n       t.isleaf,\n       t.level,\n       pg_get_expr(c.relpartbound, c.oid) AS bounds,\n       pg_size_pretty(pg_total_relation_size(t.relid)) AS total_size\nFROM pg_partition_tree('sales') t\nJOIN pg_class c ON c.oid = t.relid\nORDER BY t.level, bounds;","what":"日付列でRANGEパーティション化された親表、すべてのパーティションに伝播するインデックス、ループで12の月次パーティションを作成する。その後、境界とサイズとともに階層を一覧表示する。","when":"古いデータを定期的に削除する(DETACH/DROP)、またはクエリの大部分が日付範囲でフィルタする、増え続ける大きな表(注文、ログ、時系列)に。","caution":"パーティション表では、PRIMARY KEY/UNIQUE制約にパーティションキーを含める必要がある(グローバルな一意インデックスは存在しない)。下限は含み、上限は含まない(FROMは含む、TOは含まない)。将来のパーティションを事前作成するジョブ(pg_cron、pg_partman)がないと、範囲外のINSERTは失敗する。数千のパーティションは計画時間とロックのオーバーヘッドを増加させる。親表ではCREATE INDEX CONCURRENTLYはサポートされない: 親でCREATE INDEX ... ON ONLY、各パーティションでCREATE INDEX CONCURRENTLYを実行し、その後ALTER INDEX ... ATTACH PARTITIONを使用する。","since":"PostgreSQL 12","note":"宣言的パーティション化はPG10、親表のインデックス/PRIMARY KEYとデフォルトパーティションはPG11、pg_partition_tree()はPG12で導入された。","tags":["partition","range partition","declarative partitioning","monthly partition","pg_partition_tree","partitioning"]},{"id":"attach-partition-safely","task":"準備した表を短いロックでパーティションとしてアタッチ(ATTACH PARTITION)","category":"パーティション化","command":"-- 1) Prepare the data in a separate table without touching the live table\nCREATE TABLE sales_2027_01 (LIKE sales INCLUDING DEFAULTS INCLUDING CONSTRAINTS);\n-- ... bulk load (COPY / INSERT) ...\nALTER TABLE sales_2027_01 ADD PRIMARY KEY (id, created_at);\nCREATE INDEX CONCURRENTLY sales_2027_01_customer_id_idx ON sales_2027_01 (customer_id);\n\n-- 2) A CHECK that exactly matches the bounds: avoids a full scan during ATTACH\nALTER TABLE sales_2027_01 ADD CONSTRAINT sales_2027_01_bound_chk\n  CHECK (created_at IS NOT NULL AND created_at >= DATE '2027-01-01' AND created_at < DATE '2027-02-01') NOT VALID;\nALTER TABLE sales_2027_01 VALIDATE CONSTRAINT sales_2027_01_bound_chk;\n\n-- 3) Attach (SHARE UPDATE EXCLUSIVE on the parent; reads/writes continue)\nSET lock_timeout = '5s';\nALTER TABLE sales ATTACH PARTITION sales_2027_01\n  FOR VALUES FROM ('2027-01-01') TO ('2027-02-01');\nRESET lock_timeout;\n\n-- 4) Drop the now redundant CHECK\nALTER TABLE sales_2027_01 DROP CONSTRAINT sales_2027_01_bound_chk;","what":"別の表にロードしたデータを、境界と一致する事前検証済みのCHECK制約と事前作成したインデックスを使用して、フルスキャンや長いロックなしでパーティションにする。","when":"一括ロード(ETL)やアーカイブからのリストアに: ライブの表に触れずにデータを準備し、1回の手順でオンラインにする。","caution":"ATTACHは親表にSHARE UPDATE EXCLUSIVE、アタッチする表にACCESS EXCLUSIVEを取得する。一致する有効なCHECKがない場合、境界を検証するためにそのロックの下で表がフルスキャンされる。親と一致するインデックスがない場合、ATTACHはロックの下でそれを作成するため、両方を事前に準備する。デフォルトパーティションが存在する場合、新しい範囲の行を含まないことを証明するためにそれもスキャンされる(デフォルトパーティションのレシピを参照)。列名と型は親と完全に一致する必要がある。LIKE ... INCLUDINGで表を作成するのが最も安全。","since":"PostgreSQL 12","note":"親表にSHARE UPDATE EXCLUSIVEのみを取得するATTACH PARTITIONはPG12で導入された。PG11以前では親表はACCESS EXCLUSIVEでロックされる。","tags":["attach partition","add partition","check constraint","not valid","etl","partitioning"]},{"id":"detach-partition-concurrently","task":"ライブのトラフィックをブロックせずに古いパーティションをデタッチ(DETACH CONCURRENTLY)","category":"パーティション化","command":"-- Must run outside a transaction block\nALTER TABLE sales DETACH PARTITION sales_2026_01 CONCURRENTLY;\n\n-- If interrupted (cancel, lost connection) the partition stays 'detach pending'; complete it:\nALTER TABLE sales DETACH PARTITION sales_2026_01 FINALIZE;\n\n-- Any pending detach?\nSELECT inhrelid::regclass AS partition_name, inhparent::regclass AS parent\nFROM pg_inherits\nWHERE inhdetachpending;\n\n-- The detached table is now standalone: archive or drop it\nDROP TABLE sales_2026_01;","what":"2つのトランザクションでパーティションをデタッチする。親表にはSHARE UPDATE EXCLUSIVEのみを取得するため実行中のクエリはブロックされず、デタッチした表にパーティション境界と同等のCHECK制約を追加する。","when":"稼働中のシステムで保存期間/アーカイブのために古い期間をデタッチするときに(続いてDROP、別の表領域への移動、pg_dumpによるアーカイブ)。","caution":"BEGIN ... COMMITブロック内では実行できず、親表にデフォルトパーティションがある場合は使用できない。親表を使用する、開始前に始まったすべてのトランザクションを待機するため、長いトランザクションがあると長引く。中断した場合、パーティションはクエリからは見えないがデタッチされていない状態('detach pending')のままとなり、FINALIZEで完了させる必要がある。CONCURRENTLYなしの通常のDETACHは高速だが親表にACCESS EXCLUSIVEが必要。lock_timeoutを付けて試す。","since":"PostgreSQL 14","tags":["detach partition","concurrently","finalize","retention","archiving","partitioning"]},{"id":"default-partition-pitfall","task":"デフォルトパーティションの落とし穴: 新しいパーティションが'would be violated by some row'で失敗する","category":"パーティション化","command":"-- Which periods have rows in the default partition?\nSELECT date_trunc('month', created_at)::date AS month, count(*) AS row_count\nFROM sales_default\nGROUP BY 1\nORDER BY 1;\n\n-- Move the rows into a new partition and attach it in one transaction\nBEGIN;\nSET LOCAL lock_timeout = '5s';\nLOCK TABLE sales_default IN ACCESS EXCLUSIVE MODE;\nCREATE TABLE sales_2027_02 (LIKE sales INCLUDING DEFAULTS INCLUDING CONSTRAINTS);\nWITH moved AS (\n  DELETE FROM sales_default\n  WHERE created_at >= DATE '2027-02-01' AND created_at < DATE '2027-03-01'\n  RETURNING *\n)\nINSERT INTO sales_2027_02 SELECT * FROM moved;\nALTER TABLE sales ATTACH PARTITION sales_2027_02\n  FOR VALUES FROM ('2027-02-01') TO ('2027-03-01');\nCOMMIT;","what":"デフォルトパーティションに入った行を期間ごとに数え、新しいパーティションの範囲内の行を新しい表に移してアタッチする。すべてを1つのトランザクションで行う。","when":"CREATE TABLE ... PARTITION OFまたはATTACHが'updated partition constraint for default partition would be violated by some row'で失敗したとき、またはデフォルトパーティションの増大が見つかったときに。","caution":"デフォルトパーティションが存在すると、新しいパーティションを作成するたびにデフォルトがフルスキャンされ、その間ACCESS EXCLUSIVEが保持される。デフォルトパーティションが大きいと、メンテナンスのたびに停止が発生する。行の移動中はデフォルトへの書き込みができないため、トラフィックの少ない時間帯に行う。恒久的な対策: パーティションを事前作成し、監視でデフォルトを空に保つ(行数 > 0でアラート)、またはデフォルトをまったく使用せず、範囲外のINSERTを失敗させて問題を早期に表面化させる。デフォルトパーティションはDETACH ... CONCURRENTLYも妨げる。","since":"PostgreSQL 11","tags":["default partition","partition error","violated by some row","partition constraint","pitfall","partitioning"]},{"id":"partition-pruning-check","task":"パーティションプルーニングが機能していることを確認(計画時と実行時)","category":"パーティション化","command":"SHOW enable_partition_pruning;\n\n-- Plan-time pruning: only the relevant partition should appear in the plan\nEXPLAIN (COSTS OFF)\nSELECT count(*) FROM sales WHERE created_at >= DATE '2026-03-01' AND created_at < DATE '2026-04-01';\n\n-- Run-time pruning: generic plan / parameterized query, \"Subplans Removed: N\"\nPREPARE q_sales(date) AS SELECT count(*) FROM sales WHERE created_at = $1;\nSET plan_cache_mode = force_generic_plan;\nEXPLAIN (ANALYZE, COSTS OFF, TIMING OFF) EXECUTE q_sales('2026-03-15');\nRESET plan_cache_mode;\nDEALLOCATE q_sales;\n\n-- Pruning killer: a function on the key column scans every partition\nEXPLAIN (COSTS OFF)\nSELECT count(*) FROM sales WHERE date_trunc('month', created_at) = DATE '2026-03-01';","what":"計画時のプルーニング、汎用計画での実行時プルーニング('Subplans Removed: N')、パーティションキーに関数を適用したときにプルーニングが失われる様子を比較する。","when":"パーティション表へのクエリが想定より遅いとき、計画がすべてのパーティションをスキャンしているとき、アプリケーションがORM/プリペアドステートメントを使用しているときに。","caution":"パーティションキーに関数やキャストを適用すると(date_trunc(created_at)、created_at::text)プルーニングが無効になる。条件はキーに対する範囲として記述する。汎用計画では、プルーニングはエグゼキュータの起動時に行われ、'Subplans Removed'としてのみ表示される。now()などのSTABLE式では、ANALYZEなしのEXPLAINでも確認できる。enable_partition_pruning = offではプルーニングはまったく行われない。パーティションが多い場合はPlanning Timeも測定する。","since":"PostgreSQL 12","note":"実行時プルーニングはPG11で導入された。plan_cache_modeはPG12で導入され、PG12では多数のパーティションでの計画性能も大幅に改善された。","tags":["partition pruning","subplans removed","generic plan","plan_cache_mode","explain","partitioning"]},{"id":"pg-partman-setup","task":"pg_partmanでパーティションの作成と保存期間管理を自動化","category":"パーティション化","command":"CREATE SCHEMA partman;\nCREATE EXTENSION pg_partman SCHEMA partman;\n\nCREATE TABLE public.measurements (\n  id    bigint GENERATED ALWAYS AS IDENTITY,\n  ts    timestamptz NOT NULL,\n  value numeric,\n  PRIMARY KEY (id, ts)\n) PARTITION BY RANGE (ts);\n\n-- Daily partitions, pre-create 7 days ahead (pg_partman 5.x syntax)\nSELECT partman.create_parent(\n  p_parent_table := 'public.measurements',\n  p_control      := 'ts',\n  p_interval     := '1 day',\n  p_premake      := 7\n);\n\n-- Drop partitions older than 30 days\nUPDATE partman.part_config\n   SET retention = '30 days',\n       retention_keep_table = false\n WHERE parent_table = 'public.measurements';\n\n-- Maintenance: run periodically (schedule with pg_cron or pg_partman_bgw)\nCALL partman.run_maintenance_proc();\n\n-- Any rows in the default partition?\nSELECT * FROM partman.check_default(p_exact_count := true);","what":"親表をpg_partmanに登録する。将来のパーティションを事前作成し、保存期間を過ぎたものを削除し、デフォルトパーティションに入った行を報告する。","when":"日次/月次のパーティションを手作業や独自スクリプトで管理する代わりに、標準的で監視可能な自動化が必要なとき(ログ、メトリック、イベントの表)。","caution":"pg_partman 4.xと5.xの間でAPIが変更された: 5.xではp_typeは'range'/'list'のみを受け付け(デフォルト'range')、4.xのp_type := 'native'は無効。インストール済みのバージョンをSELECT extversion FROM pg_extension WHERE extname = 'pg_partman';で確認する。create_parentはデフォルトでデフォルトパーティションも作成する。retention_keep_table = falseはパーティションを完全にDROPする。アーカイブが必要な場合はtrueのままにしてretention_schemaを使用する。run_maintenance_proc()がスケジュールされていない場合、新しいパーティションは作成されず、データはデフォルトに入る。pg_partman_bgwにはshared_preload_librariesと再起動が必要。","note":"pg_partmanはPostgreSQL本体には含まれない(別パッケージ、例: postgresql-17-partman)。コマンドはpg_partman 5.xの構文を使用している。","tags":["pg_partman","partition maintenance","retention","create_parent","automatic partitioning","partitioning"]},{"id":"least-privilege-roles","task":"最小権限のロール階層を構築(GRANT + ALTER DEFAULT PRIVILEGES)","category":"セキュリティ","command":"-- Group roles (NOLOGIN): object owner, read-only, read-write\nCREATE ROLE app_owner NOLOGIN;\nCREATE ROLE app_readonly NOLOGIN;\nCREATE ROLE app_readwrite NOLOGIN;\nGRANT app_readonly TO app_readwrite;\nCREATE SCHEMA app AUTHORIZATION app_owner;\n\n-- Restrict PUBLIC's default privileges\nREVOKE ALL ON DATABASE mydb FROM PUBLIC;\nREVOKE CREATE ON SCHEMA public FROM PUBLIC;\n\n-- Existing objects\nGRANT CONNECT ON DATABASE mydb TO app_readonly;\nGRANT USAGE ON SCHEMA app TO app_readonly;\nGRANT SELECT ON ALL TABLES IN SCHEMA app TO app_readonly;\nGRANT INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA app TO app_readwrite;\nGRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA app TO app_readwrite;\n\n-- Objects app_owner will create IN THE FUTURE\nALTER DEFAULT PRIVILEGES FOR ROLE app_owner IN SCHEMA app GRANT SELECT ON TABLES TO app_readonly;\nALTER DEFAULT PRIVILEGES FOR ROLE app_owner IN SCHEMA app GRANT INSERT, UPDATE, DELETE ON TABLES TO app_readwrite;\nALTER DEFAULT PRIVILEGES FOR ROLE app_owner IN SCHEMA app GRANT USAGE, SELECT ON SEQUENCES TO app_readwrite;\n\n-- Login users get privileges only through group membership\nCREATE ROLE web_app LOGIN PASSWORD 'Change#2026' IN ROLE app_readwrite;\nCREATE ROLE report_app LOGIN PASSWORD 'Change#2026' IN ROLE app_readonly;\n\n-- Configured default privileges (psql: \\ddp)\nSELECT pg_get_userbyid(d.defaclrole) AS owner_role,\n       n.nspname AS schema_name,\n       d.defaclobjtype AS object_type,\n       d.defaclacl\nFROM pg_default_acl d\nLEFT JOIN pg_namespace n ON n.oid = d.defaclnamespace\nORDER BY 1, 2, 3;","what":"所有者、読み取り専用、読み取り/書き込みのグループロールの階層を構築する。既存および将来の表/シーケンスに適切な権限を付与し、アプリケーションユーザーにはグループメンバーシップを通じてのみ権限を与える。","when":"新しいアプリケーションスキーマの設定時、スーパーユーザーや表の所有者として接続しているアプリケーションの修正、監査前の権限の簡素化に。","caution":"ALTER DEFAULT PRIVILEGESは、FOR ROLEで指定したロールが後で作成するオブジェクトにのみ適用される。マイグレーションツールが別のユーザーで表を作成する場合、権限は適用されないため、SET ROLE app_ownerでDDLを実行する。GRANT ... ON ALL TABLESはその時点で存在するオブジェクトのみを対象とする。PG15以降で作成したデータベースでは、publicスキーマのCREATEはすでにPUBLICに付与されていない。古いバージョンからアップグレードしたデータベースではREVOKEが必要。REVOKE ALL ON DATABASE ... FROM PUBLICはCONNECTとTEMPも削除するため、それらを必要とする他のロールには個別に付与する。パスワードをコマンドラインに書く代わりにpsqlの\\passwordを使用する(ログや履歴に残らない)。","note":"pg_read_all_data / pg_write_all_dataロールはPG14、ロールメンバーシップのINHERIT/SETオプション(GRANT ... WITH INHERIT FALSE)はPG16で導入された。","tags":["least privilege","role hierarchy","alter default privileges","grant","privilege","security"]},{"id":"row-level-security","task":"行レベルセキュリティでテナント分離を設定","category":"セキュリティ","command":"ALTER TABLE app.orders ENABLE ROW LEVEL SECURITY;\n-- Make the table owner subject to the policy too\nALTER TABLE app.orders FORCE ROW LEVEL SECURITY;\n\nCREATE POLICY orders_tenant_isolation ON app.orders\n  FOR ALL\n  TO app_readwrite\n  USING (tenant_id = NULLIF(current_setting('app.tenant_id', true), '')::int)\n  WITH CHECK (tenant_id = NULLIF(current_setting('app.tenant_id', true), '')::int);\n\n-- The application sets the tenant at the start of every transaction (pooler-friendly)\nBEGIN;\nSET LOCAL app.tenant_id = '42';\nSELECT * FROM app.orders;\nCOMMIT;\n\n-- Configured policies\nSELECT schemaname, tablename, policyname, roles, cmd, qual, with_check\nFROM pg_policies\nWHERE tablename = 'orders';","what":"表でRLSを有効にし、セッション変数のテナントIDで行をフィルタし(USING)、別のテナントへの書き込みをブロックする(WITH CHECK)ポリシーを定義する。","when":"マルチテナントアプリケーションで、アプリケーションコードに頼らずデータベースでデータ分離を強制するため。","caution":"スーパーユーザーとBYPASSRLS属性を持つロールは常にポリシーをバイパスする。表の所有者はFORCE ROW LEVEL SECURITYを指定した場合のみ対象となる。RLSが有効で一致するポリシーがない場合、結果は空になる(エラーにはならない)。current_setting(..., true)は変数が未定義の場合NULLを返す。NULLIFは、RESET後に残る空文字列が''::intとして失敗するのを防ぐ。ユーザーはSETでapp.tenant_idを変更できるため、信頼できるアプリケーション層のみが設定し、エンドユーザーにSQLアクセスを与えてはならない。transactionモードのプーラーでは、SETの代わりにSET LOCALを使用する。ポリシーで使用するtenant_id列にインデックスを作成する。RLSの対象となるユーザーで実行するとpg_dumpは失敗するため、バックアップはBYPASSRLSロールで取得する。","since":"PostgreSQL 9.5","tags":["row level security","rls","create policy","multi-tenant","tenant isolation","security"]},{"id":"pg-hba-validate-reload","task":"pg_hba.confのルール順序を検証し、安全にリロード","category":"セキュリティ","command":"-- File location\nSHOW hba_file;\n\n# Rules are read top to bottom and the FIRST matching rule wins;\n# specific rules must come BEFORE general ones:\n#   hostssl  appdb  web_app  10.10.0.0/16  scram-sha-256\n#   host     all    all      10.10.0.0/16  reject\n#   host     all    all      0.0.0.0/0     scram-sha-256\n\n-- Validate BEFORE reloading: pg_hba_file_rules reads the file on disk\nSELECT line_number, type, database, user_name, address, netmask, auth_method, error\nFROM pg_hba_file_rules\nORDER BY line_number;\n\n-- Apply if the error column is empty\nSELECT pg_reload_conf();","what":"pg_hba.confの場所、PostgreSQLによる解釈(行、種類、データベース、ユーザー、アドレス、方式)、リロード前の構文エラーを表示し、その後構成をリロードする。","when":"新しいクライアントネットワーク/アプリケーションの追加時、md5からscram-sha-256への移行時、'no pg_hba.conf entry for host'エラーの調査時に。","caution":"pg_hba_file_rulesは有効なルールではなく現在のファイルの内容を示す。いずれかの行のerrorが空でない場合、リロードはpg_hba.confをまったく読み込まず、古いルールが有効なままとなる(ログには'pg_hba.conf was not reloaded'と出力される)。変更は新しい接続にのみ影響する。先頭近くに置いた広範なルール(例: host all all 0.0.0.0/0 trust)は、その後のすべての制限を無効にする。SSLがoffの場合、hostsslの行は一致せず、error列にメッセージが表示される。デフォルトではスーパーユーザーのみがこのビューを読み取れる。rootでファイルを編集するツールが所有権を変更しないようにする。postgresユーザーが読み取れないとリロードは失敗する。","since":"PostgreSQL 10","note":"pg_hba_file_rulesはPG10で導入された。新しいバージョンにはrule_numberとfile_name列もある。PG16はpg_hba.confでのincludeディレクティブと、user/databaseフィールドでの正規表現マッチングをサポートする。","tags":["pg_hba.conf","authentication","rule order","reload","pg_hba_file_rules","security"]},{"id":"ssl-enable-verify","task":"SSL/TLSを有効化し、暗号化接続を確認(pg_stat_ssl)","category":"セキュリティ","command":"# Server certificate (self-signed for testing; use a corporate CA in production)\nopenssl req -new -x509 -days 365 -nodes -subj \"/CN=db.example.com\" -keyout server.key -out server.crt\nchmod 600 server.key    # in the data directory, owned by postgres\n\n-- Enable SSL (a reload is enough)\nALTER SYSTEM SET ssl = on;\nALTER SYSTEM SET ssl_cert_file = 'server.crt';\nALTER SYSTEM SET ssl_key_file = 'server.key';\nALTER SYSTEM SET ssl_min_protocol_version = 'TLSv1.2';\nSELECT pg_reload_conf();\n\n-- Which connections are encrypted?\nSELECT a.pid, a.usename, a.client_addr, a.application_name,\n       s.ssl, s.version, s.cipher, s.bits\nFROM pg_stat_ssl s\nJOIN pg_stat_activity a USING (pid)\nWHERE a.backend_type = 'client backend'\nORDER BY s.ssl, a.usename;\n\n# On the client, verify the server identity as well\npsql \"host=db.example.com dbname=postgres user=postgres sslmode=verify-full sslrootcert=root.crt\"","what":"再起動なしでサーバー証明書によるTLSを有効にし、最小プロトコルバージョンを設定し、現在の接続が暗号化されているかをTLSバージョンと暗号とともに一覧表示する。","when":"セキュリティ監査/コンプライアンス要件(PCI、GDPR)のため、ネットワーク上を転送されるパスワードとデータを保護するため。","caution":"ssl = onだけでは暗号化は強制されない。クライアントはsslmode=prefer/disableで引き続き非暗号化で接続できる。強制するにはpg_hba.confでhostの代わりにhostsslを使用する(さらにhostnossl ... rejectを追加する)。sslmode=requireはサーバーの身元を検証しない(MITMに対して無防備)。証明書の検証にはverify-fullを使用する。鍵ファイルはpostgresユーザー所有でモード0600(またはroot所有で0640)である必要がある。そうでないとSSLが読み込まれないため、リロード後にログとSHOW sslを確認する。証明書の更新もリロードで反映される。","since":"PostgreSQL 10","note":"再起動ではなくリロードでSSL設定を変更できるのはPG10から、ssl_min_protocol_versionはPG12で導入され、PG13以降のデフォルトはTLSv1.2。","tags":["ssl","tls","pg_stat_ssl","hostssl","certificate","encryption"]},{"id":"scram-migration","task":"md5パスワードからscram-sha-256へ移行","category":"セキュリティ","command":"-- 1) Store new passwords as SCRAM\nALTER SYSTEM SET password_encryption = 'scram-sha-256';\nSELECT pg_reload_conf();\n\n-- 2) Find roles still carrying md5 password hashes (requires superuser)\nSELECT rolname,\n       CASE\n         WHEN rolpassword LIKE 'SCRAM-SHA-256$%' THEN 'scram-sha-256'\n         WHEN rolpassword LIKE 'md5%' THEN 'md5'\n         WHEN rolpassword IS NULL THEN 'no password'\n         ELSE 'other'\n       END AS password_type,\n       rolvaliduntil\nFROM pg_authid\nWHERE rolcanlogin\nORDER BY password_type, rolname;\n\n-- 3) Reset the password of each md5 role (preferably in psql: \\password legacy_app)\nALTER ROLE legacy_app PASSWORD 'New#Password2';\n\n# 4) Once all roles use SCRAM, change md5 -> scram-sha-256 in pg_hba.conf and reload","what":"新しいパスワードがSCRAM-SHA-256で格納されるようにし、まだmd5ハッシュを持つログインロールを特定し、パスワードの更新後にpg_hba.confをscram-sha-256に切り替える手順を示す。","when":"セキュリティ監査でmd5が指摘されたとき、PG14以降へのアップグレード後、md5が非推奨となるバージョンへの準備時に。","caution":"SCRAMは既存のmd5ハッシュから導出できず、すべてのパスワードを平文で再設定する必要がある(アプリケーションチームとの調整が必要)。pg_hba.confの'md5'方式は、パスワードがSCRAMのロールに対して自動的にSCRAM認証を行うため、移行中にmd5のままにしておくのは安全な中間段階である。ただし方式を'scram-sha-256'にすると、md5パスワードのロールは接続できなくなる。古いクライアントドライバ(libpq < 10、古いJDBC/.NETドライバ)はSCRAMをサポートしない場合があるため、先にドライバをアップグレードする。ALTER ROLE ... PASSWORDはlog_statementによってパスワードをログに書き込む場合がある。psqlの\\passwordは送信前にクライアントでハッシュ化する。","since":"PostgreSQL 10","note":"SCRAM-SHA-256はPG10で導入され、password_encryptionのデフォルトはPG14でscram-sha-256になった。PG18ではmd5パスワードは非推奨となり、警告が出力される。","tags":["scram-sha-256","md5","password_encryption","password","authentication","security"]},{"id":"pgaudit-object-audit","task":"pgauditでロールおよびオブジェクトレベルの監査ログを記録","category":"セキュリティ","command":"-- Prerequisite: shared_preload_libraries = 'pgaudit' + restart, then:\nCREATE EXTENSION pgaudit;\n\n-- Session auditing: server-wide, only DDL and role/privilege changes\nALTER SYSTEM SET pgaudit.log = 'ddl, role';\nALTER SYSTEM SET pgaudit.log_relation = on;\nALTER SYSTEM SET pgaudit.log_parameter = off;\nSELECT pg_reload_conf();\n\n-- All reads/writes of a specific application role\nALTER ROLE web_app SET pgaudit.log = 'read, write';\n\n-- Object auditing: privileges granted to the auditor role = operations to log\nCREATE ROLE auditor NOLOGIN;\nALTER SYSTEM SET pgaudit.role = 'auditor';\nSELECT pg_reload_conf();\nGRANT SELECT, DELETE ON customer TO auditor;\nGRANT UPDATE (balance) ON customer TO auditor;","what":"サーバー全体のDDLと権限変更、特定ロールのすべての読み取り/書き込み、監査ロールに付与された機密表/列へのアクセスを、'AUDIT:'で始まる構造化されたログ行として記録する。","when":"GDPR、PCI-DSS、SOXなどのコンプライアンス監査で、誰が機密データにアクセスしたかを証明するため。","caution":"サーバー全体でpgaudit.log = 'all'または'read'を有効にすると、ログ量とI/Oが大幅に増加する。ロールまたはオブジェクトの監査で範囲を絞り込む。スーパーユーザーは監査を無効にできる(ALTER SYSTEM/ALTER ROLE)ため、レコードを中央ログシステム(syslog/SIEM)に送信し、データベースサーバーとは独立して保管する。log_parameter = onはバインドパラメータ(個人データ)もログに記録する。ロールの設定は新しいセッションで有効になる。pgauditのメジャーバージョンはPostgreSQLのメジャーバージョンと一致する必要がある(pgaudit 17.x = PG17)。","note":"pgauditはPostgreSQL本体には含まれない(別パッケージ、例: postgresql-17-pgaudit)。","tags":["pgaudit","audit","auditing","object audit","log","security"]},{"id":"memory-settings-check","task":"メモリ設定を確認(shared_buffers、work_mem、maintenance_work_mem)","category":"パラメータ","command":"SELECT name,\n       current_setting(name) AS value,\n       source,\n       context\nFROM pg_settings\nWHERE name IN ('shared_buffers', 'effective_cache_size', 'work_mem', 'hash_mem_multiplier',\n               'maintenance_work_mem', 'autovacuum_work_mem', 'max_connections',\n               'max_parallel_workers_per_gather', 'huge_pages', 'temp_buffers', 'wal_buffers')\nORDER BY name;\n\n-- Rough ceilings: work_mem x max_connections and the autovacuum memory ceiling\nSELECT pg_size_pretty(pg_size_bytes(current_setting('work_mem'))\n                      * current_setting('max_connections')::int) AS work_mem_x_max_connections,\n       pg_size_pretty(pg_size_bytes(current_setting('maintenance_work_mem'))\n                      * current_setting('autovacuum_max_workers')::int) AS autovacuum_mem_ceiling;\n\n-- Trace of operations that did not fit in work_mem: temp files per database\nSELECT datname, temp_files, pg_size_pretty(temp_bytes) AS temp_size, stats_reset\nFROM pg_stat_database\nWHERE datname IS NOT NULL\nORDER BY temp_bytes DESC;","what":"メモリ関連のパラメータを、値、設定元(デフォルト/構成ファイル)、変更コンテキスト(postmaster = 再起動)とともに表示する。work_memとautovacuumのおおよそのメモリ上限、データベースごとの一時ファイル量も表示する。","when":"新しいサーバーの構築時、RAMの追加後、OOM killerの発生後、一時ファイルの大量使用が見られるときに。","caution":"work_memは接続ごとではなく、ソート/ハッシュのノードごとに(ハッシュではhash_mem_multiplier倍)、さらにパラレルワーカーごとに個別に割り当てられる。複雑なクエリはwork_memの数倍を使用する場合があるため、計算した積は上限ではなくおおよその警告値である。一般的な初期値: shared_buffersはRAMの約25%(再起動が必要)、effective_cache_sizeは約50-75%(プランナへのヒントのみで、何も割り当てない)、maintenance_work_memは512MB-2GB。autovacuum_work_mem = -1の場合、各autovacuumワーカーはmaintenance_work_memを使用できる。temp_bytesが高い場合は、グローバルではなくロールまたはクエリ単位でwork_memを引き上げる。Linuxでshared_buffersが大きい場合は、huge_pagesを検討する。","note":"hash_mem_multiplierはPG13で導入された(PG15以降のデフォルトは2.0)。","tags":["shared_buffers","work_mem","maintenance_work_mem","memory","memory tuning","temp_bytes"]},{"id":"pending-restart-config-errors","task":"再起動待ちのパラメータと構成ファイルのエラーを表示","category":"パラメータ","command":"-- Parameters changed but not effective until a restart\nSELECT name, setting, unit, context, source, sourcefile, pending_restart\nFROM pg_settings\nWHERE pending_restart;\n\n-- Lines in configuration files that were not applied or have errors\nSELECT sourcefile, sourceline, seqno, name, setting, applied, error\nFROM pg_file_settings\nWHERE NOT applied OR error IS NOT NULL\nORDER BY sourcefile, sourceline;\n\n-- Where does a parameter's effective value come from?\nSELECT name, setting, source, sourcefile, sourceline\nFROM pg_settings\nWHERE name = 'work_mem';","what":"ファイルで変更されたが再起動を待っているパラメータ、適用されなかったかエラーのある構成ファイルの行、パラメータの有効値がどのファイル/行から来ているかを表示する。","when":"ALTER SYSTEMまたはpostgresql.confの変更後にリロードが期待どおりの効果をもたらしたかの確認、計画的な再起動前の保留中の変更の一覧表示に。","caution":"pg_file_settingsは現在のファイルの内容を読み取る。パラメータが複数箇所で定義されている場合、applied = trueになるのは最後のもののみ(postgresql.auto.confは最後に読み込まれるため、ALTER SYSTEMが常に優先される)。applied = falseでerrorが空の行は、別の定義に隠されているだけでエラーではない。再起動が必要なパラメータにはerror 'setting could not be applied'が表示される。誤りのあるファイルはリロード時に部分的に適用される場合がある。変更後はpg_reload_conf()を実行し、これらのクエリとサーバーログを確認する。postgresql.auto.confを手動で編集しない。ALTER SYSTEM RESETを使用する。","since":"PostgreSQL 9.5","tags":["pending_restart","pg_file_settings","restart","configuration error","alter system","config"]},{"id":"checkpoint-stats","task":"チェックポイントの動作を確認(PG17以降はpg_stat_checkpointer、PG16以前はpg_stat_bgwriter)","category":"パラメータ","command":"-- PG17+\nSELECT num_timed,\n       num_requested,\n       round(100.0 * num_requested / NULLIF(num_timed + num_requested, 0), 1) AS req_pct,\n       restartpoints_timed,\n       restartpoints_req,\n       round((write_time / 1000)::numeric / NULLIF(num_timed + num_requested, 0), 1) AS avg_write_s,\n       round((sync_time / 1000)::numeric / NULLIF(num_timed + num_requested, 0), 1) AS avg_sync_s,\n       pg_size_pretty(buffers_written * current_setting('block_size')::bigint) AS written_by_checkpoint,\n       stats_reset\nFROM pg_stat_checkpointer;\n\n-- PG16 and earlier\nSELECT checkpoints_timed,\n       checkpoints_req,\n       round(100.0 * checkpoints_req / NULLIF(checkpoints_timed + checkpoints_req, 0), 1) AS req_pct,\n       round((checkpoint_write_time / 1000)::numeric / NULLIF(checkpoints_timed + checkpoints_req, 0), 1) AS avg_write_s,\n       round((checkpoint_sync_time / 1000)::numeric / NULLIF(checkpoints_timed + checkpoints_req, 0), 1) AS avg_sync_s,\n       pg_size_pretty(buffers_checkpoint * current_setting('block_size')::bigint) AS written_by_checkpoint,\n       pg_size_pretty(buffers_clean * current_setting('block_size')::bigint) AS written_by_bgwriter,\n       pg_size_pretty(buffers_backend * current_setting('block_size')::bigint) AS written_by_backends,\n       maxwritten_clean,\n       stats_reset\nFROM pg_stat_bgwriter;\n\n-- Related settings\nSELECT name, current_setting(name) AS value\nFROM pg_settings\nWHERE name IN ('checkpoint_timeout', 'max_wal_size', 'min_wal_size',\n               'checkpoint_completion_target', 'log_checkpoints')\nORDER BY name;","what":"スケジュールされたチェックポイントとWAL量により強制されたチェックポイントの比率、チェックポイントあたりの平均書き込み/同期時間、書き込まれたバッファ量を表示する(PG16以前では、bgwriterとバックエンドの書き込みも併せて)。","when":"書き込みの多い期間にI/Oスパイクが見られるとき、WAL生成量が多いとき、ログに'checkpoints are occurring too frequently'の警告が出るときに。","caution":"req_pctが高い(一般に10-20%超)場合、max_wal_sizeが満杯になるためにチェックポイントが強制されていることを意味する。max_wal_sizeを引き上げ、log_checkpoints = onで'checkpoint starting: wal'の行を監視する。checkpoint_timeoutを長くするとI/Oは分散されるが、クラッシュリカバリが長くなる。PG16以前でwritten_by_backendsが高い場合、バックエンドがダーティページを自ら書き込む必要があることを意味する(shared_buffers/bgwriterが不足)。PG17ではこれはpg_stat_ioにある。平均値には作業がなくスキップされたスケジュール済みチェックポイントも含まれるため、おおよその数値として読む。カウンタはstats_reset以降の累積値。","since":"PostgreSQL 17","note":"PG17ではチェックポインタの統計がpg_stat_bgwriterから新しいpg_stat_checkpointerビューに移された(checkpoints_timed → num_timed、checkpoints_req → num_requested、buffers_checkpoint → buffers_written)。buffers_backendとbuffers_backend_fsyncは削除された。PG18ではnum_doneとslru_written列が追加された。","tags":["checkpoint","pg_stat_checkpointer","pg_stat_bgwriter","max_wal_size","checkpoint_timeout","wal"]},{"id":"relation-size-breakdown","task":"表のサイズをヒープ / インデックス / TOAST別に、および最大のインデックスを一覧表示","category":"ストレージ","command":"SELECT n.nspname AS schema_name,\n       c.relname AS table_name,\n       pg_size_pretty(pg_total_relation_size(c.oid)) AS total,\n       pg_size_pretty(pg_relation_size(c.oid)) AS heap,\n       pg_size_pretty(pg_indexes_size(c.oid)) AS indexes,\n       pg_size_pretty(pg_total_relation_size(c.oid) - pg_relation_size(c.oid) - pg_indexes_size(c.oid)) AS toast_fsm_vm,\n       round(100.0 * pg_total_relation_size(c.oid) / NULLIF(pg_database_size(current_database()), 0), 1) AS pct_of_db\nFROM pg_class c\nJOIN pg_namespace n ON n.oid = c.relnamespace\nWHERE c.relkind IN ('r', 'm')\n  AND n.nspname NOT IN ('pg_catalog', 'information_schema')\nORDER BY pg_total_relation_size(c.oid) DESC\nLIMIT 20;\n\n-- Largest indexes and their usage counts\nSELECT s.schemaname,\n       s.relname AS table_name,\n       s.indexrelname AS index_name,\n       pg_size_pretty(pg_relation_size(s.indexrelid)) AS index_size,\n       s.idx_scan,\n       i.indisunique,\n       i.indisprimary\nFROM pg_stat_user_indexes s\nJOIN pg_index i ON i.indexrelid = s.indexrelid\nORDER BY pg_relation_size(s.indexrelid) DESC\nLIMIT 20;","what":"最も大きい表を合計、ヒープ、インデックス、TOAST(+FSM/VM)に分けて、データベースに占める割合とともに表示する。最も大きいインデックスをスキャン回数とunique/primaryのフラグとともに表示する。","when":"ディスク使用量の増加時に、増加の原因(データ、インデックス、TOAST)を特定するため。使用されていない大きなインデックスの発見に。","caution":"サイズ関数はリレーションごとにファイルシステムにアクセスするため、数万の表を持つデータベースでは遅くなる場合がある。パーティション表の親(relkind 'p')自体は0バイトであり除外される。階層全体の合計は: SELECT pg_size_pretty(sum(pg_total_relation_size(relid))) FROM pg_partition_tree('sales'); idx_scan = 0の大きなインデックスは削除候補だが、カウンタは最後の統計リセット以降かつこのサーバーのみの値である(レプリカでの使用は見えない)。unique/primaryインデックスは制約を強制しているため削除しない。","tags":["table size","index size","toast","disk usage","pg_total_relation_size","storage"]},{"id":"extension-update-check","task":"更新が保留中の拡張を特定して更新","category":"拡張機能","command":"SELECT e.extname,\n       e.extversion AS installed,\n       a.default_version AS available,\n       n.nspname AS schema_name,\n       format('ALTER EXTENSION %I UPDATE;', e.extname) AS fix\nFROM pg_extension e\nJOIN pg_available_extensions a ON a.name = e.extname\nJOIN pg_namespace n ON n.oid = e.extnamespace\nWHERE e.extversion IS DISTINCT FROM a.default_version\nORDER BY e.extname;\n\n-- Is there an update path?\nSELECT * FROM pg_extension_update_paths('pgstattuple') WHERE path IS NOT NULL;\n\nALTER EXTENSION pgstattuple UPDATE;","what":"データベース内の各拡張のインストール済みバージョンをサーバー上のパッケージのデフォルトバージョンと比較し、更新が保留中のものについてALTER EXTENSIONコマンドを生成する。","when":"PostgreSQLのマイナー/メジャーアップグレードや拡張パッケージの更新後、定期メンテナンス時に。","caution":"OSパッケージをアップグレードしてもSQL側は自動的に更新されない。ALTER EXTENSION ... UPDATEをデータベースごとに個別に実行する必要がある(pg_upgrade後は特に重要)。更新スクリプトはロールを取得しオブジェクトを変更する場合がある(例: PostGIS)ため、先にテストし、リリースノートを読む。特定のバージョンに移行するには: ALTER EXTENSION pgstattuple UPDATE TO '1.5'; 一部の拡張(例: pg_stat_statements)は共有ライブラリの再ロードのために再起動も必要。","tags":["alter extension update","extension version","extension","pg_available_extensions","upgrade","update"]},{"id":"pg-stat-io-analysis","task":"pg_stat_ioでI/Oの発生元を分析(バックエンドの種類、オブジェクト、コンテキスト)","category":"拡張機能","command":"SELECT backend_type,\n       object,\n       context,\n       reads,\n       pg_size_pretty(reads * op_bytes) AS read_size,\n       writes,\n       pg_size_pretty(writes * op_bytes) AS write_size,\n       extends,\n       hits,\n       round(100.0 * hits / NULLIF(hits + reads, 0), 1) AS hit_pct,\n       evictions,\n       reuses,\n       fsyncs,\n       round(read_time::numeric, 1) AS read_ms,\n       round(write_time::numeric, 1) AS write_ms\nFROM pg_stat_io\nWHERE coalesce(reads, 0) + coalesce(writes, 0) + coalesce(extends, 0) + coalesce(evictions, 0) > 0\nORDER BY coalesce(reads, 0) + coalesce(writes, 0) DESC;\n\n-- Who writes? Ideally most writes come from the checkpointer and background writer\nSELECT backend_type,\n       pg_size_pretty(sum(writes * op_bytes)) AS written,\n       round(100.0 * sum(writes) / NULLIF(sum(sum(writes)) OVER (), 0), 1) AS pct_of_writes,\n       sum(fsyncs) AS fsyncs\nFROM pg_stat_io\nWHERE object = 'relation' AND writes > 0\nGROUP BY backend_type\nORDER BY sum(writes) DESC;","what":"バックエンドの種類(client backend、autovacuum、checkpointer...)、オブジェクト(relation/temp relation)、コンテキスト(normal、vacuum、bulkread、bulkwrite)別に、読み取り、書き込み、拡張、追い出し、fsyncを表示する。書き込みがどのプロセスの種類から来ているかも表示する。","when":"I/Oボトルネック時に、負荷がクエリ、autovacuum、チェックポイントのどれから来ているかを判別するため、およびshared_buffers/bgwriterの設定の検証に。","caution":"pg_stat_ioはクラスタ全体の値で、最後のリセット以降の累積値。変化を見るには2つのサンプルの差を取る(リセットするには: SELECT pg_stat_reset_shared('io');)。read_time/write_timeはtrack_io_timing = onの場合のみ設定される。readsにはOSのページキャッシュから提供された読み取りも含まれる。client backendの書き込みや追い出しが多い場合、バックエンドが空きを作るために自らバッファを書き込んでいることを意味する。shared_buffers、bgwriter_lru_maxpages、チェックポイントの設定を見直す。context = 'vacuum'/'bulkread'の行はリングバッファの使用を反映しており、そこでのreusesは正常。","since":"PostgreSQL 16","note":"pg_stat_ioはPG16で導入された。PG18ではop_bytes列が削除され、read_bytes/write_bytes/extend_bytesが追加され、このビューでWALのI/Oも報告されるようになった。PG18ではreads * op_bytesの代わりにread_bytesを使用する。","tags":["pg_stat_io","io statistics","evictions","fsync","shared_buffers","io"]}]},"recipes/mysql.json":{"engineId":"mysql","engine":"MySQL / MariaDB","order":3,"recipes":[{"id":"rotate-binlog","task":"バイナリログをローテーション","category":"BinlogとLog","command":"FLUSH BINARY LOGS;","what":"現在のバイナリログファイルを閉じ、新しいファイルに切り替える。","when":"バックアップ前にクリーンなbinlogの開始点を作成するため、またはファイルサイズを制限するため。","caution":"頻繁なローテーションは多数の小さなbinlogファイルを生む。同じコマンドはMariaDBでも動作する。FLUSH LOGSはすべてのログをローテーションする。","tags":["binlog","rotate","flush","log"]},{"id":"purge-binlog","task":"古いバイナリログを削除(PURGE)","category":"BinlogとLog","command":"PURGE BINARY LOGS BEFORE NOW() - INTERVAL 7 DAY;","what":"指定した日付より古いバイナリログファイルをディスクから削除する。","when":"binlogがディスクを圧迫しているとき、不要になった古いログをクリーンアップするために。","caution":"削除するbinlogをレプリカがまだ必要としている場合、レプリケーションが壊れる。先にSHOW REPLICA STATUSですべてのレプリカがそれを通過していることを確認する。特定のファイルまで削除するには: PURGE BINARY LOGS TO 'mysql-bin.000123'; 自動クリーンアップにはbinlog_expire_logs_seconds設定を使用する。","tags":["binlog","purge","cleanup","log"]},{"id":"show-binlogs","task":"バイナリログの状態を表示","category":"BinlogとLog","command":"SHOW BINARY LOGS;","what":"サーバー上のすべてのバイナリログファイルとそのサイズを一覧表示する。","when":"binlogのディスク使用量と、どのファイルが存在するかを確認するため。","caution":"現在書き込み中のbinlogファイルとその位置: SHOW BINARY LOG STATUS;(MySQL 8.2以降)。古いバージョンではSHOW MASTER STATUSを使用する(8.2–8.3で非推奨、8.4で削除)。","tags":["binlog","status","show","log"]},{"id":"enable-general-slow-log","task":"一般クエリログとスロークエリログを有効化","category":"BinlogとLog","command":"SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1; SET GLOBAL general_log = 'ON';","what":"実行時に、スロークエリログ(1秒を超えるクエリ)と、すべてのクエリを記録する一般ログを有効にする。","when":"遅いクエリやすべてのクエリトラフィックを一時的に分析するため。","caution":"general_logは大きな性能とディスクのオーバーヘッドを加えるため、診断が終わったら必ず無効にする(SET GLOBAL general_log='OFF')。これらの設定は再起動でリセットされる。永続化するにはSET PERSISTを使用する。","tags":["slow-log","general-log","log","diagnostics"]},{"id":"innodb-redo-capacity","task":"InnoDBのREDOログサイズを変更","category":"ストレージ","command":"SET GLOBAL innodb_redo_log_capacity = 2147483648;","what":"InnoDBのREDOログの合計容量(バイト単位、ここでは2 GB)を実行時に動的に設定する。","when":"書き込みの多いワークロードでチェックポイントの頻度を下げ、性能を向上させるため。","caution":"innodb_redo_log_capacityはMySQL 8.0.30で導入され、旧来のinnodb_log_file_size + innodb_log_files_in_group設定を置き換える。古いバージョン/MariaDBでは、innodb_log_file_sizeはmy.cnfで変更し、再起動が必要。永続化するには: SET PERSIST innodb_redo_log_capacity = 2147483648;","since":"MySQL 8.0.30","note":"innodb_redo_log_capacityはMySQL 8.0.30で導入され、REDOログの動的な(再起動不要の)サイズ変更を可能にした。以前はinnodb_log_file_size + innodb_log_files_in_groupを設定し、サーバーを再起動する必要があった。","tags":["innodb","redo-log","capacity","storage"]},{"id":"innodb-undo-tablespace","task":"InnoDBのUNDO表領域を追加/管理","category":"ストレージ","command":"CREATE UNDO TABLESPACE undo_003 ADD DATAFILE 'undo_003.ibu';","what":"新しいInnoDBのUNDO表領域を作成する。UNDOログはデータファイルとは別に管理され、切捨て可能になる。","when":"長時間実行のトランザクションがUNDOログを肥大化させるときの領域管理、またはUNDOを別のディスクに移すために。","caution":"ファイル名は.ibuで終わる必要がある。UNDO表領域を削除するには先に非アクティブにする必要がある: ALTER UNDO TABLESPACE undo_003 SET INACTIVE; その後DROP UNDO TABLESPACE undo_003; これはMySQL 8.0以降の機能。","since":"MySQL 8.0","note":"SQLによるUNDO表領域の作成/削除(CREATE/DROP UNDO TABLESPACE)はMySQL 8.0で導入された。以前はUNDO表領域の数はinnodb_undo_tablespacesで固定されており、実行時に管理できなかった。","tags":["innodb","undo-log","tablespace","storage"]},{"id":"create-tablespace","task":"一般表領域を追加","category":"ストレージ","command":"CREATE TABLESPACE ssd_ts ADD DATAFILE 'ssd_ts.ibd' ENGINE=InnoDB;","what":"複数の表で共有できるInnoDBの一般表領域を作成する。","when":"表を特定のファイル/ディスクにまとめるため、またはファイル数を減らすため。","caution":"DATAFILEのパスが相対パスの場合、datadir配下に作成される。別のディスクに置くには絶対パスと必要な権限が必要。表をここに移動するには: ALTER TABLE customer TABLESPACE ssd_ts; 表領域は空の場合にのみ削除できる。","tags":["tablespace","innodb","storage","create"]},{"id":"optimize-table","task":"表をOPTIMIZE","category":"ストレージ","command":"OPTIMIZE TABLE customer;","what":"表を再構築して断片化を解消し、未使用領域を回収し、インデックス統計を更新する。","when":"多数のDELETE/UPDATEで肥大化したInnoDB表の領域を回収するため。","caution":"InnoDBでは、OPTIMIZEは実際には表を再構築するオンラインALTERとして実行されるが、I/Oと一時ディスク領域は依然として必要。大きな表では表サイズと同じ空きディスクが必要。ロックを減らすため、トラフィックの少ない時間帯に実行する。","tags":["optimize","table","defragment","storage"]},{"id":"table-schema-size","task":"表とスキーマのサイズを照会する","category":"ストレージ","command":"SELECT table_schema AS schema_name, table_name AS table_name, ROUND((data_length + index_length) / 1024 / 1024, 1) AS size_mb FROM information_schema.tables WHERE table_schema NOT IN ('mysql','information_schema','performance_schema','sys') ORDER BY (data_length + index_length) DESC LIMIT 20;","what":"データとインデックスの合計サイズ(MB)で最も大きい20の表を一覧表示する。","when":"ディスク使用量を分析し、どの表が領域を占めているかを特定するため。","caution":"InnoDBではinformation_schemaのサイズは概算値。スキーマごとの合計には、table_nameではなくtable_schemaのみでGROUP BYする。","tags":["size","table","schema","information-schema"]},{"id":"analyze-table","task":"表の統計を更新(ANALYZE TABLE)","category":"メンテナンス","command":"ANALYZE TABLE customer;","what":"オプティマイザがより良い計画を選択できるよう、表のインデックス/キーの分布統計を再計算する。","when":"大量のデータ変更後に悪い実行計画が現れるときに。","caution":"実行中は表に短時間のメタデータロックが取得される。InnoDBではサンプルベースであり、精度を上げるにはinnodb_stats_persistent_sample_pagesを引き上げる。","tags":["analyze","statistics","optimizer","maintenance"]},{"id":"rebuild-table","task":"表/インデックスを再構築","category":"メンテナンス","command":"ALTER TABLE customer ENGINE=InnoDB;","what":"同じエンジンで表を再構築する。インデックスとデータページを再作成し、断片化とインデックスの肥大化を解消する。","when":"空のALTERで表をリフレッシュするため、または損傷したページレイアウトを修復するため。","caution":"大きな表では表サイズと同じ一時ディスクが必要。ロックを減らすには: ALTER TABLE customer ENGINE=InnoDB, ALGORITHM=INPLACE, LOCK=NONE;","tags":["rebuild","alter","innodb","maintenance"]},{"id":"check-table","task":"表の整合性を確認(CHECK TABLE)","category":"メンテナンス","command":"CHECK TABLE customer;","what":"表とそのインデックスの破損を確認し、ステータスを返す。","when":"予期しないエラーの発生時、または破損が疑われるときに。","caution":"確認中は表に読み取りロックが取得される。破損が見つかった場合、InnoDBは通常ダンプ/リストアで修復する。REPAIR TABLEはMyISAM/Archiveなどのエンジンでのみ機能する。","tags":["check","integrity","corruption","maintenance"]},{"id":"set-global-persist","task":"グローバル変数を変更して永続化","category":"パラメータ","command":"SET PERSIST innodb_buffer_pool_size = 4294967296;","what":"変数を稼働中のサーバーに設定すると同時に、再起動後も維持されるよう永続化する(mysqld-auto.cnf)。","when":"再起動せずにサーバー変数を恒久的に変更するため。","caution":"SET PERSISTはMySQL 8.0以降の機能で、MariaDBはサポートしない(MariaDBではmy.cnfを編集して再起動する)。実行時のみの変更にはSET GLOBALを使用する。再起動時のみ有効な変数にはSET PERSIST_ONLYが必要。","since":"MySQL 8.0","note":"SET PERSISTはMySQL 8.0で導入され、変数をmysqld-auto.cnfに書き込んで永続化する。以前は(およびMariaDBでは)永続化にmy.cnfの手動編集と再起動が必要だった。","tags":["set-persist","global","variable","parameter"]},{"id":"show-variables","task":"変数の現在値を表示","category":"パラメータ","command":"SHOW VARIABLES LIKE 'innodb_buffer_pool_size';","what":"指定したサーバー変数(またはパターンに一致する変数)の有効値を表示する。","when":"パラメータの実行時の値を確認するため。","caution":"セッション値ではなくグローバル値にはSHOW GLOBAL VARIABLESを使用する。値の設定元(ファイル、コマンドライン、persist)を確認するには: SELECT * FROM performance_schema.variables_info WHERE variable_name = 'innodb_buffer_pool_size';","tags":["show-variables","parameter","current-value","config"]},{"id":"flush-privileges","task":"権限表をリロード(FLUSH PRIVILEGES)","category":"パラメータ","command":"FLUSH PRIVILEGES;","what":"mysql.userなどの権限表を直接変更した後、メモリに再読込みする。","when":"権限表に手動のINSERT/UPDATEで行った変更を有効にするため。","caution":"GRANT/REVOKE/CREATE USERは権限を直ちに適用するため、その後のFLUSH PRIVILEGESは不要。権限表を直接変更した場合にのみ必要。","tags":["flush-privileges","grants","privileges","reload"]},{"id":"setup-replica","task":"レプリカを設定(CHANGE REPLICATION SOURCE)","category":"レプリケーション","command":"CHANGE REPLICATION SOURCE TO SOURCE_HOST='source_host', SOURCE_PORT=3306, SOURCE_USER='replicator', SOURCE_PASSWORD='secret', SOURCE_AUTO_POSITION=1;","what":"GTIDベースの自動ポジショニングを使用して、指定したソースに追従するレプリカとしてこのサーバーを構成する。","when":"新しいレプリカの設定、またはレプリケーションソースの変更に。","caution":"これはMySQL 8.0.23以降の用語。古いバージョンではCHANGE MASTER TO ... MASTER_HOSTを使用する(8.0.23–8.3では別名、8.4で削除)。SOURCE_AUTO_POSITION=1にはGTIDの有効化(gtid_mode=ON)が必要。そうでない場合はSOURCE_LOG_FILEとSOURCE_LOG_POSを指定する必要がある。コマンド実行前にレプリケーションを停止する必要がある。レプリケーションユーザーが8.0以降のデフォルトであるcaching_sha2_passwordで作成されている場合、接続にはTLSが必要: SOURCE_SSL=1を追加するか、TLSなしの場合はGET_SOURCE_PUBLIC_KEY=1を設定する。そうしないとI/Oスレッドはエラー2061で接続に失敗する。","since":"MySQL 8.0.23","note":"CHANGE REPLICATION SOURCE TO(SOURCE_HOSTなど)はMySQL 8.0.23で導入された。以前はCHANGE MASTER TO ... MASTER_HOST / MASTER_AUTO_POSITIONが使用されていた。","tags":["replication","change-source","replica","setup"]},{"id":"start-stop-replica","task":"レプリカを開始/停止","category":"レプリケーション","command":"STOP REPLICA; START REPLICA;","what":"レプリケーションのI/OスレッドとSQLスレッドを停止して再開する。","when":"メンテナンス、構成変更、レプリケーションエラーの修正のために。","caution":"これはMySQL 8.0.22以降の用語。古いバージョンではSTOP SLAVE / START SLAVEを使用する。SQLスレッドのみの場合: STOP REPLICA SQL_THREAD; STOP REPLICAの後にCHANGE REPLICATION SOURCEを実行できる。","since":"MySQL 8.0.22","note":"START REPLICA / STOP REPLICAはMySQL 8.0.22で導入された。以前はSTART SLAVE / STOP SLAVEが使用されていた(旧構文は8.0.22–8.3では別名として動作し、8.4で削除された)。","tags":["replication","start","stop","replica"]},{"id":"replica-status","task":"レプリカの状態を表示(SHOW REPLICA STATUS)","category":"レプリケーション","command":"SHOW REPLICA STATUS\\G","what":"レプリカのソースへの接続、スレッドの状態、遅延、エラーを詳細に表示する。","when":"レプリケーションが正常か、どれだけ遅れているかを確認するため。","caution":"これはMySQL 8.0.22以降の用語。古いバージョンではSHOW SLAVE STATUSを使用する(8.0.22–8.3では別名、8.4で削除)。主要フィールド: Replica_IO_RunningとReplica_SQL_Runningは'Yes'である必要があり、Seconds_Behind_Sourceは遅延を、Last_Errorはエラーを示す。","since":"MySQL 8.0.22","note":"SHOW REPLICA STATUSはMySQL 8.0.22で導入された。以前はSHOW SLAVE STATUSが使用され、フィールド名はSlave_IO_Running / Seconds_Behind_Masterのようになっていた。","tags":["replication","status","replica","lag"]},{"id":"skip-gtid-transaction","task":"壊れたトランザクションをスキップ(GTID)","category":"レプリケーション","command":"STOP REPLICA; SET GTID_NEXT='aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee:15'; BEGIN; COMMIT; SET GTID_NEXT='AUTOMATIC'; START REPLICA;","what":"指定したGTIDに対して空のトランザクションをコミットし、そのトランザクションを「適用済み」として扱わせ、レプリケーションを先に進める。","when":"レプリカ上の重複/適用不能なイベントがレプリケーションを停止させたときに、そのイベントをスキップするため。","caution":"トランザクションをスキップすると、レプリカとソースの間にデータの不整合が生じる。スキップするイベントの影響がわかっている場合にのみ使用する。GTIDの値はSHOW REPLICA STATUSのLast_Error / Retrieved_Gtid_Setから取得する。GTIDが無効な場合は、SET GLOBAL sql_replica_skip_counter = 1;を使用する(8.0.26以降。以前はsql_slave_skip_counterで、8.0.26以降は非推奨の別名)。","tags":["replication","gtid","skip","recovery"]},{"id":"kill-query-connection","task":"クエリまたは接続を強制終了(KILL)","category":"セッション","command":"KILL QUERY 4567;","what":"指定した接続IDで現在実行中のクエリを、接続を閉じずに終了する。","when":"長時間実行/停止したクエリを止めるため。","caution":"接続(セッション)全体を閉じるには: KILL CONNECTION 4567;(または単にKILL 4567)。実行中の書き込みトランザクションを強制終了するとロールバックされ、大きな表では長時間かかる場合がある。","tags":["kill","query","connection","session"]},{"id":"process-list","task":"プロセスリストを表示","category":"セッション","command":"SELECT id, user, host, db, command, time, state, LEFT(info, 100) AS query FROM performance_schema.processlist WHERE command <> 'Sleep' ORDER BY time DESC;","what":"idle以外のすべての接続、実行中のクエリ、経過時間を一覧表示する。","when":"アクティブなセッションと長時間実行のクエリを診断するため。","caution":"ショートカット: SHOW FULL PROCESSLIST; performance_schema.processlistはすべての列を提供し、WHEREでフィルタできる。time列は秒単位。","tags":["processlist","session","activity","performance-schema"]},{"id":"blocking-locks","task":"ブロックしているロックを表示(data_lock_waits)","category":"セッション","command":"SELECT r.trx_id AS waiting_trx, r.trx_mysql_thread_id AS waiting_thread, LEFT(r.trx_query,80) AS waiting_query, b.trx_id AS blocking_trx, b.trx_mysql_thread_id AS blocking_thread, LEFT(b.trx_query,80) AS blocking_query FROM performance_schema.data_lock_waits w JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_engine_transaction_id JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_engine_transaction_id;","what":"どのトランザクションがどのトランザクションにブロックされているかを、関連するクエリとスレッドIDとともに表示する。","when":"ロック待機とデッドロックによる性能低下を診断するため。","caution":"performance_schema.data_lock_waitsはMySQL 8.0で導入された。古いバージョンではinformation_schema.innodb_lock_waitsを使用する。ブロックしているスレッドを停止するにはKILL blocking_thread;を使用する。","since":"MySQL 8.0","note":"performance_schema.data_lock_waitsはMySQL 8.0で導入された。MySQL 5.7以前では、同じ情報にinformation_schema.innodb_lock_waitsが使用されていた。","tags":["blocking","lock","data-lock-waits","deadlock"]}]},"recipes/mysql-ext.json":{"engineId":"mysql","engine":"MySQL","order":2,"recipes":[{"id":"replica-applier-health","task":"レプリカの遅延とアプライアワーカーのエラーを監視(performance_schema)","category":"レプリケーション","command":"-- Receiver (I/O) thread: connection state and last error\nSELECT CHANNEL_NAME, SERVICE_STATE, LAST_ERROR_NUMBER,\n       LEFT(LAST_ERROR_MESSAGE, 100) AS last_error,\n       LAST_QUEUED_TRANSACTION, LAST_HEARTBEAT_TIMESTAMP\nFROM performance_schema.replication_connection_status;\n\n-- Applier workers: error, applied GTID and real lag\nSELECT CHANNEL_NAME, WORKER_ID, SERVICE_STATE, LAST_ERROR_NUMBER,\n       LEFT(LAST_ERROR_MESSAGE, 120) AS last_error,\n       LAST_APPLIED_TRANSACTION,\n       APPLYING_TRANSACTION,\n       IF(APPLYING_TRANSACTION = '', 0,\n          TIMESTAMPDIFF(SECOND, APPLYING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP, NOW(6))) AS current_lag_sec,\n       TIMESTAMPDIFF(MICROSECOND, LAST_APPLIED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP,\n                     LAST_APPLIED_TRANSACTION_END_APPLY_TIMESTAMP) / 1000000 AS last_trx_lag_sec\nFROM performance_schema.replication_applier_status_by_worker\nORDER BY CHANNEL_NAME, WORKER_ID;","what":"SHOW REPLICA STATUSが1行に要約する内容をチャネルごと、ワーカーごとに分解する: レシーバスレッドの状態、各ワーカーの最後のエラー、適用済み/適用中のGTID、元のコミットタイムスタンプから計算した実際の遅延。","when":"Seconds_Behind_Sourceが信頼できないように見えるとき(0と大きな値の間を行き来する、NULL)、マルチスレッドレプリカでどのワーカーが停止しているかを特定するため、正確な遅延メトリックを監視に取り込むために。","caution":"current_lag_secはトランザクションの適用中のみ意味を持ち、アイドル状態のレプリカは0を返す。レシーバも遅れているかを確認するには、LAST_QUEUED_TRANSACTIONをソースのgtid_executedと比較する。元のコミットタイムスタンプはソースの時計に基づくため、サーバー間の時刻のずれ(NTP)は結果を歪める。Seconds_Behind_Sourceは大きなトランザクションの開始時はゼロ付近にとどまり、終了時に跳ね上がる。長いトランザクションはこのメトリックを誤解を招くものにする。","note":"ORIGINAL_COMMIT_TIMESTAMP / END_APPLY_TIMESTAMP列は8.0.2で導入され、チェーン全体(ソース → 中間 → レプリカ)をカバーする。5.7にはSeconds_Behind_Masterのみがある。","since":"MySQL 8.0","tags":["replication","lag","applier","worker","performance_schema","delay"]},{"id":"replica-parallel-applier","task":"マルチスレッドレプリカをチューニング(replica_parallel_workers)","category":"レプリケーション","command":"-- Replica: stop the applier, set worker count and commit order\nSTOP REPLICA SQL_THREAD;\nSET PERSIST replica_parallel_workers = 8;\nSET PERSIST replica_preserve_commit_order = ON;\nSTART REPLICA SQL_THREAD;\nSELECT COUNT(*) AS workers FROM performance_schema.replication_applier_status_by_worker;\n\n-- Source (8.0 only): switch dependency tracking to WRITESET (default in 8.4, variable removed)\nSET PERSIST binlog_transaction_dependency_tracking = WRITESET;","what":"レプリカでトランザクションを並列に適用するワーカー数を設定する。replica_preserve_commit_orderはコミット順序をソースと同一に保つ。ソースでのWRITESET依存関係追跡により、異なる行に触れるトランザクションは、ソースで逐次コミットされていても並列に適用できる。","when":"レプリカがソースの書き込み速度に追いつけず、アプライアが事実上シングルスレッドのまま遅延が蓄積するときに。","caution":"新しいワーカー数はアプライアの再起動時に有効になる。CPUコア数を超えるワーカーは調整のオーバーヘッドを加える。8–16の範囲から始め、遅延とワーカーのエラーを監視する。単一の巨大なトランザクションや、PKのない表への大量のDMLは並列化できず、通常これが持続的な遅延の本当の原因である。replica_preserve_commit_order=OFFはより高い並列性をもたらすが、レプリカで一時的に順序の異なるコミットを許す。読み取りを提供するレプリカではONのままにする。","note":"8.0.27以降、デフォルトはreplica_parallel_workers=4、replica_parallel_type=LOGICAL_CLOCK、replica_preserve_commit_order=ON。8.0.26より前は、変数名はslave_parallel_workers / slave_preserve_commit_orderだった。binlog_transaction_dependency_trackingは8.0.35で非推奨となり8.4で削除された。8.4ではWRITESETの動作がデフォルト。","since":"MySQL 8.0.26","tags":["replication","parallel","replica_parallel_workers","writeset","lag","mta"]},{"id":"replica-fix-row-conflict","task":"壊れたレプリカを修復: 1062 / 1032の行の競合","category":"レプリケーション","command":"-- 1) Failing worker, error and GTID\nSELECT WORKER_ID, LAST_ERROR_NUMBER, LEFT(LAST_ERROR_MESSAGE, 250) AS last_error, APPLYING_TRANSACTION\nFROM performance_schema.replication_applier_status_by_worker\nWHERE LAST_ERROR_NUMBER <> 0;\n\n-- 2) Shell: decode the row images of that transaction from the relay log\nmysqlbinlog --base64-output=DECODE-ROWS -vv --include-gtids='af6bc361-c353-11f1-8f12-f69e63ad6c0e:11' /var/lib/mysql/db2-relay-bin.0* | grep '^###'\n\n-- 3a) 1062 Duplicate entry: delete the extra row on the replica without binlogging\nSET SESSION sql_log_bin = 0;\nDELETE FROM shop.orders WHERE id = 20001;\n-- 3b) 1032 Can't find record: insert the missing row from the WHERE (before image) values\nINSERT INTO shop.orders (id, cust, amount, note, created) VALUES (6, 6, 9.00, 'n6', '2026-10-08 20:09:44');\nSET SESSION sql_log_bin = 1;\n\n-- 4) Start the applier and verify\nSTART REPLICA SQL_THREAD;\nSELECT SERVICE_STATE, LAST_ERROR_NUMBER FROM performance_schema.replication_applier_status_by_coordinator;","what":"行ベースレプリケーションで最もよくある2つの停止(1062 重複キー、1032 行が見つからない)を、トランザクションをスキップせず、レプリカの行をソースが期待する状態にすることで修正する。データの整合性は保たれる。","when":"Replica_SQL_Running = Noでエラー1062 / 1032のときに。空のトランザクションでGTIDをスキップする代わりの適切な修復として。","caution":"レプリカでの修正はsql_log_bin=0で実行する必要がある。そうしないと誤ったGTID(errant GTID)が作成され、フェイルオーバー時に問題になる。super_read_only=ONの場合は一時的に無効にし、その後再度有効にする。変更前イメージの値はbinlog_row_image=FULLを前提としている。MINIMALではPKのみが記録されるため、行の残りはソースから読み取る必要がある。表で1つの競合があれば通常は他にもある。修復後はpt-table-checksumで表をソースと比較する。リレーログのパス: SELECT @@relay_log_basename;","note":"replica_exec_mode=IDEMPOTENTはこれらのエラーを黙って無視する。NDBや特殊なケース向けに設計されており、常時有効にしたままにしてはならない。トランザクションを本当にスキップする必要がある場合は、skip-gtid-transactionレシピを参照する。","since":"MySQL 8.0.22","tags":["replication","1062","1032","mysqlbinlog","relay log","broken replica"]},{"id":"gtid-errant-transactions","task":"誤ったGTIDトランザクション(errant GTID)を特定して無害化","category":"レプリケーション","command":"-- 1) On the source: get gtid_executed\nSELECT @@GLOBAL.gtid_executed;\n\n-- 2) On the replica: GTIDs missing on the source (empty result = clean)\nSELECT GTID_SUBTRACT(@@GLOBAL.gtid_executed,\n       'af6bc361-c353-11f1-8f12-f69e63ad6c0e:1-13') AS errant_gtids;\n\n-- 3) If the content is harmless: commit an empty transaction per errant GTID on the source\nSET GTID_NEXT = 'b030e5a6-c353-11f1-a887-523817ec642a:1'; BEGIN; COMMIT;\nSET GTID_NEXT = 'b030e5a6-c353-11f1-a887-523817ec642a:2'; BEGIN; COMMIT;\nSET GTID_NEXT = 'AUTOMATIC';","what":"ソースに対応するものがなくレプリカで直接実行されたトランザクション(errant)をGTIDセットの差分で検出し、ソースで空のトランザクションとしてマークすることで、トポロジ全体のGTIDセットを揃える。","when":"フェイルオーバー/スイッチオーバー前の定期チェックとして。Orchestrator や MySQL Shellが誤ったGTIDのためにレプリカの昇格を拒否するとき、またはレプリカが新しいソースへの接続時に1236で失敗するときに。","caution":"まず、誤ったトランザクションが何をしたかをレプリカのbinlogから確認する(mysqlbinlog --include-gtids=...)。データを変更していた場合、空のトランザクションはGTIDを取り繕うだけでデータの差異は残る。レプリカを再構築する(CLONE)か、データを手動で揃える。ソースでコミットした空のトランザクションはすべてのレプリカに伝播するが、それは意図どおり。再発防止のため、レプリカではsuper_read_only=ONを維持する。","note":"レプリカが昇格されると、他のレプリカはこれらのGTIDをそのレプリカに要求する。そのbinlogがパージされていると、レプリケーションはエラー1236で停止する。そのため、誤ったGTIDはフェイルオーバーまで表面化しないリスクである。","since":"MySQL 5.6","tags":["gtid","errant","gtid_subtract","failover","replication","empty transaction"]},{"id":"replica-rebuild-clone","task":"CLONEプラグインでレプリカを一から再構築","category":"レプリケーション","command":"-- Donor (healthy replica or source)\nINSTALL PLUGIN clone SONAME 'mysql_clone.so';\nCREATE USER 'clone_donor'@'%' IDENTIFIED BY 'Cl0ne#Donor';\nGRANT BACKUP_ADMIN ON *.* TO 'clone_donor'@'%';\n\n-- Recipient (replica to rebuild; its data is replaced)\nINSTALL PLUGIN clone SONAME 'mysql_clone.so';\nSET GLOBAL clone_valid_donor_list = 'db1:3306';\nCLONE INSTANCE FROM 'clone_donor'@'db1':3306 IDENTIFIED BY 'Cl0ne#Donor';\n\n-- After the restart: verify and start replication\nSELECT STATE, ERROR_NO, BINLOG_FILE, BINLOG_POSITION, GTID_EXECUTED FROM performance_schema.clone_status;\nSELECT STAGE, STATE, ROUND(DATA / 1024 / 1024) AS data_mb FROM performance_schema.clone_progress;\nCHANGE REPLICATION SOURCE TO SOURCE_HOST = 'db1', SOURCE_PORT = 3306, SOURCE_USER = 'repl', SOURCE_PASSWORD = 'Repl#2024', SOURCE_AUTO_POSITION = 1, SOURCE_SSL = 1;\nSTART REPLICA;","what":"ドナーのInnoDBデータをネットワーク経由で物理的にコピーし、受信側を再起動してGTIDの状態を引き継ぐ。個別のバックアップ、転送、リストアの手順なしで一貫性のあるレプリカを作成する。","when":"破損したレプリカ、誤ったGTIDを持つレプリカ、binlogがパージされるほど遅れたレプリカの再構築、または新しいレプリカの追加に。","caution":"受信側のすべてのデータ(ユーザーを含む)はドナーのコピーで置き換えられ、rootパスワードはドナーのものになる。ドナーと受信側は同じリリースシリーズ、プラットフォーム、プラグインセットである必要がある(8.0.37より前は完全に同じポイントリリースが必要だった)。コマンドを実行する受信側のユーザーにはCLONE_ADMINが必要。クローン完了時にmysqldは自ら再起動する。systemd / mysqld_safeなどのスーパーバイザがない場合は、3707 'Restart server failed (mysqld is not managed by supervisor process)'を返す。これは失敗ではない。クローンは完了しているので、サーバーを手動で起動する。ドナーには大きなIO/ネットワーク負荷がかかるため、clone_max_concurrencyとclone_max_data_bandwidthで制限する。GTIDが無効な場合は、clone_statusのBINLOG_FILE / BINLOG_POSITIONをSOURCE_LOG_FILE / SOURCE_LOG_POSとして使用する。","note":"クローンされるのはInnoDBのデータのみで、MyISAMとCSVの表は空で届く。InnoDB Clusterでは、addInstance(..., {recoveryMethod: 'clone'})が同じ仕組みを使用する。","since":"MySQL 8.0.17","tags":["clone","rebuild","replica","provisioning","gtid","reseed"]},{"id":"delayed-replica-recover","task":"遅延レプリカで誤ったDROP / DELETEから復旧(SOURCE_DELAY + UNTIL)","category":"レプリケーション","command":"-- Setup: the replica applies events one hour behind\nSTOP REPLICA;\nCHANGE REPLICATION SOURCE TO SOURCE_DELAY = 3600;\nSTART REPLICA;\n\n-- During the incident: stop the applier (the receiver keeps fetching binlogs)\nSTOP REPLICA SQL_THREAD;\n\n-- Find the bad transaction's GTID in the source binlog, apply up to just before it\nCHANGE REPLICATION SOURCE TO SOURCE_DELAY = 0;\nSTART REPLICA SQL_THREAD UNTIL SQL_BEFORE_GTIDS = 'af6bc361-c353-11f1-8f12-f69e63ad6c0e:17';\nSELECT SERVICE_STATE FROM performance_schema.replication_applier_status_by_coordinator;","what":"レプリカに一定時間遅れてイベントを適用させる。誤ったDROP / DELETEがソースで実行された場合、そのトランザクションの直前までレプリカを進め、失われたデータをそこから回復する。","when":"バックアップからのリストアに数時間かかる大規模データベースで、人為的ミスに対する迅速な復旧層として。","caution":"コーディネータがOFFのとき、データは誤った操作の直前の状態にある。影響を受けた表をmysqldumpでダンプし、ソースにロードする。その後、レプリカを遅延モードに戻す。レプリカも誤ったトランザクションを適用すると、ここでもデータは失われる。遅延レプリカはフェイルオーバー候補にしてはならない(Orchestrator / Router / ProxySQLで除外する)。リレーログは遅延期間全体にわたって蓄積するため、それに応じてディスクをサイジングする。","note":"8.0.23より前はCHANGE MASTER TO MASTER_DELAYを使用する。遅延は直接のソースでのコミットから測定されるため、チェーン内の遅延中間レプリカの遅延は加算される。SQL_BEFORE_GTIDSは指定したGTIDの前で停止し、SQL_AFTER_GTIDSはそれも適用する。8.2より前(8.0を含む)では、マルチスレッドアプライアでSQL_AFTER_GTIDSを使用すると警告が発生し、レプリカはシングルスレッドモードに切り替わる。","since":"MySQL 8.0.23","tags":["delayed replica","source_delay","until","sql_before_gtids","recovery","drop table"]},{"id":"mysqldump-consistent","task":"mysqldumpでGTID情報付きの一貫性のある論理バックアップを取得","category":"バックアップとPITR","command":"mysqldump -h db1 -u backup -p \\\n  --single-transaction --source-data=2 --set-gtid-purged=ON \\\n  --routines --events --triggers --hex-blob \\\n  --all-databases | gzip > /backup/full_$(date +%F_%H%M).sql.gz\n\n# Restore: GTID sets must not overlap on the target\nzcat /backup/full_2026-10-08_0200.sql.gz | mysql -h db2 -u root -p","what":"単一の一貫性のあるスナップショット内でInnoDB表をダンプし、先頭にbinlogファイル/位置(コメントとして)とSET @@GLOBAL.GTID_PURGED文を書き込む。これにより、ダンプはレプリカの初期化やbinlogベースのPITRの開始点として使用できる。","when":"数十GBまでのデータベース、スキーマ/表の移動、バージョン間の論理移行に。","caution":"--single-transactionはInnoDBに対してのみ一貫性がある。MyISAM表は不整合な状態で出力される。ダンプ中に表でDDL(ALTER / RENAME / TRUNCATE)が実行されると、ダンプは失敗するかその表が欠落する。--source-data / --set-gtid-purgedは開始時に短時間のグローバル読み取りロックを取得する(RELOAD権限が必要)。その時点で長いクエリが実行中だと、ロック待機の間すべての書き込みが停止する。部分ダンプ(--databases)でもすべてのGTIDが書き込まれるため、一部を別サーバーに移す場合は--set-gtid-purged=OFFを使用する。ダンプはシングルスレッドであり、大規模データにはMySQL ShellのダンプまたはXtraBackupを推奨する。","note":"--source-dataは8.0.26で--master-dataを置き換えた。mysqlpumpは8.0.34で非推奨となり8.4で削除された。パラレル論理バックアップにはMySQL Shellのutil.dumpInstanceを使用する。","since":"MySQL 8.0.26","tags":["mysqldump","backup","single-transaction","gtid","logical backup","dump"]},{"id":"mysqlsh-dump-load","task":"MySQL Shellによるパラレルダンプ/ロード(util.dumpInstance、loadDump)","category":"バックアップとPITR","command":"# Parallel, zstd-compressed, consistent instance dump\nmysqlsh backup@db1:3306 -- util dump-instance /backup/dump_20261008 --threads=8 --compression=zstd --consistent=true\n# Single schema\nmysqlsh backup@db1:3306 -- util dump-schemas shop --outputUrl=/backup/shop_20261008 --threads=8\n\n# Load: local_infile must be temporarily ON on the target\nmysql -h db2 -u root -p -e \"SET GLOBAL local_infile = ON\"\nmysqlsh root@db2:3306 -- util load-dump /backup/dump_20261008 --threads=8 --skipBinlog=false\nmysql -h db2 -u root -p -e \"SET GLOBAL local_infile = OFF\"","what":"表をチャンクに分割し、多数のスレッドでダンプ/ロードする。ダンプとリストアのどちらもmysqldumpより何倍も高速。ダンプディレクトリはGTIDとbinlogの座標を@.jsonに格納する。","when":"数百GBの論理バックアップ、アップグレード時の論理移行、オンプレミス → クラウド(RDS、HeatWave)への移行に。","caution":"--consistent=trueは短時間のグローバル読み取りロック/バックアップロックを取得する。長いクエリが実行中だと書き込みが待機する。loadDumpはLOAD DATA LOCALを使用するため、ターゲットにはlocal_infile=ONが必要で、その後は無効にすべきである。中断したロードは停止した箇所から再開する(進捗ファイル)。最初からやり直すには--resetProgressを使用する。ユーザーアカウントはデフォルトではロードされない(--loadUsers=true)。--skipBinlog=trueはロード中のbinlog記録を無効にする。ターゲットにレプリカがある場合はfalseのままにする。","note":"これは物理バックアップではない。PITRには、ダンプの@.json内のgtidExecutedの値からbinlogを適用する。ocimds / compatibilityオプションは、HeatWave / RDSの制約に従うダンプを生成する。","since":"MySQL Shell 8.0.21","tags":["mysqlsh","dumpinstance","loaddump","parallel","logical backup","migration"]},{"id":"xtrabackup-full-incremental","task":"XtraBackupによる全体 + 増分の物理バックアップとリストア","category":"バックアップとPITR","command":"# Full backup\nxtrabackup --backup --host=127.0.0.1 --user=bkp --password='Bkp#2024' --target-dir=/backup/full --parallel=4\n# Incremental (based on the previous backup)\nxtrabackup --backup --host=127.0.0.1 --user=bkp --password='Bkp#2024' --target-dir=/backup/inc1 --incremental-basedir=/backup/full\n\n# Prepare: full and intermediate incrementals with --apply-log-only, final step without it\nxtrabackup --prepare --apply-log-only --target-dir=/backup/full\nxtrabackup --prepare --apply-log-only --target-dir=/backup/full --incremental-dir=/backup/inc1\nxtrabackup --prepare --target-dir=/backup/full\n\n# Restore: mysqld stopped and datadir empty\nsystemctl stop mysqld\nxtrabackup --copy-back --target-dir=/backup/full --datadir=/var/lib/mysql\nchown -R mysql:mysql /var/lib/mysql\nsystemctl start mysqld\ncat /backup/full/xtrabackup_binlog_info","what":"サーバーの稼働中にInnoDBファイルとREDOログをコピーしてホット物理バックアップを取得する。増分バックアップには前回のバックアップ以降に変更されたページのみが含まれる。prepareの手順でREDOを適用し、バックアップを一貫した状態にする。","when":"高速なリストア(論理より何倍も高速)が必要な大規模データベース、レプリカの初期化、日次全体 + 毎時増分の戦略に。","caution":"XtraBackupのバージョンはサーバーのリリースシリーズと一致する必要がある(8.0サーバー → XtraBackup 8.0、8.4 → 8.4)。サーバーがXtraBackupのビルドより新しいREDO/データディクショナリ形式を使用している場合、バックアップは拒否される。prepareしていないバックアップは一貫性がない。中間の手順で--apply-log-onlyを忘れると、以降の増分が使用できなくなる。リストアにはdatadirが空である必要がある。--move-backはディスクを節約するがバックアップを消費する。バックアップユーザー: BACKUP_ADMIN、PROCESS、RELOAD、LOCK TABLES、REPLICATION CLIENT、およびperformance_schema.log_status、keyring_component_status、replication_group_membersに対するSELECT。","note":"xtrabackup_binlog_infoはバックアップのbinlogファイル/位置とGTIDセットを保持する。PITRはその時点からbinlogを再生する。別のホストへストリーミングするには--stream=xbstream | ssh host 'xbstream -x -C /backup'を使用する。","since":"XtraBackup 8.0","tags":["xtrabackup","physical backup","incremental","prepare","restore","percona"]},{"id":"pitr-binlog-replay","task":"binlogによるポイントインタイムリカバリ: 誤ったトランザクションを特定してスキップ","category":"バックアップとPITR","command":"# 1) Find the bad event's GTID and position (narrow by time range)\nmysqlbinlog --base64-output=DECODE-ROWS -vv --start-datetime='2026-10-08 20:00:00' --stop-datetime='2026-10-08 20:30:00' /var/lib/mysql/binlog.000003 | grep -B12 -iE '^(DROP|TRUNCATE)' | grep -E 'GTID_NEXT|^# at|^#[0-9]{6}|^DROP|^TRUNCATE'\n\n# 2) Restore the backup on a separate server (the dump sets GTID_PURGED)\nzcat /backup/full_2026-10-08_0200.sql.gz | mysql -h restore-db -u root -p\n\n# 3a) Replay all binlogs skipping only the bad transaction\nmysqlbinlog --exclude-gtids='af6bc361-c353-11f1-8f12-f69e63ad6c0e:23' /binlogs/binlog.000003 /binlogs/binlog.000004 | mysql -h restore-db -u root -p\n# 3b) Or stop right before the bad event's GTID event\nmysqlbinlog --stop-position=537205 /binlogs/binlog.000003 | mysql -h restore-db -u root -p","what":"バックアップのリストア後、binlogを順に再生してデータベースを目的の時点まで進める。GTIDが有効な場合、バックアップに含まれるトランザクションは自動的にスキップされる。--exclude-gtidsは誤った操作のみを除外し、その後のすべての変更を保持する。","when":"誤ったDROP / DELETE / UPDATEの後、バックアップとインシデントの間に行われた変更を失わずに復旧するため。","caution":"本番ではなく別のサーバーでリストアし、検証してから影響を受けた表のみを移す。--start/--stop-datetimeはmysqlbinlogを実行するマシンのタイムゾーンで解釈される。--stop-positionは最後に指定したファイルにのみ適用されるため、複数ファイルの場合は前のファイルを別のコマンドで完全に再生する。--exclude-gtidsは独立した操作に対してのみ安全。後続のトランザクションが削除された表に書き込む場合、それらも失敗する。必要なbinlogがソースでパージされていてはならない。binlogの保存期間は少なくとも1回のバックアップ間隔より長くする。","note":"mysqlbinlogとmysqlを単一のパイプで、すべてのファイルを1つのコマンドで実行する。ファイルを1つずつ再生すると、ファイルをまたぐ一時表やトランザクションが壊れる。非常に大きなbinlogセットでは、リストアサーバーにbinlogをリレーログとして配置し、(パラレル)SQLスレッドで適用する方法もある。","since":"MySQL 8.0","tags":["pitr","mysqlbinlog","binlog","point in time","exclude-gtids","recovery"]},{"id":"innodb-cluster-status","task":"InnoDB Cluster / Group Replicationの健全性を確認","category":"InnoDB Cluster","command":"# Shell: topology, primary, fault tolerance, lag\nmysqlsh icadmin@db1:3306 -- cluster status --extended=1\nmysqlsh icadmin@db1:3306 -- cluster list-routers\n\n-- SQL: group members and queues from any member\nSELECT m.MEMBER_HOST, m.MEMBER_PORT, m.MEMBER_STATE, m.MEMBER_ROLE, m.MEMBER_VERSION,\n       s.COUNT_TRANSACTIONS_IN_QUEUE AS certify_queue,\n       s.COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE AS apply_queue,\n       s.COUNT_CONFLICTS_DETECTED AS conflicts\nFROM performance_schema.replication_group_members m\nJOIN performance_schema.replication_group_member_stats s ON s.MEMBER_ID = m.MEMBER_ID\nORDER BY m.MEMBER_ROLE, m.MEMBER_HOST;","what":"クラスタ全体の状態(OK / OK_NO_TOLERANCE / NO_QUORUM)、プライマリ、各メンバーの状態、認証/アプライアキューを表示する。キューからどのメンバーが遅れているか、フロー制御のリスクがわかる。","when":"すべての介入の前後に。アラート時、書き込みの遅延時、メンバーがRECOVERING / ERROR / UNREACHABLEを示すときに。","caution":"statusTextは'can tolerate up to ONE failure'(3メンバー)となっているべきである。NO_QUORUMでは書き込みが停止する。forceQuorumUsingPartitionOfは、もう一方のパーティションが停止していると確信できる場合にのみ使用する。そうでないとスプリットブレインが発生する。apply_queueが増え続けるメンバーはフロー制御を発動させ、プライマリの書き込みを遅くする。RECOVERINGが長い場合はクローン/増分リカバリが実行中。ERRORの場合はエラーログを確認し、cluster.rejoinInstance()を試す。パスワード内の特殊文字(#、@)はURI内でURLエンコードする必要がある(# → %23)。","note":"MEMBER_COMMUNICATION_STACKは8.0.27で導入された。MYSQLスタックは、通常のTLSとユーザー認証によりGRのトラフィックを3306経由で転送する(XCOMは別のポート、通常33061を使用する)。8.4ではgroup_replication_consistencyのデフォルトはBEFORE_ON_PRIMARY_FAILOVER、exit_state_actionのデフォルトはOFFLINE_MODE。","since":"MySQL 8.0","tags":["innodb cluster","group replication","mysqlsh","status","flow control","quorum"]},{"id":"innodb-cluster-switch-primary","task":"InnoDB Clusterでの計画的なプライマリスイッチオーバー","category":"InnoDB Cluster","command":"# Shell: planned switchover\nmysqlsh icadmin@db1:3306 -- cluster set-primary-instance db2:3306\n\n-- SQL alternative: target member's server_uuid, 30 s timeout for open transactions\nSELECT MEMBER_HOST, MEMBER_ID, MEMBER_ROLE FROM performance_schema.replication_group_members;\nSELECT group_replication_set_as_primary('3f06e651-c356-11f1-8aac-927a9034ef99', 30);","what":"シングルプライマリモードで、プライマリのロールを制御された方法で別のメンバーに移す。旧プライマリはsuper_read_onlyになり、新プライマリはバックログを適用してから書き込みを受け付ける。MySQL Routerは新しいプライマリを自動的に認識する。","when":"プライマリのメンテナンス、OSパッチ適用、アップグレードの前、ハードウェアの移行に。","caution":"旧プライマリのオープン中のトランザクションは、タイムアウトが経過すると強制終了される。タイムアウトなしでは切り替えはそれらを待機し、時間が長くなる。アプリケーションがRouter経由で接続していない場合は、自分で接続先を変更する必要がある。BEFORE_ON_PRIMARY_FAILOVERでは、新プライマリがバックログを処理し終えるまで書き込みは待機する。先にcluster statusでapply_queueが空であることを確認する。InnoDB ClusterではShellのコマンドを推奨する。メタデータとの整合性が保たれる。","note":"group_replication_set_as_primaryは8.0.13で導入され、timeoutパラメータは8.0.29で追加された。計画外のフェイルオーバーでは、GRが新しいプライマリを自ら選出する(group_replication_member_weightで優先度を設定する)。","since":"MySQL 8.0.13","tags":["innodb cluster","switchover","primary","group replication","set_as_primary","maintenance"]},{"id":"innodb-cluster-reboot-outage","task":"完全停止後にクラスタを復旧(rebootClusterFromCompleteOutage)","category":"InnoDB Cluster","command":"# Are all members OFFLINE? (on every node)\nmysql -h db1 -u icadmin -p -e \"SELECT MEMBER_HOST, MEMBER_STATE FROM performance_schema.replication_group_members\"\n# Dry run first: shows the most up-to-date member and the planned steps\nmysqlsh icadmin@db1:3306 --js -e \"dba.rebootClusterFromCompleteOutage('prodCluster', {dryRun: true})\"\nmysqlsh icadmin@db1:3306 --js -e \"dba.rebootClusterFromCompleteOutage('prodCluster')\"\nmysqlsh icadmin@db1:3306 -- cluster status","what":"停電や全ノードの同時再起動の後、クォーラムが存在しない場合にグループを再ブートストラップする。最も大きいGTIDセットを持つメンバーを選び、他のメンバーを再参加させる。","when":"cluster statusが'Cluster is not reachable'を報告し、すべてのメンバーがOFFLINEを示すときに。","caution":"すべてのメンバーがOFFLINEの場合にのみ使用する。1つのメンバーでもONLINEであればグループは生きており、他のメンバーはrejoinInstanceで参加する。実行前にすべてのノードを起動する: 到達できないメンバーがより新しい場合、そのトランザクションは失われる。force: trueは欠落しているメンバーを無視する。最後の手段である。primary: 'host:port'オプションは特定のメンバーをプライマリとして強制する。","note":"dryRun、primary、forceオプションはShell 8.0.31で導入された。それ以前のバージョンは対話型のプロンプトで動作した。group_replication_start_on_boot=ONでも、完全停止後にグループは自動的には形成されない。ブートストラップは1か所から意図的に行う必要がある。","since":"MySQL Shell 8.0.31","tags":["innodb cluster","outage","reboot","bootstrap","mysqlsh","disaster"]},{"id":"mysql-router-bootstrap","task":"InnoDB Clusterに対してMySQL Routerをブートストラップ","category":"Routerとプロキシ","command":"# Generates config from metadata and creates the router account; --user is required when run as root\nmysqlrouter --bootstrap icadmin@db1:3306 --directory /etc/mysqlrouter/prod --account routeruser --account-create if-not-exists --name router01 --conf-bind-address 0.0.0.0 --user mysqlrouter\n/etc/mysqlrouter/prod/start.sh\n# Ports: 6446 RW, 6447 RO, 6450 RW split (classic); 6448 / 6449 X protocol\nmysql -h app-host -P 6446 -u app -p -e \"SELECT @@hostname\"\nmysql -h app-host -P 6447 -u app -p -e \"SELECT @@hostname\"\nmysqlsh icadmin@db1:3306 -- cluster list-routers","what":"Routerをクラスタのメタデータに登録し、アカウントと構成を生成する。アプリケーションはRWポートで現在のプライマリに、ROポートでセカンダリにラウンドロビンで到達する。","when":"InnoDB Cluster / ClusterSet / ReplicaSetの前段に透過的なフェイルオーバー層を置くときに。一般的にはアプリケーションサーバーごとに1つのRouter。","caution":"Routerはステートレスであり、アプリケーションの隣で実行すれば単一障害点を避けられるが、単一の集中Routerではそうはならない。ブートストラップ用アカウントはブートストラップ中にのみ使用され、Routerは独自のアカウント(routeruser)でメタデータを読み取る。トポロジの変更は再ブートストラップなしでメタデータキャッシュを通じて認識する。RW分割ポート(6450)はトランザクション内の読み取りをプライマリに、それ以外をセカンダリに送る。read-your-writesを期待するアプリケーションには注意する。RouterのバージョンはクラスタのMySQLサーバーより古くてはならない。","note":"読み取り/書き込み分割ポート(6450)は8.2で導入された。フェイルオーバー時には既存の接続が切断されるため、アプリケーションには再接続(リトライ)のロジックが必要。","since":"MySQL Router 8.0","tags":["mysql router","bootstrap","innodb cluster","failover","read write split","6446"]},{"id":"proxysql-rw-split","task":"ProxySQLによる読み取り/書き込み分割とレプリカのヘルスチェック","category":"Routerとプロキシ","command":"-- On MySQL (source): monitor user\nCREATE USER 'proxysql_mon'@'%' IDENTIFIED BY 'M0n#itor2024';\nGRANT USAGE, REPLICATION CLIENT ON *.* TO 'proxysql_mon'@'%';\n\n-- ProxySQL admin: mysql -u admin -p -h 127.0.0.1 -P 6032\nUPDATE global_variables SET variable_value = 'proxysql_mon' WHERE variable_name = 'mysql-monitor_username';\nUPDATE global_variables SET variable_value = 'M0n#itor2024' WHERE variable_name = 'mysql-monitor_password';\nLOAD MYSQL VARIABLES TO RUNTIME; SAVE MYSQL VARIABLES TO DISK;\nINSERT INTO mysql_replication_hostgroups (writer_hostgroup, reader_hostgroup, check_type, comment) VALUES (10, 20, 'read_only', 'shop');\nINSERT INTO mysql_servers (hostgroup_id, hostname, port, max_replication_lag) VALUES (10, 'db1', 3306, 0), (20, 'db2', 3306, 30), (20, 'db3', 3306, 30);\nLOAD MYSQL SERVERS TO RUNTIME; SAVE MYSQL SERVERS TO DISK;\nINSERT INTO mysql_users (username, password, default_hostgroup, transaction_persistent) VALUES ('app', 'App#Pass2024', 10, 1);\nLOAD MYSQL USERS TO RUNTIME; SAVE MYSQL USERS TO DISK;\nINSERT INTO mysql_query_rules (rule_id, active, match_digest, destination_hostgroup, apply) VALUES (100, 1, '^SELECT .* FOR (UPDATE|SHARE)', 10, 1), (200, 1, '^SELECT ', 20, 1);\nLOAD MYSQL QUERY RULES TO RUNTIME; SAVE MYSQL QUERY RULES TO DISK;\n\n-- Verify\nSELECT hostgroup_id, hostname, status FROM runtime_mysql_servers;\nSELECT hostgroup, srv_host, status, ConnUsed, Queries, Latency_us FROM stats_mysql_connection_pool;\nSELECT hostgroup, substr(digest_text, 1, 60) AS digest, count_star, sum_time / 1000 AS sum_ms FROM stats_mysql_query_digest ORDER BY sum_time DESC LIMIT 10;","what":"read_onlyフラグに基づいて書き込み(10)と読み取り(20)のホストグループを自動的に管理する。SELECTをレプリカに、ロックを伴う読み取りと書き込みをソースにルーティングし、max_replication_lagを超えたレプリカを一時的に除外する(SHUNNED)。","when":"アプリケーションに触れずに非同期レプリケーショントポロジで読み取り負荷を分散するため。接続プーリング、クエリ単位のルーティング/キャッシュ/ファイアウォールに。","caution":"構成は3層(MEMORY → RUNTIME → DISK)である: LOAD ... TO RUNTIMEなしでは何も変わらず、SAVE ... TO DISKなしでは再起動時に失われる。read_onlyチェックにはレプリカでsuper_read_only=ONが必要。そうでないとレプリカが書き込みホストグループに移される。すべてのSELECTをレプリカに送ると、遅延によりread-after-writeのエラーが発生する。stats_mysql_query_digestに基づき、重い/レポート用のクエリに対してのみルールを書く方が安全。管理インタフェースはSQLiteであり、LEFT()などのMySQL関数は存在しないため、substr()を使用する。デフォルトのadmin:adminアカウント(admin-admin_credentials)を変更する。","note":"max_replication_lagのチェックには、監視ユーザーにREPLICATION CLIENTが必要。Group Replication / InnoDB Clusterではmysql_group_replication_hostgroups表を使用する。","since":"ProxySQL 2.0","tags":["proxysql","read write split","hostgroup","query rules","connection pool","replication lag"]},{"id":"online-ddl-instant-inplace","task":"オンラインDDL: ALGORITHM=INSTANT / INPLACE、LOCK=NONEと進捗の追跡","category":"オンライン操作","command":"-- Always state ALGORITHM/LOCK: unsupported operations fail immediately instead of silently falling back to COPY\nALTER TABLE shop.orders ADD COLUMN status TINYINT NOT NULL DEFAULT 0, ALGORITHM=INSTANT;\nALTER TABLE shop.orders RENAME COLUMN note TO remark, ALGORITHM=INSTANT;\nALTER TABLE shop.orders ADD INDEX ix_status (status), ALGORITHM=INPLACE, LOCK=NONE;\nALTER TABLE shop.orders MODIFY remark VARCHAR(200), ALGORITHM=INPLACE, LOCK=NONE;\n\n-- INSTANT row version counter (INSTANT is refused at 64, a rebuild resets it)\nSELECT NAME, TOTAL_ROW_VERSIONS FROM information_schema.INNODB_TABLES WHERE NAME = 'shop/orders';\n\n-- Progress of a long ALTER (enable the instruments once)\nUPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME LIKE 'stage/innodb/alter%';\nUPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME LIKE 'events_stages_%';\nSELECT t.PROCESSLIST_ID, s.EVENT_NAME, s.WORK_COMPLETED, s.WORK_ESTIMATED,\n       ROUND(100 * s.WORK_COMPLETED / NULLIF(s.WORK_ESTIMATED, 0), 1) AS pct_done\nFROM performance_schema.events_stages_current s\nJOIN performance_schema.threads t ON t.THREAD_ID = s.THREAD_ID\nWHERE s.EVENT_NAME LIKE 'stage/innodb/alter%';","what":"INSTANTはデータディクショナリのみを変更し、表のサイズにかかわらず即座に完了する。INPLACE + LOCK=NONEは、同時の読み取りと書き込みを許可しながら表をその場で処理する。最後のクエリは、実行中のALTERがどの段階にあるかとその割合を表示する。","when":"本番の表でのスキーマ変更の前に。どの操作が停止なしで実行できるかを知り、長いALTERがいつ終わるかを見積もるため。","caution":"INSTANTとINPLACEも開始時と終了時に短時間の排他メタデータロックを取得する。長時間実行のトランザクションが表を保持している場合、ALTERは待機し、その後ろのすべてのクエリがキューに並ぶ(メタデータロックの診断を参照)。セッションでlock_wait_timeoutを下げる(SET SESSION lock_wait_timeout = 5)。INPLACE中に到着したDMLはinnodb_online_alter_log_max_sizeまで記録され、超過するとALTERは最後にロールバックされる。列の型の変更、文字セットの変換、PKの変更にはCOPYが必要で、書き込みをブロックする。大きな表ではgh-ost / pt-online-schema-changeを使用する。レプリカではALTERは同じ時間シングルスレッドで実行される。大きなINPLACEのALTERはレプリカ遅延を引き起こすが、INSTANTは引き起こさない。","note":"INSTANT ADD COLUMNは8.0.12で最後の列に限り導入された。8.0.29以降は任意の位置に列を追加でき、INSTANT DROP COLUMNもサポートされる。VARCHARの拡張は、長さバイト数が変わらない(255バイトの境界を越えない)場合はメタデータのみの変更となり、INSTANTではなくINPLACEで即座に完了する。インデックス付きの列はINSTANTでは削除できないため、先にインデックスを削除する。","since":"MySQL 8.0.29","tags":["online ddl","instant","inplace","alter table","lock=none","progress"]},{"id":"pt-online-schema-change","task":"pt-online-schema-changeによる大きな表へのブロックしないALTER","category":"オンライン操作","command":"# First --dry-run, then the same command with --execute; throttles on replica lag\npt-online-schema-change --alter \"ADD COLUMN region CHAR(2) NULL, ADD INDEX ix_region (region)\" \\\n  D=shop,t=orders,h=db1,u=osc,p='Osc#2024',s=1 \\\n  --max-lag=5 --check-replica-lag h=db2,u=osc,p='Osc#2024',s=1 \\\n  --max-load Threads_running=50 --critical-load Threads_running=200 \\\n  --set-vars lock_wait_timeout=5 --noversion-check --dry-run","what":"新しい構造の空のコピーを作成し、行をチャンク単位でコピーし、コピー中の変更をトリガーで反映し、最後にアトミックなRENAMEで表を入れ替える。負荷やレプリカ遅延がしきい値を超えると、自動的に速度を落とす/一時停止する。","when":"COPYが必要なALTER(列の型、文字セット、PKの変更)や、長いレプリカ遅延を引き起こすALTERに。","caution":"表にはPKまたは一意キーが必要。移行中はトリガーがすべての書き込みにオーバーヘッドを加える。書き込みが非常に多い表ではgh-ostの方が影響が小さい。子表が外部キーでこの表を参照している場合、--alter-foreign-keys-method=autoが必要。caching_sha2_passwordアカウントではDSNにs=1(TLS)を追加する。そうしないとレプリカへの接続が'Authentication requires secure connection'で失敗する。--check-replica-lagのDSNはメインDSNからユーザー/パスワードを継承しないため、指定する。入替えでは短時間のメタデータロックを取得する。lock_wait_timeoutを低く保つ。ロックを取得できない場合はリトライする。","note":"レプリカはデフォルトでprocesslistを通じてIPで検出される。それらのIPに到達できない場合は、--recursion-method=dsn=D=percona,t=dsnsでDSN表を使用する。3.7で--check-slave-lagは--check-replica-lagに名前が変更された(旧名は非推奨)。","since":"Percona Toolkit 3.7","tags":["pt-online-schema-change","pt-osc","percona toolkit","alter","trigger","online schema change"]},{"id":"gh-ost-migration","task":"gh-ostによるトリガーなしのオンラインスキーマ変更","category":"オンライン操作","command":"# Connects to a replica and reads its binlog; postpones cut-over until the flag file is removed\ngh-ost --host=db2 --port=3306 --user=ghost --password='Gh0st#2024' \\\n  --database=shop --table=orders \\\n  --alter=\"ADD COLUMN channel VARCHAR(20) NULL, ADD INDEX ix_channel (channel)\" \\\n  --max-load=Threads_running=50 --critical-load=Threads_running=200 --max-lag-millis=1500 \\\n  --exact-rowcount --concurrent-rowcount --default-retries=120 \\\n  --postpone-cut-over-flag-file=/tmp/ghost.postpone --panic-flag-file=/tmp/ghost.panic \\\n  --serve-socket-file=/tmp/gh-ost.shop.orders.sock --ssl --ssl-allow-insecure --execute\n# While running: status / throttle / cut-over\necho status | nc -U /tmp/gh-ost.shop.orders.sock\necho throttle | nc -U /tmp/gh-ost.shop.orders.sock\nrm /tmp/ghost.postpone","what":"ゴースト表を作成して行をコピーする。同時の変更は、トリガーではなくbinlogを読み取って適用する。スロットリング、一時停止、カットオーバーのタイミングは、ソケットまたはフラグファイルを介して実行時に制御する。","when":"トリガーのオーバーヘッドが許容できない、書き込みの多い大きな表で、カットオーバーのタイミング(例: トラフィックの少ない時間帯)を自分で選びたいときに。","caution":"binlog_format=ROWとbinlog_row_image=FULLが必要。接続先のレプリカにはlog_replica_updates=ONが必要。ユーザーにはSUPERまたはREPLICATION CLIENT / REPLICATION SLAVEと、表に対するALLが必要。外部キーを持つ表(親または子)はサポートされない。カットオーバー後、旧表は_<table>_delとして残るため、検証後に手動で削除する(--ok-to-drop-tableを指定すると自動的に削除される)。1.1.8より前のgh-ostリリースはSHOW SLAVE STATUSを使用し、MySQL 8.4ではエラー1064で停止する。8.4のサポートは1.1.8で追加された。gh-ostは--postpone-cut-over-flag-fileで指定したファイルを自ら作成し、そのファイルが削除されるまでカットオーバーは行われない。","note":"--test-on-replica および --migrate-on-replica オプションで、まずレプリカ上でのみ変更を試行・検証できる。スロットル理由と ETA は 'status' コマンドの出力に表示される。","tags":["gh-ost","online schema change","binlog","cut-over","alter","triggerless"]},{"id":"ps-top-digests","task":"最もコストの高いクエリを特定する (performance_schema digest)","category":"パフォーマンス","command":"SELECT SCHEMA_NAME AS db,\n       LEFT(DIGEST_TEXT, 80) AS query,\n       COUNT_STAR AS calls,\n       ROUND(SUM_TIMER_WAIT / 1e12, 2) AS total_sec,\n       ROUND(AVG_TIMER_WAIT / 1e9, 2) AS avg_ms,\n       ROUND(QUANTILE_95 / 1e9, 2) AS p95_ms,\n       ROUND(100 * SUM_TIMER_WAIT / SUM(SUM_TIMER_WAIT) OVER (), 1) AS pct_total,\n       ROUND(SUM_ROWS_EXAMINED / NULLIF(COUNT_STAR, 0)) AS rows_exam_per_call,\n       ROUND(SUM_ROWS_SENT / NULLIF(COUNT_STAR, 0)) AS rows_sent_per_call,\n       SUM_NO_INDEX_USED AS no_index,\n       SUM_CREATED_TMP_DISK_TABLES AS tmp_disk,\n       LAST_SEEN\nFROM performance_schema.events_statements_summary_by_digest\nWHERE SCHEMA_NAME IS NOT NULL\nORDER BY SUM_TIMER_WAIT DESC\nLIMIT 20;\n\n-- Server-wide top wait events\nSELECT events, total, total_latency, avg_latency FROM sys.waits_global_by_latency LIMIT 10;","what":"正規化されたクエリを合計時間で順位付けし、実行回数、平均および p95 レイテンシ、全体に占める割合、1 回あたりの examined / sent 行数、インデックスを使わない実行、ディスクに書き出された一時テーブルを表示する。2 番目のクエリは、時間がどの待機 (IO、ロック、redo) に費やされているかを示す。","when":"CPU / IO 負荷が上昇したとき、またはユーザーから「データベースが遅い」と報告されたときに最初に確認する。slow log が無効でも機能する。","caution":"値は最後の再起動または TRUNCATE TABLE performance_schema.events_statements_summary_by_digest 以降の累積値。現在のアクティビティを見るには 2 つのスナップショットを取得して差分を取る。テーブルは performance_schema_digests_size 行が上限で、満杯になると新しいクエリは DIGEST が NULL の 1 行に集約される。DIGEST_TEXT は performance_schema_max_digest_length (1024) バイトで切り詰められる。時間の単位はピコ秒。rows_exam_per_call / rows_sent_per_call の比率が高いことは、インデックス不足の最も明確な兆候である。","note":"QUANTILE_95 / QUANTILE_99 および QUERY_SAMPLE_TEXT 列は 8.0 で追加された。同じデータを読みやすい単位で表示するには sys.statement_analysis および sys.statements_with_full_table_scans ビューを使用する。","since":"MySQL 8.0","tags":["performance_schema","digest","top sql","slow query","sys","wait"]},{"id":"sys-session-activity","task":"現在実行中の処理: アクティブセッション、レイテンシ、ロック、トランザクション (sys.session)","category":"パフォーマンス","command":"SELECT conn_id, user, db, command, state, time,\n       LEFT(current_statement, 100) AS current_statement,\n       statement_latency, progress, lock_latency,\n       rows_examined, full_scan, tmp_disk_tables,\n       trx_state, trx_latency, last_wait\nFROM sys.session\nWHERE command <> 'Sleep' OR trx_state = 'ACTIVE'\nORDER BY time DESC\nLIMIT 25;","what":"SHOW PROCESSLIST を performance_schema のデータで補完し、実行中ステートメントのレイテンシ、進捗率、ロック待機時間、examined 行数、フルスキャン / ディスク一時テーブル情報、オープン中のトランザクション状態を 1 行で表示する。Sleep 状態だがトランザクションを開いたままのセッションも一覧表示する。","when":"インシデント発生後の最初の 30 秒で、どのクエリがどれだけ実行されているか、誰がロック待ちか、どのアイドルセッションがトランザクションを開いたままかを確認する。","caution":"sys.session は performance_schema に対して複数の結合を行うため、接続数が数千になるとクエリ自体に数秒かかることがある。頻繁な監視には x$ ビューと LIMIT を使用する。progress は stage インストゥルメントが有効で、ALTER など進捗を報告する操作の場合にのみ値が入る。Sleep 状態で trx_state=ACTIVE のセッションは、autocommit=0 を使用するアプリケーション / コネクションプールが放置したトランザクションであり、メタデータロックおよび purge 問題の最も一般的な原因である。","note":"sys.processlist はバックグラウンドスレッドを含む同じデータを返す。終了するには KILL QUERY conn_id (ステートメントのみ) または KILL conn_id (接続。トランザクションはロールバックされる) を使用する。","since":"MySQL 8.0","tags":["sys.session","processlist","active sessions","incident","trx","session"]},{"id":"metadata-lock-diagnose","task":"'Waiting for table metadata lock' を診断し、真のブロッカーを特定する","category":"パフォーマンス","command":"-- Waiter -> blocker pairs; filter out the ALTER's own SHARED_UPGRADABLE entry\nSELECT object_schema, object_name, waiting_pid, LEFT(waiting_query, 60) AS waiting_query,\n       waiting_lock_type, blocking_pid, blocking_lock_type, sql_kill_blocking_connection\nFROM sys.schema_table_lock_waits\nWHERE blocking_lock_type <> 'SHARED_UPGRADABLE';\n\n-- All MDLs on the table, owner age and open transaction\nSELECT ml.OBJECT_SCHEMA, ml.OBJECT_NAME, ml.LOCK_TYPE, ml.LOCK_DURATION, ml.LOCK_STATUS,\n       t.PROCESSLIST_ID AS conn_id, t.PROCESSLIST_COMMAND AS command, t.PROCESSLIST_TIME AS sec,\n       LEFT(t.PROCESSLIST_INFO, 60) AS query, trx.trx_started\nFROM performance_schema.metadata_locks ml\nJOIN performance_schema.threads t ON t.THREAD_ID = ml.OWNER_THREAD_ID\nLEFT JOIN information_schema.INNODB_TRX trx ON trx.trx_mysql_thread_id = t.PROCESSLIST_ID\nWHERE ml.OBJECT_TYPE = 'TABLE' AND ml.OBJECT_SCHEMA NOT IN ('performance_schema', 'mysql')\nORDER BY ml.OBJECT_NAME, ml.LOCK_STATUS DESC;","what":"ALTER / TRUNCATE / RENAME などの DDL がどのセッションのメタデータロックを待っているか、および DDL の後ろに並んでいるクエリを表示する。ブロッカーは通常、テーブルを読み取った後トランザクションを閉じていない Sleep 状態のセッションである。","when":"ALTER の開始後、そのテーブルに対するすべてのクエリが 'Waiting for table metadata lock' で滞留する場合。","caution":"待機中の DDL は、その後に到着する SELECT もブロックする。インシデント中は、ブロックしているセッションを KILL するか ALTER をキャンセルする (KILL QUERY) かを迅速に判断する。ブロッカーの PROCESSLIST_INFO は NULL (アイドル) の場合がある。最後のステートメントを確認するには performance_schema.events_statements_history または sys.session.last_statement を使用する。予防策: ALTER がすぐに諦めるよう SET SESSION lock_wait_timeout = 5 の後で DDL を実行し、アプリケーションで長時間開いたままのトランザクションを避ける。","note":"wait/lock/metadata/sql/mdl インストゥルメントは 8.0 ではデフォルトで有効、5.7 では setup_instruments で有効化が必要。sys.schema_table_lock_waits は ALTER 自身の SHARED_UPGRADABLE ロックもブロッカーとして表示する。真の原因は GRANTED 状態の SHARED_READ / SHARED_WRITE を保持しているセッションである。","since":"MySQL 8.0","tags":["metadata lock","mdl","alter","waiting for table metadata lock","lock","blocking"]},{"id":"innodb-deadlock-analysis","task":"InnoDB のデッドロックを分析し、すべてをログに記録する","category":"パフォーマンス","command":"-- Latest deadlock: LATEST DETECTED DEADLOCK section (only the most recent is kept)\nSHOW ENGINE INNODB STATUS\\G\n-- Total deadlock counter\nSELECT NAME, COUNT FROM information_schema.INNODB_METRICS WHERE NAME = 'lock_deadlocks';\n-- Write every deadlock to the error log (logged at Note level, needs verbosity 3)\nSET PERSIST innodb_print_all_deadlocks = ON;\nSET PERSIST log_error_verbosity = 3;","what":"デッドロックに関与した 2 つのトランザクション、それぞれが保持・待機しているロック (インデックス、lock_mode、レコード)、および InnoDB がどちらをロールバックしたかを表示する。カウンターで頻度を追跡し、エラーログに過去のデッドロックを残す。","when":"アプリケーションがエラー 1213 'Deadlock found when trying to get lock' を受け取る場合、またはデッドロックアラートが増加した場合。","caution":"LATEST DETECTED DEADLOCK は最後のイベントのみを保持し、再起動で失われる。'HOLDS THE LOCK(S)' / 'WAITING FOR THIS LOCK TO BE GRANTED' 行にあるインデックス名と lock_mode (X、S、gap、insert intention) が原因を示し、'WE ROLL BACK TRANSACTION (n)' が犠牲となったトランザクションを示す。1213 が発生した場合、アプリケーションはトランザクション全体を再試行する必要がある。恒久的な対策: 行へのアクセス順序を一定にする、トランザクションを短く保つ、適切なインデックスを使用してギャップロックを減らす、適切な場合は READ COMMITTED を使用する。log_error_verbosity=3 はすべての Note メッセージも有効にするため、エラーログの増加に注意する。Innodb_deadlocks ステータス変数は MySQL Community には存在しないため、カウンターには INNODB_METRICS を使用する。","note":"非常に高い同時実行性のもとでは、デッドロック検出自体が CPU のボトルネックになることがある。innodb_deadlock_detect=OFF は innodb_lock_wait_timeout を低く設定した場合にのみ検討する。ロック待機タイムアウト (1205) はデッドロックではない。ブロッカーの特定には blocking-locks レシピを使用する。","since":"MySQL 8.0","tags":["deadlock","innodb","1213","innodb status","lock","error log"]},{"id":"long-trx-history-list","task":"長時間実行トランザクションと history list length (purge の遅延)","category":"パフォーマンス","command":"-- Undo records waiting for purge (millions = trouble)\nSELECT NAME, COUNT AS history_list_length\nFROM information_schema.INNODB_METRICS WHERE NAME = 'trx_rseg_history_len';\n\n-- Oldest transactions, their owner and last SQL\nSELECT trx.trx_id, trx.trx_mysql_thread_id AS conn_id, trx.trx_state,\n       TIMESTAMPDIFF(SECOND, trx.trx_started, NOW()) AS age_sec,\n       trx.trx_rows_modified, trx.trx_rows_locked, trx.trx_isolation_level,\n       p.USER, p.HOST, p.COMMAND, p.TIME AS state_sec,\n       LEFT(COALESCE(trx.trx_query, esc.SQL_TEXT), 80) AS current_or_last_sql\nFROM information_schema.INNODB_TRX trx\nJOIN performance_schema.processlist p ON p.ID = trx.trx_mysql_thread_id\nLEFT JOIN performance_schema.threads th ON th.PROCESSLIST_ID = trx.trx_mysql_thread_id\nLEFT JOIN performance_schema.events_statements_current esc ON esc.THREAD_ID = th.THREAD_ID\nORDER BY trx.trx_started\nLIMIT 10;","what":"purge の遅延量 (history list length) と、それを妨げている最も古いトランザクションの所有者、経過時間、変更行数、最後に実行した SQL を表示する。","when":"undo 表領域が増大する場合、同じクエリが時間とともに遅くなる場合 (古い行バージョンをスキャンするため)、またはディスク容量アラートの発生時。","caution":"最も一般的な原因は、トランザクションを開いたままの Sleep 状態のセッション、または REPEATABLE READ のもとで放置された一貫性スナップショット (例: 放棄された mysqldump / レポート) である。KILL 後のロールバックには、トランザクションが変更した行数に応じた時間がかかる。trx_rows_modified が大きいトランザクションを KILL すると、長く IO 負荷の高いロールバックとなり、再起動しても短縮されない。purge が追いつくと undo は自動的に切り詰められる (innodb_undo_log_truncate=ON)。","note":"performance_schema.processlist は 8.0.22 で追加され、非推奨の information_schema.PROCESSLIST を置き換える。SHOW ENGINE INNODB STATUS の 'History list length' でも同じ値が得られる。","since":"MySQL 8.0.22","tags":["history list length","purge","undo","long transaction","innodb_trx","idle in transaction"]},{"id":"slow-log-pt-query-digest","task":"短時間の完全な slow log を取得し pt-query-digest で分析する","category":"パフォーマンス","command":"-- Temporary full capture (e.g. 10 minutes); only new connections are affected\nSET GLOBAL slow_query_log_file = '/var/lib/mysql/slow.log';\nSET GLOBAL log_slow_extra = ON;\nSET GLOBAL long_query_time = 0;\nSET GLOBAL slow_query_log = ON;\n-- ... then return to the normal threshold\nSET GLOBAL long_query_time = 1;\n\n# Shell: top 10 queries by total time\npt-query-digest --limit=10 --order-by=Query_time:sum --noversion-check /var/lib/mysql/slow.log > /tmp/digest.txt\npt-query-digest --since='2026-10-08 09:00:00' --until='2026-10-08 10:00:00' --filter '$event->{db} && $event->{db} eq \"shop\"' --report-format=profile --noversion-check /var/lib/mysql/slow.log","what":"long_query_time=0 で短時間すべてのクエリを記録する。pt-query-digest がフィンガープリントごとにグループ化し、合計 / 平均 / p95 時間、examined 行数、サンプルクエリを含むランク付きレポートを生成する。","when":"performance_schema digest では不十分な場合: 完全なステートメントテキストと実際のパラメータによる分析、デプロイ前後の比較、別ホストでのオフラインレビュー。","caution":"long_query_time はセッション開始時にグローバル値からコピーされるため、プール内の既存接続は再接続するまで新しいしきい値を認識しない。long_query_time=0 は高負荷サーバーで毎秒数千件のエントリを書き込むため、ディスク容量と IO を監視し、期間を短く保ち、必ず元に戻す。分析用にファイルを本番環境の外にコピーする。pt-query-digest を実行するユーザーにはファイルの読み取り権限 (mode 640、mysql:mysql) が必要。","note":"log_slow_extra (8.0.14) は Bytes_sent、Read_first / Read_next、Created_tmp_disk_tables などの追加フィールドを書き込み、pt-query-digest はそれらをレポートに表示する。恒久的な有効化 / 無効化については enable-general-slow-log レシピを参照。","since":"MySQL 8.0.14","tags":["slow log","pt-query-digest","long_query_time","percona toolkit","query analysis","slow query"]},{"id":"explain-analyze-optimizer-trace","task":"EXPLAIN ANALYZE とオプティマイザトレースで不適切な実行計画をデバッグする","category":"パフォーマンス","command":"-- Plan + actual time and rows (the query actually runs)\nEXPLAIN ANALYZE\nSELECT region, COUNT(*) FROM shop.big WHERE id < 20000 GROUP BY region;\n\n-- Why the optimizer chose this plan: optimizer trace\nSET SESSION optimizer_trace = 'enabled=on', SESSION optimizer_trace_max_mem_size = 1048576;\nSELECT * FROM shop.big WHERE region = 'TR' AND id > 100 LIMIT 5;\nSELECT JSON_PRETTY(JSON_EXTRACT(TRACE, '$**.considered_execution_plans')) AS plans,\n       MISSING_BYTES_BEYOND_MAX_MEM_SIZE\nFROM information_schema.OPTIMIZER_TRACE;\nSET SESSION optimizer_trace = 'enabled=off';","what":"EXPLAIN ANALYZE は、実行計画の各ステップについて推定値 (cost、rows) と実績値 (actual time、rows、loops) を並べて表示する。オプティマイザトレースは、検討されたアクセスパス、そのコスト、各パスが選択または却下された理由を示す。","when":"クエリが突然遅くなった場合 (実行計画の変更)、オプティマイザが誤ったインデックスを選択する場合、または推定行数と実績行数の不一致の原因を探る場合。","caution":"EXPLAIN ANALYZE はクエリを実際に実行するため、本番環境での重いクエリには注意する。SELECT、TABLE および複数テーブルの UPDATE / DELETE で動作する。推定行数と実績行数の差が 10 倍を超える場合は統計 / ヒストグラムの問題を示す (ANALYZE TABLE、ヒストグラム)。ネステッドループの内側では actual rows はループごとの値であり、合計 = rows × loops。MISSING_BYTES_BEYOND_MAX_MEM_SIZE > 0 の場合はトレースが切り詰められているため、optimizer_trace_max_mem_size を引き上げる。トレースは同一セッションの最後のステートメントのみを保持する。","note":"EXPLAIN FORMAT=TREE は 8.0.16、EXPLAIN ANALYZE は 8.0.18 で追加された。実行計画を固定するには、オプティマイザヒント (/*+ INDEX(t ix) */、JOIN_ORDER) の方が FORCE INDEX よりきめ細かく制御できる。","since":"MySQL 8.0.18","tags":["explain analyze","optimizer trace","execution plan","query tuning","index","plan"]},{"id":"histogram-statistics","task":"インデックスのない列のヒストグラムを作成・管理する","category":"インデックスと統計","command":"ANALYZE TABLE shop.big UPDATE HISTOGRAM ON status WITH 64 BUCKETS;\n-- 8.4+: histogram refreshed automatically as data changes\nANALYZE TABLE shop.big UPDATE HISTOGRAM ON status WITH 64 BUCKETS AUTO UPDATE;\n\nSELECT SCHEMA_NAME, TABLE_NAME, COLUMN_NAME,\n       HISTOGRAM->>'$.\"histogram-type\"' AS type,\n       JSON_LENGTH(HISTOGRAM->'$.buckets') AS buckets,\n       HISTOGRAM->>'$.\"last-updated\"' AS last_updated,\n       HISTOGRAM->>'$.\"sampling-rate\"' AS sampling_rate\nFROM information_schema.COLUMN_STATISTICS;\n\nANALYZE TABLE shop.big DROP HISTOGRAM ON status;","what":"列の値分布 (singleton または equi-height) をデータディクショナリに格納する。オプティマイザがインデックスのない列に対するフィルタの選択性を正しく推定できるようになり、結合順序と実行計画の品質が向上する。","when":"EXPLAIN ANALYZE で、インデックスの追加が望ましくない偏りのある列 (例: status、type) について推定行数と実績行数の大きな差が見られる場合。","caution":"インデックス付き列ではオプティマイザが index dive を使用するため、ヒストグラムは通常効果がない (eq_range_index_dive_limit を超える場合を除く)。デフォルトの MANUAL モードでは、データが変化してもヒストグラムは更新されないため、ANALYZE ... UPDATE HISTOGRAM をスケジュールする。大きなテーブルは histogram_generation_max_mem_size に従ってサンプリングされる (sampling-rate < 1)。ANALYZE TABLE は短時間メタデータロックを取得する。ヒストグラムの更新はテーブル統計 (インデックスのカーディナリティ) を変更しない。","note":"ヒストグラムは 8.0 で追加された。AUTO UPDATE オプションは 8.4 で追加され、統計の自動再計算と同時に更新される。最大バケット数は 1024。個別値の数がバケット数より少ない場合は singleton ヒストグラムが作成される。","since":"MySQL 8.0","tags":["histogram","statistics","optimizer","analyze table","selectivity","cardinality"]},{"id":"invisible-redundant-index","task":"未使用 / 冗長なインデックスを特定し、不可視化してから安全に削除する","category":"インデックスと統計","command":"-- Candidate 1: indexes unused since the last restart\nSELECT * FROM sys.schema_unused_indexes WHERE object_schema = 'shop';\n-- Candidate 2: redundant indexes that are a left prefix of another\nSELECT table_name, redundant_index_name, redundant_index_columns, dominant_index_name, sql_drop_index\nFROM sys.schema_redundant_indexes WHERE table_schema = 'shop';\n\n-- Make it invisible before dropping; revert instantly if anything regresses\nALTER TABLE shop.big ALTER INDEX ix_region INVISIBLE;\nSELECT INDEX_NAME, IS_VISIBLE FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = 'shop' AND TABLE_NAME = 'big' AND SEQ_IN_INDEX = 1;\n-- Try the invisible index for a single query\nEXPLAIN SELECT /*+ SET_VAR(optimizer_switch = 'use_invisible_indexes=on') */ COUNT(*) FROM shop.big WHERE region = 'TR';\nALTER TABLE shop.big ALTER INDEX ix_region VISIBLE;\n-- After a few business cycles (incl. month-end) without issues\nALTER TABLE shop.big DROP INDEX ix_region, ALGORITHM=INPLACE, LOCK=NONE;","what":"未使用のインデックスと、別のインデックスに包含されているインデックスを一覧表示する。削除前にインデックスを不可視にすると、そのインデックスなしで本番環境の動作をテストでき、必要に応じて即座に (再構築なしで) 元に戻せる。","when":"書き込みコスト、バッファプールの負荷、ディスク使用量を減らすためにインデックスを整理する場合。","caution":"schema_unused_indexes は最後の再起動以降に収集された統計のみに基づくため、月次レポートなど実行頻度の低いクエリは現れない場合がある。レプリカごとにワークロードが異なる場合は、各サーバーを個別に確認する。不可視インデックスも DML では引き続き維持される (書き込みコストは残る) が、オプティマイザは無視する。一意インデックスは不可視でも一意性を強制する。PRIMARY KEY は不可視にできない。FORCE INDEX / USE INDEX でそのインデックスを指定しているクエリは、不可視にすると失敗する。","note":"インデックスの可視性の切り替えはメタデータのみの変更で、即座に完了する。冗長リストは列の順序に基づく。インデックス (a) は (a,b) に包含されるが、(b) は包含されない。","since":"MySQL 8.0","tags":["invisible index","unused index","redundant index","sys","drop index","index cleanup"]},{"id":"buffer-pool-sizing","task":"バッファプールは十分か: ヒット率、wait_free、オンラインでのサイズ変更","category":"メモリ","command":"SELECT ROUND(@@innodb_buffer_pool_size / 1024 / 1024) AS bp_mb,\n       @@innodb_buffer_pool_chunk_size / 1024 / 1024 AS chunk_mb,\n       @@innodb_buffer_pool_instances AS instances;\nSELECT\n  ROUND(100 * (1 - (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads')\n                 / NULLIF((SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests'), 0)), 3) AS hit_pct,\n  (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_pages_free') AS pages_free,\n  (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_pages_dirty') AS pages_dirty,\n  (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_wait_free') AS wait_free;\n\n-- Online resize and status tracking\nSET PERSIST innodb_buffer_pool_size = 8589934592;\nSELECT VARIABLE_NAME, VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME LIKE 'Innodb_buffer_pool_resize_status%';","what":"バッファプールのサイズ、キャッシュヒット率、空き / ダーティページ数、空きページ待機 (wait_free) カウンターを表示する。再起動なしでサイズを変更し、進捗を追跡する。","when":"読み取り IO が高い場合、RAM の増設 / 削減後、またはキャパシティプランニング時。","caution":"ヒット率だけでは誤解を招く。99% でも毎秒数千回のディスク読み取りを意味することがある。Innodb_buffer_pool_reads の毎秒の増加量を確認する。wait_free > 0 はバッファプールが小さすぎるか、ページクリーナーが追いついていないことを意味する。新しいサイズは innodb_buffer_pool_chunk_size × instances の倍数に丸められる。サイズ変更中は短時間のストールが起こりうる (縮小時は特に)。ピーク時間帯は避ける。専用サーバーでは RAM の 60〜75% から開始する。接続ごとのメモリ、OS キャッシュ、その他のプロセス用の余裕を残す。スワップは小さめのバッファプールより常に悪い。","note":"Innodb_buffer_pool_resize_status_code / _progress は 8.0.31 で追加された。innodb_dedicated_server=ON は RAM からバッファプールと redo 容量を自動的に設定する。sys.innodb_buffer_stats_by_table はテーブルごとのバッファプール使用量を表示するが、INNODB_BUFFER_PAGE をスキャンするため大きなバッファプールでは負荷が高い。","since":"MySQL 8.0","tags":["buffer pool","innodb","memory","hit ratio","resize","sizing"]},{"id":"partition-maintenance","task":"RANGE パーティションのメンテナンス: 将来のパーティションを追加し、古いものをアーカイブ / 削除する","category":"パーティション化","command":"-- Current partitions\nSELECT PARTITION_NAME, PARTITION_DESCRIPTION, TABLE_ROWS\nFROM information_schema.PARTITIONS\nWHERE TABLE_SCHEMA = 'shop' AND TABLE_NAME = 'events_log' ORDER BY PARTITION_ORDINAL_POSITION;\n\n-- Add a new month by splitting the empty pmax\nALTER TABLE shop.events_log REORGANIZE PARTITION pmax INTO (\n  PARTITION p2026_11 VALUES LESS THAN ('2026-12-01'),\n  PARTITION pmax VALUES LESS THAN (MAXVALUE));\n\n-- Move the old month into an archive table (instant), then drop the empty partition\nCREATE TABLE shop.events_log_2026_08 LIKE shop.events_log;\nALTER TABLE shop.events_log_2026_08 REMOVE PARTITIONING;\nALTER TABLE shop.events_log EXCHANGE PARTITION p2026_08 WITH TABLE shop.events_log_2026_08;\nALTER TABLE shop.events_log DROP PARTITION p2026_08;\n\n-- Pruning check: the partitions column should list a single partition\nEXPLAIN SELECT * FROM shop.events_log WHERE created >= '2026-10-01' AND created < '2026-11-01';","what":"日付ベースで RANGE パーティション化されたテーブルで、次の期間のパーティションを追加し、EXCHANGE により古い期間をミリ秒単位で別テーブルに移動し、DELETE よりはるかに低コストでパーティションを削除する。","when":"ログ、イベント、監査証跡など時間とともに増大するテーブルの月次保持とアーカイブに。","caution":"パーティション列は、すべての一意キー (PK を含む) に含まれている必要がある。REORGANIZE PARTITION pmax は pmax 内のデータを書き換えるため、pmax は空に保ち、パーティションを事前に作成しておく (例: 3 か月分)。DROP PARTITION は元に戻せず、行単位でログに記録されない。レプリカでは DDL として実行される。EXCHANGE の対象は同じ構造でパーティション化されていない必要がある。範囲外の行はエラーになる (WITHOUT VALIDATION は高速だが誤ったデータが入りうる)。パーティション DDL はテーブルレベルのメタデータロックを取得する。プルーニングのためには、WHERE でパーティション列を関数で囲まずに使用する。","note":"8.0 では、パーティショニングは InnoDB (および NDB) でのみサポートされる。将来のパーティションの追加 / 古いパーティションの削除は、通常 Event Scheduler または cron で自動化する。ALTER TABLE ... TRUNCATE PARTITION はデータを削除するがパーティションは残す。","since":"MySQL 8.0","tags":["partition","range","reorganize","exchange partition","retention","archive"]},{"id":"roles-least-privilege","task":"ロールによる最小権限モデルを構築する (CREATE ROLE、DEFAULT ROLE)","category":"セキュリティ","command":"CREATE ROLE IF NOT EXISTS 'app_read', 'app_write';\nGRANT SELECT ON shop.* TO 'app_read';\nGRANT INSERT, UPDATE, DELETE ON shop.* TO 'app_write';\n\n-- Application account: network range, TLS required, roles active by default\nCREATE USER 'svc_app'@'10.0.%' IDENTIFIED BY 'S3cure#App2024' DEFAULT ROLE 'app_read', 'app_write' REQUIRE SSL;\nCREATE USER 'ana'@'%' IDENTIFIED BY 'An4#Report2024';\nGRANT 'app_read' TO 'ana'@'%';\nSET DEFAULT ROLE ALL TO 'ana'@'%';\n\n-- Show grants with roles expanded\nSHOW GRANTS FOR 'svc_app'@'10.0.%' USING 'app_read', 'app_write';\nSELECT FROM_USER, FROM_HOST, TO_USER, TO_HOST FROM mysql.role_edges;","what":"個々のユーザーではなくロールに権限を付与し、アカウントはロールのメンバーシップを通じて権限を得る。変更が 1 か所で済み、監査とオフボーディングが容易になる。","when":"新しいアプリケーション / チームのアカウントを作成する場合や、権限が入り組んだレガシーサーバーを整理する場合。","caution":"デフォルトロールでないロールはセッション内で有効にならず (CURRENT_ROLE() NONE)、ユーザーに権限がないように見える。SET DEFAULT ROLE ALL または activate_all_roles_on_login=ON を使用する。ロールもアカウントであり (ロック済み、パスワードなし)、mysql.user に表示される。アプリケーションアカウントには '%' ではなくネットワーク範囲を使用する。アプリケーションアカウントに ALL、SUPER、FILE、PROCESS、CONNECTION_ADMIN を付与してはならない。ロールから権限を取り消すと、アクティブなセッションにも影響する。","note":"mandatory_roles はすべてのアカウントにロールを自動的に割り当てる。CREATE USER ... DEFAULT ROLE は、ロールの付与とデフォルト化を同時に行う。","since":"MySQL 8.0","tags":["role","grant","least privilege","default role","security","privilege"]},{"id":"password-policy-lockout","task":"パスワードポリシー、ログイン失敗時のロックアウト、ダウンタイムなしのパスワードローテーション","category":"セキュリティ","command":"-- Password strength policy (component)\nINSTALL COMPONENT 'file://component_validate_password';\nSET PERSIST validate_password.policy = 'MEDIUM';\nSET PERSIST validate_password.length = 12;\nSELECT VALIDATE_PASSWORD_STRENGTH('Summer2024') AS score;\n\n-- Failed-login lockout, password lifetime, history\nALTER USER 'ana'@'%' FAILED_LOGIN_ATTEMPTS 5 PASSWORD_LOCK_TIME 1\n  PASSWORD EXPIRE INTERVAL 90 DAY PASSWORD HISTORY 5 PASSWORD REUSE INTERVAL 365 DAY;\n\n-- Zero-downtime rotation: dual password\nALTER USER 'svc_app'@'10.0.%' IDENTIFIED BY 'N3w#AppSecret2025' RETAIN CURRENT PASSWORD;\n-- Once every application uses the new password\nALTER USER 'svc_app'@'10.0.%' DISCARD OLD PASSWORD;","what":"脆弱なパスワードを拒否し、連続したログイン失敗後にアカウントを一時的にロックし、パスワードの有効期間と再利用ルールを設定するポリシーを有効にする。デュアルパスワードにより、アプリケーションを 1 つずつ更新しながら、ダウンタイムなしでサービスアカウントのパスワードを変更できる。","when":"セキュリティ監査 / コンプライアンス (PCI、ISO 27001) およびサービスアカウントのパスワードローテーションに。","caution":"ポリシーは新規 / 変更されたパスワードにのみ適用され、既存の脆弱なパスワードは検出しない。サービスアカウントで FAILED_LOGIN_ATTEMPTS を使うと、設定を誤った 1 つのクライアントがアカウントをロックし、障害を引き起こす可能性がある。人間のアカウントに使用する。PASSWORD_LOCK_TIME の単位は日 (UNBOUNDED: 手動でロック解除するまで)。ロック解除は ALTER USER ... ACCOUNT UNLOCK で行う。PASSWORD EXPIRE はサービスアカウントで予期しない障害を引き起こすため、そこでは PASSWORD EXPIRE NEVER とデュアルパスワードによるローテーションを推奨する。","note":"デュアルパスワードは 8.0.14、FAILED_LOGIN_ATTEMPTS / PASSWORD_LOCK_TIME は 8.0.19 で追加された。5.7 の validate_password プラグインは 8.0 でコンポーネントに置き換えられ、変数名にはドットが使われる (validate_password.policy)。","since":"MySQL 8.0.19","tags":["password policy","validate_password","failed_login_attempts","dual password","security","password"]},{"id":"require-tls-transport","task":"TLS を強制し、非 TLS 接続を特定し、再起動なしで証明書を更新する","category":"セキュリティ","command":"SELECT @@require_secure_transport, @@tls_version, @@ssl_ca, @@ssl_cert;\nSELECT * FROM performance_schema.tls_channel_status\nWHERE PROPERTY IN ('Enabled', 'Current_tls_version', 'Current_tls_cert', 'Ssl_server_not_after');\n\n-- Active connections and their TLS versions (empty = no TLS)\nSELECT t.PROCESSLIST_USER AS user, t.PROCESSLIST_HOST AS host, t.CONNECTION_TYPE, sv.VARIABLE_VALUE AS tls_version\nFROM performance_schema.threads t\nLEFT JOIN performance_schema.status_by_thread sv ON sv.THREAD_ID = t.THREAD_ID AND sv.VARIABLE_NAME = 'Ssl_version'\nWHERE t.TYPE = 'FOREGROUND' AND t.PROCESSLIST_USER IS NOT NULL;\n\nSET PERSIST require_secure_transport = ON;\n-- After copying the new certificate files\nALTER INSTANCE RELOAD TLS;","what":"サーバーの TLS 設定、証明書の有効期限、各接続が TLS を使用しているかを表示する。暗号化されていない TCP 接続を完全に禁止し、サーバーを停止せずに証明書を更新する。","when":"セキュリティ監査 / コンプライアンス、証明書の有効期限前、暗号化なしで接続しているレガシークライアントの追跡に。","caution":"require_secure_transport=ON は Unix ソケットおよび共有メモリ接続には影響しない (これらはセキュアとみなされる)。有効化する前に TLS なしで接続しているクライアントを特定する。そうしないと、それらはエラー 3159 で失敗する。ALTER INSTANCE RELOAD TLS は既存の接続には影響せず、新しい接続にのみ適用される。証明書ファイルが無効な場合はエラーとなり、古い証明書が維持される。自動生成された自己署名証明書は、VERIFY_CA / VERIFY_IDENTITY を使用するクライアントでは検証できない。本番環境では自社 CA が署名した証明書を使用する。","note":"ALTER INSTANCE RELOAD TLS は 8.0.16、performance_schema.tls_channel_status は 8.0.21 で追加された。アカウント単位で強制するには ALTER USER ... REQUIRE SSL (または REQUIRE X509) を使用する。","since":"MySQL 8.0.21","tags":["tls","ssl","require_secure_transport","certificate","encryption","cert"]},{"id":"risky-accounts-audit","task":"リスクのあるアカウントを監査する: 空パスワード、'%' ホスト、SUPER、mysql_native_password","category":"セキュリティ","command":"SELECT user, host, plugin,\n       CONCAT_WS(', ',\n         IF(authentication_string = '' AND account_locked = 'N', 'EMPTY PASSWORD', NULL),\n         IF(host = '%', 'ANY HOST', NULL),\n         IF(plugin = 'mysql_native_password', 'NATIVE AUTH', NULL),\n         IF(Super_priv = 'Y', 'SUPER', NULL),\n         IF(Grant_priv = 'Y', 'GRANT OPTION', NULL),\n         IF(File_priv = 'Y', 'FILE', NULL),\n         IF(ssl_type = '', 'NO TLS REQUIRED', NULL),\n         IF(password_expired = 'Y', 'EXPIRED', NULL),\n         IF(account_locked = 'Y', 'LOCKED', NULL)) AS findings,\n       password_last_changed\nFROM mysql.user\nWHERE user NOT IN ('mysql.sys', 'mysql.session', 'mysql.infoschema')\nORDER BY (Super_priv = 'Y') DESC, user;\n\n-- Accounts holding powerful dynamic privileges\nSELECT GRANTEE, PRIVILEGE_TYPE FROM information_schema.USER_PRIVILEGES\nWHERE PRIVILEGE_TYPE IN ('SUPER', 'SYSTEM_VARIABLES_ADMIN', 'CONNECTION_ADMIN', 'BINLOG_ADMIN', 'REPLICATION_SLAVE_ADMIN')\nORDER BY GRANTEE;","what":"アカウントごとのセキュリティ上の指摘事項を 1 行で一覧表示する: パスワードなし、任意の場所から接続可能、レガシー認証プラグイン、SUPER / GRANT / FILE 権限、TLS 要件なし。2 番目のクエリは危険な動的権限を表示する。","when":"定期的なセキュリティ監査時、新たに引き継いだサーバー、8.4 へのアップグレード前に。","caution":"このクエリは mysql.user を直接読み取るため、それに対する SELECT 権限が必要。ロールアカウントはパスワードなしでロックされているため、EMPTY PASSWORD はロックされていないアカウントについてのみ報告される。Super_priv は静的な SUPER 権限である。8.0 ではこれが動的権限に分割されたため、2 番目のクエリも確認する。NATIVE AUTH とフラグが付いたアカウントは、8.4 より前に caching_sha2_password へ移行する必要がある: ALTER USER 'u'@'h' IDENTIFIED WITH caching_sha2_password BY '...'。古いクライアント / コネクタは caching_sha2_password をサポートしていない場合があるため、先にテストする。","note":"mysql_native_password は 8.0.34 で非推奨となり、8.4 ではデフォルトで無効 (mysql_native_password=ON で有効化可能)、9.0 で削除された。","since":"MySQL 8.0","tags":["security audit","mysql.user","mysql_native_password","super","privileges","audit"]},{"id":"upgrade-checker-84","task":"8.0 → 8.4 LTS アップグレードの事前チェック (util.checkForServerUpgrade)","category":"アップグレード","command":"# State the target version explicitly; the Shell must be the same version as the target or newer\nmysqlsh root@db1:3306 -- util check-for-server-upgrade --target-version=8.4.10 --output-format=TEXT\n# JSON output for automation, including a my.cnf check\nmysqlsh root@db1:3306 -- util check-for-server-upgrade --target-version=8.4.10 --output-format=JSON --config-path=/etc/my.cnf > /tmp/upgrade_check.json","what":"現在のサーバーを対象バージョンと照合する: 削除された変数と権限、デフォルト値が変わったパラメータ、レガシー認証方式、無効な列定義、外部キーおよびパーティションの問題。エラーレベルの指摘事項はアップグレードをブロックする。","when":"すべてのメジャー / LTS アップグレードの前に実行し、指摘事項を修正した後に再実行する。","caution":"警告も確認する: 8.4 では innodb_io_capacity (10000)、innodb_log_buffer_size (64 MB)、innodb_adaptive_hash_index (OFF)、innodb_change_buffering (none)、innodb_buffer_pool_instances、group_replication_consistency などのデフォルト値が変わり、性能に影響する可能性がある。現在の動作を維持したい値は my.cnf で固定する。SET_USER_ID などの削除された権限はアップグレード中に削除される。まずレプリカをアップグレードし、負荷下で監視してから切り替える。8.4 から 8.0 へのバイナリダウングレードはサポートされないため、フォールバック手段は論理バックアップか旧バージョンのまま残したレプリカとなる。","note":"8.4 で削除されたもの: START / STOP SLAVE、SHOW SLAVE STATUS、CHANGE MASTER TO などの旧レプリケーション構文、default_authentication_plugin (authentication_policy に置き換え)、binlog_transaction_dependency_tracking、mysqlpump。mysql_native_password はデフォルトで無効。","since":"MySQL Shell 8.0","tags":["upgrade","8.4","checkforserverupgrade","mysqlsh","lts","version upgrade"]},{"id":"charset-utf8mb4-convert","task":"latin1 / utf8mb3 テーブルを utf8mb4 に変換する","category":"メンテナンス","command":"-- Columns that are not utf8mb4\nSELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME, COLUMN_TYPE\nFROM information_schema.COLUMNS\nWHERE CHARACTER_SET_NAME IS NOT NULL AND CHARACTER_SET_NAME <> 'utf8mb4'\n  AND TABLE_SCHEMA NOT IN ('mysql', 'sys', 'information_schema', 'performance_schema')\nORDER BY TABLE_SCHEMA, TABLE_NAME;\n\n-- Generate conversion DDL for tables whose default charset is not utf8mb4\nSELECT CONCAT('ALTER TABLE `', t.TABLE_SCHEMA, '`.`', t.TABLE_NAME,\n              '` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, ALGORITHM=COPY, LOCK=SHARED;') AS ddl\nFROM information_schema.TABLES t\nJOIN information_schema.COLLATIONS c ON c.COLLATION_NAME = t.TABLE_COLLATION\nWHERE c.CHARACTER_SET_NAME <> 'utf8mb4' AND t.TABLE_TYPE = 'BASE TABLE'\n  AND t.TABLE_SCHEMA NOT IN ('mysql', 'sys', 'information_schema', 'performance_schema');\n\n-- Schema default and a single table\nALTER DATABASE legacy CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;\nALTER TABLE legacy.cust CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, ALGORITHM=COPY, LOCK=SHARED;","what":"utf8mb4 でない列とテーブルを特定し、変換 DDL を生成する。CONVERT TO はテーブルのデフォルトとすべての文字列を変更し、絵文字 / 4 バイト文字を使用可能にする。","when":"5.x から移行したスキーマ、'Incorrect string value' (1366) エラーの発生時、照合順序の異なる列同士の結合でインデックスが使えない場合に。","caution":"CONVERT TO は COPY でテーブルを書き換え、その間書き込みをブロックする (INPLACE はサポートされない)。大きなテーブルでは同じ --alter を pt-online-schema-change / gh-ost で実行する。utf8mb4 は 1 文字あたり 4 バイトを使用するため、インデックス付きの VARCHAR(255) は 1020 バイトになる。上限は DYNAMIC / COMPRESSED 行フォーマットで 3072 バイト、COMPACT / REDUNDANT で 767 バイトであり、これを超えるとエラー 1071 となる。VARCHAR / TEXT 列は、同じ文字容量を維持するために必要に応じてより大きな型に昇格される (TEXT → MEDIUMTEXT)。照合順序の変更はソートと比較に影響する: utf8mb4_0900_ai_ci はアクセントと大文字小文字を区別しないため、以前は異なっていた値が一意インデックスで衝突する可能性がある (1062)。結合されるテーブルはまとめて変換する。クライアント接続も utf8mb4 を使用する必要がある。","note":"utf8 (utf8mb3) は 8.0 で非推奨となり、8.0.30 以降は SHOW CREATE TABLE で utf8mb3 と表示される。トルコ語の照合規則 (ドット付き / ドットなしの I) には utf8mb4_tr_0900_ai_ci を使用する。8.0 のデフォルトは utf8mb4 / utf8mb4_0900_ai_ci。","since":"MySQL 8.0","tags":["utf8mb4","character set","collation","convert","emoji","charset"]}]},"recipes/mssql.json":{"engineId":"mssql","engine":"SQL Server","order":4,"recipes":[{"id":"backup-log","task":"トランザクションログのバックアップを取得する","category":"バックアップとログ","command":"BACKUP LOG [Customer]\nTO DISK = N'D:\\Backup\\Customer_log_20260706_1200.trn'\nWITH COMPRESSION, CHECKSUM, STATS = 10;","what":"トランザクションログのバックアップを取得し、(FULL/BULK_LOGGED 復旧モデルでは) ログの使用済み部分を切り捨てて再利用可能にする。","when":"FULL 復旧モデルで定期的に (例: 15 分ごと)、ポイントインタイムリカバリのチェーンのため、およびログファイルが増大した場合に。","caution":"FULL/BULK_LOGGED 復旧モデルでのみ意味がある (SIMPLE ではログは自動的に切り捨てられる)。ログチェーンを途切れさせないよう、先に少なくとも 1 つの FULL バックアップが必要。バックアップファイルの削除 / 上書き戦略を正しく設定する。","tags":["backup log","log backup","transaction log","trn","recovery","backup"]},{"id":"backup-full-diff","task":"FULL および DIFFERENTIAL バックアップを取得する","category":"バックアップとログ","command":"-- Full backup:\nBACKUP DATABASE [Customer]\nTO DISK = N'D:\\Backup\\Customer_full_20260706.bak'\nWITH COMPRESSION, CHECKSUM, INIT, STATS = 10;\n\n-- Differential backup:\nBACKUP DATABASE [Customer]\nTO DISK = N'D:\\Backup\\Customer_diff_20260706.bak'\nWITH DIFFERENTIAL, COMPRESSION, CHECKSUM, INIT, STATS = 10;","what":"FULL はデータベース全体をバックアップし、DIFFERENTIAL は最後の FULL 以降に変更されたエクステントをバックアップする。","when":"FULL: 日次 / 週次のベースバックアップ。DIFF: FULL 間の高速な中間バックアップ。","caution":"DIFF のリストアには、そのベースとなる FULL バックアップが必要。INIT は既存のファイルを上書きするため、ファイル名を誤るとバックアップを失う。CHECKSUM は破損を早期に検出する。","tags":["backup","full","differential","differential backup","bak","backup"]},{"id":"log-reuse-wait","task":"ログファイルが増大した理由 / 切り捨てられない理由","category":"バックアップとログ","command":"SELECT name,\n       recovery_model_desc,\n       log_reuse_wait_desc\nFROM   sys.databases\nWHERE  name = N'Customer';\n\n-- Log space usage for all databases:\nSELECT DB_NAME(database_id) AS db, name, type_desc,\n       size*8/1024        AS size_mb,\n       CAST(FILEPROPERTY(name,'SpaceUsed') AS BIGINT)*8/1024 AS used_mb\nFROM   sys.master_files\nWHERE  type_desc = 'LOG';","what":"log_reuse_wait_desc 列は、トランザクションログを切り捨てられない理由を示す (例: LOG_BACKUP、ACTIVE_TRANSACTION、REPLICATION、AVAILABILITY_REPLICA)。","when":"ログファイルが増大し続ける場合やログが満杯の場合 (エラー 9002) に根本原因を特定するため。","caution":"LOG_BACKUP と表示される場合、対処はファイルの圧縮ではなくログバックアップの取得である。照会のみでリスクなし。","tags":["log_reuse_wait_desc","log growth","sys.databases","log backup","recovery","diagnostics"]},{"id":"shrink-log","task":"ログファイルを圧縮する","category":"バックアップとログ","command":"-- First take a log backup so the log can be truncated (FULL model):\nBACKUP LOG [Customer] TO DISK = N'D:\\Backup\\Customer_log_pre_shrink.trn' WITH COMPRESSION;\n\n-- Find the logical name of the log file:\nSELECT name, type_desc FROM sys.database_files WHERE type_desc = 'LOG';\n\n-- Shrink (target 2048 MB):\nUSE [Customer];\nDBCC SHRINKFILE (N'Customer_log', 2048);","what":"トランザクションログファイルの物理サイズを縮小し、領域をオペレーティングシステムに返す。","when":"一時的な異常増大 (大規模トランザクション / インデックスの再構築) の後、ログが恒常的に肥大化したままの場合。","caution":"危険 / 注意: 定常的な圧縮は悪いプラクティスである。ログが再び増大する間は性能が低下し、VLF の断片化が増える。先にログバックアップを取得しないとサイズは減らない。不必要に増大したログファイルのみを圧縮し、データファイルは圧縮しない。その後、適切なサイズまで 1 回で拡張する。","tags":["shrink","dbcc shrinkfile","shrink log","log","vlf","caution"]},{"id":"vlf-count","task":"VLF (Virtual Log File) の数を表示する","category":"バックアップとログ","command":"-- SQL Server 2016 SP2 / 2017 and later:\nSELECT DB_NAME(database_id) AS db,\n       COUNT(*)             AS vlf_count,\n       SUM(CASE WHEN vlf_active = 1 THEN 1 ELSE 0 END) AS active_vlf\nFROM   sys.dm_db_log_info(DB_ID(N'Customer'))\nGROUP BY database_id;\n\n-- For older versions: DBCC LOGINFO('Customer'); (row count = VLF count)","what":"トランザクションログ内の仮想ログファイル (VLF) の数を返す。VLF が多すぎると、起動 / 復旧 / ログバックアップの性能が低下する。","when":"ログが遅い場合やデータベースの起動に時間がかかる場合、ログの自動拡張設定を見直す場合に。","caution":"数百 / 数千の VLF は警告サインである。対処は、ログを圧縮してから適切な大きさの増分 (例: 8GB 単位) で再拡張することである。照会のみでリスクなし。","since":"SQL Server 2016 SP2","note":"sys.dm_db_log_info DMV は SQL Server 2016 SP2 および 2017 で追加された。それ以前は、文書化されていない DBCC LOGINFO の出力行数から VLF を数えていた。","tags":["vlf","dm_db_log_info","dbcc loginfo","log","virtual log file","performance"]},{"id":"open-transaction","task":"最も古いオープントランザクションを特定する (ACTIVE_TRANSACTION)","category":"バックアップとログ","command":"USE [Customer];\nDBCC OPENTRAN;\n\n-- Detailed: show long-running open transactions and their owners:\nSELECT s.session_id, s.login_name, s.host_name, s.program_name,\n       t.transaction_id,\n       DATEDIFF(SECOND, t.transaction_begin_time, GETDATE()) AS duration_sec,\n       t.transaction_begin_time\nFROM   sys.dm_tran_active_transactions t\n  JOIN sys.dm_tran_session_transactions st ON st.transaction_id = t.transaction_id\n  JOIN sys.dm_exec_sessions s ON s.session_id = st.session_id\nORDER BY t.transaction_begin_time;","what":"最も古いオープン中 (コミットもロールバックもされていない) のトランザクションと、それを保持しているセッションを表示する。オープン中のトランザクションはログの切り捨てを妨げる (LOG_REUSE_WAIT = ACTIVE_TRANSACTION)。","when":"ログバックアップを取得してもログが縮小せず、log_reuse_wait_desc = ACTIVE_TRANSACTION の場合に根本原因を特定するため。","caution":"長時間オープン中のトランザクションを保持しているセッションを KILL する前に、業務オーナーに確認する。ロールバックに長時間かかる場合がある。照会のみでリスクなし。","tags":["dbcc opentran","open transaction","active_transaction","dm_tran_active_transactions","log","diagnostics"]},{"id":"add-data-file","task":"データベースにデータファイルを追加する","category":"ストレージ","command":"ALTER DATABASE [Customer]\nADD FILE (\n  NAME = N'Customer_data2',\n  FILENAME = N'E:\\Data\\Customer_data2.ndf',\n  SIZE = 4GB,\n  FILEGROWTH = 512MB,\n  MAXSIZE = 100GB\n) TO FILEGROUP [PRIMARY];","what":"既存のファイルグループに新しいデータファイル (.ndf) を追加し、容量を増やして I/O を分散する。","when":"ディスクが満杯の場合、または複数のディスクに I/O を分散したい場合。","caution":"新しいファイルへの書き込みは比例フィルによって分散され、最も空いているファイルから先に埋まる。FILEGROWTH はパーセントではなく固定 MB で指定する。MAXSIZE を設定すると無制限な増大を防げる。","tags":["add file","add data file","ndf","alter database","filegroup","storage"]},{"id":"add-filegroup","task":"ファイルグループを追加する","category":"ストレージ","command":"-- 1) Create the filegroup:\nALTER DATABASE [Customer] ADD FILEGROUP [FG_Archive];\n\n-- 2) Add a file to it:\nALTER DATABASE [Customer]\nADD FILE (\n  NAME = N'Customer_archive1',\n  FILENAME = N'F:\\Data\\Customer_archive1.ndf',\n  SIZE = 8GB, FILEGROWTH = 1GB\n) TO FILEGROUP [FG_Archive];\n\n-- (Optional) make it the default filegroup:\n-- ALTER DATABASE [Customer] MODIFY FILEGROUP [FG_Archive] DEFAULT;","what":"ファイルを含む新しいファイルグループを作成する。テーブル / インデックスを別のディスク / ファイルグループに配置できる。","when":"アーカイブ / コールドデータの分離、ファイルグループ単位のバックアップ / リストア、I/O の分離に。","caution":"空のファイルグループはバックアップ / 使用できないため、少なくとも 1 つのファイルを追加する。デフォルトを変更すると、新しいオブジェクトの配置先に影響する。","tags":["filegroup","filegroup","add filegroup","alter database","ndf","storage"]},{"id":"modify-file-growth","task":"ファイルサイズ / 自動拡張を変更する","category":"ストレージ","command":"-- Grow (SIZE only grows; shrinking requires shrink, not a resize):\nALTER DATABASE [Customer]\nMODIFY FILE (NAME = N'Customer_data', SIZE = 20GB);\n\n-- Set autogrowth (fixed MB recommended):\nALTER DATABASE [Customer]\nMODIFY FILE (NAME = N'Customer_data', FILEGROWTH = 1GB, MAXSIZE = 200GB);\n\n-- Disable autogrowth:\nALTER DATABASE [Customer]\nMODIFY FILE (NAME = N'Customer_log', FILEGROWTH = 0);","what":"データ / ログファイルを事前に拡張する、またはその自動拡張の増分 / 上限を設定する。","when":"小刻みな自動拡張による無秩序な増大を是正する、領域を事前に割り当てる、または MAXSIZE を設定するため。","caution":"パーセントベースの自動拡張は、大きなファイルでは非常に大きな増分になるため、固定 MB を使用する。Instant File Initialization がない場合、データファイルの拡張はブロックを引き起こす。SIZE ではファイルを縮小できない (圧縮が必要)。","tags":["modify file","autogrowth","filegrowth","size","alter database","storage"]},{"id":"move-file","task":"データ / ログファイルを別の場所に移動する","category":"ストレージ","command":"-- 1) Tell SQL Server the new path (nothing is moved yet):\nALTER DATABASE [Customer]\nMODIFY FILE (NAME = N'Customer_data',\n             FILENAME = N'G:\\Data\\Customer_data.mdf');\n\n-- 2) Take the database offline:\nALTER DATABASE [Customer] SET OFFLINE WITH ROLLBACK IMMEDIATE;\n\n-- 3) Physically copy/move the file to the new path AT THE OPERATING SYSTEM level (G:\\Data\\...).\n\n-- 4) Bring it online:\nALTER DATABASE [Customer] SET ONLINE;","what":"データベースファイルの物理的な場所を変更する: 新しいパスをメタデータに定義し、データベースをオフラインにしている間にファイルを物理的に移動してから、データベースをオンラインにする。","when":"ディスクを交換する場合や、領域確保のために別のドライブへ移動する場合。","caution":"OFFLINE + ROLLBACK IMMEDIATE はすべてのアクティブな接続を切断するため、ダウンタイムを計画する。OS 上で実際にファイルを新しいパスへコピーする前にデータベースを ONLINE にすると、データベースは SUSPECT になる。tempdb には別の方法が必要 (MODIFY FILE + SQL Server サービスの再起動)。","tags":["move file","move file","modify file","offline","online","mdf","ldf","storage"]},{"id":"add-tempdb-file","task":"tempdb にデータファイルを追加する","category":"ストレージ","command":"-- Show current tempdb files:\nSELECT name, physical_name, size*8/1024 AS size_mb, growth\nFROM   sys.master_files WHERE database_id = DB_ID(N'tempdb');\n\n-- Add a new file (up to the number of CPU cores, equally sized):\nALTER DATABASE [tempdb]\nADD FILE (\n  NAME = N'tempdev2',\n  FILENAME = N'T:\\tempdb\\tempdb_mssql_2.ndf',\n  SIZE = 8GB, FILEGROWTH = 1GB\n);","what":"tempdb にデータファイルを追加して、割り当て (PFS/GAM/SGAM) の競合を減らし I/O を分散する。","when":"tempdb の競合 (PAGELATCH_UP 待機) や tempdb の使用量が多いシステムで。","caution":"tempdb のすべてのデータファイルは、同じサイズと同じ拡張増分にする必要がある (比例フィルのため)。追加したファイルは再起動なしですぐに使用される。既存ファイルのサイズが異なる場合は先にすべて揃える。そうしないと新しい (空の) ファイルに不均衡な負荷がかかる。ファイル数は通常コア数に合わせる (最大 8)。SQL Server 2016 以降のセットアップはデフォルトでこれを行う。","tags":["tempdb","add file","tempdb file","ndf","contention","pagelatch","storage"]},{"id":"index-rebuild-reorg","task":"インデックスの再構築 / 再構成","category":"メンテナンス","command":"-- Rebuild (high fragmentation > 30%). ONLINE requires Enterprise:\nALTER INDEX IX_Customer_Email ON dbo.Customer\n  REBUILD WITH (ONLINE = ON, MAXDOP = 4, SORT_IN_TEMPDB = ON);\n\n-- All indexes of a table:\nALTER INDEX ALL ON dbo.Customer REBUILD WITH (FILLFACTOR = 90);\n\n-- Reorganize (moderate fragmentation 5-30%, always online, can be stopped):\nALTER INDEX IX_Customer_Email ON dbo.Customer REORGANIZE;","what":"REBUILD はインデックスをゼロから再作成する (断片化を完全に解消し、統計を更新する)。REORGANIZE はリーフレベルをその場で圧縮する (軽量、非ブロッキング)。","when":"断片化が 5〜30% なら REORGANIZE、30% を超えるなら REBUILD。大きなテーブルではメンテナンス時間帯に実施する。","caution":"ONLINE = ON は Enterprise/Developer でのみ使用可能。Standard では OFF を使用する (テーブルがロックされる)。REBUILD は大量のログを生成し、領域を必要とする。MAXDOP と SORT_IN_TEMPDB はリソース使用量に影響する。","tags":["index","rebuild","reorganize","alter index","fragmentation","maintenance","online"]},{"id":"update-statistics","task":"統計を更新する","category":"メンテナンス","command":"-- Single table, full scan:\nUPDATE STATISTICS dbo.Customer WITH FULLSCAN;\n\n-- Specific statistic, with sampling:\nUPDATE STATISTICS dbo.Customer IX_Customer_Email WITH SAMPLE 30 PERCENT;\n\n-- Bulk for the whole database (user tables), sampled:\nEXEC sys.sp_updatestats;","what":"オプティマイザが使用する列 / インデックスの統計を更新し、正しい実行計画とカーディナリティ推定を確保する。","when":"大量のデータ変更 / ロードの後、または実行計画の性能低下時に。インデックスの再構築では統計が完全に更新されるため、別途更新する必要はない。","caution":"FULLSCAN は正確だがコストが高く、大きなテーブルでは I/O 負荷を生じる。sp_updatestats は変更された統計のみを更新し、デフォルトのサンプリングを使用する。インデックスの REBUILD 後に同じインデックスに対して UPDATE STATISTICS を再実行する必要はない。","tags":["update statistics","statistics","sp_updatestats","fullscan","optimizer","maintenance"]},{"id":"dbcc-checkdb","task":"整合性チェック (DBCC CHECKDB)","category":"メンテナンス","command":"-- Full integrity check:\nDBCC CHECKDB (N'Customer') WITH NO_INFOMSGS, ALL_ERRORMSGS;\n\n-- Lighter on large databases (physical consistency):\nDBCC CHECKDB (N'Customer') WITH PHYSICAL_ONLY, NO_INFOMSGS;","what":"データベースの物理的・論理的整合性 (ページ構造、割り当て、インデックスの整合性) をチェックし、破損を報告する。","when":"定期メンテナンス (週次)、ハードウェア / IO の問題が疑われる場合、823/824 エラーの後に。","caution":"I/O と tempdb を大量に使用するため、メンテナンス時間帯に実行する。エラーが見つかった場合、REPAIR_ALLOW_DATA_LOSS は最後の手段であり、データ損失を引き起こす。まず正常なバックアップからのリストアを検討する。PHYSICAL_ONLY は高速だが論理チェックを省略する。","tags":["dbcc checkdb","integrity","corruption","corruption","integrity","maintenance"]},{"id":"index-fragmentation","task":"インデックスの断片化を表示する","category":"メンテナンス","command":"SELECT OBJECT_SCHEMA_NAME(ips.object_id) AS schema_name,\n       OBJECT_NAME(ips.object_id)        AS table_name,\n       i.name                            AS index_name,\n       ips.index_type_desc,\n       ROUND(ips.avg_fragmentation_in_percent,1) AS frag_pct,\n       ips.page_count\nFROM   sys.dm_db_index_physical_stats(DB_ID(N'Customer'), NULL, NULL, NULL, 'LIMITED') ips\n  JOIN sys.indexes i\n    ON i.object_id = ips.object_id AND i.index_id = ips.index_id\nWHERE  ips.avg_fragmentation_in_percent > 10\n  AND  ips.page_count > 1000\nORDER BY ips.avg_fragmentation_in_percent DESC;","what":"インデックスの断片化率とページ数を一覧表示する。再構築 / 再構成の判断の基準となる。","when":"メンテナンスの前に、対処すべきインデックスを決定するため。","caution":"小さなインデックス (< 1000 ページ) では断片化は問題にならないため、除外される。'DETAILED' モードはより正確だが非常にコストが高い。通常は 'LIMITED' で十分。照会のみでリスクなし。","tags":["fragmentation","dm_db_index_physical_stats","index","frag","maintenance","diagnostics"]},{"id":"kill-spid","task":"セッション (SPID) を強制終了する","category":"セッション","command":"-- First find the offending SPID:\nSELECT s.session_id, s.login_name, s.host_name, s.program_name,\n       r.status, r.command, r.wait_type, r.blocking_session_id,\n       DB_NAME(r.database_id) AS db\nFROM   sys.dm_exec_sessions s\n  LEFT JOIN sys.dm_exec_requests r ON r.session_id = s.session_id\nWHERE  s.is_user_process = 1;\n\n-- Kill (example SPID 63):\nKILL 63;\n\n-- Show rollback progress:\nKILL 63 WITH STATUSONLY;","what":"指定した session_id (SPID) を終了する。そのオープン中のトランザクションはロールバックされる。","when":"ロックを保持している、暴走 / 長時間クエリを実行している、または接続を解放しないセッションを停止するため。","caution":"大きなオープントランザクションでは、ロールバックに長時間かかり、キャンセルできない。進捗は KILL WITH STATUSONLY で監視する。システム SPID (is_user_process=0) を強制終了しない。正しい SPID であることを確認する。","tags":["kill","spid","kill session","dm_exec_sessions","dm_exec_requests","session"]},{"id":"blocking-chain","task":"ブロッキング (ロック) チェーンを特定する","category":"セッション","command":"SELECT r.session_id            AS waiting_spid,\n       r.blocking_session_id  AS blocking_spid,\n       r.wait_type,\n       r.wait_time / 1000.0   AS wait_sec,\n       r.status, r.command,\n       DB_NAME(r.database_id) AS db,\n       t.text                 AS waiting_query\nFROM   sys.dm_exec_requests r\n  CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t\nWHERE  r.blocking_session_id <> 0\nORDER BY r.wait_time DESC;\n\n-- To find the head (root) blocker of the chain, look for the SPID whose\n-- own blocking_session_id is not set (it is not blocked itself).","what":"待機中のセッションとそれをブロックしているセッションを、待機時間と実行中のクエリとともに一覧表示し、ロックチェーンを可視化する。","when":"「アプリケーションが応答しない / タイムアウトする」という苦情に対し、ロック競合の発生源を特定するため。","caution":"ルートブロッカー (誰にもブロックされていないが他をブロックしている SPID) を強制終了する前に、業務オーナーに確認する。照会のみでリスクなし。","tags":["blocking","lock","lock","dm_exec_requests","blocking_session_id","session","chain"]},{"id":"active-queries","task":"アクティブなクエリとそのコストを表示する","category":"セッション","command":"SELECT r.session_id,\n       r.status,\n       r.command,\n       DB_NAME(r.database_id) AS db,\n       r.cpu_time,\n       r.total_elapsed_time / 1000 AS elapsed_sec,\n       r.reads, r.writes, r.logical_reads,\n       r.wait_type,\n       SUBSTRING(t.text,\n         (r.statement_start_offset/2)+1,\n         ((CASE r.statement_end_offset WHEN -1 THEN DATALENGTH(t.text)\n            ELSE r.statement_end_offset END - r.statement_start_offset)/2)+1) AS running_statement\nFROM   sys.dm_exec_requests r\n  JOIN sys.dm_exec_sessions s ON s.session_id = r.session_id\n  CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t\nWHERE  s.is_user_process = 1 AND r.session_id <> @@SPID\nORDER BY r.total_elapsed_time DESC;","what":"現在実行中のユーザークエリを、CPU、経過時間、読み取り / 書き込み、正確なステートメントテキストとともに表示する。","when":"稼働中の性能低下時に、どのクエリがリソースを消費しているかを特定するため。","caution":"statement_start/end_offset により、(バッチ全体ではなく) 実行中の正確なステートメントを抽出する。照会のみでリスクなし。","tags":["active queries","active query","dm_exec_requests","dm_exec_sql_text","cpu","session"]},{"id":"sp-configure-memory","task":"sp_configure で設定する (max server memory)","category":"構成","command":"-- Make advanced options visible:\nEXEC sys.sp_configure 'show advanced options', 1;\nRECONFIGURE;\n\n-- Set max server memory (MB). Example: allow 24 GB:\nEXEC sys.sp_configure 'max server memory (MB)', 24576;\nRECONFIGURE;\n\n-- Verify:\nEXEC sys.sp_configure 'max server memory (MB)';","what":"SQL Server がバッファプールに使用できる最大メモリを制限し、オペレーティングシステムやその他のコンポーネント用に RAM を残す。","when":"サーバー上の OS / 他のサービスがメモリ不足になっている場合、または RAM を増設した場合。","caution":"オペレーティングシステム、SSAS/SSIS、CLR、スレッドスタック用に十分な RAM を残す (OS 用に通常少なくとも 4〜6 GB)。低く設定しすぎると SQL Server の性能が著しく低下する。RECONFIGURE なしでは変更は適用されない。この設定は動的 (再起動不要)。","tags":["sp_configure","max server memory","reconfigure","memory","configuration","memory"]},{"id":"reconfigure-general","task":"一般的な sp_configure 設定と RECONFIGURE","category":"構成","command":"EXEC sys.sp_configure 'show advanced options', 1;\nRECONFIGURE;\n\n-- Example: cost threshold for parallelism and MAXDOP:\nEXEC sys.sp_configure 'cost threshold for parallelism', 50;\nEXEC sys.sp_configure 'max degree of parallelism', 4;\nRECONFIGURE;\n\n-- Show all configured/running values:\nSELECT name, value AS configured, value_in_use AS running, is_dynamic, is_advanced\nFROM   sys.configurations\nORDER BY name;","what":"サーバーレベルの構成値を設定する。RECONFIGURE で実行値に適用する。","when":"MAXDOP、並列処理のしきい値、optimize for ad hoc workloads などのサーバー設定を変更する場合。","caution":"is_dynamic = 0 の設定は SQL Server の再起動が必要。RECONFIGURE WITH OVERRIDE は一部の設定で検証を省略するため、慎重に使用する。変更前に value_in_use を記録しておく。","tags":["sp_configure","reconfigure","maxdop","cost threshold","sys.configurations","configuration"]},{"id":"ag-failover","task":"可用性グループのフェイルオーバー","category":"構成","command":"-- Run on the TARGET (secondary) REPLICA - planned, no data loss (synchronous):\nALTER AVAILABILITY GROUP [AG_Customer] FAILOVER;\n\n-- Forced (asynchronous replica / primary unreachable, DATA LOSS risk):\n-- ALTER AVAILABILITY GROUP [AG_Customer] FORCE_FAILOVER_ALLOW_DATA_LOSS;\n\n-- Check status:\nSELECT ag.name, ar.replica_server_name,\n       rs.role_desc, rs.synchronization_health_desc, ar.availability_mode_desc\nFROM   sys.availability_groups ag\n  JOIN sys.availability_replicas ar ON ar.group_id = ag.group_id\n  JOIN sys.dm_hadr_availability_replica_states rs ON rs.replica_id = ar.replica_id;","what":"可用性グループのプライマリロールを別のレプリカに移動する。同期レプリカへの計画的フェイルオーバーはデータ損失なしで行われる。","when":"メンテナンス / パッチ適用のためのロール移行、プライマリノード障害時のフェイルオーバー。","caution":"通常の FAILOVER コマンドは、引き継ぐ側のセカンダリレプリカで実行する。FORCE_FAILOVER_ALLOW_DATA_LOSS はプライマリに到達できない場合または非同期レプリカでのみ使用し、データ損失を引き起こす可能性がある。同期が正常でない場合は細心の注意を払う。","tags":["availability group","ag","failover","hadr","failover","alwayson","configuration"]},{"id":"change-recovery-model","task":"データベースの復旧モデルを変更する","category":"構成","command":"-- Show the current model:\nSELECT name, recovery_model_desc FROM sys.databases WHERE name = N'Customer';\n\n-- FULL recovery (for point-in-time recovery):\nALTER DATABASE [Customer] SET RECOVERY FULL;\n\n-- SIMPLE recovery (log truncated automatically, no log backups needed):\n-- ALTER DATABASE [Customer] SET RECOVERY SIMPLE;\n\n-- BULK_LOGGED (temporary, for large bulk operations):\n-- ALTER DATABASE [Customer] SET RECOVERY BULK_LOGGED;","what":"データベースの復旧モデルを変更する。ログの管理方法と利用可能な復旧オプションが決まる。","when":"FULL: ポイントインタイムリカバリ / ログバックアップ / AG が必要な場合。SIMPLE: 復旧ポイントを必要としないシステム (開発 / テスト、DW)。","caution":"FULL に切り替えた後は、FULL バックアップを取得してログチェーンを開始し、定期的なログバックアップを設定する。そうしないとログが増大し続ける。FULL から SIMPLE に切り替えるとログチェーンが途切れ、ポイントインタイムリカバリができなくなる。AG のメンバーは FULL 復旧モデルである必要がある。","tags":["recovery model","recovery full","simple","bulk_logged","alter database","configuration"]}]},"recipes/mssql-ext.json":{"engineId":"mssql","engine":"SQL Server","order":2,"recipes":[{"id":"ag-health-lag","task":"可用性グループの正常性と遅延を監視する (log send / redo キュー、RPO)","category":"Always On と HA","command":"-- Replica health (run on the primary to see all replicas):\nSELECT ag.name AS ag_name, ar.replica_server_name, ars.role_desc,\n       ar.availability_mode_desc, ar.failover_mode_desc,\n       ars.connected_state_desc, ars.synchronization_health_desc,\n       ars.operational_state_desc, ars.last_connect_error_description\nFROM   sys.availability_groups ag\n  JOIN sys.availability_replicas ar                ON ar.group_id = ag.group_id\n  JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = ar.replica_id\nORDER BY ag.name, ars.role_desc;\n\n-- Per-database lag: log send queue (RPO), redo queue (RTO):\nSELECT ag.name AS ag_name, ar.replica_server_name, DB_NAME(drs.database_id) AS db,\n       drs.is_primary_replica, drs.synchronization_state_desc, drs.synchronization_health_desc,\n       drs.is_suspended, drs.suspend_reason_desc,\n       drs.log_send_queue_size  AS log_send_queue_kb,\n       drs.log_send_rate        AS log_send_kb_s,\n       drs.redo_queue_size      AS redo_queue_kb,\n       drs.redo_rate            AS redo_kb_s,\n       CAST(drs.redo_queue_size * 1.0 / NULLIF(drs.redo_rate, 0) AS DECIMAL(18,1)) AS est_redo_catchup_s,\n       drs.last_commit_time,\n       DATEDIFF(SECOND, drs.last_commit_time, pri.last_commit_time) AS data_loss_window_s,\n       drs.secondary_lag_seconds\nFROM   sys.dm_hadr_database_replica_states drs\n  JOIN sys.availability_replicas ar ON ar.replica_id = drs.replica_id\n  JOIN sys.availability_groups ag   ON ag.group_id = drs.group_id\n  LEFT JOIN sys.dm_hadr_database_replica_states pri\n         ON pri.group_database_id = drs.group_database_id AND pri.is_primary_replica = 1\nORDER BY ag.name, db, drs.is_primary_replica DESC;\n\n-- WSFC quorum state:\nSELECT cluster_name, quorum_type_desc, quorum_state_desc FROM sys.dm_hadr_cluster;\nSELECT member_name, member_type_desc, member_state_desc, number_of_quorum_votes\nFROM   sys.dm_hadr_cluster_members;","what":"レプリカの接続と同期の正常性を表示する。データベースごとに log send キュー、redo キュー、送信 / redo レート、redo の推定追いつき時間、プライマリとの最終コミットの差 (潜在的なデータ損失期間) を表示し、WSFC クォーラムの状態も返す。","when":"AG ダッシュボードで NOT_HEALTHY / NOT SYNCHRONIZING アラートが出た場合、計画的フェイルオーバー前に RPO/RTO を確認する場合、または読み取り可能セカンダリでデータが古いとユーザーから報告された場合。","caution":"log_send_queue の増加は、プライマリに障害が発生した場合に失われるログの量 (RPO) である。redo_queue の増加は、フェイルオーバー後にデータベースがオンラインになるまでの時間 (RTO) である。セカンダリではローカルレプリカのみが見えるため、全体像を把握するにはプライマリで実行する。data_loss_window_s は書き込みトラフィックがある間のみ意味を持つ。読み取り専用クエリのため安全。","since":"2016","note":"secondary_lag_seconds は 2016 以降の列。redo キューが増え続ける場合は、セカンダリの redo スレッドがブロックされていないか (長時間の読み取りクエリ、DDL) を確認し、REDO_THREAD_PENDING_WORK / PARALLEL_REDO_* 待機を調べる。","tags":["availability group","ag","log send queue","redo queue","synchronization","rpo"],"untested":true},{"id":"ag-forced-failover-dr","task":"強制フェイルオーバー (FORCE_FAILOVER_ALLOW_DATA_LOSS) とフェイルオーバー後の復旧","category":"Always On と HA","command":"-- 1) On each candidate secondary: pick the most current one (highest end_of_log_lsn)\nSELECT ag.name AS ag_name, DB_NAME(drs.database_id) AS db,\n       drs.synchronization_state_desc, drs.end_of_log_lsn, drs.last_commit_time\nFROM   sys.dm_hadr_database_replica_states drs\n  JOIN sys.availability_groups ag ON ag.group_id = drs.group_id\nWHERE  drs.is_local = 1;\n\n-- 2) On the chosen replica (while the primary is unreachable):\nALTER AVAILABILITY GROUP [AG_Musteri] FORCE_FAILOVER_ALLOW_DATA_LOSS;\n\n-- 3) On the other secondaries, resume the suspended data movement:\nALTER DATABASE [Musteri] SET HADR RESUME;\n\n-- 4) When the old primary returns (now a SUSPENDED secondary):\n--    take a snapshot first to inspect the lost transactions, then resume\nCREATE DATABASE [Musteri_lost_snap]\n  ON (NAME = N'Musteri', FILENAME = N'D:\\Data\\Musteri_lost_snap.ss')\n  AS SNAPSHOT OF [Musteri];\nALTER DATABASE [Musteri] SET HADR RESUME;","what":"プライマリが完全に失われた場合に、データ損失を受け入れて DR レプリカをプライマリにする。その後、他のレプリカで中断されたデータ移動を再開し、旧プライマリが復帰したら、新しいプライマリに到達しなかったトランザクションを調べるためにスナップショットを取得する。","when":"プライマリデータセンターがダウンした場合、非同期レプリカしか残っていない場合、または同期レプリカが SYNCHRONIZED でないにもかかわらずフェイルオーバーが必要な場合。","caution":"データ損失: 最後に確定 (hardened) した LSN 以降のトランザクションは失われる。先に業務側から RPO の承認を得る。強制フェイルオーバー後、すべてのセカンダリデータベースは SUSPENDED になる。HADR RESUME まではログが切り捨てられず増大し続ける。WSFC クォーラムが失われている場合は、先にクォーラムを強制してクラスタを起動する (PowerShell: Start-ClusterNode -FixQuorum)。そうしないとコマンドは失敗する。旧プライマリで HADR RESUME を実行すると、失われたトランザクションは完全に破棄される。スナップショットを取得せずに再開しない。","note":"データ損失なしの計画的フェイルオーバーには、ag-failover レシピの FAILOVER コマンドを使用する。CLUSTER_TYPE = NONE / EXTERNAL の AG でも FORCE_FAILOVER_ALLOW_DATA_LOSS を使用する。EXTERNAL (Pacemaker) ではフェイルオーバーはクラスタマネージャーが制御する。スナップショットにはソースのすべての論理データファイルが必要。複数ファイルのデータベースでは、データファイルごとに ON エントリを 1 つ追加する。","tags":["force failover","allow data loss","dr","availability group","hadr resume","data loss"],"untested":true},{"id":"ag-add-db-autoseed","task":"データベースを AG に追加し (自動シード処理)、シード処理の進捗を監視する","category":"Always On と HA","command":"-- Prerequisite (primary): FULL recovery and at least one FULL backup\nSELECT name, recovery_model_desc FROM sys.databases WHERE name = N'Musteri';\nBACKUP DATABASE [Musteri] TO DISK = N'D:\\Backup\\Musteri_pre_ag.bak' WITH COMPRESSION, CHECKSUM, INIT;\n\n-- 1) Primary: switch the replica to automatic seeding\nALTER AVAILABILITY GROUP [AG_Musteri]\n  MODIFY REPLICA ON N'SQL02' WITH (SEEDING_MODE = AUTOMATIC);\n\n-- 2) On each secondary: allow the AG to create databases\nALTER AVAILABILITY GROUP [AG_Musteri] GRANT CREATE ANY DATABASE;\n\n-- 3) Primary: add the database\nALTER AVAILABILITY GROUP [AG_Musteri] ADD DATABASE [Musteri];\n\n-- 4) Progress (primary or secondary):\nSELECT local_database_name, role_desc, internal_state_desc,\n       transferred_size_bytes / 1048576         AS transferred_mb,\n       database_size_bytes / 1048576            AS db_mb,\n       transfer_rate_bytes_per_second / 1048576 AS mb_s,\n       estimate_time_complete_utc, failure_message\nFROM   sys.dm_hadr_physical_seeding_stats;\n\n-- 5) Seeding history and failure reason:\nSELECT s.start_time, s.completion_time, adc.database_name, ar.replica_server_name,\n       s.current_state, s.failure_state_desc, s.error_code, s.number_of_attempts\nFROM   sys.dm_hadr_automatic_seeding s\n  JOIN sys.availability_databases_cluster adc ON adc.group_database_id = s.ag_db_id\n  JOIN sys.availability_replicas ar           ON ar.replica_id = s.ag_remote_replica_id\nORDER BY s.start_time DESC;","what":"手動のバックアップ / リストアなしで、エンドポイント (VDI) 経由でセカンダリにストリーミングしてデータベースを AG に追加する。シード処理のスループット、推定完了時刻、失敗理由を表示する。","when":"AG に新しいデータベースを追加する場合、新しいレプリカを追加する場合、または壊れたセカンダリデータベースを再構築する場合。","caution":"シード処理はエンドポイントのリンクを飽和させ、デフォルトでは非圧縮である。非常に大きなデータベースや低速な WAN では、手動のバックアップ / リストア + JOIN の方が予測しやすい。シード処理中はプライマリのログが切り捨てられない (log_reuse_wait_desc = AVAILABILITY_REPLICA)。2016 ではセカンダリにプライマリと同じデータ / ログフォルダーパスが必要。2017 以降は、プライマリのファイルがインスタンスの既定パスにある場合、セカンダリは自身の既定パスを使用する。TDE データベースでは、先にすべてのセカンダリで証明書をリストアする必要がある。セカンダリで GRANT CREATE ANY DATABASE がないと、シード処理は保留のままとなる。","since":"2016","note":"シード処理の圧縮はトレースフラグ 9567 で有効になる (CPU を消費する)。シード処理の開始、完了、失敗は SQL Server エラーログに書き込まれる。詳細な追跡には hadr_automatic_seeding_* および hadr_physical_seeding_* イベントで別の Extended Events セッションを作成する。SEEDING_MODE = MANUAL で元に戻す。","tags":["automatic seeding","availability group","add database","seeding_mode","dm_hadr_physical_seeding_stats","ag"],"untested":true},{"id":"ag-listener-routing","task":"リスナー、その IP、読み取り専用ルーティング構成を確認する","category":"Always On と HA","command":"-- Listener, port and IP states:\nSELECT ag.name AS ag_name, l.dns_name, l.port, l.is_conformant,\n       ip.ip_address, ip.ip_subnet_mask, ip.state_desc\nFROM   sys.availability_group_listeners l\n  JOIN sys.availability_groups ag ON ag.group_id = l.group_id\n  LEFT JOIN sys.availability_group_listener_ip_addresses ip ON ip.listener_id = l.listener_id;\n\n-- Read-only routing list: where read intent goes when X is primary:\nSELECT ag.name AS ag_name, pr.replica_server_name AS when_primary_is,\n       rl.routing_priority, sr.replica_server_name AS route_to,\n       sr.read_only_routing_url, sr.secondary_role_allow_connections_desc\nFROM   sys.availability_read_only_routing_lists rl\n  JOIN sys.availability_replicas pr ON pr.replica_id = rl.replica_id\n  JOIN sys.availability_replicas sr ON sr.replica_id = rl.read_only_replica_id\n  JOIN sys.availability_groups ag   ON ag.group_id = pr.group_id\nORDER BY ag.name, when_primary_is, rl.routing_priority;\n\n-- Replica endpoint and connection settings:\nSELECT replica_server_name, endpoint_url, read_only_routing_url,\n       secondary_role_allow_connections_desc, seeding_mode_desc, session_timeout\nFROM   sys.availability_replicas;\n\n-- Routing test from the command line (-d is required with -K ReadOnly):\n-- sqlcmd -S tcp:AGL-Musteri,1433 -d Musteri -E -M -K ReadOnly -Q \"SELECT @@SERVERNAME\"","what":"リスナーの DNS 名、ポート、各サブネット IP のクラスタ状態を表示する。読み取り専用ルーティングリスト内の各プライマリシナリオについて、読み取りインテントの接続がどのレプリカと URL にルーティングされるかを表示する。","when":"フェイルオーバー後にアプリケーションが接続できない場合、ApplicationIntent=ReadOnly の接続がプライマリに到達する場合、または新しいサブネット / レプリカを追加した場合。","caution":"読み取り専用ルーティングは、ApplicationIntent=ReadOnly と明示的なデータベースを指定してリスナー経由で行った接続でのみ機能する。インスタンス名への直接接続はルーティングされない。read_only_routing_url が空のレプリカはルーティング先になれない。マルチサブネットリスナーでは、MultiSubnetFailover=True を指定しないクライアントはフェイルオーバー後に 20〜30 秒の接続タイムアウトが発生する。読み取り専用クエリのため安全。","note":"2016 以降の負荷分散では、ルーティングリストに入れ子の括弧を使用する: READ_ONLY_ROUTING_LIST = (('SQL02','SQL03'),'SQL01')。リスナー IP が OFFLINE と表示される場合は、クラスタ側のリソース依存関係を確認する (Failover Cluster Manager / Get-ClusterResource)。","tags":["listener","read-only routing","applicationintent","multisubnetfailover","availability group","connection"],"untested":true},{"id":"logshipping-monitor","task":"ログ配布の状態と遅延を監視する","category":"Always On と HA","command":"-- Summary (on the primary, secondary or monitor server):\nEXEC master.sys.sp_help_log_shipping_monitor;\n\n-- PRIMARY: when the last log backup was taken:\nSELECT p.primary_server, p.primary_database,\n       p.last_backup_date, p.last_backup_file,\n       DATEDIFF(MINUTE, p.last_backup_date, GETDATE()) AS backup_age_min,\n       p.backup_threshold                              AS threshold_min\nFROM   msdb.dbo.log_shipping_monitor_primary p;\n\n-- SECONDARY: copy and restore latency:\nSELECT s.secondary_server, s.secondary_database, s.primary_server,\n       s.last_copied_date, s.last_copied_file,\n       s.last_restored_date, s.last_restored_file,\n       s.last_restored_latency                           AS restore_latency_min,\n       DATEDIFF(MINUTE, s.last_restored_date, GETDATE()) AS since_last_restore_min,\n       s.restore_threshold                               AS threshold_min\nFROM   msdb.dbo.log_shipping_monitor_secondary s;\n\n-- Errors in the last 24 hours:\nSELECT e.database_name, e.agent_type, e.log_time, e.message\nFROM   msdb.dbo.log_shipping_monitor_error_detail e\nWHERE  e.log_time >= DATEADD(HOUR, -24, GETDATE())\nORDER BY e.log_time DESC;\n\n-- Secondary DB mode (RESTORING = NORECOVERY, is_in_standby = STANDBY):\nSELECT name, state_desc, is_in_standby FROM sys.databases WHERE name = N'Musteri';","what":"プライマリ上の最新ログバックアップの経過時間、セカンダリ上の最後にコピー / リストアされたファイルとリストアの遅延をしきい値とともに表示し、過去 24 時間のバックアップ / コピー / リストアジョブのエラーも表示する。","when":"ログ配布のアラートジョブが発火した場合 (エラー 14420/14421)、DR テストの前、またはセカンダリの遅れを報告する場合。","caution":"監視テーブルには、サーバーから見える側の情報のみが含まれる: プライマリテーブルはプライマリ / 監視サーバーで、セカンダリテーブルはセカンダリ / 監視サーバーで格納される。手動の (ログ配布以外の) ログバックアップはチェーンを途切れさせ、リストアジョブが失敗し続ける。アドホックなログバックアップには COPY_ONLY を使用する。STANDBY モードでは、各リストアの前にユーザー接続が切断される。読み取り専用クエリのため安全。","note":"日付列はサーバーのローカル時刻である。異なるタイムゾーンのサーバーを比較する場合は *_utc 列を使用する。リストアジョブが \"skipping log backup file\" を記録する場合、そのファイルは適用済みである。実際の欠落を見つけるには、セカンダリで RESTORE HEADERONLY を使用して FirstLSN/LastLSN の連続性を確認する。","tags":["log shipping","sp_help_log_shipping_monitor","restore latency","dr","secondary","latency"],"untested":true},{"id":"backup-copy-only","task":"チェーンを途切れさせずにアドホックバックアップを取得する (COPY_ONLY、ストライピング、スループット)","category":"バックアップとログ","command":"-- Ad-hoc FULL that does not reset the differential base:\nBACKUP DATABASE [Musteri]\nTO DISK = N'D:\\Backup\\Musteri_copyonly_20261008.bak'\nWITH COPY_ONLY, COMPRESSION, CHECKSUM, INIT, STATS = 10;\n\n-- Ad-hoc log backup that does not truncate the log:\nBACKUP LOG [Musteri]\nTO DISK = N'D:\\Backup\\Musteri_copyonly_20261008.trn'\nWITH COPY_ONLY, COMPRESSION, CHECKSUM, INIT;\n\n-- Large DB: stripe across files and tune buffers:\nBACKUP DATABASE [Musteri]\nTO DISK = N'D:\\Backup\\Musteri_s1.bak', DISK = N'E:\\Backup\\Musteri_s2.bak'\nWITH COPY_ONLY, COMPRESSION, CHECKSUM, INIT,\n     MAXTRANSFERSIZE = 4194304, BUFFERCOUNT = 64, STATS = 5;","what":"通常のバックアップチェーン (差分ベースとログチェーン) に影響しない単独の FULL またはログバックアップを取得する。大きなデータベースでは、複数ファイルへのストライピングと大きな転送サイズによってバックアップ時間を短縮できる。","when":"テスト / 開発にコピーを渡す場合、リスクのある変更の前、または監査のためにバックアップを求められた場合など、スケジュールされたバックアップ戦略に触れずにバックアップが必要なとき。","caution":"COPY_ONLY なしのアドホック FULL は、以降の DIFF バックアップのベースになる。そのファイルが削除されると DIFF は使えなくなる。COPY_ONLY は DIFFERENTIAL と併用しても効果がない。ストライプ化されたバックアップのリストアにはすべてのファイルが必要で、1 つでも失うとバックアップ全体が使用不能になる。BUFFERCOUNT x MAXTRANSFERSIZE 分のメモリがバッファプールの外に割り当てられる (例では 256 MB)。メモリが逼迫しているサーバーでは値を下げる。","note":"TDE データベースでは、バックアップ圧縮に 65536 より大きい MAXTRANSFERSIZE が必要 (2016 以降)。サーバーの既定値: sp_configure 'backup compression default' および 'backup checksum default'。2022 で Intel QAT ハードウェアがある場合、WITH COMPRESSION (ALGORITHM = QAT_DEFLATE) が使用可能。","tags":["copy_only","ad-hoc backup","stripe","maxtransfersize","buffercount","backup"]},{"id":"backup-to-url","task":"URL へのバックアップ (Azure Blob SAS / S3 互換ストレージ)","category":"バックアップとログ","command":"-- A) Azure Blob: SAS credential (named after the container URL, SECRET without a leading '?')\nCREATE CREDENTIAL [https://dbabackup.blob.core.windows.net/sql]\nWITH IDENTITY = N'SHARED ACCESS SIGNATURE',\n     SECRET   = N'sv=2022-11-02&ss=b&srt=co&sp=rwdlac&se=2027-01-01T00:00:00Z&sig=XXXX';\n\nBACKUP DATABASE [Musteri]\nTO URL = N'https://dbabackup.blob.core.windows.net/sql/Musteri_full_1.bak',\n   URL = N'https://dbabackup.blob.core.windows.net/sql/Musteri_full_2.bak'\nWITH COMPRESSION, CHECKSUM, MAXTRANSFERSIZE = 4194304, BLOCKSIZE = 65536, STATS = 10;\n\n-- B) S3-compatible storage (2022+):\nCREATE CREDENTIAL [s3://s3.eu-central-1.amazonaws.com/dba-backup/sql]\nWITH IDENTITY = N'S3 Access Key',\n     SECRET   = N'<AccessKeyID>:<SecretKeyID>';\n\nBACKUP DATABASE [Musteri]\nTO URL = N's3://s3.eu-central-1.amazonaws.com/dba-backup/sql/Musteri_full.bak'\nWITH COMPRESSION, CHECKSUM, FORMAT, STATS = 10;\n\n-- Verify (uses the same credential):\nRESTORE VERIFYONLY\nFROM URL = N's3://s3.eu-central-1.amazonaws.com/dba-backup/sql/Musteri_full.bak'\nWITH CHECKSUM;","what":"バックアップをオブジェクトストレージに直接書き込む: Azure Blob には SAS 資格情報でブロック BLOB として、2022 では S3 API 互換ストレージ (AWS S3、MinIO など) にアクセスキーの資格情報で書き込む。資格情報は URL のプレフィックスとの照合により自動的に選択される。","when":"オフサイトバックアップの要件、クラウド移行 / ハイブリッド DR のシナリオ、またはローカルのバックアップストレージが不足する場合に。","caution":"Azure では 1 つのブロック BLOB は最大 50,000 ブロックであり、MAXTRANSFERSIZE が 4 MB の場合、1 ファイルあたり約 195 GB となるため、大きなデータベースは複数の URL にストライピングする。S3 では 1 ファイルは最大 10,000 パートである。大きなデータベースでは MAXTRANSFERSIZE を引き上げ (最大 20 MB、COMPRESSION が必要)、複数の URL (最大 64) にストライピングする。S3 は INIT/追記をサポートしない。FORMAT は同名の既存バックアップを上書きする。SAS の有効期限が切れるとバックアップジョブはエラーで失敗するため、有効期限をカレンダーに登録しておく。資格情報のシークレットは master に格納され、CONTROL SERVER を持つプリンシパルが使用できる。","since":"2022","note":"SAS を使用したブロック BLOB へのバックアップは 2016 以降、S3 サポートは 2022 以降。従来のストレージアカウントキー方式 (IDENTITY = アカウント名) はページ BLOB を作成するため推奨されない。S3 ではエンドポイントの TLS 証明書がサーバーから信頼されている必要がある。MinIO などのオンプレミス製品では、ポートを URL に含める (s3://minio.local:9000/bucket/...)。","tags":["backup to url","azure blob","s3","credential","sas","cloud backup"],"untested":true},{"id":"backup-history-msdb","task":"msdb のバックアップ履歴とバックアップ欠落チェック","category":"バックアップとログ","command":"-- Last FULL / DIFF / LOG per database (never backed up first):\nSELECT d.name AS db,\n       d.recovery_model_desc,\n       MAX(CASE WHEN b.type = 'D' THEN b.backup_finish_date END) AS last_full,\n       MAX(CASE WHEN b.type = 'I' THEN b.backup_finish_date END) AS last_diff,\n       MAX(CASE WHEN b.type = 'L' THEN b.backup_finish_date END) AS last_log,\n       DATEDIFF(MINUTE, MAX(CASE WHEN b.type = 'L' THEN b.backup_finish_date END), GETDATE()) AS log_age_min\nFROM   sys.databases d\n  LEFT JOIN msdb.dbo.backupset b\n         ON b.database_name = d.name AND b.is_copy_only = 0\nWHERE  d.name <> N'tempdb'\nGROUP BY d.name, d.recovery_model_desc\nORDER BY last_full;\n\n-- Chain for one DB over the last 7 days (LSN, size, file):\nSELECT b.backup_start_date, b.backup_finish_date, b.type, b.is_copy_only,\n       b.first_lsn, b.last_lsn, b.database_backup_lsn,\n       CAST(b.backup_size / 1048576.0 AS DECIMAL(12,1))            AS size_mb,\n       CAST(b.compressed_backup_size / 1048576.0 AS DECIMAL(12,1)) AS compressed_mb,\n       b.has_backup_checksums, mf.physical_device_name\nFROM   msdb.dbo.backupset b\n  JOIN msdb.dbo.backupmediafamily mf ON mf.media_set_id = b.media_set_id\nWHERE  b.database_name = N'Musteri'\n  AND  b.backup_start_date >= DATEADD(DAY, -7, GETDATE())\nORDER BY b.backup_start_date;","what":"すべてのデータベースについて、最新の FULL/DIFF/LOG バックアップ時刻とログバックアップの経過時間を一覧表示する。1 つのデータベースについては、LSN の連続性、圧縮後サイズ、チェックサムフラグ、ファイルパスを含むバックアップチェーンを表示する。","when":"朝のチェック、リストアに必要なファイルの特定、監査での「最後のバックアップはいつか」への回答、ログ満杯アラート時にログバックアップが実行されているかの確認に。","caution":"msdb はこのインスタンスが取得したバックアップしか把握していない。別のサーバーや別の AG レプリカで取得したバックアップは見えない (AG ではすべてのレプリカを確認する)。ログバックアップの first_lsn は直前のバックアップの last_lsn と等しくなければならない。差がある場合はチェーンが途切れている。FULL 復旧モデルで last_log が NULL の場合、ログが一度もバックアップされておらず、増大し続ける。読み取り専用クエリのため安全。","note":"msdb の履歴は無制限に増大し、バックアップジョブを遅くするため、EXEC msdb.dbo.sp_delete_backuphistory @oldest_date = '2026-01-01'; で定期的に削除する。type の値: D = FULL、I = DIFF、L = LOG、F = ファイル / ファイルグループ。","tags":["backupset","msdb","backup history","last backup","lsn","backup chain"]},{"id":"backup-restore-progress","task":"バックアップ / リストア / CHECKDB の進捗と推定完了時刻を確認する","category":"バックアップとログ","command":"SELECT r.session_id, r.command, DB_NAME(r.database_id) AS db,\n       CAST(r.percent_complete AS DECIMAL(5,1))                     AS pct,\n       DATEADD(SECOND, r.estimated_completion_time / 1000, GETDATE()) AS eta,\n       r.total_elapsed_time / 60000                                 AS elapsed_min,\n       r.wait_type, r.wait_time, r.blocking_session_id\nFROM   sys.dm_exec_requests r\nWHERE  r.percent_complete > 0;\n\n-- Restore phases and throughput are in the error log:\nEXEC sys.xp_readerrorlog 0, 1, N'Restore';","what":"percent_complete を報告する長時間操作 (BACKUP、RESTORE、DBCC CHECKDB/SHRINK、ALTER INDEX REORGANIZE、KILL 後のロールバック) について、進捗率、推定終了時刻、現在の待機を表示する。","when":"夜間バックアップが業務時間にずれ込んだ場合、大規模リストア中に「いつ終わるか」に答える場合、または強制終了したセッションのロールバックを追跡する場合。","caution":"推定は進捗が線形であることを前提とする。リストアの redo/undo フェーズやログのゼロ初期化中は、進捗率が長時間停滞することがある。ログファイルは瞬時ファイル初期化の恩恵を受けない (2022 での 64 MB までの拡張を除く)。ログが大きいリストアは最初のフェーズに長時間を要する。読み取り専用クエリのため安全。","note":"wait_type が主に BACKUPIO / ASYNC_IO_COMPLETION の場合、ボトルネックはターゲット / ソースのディスクである。BACKUPTHREAD や CPU が高い場合は圧縮コストを示す。リストアの長いゼロ埋めフェーズをエラーログで詳しく確認するには、トレースフラグ 3004 + 3605 を使用する。","tags":["percent_complete","backup progress","restore progress","eta","dm_exec_requests","progress"]},{"id":"tail-log-backup","task":"リストア前にログ末尾のバックアップを取得する (NORECOVERY / NO_TRUNCATE)","category":"リストアと復旧","command":"-- A) Healthy DB: back up the tail and put the DB into RESTORING (no new writes):\nBACKUP LOG [Musteri]\nTO DISK = N'D:\\Backup\\Musteri_tail.trn'\nWITH NORECOVERY, CHECKSUM, INIT;\n\n-- B) Damaged DB / data file lost, log file intact:\n-- BACKUP LOG [Musteri]\n-- TO DISK = N'D:\\Backup\\Musteri_tail_damaged.trn'\n-- WITH NO_TRUNCATE, CONTINUE_AFTER_ERROR, INIT;\n\nSELECT name, state_desc FROM sys.databases WHERE name = N'Musteri';","what":"最後のログバックアップ以降に書き込まれたログ部分 (末尾) をバックアップする。これによりリストアチェーンが障害発生時点まで到達し、最後の数分間のトランザクションが失われない。","when":"同じデータベースに上書きリストアする前、データファイルのディスクに障害が発生した場合、または移行の最終切り替え時に。","caution":"NORECOVERY はデータベースを RESTORING 状態にし、ユーザーアクセスを終了させるため、誤ったデータベースで実行しない。ログ末尾のバックアップなしで WITH REPLACE によりリストアすると、最後のログバックアップ以降のトランザクションは完全に破棄される。NO_TRUNCATE で取得したバックアップには不完全なメタデータが含まれる場合があるため、リストア後に DBCC CHECKDB を実行する。SIMPLE 復旧モデルではログ末尾のバックアップは取得できない。","note":"リストアせずにデータベースを RESTORING から戻すには: RESTORE DATABASE [Musteri] WITH RECOVERY;。NO_TRUNCATE は COPY_ONLY + CONTINUE_AFTER_ERROR と同等で、データベースを開けない場合でもログの読み取りを試みる。","tags":["tail-log","backup log","norecovery","no_truncate","restore","recovery"]},{"id":"restore-pitr-stopat","task":"特定の時点にリストアする (ポイントインタイムリストア、STOPAT)","category":"リストアと復旧","command":"-- Restore under a side name, keep the original intact:\nRESTORE DATABASE [Musteri_PITR]\nFROM DISK = N'D:\\Backup\\Musteri_full_20261008.bak'\nWITH MOVE N'Musteri'     TO N'D:\\Data\\Musteri_PITR.mdf',\n     MOVE N'Musteri_log' TO N'D:\\Log\\Musteri_PITR_log.ldf',\n     NORECOVERY, STATS = 10;\n\nRESTORE DATABASE [Musteri_PITR]\nFROM DISK = N'D:\\Backup\\Musteri_diff_20261008.bak' WITH NORECOVERY;\n\n-- All log backups in order, each with the same STOPAT:\nRESTORE LOG [Musteri_PITR] FROM DISK = N'D:\\Backup\\Musteri_log_1200.trn'\nWITH NORECOVERY, STOPAT = '2026-10-08T14:29:00';\nRESTORE LOG [Musteri_PITR] FROM DISK = N'D:\\Backup\\Musteri_log_1500.trn'\nWITH NORECOVERY, STOPAT = '2026-10-08T14:29:00';\n\nRESTORE DATABASE [Musteri_PITR] WITH RECOVERY;\n\n-- Alternative: step forward with STANDBY and read data at each point:\n-- RESTORE LOG [Musteri_PITR] FROM DISK = N'...' WITH STANDBY = N'D:\\Backup\\Musteri_PITR_undo.dat', STOPAT = '...';","what":"FULL + (任意で) DIFF + ログバックアップを WITH NORECOVERY で適用し、指定した時刻でログの再生を停止する。データベースを誤った操作 (誤った DELETE/UPDATE、DROP) の直前の状態に戻す。","when":"誤って削除 / 更新したデータを復旧する場合、特定時点のデータを調べる場合、または監査のため。","caution":"元のデータベースに上書きするのではなく別名でリストアし、必要な行をコピーして戻す。上書きリストアが必要な場合は、先にログ末尾のバックアップを取得する。STOPAT はサーバーのローカル時刻。復旧モデルは FULL である必要がある。STOPAT の時刻を含むログバックアップに BULK_LOGGED での最小ログ記録操作が含まれる場合、そのバックアップ内で停止することはできない。RESTORE ... WITH RECOVERY の後は、それ以上ログを適用できない。","note":"すべてのログリストアで STOPAT を指定するのが推奨パターンである。それより前のファイルで \"contains records that were logged before the designated point in time\" という情報メッセージが出るのは正常。名前付きマーク (BEGIN TRAN ... WITH MARK) で停止するには STOPATMARK / STOPBEFOREMARK を使用する。正確な時刻の特定には fn_dump_dblog やアプリケーションログを使用する。","tags":["stopat","point-in-time","restore log","norecovery","standby","rollback to time"]},{"id":"restore-verify-header","task":"バックアップファイルを検査・検証する (VERIFYONLY、HEADERONLY、FILELISTONLY)","category":"リストアと復旧","command":"-- Readability and page checksum verification:\nRESTORE VERIFYONLY FROM DISK = N'D:\\Backup\\Musteri_full_20261008.bak' WITH CHECKSUM;\n\n-- Backup sets in the file (type, LSN, date, version, compression):\nRESTORE HEADERONLY FROM DISK = N'D:\\Backup\\Musteri_full_20261008.bak';\n\n-- Logical file names and sizes (needed for MOVE):\nRESTORE FILELISTONLY FROM DISK = N'D:\\Backup\\Musteri_full_20261008.bak';\n\n-- Media info (stripe count: FamilyCount):\nRESTORE LABELONLY FROM DISK = N'D:\\Backup\\Musteri_full_20261008.bak';","what":"リストアせずに、バックアップが読み取り可能でページチェックサムが有効であることを検証する。内部のバックアップセット (Position、BackupType、FirstLSN/LastLSN、DatabaseVersion)、論理ファイル名、ストライプ情報を表示する。","when":"他チームから受け取ったバックアップをリストアする前、MOVE 用のファイル名を確認する場合、バックアップジョブ後の簡易チェック、または 1 ファイルに複数セットがある場合に正しい FILE = n を選ぶため。","caution":"VERIFYONLY は、データベースがリストア可能で整合性があることを保証しない。バックアップの構造と (WITH CHECKSUM で取得した場合は) ページチェックサムのみをチェックする。確実な保証のためには、定期的なテストリストア + DBCC CHECKDB を実行する。新しいバージョンのバックアップは古いバージョンにリストアできない (DatabaseVersion を確認する)。読み取り操作のため安全。","note":"HEADERONLY で HasBackupChecksums = 0 と表示される場合、バックアップは CHECKSUM なしで取得されており、VERIFYONLY WITH CHECKSUM ではページを検証できない。INIT なしで書き込まれたファイルには複数のセットが蓄積される。リストア時に WITH FILE = <Position> を指定する。","tags":["restore verifyonly","headeronly","filelistonly","labelonly","backup verification","checksum"]},{"id":"page-restore-suspect","task":"破損ページを特定し (suspect_pages)、単一ページをリストアする","category":"リストアと復旧","command":"-- Pages that hit 823/824 or checksum errors:\nSELECT DB_NAME(sp.database_id) AS db, sp.file_id, sp.page_id,\n       CASE sp.event_type WHEN 1 THEN '823/824 error' WHEN 2 THEN 'bad checksum'\n            WHEN 3 THEN 'torn page'     WHEN 4 THEN 'restored'\n            WHEN 5 THEN 'repaired'      WHEN 7 THEN 'deallocated by DBCC' END AS event_desc,\n       sp.error_count, sp.last_update_date\nFROM   msdb.dbo.suspect_pages sp\nORDER BY sp.last_update_date DESC;\n\n-- Page restore (example 1:336): FULL + later logs + a new log backup\nRESTORE DATABASE [Musteri] PAGE = '1:336'\nFROM DISK = N'D:\\Backup\\Musteri_full_20261008.bak' WITH NORECOVERY;\nRESTORE LOG [Musteri] FROM DISK = N'D:\\Backup\\Musteri_log_1200.trn' WITH NORECOVERY;\nBACKUP LOG [Musteri] TO DISK = N'D:\\Backup\\Musteri_log_pagetail.trn' WITH INIT;\nRESTORE LOG [Musteri] FROM DISK = N'D:\\Backup\\Musteri_log_pagetail.trn' WITH RECOVERY;\n\n-- Verify:\nDBCC CHECKDB (N'Musteri') WITH NO_INFOMSGS, ALL_ERRORMSGS;","what":"msdb.dbo.suspect_pages から、I/O (823/824)、チェックサム、破損ページ (torn page) エラーが発生したページを一覧表示する。データベース全体をリストアせずに、個々の破損ページを FULL バックアップから取り出し、ログでロールフォワードして修復する。","when":"エラーログに 823/824 エラーがある場合、CHECKDB で少数のページに限定された整合性エラーがある場合、またはユーザークエリが \"incorrect checksum\" で失敗する場合。","caution":"FULL または BULK_LOGGED 復旧モデルと、途切れのないログチェーンが必要。オンラインのページリストアは Enterprise/Developer のみ。他のエディションではリストア中にデータベースがオフラインになる。割り当てページ (GAM/SGAM/PFS)、ファイルヘッダー、ブートページ (1:9) はこの方法でリストアできない。823/824 は通常ストレージの問題を意味する。ディスク / コントローラー / SAN を確認せずに対応を終えると再発する。破損ページが多い場合は、データベース全体のリストアの方が速い。","note":"suspect_pages は最大 1,000 行を保持する。満杯になると新しいエラーは記録されないため、古い行 (event_type 4/5/7) を削除する。複数ページはカンマ区切りで指定する: PAGE = '1:336, 1:337'。AG では、プライマリ上の破損ページは自動ページ修復 (sys.dm_hadr_auto_page_repair) によってセカンダリから自動的に修復される。","tags":["suspect_pages","page restore","823","824","corruption","bad page"]},{"id":"top-queries-cpu","task":"プランキャッシュ内で最もコストの高いクエリを特定する (CPU、読み取り、実行時間)","category":"パフォーマンス","command":"SELECT TOP (20)\n       qs.query_hash,\n       SUM(qs.execution_count)                                       AS execs,\n       SUM(qs.total_worker_time) / 1000                              AS total_cpu_ms,\n       SUM(qs.total_worker_time) / SUM(qs.execution_count) / 1000    AS avg_cpu_ms,\n       SUM(qs.total_elapsed_time) / SUM(qs.execution_count) / 1000   AS avg_ms,\n       SUM(qs.total_logical_reads) / SUM(qs.execution_count)         AS avg_reads,\n       SUM(qs.total_grant_kb) / SUM(qs.execution_count)              AS avg_grant_kb,\n       COUNT(DISTINCT qs.query_plan_hash)                            AS plan_count,\n       MAX(qs.last_execution_time)                                   AS last_exec,\n       MIN(SUBSTRING(st.text, qs.statement_start_offset / 2 + 1,\n           ((CASE qs.statement_end_offset WHEN -1 THEN DATALENGTH(st.text)\n             ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2) + 1)) AS statement_text,\n       MIN(DB_NAME(pa.dbid))                                         AS db\nFROM   sys.dm_exec_query_stats qs\n  CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st\n  OUTER APPLY (SELECT CONVERT(int, value) AS dbid FROM sys.dm_exec_plan_attributes(qs.plan_handle)\n               WHERE attribute = N'dbid') pa\nGROUP BY qs.query_hash\nORDER BY total_cpu_ms DESC;\n\n-- To rank by reads: ORDER BY SUM(qs.total_logical_reads) DESC\n-- Plan: SELECT query_plan FROM sys.dm_exec_query_plan(<plan_handle>);","what":"プランキャッシュ内のステートメントを query_hash でグループ化し (リテラルのみが異なるアドホッククエリは 1 行にまとめられる)、CPU、実行時間、論理読み取り、メモリ許可の合計と平均、およびプラン数を返す。","when":"CPU が張り付いている場合、「サーバーが遅い」という苦情、Query Store のないデータベース、またはすべてのデータベースにわたるサーバー全体の視点が必要な場合に。","caution":"キャッシュに残っているプランのみが対象となる: 再起動、DBCC FREEPROCCACHE、メモリ負荷、RECOMPILE によりプランが削除されたクエリは含まれない。永続的で時間範囲を指定した分析には Query Store を使用する。plan_count > 1 はパラメータ感度または異なる SET オプションを示唆する。プランキャッシュが非常に大きい場合、クエリに数秒かかることがある。安全。","since":"2016","note":"total_grant_kb は 2016 以降の列。ストアドプロシージャごとの合計には sys.dm_exec_procedure_stats を使用する。","tags":["dm_exec_query_stats","top queries","cpu","query_hash","plan cache","expensive query"]},{"id":"wait-stats-top","task":"待機統計: サーバーが何を待っているか","category":"パフォーマンス","command":"WITH w AS (\n    SELECT wait_type, waiting_tasks_count,\n           wait_time_ms / 1000.0                         AS wait_s,\n           (wait_time_ms - signal_wait_time_ms) / 1000.0 AS resource_s,\n           signal_wait_time_ms / 1000.0                  AS signal_s\n    FROM   sys.dm_os_wait_stats\n    WHERE  waiting_tasks_count > 0\n      AND  wait_type NOT LIKE N'SLEEP[_]%'\n      AND  wait_type NOT IN (\n           N'BROKER_EVENTHANDLER', N'BROKER_RECEIVE_WAITFOR', N'BROKER_TASK_STOP', N'BROKER_TO_FLUSH',\n           N'BROKER_TRANSMITTER', N'CHECKPOINT_QUEUE', N'CLR_AUTO_EVENT', N'CLR_MANUAL_EVENT',\n           N'DIRTY_PAGE_POLL', N'DISPATCHER_QUEUE_SEMAPHORE', N'FT_IFTS_SCHEDULER_IDLE_WAIT',\n           N'HADR_FILESTREAM_IOMGR_IOCOMPLETION', N'HADR_WORK_QUEUE', N'LAZYWRITER_SLEEP',\n           N'LOGMGR_QUEUE', N'ONDEMAND_TASK_QUEUE', N'PVS_PREALLOCATE', N'REQUEST_FOR_DEADLOCK_SEARCH',\n           N'SNI_HTTP_ACCEPT', N'SOS_WORK_DISPATCHER', N'SP_SERVER_DIAGNOSTICS_SLEEP',\n           N'SQLTRACE_BUFFER_FLUSH', N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP', N'WAITFOR',\n           N'XE_DISPATCHER_WAIT', N'XE_TIMER_EVENT', N'XE_LIVE_TARGET_TVF', N'PREEMPTIVE_XE_DISPATCHER',\n           N'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP', N'QDS_ASYNC_QUEUE', N'QDS_SHUTDOWN_QUEUE',\n           N'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP', N'PWAIT_ALL_COMPONENTS_INITIALIZED',\n           N'PWAIT_EXTENSIBILITY_CLEANUP_TASK', N'STARTUP_DEPENDENCY_MANAGER', N'WAIT_XTP_CKPT_CLOSE')\n)\nSELECT TOP (20) wait_type, waiting_tasks_count,\n       CAST(wait_s AS DECIMAL(18,1))                                AS wait_s,\n       CAST(100.0 * wait_s / SUM(wait_s) OVER () AS DECIMAL(5,1))   AS pct,\n       CAST(resource_s AS DECIMAL(18,1))                            AS resource_s,\n       CAST(signal_s AS DECIMAL(18,1))                              AS signal_s,\n       CAST(1000.0 * wait_s / waiting_tasks_count AS DECIMAL(18,2)) AS avg_wait_ms\nFROM   w\nORDER BY wait_s DESC;\n\n-- Values accumulate since:\nSELECT sqlserver_start_time FROM sys.dm_os_sys_info;\n\n-- User requests waiting right now:\nSELECT wt.session_id, wt.wait_type, wt.wait_duration_ms, wt.resource_description, wt.blocking_session_id\nFROM   sys.dm_os_waiting_tasks wt\n  JOIN sys.dm_exec_sessions s ON s.session_id = wt.session_id\nWHERE  s.is_user_process = 1;","what":"無害なバックグラウンド待機を除外し、サーバー全体の待機時間を待機タイプ別に、割合とリソース待機 / シグナル待機 (CPU キュー) の比率とともに内訳表示する。現在待機中のユーザーリクエストも表示する。","when":"性能調査の最初のステップとして、ボトルネック (I/O、CPU、ロック、ログ、メモリ、並列処理) を分類するため。変更前後のベースライン比較に。","caution":"値は再起動以降の累積値。現在の問題を調べるには 2 つのスナップショットを取得して差分を比較する。DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR) はサーバー全体のカウンターをリセットし、監視ツールを壊すため避ける。解釈: PAGEIOLATCH_* = ディスク読み取り、WRITELOG = ログディスク、LCK_M_* = ブロッキング、CXPACKET/CXCONSUMER = 並列処理、RESOURCE_SEMAPHORE = メモリ許可、SOS_SCHEDULER_YIELD + 高いシグナル待機 = CPU 負荷。読み取り専用クエリのため安全。","note":"セッションごとの待機には sys.dm_exec_session_wait_stats (2016 以降)、Query Store におけるクエリごとの待機カテゴリには sys.query_store_wait_stats (2017 以降) を使用する。","tags":["wait stats","dm_os_wait_stats","waits","pageiolatch","writelog","performance"]},{"id":"deadlock-system-health","task":"system_health セッションから過去のデッドロックを読み取る (デッドロックグラフ)","category":"パフォーマンス","command":"SET QUOTED_IDENTIFIER ON;  -- required for XML methods (sqlcmd/Agent default is OFF)\nWITH dl AS (\n    SELECT CAST(event_data AS XML) AS x\n    FROM   sys.fn_xe_file_target_read_file(N'system_health*.xel', NULL, NULL, NULL)\n    WHERE  object_name = N'xml_deadlock_report'\n)\nSELECT TOP (20)\n       x.value('(event/@timestamp)[1]', 'datetime2')                                          AS utc_time,\n       x.value('(event/data/value/deadlock/victim-list/victimProcess/@id)[1]', 'varchar(50)')  AS victim,\n       x.value('count(event/data/value/deadlock/process-list/process)', 'int')                 AS process_count,\n       x.value('(event/data/value/deadlock/process-list/process/@currentdbname)[1]', 'sysname') AS db,\n       x.query('event/data/value/deadlock')                                                    AS deadlock_graph\nFROM   dl\nORDER BY utc_time DESC;","what":"system_health Extended Events セッション (デフォルトで有効) の event_file ターゲットから xml_deadlock_report イベントを読み取る。デッドロックごとに時刻 (UTC)、犠牲プロセス、参加者数、データベース、完全なデッドロックグラフ XML を返す。","when":"アプリケーションがエラー 1205 を報告した場合、デッドロックの頻度と関与するオブジェクトを分析する場合、トレースフラグ 1222 のないサーバーで。","caution":"system_health ファイルはロールオーバーするため、高負荷サーバーでは古いデッドロックが消えている場合がある。恒久的なアーカイブには専用の XE セッションを設定する。多数のファイルの読み取りは CPU を消費するため、業務時間中は TOP を維持する。イベントは遅延して書き込まれるため、新しいデッドロックは数秒後に表示される。読み取り専用のため安全。","note":"deadlock_graph の値をクリックして .xdl として保存すると、SSMS でグラフィカルに開ける。system_health event_file のデフォルトは、2016 SP2 CU12 / 2017 CU20 / 2019 CU3 以降 (Standard/Enterprise) で 10 x 100 MB、それ以前のビルドや他のエディションでは 4 x 5 MB。グラフでは inputbuf、waitresource (KEY/PAGE/OBJECT)、lockMode が重要なフィールドである。ほとんどのデッドロックは、不足しているインデックスの追加またはアクセス順序の統一で解消される。","tags":["deadlock","system_health","xml_deadlock_report","extended events","1205","deadlock graph"]},{"id":"xe-long-query-session","task":"Extended Events セッションを作成する: 低速クエリをファイルに記録して読み取る","category":"パフォーマンス","command":"SET QUOTED_IDENTIFIER ON;\nCREATE EVENT SESSION [dba_long_queries] ON SERVER\nADD EVENT sqlserver.sql_statement_completed (\n    ACTION (sqlserver.client_app_name, sqlserver.client_hostname, sqlserver.database_name,\n            sqlserver.session_id, sqlserver.sql_text, sqlserver.username, sqlserver.query_hash)\n    WHERE (duration >= 1000000 AND sqlserver.is_system = 0)),   -- 1 s (microseconds)\nADD EVENT sqlserver.rpc_completed (\n    ACTION (sqlserver.client_app_name, sqlserver.client_hostname, sqlserver.database_name,\n            sqlserver.session_id, sqlserver.sql_text, sqlserver.username, sqlserver.query_hash)\n    WHERE (duration >= 1000000 AND sqlserver.is_system = 0))\nADD TARGET package0.event_file (SET filename = N'D:\\XE\\dba_long_queries.xel',\n                                    max_file_size = 256, max_rollover_files = 4)\nWITH (MAX_MEMORY = 8 MB, EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS,\n      MAX_DISPATCH_LATENCY = 15 SECONDS, STARTUP_STATE = OFF);\n\nALTER EVENT SESSION [dba_long_queries] ON SERVER STATE = START;\n\n-- Read:\nSELECT x.value('(event/@name)[1]', 'sysname')                                AS event_name,\n       x.value('(event/@timestamp)[1]', 'datetime2')                         AS utc_time,\n       x.value('(event/data[@name=\"duration\"]/value)[1]', 'bigint') / 1000   AS duration_ms,\n       x.value('(event/data[@name=\"cpu_time\"]/value)[1]', 'bigint') / 1000   AS cpu_ms,\n       x.value('(event/data[@name=\"logical_reads\"]/value)[1]', 'bigint')     AS logical_reads,\n       x.value('(event/action[@name=\"database_name\"]/value)[1]', 'sysname')  AS db,\n       x.value('(event/action[@name=\"client_app_name\"]/value)[1]', 'nvarchar(256)') AS app,\n       x.value('(event/action[@name=\"sql_text\"]/value)[1]', 'nvarchar(max)') AS sql_text\nFROM  (SELECT CAST(event_data AS XML) AS x\n       FROM sys.fn_xe_file_target_read_file(N'D:\\XE\\dba_long_queries*.xel', NULL, NULL, NULL)) t\nORDER BY duration_ms DESC;\n\n-- When done:\n-- ALTER EVENT SESSION [dba_long_queries] ON SERVER STATE = STOP;\n-- DROP EVENT SESSION [dba_long_queries] ON SERVER;","what":"1 秒を超えるステートメントと RPC 呼び出しを、アプリケーション、ホスト、ユーザー、データベース、SQL テキストとともにディスクに書き込む軽量な Extended Events セッションを作成する。.xel ファイルを T-SQL で行に変換する。","when":"断続的な低速化の苦情、Query Store では見えないクライアント詳細 (アプリ / ホスト) が必要な場合、および SQL Trace/Profiler の代替として。","caution":"しきい値を非常に低くすると (例: 0)、ファイルがすぐに埋まり、高負荷サーバーではオーバーヘッドが増える。フィルタは事後ではなく WHERE 述語で行う。sql_text アクションは大量の場合コストが高い。フォルダーは SQL Server サービスアカウントが書き込み可能である必要がある。duration と cpu_time の単位はマイクロ秒。完了したらセッションを停止 / 削除する。STARTUP_STATE = OFF の場合、再起動後には開始されない。","note":"1 つのデータベースに絞り込むには、WHERE 句に sqlserver.database_name = N'Musteri' を追加する。簡易確認には SSMS > Management > Extended Events > Watch Live Data を使用する。","tags":["extended events","xe","event session","slow query","sql_statement_completed","event_file"]},{"id":"tempdb-contention","task":"tempdb の競合と領域使用量を診断する","category":"パフォーマンス","command":"-- 1) Current tempdb page latch waits (2:1:1 PFS, 2:1:2 GAM, 2:1:3 SGAM):\nSELECT wt.session_id, wt.wait_type, wt.wait_duration_ms, wt.resource_description\nFROM   sys.dm_os_waiting_tasks wt\nWHERE  wt.wait_type LIKE N'PAGELATCH[_]%'\n  AND  wt.resource_description LIKE N'2:%';\n\n-- 2) Sessions using the most tempdb (MB):\nSELECT TOP (20) su.session_id, s.login_name, s.program_name,\n       (su.user_objects_alloc_page_count - su.user_objects_dealloc_page_count) * 8 / 1024         AS user_obj_mb,\n       (su.internal_objects_alloc_page_count - su.internal_objects_dealloc_page_count) * 8 / 1024 AS internal_obj_mb\nFROM   sys.dm_db_session_space_usage su\n  JOIN sys.dm_exec_sessions s ON s.session_id = su.session_id\nWHERE  s.is_user_process = 1\nORDER BY su.user_objects_alloc_page_count + su.internal_objects_alloc_page_count\n       - su.user_objects_dealloc_page_count - su.internal_objects_dealloc_page_count DESC;\n\n-- 3) Overall breakdown and version store:\nSELECT SUM(unallocated_extent_page_count) * 8 / 1024       AS free_mb,\n       SUM(user_object_reserved_page_count) * 8 / 1024     AS user_obj_mb,\n       SUM(internal_object_reserved_page_count) * 8 / 1024 AS internal_obj_mb,\n       SUM(version_store_reserved_page_count) * 8 / 1024   AS version_store_mb\nFROM   tempdb.sys.dm_db_file_space_usage;\n\nSELECT DB_NAME(database_id) AS db, reserved_page_count * 8 / 1024 AS version_store_mb\nFROM   sys.dm_tran_version_store_space_usage\nORDER BY reserved_page_count DESC;\n\n-- 4) File count / equal sizing and memory-optimized metadata:\nSELECT name, type_desc, size * 8 / 1024 AS size_mb, growth * 8 / 1024 AS growth_mb, is_percent_growth\nFROM   tempdb.sys.database_files;\nSELECT SERVERPROPERTY('IsTempdbMetadataMemoryOptimized') AS tempdb_metadata_memopt;","what":"tempdb の割り当てページ (PFS/GAM/SGAM) とシステムテーブルに対する PAGELATCH 待機、tempdb を最も多く使用しているセッション (一時テーブルとソート / ハッシュのスピルの別)、バージョンストアを肥大化させているデータベース、ファイル構成を表示する。","when":"一時テーブルを多用するワークロードで PAGELATCH_UP/EX 待機が増加した場合、tempdb が満杯になった場合 (1105/9002)、またはバージョンストアが増大した場合。","caution":"ページ 2:1:1、2:1:2、2:1:3 および 8088 の倍数の位置にある PFS ページは割り当ての競合を意味する。対処は、同じサイズ・同じ拡張設定の複数データファイルである (8 まではコアあたり 1 つ、その後は 4 つずつ追加)。システムテーブルページの競合には、2019 以降でメモリ最適化 tempdb メタデータが利用できる (再起動が必要)。バージョンストアが増大する場合は、最も古いオープン中のスナップショットトランザクションを特定する。tempdb の圧縮は対処にならない。読み取り専用クエリのため安全。","note":"メモリ最適化メタデータ: ALTER SERVER CONFIGURATION SET MEMORY_OPTIMIZED TEMPDB_METADATA = ON; + 再起動 (2019 以降)。2022 ではラッチフリーの GAM/SGAM 更新が追加され、競合が大幅に減少した。バージョンストアを保持しているトランザクション: sys.dm_tran_active_snapshot_database_transactions ORDER BY elapsed_time_seconds DESC。","tags":["tempdb","pagelatch","pfs","gam","version store","contention"]},{"id":"qs-enable-config","task":"Query Store を有効化し、推奨設定を適用して状態を確認する","category":"Query Store","command":"ALTER DATABASE [Musteri] SET QUERY_STORE = ON;\nALTER DATABASE [Musteri] SET QUERY_STORE (\n    OPERATION_MODE = READ_WRITE,\n    QUERY_CAPTURE_MODE = AUTO,\n    MAX_STORAGE_SIZE_MB = 2048,\n    INTERVAL_LENGTH_MINUTES = 15,\n    DATA_FLUSH_INTERVAL_SECONDS = 900,\n    CLEANUP_POLICY = (STALE_QUERY_THRESHOLD_DAYS = 30),\n    SIZE_BASED_CLEANUP_MODE = AUTO,\n    MAX_PLANS_PER_QUERY = 200,\n    WAIT_STATS_CAPTURE_MODE = ON);\n\n-- State: if actual_state dropped to READ_ONLY, check readonly_reason\nUSE [Musteri];\nSELECT actual_state_desc, desired_state_desc, readonly_reason,\n       current_storage_size_mb, max_storage_size_mb,\n       query_capture_mode_desc, size_based_cleanup_mode_desc, wait_stats_capture_mode_desc\nFROM   sys.database_query_store_options;","what":"データベースで Query Store を有効にし、クエリテキスト、実行計画、実行時統計、待機統計を時間間隔ごとに永続化し始める。オプションでストレージ上限、クリーンアップ、キャプチャモードを定義する。","when":"新しいデータベースの本番稼働時、バージョン / 互換性レベルのアップグレード前 (ベースライン取得のため)、または実行計画の性能低下が疑われる場合。","caution":"MAX_STORAGE_SIZE_MB に達すると、Query Store は通知なしに READ_ONLY (readonly_reason = 65536) に切り替わり、収集を停止する。current_storage_size_mb を監視する。QUERY_CAPTURE_MODE = ALL は、アドホックの多いワークロードではストレージをすぐに埋め、オーバーヘッドを増やす。非常に高負荷な OLTP システムでは QDS_* 待機が現れることがある。OFF にしても収集済みデータは残る。CLEAR で削除される。","since":"2016","note":"2022 では、新規作成されたデータベースで Query Store がデフォルトで READ_WRITE として有効になる。2019 以降の QUERY_CAPTURE_MODE = CUSTOM ではしきい値 (EXECUTION_COUNT、TOTAL_COMPILE_CPU_TIME_MS、TOTAL_EXECUTION_CPU_TIME_MS) を指定できる。読み取り可能セカンダリ向けの Query Store (ALTER DATABASE ... FOR SECONDARY SET QUERY_STORE = ON) は 2022 では限定プレビューで、トレースフラグ 12606 でのみ有効になり、本番環境ではサポートされない。2025 ではトレースフラグは不要 (引き続きプレビュー)。","tags":["query store","enable","max_storage_size_mb","query_capture_mode","read_only","qds"]},{"id":"qs-regressed-queries","task":"Query Store で実行計画の性能低下を特定する (同じクエリ、異なる実行計画)","category":"Query Store","command":"USE [Musteri];\n-- Queries with more than one plan in the last 24 hours, per-plan performance:\nWITH plan_stats AS (\n    SELECT p.query_id, p.plan_id, p.is_forced_plan,\n           SUM(rs.count_executions) AS execs,\n           SUM(rs.avg_duration * rs.count_executions) / SUM(rs.count_executions) / 1000.0     AS avg_ms,\n           SUM(rs.avg_cpu_time * rs.count_executions) / SUM(rs.count_executions) / 1000.0     AS avg_cpu_ms,\n           SUM(rs.avg_logical_io_reads * rs.count_executions) / SUM(rs.count_executions)      AS avg_reads,\n           MAX(rs.last_execution_time) AS last_exec\n    FROM   sys.query_store_plan p\n      JOIN sys.query_store_runtime_stats rs ON rs.plan_id = p.plan_id\n      JOIN sys.query_store_runtime_stats_interval i\n        ON i.runtime_stats_interval_id = rs.runtime_stats_interval_id\n    WHERE  i.start_time >= DATEADD(HOUR, -24, SYSUTCDATETIME())\n    GROUP BY p.query_id, p.plan_id, p.is_forced_plan\n)\nSELECT ps.query_id, ps.plan_id, ps.is_forced_plan, ps.execs,\n       CAST(ps.avg_ms AS DECIMAL(18,2))     AS avg_ms,\n       CAST(ps.avg_cpu_ms AS DECIMAL(18,2)) AS avg_cpu_ms,\n       CAST(ps.avg_reads AS BIGINT)         AS avg_reads,\n       CAST(ps.avg_ms / NULLIF(MIN(ps.avg_ms) OVER (PARTITION BY ps.query_id), 0) AS DECIMAL(18,1)) AS x_slower_than_best,\n       ps.last_exec,\n       OBJECT_NAME(q.object_id)     AS module,\n       LEFT(qt.query_sql_text, 120) AS query_text\nFROM   plan_stats ps\n  JOIN sys.query_store_query q       ON q.query_id = ps.query_id\n  JOIN sys.query_store_query_text qt ON qt.query_text_id = q.query_text_id\nWHERE  ps.query_id IN (SELECT query_id FROM plan_stats GROUP BY query_id HAVING COUNT(*) > 1)\nORDER BY ps.query_id, ps.avg_ms;","what":"過去 24 時間に複数の実行計画で実行されたクエリを特定し、各実行計画の実行回数、加重平均の実行時間 / CPU / 読み取り、最良の実行計画と比べて何倍遅いかを並べて表示する。","when":"クエリが「昨日は速かったのに今日は遅い」場合、統計の更新、インデックスの変更、互換性レベルのアップグレード、パッチ適用の後に。","caution":"平均実行時間はデータ分布にも依存する。異なるパラメータ値で実行された実行計画を比較する場合は、avg_reads も確認する (パラメータスニッフィング)。時間範囲は UTC。実行回数の少ない実行計画では、結果の統計的な信頼性は低い。読み取り専用クエリのため安全。","since":"2016","note":"SSMS > Query Store > Regressed Queries でも同じことをグラフィカルに行える。2022 の互換性レベル 160 では、Parameter Sensitive Plan (PSP) 最適化により 1 つのステートメントに複数のバリアント query_id が作成される。sys.query_store_query_variant (parent_query_id) で親に対応付ける。2017 以降の自動チューニング (FORCE_LAST_GOOD_PLAN) は、このような性能低下を自動的に修正できる。","tags":["query store","plan regression","regressed queries","parameter sniffing","query_store_runtime_stats","plan"]},{"id":"qs-force-plan-hints","task":"Query Store で良好な実行計画を強制する、またはヒントを付与する","category":"Query Store","command":"USE [Musteri];\n-- Force the good plan (query_id / plan_id from the regression query):\nEXEC sys.sp_query_store_force_plan @query_id = 42, @plan_id = 7;\n\n-- Forced plans and failure reason:\nSELECT p.query_id, p.plan_id, p.is_forced_plan, p.plan_forcing_type_desc,\n       p.force_failure_count, p.last_force_failure_reason_desc\nFROM   sys.query_store_plan p\nWHERE  p.is_forced_plan = 1;\n\n-- Undo:\nEXEC sys.sp_query_store_unforce_plan @query_id = 42, @plan_id = 7;\n\n-- 2022+: attach / remove a hint without changing code:\nEXEC sys.sp_query_store_set_hints @query_id = 42, @query_hints = N'OPTION (RECOMPILE)';\nSELECT query_id, query_hint_text, last_query_hint_failure_reason_desc\nFROM   sys.query_store_query_hints;\nEXEC sys.sp_query_store_clear_hints @query_id = 42;","what":"選択したクエリに対して特定の Query Store の実行計画を強制する。オプティマイザはコンパイルのたびにその実行計画を使用する。2022 では代わりに、アプリケーションコードを変更せずに RECOMPILE、MAXDOP、OPTIMIZE FOR などのヒントを付与できる。","when":"本番環境で実行計画の性能低下に緊急の対処が必要な場合、恒久的な対策 (インデックス、クエリの書き換え、統計) が用意できるまで。","caution":"強制した実行計画はデータの増加とともに劣化する可能性があり、恒久的な対策ではないため、定期的に見直す。実行計画が使用するインデックスが削除 / 名前変更されると強制は失敗し (last_force_failure_reason_desc = NO_INDEX など)、クエリは通常どおりコンパイルされる。強制後、「実質的に同等な」実行計画が新しい plan_id で現れることがあるが、これは想定どおりである。Query Store が READ_ONLY の間も強制は機能するが、リストアや AG フェイルオーバーの後は確認する。","since":"2016","note":"Query Store ヒントは 2022 以降 (Azure SQL ではそれ以前から)。ヒントはプランガイドに代わるものである。ヒントを適用できない場合、クエリはヒントなしで実行され、理由は last_query_hint_failure_reason_desc に表示される。読み取り可能セカンダリでの実行計画の強制 (@replica_group_id) にはセカンダリレプリカ向けの Query Store が必要で、2022 ではトレースフラグ 12606 で有効になる限定プレビューである。","tags":["force plan","sp_query_store_force_plan","query store hints","plan forcing","regression","recompile"]},{"id":"missing-index-dmv","task":"DMV から不足しているインデックスの提案を読み取る (注意点あり)","category":"メンテナンス","command":"USE [Musteri];\nSELECT TOP (25)\n       mid.statement                                   AS table_name,\n       mid.equality_columns, mid.inequality_columns, mid.included_columns,\n       migs.user_seeks, migs.user_scans,\n       CAST(migs.avg_total_user_cost AS DECIMAL(18,2)) AS avg_query_cost,\n       migs.avg_user_impact                            AS est_impact_pct,\n       CAST(migs.user_seeks * migs.avg_total_user_cost * migs.avg_user_impact / 100.0 AS DECIMAL(18,0)) AS score,\n       migs.last_user_seek,\n       N'CREATE INDEX [IX_' + OBJECT_NAME(mid.object_id, mid.database_id) + N'_missing_'\n         + CAST(mid.index_handle AS NVARCHAR(10)) + N'] ON ' + mid.statement + N' ('\n         + ISNULL(mid.equality_columns, N'')\n         + CASE WHEN mid.equality_columns IS NOT NULL AND mid.inequality_columns IS NOT NULL THEN N', ' ELSE N'' END\n         + ISNULL(mid.inequality_columns, N'') + N')'\n         + ISNULL(N' INCLUDE (' + mid.included_columns + N')', N'') AS create_stmt_draft\nFROM   sys.dm_db_missing_index_details mid\n  JOIN sys.dm_db_missing_index_groups mig       ON mig.index_handle = mid.index_handle\n  JOIN sys.dm_db_missing_index_group_stats migs ON migs.group_handle = mig.index_group_handle\nWHERE  mid.database_id = DB_ID()\nORDER BY score DESC;\n\n-- 2019+: the query text behind each suggestion:\nSELECT TOP (25) mid.statement AS table_name, misq.group_handle, misq.user_seeks,\n       SUBSTRING(st.text, misq.last_statement_start_offset / 2 + 1, 300) AS statement_text\nFROM   sys.dm_db_missing_index_group_stats_query misq\n  JOIN sys.dm_db_missing_index_groups mig  ON mig.index_group_handle = misq.group_handle\n  JOIN sys.dm_db_missing_index_details mid ON mid.index_handle = mig.index_handle\n  CROSS APPLY sys.dm_exec_sql_text(misq.last_sql_handle) st\nWHERE  mid.database_id = DB_ID()\nORDER BY misq.user_seeks DESC;","what":"オプティマイザがコンパイル時に記録した不足インデックスの提案を、使用状況、推定コスト、効果でスコア付けし、CREATE INDEX ステートメントの下書きを生成する。2019 以降では各提案の元となったクエリも表示する。","when":"新しいアプリケーションのリリース後、読み取り中心のクエリに必要なインデックスを素早く洗い出す場合、またはインデックス設計レビューの出発点リストとして。","caution":"提案を盲目的に適用しない: オプティマイザは既存のインデックスを考慮せず、ほぼ重複する (重なり合う) 提案や広すぎる INCLUDE リストをしばしば生成し、列を選択性ではなく等価 / 非等価で並べる。新しいインデックスはすべて書き込みとストレージのコストを伴うため、まず既存のインデックスの拡張を検討する。DMV は再起動、データベースのオフライン化、テーブルのインデックス変更でリセットされる。読み取り専用クエリのため安全。","note":"提案されたインデックスを作成する前に、テーブルの既存のインデックス (sp_helpindex または sys.index_columns) と比較し、未使用インデックスのレシピと合わせて確認する。実行計画 XML の MissingIndex 要素は、クエリごとに同じ情報を提供する。","tags":["missing index","missing index dmv","dm_db_missing_index_details","index suggestion","create index","tuning"]},{"id":"unused-indexes","task":"未使用 / 書き込み専用のインデックスを特定する","category":"メンテナンス","command":"USE [Musteri];\nSELECT OBJECT_SCHEMA_NAME(i.object_id) AS schema_name,\n       OBJECT_NAME(i.object_id)        AS table_name,\n       i.name                          AS index_name,\n       ISNULL(us.user_seeks, 0) + ISNULL(us.user_scans, 0) + ISNULL(us.user_lookups, 0) AS reads,\n       ISNULL(us.user_updates, 0)      AS writes,\n       ps.used_mb,\n       us.last_user_seek, us.last_user_scan,\n       N'DROP INDEX ' + QUOTENAME(i.name) + N' ON ' + QUOTENAME(OBJECT_SCHEMA_NAME(i.object_id))\n         + N'.' + QUOTENAME(OBJECT_NAME(i.object_id)) + N';' AS drop_stmt_draft\nFROM   sys.indexes i\n  LEFT JOIN sys.dm_db_index_usage_stats us\n         ON us.database_id = DB_ID() AND us.object_id = i.object_id AND us.index_id = i.index_id\n  CROSS APPLY (SELECT CAST(SUM(p.used_page_count) * 8 / 1024.0 AS DECIMAL(18,1)) AS used_mb\n               FROM sys.dm_db_partition_stats p\n               WHERE p.object_id = i.object_id AND p.index_id = i.index_id) ps\nWHERE  OBJECTPROPERTY(i.object_id, 'IsUserTable') = 1\n  AND  i.type_desc = N'NONCLUSTERED'\n  AND  i.is_primary_key = 0 AND i.is_unique_constraint = 0 AND i.is_unique = 0\n  AND  ISNULL(us.user_seeks, 0) + ISNULL(us.user_scans, 0) + ISNULL(us.user_lookups, 0) = 0\nORDER BY writes DESC, ps.used_mb DESC;\n\n-- Usage counters since:\nSELECT sqlserver_start_time FROM sys.dm_os_sys_info;","what":"再起動以降に読み取られていない (seek/scan/lookup = 0) が書き込みコストは発生している非クラスタ化インデックスを、サイズとともに一覧表示し、DROP INDEX ステートメントの下書きを生成する。","when":"書き込みの多いテーブルで INSERT/UPDATE が遅い場合、ストレージとメンテナンス (再構築、CHECKDB) 時間を減らすため、またはインデックスの統合前に。","caution":"カウンターは再起動、データベースのオフライン化 / デタッチ、および (一部の古い 2012/2014 ビルドでは) インデックスの再構築でリセットされる。月末 / 年末レポートでのみ使用されるインデックスは、短い期間では「未使用」に見える。削除前に少なくとも 1 回の完全な業務サイクルを観察し、AG では読み取り可能セカンダリでの使用状況を別途確認する (カウンターはレプリカごと)。一意インデックスは読み取られなくても制約を強制するため除外される。読み取り専用クエリのため安全。","note":"削除前に ALTER INDEX ... DISABLE で無効化しておくと、ロールバックが容易になる (定義は残り、REBUILD で元に戻る)。Query Store やプランキャッシュでインデックス名を検索すると、ヒントで参照されているかどうかがわかる。","tags":["unused index","write-only index","dm_db_index_usage_stats","drop index","write overhead","index"]},{"id":"stats-health","task":"統計の健全性: いつ更新されたか、何行変更されたか","category":"メンテナンス","command":"USE [Musteri];\nSELECT OBJECT_SCHEMA_NAME(s.object_id) AS schema_name,\n       OBJECT_NAME(s.object_id)        AS table_name,\n       s.name                          AS stats_name,\n       s.auto_created, s.has_filter, s.no_recompute,\n       sp.last_updated,\n       sp.rows, sp.rows_sampled,\n       CAST(100.0 * sp.rows_sampled / NULLIF(sp.rows, 0) AS DECIMAL(5,1))         AS sample_pct,\n       sp.modification_counter,\n       CAST(100.0 * sp.modification_counter / NULLIF(sp.rows, 0) AS DECIMAL(9,1)) AS modified_pct,\n       CAST(CASE WHEN 500 + 0.20 * sp.rows < SQRT(1000.0 * sp.rows) THEN 500 + 0.20 * sp.rows\n                 ELSE SQRT(1000.0 * sp.rows) END AS BIGINT)                       AS auto_update_threshold,\n       sp.persisted_sample_percent\nFROM   sys.stats s\n  CROSS APPLY sys.dm_db_stats_properties(s.object_id, s.stats_id) sp\nWHERE  OBJECTPROPERTY(s.object_id, 'IsUserTable') = 1\nORDER BY sp.modification_counter DESC;\n\nSELECT name, is_auto_create_stats_on, is_auto_update_stats_on, is_auto_update_stats_async_on\nFROM   sys.databases\nWHERE  name = DB_NAME();","what":"各統計について、最終更新時刻、サンプリング率、最終更新以降の変更行数、自動更新が発動するしきい値 (互換性レベル 130 以降は動的しきい値) を表示する。","when":"推定行数と実績行数に大きな差がある実行計画、大量データロードの後、または統計メンテナンスジョブが有効かどうかを確認する場合に。","caution":"しきい値の式は互換性レベル 130 以降に適用される (MIN(500 + 20%, SQRT(1000 x rows)))。それより低い互換性レベルでは 20% + 500 のルールが使われる。一度も更新されていない統計 (空のテーブル) は NULL を返す。sample_pct が低い偏りのある列では、FULLSCAN または PERSIST_SAMPLE_PERCENT が必要な場合がある。読み取り専用クエリのため安全。","since":"2016","note":"persisted_sample_percent は UPDATE STATISTICS ... WITH PERSIST_SAMPLE_PERCENT = ON (2016 SP1 CU4 / 2017 CU1 以降) を反映する。更新コマンドについては update-statistics レシピを参照。","tags":["statistics","stats health","dm_db_stats_properties","modification_counter","auto update","cardinality"]},{"id":"checkdb-strategy","task":"DBCC CHECKDB の戦略: 最後の正常なチェック、作業の分割、結果の解釈","category":"メンテナンス","command":"-- Last successful CHECKDB (1900-01-01 = never):\nSELECT name, DATABASEPROPERTYEX(name, 'LastGoodCheckDbTime') AS last_good_checkdb\nFROM   sys.databases\nWHERE  state_desc = N'ONLINE' AND name <> N'tempdb'\nORDER BY last_good_checkdb;\n\n-- Estimated tempdb requirement:\nDBCC CHECKDB (N'Musteri') WITH ESTIMATEONLY;\n\n-- Split a large DB across days: allocation + catalog + table by table CHECKTABLE\nUSE [Musteri];\nDBCC CHECKALLOC (N'Musteri') WITH NO_INFOMSGS;\nDBCC CHECKCATALOG (N'Musteri') WITH NO_INFOMSGS;\nDBCC CHECKTABLE (N'dbo.Siparis') WITH NO_INFOMSGS, ALL_ERRORMSGS;\n\n-- Get results as rows (error rows with object and page):\nDBCC CHECKDB (N'Musteri') WITH TABLERESULTS, NO_INFOMSGS, ALL_ERRORMSGS, MAXDOP = 4;","what":"すべてのデータベースについて最後に成功した CHECKDB の時刻を表示し、必要な tempdb を見積もる。大きなデータベースではチェックを CHECKALLOC + CHECKCATALOG + CHECKTABLE に分割でき、結果を行 (オブジェクト、インデックス、ページ) として返す。","when":"メンテナンスを監査する場合、メンテナンス時間帯に収まらない非常に大きなデータベースの場合、または 823/824 の後に破損の範囲を特定する場合。","caution":"結果に \"repair_allow_data_loss is the minimum repair level\" という文言がある場合、修復によってデータが削除されることを意味する。まず正常なバックアップからのリストア (またはページリストア) を検討する。非クラスタ化インデックス (index_id > 1) のみが影響を受けている場合は、インデックスを削除して再作成すればデータ損失なしで修正できる。破損を発見したら、ディスクサブシステムを調査する。PHYSICAL_ONLY は論理チェックを省略するため、定期的な完全 CHECKDB は引き続き必要。CHECKTABLE で分割する場合、CHECKALLOC/CHECKCATALOG も実行しないと網羅性が不完全になる。","note":"DATABASEPROPERTYEX(..., 'LastGoodCheckDbTime') は 2016 SP2、2017 CU9、2019 以降で使用可能。古いビルドでは DBCC DBINFO WITH TABLERESULTS の dbi_dbccLastKnownGood を読み取る。負荷を逃がすため、バックアップからリストアしたコピー (例: テストサーバー上) で CHECKDB を実行しても本番データベースの検証になる。MAXDOP オプションは 2014 SP2 / 2016 以降。","tags":["dbcc checkdb","lastgoodcheckdbtime","checktable","corruption","repair_allow_data_loss","integrity"]},{"id":"resource-governor","task":"Resource Governor でレポート負荷を制限する (プール、ワークロードグループ、分類関数)","category":"構成","command":"USE master;\n-- 1) Pool and workload group:\nCREATE RESOURCE POOL [pool_report]\nWITH (MIN_CPU_PERCENT = 0, MAX_CPU_PERCENT = 30, CAP_CPU_PERCENT = 40,\n      MIN_MEMORY_PERCENT = 0, MAX_MEMORY_PERCENT = 25);\nCREATE WORKLOAD GROUP [wg_report]\nWITH (IMPORTANCE = LOW, REQUEST_MAX_MEMORY_GRANT_PERCENT = 15,\n      MAX_DOP = 2, REQUEST_MAX_CPU_TIME_SEC = 600)\nUSING [pool_report];\nGO\n-- 2) Classifier function (in master, SCHEMABINDING required):\nCREATE FUNCTION dbo.fn_rg_classifier()\nRETURNS sysname\nWITH SCHEMABINDING\nAS\nBEGIN\n    DECLARE @grp sysname = N'default';\n    IF SUSER_SNAME() = N'rapor_user' OR APP_NAME() LIKE N'Power BI%'\n        SET @grp = N'wg_report';\n    RETURN @grp;\nEND;\nGO\n-- 3) Enable:\nALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION = dbo.fn_rg_classifier);\nALTER RESOURCE GOVERNOR RECONFIGURE;\n\n-- 4) Which session landed in which group:\nSELECT s.session_id, s.login_name, s.program_name, wg.name AS workload_group, rp.name AS pool\nFROM   sys.dm_exec_sessions s\n  JOIN sys.dm_resource_governor_workload_groups wg ON wg.group_id = s.group_id\n  JOIN sys.dm_resource_governor_resource_pools rp  ON rp.pool_id = wg.pool_id\nWHERE  s.is_user_process = 1;\n\n-- Rollback:\n-- ALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION = NULL); ALTER RESOURCE GOVERNOR DISABLE;","what":"特定のログインやアプリケーションからのセッションを接続時に別のワークロードグループへ振り分け、そのグループの CPU、メモリ許可、DOP、リクエストあたりの CPU 時間を制限して OLTP ワークロードを保護する。","when":"レポート / BI クエリが OLTP を圧迫する場合、ETL が業務時間の負荷と重なる場合、またはマルチテナントサーバーでのリソース共有に。","caution":"分類関数は新しい接続のたびに実行される。関数が遅いか失敗すると、すべてのログインが遅くなるか失敗する (関数内でクエリやテーブルアクセスを行わない)。誤動作した場合は DAC で接続して CLASSIFIER_FUNCTION = NULL を設定する。分類は接続時にのみ行われ、既存のセッションには影響しない。CAP_CPU_PERCENT は CPU がアイドルでも適用されるハード上限である。MAX_CPU_PERCENT は CPU の競合時にのみ適用される。Resource Governor は Enterprise/Developer の機能である。","note":"REQUEST_MAX_CPU_TIME_SEC を超えた場合、デフォルトではイベント (cpu_threshold_exceeded) が発生するだけである。トレースフラグ 2422 (2016 SP2 / 2017 CU3 以降) を使用するとリクエストは中止される。I/O 制限にはプールの MAX_IOPS_PER_VOLUME (2014 以降) を使用する。統計: sys.dm_resource_governor_resource_pools / _workload_groups。","tags":["resource governor","resource pool","workload group","classifier","cpu limit","resource management"]},{"id":"tde-enable","task":"TDE を設定する: マスターキー、証明書、証明書のバックアップ、暗号化の進捗","category":"セキュリティ","command":"USE master;\nIF NOT EXISTS (SELECT 1 FROM sys.symmetric_keys WHERE name = N'##MS_DatabaseMasterKey##')\n    CREATE MASTER KEY ENCRYPTION BY PASSWORD = N'<GucluParola_1>';\nCREATE CERTIFICATE [TDE_Cert_2026]\n    WITH SUBJECT = N'TDE certificate', EXPIRY_DATE = '20361231';\n\n-- Back it up NOW: without cert + private key the backups cannot be restored anywhere\nBACKUP CERTIFICATE [TDE_Cert_2026]\n    TO FILE = N'D:\\Keys\\TDE_Cert_2026.cer'\n    WITH PRIVATE KEY (FILE = N'D:\\Keys\\TDE_Cert_2026.pvk',\n                      ENCRYPTION BY PASSWORD = N'<GucluParola_2>');\n\nUSE [Musteri];\nCREATE DATABASE ENCRYPTION KEY\n    WITH ALGORITHM = AES_256\n    ENCRYPTION BY SERVER CERTIFICATE [TDE_Cert_2026];\nALTER DATABASE [Musteri] SET ENCRYPTION ON;\n\n-- Progress and certificate backup date:\nSELECT DB_NAME(dek.database_id) AS db, dek.encryption_state_desc, dek.percent_complete,\n       dek.encryption_scan_state_desc, c.name AS cert_name, c.expiry_date, c.pvt_key_last_backup_date\nFROM   sys.dm_database_encryption_keys dek\n  LEFT JOIN master.sys.certificates c ON c.thumbprint = dek.encryptor_thumbprint;\n\n-- On the target server (before restore / AG secondary):\n-- CREATE CERTIFICATE [TDE_Cert_2026] FROM FILE = N'D:\\Keys\\TDE_Cert_2026.cer'\n--   WITH PRIVATE KEY (FILE = N'D:\\Keys\\TDE_Cert_2026.pvk', DECRYPTION BY PASSWORD = N'<GucluParola_2>');","what":"master にデータベースマスターキーと証明書を作成し、証明書を秘密キーとともにバックアップし、AES-256 のデータベース暗号化キーを作成して、保存時のデータファイルとログファイルを暗号化する。バックグラウンドの暗号化スキャンの進捗を表示する。","when":"GDPR/PCI などの保存データ暗号化の要件に、およびバックアップファイルや MDF/LDF ファイルの盗難対策として。","caution":"証明書 + 秘密キーのバックアップまたはそのパスワードを失うと、TDE データベースとそのすべてのバックアップは永久に読み取れなくなる。バックアップはサーバーから離れた安全な保管庫に保管する。いずれかのデータベースで TDE を有効にすると tempdb も暗号化される (サーバー全体でわずかな CPU コスト)。暗号化スキャンは I/O 負荷が高い。2019 以降では ALTER DATABASE ... SET ENCRYPTION SUSPEND/RESUME で一時停止できる。AG / ログ配布では、先にすべてのターゲットサーバーに証明書をインストールする必要がある。TDE はメモリ上やネットワーク上のデータは暗号化しない。","note":"証明書の有効期限が切れても既存の TDE は停止しないが、ローテーションでは新しい証明書を作成し、ALTER DATABASE ENCRYPTION KEY ENCRYPTION BY SERVER CERTIFICATE [new] で再暗号化する (再暗号化されるのは DEK のみで、データではない)。encryption_state_desc と encryption_scan_state_desc は 2019 以降の列。古いバージョンでは encryption_state (3 = 暗号化済み、2 = 進行中) を使用する。TDE は 2019 から Standard エディションで使用可能。","tags":["tde","transparent data encryption","certificate","backup certificate","encryption","dek"]},{"id":"sql-server-audit","task":"SQL Server Audit を設定する: ログイン、権限変更、テーブルアクセス","category":"セキュリティ","command":"USE master;\nCREATE SERVER AUDIT [Audit_DBA]\nTO FILE (FILEPATH = N'D:\\Audit\\', MAXSIZE = 256 MB, MAX_ROLLOVER_FILES = 20, RESERVE_DISK_SPACE = OFF)\nWITH (QUEUE_DELAY = 1000, ON_FAILURE = CONTINUE);\nALTER SERVER AUDIT [Audit_DBA] WITH (STATE = ON);\n\n-- Server-wide (covers all databases):\nCREATE SERVER AUDIT SPECIFICATION [AuditSpec_Server]\nFOR SERVER AUDIT [Audit_DBA]\n    ADD (FAILED_LOGIN_GROUP),\n    ADD (SERVER_ROLE_MEMBER_CHANGE_GROUP),\n    ADD (DATABASE_ROLE_MEMBER_CHANGE_GROUP),\n    ADD (SERVER_PRINCIPAL_CHANGE_GROUP),\n    ADD (DATABASE_PRINCIPAL_CHANGE_GROUP),\n    ADD (SERVER_PERMISSION_CHANGE_GROUP),\n    ADD (DATABASE_PERMISSION_CHANGE_GROUP),\n    ADD (AUDIT_CHANGE_GROUP)\nWITH (STATE = ON);\n\n-- Database: access to a sensitive table:\nUSE [Musteri];\nCREATE DATABASE AUDIT SPECIFICATION [AuditSpec_Musteri]\nFOR SERVER AUDIT [Audit_DBA]\n    ADD (SELECT, INSERT, UPDATE, DELETE ON OBJECT::[dbo].[Siparis] BY [public])\nWITH (STATE = ON);\n\n-- Read:\nSELECT event_time, action_id, succeeded, server_principal_name, database_name,\n       schema_name, object_name, LEFT(statement, 200) AS stmt, client_ip, application_name\nFROM   sys.fn_get_audit_file(N'D:\\Audit\\Audit_DBA_*.sqlaudit', DEFAULT, DEFAULT)\nWHERE  event_time >= DATEADD(HOUR, -24, SYSUTCDATETIME())\nORDER BY event_time DESC;","what":"ファイルに書き込むサーバー監査を作成する。サーバー全体でログイン失敗、ロールメンバーシップ、プリンシパルと権限の変更を記録し、データベースレベルで選択したテーブルへの SELECT/DML アクセスを記録し、T-SQL でレコードを読み取る。","when":"監査 / コンプライアンス要件 (GDPR、PCI、SOX)、「誰がこのテーブルを読んだ / 変更したか」という問い、または権限昇格が疑われる場合に。","caution":"高負荷テーブルでの SELECT 監査はレコードを非常に速く生成し、性能コストがかかるため、オブジェクトとプリンシパルで絞り込む。ON_FAILURE = SHUTDOWN は監査を書き込めない場合にサーバーを停止させるため、義務付けられている場合にのみ使用する。監査フォルダーは SQL Server サービスアカウントが書き込み可能で、DBA 以外が削除できないようにする必要がある。event_time は UTC。データベース監査仕様はデータベースとともにリストアされるが、サーバー監査の GUID が一致しない場合は孤立したままとなる。","note":"データベース監査仕様は 2016 SP1 から Standard エディションで使用可能。監査自体の変更 (無効化を含む) が記録されるよう、常に AUDIT_CHANGE_GROUP を含める。","tags":["sql server audit","server audit","audit specification","fn_get_audit_file","auditing","compliance"]},{"id":"orphaned-users-fix","task":"孤立ユーザーを特定し、ログインに再マッピングする (リストア / AG の後)","category":"セキュリティ","command":"USE [Musteri];\n-- Database users without a matching login:\nSELECT dp.name AS user_name, dp.type_desc, dp.authentication_type_desc, dp.sid, dp.create_date\nFROM   sys.database_principals dp\n  LEFT JOIN sys.server_principals sp ON sp.sid = dp.sid\nWHERE  sp.sid IS NULL\n  AND  dp.type IN ('S', 'U', 'G')\n  AND  dp.authentication_type_desc IN (N'INSTANCE', N'WINDOWS')\n  AND  dp.principal_id > 4;\n\n-- If a login with the same name exists, remap the SID:\nALTER USER [app_user] WITH LOGIN = [app_user];\n\n-- Permanent fix: generate CREATE LOGIN with SID + password hash on the source, run it on the target:\nSELECT N'CREATE LOGIN ' + QUOTENAME(sp.name)\n     + N' WITH PASSWORD = ' + CONVERT(NVARCHAR(MAX), LOGINPROPERTY(sp.name, 'PasswordHash'), 1)\n     + N' HASHED, SID = ' + CONVERT(NVARCHAR(MAX), sp.sid, 1)\n     + N', CHECK_POLICY = OFF;' AS create_login_stmt\nFROM   sys.server_principals sp\nWHERE  sp.type = 'S' AND sp.name = N'app_user';","what":"SID がどのサーバーログインとも一致しないデータベースユーザー (孤立ユーザー) を特定する。ユーザーを既存のログインに再マッピングし、別のサーバーで同じ SID とパスワードハッシュを持つログインを再作成するスクリプトを生成する。","when":"別のサーバーでデータベースをリストア / アタッチした後、AG / ログ配布のフェイルオーバー後にアプリケーションが \"Login failed for user\" を受け取る場合、またはサーバー移行中に。","caution":"ALTER USER ... WITH LOGIN はユーザーの SID をログインの SID に変更する。AG ではこの変更がプライマリからセカンダリに反映されるが、セカンダリサーバー上のログインの SID が異なる場合、次のフェイルオーバーで問題が再発する。恒久的な対策は、すべてのレプリカで同じ SID のログインを作成することである。パスワードハッシュは機密情報のため、スクリプトは安全に保管する。包含データベースユーザー (authentication_type = DATABASE) はログインを必要とせず、一覧には表示されない。","note":"sp_change_users_login は非推奨のため、ALTER USER WITH LOGIN を使用する。孤立した dbo (データベース所有者のログインが存在しない) には ALTER AUTHORIZATION ON DATABASE::[Musteri] TO [sa]; を使用する。ログインの一括移行には PowerShell dbatools を使用する: Copy-DbaLogin -Source SQL01 -Destination SQL02。","tags":["orphaned user","alter user with login","sid","login failed","after restore","sp_change_users_login"]},{"id":"permission-audit","task":"ログインと権限の監査: sysadmin メンバー、リスクのある権限、脆弱なパスワード","category":"セキュリティ","command":"-- 1) Server role memberships:\nSELECT r.name AS server_role, m.name AS member, m.type_desc, m.is_disabled, m.create_date\nFROM   sys.server_role_members rm\n  JOIN sys.server_principals r ON r.principal_id = rm.role_principal_id\n  JOIN sys.server_principals m ON m.principal_id = rm.member_principal_id\nORDER BY r.name, m.name;\n\n-- 2) Risky server permissions:\nSELECT pr.name AS grantee, pr.type_desc, pe.permission_name, pe.state_desc\nFROM   sys.server_permissions pe\n  JOIN sys.server_principals pr ON pr.principal_id = pe.grantee_principal_id\nWHERE  pe.permission_name IN (N'CONTROL SERVER', N'IMPERSONATE ANY LOGIN', N'ALTER ANY LOGIN',\n                              N'ALTER ANY SERVER ROLE', N'ALTER SETTINGS', N'IMPERSONATE')\n   OR  pe.state_desc = N'GRANT_WITH_GRANT_OPTION';\n\n-- 3) SQL login health (policy, lockout, password = login name):\nSELECT sl.name, sl.is_disabled, sl.is_policy_checked, sl.is_expiration_checked,\n       LOGINPROPERTY(sl.name, 'PasswordLastSetTime') AS pwd_last_set,\n       LOGINPROPERTY(sl.name, 'IsLocked')            AS is_locked,\n       LOGINPROPERTY(sl.name, 'BadPasswordCount')    AS bad_pwd_count,\n       PWDCOMPARE(sl.name, sl.password_hash)         AS pwd_equals_name,\n       PWDCOMPARE(N'', sl.password_hash)             AS pwd_empty\nFROM   sys.sql_logins sl;\n\n-- 4) Database role memberships and explicit object permissions:\nUSE [Musteri];\nSELECT r.name AS db_role, m.name AS member, m.type_desc\nFROM   sys.database_role_members rm\n  JOIN sys.database_principals r ON r.principal_id = rm.role_principal_id\n  JOIN sys.database_principals m ON m.principal_id = rm.member_principal_id\nWHERE  m.name <> N'dbo'\nORDER BY r.name, m.name;\n\nSELECT pr.name AS grantee, pe.class_desc, pe.permission_name, pe.state_desc,\n       OBJECT_SCHEMA_NAME(pe.major_id) AS schema_name,\n       CASE pe.class WHEN 1 THEN OBJECT_NAME(pe.major_id) WHEN 3 THEN SCHEMA_NAME(pe.major_id) END AS object_name\nFROM   sys.database_permissions pe\n  JOIN sys.database_principals pr ON pr.principal_id = pe.grantee_principal_id\nWHERE  (pr.name NOT IN (N'public', N'dbo') AND NOT (pe.class = 0 AND pe.permission_name = N'CONNECT'))\n   OR  (pr.name = N'public' AND OBJECT_SCHEMA_NAME(pe.major_id) <> N'sys')\nORDER BY pr.name, pe.class_desc;","what":"サーバーロールのメンバーシップ、CONTROL SERVER/IMPERSONATE などのリスクのある権限、パスワードポリシーが無効、ロック中、またはパスワードがログイン名と同じか空の SQL ログインを一覧表示する。データベース内では、ロールメンバーシップと、システム以外のオブジェクトに対する明示的な権限を表示する。","when":"定期的なアクセスレビュー、監査の前、チームメンバーの離任後、またはセキュリティインシデントが疑われる場合に。","caution":"Windows グループ経由で付与された権限はグループ名で表示される。個人を確認するには EXEC xp_logininfo N'DOMAIN\\Group', 'members'; を使用する。権限を取り消す前にアプリケーションの依存関係を確認する。PWDCOMPARE は SQL ログインでのみ機能し、CONTROL SERVER が必要。読み取り専用クエリのため安全。","note":"プリンシパルの有効な権限: EXECUTE AS USER = N'app_user'; SELECT * FROM fn_my_permissions(NULL, 'DATABASE'); REVERT;。2022 の新しい細分化されたロール (##MS_ServerStateReader##、##MS_DefinitionReader## など) は sysadmin なしで監視権限を付与する。","tags":["permission audit","sysadmin","server_role_members","database_permissions","pwdcompare","security"]},{"id":"ledger-tables","task":"台帳テーブルを作成し、変更履歴を読み取り、整合性を検証する","category":"セキュリティ","command":"USE [Musteri];\n-- Ledger verification requires snapshot isolation:\nALTER DATABASE [Musteri] SET ALLOW_SNAPSHOT_ISOLATION ON;\n\n-- Updatable ledger table (history table maintained automatically):\nCREATE TABLE dbo.Hesap (\n    HesapId int           NOT NULL PRIMARY KEY,\n    Bakiye  decimal(18,2) NOT NULL\n)\nWITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Hesap_History), LEDGER = ON);\n\n-- Append-only ledger (UPDATE/DELETE are blocked):\nCREATE TABLE dbo.IslemLog (Id bigint IDENTITY, Mesaj nvarchar(400))\nWITH (LEDGER = ON (APPEND_ONLY = ON));\n\n-- Who changed what, and when:\nSELECT t.commit_time, t.principal_name, l.HesapId, l.Bakiye, l.ledger_operation_type_desc\nFROM   dbo.Hesap_Ledger l\n  JOIN sys.database_ledger_transactions t ON t.transaction_id = l.ledger_transaction_id\nORDER BY t.commit_time DESC;\n\n-- Take a digest (store it somewhere trusted outside) and verify:\nEXEC sys.sp_generate_database_ledger_digest;\nEXEC sys.sp_verify_database_ledger\n     N'{\"database_name\":\"Musteri\",\"block_id\":0,\"hash\":\"0x...\",\"last_transaction_commit_time\":\"...\",\"digest_time\":\"...\"}';","what":"行の変更を暗号学的ハッシュチェーンに記録する台帳テーブルを作成する。_Ledger ビューは各 INSERT/UPDATE/DELETE を誰がいつ行ったかを示し、保存済みのダイジェストに対する検証により、データが事後に (DBA によるものを含め) 改ざんされていないことを証明する。","when":"不変性を証明する必要があるデータ: 財務記録、監査証跡、契約 / 承認記録に。","caution":"台帳はテーブル作成後に無効にできない。台帳テーブルは通常のテーブルに変換できず、削除した台帳テーブルは削除済み台帳テーブルとして保持される。更新可能な台帳は変更のたびに履歴行を書き込むため、ストレージが増大する。ダイジェストをデータベースの外部の不変ストレージ (WORM、Azure の不変 BLOB) に保存しない限り、検証に証拠能力はない。sp_verify_database_ledger はスナップショット分離がないとエラー 37498 で失敗する。","since":"2022","note":"sp_generate_database_ledger_digest は JSON を返す。sp_verify_database_ledger は単一のダイジェストまたは JSON 配列を受け付け、@table_name で単一のテーブルを検証できる。ダイジェストの自動保存: ALTER DATABASE SCOPED CONFIGURATION SET LEDGER_DIGEST_STORAGE_ENDPOINT = '<blob url>'。CREATE DATABASE ... WITH LEDGER = ON にすると、デフォルトですべてのテーブルが台帳テーブルになる。","tags":["ledger","append-only","sp_verify_database_ledger","digest","immutable","tamper-evident"]},{"id":"agent-job-failures","task":"SQL Agent ジョブの失敗履歴と最終実行状態","category":"SQL Agent","command":"-- Job steps that failed / were cancelled in the last 24 hours:\nSELECT j.name AS job_name, h.step_id, h.step_name,\n       msdb.dbo.agent_datetime(h.run_date, h.run_time) AS run_at,\n       STUFF(STUFF(RIGHT('000000' + CAST(h.run_duration AS VARCHAR(6)), 6), 3, 0, ':'), 6, 0, ':') AS duration_hhmmss,\n       CASE h.run_status WHEN 0 THEN 'Failed' WHEN 1 THEN 'Succeeded' WHEN 2 THEN 'Retry'\n                         WHEN 3 THEN 'Canceled' WHEN 4 THEN 'In progress' END AS status,\n       h.sql_message_id, h.sql_severity,\n       LEFT(h.message, 500) AS message\nFROM   msdb.dbo.sysjobhistory h\n  JOIN msdb.dbo.sysjobs j ON j.job_id = h.job_id\nWHERE  h.run_status IN (0, 3)\n  AND  msdb.dbo.agent_datetime(h.run_date, h.run_time) >= DATEADD(HOUR, -24, GETDATE())\nORDER BY run_at DESC;\n\n-- Each job's last outcome, running now, next run:\nSELECT j.name, j.enabled,\n       CASE lr.run_status WHEN 0 THEN 'Failed' WHEN 1 THEN 'Succeeded' WHEN 3 THEN 'Canceled' END AS last_outcome,\n       lr.run_at AS last_run_at,\n       CASE WHEN a.start_execution_date IS NOT NULL AND a.stop_execution_date IS NULL THEN 'RUNNING' END AS running_now,\n       a.next_scheduled_run_date\nFROM   msdb.dbo.sysjobs j\n  LEFT JOIN msdb.dbo.sysjobactivity a\n         ON a.job_id = j.job_id AND a.session_id = (SELECT MAX(session_id) FROM msdb.dbo.syssessions)\n  OUTER APPLY (SELECT TOP (1) h.run_status, msdb.dbo.agent_datetime(h.run_date, h.run_time) AS run_at\n               FROM msdb.dbo.sysjobhistory h\n               WHERE h.job_id = j.job_id AND h.step_id = 0\n               ORDER BY h.instance_id DESC) lr\nORDER BY j.name;\n\n-- Is the Agent service running:\nSELECT servicename, status_desc, startup_type_desc FROM sys.dm_server_services;","what":"過去 24 時間に失敗またはキャンセルされたジョブステップをエラーメッセージとともに表示する。各ジョブの最終結果、現在実行中かどうか、次回のスケジュール実行、および Agent サービスの状態を表示する。","when":"朝のチェック、バックアップ / メンテナンスジョブのアラート時、「夜間ジョブは実行されたか」の確認、またはフェイルオーバー後にジョブが正しいレプリカで実行されているかの確認に。","caution":"msdb のジョブ履歴には上限がある (デフォルトは合計 1,000 行、ジョブあたり 100 行)。頻繁に実行されるジョブは古い失敗をすぐに押し出すため、Agent のプロパティで上限を引き上げる。message 列は 4,000 文字で切り詰められる。長い出力にはジョブステップに出力ファイルを定義する。Agent サービスが停止している場合、スケジュールされたジョブは実行されず、エラーも報告されない。読み取り専用クエリのため安全。","note":"msdb.dbo.agent_datetime は文書化されていないが広く使われている。AG では、ジョブはすべてのレプリカに存在し、最初のステップで sys.fn_hadr_is_primary_replica(N'Musteri') によりロールを確認する必要がある。dbatools: Get-DbaAgentJobHistory -SqlInstance SQL01 -StartDate (Get-Date).AddDays(-1) -OutcomeType Failed。","tags":["sql agent","job history","sysjobhistory","job failure","msdb","scheduled job"]}]},"recipes/mongodb.json":{"engineId":"mongodb","engine":"MongoDB","order":5,"recipes":[{"id":"rs-add-member","task":"レプリカセットにメンバーを追加する","category":"レプリカセット","command":"rs.add({ host: \"mongo2:27017\", priority: 1, votes: 1 })","what":"既存のレプリカセットに新しいメンバー (セカンダリ) を追加し、初期同期を開始する。","when":"読み取り容量を増やすため、または冗長性のために新しいノードを追加する場合。","caution":"新しいメンバーは初期同期中にプライマリからデータを取得する。データセットが大きい場合、ネットワークとディスクに負荷がかかる。","tags":["replica","rs.add","member","member","add"]},{"id":"rs-remove-member","task":"レプリカセットからメンバーを削除する","category":"レプリカセット","command":"rs.remove(\"mongo2:27017\")","what":"指定したホストをレプリカセットの構成から削除する。","when":"ノードをサービスから外す場合やハードウェアを交換する場合。","caution":"プライマリを削除しない。過半数を崩すような形でメンバーを削除すると、セットが読み取り・書き込みともに利用できなくなる可能性がある。","tags":["replica","rs.remove","member","member","remove"]},{"id":"rs-step-down","task":"プライマリを降格する (stepDown)","category":"レプリカセット","command":"rs.stepDown(60)","what":"現在のプライマリを指定した秒数だけセカンダリに降格し、新しい選挙をトリガーする。","when":"計画メンテナンスの前に、プライマリロールを別のノードに引き渡すため。","caution":"stepDown 中は短時間の書き込み停止が発生する。アプリケーションは再接続する必要がある。","tags":["replica","stepdown","primary","failover","step down"]},{"id":"rs-set-priority","task":"メンバーの優先度を変更する","category":"レプリカセット","command":"cfg = rs.conf(); cfg.members[1].priority = 2; rs.reconfig(cfg)","what":"選挙でプライマリになるための、指定したメンバーの優先度を変更する。","when":"特定のノードを優先的なプライマリにしたい場合。","caution":"reconfig は選挙をトリガーし、短時間のプライマリ変更 / 書き込み停止を引き起こすことがある。","tags":["replica","priority","reconfig","priority","election"]},{"id":"rs-status","task":"レプリカセットの状態を表示する","category":"レプリカセット","command":"rs.status()","what":"セットメンバーの状態、ロール、レプリケーション遅延、健全性を表示する。","when":"レプリケーションの健全性と遅延を確認する場合。","caution":"読み取り専用コマンドのためリスクなし。","tags":["replica","status","status","health","rs.status"]},{"id":"rs-hidden-member","task":"hidden / 非投票メンバーを構成する","category":"レプリカセット","command":"cfg = rs.conf(); cfg.members[2].hidden = true; cfg.members[2].priority = 0; cfg.members[2].votes = 0; rs.reconfig(cfg)","what":"メンバーを hidden (アプリケーションから不可視)、非投票、優先度 0 にし、バックアップ / 分析専用に使用する。","when":"バックアップや分析クエリを分離したい場合。","caution":"hidden メンバーは優先度 0 である必要がある。そうでないと reconfig は失敗する。","tags":["replica","hidden","votes","hidden","non-voting"]},{"id":"rs-resync","task":"メンバーをゼロから再同期する","category":"レプリカセット","command":"// On the SECONDARY to be resynced (NEVER on the PRIMARY):\ndb.getSiblingDB(\"admin\").shutdownServer()\n// At the OS level: empty the dbPath contents (or move them elsewhere as a backup)\n// and restart mongod with the same configuration; the member starts an initial sync automatically.\n// Monitor progress (stateStr: STARTUP2 -> SECONDARY):\nrs.status()","what":"MongoDB には独立した resync コマンドはない。セカンダリを停止し、データディレクトリを空にして再起動すると、プライマリ (または同期ソース) からの新しい初期同期が開始される。","when":"メンバーが大きく遅れて oplog ウィンドウの外に出た場合 (RECOVERING / too stale)、またはデータに不整合が生じた場合。","caution":"メンバー上のすべてのローカルデータが削除されて再取得されるため、セカンダリでのみ実施し、過半数が稼働し続けることを確認する。同期時間とネットワーク / ディスク負荷は大きい。非常に大きなデータセットでは、正常なメンバーのファイルシステムスナップショットからシードする方が速い。","tags":["replica","resync","initialsync","sync","resync"]},{"id":"sh-add-shard","task":"クラスタにシャードを追加する","category":"シャーディング","command":"sh.addShard(\"shardRS/mongoShard1:27018\")","what":"シャードクラスタに新しいシャード (レプリカセット) を追加する。","when":"ストレージまたはスループットの容量を水平方向に拡張する場合。","caution":"シャードを追加すると、バランサーがチャンクの移行を開始し、追加の IO 負荷が発生する。","tags":["sharding","addshard","shard","add","cluster"]},{"id":"sh-shard-collection","task":"コレクションをシャーディングする","category":"シャーディング","command":"sh.shardCollection(\"shop.customer\", { customerId: \"hashed\" })","what":"指定したコレクションを、指定したシャードキーでシャーディングする。","when":"増大するコレクションを複数のシャードに分散したい場合。","caution":"シャードキーは 5.0 以降では reshardCollection で変更でき (4.4 以降では refineCollectionShardKey で拡張可能)、ただしすべてのデータを再分散するためコストが高い。シャードキーの選択を誤ると分散が不均一になる。","tags":["sharding","shardcollection","key","customer","shard key"]},{"id":"sh-start-balancer","task":"バランサーを開始する","category":"シャーディング","command":"sh.startBalancer()","what":"チャンクを分散するバランサープロセスを有効にする。","when":"メンテナンス後にバランシングを再度有効にしたい場合。","caution":"バランサーはチャンクの移行中に IO とネットワークの負荷を生じるため、ピーク時間外にバランシングウィンドウを定義する。","tags":["sharding","balancer","start","start","rebalance"]},{"id":"sh-stop-balancer","task":"バランサーを停止する","category":"シャーディング","command":"sh.stopBalancer()","what":"チャンクの移行を行うバランサーを無効にする。","when":"バックアップ、メンテナンス、大量データロードの前に移行を停止するため。","caution":"長時間無効のままにするとシャード間の偏りが生じるため、後で再度有効にすることを忘れない。","tags":["sharding","balancer","stop","stop","maintenance"]},{"id":"sh-status","task":"シャーディングの状態を表示する","category":"シャーディング","command":"sh.status()","what":"シャード、データベース、シャーディングされたコレクション、チャンクの分散状況を要約する。","when":"クラスタの分散状態とバランサーの健全性を調べる場合。","caution":"読み取り専用コマンドのためリスクなし。","tags":["sharding","status","status","chunk","sh.status"]},{"id":"sh-add-zone","task":"ゾーン (タグ) を追加して範囲を割り当てる","category":"シャーディング","command":"sh.addShardToZone(\"shard0000\", \"TR\"); sh.updateZoneKeyRange(\"shop.customer\", { region: \"TR\" }, { region: \"TR~\" }, \"TR\")","what":"シャードをゾーンに割り当て、特定のキー範囲をそのゾーンに結び付ける (ゾーンシャーディング)。","when":"地理やハードウェアに応じて、データを特定のシャードに保持したい場合。","caution":"ゾーンの範囲はシャードキーと一致している必要がある。範囲を誤るとチャンクを移行できなくなる。","tags":["sharding","zone","tag","region","range"]},{"id":"sh-move-chunk","task":"チャンクを手動で移動する","category":"シャーディング","command":"sh.moveChunk(\"shop.customer\", { customerId: 1000 }, \"shard0001\")","what":"指定したキーを含むチャンクを、対象のシャードへ手動で移動する。","when":"不均一な分散を是正する場合や、特定のデータを配置する場合。","caution":"手動での移動はバランサーと競合することがある。大きなチャンクの移行は IO 負荷と短時間のロックを生じる。","tags":["sharding","movechunk","chunk","move","manual"]},{"id":"compact-collection","task":"コレクションを圧縮する (compact)","category":"メンテナンス","command":"db.runCommand({ compact: \"customer\" })","what":"コレクションとそのインデックスをディスク上で書き換え、空き領域を回収する。","when":"大量の削除 / 更新の後にディスク領域を回収したい場合。","caution":"4.4 以降では、compact は読み取り / 書き込みをブロックせず、同じコレクションに対する特定の DDL 操作 (drop、createIndex、dropIndex など) のみをブロックする。それでも大量の IO を生じ、常にオペレーティングシステムへ領域を返すとは限らない。可能であればセカンダリ上で、メンテナンス時間帯に実行する。","tags":["compact","storage","maintenance","disk","storage"]},{"id":"create-index-background","task":"インデックスを作成する (非ブロッキング)","category":"メンテナンス","command":"db.customer.createIndex({ email: 1 }, { name: \"idx_email\" })","what":"指定したフィールドにインデックスを作成する。MongoDB 4.2 以降、インデックスの構築はデフォルトで書き込みをブロックしない。","when":"クエリ性能を改善するために新しいインデックスを追加する場合。","caution":"大きなコレクションでは、インデックスの構築は CPU と IO を消費し、プライマリの負荷が増加することがある。","since":"MongoDB 4.2","note":"MongoDB 4.2 で新しいインデックス構築プロセスが導入され、インデックスの作成はデフォルトで書き込みをブロックしなくなった。そのため従来の { background: true } オプションは不要であり、4.2 以降は無視される。","tags":["index","createindex","background","create","performance"]},{"id":"collection-stats","task":"インデックスとコレクションのサイズを表示する","category":"メンテナンス","command":"db.customer.stats({ indexDetails: true })","what":"コレクションのサイズ、ストレージサイズ、各インデックスのサイズを報告する。","when":"ストレージ使用量とインデックスのコストを分析する場合。","caution":"読み取り専用コマンドのためリスクなし。","tags":["stats","index","size","collection","storage"]},{"id":"log-rotate","task":"ログファイルをローテーションする","category":"メンテナンス","command":"db.adminCommand({ logRotate: 1 })","what":"現在のログファイルを閉じ、新しいログファイルを開く (ログローテーション)。","when":"ログファイルが大きくなった場合やアーカイブの前に。","caution":"OS のログローテーションと併用する場合は、競合しないよう設定を確認する。","tags":["log","logrotate","rotate","maintenance","archive"]},{"id":"current-op-long","task":"長時間実行中の操作を特定する","category":"メンテナンス","command":"db.currentOp({ \"active\": true, \"secs_running\": { $gt: 5 } })","what":"5 秒を超えて実行中のアクティブな操作を一覧表示する。","when":"低速化やロックアップ時に問題のあるクエリを特定する場合。","caution":"読み取り専用コマンドのためリスクなし。","tags":["currentop","long","long-running","operation","diagnostics"]},{"id":"kill-op","task":"操作を強制終了する","category":"メンテナンス","command":"db.killOp(12345)","what":"指定した opid の実行中の操作を終了する。","when":"クエリがシステムをロックアップさせている場合や、実行時間が長すぎる場合。","caution":"書き込み操作を強制終了すると、部分的な変更が残る可能性がある。システム / レプリケーションの操作は強制終了しない。","tags":["killop","kill","operation","kill","diagnostics"]},{"id":"set-parameter","task":"実行時パラメータを変更する","category":"パラメータ","command":"db.adminCommand({ setParameter: 1, cursorTimeoutMillis: 600000 })","what":"サーバーを再起動せずに実行時パラメータを変更する。","when":"サーバーの動作を一時的に調整したい場合。","caution":"変更は永続化されず、再起動すると設定ファイルの値に戻る。誤った値は性能を低下させることがある。","tags":["setparameter","parameter","runtime","setting","admin"]},{"id":"set-profiling","task":"プロファイリングレベルを設定する","category":"パラメータ","command":"db.setProfilingLevel(1, { slowms: 100 })","what":"低速クエリ (100 ms 超) を system.profile コレクションに記録する (レベル 1)。","when":"低速クエリを診断したい場合。","caution":"レベル 2 はすべての操作を記録し、大きなオーバーヘッドを生じる。プロファイリングデータはディスク領域を消費する。","tags":["profiling","slowms","profiler","slow","diagnostics"]}]},"recipes/mongodb-ext.json":{"engineId":"mongodb","engine":"MongoDB","order":2,"recipes":[{"id":"rs-oplog-window","task":"oplog ウィンドウとレプリケーション遅延を測定する","category":"レプリカセット","command":"// Oplog size and the time span it covers (oplog window):\nrs.printReplicationInfo()\n// Lag of each secondary relative to the primary:\nrs.printSecondaryReplicationInfo()\n// Lag in seconds and sync source, for monitoring/scripts:\nconst s = rs.status(); const p = s.members.find(m => m.stateStr === \"PRIMARY\");\ns.members.filter(m => m.stateStr === \"SECONDARY\").map(m => ({ host: m.name, lagSec: (p.optimeDate - m.optimeDate) / 1000, syncSource: m.syncSourceHost }))\n// Window (hours):\ndb.getReplicationInfo().timeDiffHours","what":"oplog が何時間分の書き込みを保持しているか (oplog ウィンドウ)、および各セカンダリがプライマリから何秒遅れているかを、同期ソースとともに表示する。","when":"レプリケーション遅延のアラート時、計画メンテナンスの前にメンバーが停止していられる時間を算出する場合、および一括書き込みジョブの後に。","caution":"メンバーが oplog ウィンドウより長く停止していると 'too stale' となり、初期同期が必要になる。一括更新 / 削除ジョブは数時間でウィンドウを縮める可能性があるため、ウィンドウはピーク負荷時の値で判断する。遅延の計算は optimeDate の差に基づく。プライマリが書き込みを受けていない場合、遅延は大きく見えないが、ウィンドウも縮まらない。","since":"MongoDB 4.4","note":"rs.printSlaveReplicationInfo() は 4.4 で rs.printSecondaryReplicationInfo() に名称変更された。ウィンドウが小さすぎる場合は replSetResizeOplog で oplog を拡大する (rs-oplog-resize を参照)。遅延メンバーは secondaryDelaySecs (4.4 では slaveDelay) の分だけ遅れて表示されるため、遅延アラートから除外する。","tags":["oplog","oplog window","replication lag","delay","secondary","printReplicationInfo"],"untested":true},{"id":"rs-oplog-resize","task":"oplog のサイズをオンラインで変更する (replSetResizeOplog)","category":"レプリカセット","command":"// Current oplog size (MB):\ndb.getSiblingDB(\"local\").oplog.rs.stats().maxSize / 1024 / 1024\n// Resize the oplog to 50 GB (in MB; run on each member separately, secondaries first):\ndb.adminCommand({ replSetResizeOplog: 1, size: 51200 })\n// Minimum retention period (hours), independent of size:\ndb.adminCommand({ replSetResizeOplog: 1, minRetentionHours: 48 })\n// Verify the result:\nrs.printReplicationInfo()","what":"稼働中のメンバーの oplog を再起動なしで拡大または縮小する。minRetentionHours は、サイズ上限を超えても oplog エントリを最低限の期間保持する。","when":"oplog ウィンドウがメンテナンスや初期同期の所要時間をカバーしない場合、または一括書き込みジョブがウィンドウを縮める場合。","caution":"このコマンドは実行したメンバーにのみ影響し、レプリケートされないため、すべてのメンバーで適用する。同期ソースとして機能するメンバーでも、ウィンドウが十分である必要がある。縮小してもディスク領域はすぐには OS に返されない。そのためには oplog.rs に対する compact が必要。minRetentionHours を指定すると、書き込み量によって oplog が size を超えて増大することがあるため、それに応じてディスクを計画する。","since":"MongoDB 4.4","note":"新しいサイズは再起動後も維持されるが、コマンドで設定した minRetentionHours は維持されないため、保持するには storage.oplogMinRetentionHours も設定する。size は 990 MB 以上である必要がある。設定の replication.oplogSizeMB の変更は、oplog の初回作成時にのみ有効になる。","tags":["oplog","resize","replSetResizeOplog","minRetentionHours","size","oplog window"],"untested":true},{"id":"rs-force-reconfig","task":"過半数を失った後にレプリカセットの再構成を強制する (force reconfig)","category":"レプリカセット","command":"// On a surviving member with the most recent optime (runs as a secondary):\nrs.status().members.map(m => ({ host: m.name, state: m.stateStr, health: m.health, optime: m.optimeDate }))\ncfg = rs.conf()\ncfg.members.map((m, i) => ({ i: i, host: m.host }))\n// Keep only the reachable members (example: members 0 and 2):\ncfg.members = [cfg.members[0], cfg.members[2]]\nrs.reconfig(cfg, { force: true })\n// Verify the new primary election:\nrs.status().members.map(m => ({ host: m.name, state: m.stateStr }))","what":"投票メンバーの過半数が恒久的に失われた場合 (例: データセンター全体の喪失)、生き残ったメンバーから新しい構成を作成し、セットが再びプライマリを選出できるようにする。","when":"災害シナリオでのみ: 過半数が戻らず、セットが読み取り専用のまま動けない場合。","caution":"これは最後の手段である。失われたメンバーが後で古い構成のまま復帰すると、スプリットブレインやロールバックが発生する可能性がある。それらをネットワークから隔離し、復帰させる際はデータを消去して初期同期で追加する。最新の optime を持つメンバーを選ぶ。そうしないと、他のメンバーで過半数コミットされていない書き込みがロールバックされる。通常のメンバー変更に force を使用しない。","since":"MongoDB 4.4","note":"force reconfig は構成バージョンを大きなランダム値だけ増加させ、セカンダリで実行できる唯一の reconfig 形式である。4.4 以降、通常の reconfig で一度に追加 / 削除できる投票メンバーは最大 1 つだが、force にはこの制限は適用されない。","tags":["force reconfig","majority","disaster","recovery","split-brain","rs.reconfig"],"untested":true},{"id":"rs-rolling-maintenance","task":"レプリカセットのローリングメンテナンス (再起動、OS パッチ、マイナーアップグレード)","category":"レプリカセット","command":"// 1) Before starting: all members healthy, low lag, and an oplog window longer than the maintenance\nrs.printSecondaryReplicationInfo()\n// 2) Clean shutdown on the SECONDARY under maintenance (then OS/binary work, restart with the same config):\ndb.getSiblingDB(\"admin\").shutdownServer({ timeoutSecs: 60 })\n// 3) Wait until the member is SECONDARY and lag has closed, then move to the next secondary:\nrs.status().members.map(m => ({ host: m.name, state: m.stateStr, health: m.health }))\n// 4) When all secondaries are done, on the PRIMARY: hand over to a secondary that catches up within 30 s\nrs.stepDown(120, 30)\n// 5) The old primary is now a SECONDARY: apply steps 2 and 3 to it","what":"セカンダリを先に、プライマリを最後にして、メンバーを 1 つずつメンテナンスに入れる順序を示す。これにより、セットをサービスから外さずに再起動、OS パッチ、バイナリ更新を行える。","when":"計画的な OS / カーネルの更新、マイナーバージョンのアップグレード、mongod パラメータの変更、ディスク / ハードウェアのメンテナンス時に。","caution":"一度に複数のメンバーを停止しない。3 メンバーのセットで 2 つを失うと過半数を失う。各メンバーの後で SECONDARY 状態と遅延の解消を確認する。stepDown は短時間の書き込み中断を引き起こすため、ドライバーが retryable writes で再接続することを確認する。アービターがある場合は、同じ手順の中で扱う。","since":"MongoDB 4.4","note":"rs.stepDown(stepDownSecs, secondaryCatchUpPeriodSecs): 2 番目のパラメータは、プライマリがセカンダリの追いつきを待つ時間である。どのセカンダリも追いつかない場合、stepDown は失敗し、プライマリはそのまま残る。メンテナンス中に特定のメンバーがプライマリにならないようにするには、そのメンバーで rs.freeze(seconds) を実行する。","tags":["rolling","maintenance","restart","stepDown","upgrade","patching"],"untested":true},{"id":"sh-balancer-window","task":"バランサーの状態、アクティブウィンドウ、コレクション単位のバランシング","category":"シャーディング","command":"// Is the balancer enabled, is it running a round right now:\nsh.getBalancerState()\ndb.adminCommand({ balancerStatus: 1 })\n// Run the balancer only between 01:00 and 05:00 (on mongos):\ndb.getSiblingDB(\"config\").settings.updateOne({ _id: \"balancer\" }, { $set: { activeWindow: { start: \"01:00\", stop: \"05:00\" } } }, { upsert: true })\n// Remove the window:\ndb.getSiblingDB(\"config\").settings.updateOne({ _id: \"balancer\" }, { $unset: { activeWindow: true } })\n// Disable / enable balancing for a single collection:\nsh.disableBalancing(\"shop.musteri\")\nsh.enableBalancing(\"shop.musteri\")\n// Whether the collection is balanced (4.4+):\ndb.adminCommand({ balancerCollectionStatus: \"shop.musteri\" })","what":"バランサーが有効でラウンドを実行中かどうかを表示し、チャンクの移行を時間ウィンドウに制限し、単一コレクションのバランシングを無効化または有効化する。","when":"チャンクの移行が日中の性能を損なう場合、バックアップウィンドウ中、または 1 つのコレクションで移行の問題を切り分ける場合。","caution":"狭すぎるウィンドウではデータの増加に追いつけず、シャード間の偏りが生じる。balancerCollectionStatus で定期的にバランスを確認する。ウィンドウが閉じる前に開始された移行は完了するまで実行される。コレクション単位のバランシングを無効のままにすると、そのコレクションは単一のシャード上で増大し続ける。","since":"MongoDB 6.0","note":"activeWindow の時刻は、config サーバーレプリカセットのプライマリのローカルタイムゾーンで評価される。6.0.3 以降、バランサーはチャンク数ではなくシャード間のデータサイズの差に基づいて判断する。データがバランスしていても、sh.status() のチャンク数は不均一に見えることがある。","tags":["balancer","activeWindow","window","migration","sharding","balancerCollectionStatus"],"untested":true},{"id":"sh-jumbo-chunks","task":"jumbo チャンクを特定し、分割してフラグをクリアする","category":"シャーディング","command":"// Chunks flagged as jumbo (5.0+ config.chunks links to the collection by uuid):\nconst uuid = db.getSiblingDB(\"config\").collections.findOne({ _id: \"shop.musteri\" }).uuid;\ndb.getSiblingDB(\"config\").chunks.find({ uuid: uuid, jumbo: true }, { min: 1, max: 1, shard: 1 })\n// If the chunk can be split, split it at the median:\nsh.splitFind(\"shop.musteri\", { musteriId: 1000 })\n// Last resort for an indivisible chunk, clear the flag manually (a successful split already clears it):\ndb.adminCommand({ clearJumboFlag: \"shop.musteri\", find: { musteriId: 1000 } })\n// If a single key value is too large, refine the key (4.4+):\ndb.adminCommand({ refineCollectionShardKey: \"shop.musteri\", key: { musteriId: 1, siparisId: 1 } })","what":"バランサーが移動できなかったために jumbo フラグが付いたチャンクを一覧表示し、分割可能なものを分割して jumbo フラグをクリアする。単一値の巨大なチャンクについて、シャードキーを精緻化する方法を示す。","when":"1 つのシャードが他より明らかに大きいままの場合、sh.status() の出力に jumbo が表示される場合、またはバランサーが移行エラーを報告する場合。","caution":"すべてのドキュメントが同じシャードキー値を持つチャンクは分割できない。恒久的な対策は、refineCollectionShardKey または reshardCollection でシャードキーを変更することだけである。refineCollectionShardKey には、新しいキーをサポートするインデックスが事前に存在している必要がある。分割せずに jumbo フラグをクリアすると、バランサーは同じチャンクを再試行して再び失敗する。","since":"MongoDB 5.0","note":"カーディナリティの低いシャードキーや、1 つの値に集中するキー (例: status、country) が jumbo チャンクの最も一般的な原因である。5.0 より前では、config.chunks ドキュメントは ns フィールドで照会する。clearJumboFlag は 4.2.3/4.0.15 で追加された。","tags":["jumbo","chunk","split","clearJumboFlag","shard key","refineCollectionShardKey"],"untested":true},{"id":"sh-shard-key-check","task":"シャードキーの選択とデータ分散を確認する (getShardDistribution、analyzeShardKey)","category":"シャーディング","command":"// Data and document distribution of the collection across shards:\ndb.getSiblingDB(\"shop\").musteri.getShardDistribution()\n// Cardinality, frequency and monotonicity analysis of the current or candidate shard key:\ndb.adminCommand({ analyzeShardKey: \"shop.musteri\", key: { musteriId: 1 }, keyCharacteristics: true, readWriteDistribution: false })\n// For read/write distribution, enable query sampling first (10 samples per second):\ndb.adminCommand({ configureQueryAnalyzer: \"shop.musteri\", mode: \"full\", samplesPerSecond: 10 })\ndb.adminCommand({ analyzeShardKey: \"shop.musteri\", key: { musteriId: 1 }, keyCharacteristics: false, readWriteDistribution: true })\n// Turn sampling off when done:\ndb.adminCommand({ configureQueryAnalyzer: \"shop.musteri\", mode: \"off\" })","what":"コレクションのデータが各シャードに何パーセントあるかを表示する。analyzeShardKey は、現在または候補のシャードキーのカーディナリティ、最頻値、単調性、およびサンプリングしたクエリが単一シャードを対象とするか全シャード (scatter-gather) を対象とするかを報告する。","when":"新しいコレクションをシャーディングする前、ホットシャードや不均一な増大に気付いた場合、および reshardCollection を決定する前に。","caution":"analyzeShardKey にはキーをサポートするインデックスが必要で、大きなコレクションではドキュメントをサンプリングするため、ピーク時には読み取り負荷が増える。クエリサンプリングが有効な間、サンプルは config.sampledQueries に書き込まれるため、分析が終わったら無効にする。単調増加するキー (ObjectId、タイムスタンプ) では、すべての挿入が 1 つのシャードに集中する。","since":"MongoDB 7.0","note":"analyzeShardKey と configureQueryAnalyzer は 7.0 で追加され、レプリカセットでも機能する。良いシャードキーは、カーディナリティが高く、頻度が低く、単調でなく、頻繁なクエリのフィルタに現れるものである。hashed キーは分散を改善するが、範囲クエリを scatter-gather に変える。","tags":["shard key","analyzeShardKey","getShardDistribution","cardinality","distribution","hot shard"],"untested":true},{"id":"explain-execstats","task":"実際の実行統計で実行計画を調べる (explain executionStats)","category":"パフォーマンス","command":"db.musteri.find({ sehir: \"Ankara\", durum: \"aktif\" }).sort({ kayitTarihi: -1 }).explain(\"executionStats\")\n// Summary: winning plan, returned documents, examined keys/documents and time\nconst e = db.musteri.find({ sehir: \"Ankara\", durum: \"aktif\" }).sort({ kayitTarihi: -1 }).explain(\"executionStats\");\n({ plan: e.queryPlanner.winningPlan, n: e.executionStats.nReturned, keys: e.executionStats.totalKeysExamined, docs: e.executionStats.totalDocsExamined, ms: e.executionStats.executionTimeMillis })\n// For an aggregation:\ndb.musteri.explain(\"executionStats\").aggregate([{ $match: { sehir: \"Ankara\" } }, { $group: { _id: \"$durum\", n: { $sum: 1 } } }])","what":"クエリを実行し、採用されたプラン (IXSCAN/COLLSCAN、SORT ステージ)、返されたドキュメント数、調べたインデックスキー数とドキュメント数、所要時間を表示する。","when":"プロファイラーやログで遅く見えるクエリを分析する場合、および新しいインデックスが実際に使われていることを確認する場合。","caution":"executionStats はクエリを実際に実行するため、ピーク時に重いクエリを explain すると負荷も増える。書き込みコマンド (update/delete/findAndModify) では、explain はデータを変更しないがプランは実行する。totalDocsExamined/nReturned の比率が高い場合や、プランにメモリ内 SORT ステージがある場合は、インデックスが適切でないことを意味する。","since":"MongoDB 4.4","note":"複合インデックスを設計する際は ESR ルールを適用する: 等価 (Equality) フィールドを先に、次にソート (Sort)、次に範囲 (Range)。却下されたプランも確認するには explain(\"allPlansExecution\") を使用する。7.0 以降、クエリが Slot-Based Engine で実行される場合、winningPlan には queryPlan と slotBasedPlan フィールドが含まれる。","tags":["explain","executionStats","IXSCAN","COLLSCAN","plan","index"]},{"id":"profiler-analyze","task":"プロファイラーのデータから最も遅いクエリとクエリシェイプを抽出する","category":"パフォーマンス","command":"// Recent slow operations (in the db where profiling is on; see set-profiling):\ndb.system.profile.find({ millis: { $gte: 100 } }, { ts: 1, ns: 1, op: 1, millis: 1, planSummary: 1, keysExamined: 1, docsExamined: 1, nreturned: 1, appName: 1 }).sort({ ts: -1 }).limit(20)\n// Total time per query shape (those consuming the most time):\ndb.system.profile.aggregate([\n  { $group: { _id: { ns: \"$ns\", plan: \"$planSummary\", shape: \"$queryHash\" }, n: { $sum: 1 }, totalMs: { $sum: \"$millis\" }, maxMs: { $max: \"$millis\" }, avgDocs: { $avg: \"$docsExamined\" } } },\n  { $sort: { totalMs: -1 } },\n  { $limit: 10 }\n])\n// Queries not using an index (COLLSCAN):\ndb.system.profile.find({ planSummary: \"COLLSCAN\" }, { ns: 1, millis: 1, command: 1 }).sort({ millis: -1 }).limit(10)","what":"system.profile コレクションのレコードから、最近の低速操作、クエリシェイプ (queryHash) ごとの合計時間、インデックスを使用しない COLLSCAN クエリを一覧表示する。","when":"低速化の苦情に対し、どのクエリがサーバー時間を消費しているかを特定し、インデックスの必要性を判断するため。","caution":"system.profile はデフォルトで 1 MB の capped コレクションで、データベースごとに存在する。高負荷システムではレコードが数分でロールオーバーするため、プロファイリングが有効な間かその直後に分析する。プロファイリングレベル 2 または slowms 0 はすべての操作を書き込み、大きなオーバーヘッドを生じる。レコードは実行されたメンバー上にのみ保持され、レプリケートされない。","since":"MongoDB 4.4","note":"プロファイリングが無効でも、slowms (デフォルト 100 ms) を超える操作は 'Slow query' として mongod ログに書き込まれる。ログ内の attr.durationMillis と attr.planSummary で同じ診断ができる。8.0 以降では、クエリシェイプ用に planCacheShapeHash フィールドも書き込まれる。","tags":["profiler","system.profile","slow query","top queries","COLLSCAN","queryHash"]},{"id":"index-usage-hide","task":"未使用のインデックスを特定し、削除前に非表示にする (hideIndex)","category":"パフォーマンス","command":"// Usage counter per index (on this member, since the last restart):\ndb.musteri.aggregate([{ $indexStats: {} }, { $project: { name: 1, ops: \"$accesses.ops\", since: \"$accesses.since\" } }, { $sort: { ops: 1 } }])\n// Hide it from the planner before dropping (the index keeps being maintained):\ndb.musteri.hideIndex(\"idx_email\")\n// Revert immediately if problems appear:\ndb.musteri.unhideIndex(\"idx_email\")\n// If the observation period passes without issues:\ndb.musteri.dropIndex(\"idx_email\")","what":"$indexStats は各インデックスが使用された回数を表示する。hideIndex はインデックスを削除せずにクエリプランナーから隠すため、削除した場合の影響を元に戻せる形でテストできる。","when":"書き込みオーバーヘッドとストレージを増やす不要なインデックスを整理する場合。","caution":"カウンターはメンバーごとで、再起動でリセットされる。読み取りがセカンダリに向かう場合は、すべてのメンバーを確認し、十分に長い期間 (月末レポートを含む) 観察する。ops が 0 の一意インデックスや TTL インデックスも必要な場合がある: 一意制約と TTL による削除はカウンターに現れない。非表示のインデックスも書き込み時には維持され、非表示の一意インデックスも引き続き制約を強制する。","since":"MongoDB 4.4","note":"hideIndex には featureCompatibilityVersion 4.4 以上が必要。_id インデックスは非表示にできない。unhideIndex による再表示は再構築不要で、即座に有効になる。","tags":["indexStats","hideIndex","unused index","index cleanup","dropIndex","index"]},{"id":"connections-by-app","task":"アプリケーションとクライアント別に接続数を数える (コネクションストームの診断)","category":"パフォーマンス","command":"// Total, available and rejected connection counts:\ndb.serverStatus().connections\n// Count connections by application name and client IP:\ndb.getSiblingDB(\"admin\").aggregate([\n  { $currentOp: { allUsers: true, idleConnections: true } },\n  { $group: { _id: { app: \"$appName\", client: { $arrayElemAt: [{ $split: [\"$client\", \":\"] }, 0] } }, conns: { $sum: 1 }, active: { $sum: { $cond: [\"$active\", 1, 0] } } } },\n  { $sort: { conns: -1 } },\n  { $limit: 20 }\n])","what":"サーバー上の合計接続数と利用可能な接続数を表示し、オープン中の接続を appName とクライアント IP ごとに、アクティブな数とともにグループ化する。","when":"接続数が急増した場合、'connection refused' やプールのタイムアウトエラーの発生時、どのアプリケーションサーバーが接続をリークしているかを特定するため。","caution":"idleConnections: true はすべてのアイドル接続も返すため、数千の接続があるシステムでは出力が大きくなる。そのため $group による要約が重要である。client が null の行は内部スレッドである。各接続は約 1 MB のメモリを消費する。コネクションストームは WiredTiger キャッシュ外のメモリも増大させる。","since":"MongoDB 4.4","note":"恒久的な対策は通常ドライバー側にある: maxPoolSize、maxIdleTimeMS、アプリケーションインスタンスの数。アプリケーションが appName を設定していないと区別が難しいため、接続文字列に appName=<service> を指定するよう依頼する。net.maxIncomingConnections と OS の ulimit -n の値がハード上限を決める。","tags":["connections","connection count","currentOp","appName","connection storm","pool"]},{"id":"index-build-monitor","task":"進行中のインデックス構築を監視・中止する","category":"メンテナンス","command":"// Index builds in progress and their completion percentage:\ndb.getSiblingDB(\"admin\").aggregate([\n  { $currentOp: { allUsers: true } },\n  { $match: { $or: [{ \"command.createIndexes\": { $exists: true } }, { desc: /^IndexBuildsCoordinator/ }] } },\n  { $project: { opid: 1, desc: 1, ns: 1, secs_running: 1, msg: 1, progress: 1, \"command.indexes.name\": 1 } }\n])\n// Abort the build (on the primary; in a replica set it stops on all members):\ndb.musteri.dropIndex(\"idx_email\")","what":"実行中のインデックス構築を、スキャン済みドキュメント数と進捗率 (progress.done / progress.total) とともに一覧表示する。必要に応じて dropIndex で構築を中止する。","when":"大きなコレクションで開始した createIndex がいつ終わるかを見積もる場合、またはピーク時に負荷を生じている構築を停止する場合。","caution":"インデックス構築の中止には killOp ではなく dropIndex/dropIndexes を使用する。レプリカセットではプライマリで実行し、中止がすべてのメンバーに伝播するようにする。構築中、コレクションに対する一部の DDL 操作は待機する。構築の最後に短時間の排他ロックが取得され、非常に書き込みが多い状況ではその瞬間にレイテンシが生じることがある。","since":"MongoDB 4.4","note":"4.4 以降のレプリカセットでは、インデックス構築はすべてのデータ保持メンバーで同時に実行され、commitQuorum (デフォルトは votingMembers) が満たされた時点でコミットされる。セカンダリが遅れていると、プライマリでも構築は完了しない。5.0 以降、クリーンシャットダウンで中断された構築は、再起動後に中断箇所から再開される。","tags":["index build","createIndex","progress","monitor","dropIndex","commitQuorum"]},{"id":"rolling-index-build","task":"レプリカセットでのローリングインデックス構築 (メンバーごと)","category":"メンテナンス","command":"// 1) Shut down a SECONDARY; comment out replication.replSetName and start it standalone on another port:\n//    mongod --config /etc/mongod.conf --port 27217 --setParameter disableLogicalSessionCacheRefresh=true\n// 2) Build the index on the standalone member:\ndb.getSiblingDB(\"shop\").musteri.createIndex({ email: 1 }, { name: \"idx_email\" })\n// 3) Restart with the normal configuration; wait until it is SECONDARY and lag has closed:\nrs.printSecondaryReplicationInfo()\n// 4) When all secondaries are done, step down the primary and apply steps 1-3 to the old primary:\nrs.stepDown(120, 30)","what":"メンバーを一時的にセット外のスタンドアロンとして実行し、各メンバーで個別にインデックスを構築する。プライマリが構築の負荷を負うことはない。","when":"非常に大きなコレクションで、デフォルトの分散構築によるプライマリとレプリケーション遅延への影響が許容できない場合。","caution":"各メンバーのメンテナンス時間は oplog ウィンドウより短くする必要がある。そうしないと、メンバーは復帰時に too stale となる。ローリング方式で一意インデックスを構築する場合は、構築全体の間コレクションへの書き込みを停止する。そうしないと、一部のメンバーに制約違反のドキュメントが残る可能性がある。アプリケーションが接続しないよう、スタンドアロンのメンバーは別のポートで起動する。","since":"MongoDB 4.4","note":"4.4 以降、デフォルトの構築はすでに非ブロッキングで、すべてのメンバーで同時に実行される。ローリング方式はその負荷が許容できない場合にのみ必要である。シャードクラスタでは、事前にバランサーを停止したうえで、各シャードのレプリカセットごとに手順を実施する。","tags":["rolling index","index build","standalone","replica","createIndex","maintenance"],"untested":true},{"id":"ttl-index","task":"TTL インデックスを作成し、有効期限を変更し、TTL による削除を監視する","category":"メンテナンス","command":"// Automatically delete documents lastSeen + 3600 s later:\ndb.oturum.createIndex({ lastSeen: 1 }, { expireAfterSeconds: 3600, name: \"ttl_lastSeen\" })\n// Change the expiry without rebuilding the index:\ndb.runCommand({ collMod: \"oturum\", index: { name: \"ttl_lastSeen\", expireAfterSeconds: 7200 } })\n// TTL indexes on the collection and their expiry:\ndb.oturum.getIndexes().filter(i => i.expireAfterSeconds !== undefined)\n// TTL monitor statistics (deleted documents, passes):\ndb.serverStatus().metrics.ttl","what":"日付フィールドから一定時間後にドキュメントを自動削除する TTL インデックスを作成し、collMod で再構築なしに有効期限を変更し、TTL モニターが削除したドキュメント数を表示する。","when":"セッション、ログ、一時トークンなどの期限付きデータを、アプリケーションに削除ジョブを書かずに整理する場合、および増大するコレクションが縮小しない理由を調べる場合。","caution":"TTL モニターはデフォルトで 60 秒ごとに実行されるため、削除は即時ではない。フィールドは Date 型 (または Date の配列) である必要がある。文字列の日付やフィールドのないドキュメントは削除されない。有効期限を短縮すると、多数のドキュメントが一度に削除され、書き込み負荷とレプリケーション遅延が生じる。削除はプライマリでのみ行われ、oplog に書き込まれる。","since":"MongoDB 5.1","note":"TTL インデックスは単一フィールドである必要がある (複合 TTL はサポートされない)。既存の非 TTL 単一フィールドインデックスに collMod で expireAfterSeconds を追加することは 5.1 以降で可能。既存の TTL の有効期限の変更は古いバージョンでも機能する。特定の時刻に削除するには expireAfterSeconds: 0 を使用し、フィールドに削除時刻を格納する。","tags":["ttl","expireAfterSeconds","collMod","auto delete","index","metrics.ttl"]},{"id":"wt-cache-pressure","task":"WiredTiger キャッシュの負荷を測定する (使用率、ダーティ率、アプリケーションによる eviction)","category":"パフォーマンス","command":"const c = db.serverStatus().wiredTiger.cache;\nconst max = c[\"maximum bytes configured\"];\n({\n  maxGB: (max / 1024 ** 3).toFixed(1),\n  usedPct: (100 * c[\"bytes currently in the cache\"] / max).toFixed(1),\n  dirtyPct: (100 * c[\"tracked dirty bytes in the cache\"] / max).toFixed(1),\n  appThreadEvictedPages: c[\"pages evicted by application threads\"],\n  pagesReadIntoCache: c[\"pages read into cache\"]\n})\n// Read/write ticket usage and queue:\ndb.serverStatus().wiredTiger.concurrentTransactions","what":"WiredTiger キャッシュのサイズ、その使用率とダーティ率、アプリケーションスレッドが強制的に追い出した (evict) ページ数、読み取り / 書き込みチケットの状態を表示する。","when":"ディスク読み取りが増加した場合、レイテンシが急上昇した場合、書き込みスループットが低下した場合、またはキャッシュのサイジング時に。","caution":"使用率が 80% (eviction_target) を超えるとバックグラウンドの eviction が始まる。95% (eviction_trigger) ではアプリケーションスレッドも eviction に参加し、クエリが遅くなる。ダーティデータでは 5% が目標、20% がトリガーである。常に 20% 付近にある場合は、ディスクの書き込み能力が不足している。pages evicted by application threads カウンターの増加は、ユーザーが直接感じるレイテンシである。値は累積カウンターのため、2 つのサンプル間の差を確認する。","since":"MongoDB 7.0","note":"デフォルトのキャッシュサイズは (RAM - 1 GB) / 2 と 256 MB の大きい方である。コンテナ内では cgroup の制限から計算される。storage.wiredTiger.engineConfig.cacheSizeGB を増やすと OS のページキャッシュが減る。RAM の半分を超えて増やしても効果があることは稀である。7.0 ではチケット数が動的に調整される。8.0 以降、チケットのメトリクスは serverStatus().queues.execution にも表示される。","tags":["wiredtiger","cache","eviction","dirty","tickets","memory"]},{"id":"dump-restore-archive","task":"mongodump/mongorestore でアーカイブバックアップを取得し、単一コレクションをリストアする","category":"バックアップ","command":"# Single database, one compressed archive file (password is prompted):\nmongodump --uri=\"mongodb://admin@mongo1:27017/?authSource=admin\" --db=shop --gzip --archive=/backup/shop_$(date +%F).archive.gz\n# Dry run before restoring the archive under a different name:\nmongorestore --uri=\"mongodb://admin@mongo1:27017/?authSource=admin\" --gzip --archive=/backup/shop_2026-10-08.archive.gz --nsFrom=\"shop.*\" --nsTo=\"shop_restore.*\" --dryRun\n# Restore a single collection from the archive under a new name:\nmongorestore --uri=\"mongodb://admin@mongo1:27017/?authSource=admin\" --gzip --archive=/backup/shop_2026-10-08.archive.gz --nsInclude=\"shop.musteri\" --nsFrom=\"shop.*\" --nsTo=\"shop_restore.*\" --numInsertionWorkersPerCollection=4\n# Restore under the same name, dropping the existing collection:\nmongorestore --uri=\"mongodb://admin@mongo1:27017/?authSource=admin\" --gzip --archive=/backup/shop_2026-10-08.archive.gz --nsInclude=\"shop.musteri\" --drop","what":"データベースを単一の gzip アーカイブファイルにバックアップする。アーカイブからデータベース全体または単一コレクションをリストアし、必要に応じて別名 (nsFrom/nsTo) でリストアする。","when":"論理バックアップ、環境間のデータ移動、または誤って削除・破損した単一コレクションの復旧に。","caution":"mongodump は論理バックアップであり、大きなデータセットでは遅く、リストア時にインデックスが再構築される。--oplog なしで取得したダンプは、稼働中のシステムではポイントインタイムの一貫性がない。--drop はリストア開始前に対象コレクションを削除するため、まず nsTo で別名にリストアして検証する。リストアはプライマリに書き込むため、レプリケーション遅延を引き起こすことがある。","since":"MongoDB 4.4","note":"4.4 以降、データベースツール (mongodump/mongorestore) はサーバーとは別にバージョン管理されている (100.x)。バックアップ中にプライマリの読み取り負荷を減らすには、URI に readPreference=secondary を追加する。ユーザーとロールも移行するには、--restoreDbUsersAndRoles を使用したインスタンス全体のダンプを使用するか、admin データベースを別途バックアップする。","tags":["mongodump","mongorestore","backup","archive","nsFrom","restore"]},{"id":"pitr-oplog-replay","task":"oplog の再生によるポイントインタイムリストア (誤った drop/delete の前に戻す)","category":"バックアップ","command":"# 1) Full backup + oplog written during the backup (whole instance, from a replica set member):\nmongodump --uri=\"mongodb://admin@mongo2:27017/?authSource=admin&readPreference=secondary\" --oplog --gzip --out=/backup/full\n# 2) Find the time of the bad operation (mongosh): db.getSiblingDB(\"local\").oplog.rs.find({ \"o.drop\": \"musteri\" }).sort({ $natural: -1 }).limit(1)\n# 3) Dump the oplog after the backup (t: start time of the full backup, epoch seconds):\nmongodump --uri=\"mongodb://admin@mongo2:27017/?authSource=admin\" --db=local --collection=oplog.rs --query='{\"ts\":{\"$gte\":{\"$timestamp\":{\"t\":1791400000,\"i\":1}}}}' --out=/backup/oplog\n# 4) Restore the full backup together with its own oplog:\nmongorestore --uri=\"mongodb://admin@target:27017/?authSource=admin\" --gzip --oplogReplay /backup/full\n# 5) Replay the oplog up to the bad operation (oplogLimit is exclusive):\nmkdir /backup/pitr && mv /backup/oplog/local/oplog.rs.bson /backup/pitr/oplog.bson\nmongorestore --uri=\"mongodb://admin@target:27017/?authSource=admin\" --oplogReplay --oplogLimit=1791403600:1 /backup/pitr","what":"--oplog でフルバックアップの一貫性を確保し、バックアップ後に蓄積された oplog を誤った操作 (drop、一括削除) のタイムスタンプまで再生して、データをその時点に戻す。","when":"コレクションを誤って削除した場合や、誤った一括更新 / 削除が実行され、損傷前の最後の状態が必要な場合。","caution":"稼働中のシステムではなく別のターゲットにリストアし、検証後に必要なデータを移動する。バックアップ開始から誤った操作までの oplog が、まだ oplog ウィンドウ内にある必要がある。ウィンドウから外れた操作は復旧できない。--oplog はインスタンス全体のダンプでのみ機能する (--db とは併用できない)。シャードクラスタでは mongodump による一貫した PITR は不可能であり、ファイルシステムスナップショットまたはバックアップ製品が必要。","since":"MongoDB 4.4","note":"--oplogLimit=<seconds>:<ordinal> は、指定したタイムスタンプ以降のエントリを適用しない。誤った操作の ts を直接指定すると、その操作は除外される。ts の値は oplog 内で Timestamp(t, i) として表示される。ウィンドウが閉じる前に、誤った操作の直後に oplog をダンプする。","tags":["pitr","point in time","oplogReplay","oplogLimit","rollback","mongorestore"],"untested":true},{"id":"user-role-admin","task":"カスタムロールを定義し、ユーザーを作成し、ロールを付与 / 取り消し、パスワードを変更する","category":"セキュリティ","command":"use admin\ndb.createRole({\n  role: \"opsRead\",\n  privileges: [\n    { resource: { db: \"shop\", collection: \"\" }, actions: [\"find\", \"listCollections\", \"listIndexes\", \"collStats\", \"dbStats\"] },\n    { resource: { cluster: true }, actions: [\"serverStatus\", \"inprog\"] }\n  ],\n  roles: []\n})\ndb.createUser({ user: \"shop_app\", pwd: passwordPrompt(), roles: [{ role: \"readWrite\", db: \"shop\" }, { role: \"opsRead\", db: \"admin\" }] })\ndb.grantRolesToUser(\"shop_app\", [{ role: \"clusterMonitor\", db: \"admin\" }])\ndb.revokeRolesFromUser(\"shop_app\", [{ role: \"clusterMonitor\", db: \"admin\" }])\ndb.changeUserPassword(\"shop_app\", passwordPrompt())\ndb.getUser(\"shop_app\", { showPrivileges: true })\ndb.runCommand({ usersInfo: { forAllDBs: true } })","what":"特定のデータベースアクションとクラスタアクションを持つカスタムロールを定義し、そのロールと組み込みロールを持つユーザーを作成し、ロールを付与・取り消し、パスワードを変更し、全データベースのユーザーを一覧表示する。","when":"最小権限でアプリケーションアカウントや監視アカウントを作成する場合、アクセスレビューやパスワードローテーションの際に。","caution":"ユーザーが定義されたデータベース (ここでは admin) が authSource として使用され、アプリケーションの接続文字列と一致している必要がある。アプリケーションアカウントに root/dbOwner などの広範なロールを付与しない。ロールの変更は既存のセッションに即座に適用される。パスワードの変更はオープン中の接続を切断せず、新しい接続に適用される。","since":"MongoDB 4.4","note":"passwordPrompt() は、シェル履歴やプロセス一覧に残さずにパスワードを入力させる。レプリカセットとシャードクラスタでは、ユーザーはプライマリ / mongos を通じて管理され、レプリケートされる。ユーザーの有効な権限を確認するには、getUser で showPrivileges: true を使用する。","tags":["createUser","createRole","grantRolesToUser","privileges","rbac","password"]},{"id":"fcv-upgrade","task":"featureCompatibilityVersion (fCV) とメジャーアップグレードの手順を確認する","category":"アップグレード","command":"// 1) Current fCV (must be the same on all members; targetVersion appears if a transition is incomplete):\ndb.adminCommand({ getParameter: 1, featureCompatibilityVersion: 1 })\n// 2) Upgrade binaries in a rolling fashion (secondaries -> stepDown -> old primary); fCV stays old\ndb.version()\n// 3) After the observation period, raise fCV on the primary (on mongos in a sharded cluster):\ndb.adminCommand({ setFeatureCompatibilityVersion: \"7.0\", confirm: true })\n// 4) If a rollback is needed, fCV is lowered BEFORE the binaries:\ndb.adminCommand({ setFeatureCompatibilityVersion: \"6.0\", confirm: true })","what":"実行中の fCV を表示する。別々のステップであるバイナリのアップグレードと fCV のアップグレードを実施する順序を示す。","when":"メジャーバージョンのアップグレード (例: 6.0 -> 7.0) を計画する場合、アップグレード後に新機能が使えない場合、または次のメジャーへ移行する前に。","caution":"メジャーバージョンは飛ばせない: 5.0 -> 7.0 では、まず 6.0 に移行して fCV を 6.0 に設定する。fCV を上げると、データファイルが新しい形式に切り替わり、バイナリのダウングレードが難しくなることがある。新バージョンが数日間問題なく稼働してから fCV を上げる。7.0 以降の Community ではバイナリのダウングレードは公式にサポートされないため、フォールバック計画はバックアップに基づかせる。アップグレード前にドライバーの互換性を確認する。","since":"MongoDB 7.0","note":"7.0 以降、setFeatureCompatibilityVersion には confirm: true が必要。fCV の移行に失敗した場合、getParameter の出力に targetVersion/previousVersion が表示される。同じコマンドを再実行して完了させる。fCV の値はレプリカセット内でレプリケートされる。","tags":["fcv","featureCompatibilityVersion","upgrade","major upgrade","major","downgrade"]}]},"recipes/redis.json":{"engineId":"redis","engine":"Redis","order":6,"recipes":[{"id":"bgrewriteaof","task":"AOF ファイルを書き換える (圧縮する)","category":"永続化","command":"BGREWRITEAOF","what":"AOF ファイルをバックグラウンドでよりコンパクトな形式に書き換える。","when":"AOF ファイルが肥大化した場合、再起動時間を短縮するため。","caution":"fork 中はメモリと IO の使用量が増加するため、ピーク時間帯には注意する。","tags":["aof","rewrite","persistence","persistence"]},{"id":"bgsave","task":"バックグラウンドで RDB スナップショットを取得する","category":"永続化","command":"BGSAVE","what":"fork した子プロセスを使用して、バックグラウンドで RDB スナップショットをディスクに書き込む。","when":"バックアップを取得したい場合やスナップショットを作成したい場合。","caution":"fork 時には copy-on-write のため、メモリ使用量が一時的に増加することがある。","tags":["rdb","bgsave","snapshot","persistence","backup"]},{"id":"save","task":"同期的に RDB スナップショットを取得する","category":"永続化","command":"SAVE","what":"メインスレッド上で同期的に RDB スナップショットをディスクに書き込む。","when":"メンテナンス / シャットダウンの前で、クライアントにサービスしていない場合のみ。","caution":"SAVE はサーバー全体をブロックし、完了するまでコマンドは処理されない。本番環境では BGSAVE を推奨する。","tags":["rdb","save","snapshot","blocking","persistence"]},{"id":"lastsave","task":"最後に成功したスナップショットの時刻を表示する","category":"永続化","command":"LASTSAVE","what":"最後に成功した RDB 保存の Unix タイムスタンプを返す。","when":"BGSAVE が完了したかどうかを確認するため。","caution":"読み取り専用コマンドのためリスクなし。","tags":["lastsave","rdb","timestamp","check","persistence"]},{"id":"config-rewrite","task":"実行中の構成をディスクに書き込む","category":"永続化","command":"CONFIG REWRITE","what":"CONFIG SET で実行時に行った変更を redis.conf ファイルに永続化する。","when":"実行時の変更を再起動後も維持したい場合。","caution":"既存の redis.conf ファイルを上書きする。ファイルが定義されており、書き込み可能である必要がある。","tags":["config","rewrite","persistent","conf","setting"]},{"id":"config-appendonly","task":"AOF を有効化または無効化する","category":"永続化","command":"CONFIG SET appendonly yes","what":"実行時に AOF 永続化を有効 (yes) または無効 (no) にする。","when":"再起動なしで AOF 永続化をオンまたはオフにしたい場合。","caution":"AOF を無効にすると耐久性の保証が弱まる。有効にすると、初回の AOF 書き換えが IO 負荷を生じる。","tags":["aof","appendonly","config","persistence","setting"]},{"id":"config-save-rdb","task":"RDB スナップショットのルールを設定する","category":"永続化","command":"CONFIG SET save \"900 1 300 10 60 10000\"","what":"自動 RDB スナップショットをトリガーするルール (秒数 / 変更回数) を設定する。","when":"自動スナップショットの頻度を変更したい場合。","caution":"空の値 (\"\") を指定すると、自動 RDB 保存が完全に無効になり、永続性が失われる可能性がある。","tags":["rdb","save","config","snapshot","setting"]},{"id":"replicaof","task":"ノードをレプリカにする","category":"レプリケーション","command":"REPLICAOF redis-master 6379","what":"このノードを、指定したホストとポートのマスターのレプリカにし、同期を開始する。","when":"新しい読み取りレプリカを追加する場合やロールを割り当てる場合。","caution":"レプリカになるノード上の既存データは破棄され、マスターから完全同期が取得される。","since":"Redis 5.0","note":"Redis 5.0 で REPLICAOF コマンドが SLAVEOF に代わった。古い SLAVEOF コマンドもエイリアスとして引き続き機能する。","tags":["replicaof","replica","replication","master","sync"]},{"id":"replicaof-no-one","task":"レプリカをマスターに昇格する","category":"レプリケーション","command":"REPLICAOF NO ONE","what":"ノードのレプリカリンクを切断し、独立したマスターにする。","when":"フェイルオーバーのシナリオでレプリカを昇格させたい場合。","caution":"昇格後は、旧マスターとのデータの分岐 (スプリットブレイン) が生じないよう、トポロジーを慎重に管理する。","since":"Redis 5.0","note":"Redis 5.0 で REPLICAOF NO ONE が SLAVEOF NO ONE に代わった。古い SLAVEOF NO ONE もエイリアスとして引き続き機能する。","tags":["replicaof","promote","master","failover","replication"]},{"id":"cluster-failover","task":"手動フェイルオーバーを実行する","category":"クラスタ","command":"CLUSTER FAILOVER","what":"レプリカで実行すると、そのレプリカをマスターに昇格させる制御されたフェイルオーバーを開始する。","when":"メンテナンスの前に、マスターロールをレプリカに引き渡したい場合。","caution":"このコマンドは、マスター自体ではなく対象のレプリカで実行する必要がある。","tags":["cluster","failover","promote","maintenance","replication"]},{"id":"cluster-meet","task":"クラスタにノードを追加する","category":"クラスタ","command":"CLUSTER MEET 10.0.0.12 6379","what":"指定した IP とポートのノードを、クラスタの gossip ネットワークに参加させる。","when":"クラスタに新しいノードを追加する場合 (スケーリング)。","caution":"ノードの追加後にスロットの割り当て (ADDSLOTS) または reshard を行わないと、ノードはデータを受け取らない。","tags":["cluster","meet","node","add","node"]},{"id":"cluster-addslots","task":"クラスタスロットを割り当てる","category":"クラスタ","command":"CLUSTER ADDSLOTS 0 1 2 3 4 5","what":"指定したハッシュスロットをこのマスターノードに割り当てる。","when":"新しいマスターノードを手動で構成する場合や、スロットの分散を修正する場合。","caution":"同じスロットを複数のノードに割り当てることはできない。16384 個のスロットがすべて割り当てられていないと、クラスタは down 状態になる。","tags":["cluster","addslots","slot","assign","node"]},{"id":"info-replication","task":"レプリケーションの状態を表示する","category":"クラスタ","command":"INFO replication","what":"ロール (master/replica)、接続中のレプリカ、レプリケーションオフセットの情報を表示する。","when":"レプリケーション遅延とリンク状態を確認する場合。","caution":"読み取り専用コマンドのためリスクなし。","tags":["info","replication","status","replication","lag"]},{"id":"cluster-info","task":"クラスタの状態を表示する","category":"クラスタ","command":"CLUSTER INFO","what":"クラスタ全体の状態 (ok/fail)、割り当て済みスロット数、既知のノード数を表示する。","when":"クラスタの健全性とスロットの整合性を検証する場合。","caution":"読み取り専用コマンドのためリスクなし。","tags":["cluster","info","status","slot","health"]},{"id":"config-maxmemory","task":"maxmemory とポリシーを設定する","category":"メモリ","command":"CONFIG SET maxmemory 4gb maxmemory-policy allkeys-lru","what":"メモリ上限と、上限を超えた場合に適用される eviction ポリシーを設定する。Redis 7.0 以降は 1 回の CONFIG SET で複数のパラメータを受け付ける。古いバージョンでは 2 つの CONFIG SET コマンドを別々に実行する。","when":"メモリ使用量に上限を設け、eviction の動作を定義したい場合。","caution":"noeviction ポリシーでは、上限に達すると書き込みが失敗する。上限を誤るとデータ損失 / ダウンタイムにつながる可能性がある。","tags":["maxmemory","policy","memory","eviction","config"]},{"id":"memory-doctor","task":"メモリを分析する","category":"メモリ","command":"MEMORY DOCTOR","what":"メモリ使用量を分析し、考えられる問題について人が読める形式のレポートを生成する。","when":"高いメモリ使用量や断片化が疑われる場合の診断に。","caution":"読み取り専用の分析。詳細には MEMORY STATS コマンドも使用できる。","tags":["memory","doctor","memory","analysis","diagnostics"]},{"id":"slowlog-get","task":"低速コマンドログを表示する","category":"メンテナンス","command":"SLOWLOG GET 10","what":"slowlog から直近 10 件の低速コマンドエントリ (所要時間、時刻、引数) を返す。","when":"低速コマンドを特定し、性能のボトルネックを調査する場合。","caution":"読み取り専用コマンド。エントリをクリアするには SLOWLOG RESET を使用する。","tags":["slowlog","get","slow","diagnostics","performance"]},{"id":"slowlog-config","task":"低速コマンドのしきい値を設定する","category":"メンテナンス","command":"CONFIG SET slowlog-log-slower-than 10000","what":"コマンドが slowlog に記録されるための所要時間のしきい値をマイクロ秒単位で設定する (10000 = 10 ms)。","when":"slowlog の感度を調整したい場合。","caution":"0 に設定するとすべてのコマンドが記録され、オーバーヘッドが増える。-1 で slowlog は無効になる。","tags":["slowlog","threshold","threshold","config","slow"]},{"id":"slowlog-reset","task":"低速コマンドログをリセットする","category":"メンテナンス","command":"SLOWLOG RESET","what":"slowlog 内のすべてのエントリをクリアする。","when":"新しい観測期間を開始するためにエントリをクリアする場合。","caution":"既存の低速コマンド履歴は完全に削除される。","tags":["slowlog","reset","reset","clear","maintenance"]},{"id":"client-kill","task":"クライアント接続を強制終了する","category":"メンテナンス","command":"CLIENT KILL ADDR 10.0.0.5:53210","what":"指定したアドレスのクライアント接続を終了する。","when":"応答しない、または異常な動作をするクライアントを終了したい場合。","caution":"接続は即座に切断され、処理中の操作が未完了のまま残る可能性がある。正しいアドレスを選択していることを確認する。","tags":["client","kill","client","kill","maintenance"]},{"id":"client-list","task":"接続中のクライアントを一覧表示する","category":"メンテナンス","command":"CLIENT LIST","what":"接続中のすべてのクライアントを、アドレス、アイドル時間、最後のコマンドなどの詳細とともに一覧表示する。","when":"接続を調べる場合や、問題のあるクライアントを特定する場合。","caution":"読み取り専用コマンドのためリスクなし。","tags":["client","list","client","list","connection"]},{"id":"config-get","task":"パラメータの値を表示する","category":"実行時","command":"CONFIG GET maxmemory-policy","what":"1 つ以上の構成パラメータの現在値を返す (glob パターン対応)。","when":"設定の実行時の値を検証する場合。","caution":"読み取り専用コマンドのためリスクなし。","tags":["config","get","parameter","view","runtime"]},{"id":"config-set","task":"パラメータの値を変更する","category":"実行時","command":"CONFIG SET appendfsync everysec","what":"再起動なしで、実行時に構成パラメータを変更する。","when":"サーバーの動作を即座に調整したい場合。","caution":"変更は一時的である。永続化するには CONFIG REWRITE を実行する。誤った値は性能 / 耐久性を低下させることがある。","tags":["config","set","parameter","runtime","setting"]}]},"recipes/redis-ext.json":{"engineId":"redis","engine":"Redis","order":2,"recipes":[{"id":"mem-fragmentation","task":"メモリ使用量と断片化を分析し、active defrag を有効にする","category":"メモリ","command":"INFO memory\n# Fields to check: used_memory_human, used_memory_rss_human, mem_fragmentation_ratio, mem_fragmentation_bytes, allocator_frag_ratio\nMEMORY STATS\n# If fragmentation is high and persistent, enable active defrag (requires jemalloc):\nCONFIG SET activedefrag yes\nCONFIG SET active-defrag-ignore-bytes 100mb\nCONFIG SET active-defrag-threshold-lower 10\n# Ask the allocator to return free pages to the OS:\nMEMORY PURGE","what":"Redis がデータに割り当てたメモリ (used_memory) と OS から見た RSS の差、断片化率、メモリの内訳を表示する。必要に応じて実行時に active defrag を有効にする。","when":"RSS がデータセットより明らかに大きい場合、一括削除 / 有効期限切れの後もメモリが減らない場合、または OOM のリスクが生じた場合。","caution":"mem_fragmentation_ratio は小さなデータセットでは誤解を招く (例: 2 MB のデータで 4.0)。絶対値については mem_fragmentation_bytes を確認する。比率が 1 未満の場合は断片化ではなくスワップを意味し、レイテンシを引き起こす。active defrag は CPU を消費するため、active-defrag-cycle-max で上限を設ける。永続化するには CONFIG REWRITE または redis.conf が必要。","since":"Redis 4.0","note":"active defrag は、Redis に同梱されている jemalloc でコンパイルされたビルドでのみ機能する。allocator_frag_ratio は defrag で解消できる内部断片化を示し、allocator_rss_ratio はアロケーターが OS に返していない領域を示す。サイズの異なる値を頻繁に更新するワークロードでは、断片化がより速く進む。","tags":["memory","ram","fragmentation","activedefrag","rss","info memory"]},{"id":"bigkeys-memkeys","task":"大きなキーを特定する (--bigkeys、--memkeys、MEMORY USAGE)","category":"メモリ","command":"# Largest keys per type by element count:\nredis-cli -h redis1 -p 6379 --bigkeys -i 0.01\n# By memory size:\nredis-cli -h redis1 -p 6379 --memkeys -i 0.01\n# Size and length together, top 20 keys (redis-cli 7.4+):\nredis-cli -h redis1 -p 6379 --keystats --top 20 -i 0.01\n# Memory usage (SAMPLES 0: all elements) and encoding of a single suspicious key:\nredis-cli -h redis1 -p 6379 MEMORY USAGE kullanici:1001:sepet SAMPLES 0\nredis-cli -h redis1 -p 6379 OBJECT ENCODING kullanici:1001:sepet","what":"SCAN でキースペースを走査し、型ごとに要素数が最も多いキーとメモリ使用量が最も多いキーを報告する。疑わしいキーの実際のメモリ消費量とエンコーディングを表示する。","when":"メモリが予期せず増加した場合、単一のコマンド (HGETALL、SMEMBERS、DEL) がレイテンシを引き起こす場合、またはクラスタ内の 1 つのノードが他より多くのメモリを使用している場合。","caution":"走査は SCAN を使用するためサーバーをブロックしないが、キースペース全体をたどる。-i 0.01 は 100 回の SCAN 呼び出しごとにスリープして負荷を減らす。大きなキーを DEL で削除するとメインスレッドがブロックされるため、UNLINK を使用する。SAMPLES 0 を指定した MEMORY USAGE は、大きなコレクションでは O(N) になる。レプリカで実行すればマスターに負荷はかからない。","since":"Redis 6.0","note":"--bigkeys は要素数を、--memkeys は MEMORY USAGE を見る。list/hash などの型では、異なるキーが目立つことがある。小さな hash/zset/list は listpack エンコーディングを使用し、メモリ消費がはるかに少ない。hash-max-listpack-entries などのしきい値を超えると hashtable に変換される。クラスタでは各マスターで個別に実行する。","tags":["bigkeys","memkeys","big key","memory usage","keystats","large key"]},{"id":"hotkeys-lfu","task":"ホットキーを特定する (--hotkeys、OBJECT FREQ)","category":"パフォーマンス","command":"# Requires an LFU-based policy; note the current policy:\nCONFIG GET maxmemory-policy\nCONFIG SET maxmemory-policy allkeys-lfu\n# Hottest keys by access frequency:\nredis-cli -h redis1 -p 6379 --hotkeys -i 0.01\n# LFU counter of a single key:\nOBJECT FREQ urun:populer:liste\n# Revert to the previous policy when the analysis is done:\nCONFIG SET maxmemory-policy noeviction","what":"LFU カウンターを使用して、最も頻繁にアクセスされるキーを一覧表示する。単一キーのアクセス頻度カウンターを表示する。","when":"1 つのノードの CPU が 100% に近づく場合、クラスタ内のスロット / ノードが他よりはるかに多くのトラフィックを受ける場合、または単一のキーによってネットワーク帯域が飽和する場合。","caution":"--hotkeys は maxmemory-policy が *-lfu の場合にのみ機能する。ポリシーを変更すると eviction の動作も変わる: maxmemory が設定されていて以前のポリシーが volatile-* または noeviction だった場合、allkeys-lfu は TTL のないキーも追い出す可能性がある。分析は短時間にとどめ、ポリシーを元に戻す。LFU カウンターは対数的で時間とともに減衰するため、絶対的なアクセス回数ではない。","since":"Redis 4.0","note":"ポリシーの変更後、LFU カウンターが意味を持つまでにはある程度のトラフィックが必要。ポリシーを変更できない場合は短時間の MONITOR サンプルが代替手段となるが、MONITOR は高負荷システムでスループットを大きく低下させる。読み取りの多いホットキーには、クライアントサイドキャッシュ (CLIENT TRACKING) またはキーの分割が恒久的な対策となる。","tags":["hotkeys","hot keys","lfu","object freq","hot key","cpu"]},{"id":"scan-unlink-pattern","task":"KEYS を使わずにパターンに一致するキーを特定し、安全に削除する (SCAN + UNLINK)","category":"メンテナンス","command":"# Cursor-based scan instead of KEYS (call again with the returned cursor until it returns 0):\nSCAN 0 MATCH oturum:* COUNT 1000 TYPE string\n# Number of keys matching the pattern:\nredis-cli -h redis1 -p 6379 --scan --pattern 'oturum:*' --count 1000 | wc -l\n# Bulk delete in batches of 500, freeing memory in the background:\nredis-cli -h redis1 -p 6379 --scan --pattern 'oturum:*' --count 1000 | xargs -r -n 500 redis-cli -h redis1 -p 6379 UNLINK","what":"サーバーをブロックせずにカーソルでキースペースを走査し、パターンと型に一致するキーを数え、UNLINK で一括削除してバックグラウンドでメモリを解放する。","when":"古いアプリケーションバージョンが残したキーを整理する場合、あるプレフィックス配下のキー数を調べる場合、または本番環境で本来なら KEYS が必要となる場合。","caution":"KEYS はキースペース全体を一度に返し、大量データではサーバーを数秒間ブロックするため、本番環境では使用しない。SCAN は走査中に追加 / 削除されたキーについて完全な保証をせず、同じキーを複数回返すことがある。空白や引用符を含むキー名は xargs で壊れる。削除前に件数といくつかのサンプルを確認する。元に戻す手段はない。","since":"Redis 4.0","note":"SCAN の TYPE オプションは 6.0 で追加された。COUNT はヒントであり、返される要素数を保証しない。クラスタでは --scan は接続中のノードのみを走査するため、各マスターで実行する。UNLINK は lazyfree により大きな値を別スレッドで解放する。小さなキーでは DEL と同じコストである。","tags":["scan","unlink","keys","bulk delete","pattern","match"]},{"id":"latency-diagnosis","task":"レイテンシの発生源を診断する (LATENCY DOCTOR、ヒストグラム、commandstats)","category":"パフォーマンス","command":"# Enable the latency monitor (record events above 100 ms):\nCONFIG SET latency-monitor-threshold 100\nLATENCY LATEST\nLATENCY HISTORY command\nLATENCY DOCTOR\n# Per-command latency distribution and percentiles:\nLATENCY HISTOGRAM GET SET HGETALL\nINFO latencystats\n# Most expensive commands by total CPU time:\nredis-cli -h redis1 -p 6379 INFO commandstats | sort -t= -k3 -rn | head\n# On the server host, baseline latency outside Redis (VM/steal detection, 30 s):\nredis-cli --intrinsic-latency 30\nLATENCY RESET","what":"レイテンシモニターは、fork、AOF fsync、expire サイクル、低速コマンドなどのイベントによるレイテンシの急上昇を記録する。コマンドごとのレイテンシのパーセンタイルと、合計 CPU 時間で最もコストの高いコマンドを表示し、ホストレベルでベースラインのレイテンシを測定する。","when":"アプリケーションで p99 レイテンシの急上昇が見られ、SLOWLOG が空であるにもかかわらず低速化の苦情が続く場合。","caution":"latency-monitor-threshold のデフォルトは 0 (無効)。診断後は元の値に戻す。SLOWLOG はコマンドの実行時間のみを測定し、ネットワークやキューの待機は見えない。LATENCY イベントは fork や fsync などのサーバー内部のストールも捕捉する。--intrinsic-latency は CPU を消費し、Redis サーバーをホストしているマシン上で実行する必要がある。","since":"Redis 7.0","note":"LATENCY HISTOGRAM と INFO latencystats は 7.0 で追加された (latency-tracking はデフォルトで有効)。LATENCY HISTORY で fork イベントが支配的な場合は、データセットのサイズと THP (transparent huge pages) を確認する。aof-fsync-always/aof-write イベントが多い場合は、ディスクのレイテンシを確認する。commandstats で usec_per_call が高いコマンドは、O(N) の使い方を示す。","tags":["latency","slowness","latency doctor","histogram","commandstats","intrinsic-latency"]},{"id":"eviction-oom-diag","task":"eviction、有効期限切れ、OOM エラーを診断する","category":"メモリ","command":"INFO stats\n# Fields to check: evicted_keys, expired_keys, expired_stale_perc, keyspace_hits, keyspace_misses, total_eviction_exceeded_time (7.0+)\nINFO keyspace\nCONFIG GET maxmemory\nCONFIG GET maxmemory-policy\nINFO memory\n# The value that triggers eviction: used_memory - mem_not_counted_for_evict, compared with maxmemory","what":"追い出された (evicted) キー数と有効期限切れ (expired) キー数、キャッシュヒット率、TTL を持つキーの割合、および maxmemory に対して eviction をトリガーするメモリ値を表示する。","when":"アプリケーションが 'OOM command not allowed when used memory > maxmemory' を受け取る場合、キャッシュヒット率が低下した場合、またはキーが予期せず消えると報告された場合。","caution":"noeviction ポリシーでは、maxmemory に達すると書き込みコマンドは OOM エラーになるが、読み取りは引き続き機能する。volatile-* ポリシーでは TTL のないキーは追い出されない。TTL を持つキーがない場合は noeviction と同様に動作する (INFO keyspace の expires を確認する)。maxmemory を物理 RAM に近づけすぎない: レプリケーションバッファと fork 中の copy-on-write のための余裕を残す。","since":"Redis 6.0","note":"ヒット率 = keyspace_hits / (keyspace_hits + keyspace_misses)。ヒット率が低下する一方で evicted_keys が着実に増加している場合、メモリが不足している。expired_stale_perc が高い場合は、有効期限切れでまだ削除されていないキーの割合が高いことを意味する。expire サイクルは active-expire-effort で高速化できる。レプリカバッファと AOF バッファは mem_not_counted_for_evict に含まれる。","tags":["eviction","oom","maxmemory","expire","hit ratio","evicted_keys"]},{"id":"client-memory","task":"メモリを肥大化させている接続を特定する (output buffer、query buffer、maxmemory-clients)","category":"メモリ","command":"INFO clients\n# Top 10 connections by tot-mem (tot-mem, omem, qbuf, id, addr, user, cmd, age):\nredis-cli -h redis1 -p 6379 CLIENT LIST | awk '{for(i=1;i<=NF;i++){split($i,a,\"=\"); f[a[1]]=a[2]} print f[\"tot-mem\"], f[\"omem\"], f[\"qbuf\"], f[\"id\"], f[\"addr\"], f[\"user\"], f[\"cmd\"], f[\"age\"]}' | sort -rn | head -10\nCLIENT LIST TYPE pubsub\nCONFIG GET client-output-buffer-limit\n# Upper limit for the total memory of all clients (largest clients are closed when exceeded):\nCONFIG SET maxmemory-clients 5%","what":"接続を合計メモリ (tot-mem)、出力バッファ (omem)、クエリバッファ (qbuf) で並べ替える。pub/sub 接続とバッファの上限を表示し、クライアントメモリ全体の上限を設定する。","when":"データが増えていないのに used_memory が増加する場合、mem_clients_normal が高く見える場合、または消費の遅い pub/sub/MONITOR クライアントがメモリを埋める場合。","caution":"omem が大きい場合は通常、結果の読み取りが遅いクライアント (大きな KEYS/HGETALL の応答、遅い pub/sub サブスクライバー、開いたままの MONITOR) を示す。maxmemory-clients を超えると、最も多くのメモリを保持しているクライアントが警告なしに切断される。レプリカとマスターのリンクは除外されるが、アプリケーションの接続は切断される可能性がある。重要な接続には CLIENT NO-EVICT on を使用する。","since":"Redis 7.0","note":"maxmemory-clients は 7.0 で追加され、デフォルトは 0 (無制限)。client-output-buffer-limit は pubsub および replica クラスに hard/soft の上限を適用する。normal クライアントはデフォルトで無制限。問題のある接続は CLIENT KILL ID <id> で切断する (client-kill を参照)。","tags":["client list","omem","output buffer","maxmemory-clients","connections","pubsub"]},{"id":"persistence-health","task":"RDB/AOF のエラー状態、fork 時間、MISCONF の原因を診断する","category":"永続化","command":"INFO persistence\n# Critical fields: rdb_last_bgsave_status, aof_last_bgrewrite_status, aof_last_write_status, rdb_changes_since_last_save, aof_delayed_fsync\nINFO stats\n# latest_fork_usec: duration of the last fork (microseconds), total_forks\nCONFIG GET stop-writes-on-bgsave-error\nCONFIG GET dir\nCONFIG GET appendfsync","what":"最後の RDB スナップショットと AOF の書き換え / 書き込みが成功したかどうか、最後の保存以降に変更されたキー数、遅延した fsync の回数、fork の所要時間を表示する。","when":"アプリケーションが 'MISCONF Redis is configured to save RDB snapshots, but it's currently unable to persist to disk' を受け取る場合、BGSAVE/BGREWRITEAOF が失敗する場合、または fork に関連するレイテンシが見られる場合。","caution":"stop-writes-on-bgsave-error yes (デフォルト) では、BGSAVE の失敗後すべての書き込みが拒否される。'no' に設定してエラーを抑止すると、データ損失のリスクが隠れてしまう。まず原因を修正する: ディスク満杯、dir への書き込み権限なし、または fork がメモリを確保できない (vm.overcommit_memory=0)。大きなデータセットでは fork 時間が数百ミリ秒に達することがあり、その間 Redis は応答しない。","since":"Redis 7.0","note":"Linux での vm.overcommit_memory=1 と transparent huge pages の無効化は、Redis の公式な推奨事項である。aof_delayed_fsync の増加は、ディスクが fsync に追いつけないことを意味する (appendfsync everysec)。エラーの詳細は Redis ログにある ('Background saving error'、'Can't save in background: fork')。","tags":["misconf","bgsave","aof","fork","persistence","durability"]},{"id":"aof-repair","task":"破損した AOF のために起動しない Redis を修復する (redis-check-aof、redis-check-rdb)","category":"永続化","command":"# With Redis stopped, copy the files first:\ncp -a /var/lib/redis/appendonlydir /var/lib/redis/appendonlydir.bak\n# Check (7.0+ multi-part AOF: pass the manifest file):\nredis-check-aof /var/lib/redis/appendonlydir/appendonly.aof.manifest\n# Repair by truncating everything after the first corrupt point (asks for confirmation):\nredis-check-aof --fix /var/lib/redis/appendonlydir/appendonly.aof.manifest\n# Verify the RDB file:\nredis-check-rdb /var/lib/redis/dump.rdb","what":"AOF ファイル (base + incr + manifest) と RDB ファイルを検証する。AOF の不完全または破損した末尾を切り詰め、Redis が再び起動できるようにする。","when":"停電、ディスク満杯、突然のシャットダウンの後、Redis が 'Bad file format reading the append only file' または 'Unexpected EOF' で起動に失敗する場合。","caution":"--fix は最初の破損箇所からファイル末尾までをすべて削除する。破損がファイルの途中にある場合、それ以降の書き込みはすべて失われる。確定する前に、出力で何バイトが切り詰められるか (ok_up_to、diff) を確認する。不完全な最後のコマンド (例: 大きな HSET) は丸ごと破棄される。必ず先にコピーを取得する。","since":"Redis 7.0","note":"aof-load-truncated yes (デフォルト) では、末尾のみが切り詰められた AOF は起動時に自動的に修正される。redis-check-aof が必要になるのは、通常は破損がファイルの途中にある場合である。7.0 以降のマルチパート AOF では、ファイルは appenddirname ディレクトリにあり、base ファイルは RDB 形式の場合がある。破損した RDB については、redis-check-rdb は診断のみを行い、修復はしない。","tags":["aof","redis-check-aof","corrupted","corrupt","repair","redis-check-rdb"]},{"id":"replication-backlog","task":"レプリケーションの切断と終わらない完全再同期のループを解消する (backlog、replica バッファ)","category":"レプリケーション","command":"INFO replication\n# Master: connected_slaves, slaveN:...,state=online,offset=,lag=  Replica: master_link_status, master_last_io_seconds_ago, master_sync_in_progress\nINFO stats\n# sync_full / sync_partial_ok / sync_partial_err: repeated full syncs = backlog too small\nCONFIG GET repl-backlog-size\nCONFIG SET repl-backlog-size 256mb\n# If the replica buffer exceeds its limit during a full sync, the link drops and sync starts over:\nCONFIG GET client-output-buffer-limit\nCONFIG SET client-output-buffer-limit \"replica 1gb 512mb 120\"","what":"マスターとレプリカでリンク状態、オフセットの差、部分 / 完全同期のカウンターを表示する。短時間の切断が完全同期にならないようレプリケーション backlog を拡大し、完全同期が途中で切断されないようレプリカの出力バッファ上限を引き上げる。","when":"レプリカが 'MASTER <-> REPLICA sync started' でループし続ける場合、sync_full カウンターが増加する場合、またはマスターのログに 'scheduled to be closed ASAP for overcoming of output buffer limits' と表示される場合。","caution":"完全同期のたびに、マスターで fork + RDB の生成が行われる。このループはマスターのメモリとディスクに負荷をかける。repl-backlog-size はマスターのメモリから割り当てられる。レプリカバッファの上限を引き上げると、完全同期中にマスターがその分の追加メモリを使用する可能性があるため、maxmemory の計算に含める。変更を永続化するには CONFIG REWRITE または redis.conf が必要。","since":"Redis 4.0","note":"backlog の大まかなサイジング: マスターの毎秒の書き込み量 (master_repl_offset の増加量) x 許容したい切断時間。client-output-buffer-limit のクラス名には、5.0 以降 'slave' の代わりに 'replica' を指定できる。CONFIG GET の出力にはまだ slave と表示されることがある。ディスクが遅い場合、repl-diskless-sync yes (7.0 以降のデフォルト) は RDB をディスクに書かずにソケット経由でストリーミングする。","tags":["replication","backlog","full sync","psync","replica","output buffer"]},{"id":"sentinel-status","task":"Sentinel の状態、現在のマスター、クォーラムを確認する","category":"Sentinel","command":"redis-cli -p 26379 SENTINEL MASTERS\nredis-cli -p 26379 SENTINEL GET-MASTER-ADDR-BY-NAME mymaster\nredis-cli -p 26379 SENTINEL REPLICAS mymaster\nredis-cli -p 26379 SENTINEL SENTINELS mymaster\n# Are there enough sentinels (quorum and majority) for a failover:\nredis-cli -p 26379 SENTINEL CKQUORUM mymaster\nredis-cli -p 26379 INFO sentinel","what":"Sentinel が監視しているマスター、現在のマスターアドレス、既知のレプリカと他の Sentinel を一覧表示し、フェイルオーバーに必要なクォーラムと過半数が確保されているかを検証する。","when":"アプリケーションが誤ったノードに接続する場合、フェイルオーバー後にトポロジーを検証する場合、およびすべてのメンテナンスの前に。","caution":"各 Sentinel は自身の視点を報告する。GET-MASTER-ADDR-BY-NAME はすべての Sentinel で同じアドレスを返す必要があり、そうでない場合はネットワーク分断または構成の不一致がある。flags フィールドの s_down/o_down やレプリカの disconnected は、至急の調査が必要。Sentinel のポート (26379) は、ファイアウォールで Sentinel 間とクライアント間にのみ開放する。","since":"Redis 5.0","note":"5.0 で SENTINEL REPLICAS が SENTINEL SLAVES に代わった (旧名称も引き続き機能する)。Sentinel の数は奇数で少なくとも 3 とし、異なる障害ドメイン (ホスト / ラック / AZ) に分散させる。Redis が ACL / パスワードを使用する場合、sentinel.conf に sentinel auth-user/auth-pass を設定する必要がある。","tags":["sentinel","master","quorum","ckquorum","topology","failover"],"untested":true},{"id":"sentinel-failover","task":"Sentinel で手動フェイルオーバーを実行し、トポロジーを整理する","category":"Sentinel","command":"# First check quorum and an eligible replica:\nredis-cli -p 26379 SENTINEL CKQUORUM mymaster\nredis-cli -p 26379 SENTINEL REPLICAS mymaster\n# Manual failover without waiting for agreement from other sentinels:\nredis-cli -p 26379 SENTINEL FAILOVER mymaster\n# Verify the new master (must be the same on all sentinels):\nredis-cli -p 26379 SENTINEL GET-MASTER-ADDR-BY-NAME mymaster\n# If old/removed replicas remain listed, reset sentinels one at a time, 30 s apart:\nredis-cli -p 26379 SENTINEL RESET mymaster","what":"マスターが正常であっても、マスターロールを最適なレプリカに引き渡す。その後、新しいマスターを検証し、もう存在しないレプリカを Sentinel のメモリからクリアする。","when":"マスターのホストで計画メンテナンスを行う前、フェイルオーバー訓練中、またはマスターを別のデータセンターに移す場合。","caution":"フェイルオーバー中に数秒間の書き込み中断があり、マスターに書き込まれたがまだレプリケートされていないデータは失われる可能性がある。replica-priority 0 のレプリカは選ばれない。適格なレプリカが存在しない場合、コマンドはエラーを返す。すべての Sentinel で同時に SENTINEL RESET を実行すると、トポロジー情報が一時的に失われるため、各 Sentinel で間隔を空けて個別に実行する。クライアントが Sentinel にマスターアドレスを照会するドライバーを使用していることを確認する。","since":"Redis 5.0","note":"SENTINEL FAILOVER は他の Sentinel に同意を求めないが、新しい config epoch は伝播させる。選択順序: replica-priority (低い方が優先)、レプリケーションオフセット (大きい方が優先)、run ID。フェイルオーバー後に旧マスターが復帰すると、Sentinel はそれを新しいマスターのレプリカとして自動的に再構成する。","tags":["sentinel","failover","manual failover","master","reset","switchover"],"untested":true},{"id":"cluster-check-fix","task":"クラスタの健全性を確認し、スロットの不整合を修復する (--cluster check/fix)","category":"クラスタ","command":"redis-cli -h node1 -p 6379 CLUSTER INFO\nredis-cli -h node1 -p 6379 CLUSTER NODES\nredis-cli -h node1 -p 6379 CLUSTER SHARDS\n# Slot coverage, open (migrating/importing) slots and node consistency:\nredis-cli --cluster check node1:6379\n# Repair if there are open or unowned slots:\nredis-cli --cluster fix node1:6379\n# Which slot and node a key lives on (-c: follow redirects):\nredis-cli -h node1 -p 6379 CLUSTER KEYSLOT kullanici:1001\nredis-cli -c -h node1 -p 6379 GET kullanici:1001","what":"すべてのノードが同じスロットマップを認識していること、16384 個のスロットがすべて割り当てられていること、不完全な (migrating/importing) スロットがないことを確認する。見つかった問題を修正し、キーがどのスロット / ノードにあるかを表示する。","when":"cluster_state:fail が表示される場合、クライアントが CLUSTERDOWN や絶え間ない MOVED/ASK エラーを受け取る場合、および reshard が中断された後に。","caution":"--cluster fix は、所有者のないスロットを任意のノードに割り当て、オープン中のスロットのキーを移動することがあるため、まず check の出力を確認する。マスターとそのすべてのレプリカが失われた場合、それらのスロットのデータは失われる。fix はそのスロットを空のまま別のノードに割り当てるだけである。cluster-require-full-coverage yes (デフォルト) では、所有者のないスロットが 1 つでもあるとクラスタ全体の書き込みが停止する。","since":"Redis 7.0","note":"CLUSTER SHARDS は 7.0 で追加され、CLUSTER SLOTS を置き換える。認証が有効な場合は、--cluster コマンドに -a <password> または --user/--pass を追加する。CLUSTER NODES の出力にある fail/pfail フラグは、そのノードが他のノードから到達不能とみなされていることを意味する。","tags":["cluster","check","fix","slot","clusterdown","cluster nodes"],"untested":true},{"id":"cluster-reshard","task":"クラスタでノードの追加、スロットの移動、ノードの削除を行う (add-node、reshard、rebalance)","category":"クラスタ","command":"# Add the new master to the cluster (joins empty, with no slots):\nredis-cli --cluster add-node node7:6379 node1:6379\n# Attach a new replica to a specific master:\nredis-cli --cluster add-node node8:6379 node1:6379 --cluster-slave --cluster-master-id <master-node-id>\n# Move 1000 slots from all masters to the new node:\nredis-cli --cluster reshard node1:6379 --cluster-from all --cluster-to <node7-id> --cluster-slots 1000 --cluster-yes\n# Or rebalance automatically (give slots to empty masters too):\nredis-cli --cluster rebalance node1:6379 --cluster-use-empty-masters\n# Remove a node whose slots have been emptied:\nredis-cli --cluster del-node node1:6379 <node-id>","what":"クラスタに新しいマスターまたはレプリカを追加し、ノード間でスロットとそのキーをオンラインで移動し、スロットの分散を自動的に再バランスし、空にしたノードをクラスタから削除する。","when":"メモリ / スループットを水平方向に拡張する場合、ホットノードの負荷を分散する場合、またはノードを廃止する場合。","caution":"スロットの移行は MIGRATE でキーを 1 つずつ転送する。大きなキーの移動中は、両方のノードが短時間ブロックされることがある。移行中、クライアントは ASK リダイレクトを受け取るため、クラスタ対応のクライアントが必要。reshard が中断されると、スロットは migrating/importing 状態のまま残るため、--cluster fix で完了させる。まだスロットを所有しているマスターを del-node で削除しない。先にスロットを移動する。","since":"Redis 5.0","note":"ノード ID は CLUSTER NODES または CLUSTER MYID から取得する。--cluster-pipeline は、各 MIGRATE 呼び出しで移動するキー数を設定する (デフォルト 10)。--cluster rebalance に --cluster-weight を指定すると、ノードに異なる重みを与えられる。5.0 で redis-cli --cluster コマンドが redis-trib.rb に代わった。","tags":["cluster","reshard","rebalance","add-node","slot","del-node"],"untested":true},{"id":"acl-users","task":"ACL ユーザーを作成し、権限をテストして永続化する","category":"セキュリティ","command":"# Application user: only app:* keys and channels, dangerous commands excluded:\nACL SETUSER app_rw on >S3cret-Change ~app:* resetchannels &app:* +@read +@write -@dangerous\n# Monitoring user: no key access, only specific commands:\nACL SETUSER monitor on >M0n-Secret resetkeys resetchannels -@all +info +ping +client|list +slowlog|get +latency +config|get\n# Test permissions without running the command:\nACL DRYRUN app_rw GET app:1001\nACL GETUSER app_rw\nACL LIST\n# Make it persistent: ACL SAVE if aclfile is set, otherwise CONFIG REWRITE into redis.conf\nACL SAVE","what":"キーのプレフィックス、pub/sub チャネル、コマンドカテゴリで権限を与えたアプリケーションユーザーと監視ユーザーを作成する。DRYRUN でコマンドを実行せずに許可されるかどうかをテストし、ACL をディスクに書き込む。","when":"単一の共有パスワード (requirepass) からユーザーごとのアクセスに移行する場合、アプリケーション同士のキーを分離する場合、または監視ツール用の読み取り専用アカウントを作成する場合。","caution":"ルールの順序が重要: resetchannels は、それより前に指定された &channel ルールをすべて削除する。-@dangerous は KEYS、FLUSHALL、CONFIG、DEBUG などのコマンドもブロックするため、アプリケーションが使用するコマンドを DRYRUN で検証する。default ユーザーが nopass と +@all で有効なままだと、ACL は何の保護にもならない。管理ユーザーを作成した後に ACL SETUSER default off を実行する。redis-cli では、--user/--pass による AUTH が失敗すると接続は default ユーザーとして継続し、コマンドはそのまま実行される。そのため権限のテストには DRYRUN を使用する。","since":"Redis 7.0","note":"ACL は 6.0 で追加された。ACL DRYRUN、セレクター、サブコマンドのルール (client|list) は 7.0 で追加された。aclfile と redis.conf 内の user 行は併用できない。パスワードは SHA-256 ハッシュとして保存され、ACL GETUSER は平文のパスワードを表示しない。","tags":["acl","setuser","users","permissions","dryrun","security"]},{"id":"acl-log-denied","task":"NOPERM および WRONGPASS エラーを調査する (ACL LOG)","category":"セキュリティ","command":"# Last 10 permission denials and failed logins (reason: auth/command/key/channel):\nACL LOG 10\n# User of this connection:\nACL WHOAMI\n# Cumulative denial counters:\nINFO stats\n# acl_access_denied_auth, acl_access_denied_cmd, acl_access_denied_key, acl_access_denied_channel\nACL LOG RESET","what":"拒否されたコマンド、キー、チャネルへのアクセスと失敗した AUTH の試行を、ユーザー名、オブジェクト、繰り返し回数、クライアント情報 (IP、最後のコマンド) とともに一覧表示する。拒否の累積カウンターを表示する。","when":"デプロイ後にアプリケーションが NOPERM や WRONGPASS を受け取る場合、厳格化した ACL ルールで動かなくなったコマンドを特定する場合、またはパスワードの推測を検出する場合。","caution":"ACL LOG はメモリ上にあり、再起動でクリアされ、acllog-max-len (デフォルト 128) エントリに制限される。同じエラーが繰り返されると、新しい行ではなく count が増加する。client-info フィールドには、クライアントの IP と使用中のユーザーが含まれる。リセットする前に必要な情報を記録しておく。","since":"Redis 7.0","note":"acl_access_denied_* カウンターは 7.2 で INFO stats に追加された。監視に組み込み、増加時にアラートを出す。entry-id と timestamp-created/last-updated フィールドは 7.2 で追加された。誤ったパスワードの試行は reason=auth、コマンド権限の不足は reason=command として表示される。","tags":["acl log","noperm","wrongpass","access denied","auth","security"]},{"id":"keyspace-notifications","task":"キースペース通知でキーの削除と有効期限切れのイベントを監視する","category":"メンテナンス","command":"CONFIG GET notify-keyspace-events\n# E: keyevent channel, x: expire events, g: generic commands (DEL, EXPIRE, RENAME):\nCONFIG SET notify-keyspace-events Exg\n# Listen to expire and del events in db 0:\nredis-cli -h redis1 -p 6379 --csv PSUBSCRIBE '__keyevent@0__:expired' '__keyevent@0__:del'\n# Turn off:\nCONFIG SET notify-keyspace-events \"\"","what":"キーに関するイベント (expire、del、set など) を pub/sub チャネルに発行し、どのキーがいつ削除または期限切れになったかをリアルタイムで確認できるようにする。","when":"キーが「勝手に消える」場合にどのコマンドまたは有効期限切れが原因かを証明するため、または有効期限切れイベントに依存するワークフロー (セッション終了) にイベントを供給するため。","caution":"イベントは CPU とネットワークの負荷を増やす。特に 'A' (全クラス) は高負荷システムでコストが高いため、必要なクラスのみを有効にし、終わったら無効にする。pub/sub は送りっぱなし (fire-and-forget) である: 接続していないサブスクライバーはイベントを受け取れず、何も永続化されない。expired イベントは TTL の時点ではなく、キーが実際に削除された時点 (アクセス時またはバックグラウンドの expire サイクルによる) で生成される。","since":"Redis 2.8","note":"eviction によって削除されたキーには e (evicted) クラスを追加する。クラスタでは、イベントはキーを保持しているノードでのみ発行されるため、各マスターに個別にサブスクライブする。永続的な設定には redis.conf で notify-keyspace-events を設定する。","tags":["keyspace notifications","notify-keyspace-events","expired","pubsub","events","psubscribe"]}]},"recipes/elasticsearch.json":{"engineId":"elasticsearch","engine":"Elasticsearch","order":7,"recipes":[{"id":"flush","task":"インデックスをフラッシュする","category":"インデックスのライフサイクル","command":"POST /customer/_flush","what":"Lucene のコミットを実行する: メモリ上のインデックス作成データをセグメントとしてディスクに永続的に書き込み、不要になった translog エントリを切り詰める。","when":"メンテナンスや再起動の前に translog を縮小するため。","caution":"通常は自動的に行われる。手動のフラッシュは IO をわずかに増加させる。","tags":["flush","translog","index","customer","maintenance"]},{"id":"force-merge","task":"インデックスのセグメントをマージする (force merge)","category":"インデックスのライフサイクル","command":"POST /customer/_forcemerge?max_num_segments=1","what":"インデックスのセグメントをマージしてセグメント数を減らし、読み取り性能を向上させる。","when":"書き込みが行われなくなった (読み取り専用の) インデックスでのみ、クエリ性能を向上させるため。","caution":"大量の IO と CPU を消費するため、書き込み中のインデックスでは決して実行しない。長時間かかることがあり、キャンセルできない。","tags":["forcemerge","segment","merge","merge segments","performance"]},{"id":"rollover","task":"エイリアス経由でロールオーバーする","category":"インデックスのライフサイクル","command":"POST /customer-alias/_rollover\n{\n  \"conditions\": {\n    \"max_age\": \"7d\",\n    \"max_docs\": 100000000,\n    \"max_primary_shard_size\": \"50gb\"\n  }\n}","what":"エイリアスが指す書き込みインデックスが条件を満たした場合、新しいインデックスを作成し、エイリアスをそこに向ける。","when":"時系列データのインデックスサイズを管理するため (ILM の代替 / 補完)。","caution":"エイリアスは is_write_index で単一の書き込みインデックスを持つ必要がある。構成を誤るとロールオーバーがブロックされる。","tags":["rollover","alias","index","time series","ilm"]},{"id":"set-refresh-interval","task":"リフレッシュ間隔を変更する","category":"インデックスのライフサイクル","command":"PUT /customer/_settings\n{\n  \"index\": { \"refresh_interval\": \"30s\" }\n}","what":"インデックスが新しいドキュメントを検索可能にする頻度 (refresh) を設定する。","when":"一括ロード中にインデックス作成を高速化するため、間隔を長くする場合。","caution":"-1 はリフレッシュを完全に無効にし、ドキュメントは検索可能にならない。ロード後は妥当な値に戻す。","tags":["refresh","interval","settings","bulk","refresh interval"]},{"id":"set-replicas","task":"レプリカ数を変更する","category":"インデックスのライフサイクル","command":"PUT /customer/_settings\n{\n  \"index\": { \"number_of_replicas\": 2 }\n}","what":"インデックスのレプリカシャード数を動的に変更する。","when":"冗長性や読み取り容量を増減するため。","caution":"レプリカを追加すると、追加のディスク使用量とネットワークトラフィック (リカバリ) が発生する。0 にすると冗長性がなくなる。","tags":["replica","settings","number_of_replicas","redundancy","capacity"]},{"id":"open-close-index","task":"インデックスを開く / 閉じる","category":"インデックスのライフサイクル","command":"POST /customer/_close\nPOST /customer/_open","what":"インデックスを読み取り / 書き込みに対して閉じる (リソースを解放する)、または再び開く。","when":"使用頻度の低いインデックスのリソース使用量を減らす場合や、特定の設定を変更する場合。","caution":"閉じたインデックスにはクエリも書き込みもできない。閉じている間は、スナップショット経由以外ではアクセスできない。","tags":["open","close","index","open index","close index"]},{"id":"node-join-note","task":"クラスタにノードを追加する","category":"クラスタ / ノード","command":"GET /_cat/nodes?v","what":"新しいノードを elasticsearch.yml で同じ cluster.name と正しい discovery.seed_hosts を指定して起動すれば十分である。このコマンドは、ノードが参加したことを検証する。","when":"クラスタに新しいノードを追加する際にメンバーシップを検証するため。","caution":"7.0 以降 minimum_master_nodes はなく、投票構成は自動的に管理される。master-eligible ノードは 1 つずつ追加・削除し、半数以上を一度に削除しない。複数の master-eligible ノードを恒久的に削除する場合は、先に POST _cluster/voting_config_exclusions?node_names=.... を使用する。","tags":["node","join","cluster","cat","add node"]},{"id":"node-decommission","task":"ノードを退避させる (廃止)","category":"クラスタ / ノード","command":"PUT /_cluster/settings\n{\n  \"persistent\": {\n    \"cluster.routing.allocation.exclude._name\": \"node-3\"\n  }\n}","what":"指定したノードのシャードを他のノードに移動し、ノードを安全に退避させる。","when":"ノードをサービスから外す前に、そのデータを移動するため。","caution":"シャードの再配置はネットワーク / IO に大きな負荷を生じるため、残りのノードに十分なディスクと容量があることを確認する。ノードの削除後は null で設定を削除する。transient 設定は 7.16 以降非推奨のため、persistent を使用する。","tags":["decommission","exclude","allocation","drain","node"]},{"id":"reroute-shard","task":"シャードを手動で移動する (reroute)","category":"クラスタ / ノード","command":"POST /_cluster/reroute\n{\n  \"commands\": [\n    {\n      \"move\": {\n        \"index\": \"customer\",\n        \"shard\": 0,\n        \"from_node\": \"node-1\",\n        \"to_node\": \"node-2\"\n      }\n    }\n  ]\n}","what":"特定のシャードを、あるノードから別のノードへ手動で移動する。","when":"偏ったシャード分散を是正する場合や、特定のノードを退避させる場合。","caution":"自動リバランスと競合することがある。大きなシャードの移動はネットワークと IO の負荷を生じる。","tags":["reroute","shard","move","relocate","cluster"]},{"id":"allocation-enable","task":"シャードの割り当てを有効化または無効化する","category":"クラスタ / ノード","command":"PUT /_cluster/settings\n{\n  \"persistent\": {\n    \"cluster.routing.allocation.enable\": \"primaries\"\n  }\n}","what":"クラスタ全体でシャードの割り当てを制限する (primaries: プライマリのみ割り当て、none: 何も割り当てない)、またはデフォルト (all / null) に戻す。","when":"ローリング再起動の前に、不要なレプリカの再配置を防ぐため (公式に推奨される値は \"primaries\")。","caution":"後で必ず null (または \"all\") で設定を元に戻す。制限したままだと、レプリカは未割り当てのままとなる。transient 設定は非推奨のため、persistent を使用する。","tags":["allocation","enable","restart","shard","cluster"]},{"id":"cluster-settings","task":"クラスタ設定を変更する","category":"クラスタ / ノード","command":"PUT /_cluster/settings\n{\n  \"persistent\": {\n    \"indices.recovery.max_bytes_per_sec\": \"100mb\"\n  }\n}","what":"クラスタ全体の persistent または transient 設定を変更する。","when":"リカバリ速度などのクラスタの動作を調整する場合。","caution":"persistent 設定は再起動後も維持される。transient 設定は失われ、7.16 以降非推奨のため使用しない。設定をデフォルトに戻すには、値を null に設定する。誤った値はクラスタの安定性に影響する。","tags":["cluster","settings","persistent","transient","setting"]},{"id":"snapshot-repo","task":"スナップショットリポジトリを登録する","category":"スナップショット","command":"PUT /_snapshot/backup_repo\n{\n  \"type\": \"fs\",\n  \"settings\": {\n    \"location\": \"/mnt/es_backups\"\n  }\n}","what":"スナップショットを保存するリポジトリを登録する。","when":"バックアップ基盤を初めて構築する場合。","caution":"fs リポジトリの場合、パスは path.repo で定義され、すべての master ノードと data ノードからアクセス可能である必要がある。","tags":["snapshot","repository","repo","backup","register"]},{"id":"snapshot-create","task":"スナップショットを取得する","category":"スナップショット","command":"PUT /_snapshot/backup_repo/snap1?wait_for_completion=false\n{\n  \"indices\": \"customer\",\n  \"include_global_state\": false\n}","what":"指定したインデックスのポイントインタイムバックアップ (スナップショット) をリポジトリに取得する。","when":"定期的なバックアップ、または大きな変更の前の安全のためのバックアップとして。","caution":"wait_for_completion=true は、大きなインデックスでは HTTP 接続を長時間待機させる。大きなスナップショットには false を使用する。","tags":["snapshot","create","backup","backup snapshot","take"]},{"id":"snapshot-restore","task":"スナップショットからリストアする","category":"スナップショット","command":"POST /_snapshot/backup_repo/snap1/_restore\n{\n  \"indices\": \"customer\",\n  \"rename_pattern\": \"customer\",\n  \"rename_replacement\": \"customer_restored\"\n}","what":"スナップショットからインデックスをクラスタにリストアする (必要に応じて名前を変更する)。","when":"データ損失後の復旧時、またはバックアップをテスト環境に移す場合。","caution":"同じ名前でリストアするには、対象のインデックスを閉じるか削除する必要がある。開いているインデックスに上書きリストアすることはできない。","tags":["snapshot","restore","restore snapshot","recovery","backup"]},{"id":"cache-clear","task":"キャッシュをクリアする","category":"メンテナンス","command":"POST /customer/_cache/clear","what":"インデックスの query、request、fielddata キャッシュをクリアする。","when":"メモリ負荷を減らす場合や、fielddata の問題を解決する場合。","caution":"キャッシュをクリアした後、再びウォームアップするまでは最初のクエリが遅くなる。","tags":["cache","clear","clear cache","fielddata","maintenance"]},{"id":"pending-tasks","task":"保留中のクラスタタスクを表示する","category":"メンテナンス","command":"GET /_cluster/pending_tasks","what":"master ノードで処理待ちのクラスタレベルのタスクを一覧表示する。","when":"クラスタが遅くなった場合や更新が滞る場合に、master の負荷を診断するため。","caution":"読み取り専用コマンドのためリスクなし。","tags":["pending","tasks","master","diagnostics","pending tasks"]},{"id":"hot-threads","task":"ホットスレッドの分析を取得する","category":"メンテナンス","command":"GET /_nodes/hot_threads","what":"ノード上で最も CPU を消費しているスレッドのスタックトレースを表示する。","when":"高い CPU 使用率の発生源を診断する場合。","caution":"読み取り専用コマンド。出力が長くなることがあるため、thread_type パラメータで絞り込む。","tags":["hotthreads","cpu","diagnostics","thread","performance"]},{"id":"cat-shards","task":"シャードの分散を表示する","category":"メンテナンス","command":"GET /_cat/shards?v&s=state","what":"すべてのシャードを、インデックス、種類 (プライマリ / レプリカ)、状態、配置されているノードとともに一覧表示する。","when":"シャードの配置や未割り当てのシャードを確認する場合。","caution":"読み取り専用コマンドのためリスクなし。","tags":["cat","shards","distribution","state","shard"]},{"id":"allocation-explain","task":"シャードが未割り当てである理由を特定する","category":"メンテナンス","command":"GET /_cluster/allocation/explain\n{\n  \"index\": \"customer\",\n  \"shard\": 0,\n  \"primary\": true\n}","what":"特定のシャードを割り当てられなかった (unassigned) 理由を詳しく説明する。","when":"yellow/red のクラスタで、未割り当てシャードの理由を探す場合。","caution":"読み取り専用の診断コマンドのためリスクなし。","tags":["allocation","explain","unassigned","diagnostics","shard"]},{"id":"cluster-health","task":"クラスタの健全性を表示する","category":"メンテナンス","command":"GET /_cluster/health","what":"クラスタ全体の健全性 (green/yellow/red) と、アクティブなシャード数および未割り当てのシャード数を表示する。","when":"クラスタの状態を素早く確認する場合。","caution":"読み取り専用コマンドのためリスクなし。","tags":["cluster","health","health check","status","green"]},{"id":"refresh-index","task":"インデックスを手動でリフレッシュする","category":"インデックスのライフサイクル","command":"POST /customer/_refresh","what":"インデックス内の保留中の変更を即座に検索可能にする。","when":"一括ロードの直後にデータを照会可能にしたい場合。","caution":"頻繁な手動リフレッシュは多数の小さなセグメントを生み、性能を低下させることがある。","tags":["refresh","index","search","segment","customer"]}]},"recipes/elasticsearch-ext.json":{"engineId":"elasticsearch","engine":"Elasticsearch","order":2,"recipes":[{"id":"red-yellow-triage","task":"red/yellow クラスタのトリアージ手順 (どのインデックス、どのシャード、なぜ)","category":"クラスタ / ノード","command":"GET _cluster/health?filter_path=status,unassigned_shards,initializing_shards,delayed_unassigned_shards,number_of_pending_tasks\nGET _health_report?verbose=false\nGET _cat/indices?v&health=red&h=health,index,pri,rep,docs.count,store.size\nGET _cat/indices?v&health=yellow&h=health,index,pri,rep\nGET _cat/shards?v&h=index,shard,prirep,state,unassigned.reason,unassigned.for,node&s=state\n# Without a body, the call explains the first unassigned shard:\nGET _cluster/allocation/explain","what":"クラスタの状態から問題のあるインデックス、未割り当てのシャード、それらが割り当てられない理由 (unassigned.reason、allocation explain) へと順に絞り込むトリアージ手順を示す。_health_report は、どの指標 (ディスク、シャードの可用性、master) が異常かを要約する。","when":"クラスタが red または yellow になったときの初動対応として。","caution":"red: 少なくとも 1 つのプライマリシャードが未割り当てであり、そのインデックスへの書き込みとそのシャードに当たる検索は失敗する。yellow: すべてのプライマリは存在するがレプリカが欠けており、データには到達できるが冗長性がない。単一ノードのクラスタでは、replicas > 0 のインデックスは恒常的に yellow のままとなる (same_shard の判定)。ノードが最近離脱した場合、delayed_unassigned_shards は index.unassigned.node_left.delayed_timeout (デフォルト 1m) が経過するまで意図的に保留される。","since":"Elasticsearch 8.7","note":"_health_report は 8.7 で追加された。古いバージョンでは最初の 4 ステップを使用する。unassigned.reason の値: NODE_LEFT (ノードの離脱)、ALLOCATION_FAILED (再試行上限に到達。retry-failed-allocation を参照)、INDEX_CREATED、CLUSTER_RECOVERED。特定のシャードについては、index/shard/primary を指定したボディで allocation-explain レシピを使用する。","tags":["red","yellow","cluster health","unassigned","health report","triage"]},{"id":"retry-failed-allocation","task":"再試行上限に達したシャードを再割り当てする (reroute retry_failed)","category":"クラスタ / ノード","command":"# Attempt count and last failure details:\nGET _cluster/allocation/explain?filter_path=index,shard,unassigned_info.reason,unassigned_info.failed_allocation_attempts,unassigned_info.details,allocate_explanation\n# After fixing the cause, retry shards that hit the limit:\nPOST _cluster/reroute?retry_failed=true&metric=none\n# Recovery progress:\nGET _cat/recovery?v&active_only=true&h=index,shard,stage,source_node,target_node,bytes_percent,translog_ops_percent","what":"連続した失敗の後に割り当てが停止されたシャード (ALLOCATION_FAILED、max_retry) の失敗の詳細を表示し、再度割り当てをトリガーする。リカバリの進捗を監視する。","when":"allocation explain で 'shard has exceeded the maximum number of retries' と表示された場合。ディスク満杯、translog の破損、一時的なネットワークの問題が解決した後に。","caution":"原因を修正せずに retry_failed を実行すると、シャードはさらに 5 回試行して再び失敗する。まず unassigned_info.details のエラーを解決する。多数のシャードが一度にリカバリに入ると、ネットワークとディスクの負荷が上がる。これは cluster.routing.allocation.node_concurrent_recoveries と indices.recovery.max_bytes_per_sec で制限される。","since":"Elasticsearch 7.0","note":"再試行の上限は index.allocation.max_retries (デフォルト 5)。Elasticsearch も定期的に再試行するが、retry_failed はその待機をなくす。metric=none を指定すると、レスポンス内の大きな cluster state が省略される。","tags":["reroute","retry_failed","allocation failed","max_retries","unassigned","recovery"]},{"id":"allocate-stale-primary","task":"最後の手段として、失われたプライマリシャードを割り当てる (allocate_stale_primary)","category":"クラスタ / ノード","command":"# Which nodes hold copies of the primary (allocation id, store errors):\nGET _shard_stores/musteri?status=red\n# Last resort: promote a stale copy to primary; data loss is accepted:\nPOST _cluster/reroute\n{\n  \"commands\": [\n    {\n      \"allocate_stale_primary\": {\n        \"index\": \"musteri\",\n        \"shard\": 0,\n        \"node\": \"node-2\",\n        \"accept_data_loss\": true\n      }\n    }\n  ]\n}","what":"最新のプライマリコピーを保持していたノードが恒久的に失われた場合、別のノード上の古い (in-sync でない) コピーをプライマリとして割り当て、インデックスを red から脱出させる。","when":"プライマリをホストしていたノードを復旧できず、スナップショットからのリストアが選択肢にない、またはより時間がかかる場合にのみ。","caution":"古いコピーには最新の書き込みが含まれない。そのコピー以降に行われた書き込みはすべて完全に失われる。失われたノードが後で復帰すると、そこにあるより新しいコピーは削除される。まずノードの復旧とスナップショットからのリストアを検討する。allocate_empty_primary はシャードを完全に空の状態で作成し、そのシャード内のすべてのデータを削除する。コピーが一切残っていない場合にのみ使用する。","since":"Elasticsearch 7.0","note":"_shard_stores の出力では、割り当ての種類が 'primary'、'replica'、'unused' として表示される。store_exception のあるコピーは選ばない。先に ?dry_run=true&explain=true を付けてコマンドを実行し、判定を確認できる。操作後は、アプリケーション側から再インデックスしてデータの欠落を埋める。","tags":["allocate_stale_primary","red","primary","data loss","shard_stores","reroute"],"untested":true},{"id":"disk-watermark","task":"ディスクのウォーターマークを管理し、flood-stage の書き込みブロックを解除する","category":"クラスタ / ノード","command":"GET _cat/allocation?v&h=node,shards,disk.indices,disk.used,disk.avail,disk.percent&s=disk.percent:desc\nGET _cluster/settings?include_defaults=true&filter_path=*.cluster.routing.allocation.disk\n# Adjust thresholds temporarily (null returns to the default):\nPUT _cluster/settings\n{\n  \"persistent\": {\n    \"cluster.routing.allocation.disk.watermark.low\": \"85%\",\n    \"cluster.routing.allocation.disk.watermark.high\": \"90%\",\n    \"cluster.routing.allocation.disk.watermark.flood_stage\": \"95%\"\n  }\n}\n# After freeing space, remove the flood-stage write block:\nPUT _all/_settings\n{\n  \"index.blocks.read_only_allow_delete\": null\n}","what":"ノードごとのディスク使用量と有効なウォーターマークの値を表示する。low/high/flood_stage のしきい値を調整し、flood stage でインデックスに設定された read_only_allow_delete ブロックを解除する。","when":"書き込みが 'TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark, index has read-only-allow-delete block' で拒否される場合、新しいシャードが割り当てられない場合、または満杯のノードからシャードが移動し始めた場合。","caution":"low を超えると、そのノードには新しいシャードが割り当てられない。high を超えると、シャードはそのノードから移動される。flood_stage を超えると、そのノードにシャードを持つインデックスは読み取り専用になる。しきい値の引き上げは時間稼ぎにすぎない。恒久的な対策は、古いインデックスの削除、レプリカの削減、ディスク / ノードの追加である。ディスクが完全に満杯になると、シャードが破損する可能性がある。","since":"Elasticsearch 8.5","note":"7.4 以降、ディスク使用量が high ウォーターマークを下回るとブロックは自動的に解除される。手動で解除すると待ち時間を短縮できる。8.5 以降、大容量ディスクではパーセントの代わりに絶対的な空き容量として max_headroom (low 200GB、high 150GB、flood 100GB) を使用する。これらのデフォルトの headroom はウォーターマークをデフォルトのままにしている場合にのみ適用されるため、上記のようにパーセントを明示的に設定すると無効になる。ウォーターマークは単一の data ノードのクラスタにも適用される。","tags":["disk watermark","flood_stage","read_only_allow_delete","disk full","allocation","cat allocation"]},{"id":"rolling-restart","task":"ローリング再起動 / ローリングアップグレード (ノードごと、不要なシャード移動なし)","category":"クラスタ / ノード","command":"# 1) Disable replica allocation (only primaries are allocated):\nPUT _cluster/settings\n{\n  \"persistent\": { \"cluster.routing.allocation.enable\": \"primaries\" }\n}\n# 2) Optional: stop indexing and flush to speed up recovery:\nPOST _flush\n# 3) Stop one node, do the maintenance, start it; verify it joined:\nGET _cat/nodes?v&h=name,version,node.role,master,heap.percent\n# 4) Re-enable allocation:\nPUT _cluster/settings\n{\n  \"persistent\": { \"cluster.routing.allocation.enable\": null }\n}\n# 5) Wait for green before moving to the next node:\nGET _cluster/health?wait_for_status=green&timeout=10m","what":"ノードが停止している間にレプリカが他のノードへ再コピーされるのを防ぎながら、ノードを 1 つずつ再起動またはアップグレードする順序を示す。ノードが復帰すると、シャードはローカルコピーから素早くリカバリする。","when":"OS パッチ、JVM / ヒープの変更、elasticsearch.yml の変更、マイナー / メジャーバージョンのアップグレードのためにノードを順に再起動する場合。","caution":"green を待たずに次のノードへ進まない。2 つのノードが同時に停止すると、あるシャードのすべてのコピーが失われる可能性がある。master-eligible ノードは最後に 1 つずつ再起動する。過半数が失われると、クラスタは master を選出できない。allocation.enable を再度有効にし忘れると、レプリカは未割り当てのままとなる。アップグレード時は data ノードを先に (frozen/cold を先に、hot を最後に)、その後 master をアップグレードする。","since":"Elasticsearch 7.16","note":"ML ジョブがある場合は、開始時に POST _ml/set_upgrade_mode?enabled=true を、終了時に enabled=false を実行する。synced flush は 8.0 で削除されたため、通常の _flush で十分。transient 設定は 7.16 で非推奨となったため、persistent を使用する。短時間の再起動では、割り当てを無効にする代わりに index.unassigned.node_left.delayed_timeout を引き上げる方法も有効。","tags":["rolling restart","rolling upgrade","allocation","primaries","maintenance","upgrade"],"untested":true},{"id":"shard-sizing","task":"シャードサイズとシャード数を監査する (オーバーシャーディング / 過大なシャードの検出)","category":"メンテナンス","command":"# Largest shards (GB):\nGET _cat/shards?v&h=index,shard,prirep,state,docs,store,node&s=store:desc&bytes=gb\n# Indices by primary size:\nGET _cat/indices?v&h=index,pri,rep,docs.count,pri.store.size,store.size&s=pri.store.size:desc&bytes=gb\n# Shard count and disk per node:\nGET _cat/allocation?v&h=node,shards,disk.indices,disk.percent&s=shards:desc\nGET _cluster/stats?filter_path=indices.shards.total,indices.shards.primaries,nodes.count.data\nGET _cluster/settings?include_defaults=true&filter_path=*.cluster.max_shards_per_node","what":"最大のシャード、インデックスのプライマリサイズ、ノードごとのシャード数、合計シャード数、cluster.max_shards_per_node の上限を一覧表示する。","when":"キャパシティプランニング時、リカバリ時間が延びる場合やヒープの負荷が上がる場合、および 'this action would add [x] shards, but this cluster currently has [y]/[z] maximum normal shards open' エラーの発生時。","caution":"非常に小さなシャードが多数あると (オーバーシャーディング)、master とヒープに負担がかかる。非常に大きなシャードは、リカバリとリバランスを数時間に引き延ばす。プライマリシャード数はインデックス作成後に変更できないため、修正には shrink、split、または reindex が必要。max_shards_per_node を引き上げると上限はなくなるが、問題は解決しない。","since":"Elasticsearch 8.3","note":"Elastic の一般的なガイダンス: シャードあたり 10〜50 GB、ドキュメント数は最大約 2 億。8.3 以降、従来の「ヒープ 1 GB あたり 20 シャード」のルールは、マッピングされたフィールド数に基づくヒープ見積もりに置き換えられた。時系列データでは、rollover の max_primary_shard_size でシャードサイズを固定する。","tags":["shard size","oversharding","cat shards","max_shards_per_node","capacity","sizing"]},{"id":"shrink-index","task":"シャードが多すぎるインデックスを縮小する (shrink)","category":"インデックスのライフサイクル","command":"# 1) Block writes on the source and gather all shard copies on one node:\nPUT log-2026.09/_settings\n{\n  \"index.number_of_replicas\": 0,\n  \"index.routing.allocation.require._name\": \"node-1\",\n  \"index.blocks.write\": true\n}\nGET _cluster/health/log-2026.09?wait_for_no_relocating_shards=true&timeout=30m\n# 2) Create a new index with fewer shards (the target must be a factor of the source):\nPOST log-2026.09/_shrink/log-2026.09-shrunk\n{\n  \"settings\": {\n    \"index.number_of_shards\": 1,\n    \"index.number_of_replicas\": 1,\n    \"index.routing.allocation.require._name\": null,\n    \"index.blocks.write\": null,\n    \"index.codec\": \"best_compression\"\n  }\n}","what":"書き込みが行われなくなったインデックスのセグメントを新しいインデックスにハードリンクして、プライマリシャード数を減らす。ヒープとシャード数のオーバーヘッドを下げる。","when":"日次インデックスが必要以上のシャード数で作成された場合、シャード数の上限に近づいている場合、または古いインデックスを warm 層に移す前に。","caution":"shrink 中、ソースインデックスは書き込みに対して閉じられるため、書き込みが行われなくなったインデックスにのみ適用する。対象のシャード数はソースのシャード数の約数である必要がある (8 -> 4、2、または 1)。すべてのコピーが集められるノードには、ソースインデックスと同じだけの空きディスクが必要。replicas 0 ではソースシャードのコピーは 1 つしかないため、操作が完了して新しいインデックスが green になるまでソースを削除しない。","since":"Elasticsearch 7.0","note":"shrink の後、ソースを削除するか、エイリアスを新しいインデックスに切り替える。同じノードが同じファイルシステム上でファイルをハードリンクできるため、通常操作は高速である。そうでない場合はファイルがコピーされる。シャード数を増やすには _split を、ILM で自動化するには warm フェーズの shrink アクションを使用する。","tags":["shrink","shard count","oversharding","index","blocks.write","warm"]},{"id":"ilm-policy-bootstrap","task":"ILM ポリシーを定義し、テンプレート経由で適用し、ロールオーバーチェーンをブートストラップする","category":"インデックスのライフサイクル","command":"PUT _ilm/policy/log-policy\n{\n  \"policy\": {\n    \"phases\": {\n      \"hot\": { \"actions\": { \"rollover\": { \"max_primary_shard_size\": \"50gb\", \"max_age\": \"1d\" }, \"set_priority\": { \"priority\": 100 } } },\n      \"warm\": { \"min_age\": \"7d\", \"actions\": { \"shrink\": { \"number_of_shards\": 1 }, \"forcemerge\": { \"max_num_segments\": 1 }, \"set_priority\": { \"priority\": 50 } } },\n      \"delete\": { \"min_age\": \"30d\", \"actions\": { \"delete\": {} } }\n    }\n  }\n}\nPUT _index_template/log\n{\n  \"index_patterns\": [\"log-*\"],\n  \"priority\": 500,\n  \"template\": {\n    \"settings\": {\n      \"number_of_shards\": 1,\n      \"number_of_replicas\": 1,\n      \"index.lifecycle.name\": \"log-policy\",\n      \"index.lifecycle.rollover_alias\": \"log\"\n    }\n  }\n}\n# Create the first index with the write alias (its name must end with a number such as -000001):\nPUT log-000001\n{\n  \"aliases\": { \"log\": { \"is_write_index\": true } }\n}","what":"hot (rollover)、warm (shrink + force merge)、delete の各フェーズを持つ ILM ポリシーを作成し、テンプレートを通じて新しいインデックスにポリシーとロールオーバーエイリアスを適用し、書き込みエイリアスを持つチェーンの最初のインデックスを作成する。","when":"ログやメトリクスなどの時系列データについて、インデックスのサイズ、保持、削除を自動化する場合。","caution":"warm フェーズと delete フェーズの min_age は、インデックスの作成時ではなくロールオーバーの時点から数えられる。ポリシーの変更は、既存のインデックスには現在のフェーズが完了した後にのみ適用される。warm フェーズの shrink と forcemerge は大量の IO を生じる。force merge が完了するまで、インデックスに書き込んではならない。ILM はデフォルトで 10 分ごとに実行されるため、条件は即座には評価されない。","since":"Elasticsearch 7.8","note":"新しいプロジェクトでは、data stream を使えば同じことをより簡単に実現できる: インデックステンプレートに \"data_stream\": {} を追加すれば、ロールオーバーエイリアスもブートストラップインデックスも不要になる。ロールオーバーの条件は、リフレッシュ済みの統計に対して評価される。コンポーザブルインデックステンプレート (_index_template) は 7.8 で追加された。従来の _template API は非推奨。","tags":["ilm","lifecycle","rollover","policy","index template","retention"]},{"id":"ilm-explain-retry","task":"停滞した ILM ステップを診断して再試行する (_ilm/explain、_ilm/retry)","category":"インデックスのライフサイクル","command":"# Indices waiting in an error step:\nGET log-*/_ilm/explain?only_errors=true\n# Phase/action/step state and failure reason for one index:\nGET log-000003/_ilm/explain?filter_path=indices.*.phase,indices.*.action,indices.*.step,indices.*.failed_step,indices.*.step_info,indices.*.is_auto_retryable_error\n# After fixing the cause (example: missing rollover alias setting):\nPUT log-000003/_settings\n{\n  \"index.lifecycle.rollover_alias\": \"log\"\n}\nPOST log-000003/_ilm/retry\n# Is ILM running (if STOPPED, POST _ilm/start):\nGET _ilm/status","what":"ERROR ステップで待機しているインデックス、それらが停滞しているフェーズ / アクション / ステップ、失敗理由 (step_info) を表示する。原因を修正した後、失敗したステップを再実行する。","when":"ロールオーバーが行われない場合、古いインデックスが削除されない場合、または ILM が削除すべきインデックスでディスクが埋まる場合。","caution":"_ilm/retry は ERROR ステップにあるインデックスでのみ機能し、それ以外では 'has not encountered an error' を返す。よくある原因: rollover_alias 設定がない、またはエイリアスの is_write_index が別のインデックスにある、shrink のための単一ノード上のディスクが不足している、割り当てルール (_tier_preference) を満たせない。ポリシーを削除しても、インデックスの ILM 管理は解除されない。先にインデックスからポリシーの設定を削除する。","since":"Elasticsearch 7.0","note":"is_auto_retryable_error が true のエラーは、ILM が自動的に再試行する (failed_step_retry_count が増える)。ILM のチェック間隔は indices.lifecycle.poll_interval (デフォルト 10m) で設定する。インデックスを ILM から外すには POST <index>/_ilm/remove を使用する。","tags":["ilm","explain","retry","error step","rollover","lifecycle"]},{"id":"index-template-component","task":"コンポーネントテンプレートからインデックステンプレートを構築し、結果をシミュレーションする","category":"インデックスのライフサイクル","command":"PUT _component_template/app-mappings\n{\n  \"template\": {\n    \"mappings\": {\n      \"dynamic\": \"strict\",\n      \"properties\": {\n        \"@timestamp\": { \"type\": \"date\" },\n        \"level\": { \"type\": \"keyword\" },\n        \"msg\": { \"type\": \"text\" }\n      }\n    }\n  }\n}\nPUT _index_template/app-events\n{\n  \"index_patterns\": [\"app-events-*\"],\n  \"priority\": 500,\n  \"composed_of\": [\"app-mappings\"],\n  \"template\": { \"settings\": { \"number_of_shards\": 1, \"refresh_interval\": \"5s\" } }\n}\n# See the final settings and mapping before the index is created:\nPOST _index_template/_simulate_index/app-events-000001\nGET _cat/templates?v&s=name","what":"再利用可能なマッピングのコンポーネントテンプレートを定義し、それをインデックステンプレートに組み込み、インデックスを作成せずに、指定したインデックス名に適用される最終的な設定とマッピングを表示する。","when":"新しいインデックスが誤ったマッピングやシャード数で作成される場合 (dynamic mapping の爆発、keyword ではなく text)、およびテンプレートの変更を展開する前に。","caution":"テンプレートは新しく作成されるインデックスにのみ適用され、既存のインデックスのマッピングは変わらない (reindex-alias-swap を参照)。2 つのテンプレートが同じパターンに一致する場合、priority が最も高いものだけが使用され、マージはされない。dynamic: strict は未定義のフィールドを含むドキュメントを拒否する。アプリケーションが新しいフィールドを送ると、インデックス作成は失敗する。","since":"Elasticsearch 7.8","note":"_simulate_index の出力にある overlapping フィールドは、同じパターンに一致して上書きされる他のテンプレートを示す。組み込みテンプレート (logs-*-*、metrics-*-*) との衝突を避けるため、priority は 200 より大きくする。コンポーザブルテンプレートは従来の _template API より優先される。","tags":["index template","component template","simulate","mapping","priority","dynamic strict"]},{"id":"reindex-alias-swap","task":"ダウンタイムなしでマッピングを変更する (reindex + アトミックなエイリアス切り替え)","category":"インデックスのライフサイクル","command":"# 1) Target index with the new mapping (refresh off and replicas 0 for loading):\nPUT musteri-v2\n{\n  \"settings\": { \"number_of_shards\": 1, \"number_of_replicas\": 0, \"refresh_interval\": \"-1\" },\n  \"mappings\": { \"properties\": { \"kod\": { \"type\": \"keyword\" }, \"adet\": { \"type\": \"long\" } } }\n}\n# 2) Reindex in the background (tracked with the returned task id):\nPOST _reindex?wait_for_completion=false&slices=auto\n{\n  \"source\": { \"index\": \"musteri-v1\", \"size\": 1000 },\n  \"dest\": { \"index\": \"musteri-v2\", \"op_type\": \"create\" },\n  \"conflicts\": \"proceed\"\n}\nGET _tasks/<task_id>\n# 3) Restore settings and compare document counts:\nPUT musteri-v2/_settings\n{\n  \"index\": { \"refresh_interval\": null, \"number_of_replicas\": 1 }\n}\nPOST musteri-v2/_refresh\nGET _cat/indices/musteri-v1,musteri-v2?v&h=index,docs.count,pri.store.size\n# 4) Switch the alias to the new index in one atomic operation:\nPOST _aliases\n{\n  \"actions\": [\n    { \"remove\": { \"index\": \"musteri-v1\", \"alias\": \"musteri\" } },\n    { \"add\": { \"index\": \"musteri-v2\", \"alias\": \"musteri\", \"is_write_index\": true } }\n  ]\n}","what":"新しいマッピングでインデックスを作成し、reindex でバックグラウンドでデータをコピーし、ドキュメント数を比較して、アプリケーションが使用するエイリアスを 1 回のアトミック操作で新しいインデックスに切り替える。","when":"既存フィールドの型を変更する必要がある場合 (text -> keyword、integer -> long)、アナライザーを変更する必要がある場合、またはシャード数を再定義する必要がある場合。これらは既存のインデックス上では直接行えない。","caution":"アプリケーションはインデックス名ではなくエイリアスに接続する必要がある。そうでないと、切り替えにデプロイが必要になる。reindex 中にソースへ行われた新しい書き込みはターゲットに届かない: 書き込みを停止するか、切り替えの直前に op_type create + conflicts proceed で reindex を再実行して差分を埋める (この方法では更新と削除は引き継がれない)。reindex はソースに読み取り負荷を、ターゲットに書き込み負荷を生じるため、requests_per_second でスロットルする。","since":"Elasticsearch 7.0","note":"refresh_interval が -1 の間にロードされたドキュメントは、リフレッシュされるまで件数に現れない。比較の前に _refresh を実行する。_cat/count にカンマ区切りで複数のインデックスを指定すると合計が返されるため、インデックスごとの比較には _cat/indices を使用する。実行中の reindex の速度は POST _reindex/<task_id>/_rethrottle?requests_per_second=500 で変更できる。wait_for_completion=false は結果を .tasks インデックスに書き込むため、GET _tasks/<task_id> で response.failures を確認する。","tags":["reindex","alias","mapping change","zero downtime","_aliases","no downtime"]},{"id":"tasks-cancel","task":"長時間実行中の検索タスクと reindex タスクを特定し、キャンセルまたはスロットルする","category":"メンテナンス","command":"# Longest running tasks:\nGET _cat/tasks?v&detailed&h=action,task_id,parent_task_id,running_time,node,description&s=running_time:desc\n# Search, reindex and by-query tasks, grouped by parent:\nGET _tasks?actions=*search*,*reindex*,*byquery*&detailed=true&group_by=parents\n# Cancel a single task:\nPOST _tasks/<task_id>/_cancel\n# Cancel all search tasks (with care):\nPOST _tasks/_cancel?actions=*search*\n# Slow down a running reindex/update_by_query:\nPOST _reindex/<task_id>/_rethrottle?requests_per_second=500","what":"クラスタで実行中のタスクを所要時間で並べ替え、検索と一括操作をクエリの説明とともに表示する。選択したタスクまたはすべての検索をキャンセルし、reindex/by-query ジョブをスロットルする。","when":"search スレッドプールが満杯になった場合、CPU が急上昇した場合、ダッシュボードの重い集計がクラスタに負担をかける場合、または update_by_query が本番環境に影響する場合。","caution":"キャンセルは協調的に行われる: タスクは次のチェックポイントで停止する。一部のフェーズ (例: force merge) はキャンセルできない。すべての検索をキャンセルすると、ユーザーにエラーが返される。キャンセルした reindex/by-query は、それまでに行われた変更をロールバックしないため、ターゲットには部分的なデータが含まれる。親タスクをキャンセルすると、その子タスクもキャンセルされる。","since":"Elasticsearch 7.0","note":"detailed パラメータを指定すると、検索タスクのクエリボディが description フィールドに書き込まれる。恒久的な保護には、search.default_search_timeout、検索リクエストの timeout、大きな集計に対する search.max_buckets を使用する。7.x 以降、HTTP 接続が閉じられた検索は自動的にキャンセルされる。","tags":["tasks","cancel","kill query","rethrottle","long query","search"]},{"id":"search-slowlog","task":"検索とインデックス作成の slow log を有効にする (インデックスごとのしきい値)","category":"パフォーマンス","command":"PUT musteri/_settings\n{\n  \"index.search.slowlog.threshold.query.warn\": \"2s\",\n  \"index.search.slowlog.threshold.query.info\": \"500ms\",\n  \"index.search.slowlog.threshold.fetch.warn\": \"1s\",\n  \"index.indexing.slowlog.threshold.index.warn\": \"1s\",\n  \"index.indexing.slowlog.source\": \"200\"\n}\nGET musteri/_settings/index.*slowlog*?flat_settings=true\n# Set thresholds to null to turn it off:\nPUT musteri/_settings\n{\n  \"index.search.slowlog.threshold.query.warn\": null,\n  \"index.search.slowlog.threshold.query.info\": null,\n  \"index.search.slowlog.threshold.fetch.warn\": null,\n  \"index.indexing.slowlog.threshold.index.warn\": null,\n  \"index.indexing.slowlog.source\": null\n}","what":"指定したインデックスについて、query フェーズと fetch フェーズ、およびインデックス作成でしきい値を超えたリクエストを、クエリボディとともに slow log に書き込む。","when":"どのクエリが検索を遅くしているかを特定する場合、または特定のダッシュボードやクライアントからの重いクエリを捕捉する場合。","caution":"しきい値はシャードごとに測定される: シャードの多いインデックスでは、各シャードがそれぞれ行を書き込むことがある。非常に低いしきい値 (0ms) はログ量と IO を大幅に増やすため、診断後は null で無効にする。indexing.slowlog.source はドキュメントのソースをログに書き込むため、機密データが含まれる場合は false に設定する。設定は指定したインデックスにのみ適用されるため、新しいインデックス用にテンプレートに追加する。","since":"Elasticsearch 8.0","note":"slow log ファイルは logs ディレクトリに <cluster>_index_search_slowlog.json および <cluster>_index_indexing_slowlog.json として書き込まれる。log4j2 がコンソールに出力するよう設定されている場合は stdout に出力される。index.search.slowlog.level 設定は 8.0 で削除され、レベルはしきい値 (warn/info/debug/trace) によって決まる。8.14 以降、index.search.slowlog.include.user: true を指定すると、リクエストしたユーザーもログに書き込まれる。単一のクエリを詳しく調べるには、検索リクエストに \"profile\": true を追加する。","tags":["slowlog","slow log","slow search","search","indexing","threshold"]},{"id":"rejections-heap-breaker","task":"429 による拒否、ヒープ、サーキットブレーカーの負荷を診断する","category":"パフォーマンス","command":"# Thread pool queue and rejection counts (source of 429):\nGET _cat/thread_pool/write,search,get?v&h=node_name,name,active,queue,rejected,completed,size,queue_size&s=rejected:desc\nGET _cat/nodes?v&h=name,node.role,heap.percent,ram.percent,cpu,load_1m,disk.used_percent,master&s=heap.percent:desc\n# Circuit breaker trips and parent breaker usage:\nGET _nodes/stats/breaker?filter_path=nodes.*.name,nodes.*.breakers.*.tripped,nodes.*.breakers.parent\nGET _nodes/stats/jvm?filter_path=nodes.*.name,nodes.*.jvm.mem.heap_used_percent,nodes.*.jvm.gc.collectors.old\n# Fielddata memory usage (per field):\nGET _nodes/stats/indices/fielddata?fields=*&filter_path=nodes.*.indices.fielddata","what":"write/search スレッドプールのキューが満杯のために拒否されたリクエスト、ノードごとのヒープ / CPU の状態、サーキットブレーカーの作動、old GC の回数、fielddata のメモリ使用量を表示する。","when":"クライアントが 429 Too Many Requests や es_rejected_execution_exception を受け取る場合、CircuitBreakingException ([parent] Data too large) が発生する場合、またはノードで長い GC 停止が発生する場合。","caution":"rejected カウンターはノード起動以降の累積値のため、2 つのサンプル間の増加量を確認する。queue_size を引き上げると拒否は見えなくなるが、ヒープとレイテンシが増加する。本当の対策は、一括処理のサイズ / 同時実行数を減らすか、容量を追加することである。ヒープが 85% を超えたままで old GC が頻繁に実行される場合、ノードは OOM に近づいている。text フィールドで fielddata を有効にすると、ヒープを急速に消費する。","since":"Elasticsearch 7.0","note":"parent ブレーカーのデフォルトはヒープの 95% (real memory circuit breaker、7.0 以降)。書き込みの拒否は通常、単一のホットノードに集中する: シャードの分散とルーティング (_routing) を確認する。fielddata を一時的に解放するには POST _cache/clear?fielddata=true を使用する (cache-clear を参照)。","tags":["429","rejected","thread pool","circuit breaker","heap","fielddata"]},{"id":"slm-snapshot-monitor","task":"SLM でスナップショットと保持を自動化し、スナップショットの進捗を監視する","category":"スナップショット","command":"# Take a snapshot every night at 01:30, keep for 30 days (at least 7, at most 60 snapshots):\nPUT _slm/policy/gece-yedek\n{\n  \"schedule\": \"0 30 1 * * ?\",\n  \"name\": \"<gece-{now/d}>\",\n  \"repository\": \"yedek_repo\",\n  \"config\": { \"indices\": [\"*\"], \"include_global_state\": true },\n  \"retention\": { \"expire_after\": \"30d\", \"min_count\": 7, \"max_count\": 60 }\n}\n# Run the policy now and see success/failure statistics:\nPOST _slm/policy/gece-yedek/_execute\nGET _slm/stats\n# Snapshot in progress and per-shard progress:\nGET _snapshot/yedek_repo/_current\nGET _snapshot/yedek_repo/_status\nGET _cat/snapshots/yedek_repo?v&s=end_epoch:desc\n# Verify that the repository is writable from all nodes:\nPOST _snapshot/yedek_repo/_verify","what":"cron スケジュールでスナップショットを取得し、保持ルールに従って古いものを削除する SLM ポリシーを定義する。実行中のスナップショットのシャードごとの進捗、過去のスナップショット、リポジトリの到達可能性を表示する。","when":"定期的なバックアップを設定する場合、夜間のスナップショットが失敗したというアラートの発生時、または長時間実行中のスナップショットがいつ終わるかを見積もる場合。","caution":"スケジュールは UTC で評価される。複数のクラスタが同じリポジトリに書き込む場合、またはリポジトリが別のクラスタで書き込み可能として登録されている場合、リポジトリが破損する可能性がある。他のクラスタでは readonly: true を使用する。保持ルールは SLM が取得したスナップショットのみを削除する。include_global_state が true の場合、リストア時にテンプレートと persistent のクラスタ設定もリストアされることがある。","since":"Elasticsearch 7.5","note":"スナップショットは増分である: 前回のスナップショットにないセグメントのみがコピーされるため、頻繁なスナップショットでもリポジトリ内でそれに比例した領域は消費しない。SLM は 7.4、保持は 7.5 で追加された。リポジトリ名を指定しない場合、_status はクラスタ内で実行中のすべてのスナップショットを返す。過去のスナップショット名を指定するとリポジトリから読み取るため、遅くなることがある。","tags":["slm","snapshot","retention","backup","schedule","snapshot status"],"untested":true},{"id":"security-user-role","task":"ロールとネイティブユーザーを作成し、パスワードを変更し、API キーを発行する","category":"セキュリティ","command":"POST _security/role/log_okuma\n{\n  \"cluster\": [\"monitor\"],\n  \"indices\": [\n    { \"names\": [\"log-*\"], \"privileges\": [\"read\", \"view_index_metadata\"] }\n  ]\n}\nPOST _security/user/rapor_kullanici\n{\n  \"password\": \"Degistir-123!\",\n  \"roles\": [\"log_okuma\"],\n  \"full_name\": \"Rapor Servisi\"\n}\nGET _security/user/rapor_kullanici\n# User making this request and its roles:\nGET _security/_authenticate\nPOST _security/user/rapor_kullanici/_password\n{\n  \"password\": \"Yeni-Sifre-456!\"\n}\n# Time-limited API key with restricted privileges:\nPOST _security/api_key\n{\n  \"name\": \"rapor-key\",\n  \"expiration\": \"30d\",\n  \"role_descriptors\": { \"log_okuma\": { \"indices\": [ { \"names\": [\"log-*\"], \"privileges\": [\"read\"] } ] } }\n}\n# If the elastic user's password is lost (shell on a node):\n# bin/elasticsearch-reset-password -u elastic -i","what":"インデックスパターンに対する読み取りアクセスを持つロールと、そのロールを持つ native レルムのユーザーを作成し、パスワードを変更し、呼び出し元の ID を検証し、権限を絞り込んだ有効期限付きの API キーを発行する。","when":"最小権限でレポート用、アプリケーション用、監視用のアカウントを作成する場合、パスワードローテーション時、およびサービスをユーザーから API キーへ移行する場合。","caution":"アプリケーションで elastic スーパーユーザーを使用しない。API キーの権限は、それを作成したユーザーの権限を超えることはできない。role_descriptors は権限を絞り込むだけである。API キーは、作成時点の所有者の権限のスナップショットによって制限される。後からロールを変更しても、既存のキーには影響しない。パスワードの変更後、古いパスワードを使用しているサービスは 401 を受け取るため、切り替えを計画する。API キーのレスポンスにある encoded の値は一度しか返されないため、保存しておく。","since":"Elasticsearch 8.0","note":"8.0 以降、セキュリティはデフォルトで有効で、elastic のパスワードは初回起動時に生成される。elasticsearch-reset-password ツールは 8.0 で追加された。API キーは GET _security/api_key?name=rapor-key で一覧表示し、DELETE _security/api_key で失効させる。LDAP/AD/SAML レルムのユーザーに対するロールマッピングは _security/role_mapping で行う。","tags":["security","users","roles","api key","password","rbac"],"untested":true}]},"solver/slow-query.json":{"id":"slow-query","title":"低速クエリ: 詳細な診断","icon":"🐢","category":"パフォーマンス","intro":"クエリまたはシステム全体が遅い。段階的に絞り込む: 各ノードでチェックを実行し、結果に応じて分岐を選択する。最後に根本原因と対策にたどり着く。","start":"scope","nodes":{"scope":{"kind":"step","title":"何が遅いか?","detail":"特定の 1 つまたは少数のクエリが遅いのか、それともシステム全体が遅いのか? これにより、調査は「クエリ中心」または「リソース / ボトルネック中心」の 2 つの経路のいずれかに分かれる。","choices":[{"label":"特定の 1 つまたは少数のクエリが遅い","next":"running"},{"label":"システム全体が遅い","next":"system"}]},"running":{"kind":"step","title":"クエリは現在実行中か?","detail":"現在実行中 / 停滞中のクエリか、それとも「全般的に遅い」クエリか? アクティブセッションを確認する。","command":{"oracle":"SELECT sid, serial#, sql_id, last_call_et AS running_sec, event, blocking_session\nFROM v$session WHERE status='ACTIVE' AND type='USER' ORDER BY last_call_et DESC;","postgres":"SELECT pid, now()-query_start AS dur, state, wait_event, query\nFROM pg_stat_activity WHERE state='active' ORDER BY query_start;","mysql":"SELECT id, time, state, info FROM information_schema.processlist WHERE command='Query' ORDER BY time DESC;","mssql":"SELECT session_id, total_elapsed_time/1000 AS sec, status, wait_type, blocking_session_id\nFROM sys.dm_exec_requests WHERE session_id IN (SELECT session_id FROM sys.dm_exec_sessions WHERE is_user_process = 1) ORDER BY total_elapsed_time DESC;"},"choices":[{"label":"現在実行中 / 停滞中","next":"blocked"},{"label":"全般的に遅い。実行計画を確認したい","next":"plan"}]},"blocked":{"kind":"step","title":"クエリは何かを待っているか?","detail":"アクティブなのに進んでいない場合、待機している可能性が高い。blocking_session / wait_event に値があるか?","command":{"oracle":"SELECT sid, blocking_session, event, seconds_in_wait\nFROM v$session WHERE sid=&target_sid;","postgres":"SELECT pid, pg_blocking_pids(pid) AS blocked_by, wait_event_type, wait_event\nFROM pg_stat_activity WHERE pid=&target_pid;","mssql":"SELECT session_id, blocking_session_id, wait_type, wait_resource\nFROM sys.dm_exec_requests WHERE session_id=&target;"},"choices":[{"label":"別のセッションにブロックされている","next":"sol_blocking"},{"label":"リソースを待機している (IO / ログ / ラッチ)","next":"wait"},{"label":"待機なし。CPU を消費し続けている","next":"plan"}]},"wait":{"kind":"step","title":"どの待機が支配的か?","detail":"支配的な wait event がボトルネックの種類を示す。","command":{"oracle":"SELECT event, total_waits, time_waited FROM v$session_event WHERE sid=&target_sid ORDER BY time_waited DESC FETCH FIRST 5 ROWS ONLY;","postgres":"SELECT wait_event_type, wait_event, count(*) FROM pg_stat_activity WHERE state='active' GROUP BY 1,2 ORDER BY 3 DESC;","mssql":"SELECT TOP 5 wait_type, waiting_tasks_count, wait_time_ms FROM sys.dm_os_wait_stats ORDER BY wait_time_ms DESC;"},"choices":[{"label":"IO 待機 (db file read / PAGEIOLATCH)","next":"sol_io"},{"label":"ログ / コミット待機 (log file sync / WRITELOG)","next":"sol_log"},{"label":"ロック / エンキュー (enq: TX / LCK)","next":"sol_blocking"}]},"plan":{"kind":"step","title":"実行計画を取得する (EXPLAIN)","detail":"実行計画を取得する。フルテーブルスキャン、予期しない結合順序、推定行数と実績行数の差はあるか?","command":{"oracle":"SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('&sql_id', NULL, 'ALLSTATS LAST'));","postgres":"EXPLAIN (ANALYZE, BUFFERS) <query>;","mysql":"EXPLAIN ANALYZE <query>;","mssql":"SET STATISTICS PROFILE ON; <query>; SET STATISTICS PROFILE OFF;","mongodb":"db.collection.find({...}).explain('executionStats')  // COLLSCAN or IXSCAN?"},"choices":[{"label":"フルスキャン / インデックス不足","next":"sol_index"},{"label":"昨日は速かった。実行計画が突然変わった","next":"sol_planchange"},{"label":"処理する行が多すぎる / N+1","next":"sol_rewrite"},{"label":"実行計画は良好だが遅い","next":"stats"}]},"stats":{"kind":"step","title":"統計は最新か?","detail":"推定行数と実績行数 (E-rows と A-rows) の大きな差は、統計が古いことの兆候である。","command":{"oracle":"SELECT table_name, num_rows, last_analyzed FROM dba_tables WHERE table_name='&TABLE_NAME';","postgres":"SELECT relname, last_analyze, last_autoanalyze, n_live_tup FROM pg_stat_user_tables WHERE relname='&table_name';","mysql":"SELECT table_name, table_rows, update_time FROM information_schema.tables WHERE table_name='&table_name';","mssql":"SELECT name, STATS_DATE(object_id, stats_id) AS last_updated FROM sys.stats WHERE object_id=OBJECT_ID('&table_name');"},"choices":[{"label":"統計が古い","next":"sol_stats"},{"label":"統計は最新だがそれでも遅い","next":"sol_deep"}]},"system":{"kind":"step","title":"システム全体: ボトルネックはどこか?","detail":"単一のクエリではなくすべてが遅い場合は、リソースのボトルネックを探す: CPU、IO、メモリ、それとも広範なブロッキングか?","command":{"oracle":"SELECT metric_name, value FROM v$sysmetric WHERE metric_name IN ('Host CPU Utilization (%)','Average Active Sessions') AND intsize_csec=(SELECT MAX(intsize_csec) FROM v$sysmetric);","postgres":"SELECT state, wait_event_type, count(*) FROM pg_stat_activity GROUP BY 1,2 ORDER BY 3 DESC;","mssql":"SELECT TOP 5 wait_type, wait_time_ms FROM sys.dm_os_wait_stats ORDER BY wait_time_ms DESC;"},"choices":[{"label":"CPU が 100% 近い","next":"sol_cpu"},{"label":"IO 待機が高い","next":"sol_io"},{"label":"メモリ負荷 / キャッシュヒット率が低い","next":"sol_mem"},{"label":"ブロッキングが多い","next":"sol_blocking"}]},"sol_blocking":{"kind":"solution","title":"根本原因: ブロッキング","detail":"クエリは別のセッションが保持しているロックを待っている。チェーンの先頭にあるセッション (ルートブロッカー) を特定して解消する。","steps":["ブロッキングチェーンの先頭 (自身は待機していないが他を待たせているセッション) を特定する。","ルートブロッカーが何をしているかを把握する: コミットされていない長時間のトランザクションか、'idle in transaction' か?","アプリケーションでコミット / ロールバックできる場合はそれを実行させる。できず、処理が停滞している場合はルートブロッカーを終了する。","根本原因を修正する: インデックスの不足が広範なロックを引き起こしている可能性がある。トランザクションを短くし、分離レベルを見直す。"],"related":["blocking-sessions","kill-session"],"playbook":"blocking"},"sol_io":{"kind":"solution","title":"根本原因: IO のボトルネック","detail":"クエリがディスクから大量に読み取っている。通常はフルスキャン (インデックス不足) またはメモリ不足 (バッファキャッシュ) が原因。","steps":["フルスキャンを引き起こしているフィルタに適したインデックスを追加する (実行計画がインデックススキャン、IXSCAN に切り替わるはず)。","バッファキャッシュ / バッファプールのヒット率を確認し、低い場合はメモリを増やす。","不要な列 / 行の読み取りを減らす (SELECT * ではなく必要な列、ページネーション)。","ストレージが本当に遅い場合 (IO レイテンシが高い) は、ディスク層を改善する。"],"related":["cache-hit-ratio","create-index"]},"sol_log":{"kind":"solution","title":"根本原因: コミット / ログのボトルネック","detail":"'log file sync' / 'WRITELOG' が支配的な場合、コミットは redo/WAL の書き込みを待っている。","steps":["頻繁な単一行コミットをバッチコミットに変える。不要なコミットを減らす。","redo/WAL のディスクを高速化する (別の高速ディスク)。ログファイルのサイズ / 数を見直す。","synchronous_commit / commit_write の設定を、ワークロードと耐久性のトレードオフに照らして評価する。"],"related":["show-config-param"]},"sol_index":{"kind":"solution","title":"根本原因: インデックス不足","detail":"実行計画がフルスキャンを行っている。フィルタ / 結合列に適したインデックスを作成すると大幅に高速化する。","steps":["WHERE/JOIN の列に適したインデックス (必要に応じて複合インデックス) をオンラインで追加する。","インデックスの追加後、再度実行計画を取得し、インデックススキャン (IXSCAN) に切り替わったことを確認する。","書き込み負荷が高い場合はインデックスのコストを考慮し、不要なインデックスを削除する。","選択性の低い列ではインデックスは効果がないため、選択性を確認する。"],"related":["create-index","explain-plan"]},"sol_planchange":{"kind":"solution","title":"根本原因: 実行計画の性能低下","detail":"クエリが昨日は速かったが今日は遅い。実行計画が変わった。通常は古い統計またはパラメータの変更が原因。","steps":["まず最新の統計を収集する (古い統計が最も一般的な原因)。","良好な実行計画を固定する: Oracle SQL Plan Baseline / ヒント、MSSQL Query Store の 'force plan'、PG の設定。","最近アップグレード / パッチ / パラメータ変更があった場合は、それを見直す (オプティマイザの動作)。"],"related":["update-statistics"]},"sol_rewrite":{"kind":"solution","title":"根本原因: クエリの設計","detail":"実行計画は妥当だが、クエリ自体が本質的に多すぎる処理を行っている (行が多すぎる、N+1、不要な結合)。","steps":["結果セットを小さくする: ページネーション (LIMIT/OFFSET またはキーセット)、早期のフィルタリング。","N+1 パターンを単一のバッチクエリに変える。不要な結合 / サブクエリを簡素化する。","繰り返し実行される重いレポートには、マテリアライズドビュー / 集計テーブルを検討する。"],"related":["explain-plan","materialized-view"]},"sol_stats":{"kind":"solution","title":"根本原因: 古い統計","detail":"統計が最新でないため、オプティマイザが誤った推定をしている。","steps":["影響を受けるテーブルの統計を手動で収集する。","自動収集ジョブ (autovacuum/auto stats/gather job) が実行されていることを確認する。","突発的な大量データロードの後に、統計収集をワークフローに組み込む。"],"related":["update-statistics"]},"sol_deep":{"kind":"solution","title":"詳細な分析","detail":"実行計画と統計に問題がないのにそれでも遅い場合は、さらに掘り下げる。","steps":["セッションレベルのトレースを有効にする: Oracle 10046、PG auto_explain、MySQL profiling、MSSQL Extended Events。","並列処理、メモリ許可、ソート / ハッシュのスピル (tempdb/temp) を調べる。","ハードウェア / OS 層 (CPU steal、IO レイテンシ、ネットワーク) の問題を除外する。","接続数と同時実行性に起因する競合を評価する。"],"related":["session-trace","top-wait-events"]},"sol_cpu":{"kind":"solution","title":"根本原因: CPU のボトルネック","detail":"システム全体が CPU バウンドになっている。通常は、実行計画の悪い少数のクエリが CPU を消費している。","steps":["CPU 消費の上位 10 クエリを特定し、その実行計画を修正する (インデックス / 統計)。","暴走クエリを制限する (Resource Manager / Resource Governor)。","使用率が高いままの場合はスケールする (CPU の追加、読み取りをリードレプリカに分散)。"],"related":["top-slow-queries"],"playbook":"high-cpu"},"sol_mem":{"kind":"solution","title":"根本原因: メモリ負荷","detail":"キャッシュヒット率が低い、またはスワップが発生している: メモリが不足しているか、割り当てが誤っている。","steps":["バッファプール / SGA とセッションメモリ (work_mem/PGA) を正しくサイジングする (ツール > メモリ計算機)。","メモリを消費している暴走クエリを特定して修正する。","システムがスワップしている場合は、スワップからの脱出が最優先。必要に応じて RAM を追加する。"],"related":["cache-hit-ratio","show-config-param"],"playbook":"memory-pressure"}}},"solver/deadlock.json":{"id":"deadlock","title":"デッドロック / ロックの競合 (ORA-00060、1213、40P01)","icon":"♻️","category":"ロック","intro":"デッドロックが発生した (Oracle ORA-00060、MySQL 1213、PG 40P01、MSSQL 1205)。グラフを取得し、パターンを把握し、再発を防ぐ。デッドロックは設計によって解消するものであり、目標はその頻度を減らすことである。","start":"capture","nodes":{"capture":{"kind":"step","title":"まずデッドロックグラフを取得する","detail":"どの 2 つ (またはそれ以上) のセッションが、どのリソースで、どのロックモードで衝突したか? これを確認せずに当てずっぽうの修正をしない。","command":{"oracle":"-- Check the trace file referenced in the alert log (deadlock graph). For history:\nSELECT * FROM dba_hist_active_sess_history WHERE event LIKE 'enq: TX%' ORDER BY sample_time DESC FETCH FIRST 20 ROWS ONLY;","mysql":"SHOW ENGINE INNODB STATUS\\G  -- 'LATEST DETECTED DEADLOCK' section","postgres":"-- Deadlock errors are always written to postgresql.log as ERROR (log_lock_waits not required); log_lock_waits=on also logs lock waits longer than deadlock_timeout.","mssql":"SELECT XEvent.query('.') FROM (SELECT CAST(target_data AS XML) td FROM sys.dm_xe_session_targets t JOIN sys.dm_xe_sessions s ON s.address=t.event_session_address WHERE s.name='system_health') x CROSS APPLY td.nodes('//event[@name=\"xml_deadlock_report\"]') AS q(XEvent);"},"choices":[{"label":"グラフを取得した — 2 つのトランザクションが逆の順序でリソースをロックしている","next":"sol_order"},{"label":"多数のトランザクションが単一の行 / テーブルに集中している (ホットスポット)","next":"sol_hotspot"},{"label":"広範囲のロックがある (多数の行がロックされる)","next":"index_check"}]},"index_check":{"kind":"step","title":"ロックしているクエリはインデックスを使用しているか?","detail":"インデックスがないと、UPDATE/DELETE は WHERE 句を満たすために多数の行 (テーブル全体の場合もある) をロックする → デッドロックの原因。実行計画を確認する。","command":{"mysql":"EXPLAIN <the UPDATE/DELETE involved in the deadlock>;  -- type=ALL means a full scan, no index","postgres":"EXPLAIN <query>;  -- Seq Scan or Index Scan?","oracle":"SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('&sql_id'));"},"choices":[{"label":"インデックスがない / フルスキャンを行っている","next":"sol_index"},{"label":"インデックスはあるが、それでも競合する","next":"sol_order"}]},"sol_order":{"kind":"solution","title":"根本原因: 逆順のロック","detail":"デッドロックの最も一般的な原因: 2 つのトランザクションが異なる順序でリソースにアクセスしている。A→B と B→A が同時に起こるとデッドロックになる。","steps":["すべてのコードパスで同じ順序でリソースにアクセスする (例: 常に最小 id → 最大 id)。","トランザクションを短く保つ。ユーザー操作や長時間の処理はトランザクションの外に出す。","必要に応じて、決まった順序で早めにロックを取得する (順序付きの SELECT ... FOR UPDATE)。","アプリケーションに、デッドロックの犠牲となったトランザクションの自動再試行 (retry + backoff) を追加する — これは必須である。"],"related":["blocking-sessions","open-transactions"]},"sol_index":{"kind":"solution","title":"根本原因: インデックス不足 → 広範なロック","detail":"インデックスのない UPDATE/DELETE は必要以上の行をロックし、デッドロックの可能性を大幅に高める。","steps":["WHERE 句の列にインデックスを追加する。これによりロックは影響を受ける行に限定される。","再度実行計画を取得し、フルスキャン (Seq Scan / type=ALL) がインデックスアクセスに変わったことを確認する。","一括更新は小さなバッチ (チャンク) に分けて実行する。"],"related":["create-index","list-indexes"]},"sol_hotspot":{"kind":"solution","title":"根本原因: ホットスポット","detail":"カウンター行 / キーなどの単一のリソースに、多数のトランザクションが同時に集中している。","steps":["ホットな行を分散させる: シーケンス / identity を使用する、カウンターを分割する (シャードカウンター)。","トランザクションの所要時間を短くし、ロックの保持時間を減らす。","可能であれば、楽観的ロック (バージョン / タイムスタンプ) またはキューパターンを使用する。"],"related":["sequence","open-transactions"]}}},"solver/disk-full.json":{"id":"disk-full","title":"ディスク / 表領域が満杯","icon":"💽","category":"容量","intro":"'unable to extend'、'disk full'、'could not extend'、'log full' が発生した。慌てない: まず何が満杯なのかを特定し、安全に領域を回収してから、恒久的に修正する。","start":"what","nodes":{"what":{"kind":"step","title":"何が満杯か?","detail":"誤った場所を整理しても効果はない。まず使用量を測定する: データファイル、トランザクションログ、アーカイブ / redo、temp、それとも OS のディスクか?","command":{"oracle":"SELECT d.tablespace_name, ROUND((1-(d.alloc-NVL(f.free,0))/d.maxb)*100,1) AS pct_free\nFROM (SELECT tablespace_name, SUM(bytes) alloc, SUM(GREATEST(bytes,maxbytes)) maxb FROM dba_data_files GROUP BY tablespace_name) d LEFT JOIN (SELECT tablespace_name, SUM(bytes) free FROM dba_free_space GROUP BY tablespace_name) f ON f.tablespace_name = d.tablespace_name ORDER BY pct_free;","postgres":"SELECT datname, pg_size_pretty(pg_database_size(datname)) FROM pg_database ORDER BY 2 DESC;  -- OS disk: df -h","mssql":"SELECT name, size/128.0 AS size_mb, size/128.0 - CAST(FILEPROPERTY(name,'SpaceUsed') AS int)/128.0 AS free_mb, type_desc\nFROM sys.database_files;","mysql":"SELECT table_schema, ROUND(SUM(data_length+index_length)/1048576,1) AS mb FROM information_schema.tables GROUP BY table_schema ORDER BY mb DESC;"},"choices":[{"label":"データファイル / 表領域が満杯","next":"data"},{"label":"トランザクションログ / アーカイブ・redo が満杯","next":"log"},{"label":"temp / undo が満杯","next":"sol_temp"},{"label":"OS のディスクが満杯 (DB ではない)","next":"sol_os"}]},"data":{"kind":"step","title":"最大の消費者は何か?","detail":"ほとんどの場合、暴走した単一のテーブル / セグメントが原因である。最も大きいものを特定する。","command":{"oracle":"SELECT segment_name, segment_type, ROUND(bytes/1048576,1) AS mb FROM dba_segments ORDER BY bytes DESC FETCH FIRST 10 ROWS ONLY;","postgres":"SELECT relname, pg_size_pretty(pg_total_relation_size(relid)) FROM pg_statio_user_tables ORDER BY pg_total_relation_size(relid) DESC LIMIT 10;","mssql":"SELECT TOP 10 OBJECT_NAME(object_id) AS table_name, SUM(reserved_page_count)*8/1024 AS mb FROM sys.dm_db_partition_stats GROUP BY object_id ORDER BY mb DESC;"},"choices":[{"label":"予期せず大きい / 暴走したテーブルがある","next":"sol_runaway"},{"label":"通常の増加で、本当に領域が不足している","next":"sol_extend"},{"label":"デッド行 / 肥大化 (bloat) が多すぎる","next":"sol_reclaim"}]},"log":{"kind":"step","title":"ログが増大しているのはなぜか?","detail":"最も古いアクティブなトランザクション / バックアップが完了するまで、ログ / アーカイブは整理できない。なぜ蓄積したのか?","command":{"mssql":"SELECT name, log_reuse_wait_desc FROM sys.databases WHERE name=DB_NAME();  -- why can it not be truncated?","postgres":"SELECT slot_name, active, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained FROM pg_replication_slots ORDER BY 3 DESC;","oracle":"SELECT * FROM v$flash_recovery_area_usage;  -- FRA (archive) usage"},"choices":[{"label":"MSSQL: ログバックアップが取得されていない (LOG_BACKUP)","next":"sol_logbackup"},{"label":"PG: 停滞したレプリケーションスロットが WAL を保持している","next":"sol_slot"},{"label":"Oracle: アーカイブログ領域 (FRA) が満杯","next":"sol_archive"},{"label":"長時間オープン中のトランザクションがログを保持している","next":"sol_longtxn"}]},"sol_runaway":{"kind":"solution","title":"根本原因: 暴走したテーブル / セグメント","detail":"単一のオブジェクトが予期せず増大した (制御されない挿入、一度も削除されないキュー / ログテーブル)。","steps":["そのオブジェクトが本当に必要かを確認する。ログ / キューテーブルであれば、保持期間を適用する。","不要な古いデータは、パーティションの削除 / TRUNCATE で削除する (バックアップ / 承認の後)。","アプリケーション側で制御されない増大を止め、増大のアラートを設定する。"],"related":["largest-tables","create-partition"]},"sol_extend":{"kind":"solution","title":"根本原因: 実際の容量不足","detail":"通常の増加であり、領域を追加する必要がある。","steps":["データファイルに領域を追加するか、AUTOEXTEND を有効にする (Oracle: ALTER DATABASE DATAFILE ... AUTOEXTEND ON MAXSIZE)。","必要に応じて、新しいデータファイル / 表領域を追加するか、ディスクを拡張する。","今後不意を突かれないよう、使用率 80%/90% のアラートを設定する。"],"related":["free-space"]},"sol_reclaim":{"kind":"solution","title":"根本原因: 肥大化 (bloat) / デッド行","detail":"削除 / 更新された行の領域が回収されていない。","steps":["領域を回収する: PG VACUUM (必要に応じて pg_repack)、Oracle SHRINK SPACE、MySQL OPTIMIZE TABLE、Mongo compact。","autovacuum / 自動メンテナンスの設定をより積極的にする。","VACUUM FULL / OPTIMIZE はテーブルをロックするため、ピーク時間外に実行する。"],"related":["reclaim-space","free-space"]},"sol_temp":{"kind":"solution","title":"根本原因: temp / undo が満杯","detail":"大きなソート / ハッシュ、または長時間オープン中のトランザクションが一時領域を埋めた。","steps":["temp を使い果たしたクエリ (大きなソート / ハッシュのスピル) を特定して最適化する。","長時間オープン中のトランザクションを特定する。それが undo を保持している (Oracle)。","必要に応じて temp/undo 領域を拡張し、保持期間の設定を見直す。"],"related":["open-transactions","reclaim-space"]},"sol_os":{"kind":"solution","title":"根本原因: OS のディスクが満杯","detail":"問題は DB ではなく、オペレーティングシステムのディスクにある。ログ、コアダンプ、古いバックアップ、トレースファイルが領域を占めている可能性がある。","steps":["df -h で満杯のファイルシステムを特定し、最も大きなディレクトリを調べる (du -sh *)。","古いログ / トレース / コアダンプ / バックアップファイルを整理する (承認を得たうえで)。","DB の診断ディレクトリ (Oracle ADR、PG ログ) をローテーションの対象にする。"]},"sol_logbackup":{"kind":"solution","title":"根本原因: ログバックアップが取得されていない (SQL Server)","detail":"FULL 復旧モデルでは、ログバックアップを取得しないとログは無制限に増大する。","steps":["ログバックアップを取得する (BACKUP LOG) — これによりログが再利用可能になる。","復旧モデルが本来 SIMPLE であるべきなら、変更する。","ログファイルの圧縮は必要な場合にのみ行い (DBCC SHRINKFILE)、定期的なログバックアップジョブを設定する。"],"related":["last-backup-status"],"playbook":"log-growth"},"sol_slot":{"kind":"solution","title":"根本原因: 放置されたレプリケーションスロット (PG)","detail":"停滞した (非アクティブな) スロットが WAL の削除を妨げ、pg_wal を肥大化させる。","steps":["そのスロットが実際に使用されているかを確認する。","不要であれば削除する: SELECT pg_drop_replication_slot('slot_name');","スロットが進むようアクティブなレプリカを修正し、スロットの遅延に対するアラートを設定する。"],"related":["free-space"],"playbook":"log-growth"},"sol_archive":{"kind":"solution","title":"根本原因: アーカイブログ領域 (FRA) が満杯 (Oracle)","detail":"アーカイブログが蓄積して FRA が満杯になった。アーカイバが停止すると、データベースは書き込みを受け付けなくなることがある。","steps":["バックアップ済みの古いアーカイブログを RMAN で削除する (バックアップなしで決して削除しない)。","必要に応じて FRA のサイズ (db_recovery_file_dest_size) を増やす。","アーカイブログの整理 / バックアップジョブが定期的に実行されるよう設定する。"],"related":["last-backup-status"]},"sol_longtxn":{"kind":"solution","title":"根本原因: 長時間オープン中のトランザクション","detail":"最も古いアクティブなトランザクションが、ログ / undo の回収を妨げている。","steps":["最も古いオープントランザクションを特定し、コミット / ロールバックさせる (または所有者と話す)。","セッションを 'idle in transaction' のままにするアプリケーションの動作を修正し、タイムアウトを設定する。","長時間のレポートを別のレプリカ / 時間帯に移す。"],"related":["open-transactions"],"playbook":"log-growth"}}},"solver/connection-storm.json":{"id":"connection-storm","title":"コネクションストーム (接続数過多)","icon":"🌊","category":"容量","intro":"'too many connections'、'remaining connection slots reserved'、または ORA-00018 が発生し、新しい接続が拒否されている。発生源を特定し、今すぐ負荷を緩和し、恒久的に修正する。","start":"measure","nodes":{"measure":{"kind":"step","title":"状況を測定する: 接続数はいくつで、そのうちアクティブなものはいくつか?","detail":"まず合計接続数、上限、アクティブ / アイドルの内訳を確認する。","command":{"oracle":"SELECT status, COUNT(*) FROM v$session WHERE type='USER' GROUP BY status;\nSELECT name, value FROM v$parameter WHERE name IN ('processes','sessions');","postgres":"SELECT state, count(*) FROM pg_stat_activity GROUP BY state;\nSHOW max_connections;","mysql":"SHOW STATUS LIKE 'Threads_connected'; SHOW VARIABLES LIKE 'max_connections';","mssql":"SELECT status, COUNT(*) FROM sys.dm_exec_sessions WHERE is_user_process=1 GROUP BY status;","redis":"INFO clients"},"choices":[{"label":"ほとんどの接続が idle / idle in transaction","next":"sol_idle"},{"label":"ほとんどがアクティブ。発生源を特定する必要がある","next":"who"}]},"who":{"kind":"step","title":"誰が / どこから? 接続を発生源別にグループ化する","detail":"通常は、単一のアプリケーションサーバーのプールが膨れ上がったか、接続リークがある。ホスト / ユーザー / アプリケーション別の分布を確認する。","command":{"postgres":"SELECT client_addr, usename, application_name, count(*) FROM pg_stat_activity GROUP BY 1,2,3 ORDER BY 4 DESC;","mysql":"SELECT host, user, count(*) FROM information_schema.processlist GROUP BY host, user ORDER BY 3 DESC;","mssql":"SELECT host_name, program_name, login_name, COUNT(*) FROM sys.dm_exec_sessions WHERE is_user_process=1 GROUP BY host_name, program_name, login_name ORDER BY 4 DESC;","oracle":"SELECT machine, program, COUNT(*) FROM v$session WHERE type='USER' GROUP BY machine, program ORDER BY 3 DESC;"},"choices":[{"label":"単一のアプリケーション / ホストが接続を膨れ上がらせた (プール)","next":"sol_pool"},{"label":"負荷が実際に増加した。すべて正当でアクティブ","next":"sol_scale"}]},"sol_idle":{"kind":"solution","title":"根本原因: アイドル接続の蓄積 / リーク","detail":"接続が開かれたまま閉じられない、または 'idle in transaction' のまま放置されており、無駄にスロットを占有している。","steps":["長時間 idle / idle in transaction の接続を整理する。管理者用に予約されたスロットを使用する。","サーバー側のタイムアウトを設定する: PG idle_in_transaction_session_timeout、MySQL wait_timeout、Oracle プロファイルの idle_time。","アプリケーションが接続 (およびトランザクション) を閉じることを確認し、リークを発生源で修正する。"],"related":["open-transactions","kill-session","connection-count"],"playbook":"connection-storm"},"sol_pool":{"kind":"solution","title":"根本原因: アプリケーションのプールが膨れ上がった","detail":"アプリケーションサーバーのコネクションプールが無制限 / 大きすぎる、またはリークしている。接続を生み出しているのはそのサーバーである。","steps":["即時対応: 問題のアプリケーションのアイドル接続を強制終了し、そのプールを再起動する。","アプリケーション側で妥当なプールサイズを設定する (ツール > コネクションプール計算機)。","サーバーと DB の間にプーラーを配置する (PgBouncer / ProxySQL / Oracle DRCP / Connection Manager (CMAN))。","max_connections をむやみに増やさない。メモリを消費し、問題を先送りするだけである。"],"related":["connection-count","kill-session"],"playbook":"connection-storm"},"sol_scale":{"kind":"solution","title":"根本原因: 実際の負荷増加","detail":"接続は正当でアクティブであり、容量が実際に不足している。","steps":["コネクションプーラーで多重化し、DB に到達する接続数を減らす。","読み取り負荷をリードレプリカに分散する。","必要に応じて、メモリ予算に従って max_connections を制御しながら増やす。サーバーのメモリも拡張する。"],"related":["connection-count"],"playbook":"connection-storm"}}},"solver/replication-lag.json":{"id":"replication-lag","title":"レプリケーションの遅延 / 停止","icon":"🔁","category":"レプリケーション","intro":"スタンバイ / レプリカがプライマリから遅れている、またはレプリケーションが完全に停止している。このツリーは遅延の種類 (増加中、一定、停止) を段階的に絞り込み、適用エラー、シングルスレッドのボトルネック、リカバリの競合、破損などの根本原因にたどり着く。","start":"root","nodes":{"root":{"kind":"step","title":"遅延はどのように推移しているか?","detail":"まず状況を測定する。レプリカのストリームと遅延のメトリクスを確認する: 遅延は時間とともに増加しているか、一定の水準で止まっているか、それとも適用が完全に停止しているか? これにより、調査は 3 つの主な分岐に分かれる。","command":{"postgres":"SELECT client_addr, state, write_lag, flush_lag, replay_lag,\n       pg_wal_lsn_diff(sent_lsn, replay_lsn) AS bytes_behind\nFROM pg_stat_replication;","mysql":"SHOW REPLICA STATUS\\G","oracle":"SELECT name, value, unit FROM v$dataguard_stats WHERE name IN ('apply lag','transport lag');","mssql":"SELECT database_id, is_local, synchronization_state_desc, redo_queue_size, log_send_queue_size\nFROM sys.dm_hadr_database_replica_states;","redis":"INFO replication","elasticsearch":"GET _cluster/health"},"choices":[{"label":"適用が完全に停止した / エラーがある","next":"stopped"},{"label":"遅延が増え続けている (追いつけない)","next":"growing"},{"label":"遅延は一定だが、長時間のクエリが疑われる","next":"standby_query"},{"label":"大きく遅れている / 不整合があるように見える","next":"sol_rebuild"}]},"stopped":{"kind":"step","title":"適用エラーは何を示しているか?","detail":"レプリケーションが停止している場合、通常は適用中のイベントでエラーが発生している。エラーメッセージを確認する: ターゲットに行 / テーブルがないのか、主キーの競合か、接続 / ネットワークの切断か?","command":{"mysql":"SHOW REPLICA STATUS\\G  -- Last_Error, Last_SQL_Error, Replica_IO_Running, Replica_SQL_Running","postgres":"SELECT status, last_msg_receipt_time, latest_end_lsn, slot_name\nFROM pg_stat_wal_receiver;","oracle":"SELECT process, status, sequence#, block# FROM v$managed_standby WHERE process LIKE 'MRP%';","elasticsearch":"GET _cat/recovery?v&active_only=true"},"choices":[{"label":"競合する行 / 存在しない行またはテーブルのエラー","next":"sol_apply_error"},{"label":"ネットワーク / 接続が切断され、IO スレッドが停止した","next":"sol_connection"}]},"growing":{"kind":"step","title":"なぜ追いつけないのか?","detail":"遅延が増え続けている場合、レプリカはプライマリの書き込み速度に追いつけていない。シングルスレッドの適用がボトルネックなのか、それともレプリカのディスク / IO が遅いのか? 適用ワーカーの状態と IO 待機を確認する。","command":{"mysql":"SHOW REPLICA STATUS\\G  -- Seconds_Behind_Source and apply thread state\nSELECT * FROM performance_schema.replication_applier_status_by_worker;","postgres":"SELECT pid, wait_event_type, wait_event, state\nFROM pg_stat_activity WHERE backend_type='startup';","mssql":"SELECT database_id, redo_queue_size, redo_rate, log_send_queue_size\nFROM sys.dm_hadr_database_replica_states;"},"choices":[{"label":"シングルスレッドの適用 + 高い書き込み負荷","next":"sol_parallel"},{"label":"レプリカのディスク / IO が遅い","next":"sol_io"}]},"standby_query":{"kind":"step","title":"スタンバイで長時間のクエリが実行されているか?","detail":"読み取り専用のスタンバイで実行されている長時間のクエリは、適用 (リカバリ) をブロックすることがある。PostgreSQL ではこれによりリカバリの競合が発生する。スタンバイのアクティブなクエリと競合カウンターを確認する。","command":{"postgres":"SELECT now()-query_start AS dur, pid, state, query\nFROM pg_stat_activity WHERE state='active' ORDER BY query_start;\nSELECT confl_snapshot, confl_lock, confl_bufferpin FROM pg_stat_database_conflicts WHERE datname=current_database();"},"choices":[{"label":"はい、長時間のクエリが適用をブロックしている","next":"sol_recovery_conflict"},{"label":"いいえ、クエリはないが、それでも遅れている","next":"sol_parallel"}]},"sol_apply_error":{"kind":"solution","title":"根本原因: 適用エラー (データの競合)","detail":"レプリカが適用できないイベントで停止している: ターゲットに行がない、主キーの競合、またはテーブルがない。むやみにスキップせず、不整合の原因を修正する。","steps":["エラーと停止したイベントを調べる: どのテーブルのどの操作 (delete/update/insert) が失敗したか?","根本原因を特定する: ターゲットに手動で書き込まれたデータ、欠落した DDL (テーブル / 列)、または破損した binlog/WAL エントリ。","スキーマを揃える: 欠落しているテーブル / 列を追加し、競合する行をプライマリと比較して修正する。","イベントをスキップする必要がある場合 (例: MySQL での単一イベント)、それを記録し、その後レプリカのデータ整合性を検証する。","再発を防ぐ: ターゲットへの直接書き込みを無効にし、DDL はプライマリを通じて実行する。"],"related":["replication-status"],"playbook":"replication-lag"},"sol_connection":{"kind":"solution","title":"根本原因: 接続 / ネットワークの切断","detail":"受信側 (IO/receiver) スレッドがプライマリに接続できない。ネットワーク、認証、または蓄積 / 削除されたログセグメントが問題の可能性がある。","steps":["プライマリとレプリカの間のネットワークアクセスと、レプリケーションユーザーの権限を確認する。","必要な WAL/binlog セグメントがプライマリにまだ存在することを確認する (保持期間 / expire)。","PostgreSQL では、レプリケーションスロットが存在しアクティブであることを確認する。スロットがないと、WAL が早期に削除されている可能性がある。","接続を再開する。ログが再び流れ始めれば、遅延は解消するはずである。"],"related":["replication-status","list-replicas"],"playbook":"replication-lag"},"sol_parallel":{"kind":"solution","title":"根本原因: シングルスレッド適用のボトルネック","detail":"プライマリが並列に書き込む一方で、レプリカは変更を単一の順序で適用しており、追いつけない。適用を並列化する。","steps":["並列適用を有効にする: MySQL では replica_parallel_workers + replica_parallel_type=LOGICAL_CLOCK。","PostgreSQL の物理レプリケーションでは適用は単一プロセスで行われるため、大きなトランザクションを分割してプライマリでの生成速度を下げる。","重いバッチジョブをトラフィックの少ない時間帯に移すか、分割する。","変更後は遅延のメトリクスを監視する。ゼロまで減少するはずである。"],"related":["replication-status"],"playbook":"replication-lag"},"sol_io":{"kind":"solution","title":"根本原因: レプリカの IO ボトルネック","detail":"適用スレッドは CPU ではなくディスクを待っている。レプリカのストレージがプライマリの書き込み速度に追いつけない。","steps":["レプリカのディスクの IO レイテンシ / 飽和度を測定し、プライマリと比較する。","レプリカのハードウェアの方が弱い場合 (遅いディスク、少ない RAM) は、プライマリに合わせる。非対称なハードウェアはよくある原因である。","redo/WAL の適用のためにディスクを高速化し、バッファ / キャッシュを適切にサイジングする。","改善しない場合は、書き込み負荷を減らすか、読み取りトラフィックを別のレプリカに分散する。"],"related":["replication-status"],"playbook":"replication-lag"},"sol_recovery_conflict":{"kind":"solution","title":"根本原因: スタンバイでのリカバリの競合","detail":"スタンバイ上の長時間の読み取り専用クエリが、プライマリからの変更の適用をブロックしている (vacuum / ロックの競合)。PostgreSQL は適用を遅らせるか、クエリをキャンセルしてこれを解消する。","steps":["ブロックしている長時間のクエリを特定する。本当に必要なら完了を待ち、そうでなければ終了する。","hot_standby_feedback=on により、プライマリにスタンバイのクエリを考慮させる (プライマリでの肥大化と引き換えに)。","あるいは、max_standby_streaming_delay をワークロードに合わせて調整する (遅延の許容度とクエリのキャンセルのバランス)。","長時間のレポートを、適用をブロックしない別のレプリカまたは別の時間帯に移す。"],"related":["replication-status","open-transactions"],"playbook":"replication-lag"},"sol_rebuild":{"kind":"solution","title":"根本原因: レプリカが大きく遅れている / 破損している - 再構築する","detail":"レプリカの遅れが大きすぎて回復できない、必要なログが削除されている、またはデータに不整合がある。最も安全な方法は、新しいバックアップから再構築することである。","steps":["プライマリから現在のベースバックアップを取得する: PG pg_basebackup、MySQL clone/xtrabackup、Oracle RMAN duplicate。","バックアップをレプリカにリストアし、レプリケーションの構成 (スロット / ユーザー / 位置) を再確立する。","レプリケーションを開始し、初期同期 (追いつき) の進捗を監視する。","遅延がゼロになったら、データの整合性と読み取りトラフィックを検証してからサービスに投入する。"],"related":["replication-status","list-replicas","last-backup-status"],"playbook":"replication-lag"}}},"solver/ora-01555.json":{"id":"ora-01555","title":"ORA-01555: Snapshot too old (Oracle)","icon":"⏳","category":"Oracle","intro":"Oracle の 'ORA-01555: snapshot too old' エラーは、クエリが読み取り一貫性のために必要とする古い (undo) データがすでに上書きされていることを示す。このツリーはエラーの発生源 (長時間クエリ + UNDO 不足、undo の高い回転率、LOB) を絞り込み、適切な対策へと導く。","start":"root","nodes":{"root":{"kind":"step","title":"エラーはどこで発生しているか?","detail":"まずエラーの状況を特定する。典型的な ORA-01555 が長時間の SELECT / レポートの実行中に発生しているのか、それとも LOB (CLOB/BLOB) 列へのアクセス中に発生しているのか? LOB 関連の ORA-01555 は別のメカニズム (PCTVERSION/RETENTION) であり、別途解決する。","command":{"oracle":"SELECT sql_id, elapsed_time/1e6 AS sec, sql_text\nFROM v$sql ORDER BY elapsed_time DESC FETCH FIRST 10 ROWS ONLY;"},"choices":[{"label":"長時間のクエリ / レポートの実行中","next":"undo_size"},{"label":"LOB 列へのアクセス中","next":"sol_lob"}]},"undo_size":{"kind":"step","title":"UNDO は十分か、保持期間は適切か?","detail":"長時間のクエリは、開始以降に変更されたブロックの古いイメージを UNDO から読み取る。UNDO 表領域が小さい場合や undo_retention がクエリの所要時間より短い場合、古い undo は上書きされる。UNDO の使用量と保持期間を測定する。","command":{"oracle":"SHOW PARAMETER undo_retention;\nSELECT tablespace_name, SUM(bytes)/1024/1024 AS mb, status\nFROM dba_undo_extents GROUP BY tablespace_name, status;\nSELECT MAX(maxquerylen) AS longest_query_sec, MAX(tuned_undoretention) AS tuned_retention\nFROM v$undostat;"},"choices":[{"label":"UNDO が小さい / 保持期間がクエリより短い","next":"sol_undo"},{"label":"UNDO は十分だがコミットが非常に頻繁","next":"sol_commits"},{"label":"クエリの実行時間が長すぎる","next":"sol_query"}]},"sol_undo":{"kind":"solution","title":"根本原因: UNDO / 保持期間の不足","detail":"保持期間の経過または表領域の満杯により、長時間のクエリが必要とする古い undo が上書きされた。UNDO を拡張し、保持期間をクエリの所要時間をカバーするよう設定する。","steps":["最長のクエリ所要時間 (v$undostat.maxquerylen) に基づき、undo_retention をそれより大きくする: ALTER SYSTEM SET undo_retention=10800;","保持期間を収容できるよう UNDO 表領域を拡張するか、autoextend を有効にする: ALTER DATABASE DATAFILE '...' AUTOEXTEND ON MAXSIZE ...;","重要な長時間クエリについては保証する: ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;  (注意: UNDO が満杯になると DML が失敗する可能性がある)。","変更後、同じレポートを再実行し、ORA-01555 が解消したことを確認する。"],"related":["show-config-param"],"playbook":"ora-01555"},"sol_commits":{"kind":"solution","title":"根本原因: undo の高い回転率 (頻繁なコミット)","detail":"非常に頻繁なコミットを伴う大量の DML は undo ブロックを急速に再利用し、長時間のクエリが必要とする古いイメージを消してしまう。'commit cleanout' の影響でさらに悪化する。","steps":["不必要に頻繁なコミットを減らす: ループ内で行ごとにコミットする代わりに、バッチコミットを使用する。","undo の回転を遅くするため、大量の DML ワークロードを長時間のレポートと同時にスケジュールしない。","undo_retention を増やし、必要に応じて RETENTION GUARANTEE で古い undo を保護する。","レポートを大量書き込みの時間帯の外に移すか、一貫した読み取りポイントに固定する。"],"related":["open-transactions","show-config-param"],"playbook":"ora-01555"},"sol_query":{"kind":"solution","title":"根本原因: クエリの所要時間が長すぎる","detail":"クエリの実行時間が長すぎて、妥当な undo_retention でも足りない。恒久的な対策は、クエリを高速化するか、その負荷を逃がすことである。","steps":["クエリを最適化する: インデックスの不足、不適切な実行計画、不要なフルスキャンを修正し、所要時間を短縮する。","大きなジョブを (日付 / 範囲で) 分割し、各チャンクが undo ウィンドウ内に収まるようにする。","重いレポートをスタンバイ / レプリカまたは別の読み取り時間帯に移し、アクティブな DML と衝突しないようにする。","所要時間が許容範囲になったら、それに応じて undo_retention を設定する。"],"related":["explain-plan"],"playbook":"ora-01555"},"sol_lob":{"kind":"solution","title":"根本原因: LOB の保持 / PCTVERSION","detail":"LOB の読み取り中の ORA-01555 は、古い LOB バージョンを保持する領域 (RETENTION または PCTVERSION) が不足していることを示す。LOB には独自のバージョン管理メカニズムがある。","steps":["LOB 列の現在の設定を確認する: SELECT retention, pctversion FROM dba_lobs WHERE table_name='...' AND column_name='...';","AUTO/MANUAL の undo モードに応じて適切な設定を引き上げる: ALTER TABLE t MODIFY LOB (my_column) (RETENTION);  または MANUAL モードでは PCTVERSION を増やす。","RETENTION を使用する LOB はデータベースの undo_retention の値に基づくため、これも十分に保つ。","LOB にアクセスする長時間の操作を短縮し、変更後にエラーを再テストする。"],"related":["show-config-param"],"playbook":"ora-01555"}}},"solver/backup-restore.json":{"id":"backup-restore","title":"バックアップとリストアの判断","icon":"💾","category":"バックアップとリカバリ","intro":"バックアップで行う必要のある作業 (バックアップの取得、リストア、特定時点への復帰 - PITR、バックアップの検証) を段階的に案内し、各データベースに適したコマンドと手順へと導く診断フロー。","start":"root","nodes":{"root":{"kind":"step","title":"何をしたいか?","detail":"目的を選択する。新しいバックアップを取得するのか、既存のバックアップをリストアするのか、特定の時刻 (障害の直前) に戻るのか、それとも手元のバックアップが健全であることを検証するのか?","choices":[{"label":"バックアップを取得したい","next":"take"},{"label":"バックアップをリストアしたい","next":"restore"},{"label":"特定の時点に戻る (PITR)","next":"pitr"},{"label":"バックアップを検証したい","next":"verify"}]},"take":{"kind":"step","title":"どの種類のバックアップか?","detail":"論理バックアップ (ダンプ) は移植性があり選択的なリストアに適しているが、大量データでは遅い。物理バックアップ (ファイル / ブロックレベル) は大規模データベースと高速な復旧に適している。必要に応じて選択する。","choices":[{"label":"論理バックアップ (ダンプ / エクスポート)","next":"sol_logical_backup"},{"label":"物理 / フルバックアップ","next":"sol_physical_backup"}]},"sol_logical_backup":{"kind":"solution","title":"論理バックアップ (ダンプ) の取得","detail":"データを SQL/BSON ステートメントとしてエクスポートする。バージョン / プラットフォーム間の移行や、単一テーブル / コレクションのリストアに最適。","steps":["PostgreSQL: pg_dump -Fc -d mydb -f backup.dump  (クラスタ全体には pg_dumpall)。","Oracle: expdp app_user/password directory=DP_DIR dumpfile=backup.dmp schemas=APP_SCHEMA logfile=exp.log","MySQL/MariaDB: mysqldump --single-transaction --routines --triggers mydb > backup.sql","MongoDB: mongodump --db mydb --out /backup/dir","Redis: BGSAVE でバックグラウンドで RDB スナップショットを取得する (dump.rdb)。","Elasticsearch: まずスナップショットリポジトリを登録し、次に PUT _snapshot/my_repo/snap1?wait_for_completion=true","バックアップを安全な場所に移し、そのサイズ / 完了状態を記録する。"],"related":["logical-dump","last-backup-status"],"playbook":"backup-restore"},"sol_physical_backup":{"kind":"solution","title":"物理 / フルバックアップの取得","detail":"データファイルのブロック / ファイルレベルのコピー。大規模データベースでも高速で、PITR と完全復旧の基盤となる。","steps":["Oracle: RMAN> BACKUP DATABASE PLUS ARCHIVELOG;  (アーカイブログとともに)。","PostgreSQL: pg_basebackup -D /backup/base -Fp -Xs -P  (WAL アーカイブを有効にしたうえで)。","SQL Server: BACKUP DATABASE [mydb] TO DISK='D:\\backup\\db.bak' WITH CHECKSUM, COMPRESSION;","MySQL/MariaDB: xtrabackup --backup --target-dir=/backup/base  (一貫性のある物理コピー)。","MongoDB: ファイルシステムスナップショット、またはレプリカセットメンバーからの一貫性のあるスナップショットを取得する。","バックアップをオフライン / リモートの場所にコピーし、最新のバックアップ状態を記録する。"],"related":["last-backup-status"],"playbook":"backup-restore"},"restore":{"kind":"solution","title":"バックアップのリストア","detail":"手元にある最適なバックアップをターゲットにリストアする。まずバックアップの整合性とタイムスタンプを検証し、次にエンジンに適したコマンドでロードする。","steps":["リストアするバックアップの日付と健全性を確認する (データ損失の範囲を把握する)。","PostgreSQL: pg_restore -d new_db backup.dump   (SQL ダンプの場合: psql -d new_db -f backup.sql)。","Oracle: RMAN> RESTORE DATABASE; RECOVER DATABASE; ALTER DATABASE OPEN;  (論理インポートは impdp)。","MySQL/MariaDB: mysql mydb < backup.sql   (物理: xtrabackup --copy-back)。","SQL Server: RESTORE DATABASE [mydb] FROM DISK='D:\\backup\\db.bak' WITH RECOVERY, REPLACE;","MongoDB: mongorestore --db mydb /backup/dir","リストア後、行数 / アプリケーションのチェックでデータを検証する。"],"related":["restore-dump","last-backup-status"],"playbook":"backup-restore"},"pitr":{"kind":"solution","title":"特定の時点への復帰 (PITR)","detail":"誤った削除 / 破損の直前に、秒単位の精度で戻りたい場合。フルバックアップ + その時点までのトランザクションログ (アーカイブログ / WAL / binlog) が必要。","steps":["目標時刻 (インシデントの直前) を正確に特定し、必要なログが揃っていることを確認する。","Oracle: RMAN> RESTORE DATABASE; RECOVER DATABASE UNTIL TIME \"TO_DATE('2026-07-04 10:00:00','YYYY-MM-DD HH24:MI:SS')\"; ALTER DATABASE OPEN RESETLOGS;","PostgreSQL: ベースバックアップをリストアし、recovery_target_time='2026-07-04 10:00:00' を設定して、その時点まで WAL を適用する。","SQL Server: RESTORE ... WITH NORECOVERY; 次に RESTORE LOG ... WITH STOPAT='2026-07-04 10:00:00', RECOVERY;","MySQL/MariaDB: フルバックアップをリストアし、mysqlbinlog --stop-datetime='2026-07-04 10:00:00' でその時点まで binlog を適用する。","オープン後、データが想定した時点の状態であることを確認する。"],"related":["restore-dump","last-backup-status"],"playbook":"backup-restore"},"verify":{"kind":"solution","title":"バックアップの検証","detail":"バックアップは、リストア可能であることが証明されて初めてバックアップといえる。整合性と実際のリストア可能性を定期的にテストする。","steps":["Oracle: RMAN> RESTORE DATABASE VALIDATE;  ブロックの整合性には VALIDATE CHECK LOGICAL DATABASE;","SQL Server: バックアップを WITH CHECKSUM で取得し、RESTORE VERIFYONLY ... WITH CHECKSUM を実行する (バックアップファイルのみをチェックする)。確実な証明のためには、バックアップをテストサーバーにリストアし、そこで DBCC CHECKDB([mydb]) WITH NO_INFOMSGS; を実行する (CHECKDB はバックアップファイルではなく、稼働中 / リストア済みのデータベースをチェックする)。","PostgreSQL: バックアップを別の / 一時的なサーバーに実際にリストアし、pg_restore がエラーなく完了することを確認する。","MySQL/MongoDB: ダンプをテスト環境にリストアし、行数 / コレクション数とサンプルデータを比較する。","定期的な「リストア訓練」をスケジュールする — バックアップを取得するだけでは不十分で、リストアも証明する。","結果と、最後に検証が成功した日付を記録する。"],"related":["last-backup-status","restore-dump"],"playbook":"backup-restore"}}},"solver/upgrade-wizard.json":{"id":"upgrade-wizard","title":"バージョンアップグレードウィザード","icon":"⬆️","category":"ライフサイクル","intro":"パッチかメジャーか、インプレースか移行か? アップグレードを段階的に計画する。各分岐で事前チェック、方法、アップグレード後の作業を扱う。本番環境に手を付ける前に、ここでリハーサルする。","start":"kind","nodes":{"kind":{"kind":"step","title":"どのような種類のアップグレードを行いますか?","detail":"パッチ/マイナーバージョン (同一メジャーバージョン内。例: 16.2 -> 16.4、または SQL Server の CU) はリスクが低く、通常はインプレースで行う。メジャーバージョン (例: 15 -> 16) ではデータ形式の変更を伴う場合があり、より慎重な計画が必要となる。","command":{"oracle":"SELECT * FROM v$version;\nSELECT patch_id, action, status FROM dba_registry_sqlpatch ORDER BY action_time DESC;","postgres":"SELECT version();","mysql":"SELECT VERSION();","mssql":"SELECT SERVERPROPERTY('ProductVersion') AS v, SERVERPROPERTY('ProductUpdateLevel') AS cu;","elasticsearch":"GET /"},"choices":[{"label":"マイナーバージョン/パッチ (同一メジャーバージョン、CU)","next":"patch_prep"},{"label":"メジャーバージョン (メジャーバージョンが変わる)","next":"major_method"},{"label":"違いが分からないので説明してほしい","next":"explain"}]},"explain":{"kind":"step","title":"パッチかメジャーか?","detail":"パッチ: メジャーバージョンは変わらない (16.2 -> 16.4)。データファイルの形式は変わらず、通常はバイナリの入れ替え + 再起動で済む。メジャー: メジャーバージョンが変わる (15 -> 16)。カタログ / 形式が変わる可能性があり、pg_upgrade / AutoUpgrade / ダンプ/リストアが必要で、アプリケーションの互換性をテストする必要がある。","choices":[{"label":"パッチである (同じメジャーバージョン)","next":"patch_prep"},{"label":"メジャーである (メジャーバージョンが変わる)","next":"major_method"}]},"patch_prep":{"kind":"step","title":"バックアップとロールバック計画は準備できているか?","detail":"パッチはリスクが低いとはいえ、すべてのアップグレードの鉄則は「まずフルバックアップ (可能ならスナップショットも)」である。問題が起きたときに戻れるポイントが必要。","choices":[{"label":"はい、バックアップとロールバックは準備できている","next":"sol_patch"},{"label":"いいえ、まだ","next":"sol_backupfirst"}]},"sol_backupfirst":{"kind":"solution","title":"まずバックアップとロールバック計画","detail":"アップグレードを開始する前にセーフティネットを用意する。","steps":["フルバックアップを取得する (可能であればストレージスナップショット / Oracle の保証付きリストアポイントも)。","ロールバック手順を書き出す: 問題が起きた場合、どうやって旧バージョンに戻るか?","メンテナンス時間帯と連絡計画を確定し、パッチの手順に進む。"],"related":["logical-dump","last-backup-status"]},"sol_patch":{"kind":"solution","title":"パッチを適用する","detail":"同じメジャーバージョン内のパッチ。クラスタ全体にローリングで適用すると (レプリカから開始)、ダウンタイムを減らせる。","steps":["Oracle: opatch で新しい RU をインストールし、'datapatch -verbose' で SQL の変更を適用する。","PostgreSQL: マイナーアップグレード = 新しいバイナリをインストールしてサービスを再起動する (initdb/ダンプは不要)。","MySQL: パッケージを更新する。8.0 ではサーバーが起動時に自動的にアップグレードを実行する。","SQL Server: 該当する CU/GDR のインストーラーを実行し、再起動する。","MongoDB/Redis/Elasticsearch: ローリング再起動。セカンダリノードを先に、プライマリを最後に。","その後、バージョンとアプリケーションを確認する。エラーが見られる場合は、ロールバック計画を実行する。"],"related":["apply-patch","check-version"],"playbook":"upgrade-rollback"},"major_method":{"kind":"step","title":"メジャーアップグレードの方法","detail":"主な方法は 2 つ: (1) インプレース: 既存のサーバー上で変換する (pg_upgrade、Oracle AutoUpgrade/DBUA、MySQL のインプレース)。高速だがロールバックが難しい。(2) 移行: 新バージョンで新しいサーバーを構築し、データを移動 (ダンプ / リストアまたはレプリケーションで) してから切り替える。より安全で、ダウンタイムは最小限。","choices":[{"label":"まず準備 / 互換性チェックを実行する","next":"precheck"},{"label":"インプレース","next":"sol_inplace"},{"label":"新しいサーバーへの移行による (最小限のダウンタイム)","next":"sol_migrate"}]},"precheck":{"kind":"step","title":"互換性 / 準備状況のチェック","detail":"アップグレードの前に、対象バージョンの警告を収集する: 削除された (非推奨の) 機能、無効なオブジェクト、互換性レベル。","command":{"oracle":"-- AutoUpgrade analyze mode: java -jar autoupgrade.jar -config cfg -mode analyze","postgres":"-- pg_upgrade --check   (with the old and new binary paths)","mysql":"-- MySQL Shell: util.checkForServerUpgrade('root@localhost:3306', {targetVersion: '8.4.0'})","mssql":"-- Compatibility report with Data Migration Assistant (DMA)","elasticsearch":"GET _migration/deprecations"},"choices":[{"label":"出力に問題なし。続行する","next":"major_method"},{"label":"警告 / 非互換性がある","next":"sol_fixwarn"}]},"sol_fixwarn":{"kind":"solution","title":"まず警告を修正する","detail":"アップグレードの前に、レポート内のすべての警告を解決する。そうしないと、アップグレードが途中で失敗したり、アプリケーションが動作しなくなったりする可能性がある。","steps":["削除された (非推奨の) 機能 / 構文を使用しているオブジェクトとクエリを更新する。","無効なオブジェクトをコンパイル / 修正し、欠落している依存関係を解決する。","対象バージョンに向けた互換性レベル / 機能バージョンの段階を計画する。","警告が解消したら、事前チェックを再実行し、方法の選択に戻る。"],"related":["check-upgrade-readiness","set-compatibility"]},"sol_inplace":{"kind":"solution","title":"インプレースでのメジャーアップグレード","detail":"既存のサーバー上で変換する。高速だが、ロールバックは通常バックアップからのリストアを意味するため、スナップショットは必須。","steps":["フルバックアップ + スナップショット / 保証付きリストアポイントを取得する (唯一の戻り道)。","Oracle: AutoUpgrade (deploy モード) または DBUA。PostgreSQL: pg_upgrade (--link は高速だが戻る手段がない)。MySQL: 新しいバイナリ + 自動インプレースアップグレード。SQL Server: setup /ACTION=upgrade。","アップグレード後のタスクを実行する (下記の関連項目を参照)。","実際の負荷のもとでアプリケーションを検証する。実行計画の性能低下が発生した場合は、オプティマイザの動作を固定する。"],"related":["upgrade-major","post-upgrade-tasks"],"playbook":"upgrade-rollback"},"sol_migrate":{"kind":"solution","title":"移行によるアップグレード (最小限のダウンタイム)","detail":"新バージョンで新しいサーバーを構築し、データを移動してから、短時間の切り替えで移行する。最も安全な方法で、旧システムはそのまま残る。","steps":["対象バージョンで新しいサーバーを構築し、スキーマを準備する。","初期ロードをダンプ / リストアまたはレプリケーションで転送し、その後は継続的なレプリケーション (CDC / 論理レプリケーション) で同期を保つ。","短いメンテナンス時間帯に: 書き込みを停止し、残りの差分を待ち、アプリケーションを新しいサーバーに向ける (切り替え)。","移行を検証する (行数 / チェックサム)。問題がある場合は、すぐに旧サーバーに戻す。"],"related":["setup-cdc-replication","verify-migration","export-for-migration"]}}},"solver/migration-wizard.json":{"id":"migration-wizard","title":"移行ウィザード (データ / スキーマの移行)","icon":"🚚","category":"ライフサイクル","intro":"データ / スキーマを移行する。同種か異種か、ダウンタイムの許容度はどれくらいか? 評価 → 移行 → 検証の順に段階的に計画する。まずここで切り替えのリハーサルを行う。","start":"kind","nodes":{"kind":{"kind":"step","title":"移行元と移行先は何ですか?","detail":"同種: 同じデータベースエンジン (例: Oracle 19 → Oracle 23、または PostgreSQL から別のサーバーへ)。異種: 異なるエンジン (例: Oracle → PostgreSQL、MySQL → SQL Server)。異種移行では、はるかに多くの互換性対応 (データ型、関数、PL/SQL) が必要となる。","choices":[{"label":"同じエンジン、新しいサーバー/バージョン (同種)","next":"downtime"},{"label":"異なるエンジンへ (異種)","next":"hetero"},{"label":"計画段階なので、どう進めるべきか知りたい","next":"downtime"}]},"downtime":{"kind":"step","title":"ダウンタイムの許容度はどれくらいか?","detail":"これにより移行方法が決まる。メンテナンス時間帯がある場合、最も簡単な方法はダンプ / リストアである。ほぼゼロのダウンタイムが求められる場合は、初期データをロードし、継続的なレプリケーション (CDC) で同期を保ち、短時間で切り替える。","choices":[{"label":"メンテナンス時間帯がある (ダウンタイムは許容できる)","next":"sol_offline"},{"label":"ほぼゼロのダウンタイムが求められる","next":"sol_online"}]},"hetero":{"kind":"step","title":"スキーマと型の互換性を評価したか?","detail":"異種間の移行では、本当の作業はデータのコピーではなく差異の解消である: データ型 (VARCHAR2↔TEXT)、関数 (NVL↔COALESCE)、自動採番の値、PL/SQL ↔ PL/pgSQL、削除された / 異なる機能。","choices":[{"label":"スキーマ / 型の差異を対応付けた","next":"sol_hetero"},{"label":"まだ評価していない","next":"sol_assess"}]},"sol_assess":{"kind":"solution","title":"まず互換性を評価する","detail":"移行の前に、ソースとターゲットの差異を対応付ける。この手順を省くと、移行は途中で行き詰まる。","steps":["スキーマの差分を作成する: テーブル、制約、インデックス、ビュー、プロシージャ。","データ型と関数を対応付ける (DBAtlas > 型と関数 モジュールはまさにこのためのもの)。","エンジン固有の機能 (identity/シーケンス、パーティショニング、PL/SQL、トリガー) をターゲットでどう扱うかを決める。","変換ツール (ora2pg、pgloader、AWS SCT/DMS) を選び、小さなサンプルでリハーサルする。"],"related":["compare-schema","heterogeneous-migration"]},"sol_offline":{"kind":"solution","title":"オフライン移行 (ダンプ / リストア)","detail":"最も簡単で信頼性の高い同種間の方法: 一貫性のあるバックアップを取得し、ターゲットにロードし、検証し、切り替える。","steps":["ソースから一貫性のあるエクスポートを取得する (pg_dump -Fc、expdp FLASHBACK_SCN、mysqldump --single-transaction、BACKUP、mongodump --oplog)。","ターゲットにロードする (pg_restore -j、impdp、mysql <、RESTORE、mongorestore)。","移行を検証する: ソースとターゲットで行数と重要なチェックサムは一致しているか?","メンテナンス時間帯に、アプリケーションをターゲットに向ける (切り替え)。問題が起きた場合は、ソースに戻す。"],"related":["export-for-migration","import-for-migration","verify-migration"]},"sol_online":{"kind":"solution","title":"最小限のダウンタイム (CDC / レプリケーション)","detail":"初期データをロードした後、継続的なレプリケーションでターゲットをソースと同期させる。ダウンタイムは短い切り替えの間だけ発生する。","steps":["初期 (ベースライン) データをダンプ / リストアまたはスナップショットでロードする。","継続的なレプリケーションを設定する: PG 論理レプリケーション (PUBLICATION/SUBSCRIPTION)、MySQL binlog レプリケーション、Oracle GoldenGate、MSSQL トランザクションレプリケーション / CDC、Mongo change streams/mongosync。","ターゲットがソースに追いつき、遅延が約 0 になるまで待機して監視する。","短時間の切り替え: ソースへの書き込みを停止し、残りの差分を待ち、アプリケーションをターゲットに向けて検証する。"],"related":["setup-cdc-replication","verify-migration"]},"sol_hetero":{"kind":"solution","title":"異種間の移行 (別のエンジンへ)","detail":"スキーマを変換し、データを移動し、ロジックを適合させ、検証する。段階的に進め、すべてを一度に移行しない。","steps":["スキーマを変換する: ツール (ora2pg、pgloader、AWS SCT) または手作業で。型と制約をターゲットに合わせる。","データを移動する: 一括ロードまたはツールで。大きなテーブルはパーティション / チャンクに分割する。","サーバー側のロジックを適合させる: PL/SQL → PL/pgSQL、関数 / トリガーの同等物。","徹底的に検証する: 行数、サンプルデータ、重要なクエリの結果。ターゲット上でアプリケーションをテストする。","ダウンタイムを短縮する必要がある場合は、変換後に CDC レイヤーでターゲットを同期させてから切り替える。"],"related":["heterogeneous-migration","verify-migration","setup-cdc-replication"]}}},"solver/high-cpu.json":{"id":"high-cpu","title":"高い CPU 使用率","icon":"🔥","category":"パフォーマンス","intro":"サーバーの CPU が張り付いている。まずデータベースが本当に消費しているのかを確認し、分岐をたどって根本原因に到達する: 実行計画の悪いクエリ、実行計画の性能低下、過剰な同時実行、または DB 以外のプロセス。","start":"root","nodes":{"root":{"kind":"step","title":"データベースが本当に CPU を消費しているか?","detail":"オペレーティングシステム側で、どのプロセスが CPU を消費しているかを確認する。負荷の大部分が DB プロセスにあるのか、それとも隣接するプロセス (バックアップ、ウイルス対策、別のアプリケーション) にあるのか? これにより調査は 2 つに分かれる。","command":{"oracle":"-- OS side: top -o %CPU  (or: top -c)\n-- DB-side verification:\nSELECT ROUND(value,1) AS host_cpu_util_pct FROM v$sysmetric WHERE metric_name='Host CPU Utilization (%)' AND rownum=1;","postgres":"-- OS: top -c  /  ps -eo pcpu,pid,cmd --sort=-pcpu | head\n-- DB active session count:\nSELECT count(*) FROM pg_stat_activity WHERE state='active';","mysql":"-- OS: top -c  /  mysqladmin processlist\nSHOW GLOBAL STATUS LIKE 'Threads_running';","mssql":"-- OS: Task Manager / typeperf\nSELECT record_id, SQLProcessUtilization AS sql_cpu_pct, (100 - SystemIdle - SQLProcessUtilization) AS other_cpu_pct FROM (SELECT record.value('(./Record/@id)[1]','int') AS record_id, record.value('(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]','int') AS SystemIdle, record.value('(./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]','int') AS SQLProcessUtilization FROM (SELECT CONVERT(xml, record) AS record FROM sys.dm_os_ring_buffers WHERE ring_buffer_type='RING_BUFFER_SCHEDULER_MONITOR') AS x) AS y ORDER BY record_id DESC;","mongodb":"// OS: top -c  |  db.serverStatus().metrics\ndb.serverStatus().opcounters","redis":"INFO cpu","elasticsearch":"GET _nodes/stats/os,process"},"choices":[{"label":"はい、DB プロセスが CPU を消費している","next":"db_confirm"},{"label":"いいえ、隣接するプロセス / バックアップジョブが消費している","next":"sol_os"}]},"db_confirm":{"kind":"step","title":"負荷はどのように現れたか?","detail":"DB が CPU を消費している場合は、パターンを特定する: 少数の重いクエリが支配的なのか、変更の後に問題が突然始まったのか、それとも同時実行 / 接続の競合が多いのか?","choices":[{"label":"少数の重いクエリが CPU を消費している","next":"topcpu"},{"label":"突然始まった。最近デプロイ / パラメータ変更があった","next":"sol_regression"},{"label":"接続が多い / 同時実行の競合","next":"sol_concurrency"}]},"topcpu":{"kind":"step","title":"CPU を最も消費しているクエリを特定する","detail":"CPU の合計消費量で上位のクエリを取得する。次に、それぞれが 1 回あたり重い (実行計画が悪い) のか、1 回あたりは軽いが非常に頻繁に呼び出されているのかを判断する。","command":{"oracle":"SELECT sql_id, executions, ROUND(cpu_time/1e6,1) AS cpu_sec, ROUND(cpu_time/GREATEST(executions,1)/1000,2) AS cpu_ms_per_exec, sql_text\nFROM v$sql ORDER BY cpu_time DESC FETCH FIRST 10 ROWS ONLY;","postgres":"SELECT queryid, calls, ROUND(total_exec_time::numeric,1) AS total_ms, ROUND(mean_exec_time::numeric,2) AS mean_ms, query\nFROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 10;","mysql":"SELECT DIGEST_TEXT, COUNT_STAR AS calls, ROUND(SUM_CPU_TIME/1e12,2) AS cpu_sec, ROUND(SUM_TIMER_WAIT/1e12,2) AS total_sec\nFROM performance_schema.events_statements_summary_by_digest ORDER BY SUM_TIMER_WAIT DESC LIMIT 10;","mssql":"SELECT TOP 10 qs.execution_count, qs.total_worker_time/1000 AS cpu_ms, qs.total_worker_time/qs.execution_count/1000 AS cpu_ms_per_exec, SUBSTRING(st.text,(qs.statement_start_offset/2)+1,50) AS stmt\nFROM sys.dm_exec_query_stats qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st ORDER BY qs.total_worker_time DESC;","mongodb":"db.setProfilingLevel(1, { slowms: 100 });  // then: db.system.profile.find().sort({ millis: -1 }).limit(10)"},"choices":[{"label":"1 回あたりが重い。実行計画が悪い / フルスキャン","next":"sol_query"},{"label":"1 回あたりは軽いが、非常に頻繁に呼び出される","next":"sol_frequency"}]},"sol_query":{"kind":"solution","title":"根本原因: 実行計画の悪いクエリが CPU を消費している","detail":"少数のクエリが、フルスキャンや不適切な結合順序のために 1 回あたり過剰な CPU を消費している。それらの実行計画の修正が中心的な解決策である。","steps":["CPU 消費の上位クエリの実行計画 (EXPLAIN) を取得し、フルスキャン、不適切な結合順序、推定行数と実績行数の差を探す。","フィルタ / 結合列に適したインデックスを追加し、実行計画がインデックススキャン (IXSCAN) に切り替わることを確認する。","オプティマイザが誤った推定をしている場合は、最新の統計を収集する。","暴走クエリを制限し (Oracle Resource Manager / MSSQL Resource Governor)、必要に応じてクエリを書き換える。"],"related":["top-slow-queries","explain-plan","create-index","update-statistics"],"playbook":"high-cpu"},"sol_frequency":{"kind":"solution","title":"根本原因: 過剰な呼び出し頻度","detail":"クエリは個々には軽いが、毎秒数千回呼び出されており、それが CPU の合計コストの原因である。通常は N+1 パターン、またはキャッシュされていないホットパスである。","steps":["最も頻繁に呼び出されるステートメント (calls / execution_count) を特定し、呼び出し元のアプリケーションのパスを見つける。","N+1 パターンをバッチクエリに変える。アプリケーション / 結果キャッシュで繰り返しの読み取りを減らす。","プリペアドステートメントを使用して、繰り返しの解析 (ハードパース) のコストを削減する。","頻繁に実行され、結果が変わらない重いクエリには、マテリアライズドビュー / 集計テーブルを検討する。"],"related":["top-slow-queries","explain-plan"],"playbook":"high-cpu"},"sol_regression":{"kind":"solution","title":"根本原因: 実行計画の性能低下 / 古い統計","detail":"昨日まではシステムは正常だった。デプロイ、パラメータ変更、データロードの後に CPU が急上昇した。オプティマイザがより悪い実行計画に切り替えた可能性がある。","steps":["変更を特定する: 最近のデプロイ、アップグレード / パッチ、パラメータ変更、大量データロード。","影響を受けるテーブルの最新の統計を収集する (古い統計が最も一般的な原因)。","良好な実行計画を固定する: Oracle SQL Plan Baseline / ヒント、MSSQL Query Store の 'force plan'。","変更がパラメータによるものであれば、元に戻して制御された方法で再評価する。"],"related":["update-statistics","explain-plan","show-config-param"],"playbook":"high-cpu"},"sol_concurrency":{"kind":"solution","title":"根本原因: 高い同時実行性 / 接続の競合","detail":"個々のクエリは許容範囲だが、同時に実行されるセッションが多すぎる。CPU コア数を超えるアクティブセッションは、コンテキストスイッチとラッチ / スピンの競合を引き起こす。","steps":["アクティブセッション数を CPU コア数と比較する。コア数を超えるアクティブセッションがあると、実行キューが積み上がる。","アプリケーションと DB の間にコネクションプーラー (PgBouncer / ProxySQL) を配置し、妥当なプールサイズを設定する。","過剰な並列処理がある場合は、並列度を制限する (Oracle parallel_degree_limit / parallel_max_servers、MSSQL MAXDOP)。","読み取り負荷をリードレプリカに分散して、プライマリノードの CPU を軽減する。"],"related":["connection-count","active-sessions"],"playbook":"connection-storm"},"sol_os":{"kind":"solution","title":"根本原因: DB 以外のプロセスが CPU を消費している","detail":"CPU を消費しているのはデータベースではなく隣接するプロセスである: 同じマシン上のバックアップ / 圧縮ジョブ、ウイルススキャン、ログ転送ツール、または別のアプリケーション。","steps":["OS のツール (top / タスクマネージャー) で原因となるプロセスを特定する。","バックアップ、統計収集、メンテナンスジョブであれば、ピーク時間外に再スケジュールする。","データディレクトリを、ウイルス対策 / スキャンプロセスの除外リストに追加する。","競合が恒常的な場合は、DB を専用のリソースを持つ別のサーバーに移す。"],"related":["os-resource"],"playbook":"high-cpu"}}},"solver/memory-pressure.json":{"id":"memory-pressure","title":"メモリ負荷 / OOM","icon":"🧠","category":"パフォーマンス","intro":"サーバーのメモリが不足している、システムがスワップしている、または OOM killer が作動している。まず誰がメモリを消費しているかを特定する: 割り当て済みメモリ (バッファプール / SGA)、セッションメモリ (work_mem/PGA)、OS 全体、それとも Redis 固有の状況か?","start":"root","nodes":{"root":{"kind":"step","title":"誰がメモリを消費しているか?","detail":"メモリ負荷の発生源を層ごとに切り分ける。割り当て済み (固定) メモリが大きすぎるのか、セッションごとのメモリが爆発しているのか、DB 以外のプロセスが消費しているのか、それとも Redis 自身のメモリ管理が関係しているのか?","command":{"oracle":"SELECT component, ROUND(current_size/1024/1024) AS mb FROM v$memory_dynamic_components WHERE current_size>0 ORDER BY current_size DESC;","postgres":"SHOW shared_buffers; SHOW work_mem; SHOW effective_cache_size;\nSELECT count(*) FROM pg_stat_activity WHERE state='active';","mysql":"SHOW VARIABLES LIKE 'innodb_buffer_pool_size';\nSHOW VARIABLES LIKE 'sort_buffer_size'; SHOW VARIABLES LIKE 'join_buffer_size';\nSHOW STATUS LIKE 'Threads_connected';","mssql":"SELECT physical_memory_in_use_kb/1024 AS used_mb, large_page_allocations_kb/1024 AS large_mb FROM sys.dm_os_process_memory;\nSELECT cntr_value/1024 AS target_mb FROM sys.dm_os_performance_counters WHERE counter_name='Target Server Memory (KB)';","mongodb":"db.serverStatus().wiredTiger.cache","redis":"INFO memory","elasticsearch":"GET _nodes/stats/jvm,os"},"choices":[{"label":"割り当て済みメモリ (バッファプール / SGA) が支配的","next":"allocated"},{"label":"セッションメモリ (work_mem / PGA) が爆発している","next":"sol_session"},{"label":"DB 以外のプロセス / OS 全体","next":"sol_os"},{"label":"Redis 固有 (maxmemory / eviction / 断片化)","next":"sol_redis"}]},"allocated":{"kind":"step","title":"構成したメモリの合計が物理 RAM を超えているか?","detail":"固定で割り当てたメモリが大きい場合、2 つの可能性がある: 構成した合計 (バッファプール + セッション + OS) が物理 RAM を超えている (オーバーコミット) か、サイズは妥当だがキャッシュヒット率が依然として低いかである。設定を合計して RAM と比較する。","command":{"oracle":"SHOW PARAMETER sga_target;  SHOW PARAMETER pga_aggregate_target;\nSELECT ROUND(value/1024/1024/1024,1) AS host_ram_gb FROM v$osstat WHERE stat_name='PHYSICAL_MEMORY_BYTES';","postgres":"SELECT name, setting, unit FROM pg_settings WHERE name IN ('shared_buffers','work_mem','maintenance_work_mem','max_connections');","mysql":"SELECT ROUND(@@innodb_buffer_pool_size/1024/1024/1024,1) AS pool_gb, ROUND((@@sort_buffer_size+@@join_buffer_size)/1024/1024,1) AS per_conn_mb, @@max_connections AS max_conn;","mssql":"SELECT value_in_use AS max_server_mem_mb FROM sys.configurations WHERE name='max server memory (MB)';\nSELECT total_physical_memory_kb/1024 AS ram_mb FROM sys.dm_os_sys_memory;"},"choices":[{"label":"はい、構成した合計が RAM を超えている (オーバーコミット)","next":"sol_overcommit"},{"label":"いいえ、サイズは妥当だがキャッシュヒット率が低い","next":"sol_cache"}]},"sol_overcommit":{"kind":"solution","title":"根本原因: メモリのオーバーコミット","detail":"バッファプール / SGA + セッションメモリ + OS の必要量の合計が物理 RAM を超えている。システムがスワップしているか、OOM killer がプロセスを強制終了している。","steps":["メモリ予算を見直す: OS 用の分を確保し、そのうえで割り当てメモリを正しくサイジングする (ツール > メモリ計算機)。","バッファプール / SGA の目標値とセッションメモリの上限を下げ、RAM の範囲内に収める。","変更を制御された方法で適用し、スワップの使用と OOM イベントが止まったことを確認する。","容量が恒常的に不足している場合は、RAM を追加するか負荷を分割する。"],"related":["show-config-param","cache-hit-ratio"],"playbook":"memory-pressure"},"sol_cache":{"kind":"solution","title":"根本原因: キャッシュ不足 (キャッシュヒット率が低い)","detail":"割り当てメモリは RAM を超えていないが、ワーキングセットに対して小さい。バッファキャッシュのヒット率が低く、DB は常にディスクから読み取っている。","steps":["バッファキャッシュ / バッファプールのヒット率を測定する。恒常的に低い場合 (例: 90% 未満)、キャッシュが小さすぎる。","RAM に余裕があれば、バッファプール / SGA を制御された方法で拡大し、ヒット率を再測定する。","ホットデータが本当に大きい場合は、不要な読み取りを減らす: インデックスを追加する、SELECT * ではなく必要な列のみを選択する、ページネーションを行う。","拡大によって RAM が逼迫する場合は、セッションメモリと割り当てメモリのバランスを取り直す。"],"related":["cache-hit-ratio","show-config-param"],"playbook":"memory-pressure"},"sol_session":{"kind":"solution","title":"根本原因: セッションメモリの爆発","detail":"work_mem/PGA などのセッションごとのメモリが高い同時実行数と掛け合わされ、RAM を使い果たしている。ソート / ハッシュ操作ごとに、このメモリが個別に割り当てられることがある。","steps":["最悪のケースを見積もる: セッションメモリ × 同時セッション数 × 操作数。これを RAM と比較する。","グローバルなセッションメモリの設定 (work_mem / sort_buffer_size / PGA target) を下げる。","本当に大きなソート / ハッシュが必要な重いクエリについては、セッションレベルでのみ設定を引き上げる。","コネクションプーラーで同時実行数を制限し、総メモリ需要を削減する。"],"related":["show-config-param","connection-count"],"playbook":"memory-pressure"},"sol_redis":{"kind":"solution","title":"根本原因: Redis のメモリ管理","detail":"Redis で used_memory が maxmemory に達している、エビクションが発生している、または断片化率が高い (used_memory_rss >> used_memory)。ポリシーと断片化への対処が必要。","steps":["INFO memory で used_memory、maxmemory、mem_fragmentation_ratio を確認する。","用途に合ったエビクションポリシーを設定する: CONFIG SET maxmemory-policy allkeys-lru (キャッシュ) または noeviction (永続データ)。","TTL を使って期限切れキーを削除し、大きなキー (BIG KEYS) を縮小する。","断片化率が高い場合はアクティブデフラグを有効化する (CONFIG SET activedefrag yes) か、適切なメンテナンスウィンドウで再起動する。"],"related":["show-config-param"],"playbook":"memory-pressure"},"sol_os":{"kind":"solution","title":"根本原因: DB 以外のメモリ消費","detail":"メモリを消費しているのはデータベースではなく、OS 全体または隣接プロセス (別アプリケーション、ファイルシステムキャッシュの圧迫、メモリリークするヘルパープロセス)。","steps":["OS ツール (top / free / タスクマネージャー) で最もメモリを消費しているプロセスを特定する。","原因が DB 以外のプロセスであれば、移設する、制限する (cgroup / job object)、またはメモリリークを修正する。","OOM killer が DB プロセスを強制終了している場合は、OOM 設定を見直し、DB 用のメモリを確保する。","競合が恒常的な場合は、専用メモリを持つ別サーバーに DB を移設する。"],"related":["os-resource"],"playbook":"memory-pressure"}}},"solver/install-setup.json":{"id":"install-setup","title":"新規インストールとセキュアなベースライン","icon":"🛠️","category":"ライフサイクル","intro":"新規インストールしたデータベースを本番向けに準備する際に省略した手順は、最もコストの高い障害につながる。現在の段階を選択すると、初期設定、セキュリティ強化、耐久性、監視の順序付きチェックリストが得られる。","start":"root","nodes":{"root":{"kind":"step","title":"現在どの段階か?","detail":"新規インストールの本番準備には 4 つの段階がある: 初期設定、セキュリティ強化、耐久性 (バックアップ/レプリケーション)、監視。現在どの段階に取り組んでいるか? すべてを順に実施することを推奨する。","command":{"oracle":"SELECT banner_full FROM v$version; SHOW PARAMETER compatible;","postgres":"SELECT version(); SHOW server_encoding; SHOW data_directory;","mysql":"SELECT VERSION(); SHOW VARIABLES LIKE 'character_set_server'; SHOW VARIABLES LIKE 'datadir';","mssql":"SELECT @@VERSION; SELECT SERVERPROPERTY('Collation') AS collation;","mongodb":"db.version(); db.serverStatus().host","redis":"INFO server","elasticsearch":"GET /"},"choices":[{"label":"インストール後の初期設定","next":"firstconfig"},{"label":"セキュリティ強化","next":"sol_security"},{"label":"バックアップと耐久性の設定","next":"durability"},{"label":"監視とアラートの設定","next":"sol_monitoring"}]},"firstconfig":{"kind":"step","title":"初期設定で優先すべきことは?","detail":"初期設定は 2 つの主要テーマに分かれる: リソース/パラメータのサイジング (メモリ、接続数) と恒久的な基盤 (キャラクタセット/照合順序、データディレクトリ/ファイル配置)。これらは後から変更するのが最も難しい決定事項。","command":{"postgres":"SELECT name, setting, unit FROM pg_settings WHERE name IN ('shared_buffers','work_mem','max_connections','wal_level');","oracle":"SHOW PARAMETER sga_target; SHOW PARAMETER pga_aggregate_target; SHOW PARAMETER processes;","mysql":"SHOW VARIABLES LIKE 'innodb_buffer_pool_size'; SHOW VARIABLES LIKE 'max_connections';","mssql":"SELECT name, value_in_use FROM sys.configurations WHERE name IN ('max server memory (MB)','max degree of parallelism');"},"choices":[{"label":"メモリ / パラメータのサイジング","next":"sol_sizing"},{"label":"キャラクタセット、照合順序、ファイル配置","next":"sol_layout"}]},"durability":{"kind":"step","title":"耐久性のどの部分を設定するか?","detail":"耐久性は 2 つの柱で成り立つ: 検証済みのバックアップ戦略 (初回バックアップ + リストアテスト) と継続性 (アーカイブ/ログモード、レプリケーション)。テストせずに「バックアップはある」と言うのが最もよくある誤解。","command":{"postgres":"SHOW archive_mode; SHOW wal_level;","oracle":"ARCHIVE LOG LIST; SELECT log_mode FROM v$database;","mysql":"SHOW VARIABLES LIKE 'log_bin'; SHOW VARIABLES LIKE 'server_id';","mssql":"SELECT name, recovery_model_desc FROM sys.databases;"},"choices":[{"label":"バックアップ戦略 + 初回バックアップ + リストアテスト","next":"sol_backup"},{"label":"アーカイブ/ログモード + レプリケーション","next":"sol_replication"}]},"sol_sizing":{"kind":"solution","title":"初期設定: メモリとパラメータのサイジング","detail":"ほとんどのエンジンでデフォルト値は保守的。サーバーの RAM と CPU に合わせてサイジングするが、オーバーコミットは避ける。","steps":["総 RAM を配分する: OS 用の割り当てを残し、buffer pool/SGA をメインキャッシュとして設定する。","セッションメモリ (work_mem/PGA) は想定同時実行数に基づき控えめに設定し、総 RAM を超えないようにする。","max_connections は実際の必要量に設定し、高い同時実行数にはコネクションプーラーを計画する。","エンジン固有の主要パラメータ (WAL/redo、checkpoint、並列処理) を見直し、変更内容を文書化する。"],"related":["show-config-param","connect-cli"]},"sol_layout":{"kind":"solution","title":"初期設定: キャラクタセット、照合順序、ファイル配置","detail":"キャラクタセット/照合順序とデータディレクトリ配置はインストール時に決まり、後から変更するには通常、再インストールか移行が必要。","steps":["サーバーレベルで Unicode キャラクタセット (例: UTF-8 / AL32UTF8) を選択し、一貫した照合順序を設定する。","データ、ログ/WAL、バックアップの各ディレクトリを別々のディスク/ボリュームに配置し、IO 競合と単一障害点を減らす。","ファイルシステムと権限を強化する: データディレクトリを読めるのは DB ユーザーのみにする。","後から追加するノードが一致するよう、配置とキャラクタセットの決定事項を文書化する。"],"related":["show-config-param","connect-cli"]},"sol_security":{"kind":"solution","title":"セキュリティ強化","detail":"新規インストールには、デフォルトアカウント、緩いネットワークアクセス、開いたポートが含まれる。本番移行前に攻撃対象領域を縮小することは必須。","steps":["デフォルト/サンプルアカウントを削除またはロックし、未使用の管理アカウントを無効化する。","強固なパスワードポリシーを適用し、すべてのデフォルトパスワードを変更する。","最小権限: 各アプリケーションには必要な権限のみを付与し、広範なロールは避ける。","TLS を有効化し、リスナー/ポートを信頼できるネットワークに制限し、監査ログを有効化する。"],"related":["create-user-grant","change-password","enable-audit"]},"sol_backup":{"kind":"solution","title":"耐久性: バックアップ戦略とリストアテスト","detail":"バックアップの価値はリストアできるかどうかで決まる。初回バックアップを取得し、継続性を確保し、必ずリストアテストを実施する。","steps":["復旧目標 (RPO/RTO) を定義し、フル + 増分のバックアップスケジュールを設定する。","初回フルバックアップを取得し、バックアップは DB サーバーとは別の場所に保管する。","別環境にリストアしてバックアップをテストする。整合性が証明されていないバックアップはバックアップとはみなさない。","バックアップジョブをスケジュールし、その出力を監視に連携し、直近のバックアップ状態を定期的に確認する。"],"related":["logical-dump","restore-dump","last-backup-status"]},"sol_replication":{"kind":"solution","title":"耐久性: アーカイブ/ログモードとレプリケーション","detail":"ポイントインタイムリカバリと高可用性のためには、アーカイブ/ログモードを有効化し、少なくとも 1 つのレプリカが必要。","steps":["アーカイブ/ログモードを有効化する (PG archive_mode/wal_level、Oracle ARCHIVELOG、MySQL binlog、MSSQL FULL 復旧モデル)。","少なくとも 1 つのレプリカ (standby/replica) を構築し、初期同期を完了する。","レプリケーション遅延を監視し、遅延アラートを定義する。","制御されたフェイルオーバー/スイッチオーバー訓練を実施してフェイルオーバーを検証する。"],"related":["replication-status","list-replicas"],"playbook":"replication-lag"},"sol_monitoring":{"kind":"solution","title":"監視とアラートの設定","detail":"本番前の最終ステップ: ユーザーより先に問題を把握すること。適切なしきい値でヘルスチェックとアラートを設定する。","steps":["基本的なヘルスチェックを収集する: キャッシュヒット率、アクティブ/待機中のセッション、最も遅いクエリ。","容量アラートを定義する: ディスク使用量、上限に近づく接続数、レプリケーション遅延。","アラートをチャネル (メール/チャット) に送信し、しきい値を実際の負荷に合わせて調整する。","サイレント障害を検出するため、バックアップの成否とエラーログも監視に追加する。"],"related":["cache-hit-ratio","connection-count","free-space"]}}},"solver/corruption-recovery.json":{"id":"corruption-recovery","title":"データ破損からの復旧","icon":"🧯","category":"リカバリ","intro":"データ破損 (ブロック/ページのチェックサムエラー、読み取り不能なテーブル、破損した RDB/AOF) に対する段階的な診断フロー: まず破損範囲を確認し、ブロックレベルのリカバリ、バックアップからの完全リストア/PITR、最終手段の修復ツールのいずれかを正しく選択する。","start":"root","nodes":{"root":{"kind":"step","title":"破損範囲はどの程度か?","detail":"まず整合性チェックを実行し、破損がどこまで広がっているかを判断する。破損しているのは少数のブロック/ページのみか、単一オブジェクト (テーブル/インデックス) が影響を受けているか、それとも破損が広範囲か? 以下のコマンドでスキャンして範囲を判断し、該当する分岐を選択する。","command":{"oracle":"RMAN> BACKUP VALIDATE CHECK LOGICAL DATABASE;  -- then: SELECT file#, block#, blocks, corruption_type FROM v$database_block_corruption;","postgres":"pg_amcheck --all --heapallindexed --progress   # single table: pg_amcheck -d mydb -t app_schema.my_table","mysql":"CHECK TABLE app_schema.my_table EXTENDED;   -- for InnoDB also: SHOW ENGINE INNODB STATUS\\G","mssql":"DBCC CHECKDB (N'mydb') WITH NO_INFOMSGS, ALL_ERRORMSGS;","mongodb":"db.my_table.validate({ full: true })","redis":"redis-check-rdb /var/lib/redis/dump.rdb   # AOF (7+, read-only check): redis-check-aof /var/lib/redis/appendonlydir/appendonly.aof.manifest  (--fix modifies the files; only after taking a copy)","elasticsearch":"GET _cluster/health?level=shards   # for a corrupted shard: GET _cat/shards?v&h=index,shard,state,unassigned.reason"},"choices":[{"label":"少数のブロック / ページのみ破損","next":"block_level"},{"label":"単一オブジェクト (テーブル/インデックス) が影響を受けている","next":"restore"},{"label":"破損が広範囲 / 多数のオブジェクト","next":"restore"},{"label":"チェックツールが動作せず、DB がオープンできない","next":"last_resort"},{"label":"破損が繰り返し発生する (根本原因が疑われる)","next":"hardware"}]},"block_level":{"kind":"solution","title":"根本原因: 限定的なブロック/ページ破損 → 対象を絞ったリカバリ","detail":"破損しているのが少数のブロック/ページのみであれば、データベース全体をリストアする必要はない。エンジンのブロック/ページレベルのリカバリ機能を使い、破損部分のみをバックアップ/ログから修復してデータ損失を最小化する。","steps":["Oracle: v$database_block_corruption で破損ブロックの一覧を確認した後 (一覧が古い場合は先に RMAN> VALIDATE DATABASE; を実行)、単一ブロックは RMAN> RECOVER DATAFILE 5 BLOCK 1234; で、一覧のすべてのブロックは RMAN> RECOVER CORRUPTION LIST; でリカバリする。","SQL Server: 単一ページのリストア — RESTORE DATABASE [db] PAGE='5:1234' FROM DISK='D:\\backup\\db.bak' WITH NORECOVERY;  その後、後続のログバックアップを WITH NORECOVERY で、最後のものを WITH RECOVERY で適用する。","PostgreSQL: ブロックレベルの自動修復はない。影響を受けたテーブルをバックアップから部分的にリストアするか、データ抽出の目的に限り zero_damaged_pages=on を一時的に有効化する (破損した行は失われる)。","MySQL/InnoDB: 単一ページの修復はない。影響を受けたテーブルを最後の正常なバックアップからリストアし、必要に応じて PITR でロールフォワードする。","修復後、チェックコマンド (VALIDATE / DBCC CHECKDB / pg_amcheck) を再実行し、破損が残っていないことを確認する。","リカバリしたブロックの業務データを、アプリケーション側でサンプリングして検証する。"],"related":["restore-dump","last-backup-status"],"playbook":"corruption"},"restore":{"kind":"solution","title":"根本原因: オブジェクトレベル/広範囲の破損 → バックアップからの完全リストアまたは PITR","detail":"破損が 1 つ以上のオブジェクトに広がっている場合、最も安全なのは正常なバックアップからリストアし、可能であれば破損発生時点までロールフォワード (PITR) すること。これにより修復ツールが引き起こすデータ損失を回避できる。","steps":["破損の開始時刻の目安を特定し (alert log / error log)、PITR の目標をその直前に設定できるようにする。","最新の正常なフルバックアップと、その時点までのトランザクションログ (アーカイブログ / WAL / binlog) を確認する。","Oracle: RMAN> RESTORE DATABASE; RECOVER DATABASE UNTIL TIME \"TO_DATE('2026-07-04 09:59:00','YYYY-MM-DD HH24:MI:SS')\"; ALTER DATABASE OPEN RESETLOGS;","SQL Server: RESTORE DATABASE [db] FROM DISK='...' WITH NORECOVERY; RESTORE LOG [db] FROM DISK='...' WITH STOPAT='2026-07-04 09:59:00', RECOVERY;","PostgreSQL: ベースバックアップをリストアし、recovery_target_time='2026-07-04 09:59:00' を設定して、その時点まで WAL を適用する。","MySQL/MariaDB: フルバックアップをリストアし、mysqlbinlog --stop-datetime='2026-07-04 09:59:00' でその時点まで binlog を適用する。","MongoDB: 正常なレプリカ/スナップショットから mongorestore でリストアする。Elasticsearch: 破損したインデックスを POST _snapshot/my_repo/snap1/_restore でリストアする。","オープン後、整合性チェックを再実行し、行数/アプリケーションのチェックでデータを検証する。"],"related":["restore-dump","logical-dump","last-backup-status"],"playbook":"corruption"},"last_resort":{"kind":"step","title":"バックアップなし / DB がオープンできない — 最終手段に進むか?","detail":"修復ツール (REPAIR_ALLOW_DATA_LOSS、innodb_force_recovery、--fix) はデータ損失を引き起こす可能性があり、整合性制約を破壊する場合がある。使用可能なバックアップが存在せず、データベースをオープンできない場合に限る最終手段。まず使用可能なバックアップが本当にないことを確認する。","choices":[{"label":"正常なバックアップが見つかったのでリストアする","next":"restore"},{"label":"バックアップがまったくなく、修復ツールしか選択肢がない","next":"repair"}]},"repair":{"kind":"solution","title":"最終手段: データ損失リスクのある修復ツール","detail":"これらのツールは、破損した行/ページを破棄してデータベースをオープン可能にする。バックアップがなく、既存ファイルのコピーを先に取得した場合にのみ使用する。目的: データをエクスポートできる程度にオープンし、クリーンなコピーへ移行すること。","steps":["まず既存のデータファイルの raw コピーを取得する (試行によって状況が悪化する可能性がある)。","SQL Server: DBCC CHECKDB (N'db', REPAIR_ALLOW_DATA_LOSS) WITH ALL_ERRORMSGS;  (データベースは SINGLE_USER モードである必要がある。このコマンドはデータ損失を引き起こす可能性がある)。","MySQL/InnoDB: my.cnf の [mysqld] に innodb_force_recovery=1 を設定して起動する。オープンできない場合は 2、3... (最大 6) と上げる。オープンできたら直ちに mysqldump でデータをエクスポートし、クリーンなインストール環境にインポートして設定を削除する。","PostgreSQL: 最終手段として、WAL が破損している場合に限り pg_resetwal を使用する (データ損失リスク大)。その後 pg_dump でデータを抽出し、新しいクラスタにロードする。","Oracle: バックアップがない場合、DBMS_REPAIR / イベントベースのリカバリを Oracle Support と検討する。'skip corrupt' でブロックをスキップできる (データ損失あり)。","MongoDB: mongod --repair または WiredTiger salvage でオープンし、データを新しいレプリカセットに移行する。","修復後は必ずクリーンなインストール環境に移行し、整合性チェックを再実行して、失われたデータを報告する。"],"related":["logical-dump","restore-dump"],"playbook":"corruption"},"hardware":{"kind":"solution","title":"根本原因: ハードウェア/インフラ → 発生源を修正し、チェックサムを有効化する","detail":"破損が繰り返し発生する場合、真の原因はディスク、コントローラー、メモリ (RAM)、または不安定なストレージ層である可能性が高い。データをリカバリするだけでは不十分で、発生源を修正しなければ破損は再発する。早期検出のためにチェックサム/整合性検証も有効化する。","steps":["ディスクの健全性を確認する: SMART 値 (smartctl -a /dev/sdX)、RAID コントローラーのログ、ストレージのアラート。","メモリテストを実行する (memtest86+ または ECC エラーカウンタ)。シングルビットエラーは破損の典型的な原因。","OS/ファイルシステムとハードウェアのエラーログ (dmesg、イベントビューアー、ストレージアレイのアラート) を確認する。","PostgreSQL: initdb --data-checksums (または pg_checksums --enable) でチェックサム付きクラスタを作成し、ディスクへの書き込み時に破損を検出できるようにする。","Oracle: DB_BLOCK_CHECKSUM=FULL と DB_BLOCK_CHECKING=FULL でブロック検証を有効化し、DB_LOST_WRITE_PROTECT=TYPICAL を追加する。","SQL Server: データベースが PAGE_VERIFY CHECKSUM を使用していることを確認する (ALTER DATABASE [db] SET PAGE_VERIFY CHECKSUM)。","MySQL/InnoDB: innodb_checksum_algorithm=crc32 と、必要に応じて innodb_doublewrite=ON で部分書き込みから保護する。","発生源を修正した後、最新の正常なバックアップからクリーンなコピーにリストアし、監視を強化する。"],"related":["restore-dump","last-backup-status"],"playbook":"corruption"}}},"solver/failover-drill.json":{"id":"failover-drill","title":"フェイルオーバー訓練 / 計画的なロール移行","icon":"🔀","category":"レプリケーション","intro":"ロール変更の種類 (計画的なスイッチオーバー、緊急フェイルオーバー、本番に影響しない訓練) を判別し、シナリオごとに正しいコマンド手順と検証手順を示す診断フロー。目的: 計画時はデータ損失ゼロ、緊急時は最小限の損失、訓練時はダウンタイムなしで移行できる状態を整えること。","start":"root","nodes":{"root":{"kind":"step","title":"何をしたいか?","detail":"ロール変更の状況を選択する。プライマリが正常な状態で計画的な移行 (メンテナンス/移行) を行うのか、プライマリが実際に停止して緊急移行が必要なのか、それとも本番に触れずに訓練/準備状況の検証を行うのか?","choices":[{"label":"計画的なスイッチオーバー (プライマリは正常)","next":"planned"},{"label":"緊急フェイルオーバー (プライマリが停止)","next":"emergency_check"},{"label":"訓練 / 準備状況テスト (本番には触れない)","next":"drill"}]},"planned":{"kind":"step","title":"計画的な移行 — まず準備はできているか?","detail":"計画的なスイッチオーバーの目標はデータ損失ゼロ。そのため移行前に、レプリカがプライマリに追いついており (遅延 ~0)、正常であることを確認する必要がある。以下のコマンドで遅延を確認し、遅延がゼロに近ければ移行手順に進む。","command":{"oracle":"SELECT thread#, MAX(sequence#) FROM v$archived_log GROUP BY thread#;   -- DG: SELECT name, value FROM v$dataguard_stats WHERE name LIKE '%lag%';","postgres":"SELECT client_addr, state, replay_lag, write_lag FROM pg_stat_replication;","mysql":"SHOW REPLICA STATUS\\G   -- check Seconds_Behind_Source and Replica_SQL_Running","mssql":"SELECT ag.name, drs.synchronization_state_desc, drs.log_send_queue_size, drs.redo_queue_size FROM sys.dm_hadr_database_replica_states drs JOIN sys.availability_groups ag ON ag.group_id = drs.group_id;","mongodb":"rs.printSecondaryReplicationInfo()","redis":"redis-cli INFO replication   # check the difference between master_repl_offset and the slave offset","elasticsearch":"GET _cat/recovery?v&active_only=true"},"choices":[{"label":"遅延はゼロに近く、移行の準備完了","next":"sol_planned"},{"label":"遅延が大きいため、まず同期を待つ","next":"drill"}]},"sol_planned":{"kind":"solution","title":"計画的なスイッチオーバー (データ損失のない制御された移行)","detail":"プライマリとスタンバイが正常かつ同期している間に、制御された方法でロールを入れ替える。順序が重要: 書き込みを停止し、残りの変更がスタンバイに到達したことを確認してからロールを引き渡し、アプリケーションを新しいプライマリにリダイレクトする。","steps":["メンテナンスウィンドウを告知し、アプリケーションの読み取りと書き込みを制御された方法で保留する。","Oracle Data Guard (12c+): SQL> ALTER DATABASE SWITCHOVER TO standby_db VERIFY; の後に SQL> ALTER DATABASE SWITCHOVER TO standby_db;  (Broker の場合: DGMGRL> SWITCHOVER TO 'standby_db'; 11g 以前: COMMIT TO SWITCHOVER TO PHYSICAL STANDBY)。","PostgreSQL: プライマリをクリーンに停止し (pg_ctl stop -m fast)、SELECT pg_promote(); でスタンバイを昇格させた後、pg_rewind で旧プライマリを新しいスタンバイとして再接続する。","SQL Server AG: 同期レプリカ上で ALTER AVAILABILITY GROUP [ag] FAILOVER;  (データ損失のない計画的フェイルオーバー。SYNCHRONOUS_COMMIT が必要)。","MongoDB: rs.stepDown(60) で現在のプライマリを 60 s 間強制的に降格させる。最新のセカンダリが自動的に選出され、プライマリになる。","Redis: 新しいマスター候補で REPLICAOF NO ONE; を実行し、他のノードで REPLICAOF new_master port; を実行する (Sentinel の場合は SENTINEL FAILOVER master_name)。","アプリケーションの接続文字列 / ルーティングを新しいプライマリに向ける (VIP、サービス名、または接続文字列)。","検証: 新しいプライマリが書き込みを受け付け、旧プライマリが遅延 ~0 のスタンバイとしてストリーミングしており、アプリケーションにエラーがないこと。"],"related":["promote-failover","replication-status","list-replicas"],"playbook":"replication-lag"},"emergency_check":{"kind":"step","title":"緊急移行 — プライマリは本当に停止しているか?","detail":"フェイルオーバーを強制する前に、プライマリが本当に到達不能であることを確認し、スプリットブレインのリスクを評価する。プライマリが実際には稼働している場合 (例: 一時的なネットワーク障害)、強制移行により書き込み可能なコピーが 2 つ生じる (スプリットブレイン)。最新のスタンバイを選ぶため、遅延も比較する。","command":{"oracle":"-- try to reach the primary: tnsping primary_db; and on the standby: SELECT thread#, MAX(sequence#) FROM v$archived_log GROUP BY thread#;","postgres":"SELECT pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn();   -- choose the highest LSN among the standbys","mysql":"SHOW REPLICA STATUS\\G   -- choose the candidate with the largest Exec_Source_Log_Pos","mssql":"SELECT drs.replica_id, drs.last_hardened_lsn FROM sys.dm_hadr_database_replica_states drs;","mongodb":"rs.status()   -- the member with the highest optime is the primary candidate","redis":"redis-cli INFO replication   # choose the one with the highest slave_repl_offset","elasticsearch":"GET _cat/nodes?v   # verify whether the master node is reachable"},"choices":[{"label":"はい、プライマリは停止している — 移行を強制する","next":"emergency"},{"label":"確信がない / プライマリが復帰する可能性がある","next":"planned"}]},"emergency":{"kind":"solution","title":"緊急フェイルオーバー (プライマリが停止、データ損失リスクを伴う移行)","detail":"プライマリが到達不能で、復帰を待てない。スタンバイを強制昇格させる必要があり、非同期レプリケーションでは直近のトランザクションの一部が失われる可能性がある。優先すべきはサービスの復旧であり、その後に損失範囲を特定し、旧プライマリを安全に復帰させる。","steps":["プライマリが本当に停止していることを確認する (スプリットブレインを防ぐため、旧プライマリをネットワークから隔離 / 停止する — フェンシング/STONITH)。","最新のスタンバイを選択する: 実行前に遅延/オフセットを比較し、データ損失が最も少ないものを昇格させる。","Oracle Data Guard: DGMGRL> FAILOVER TO 'standby_db';  (または SQL> ALTER DATABASE ACTIVATE STANDBY DATABASE;)。","PostgreSQL: SELECT pg_promote();; でスタンバイを直ちに昇格させる。旧プライマリが復帰した場合、pg_rewind を実行せずにプライマリとして OPEN しないこと (スプリットブレインのリスク)。","SQL Server AG: ALTER AVAILABILITY GROUP [ag] FORCE_FAILOVER_ALLOW_DATA_LOSS;  (非同期レプリカではデータ損失の可能性がある)。","MongoDB: 過半数が残っていない場合、rs.reconfig(cfg, {force:true}) で残存メンバーを再構成する。","Redis: Sentinel がない場合、新しいマスター候補で REPLICAOF NO ONE を実行し、他のノードをそれに接続する。旧マスターが自動的に再参加しないようにする。","アプリケーションを新しいプライマリにリダイレクトする。その後、失われたデータの範囲 (失われたトランザクション) を特定して報告し、旧プライマリを新しいスタンバイとしてクリーンに再構築する。"],"related":["promote-failover","replication-status","list-replicas"],"playbook":"db-down"},"drill":{"kind":"solution","title":"訓練 / 準備状況テスト (本番に触れずに検証)","detail":"実際の移行を行わずに、フェイルオーバーの準備ができていることを証明する。本番に影響を与えずに、レプリカの健全性、遅延が許容範囲内であること、アプリケーションをリダイレクトできることを検証する。必要に応じて、隔離したコピー上で実際のスイッチオーバーをリハーサルする。","steps":["遅延を測定し、しきい値を下回っていることを確認する (PG: pg_stat_replication.replay_lag、MySQL: Seconds_Behind_Source、Oracle: v$dataguard_stats、Mongo: rs.printSecondaryReplicationInfo())。","レプリカの健全性を確認する: すべてのスタンバイがストリーミング中で、想定どおりのメンバーで同期モードが有効になっていること (SQL Server: synchronization_state_desc='SYNCHRONIZED')。","読み取り/ロールのテスト: スタンバイで読み取り専用クエリを実行し、遅延なく応答が返ることを確認する (PG hot standby、Oracle Active Data Guard、リードレプリカ)。","アプリケーションのルーティングのリハーサル: テスト環境で接続文字列/サービス名を新しいプライマリに向け、アプリケーションが問題なく接続できることを確認する (本番トラフィックには触れない)。","隔離したコピー上で実際のスイッチオーバーをエンドツーエンドでリハーサルし、移行時間 (RTO) を測定する。","フェイルバック手順もリハーサルする: pg_rewind / DG reinstate / AG resume による旧プライマリの再構築。","所見、所要時間、不足点を記録し、Runbook を更新して、訓練を定期的にスケジュールする。"],"related":["replication-status","list-replicas","promote-failover"],"playbook":"replication-lag"}}},"solver/security-incident.json":{"id":"security-incident","title":"セキュリティインシデント / 不審なアクセス","icon":"🚨","category":"セキュリティ","intro":"不審なアクセス、予期しない権限変更、データ漏洩の可能性に対し、症状に応じて適切な対応手順 (アカウントのロック、過剰な権限の取り消し、接続の切断、影響範囲の特定) とインシデント後の恒久的な強化策に導く診断フロー。","start":"root","nodes":{"root":{"kind":"step","title":"何に気付いたか?","detail":"インシデントの種類を選択する。症状は不審なログインまたはログイン失敗の急増か、予期しない権限 (GRANT/ロール) 変更か、データ漏洩 / 異常なエクスポートの可能性か、それともインシデントは収束しており恒久的な強化を行うのか? 最初の観察に基づき、最も適切な分岐を選択する。まず、インシデントの発生時刻と影響を受けたアカウント/リソースを記録する。","choices":[{"label":"不審なログイン / ログイン失敗の急増","next":"identity"},{"label":"予期しない権限 (GRANT/ロール) 変更","next":"privilege"},{"label":"データ漏洩 / 異常なエクスポート","next":"data"},{"label":"インシデント後の恒久的な対策 (強化)","next":"harden"}]},"identity":{"kind":"step","title":"認証インシデント: どの症状か?","detail":"大量のログイン失敗は、ブルートフォース / クレデンシャルスタッフィング攻撃を示す。一方、成功したものの予期しないログイン (通常と異なる IP/時間帯) は、アカウントが侵害された可能性を示す。いずれの場合も、まず証拠を収集してから対応する。","command":{"oracle":"SELECT username, os_username, userhost, timestamp, returncode FROM dba_audit_session WHERE returncode <> 0 ORDER BY timestamp DESC;","postgres":"-- failed logins in the log file: grep 'password authentication failed' postgresql.log | awk '{print $NF}' | sort | uniq -c | sort -rn","mysql":"SELECT * FROM performance_schema.host_cache ORDER BY COUNT_AUTHENTICATION_ERRORS DESC;   -- also 'Access denied' in the error log","mssql":"-- failed logins in the error log: EXEC xp_readerrorlog 0,1,N'Login failed';  also SELECT login_name, COUNT(*) FROM sys.dm_exec_sessions GROUP BY login_name;","mongodb":"-- audit log: grep 'authenticate' audit.json | grep '\"result\":18'  (18 = AuthenticationFailed)","redis":"ACL LOG   # shows failed authentication/command attempts","elasticsearch":"GET .security-audit-*/_search { \"query\": { \"match\": { \"event.action\": \"authentication_failed\" } } }"},"choices":[{"label":"ログイン失敗の急増 (ブルートフォース)","next":"id_bruteforce"},{"label":"成功したが予期しないログイン (侵害)","next":"id_compromised"}]},"id_bruteforce":{"kind":"solution","title":"ブルートフォース → 発信元をブロックし、アカウントを保護する","detail":"ログイン失敗が急増している段階では、まだアクセスを許していない可能性がある。目的は、発信元をブロックし、ロックアウト/遅延でアカウントを保護し、侵入の成功がないことを確認すること。","steps":["攻撃元の IP を特定し (上記のクエリ)、ネットワークレベルでブロックする: ファイアウォール / pg_hba.conf reject / listener ACL / セキュリティグループ。","標的となったアカウントを一時的にロックする: Oracle: ALTER USER target_user ACCOUNT LOCK;  PostgreSQL: ALTER ROLE target_user NOLOGIN;  SQL Server: ALTER LOGIN [target_user] DISABLE;  MySQL: ALTER USER 'target_user'@'%' ACCOUNT LOCK;  Redis: ACL SETUSER target_user off。","ログイン試行回数の制限 / ロックアウトポリシーを適用する: Oracle: プロファイルの FAILED_LOGIN_ATTEMPTS、PostgreSQL: auth_delay モジュール (shared_preload_libraries。ロックアウトではなく失敗した試行を遅延させる)、MySQL: FAILED_LOGIN_ATTEMPTS ... PASSWORD_LOCK_TIME。","念のため、標的となったアカウントのパスワードを強固な値にリセットする (試行が成功している可能性がある)。","試行が成功したかどうかを確認する: 同じ IP からのログイン成功がないか確認し、あれば侵害の分岐にも従う。","タイムラインとともにインシデントを記録し、恒久的な対策として強化ステップ (ルートの「インシデント後の恒久的な対策」) に従う。"],"related":["change-password","list-users"],"playbook":"harden-sql"},"id_compromised":{"kind":"solution","title":"侵害されたアカウント → 停止、調査、認証情報のローテーション","detail":"予期しないログイン成功は、アカウントが侵害されたことを示す。まずアカウントとそのセッションを停止し、何を行ったかを調査してから、パスワードをリセットしてアクセス元を絞り込む。","steps":["アカウントを直ちにロックし (上記の LOCK/DISABLE コマンド)、アクティブなセッションを終了する: Oracle: ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;  PostgreSQL: SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE usename='app_user';  SQL Server: KILL <spid>;  MySQL: KILL <id>;  Redis: CLIENT KILL。","アカウントがセッション内で行ったことを調査する: 監査証跡/ログ内の実行クエリ、アクセスしたテーブル、GRANT/CREATE 操作。","パスワードを強固な値にリセットし、関連するすべてのサービス/アプリケーションの認証情報をローテーションする。","攻撃者が作成した可能性のある新規アカウントや権限変更を探す (権限の分岐にも従う)。","アクセス元を絞り込む: 既知の IP からのみアカウントが接続できるようにする (pg_hba.conf / listener ACL / ファイアウォール)。","恒久的な対策として強化ステップ (ルートの「インシデント後の恒久的な対策」) に従う。"],"related":["change-password","list-users","show-privileges"],"playbook":"harden-sql"},"privilege":{"kind":"solution","title":"権限昇格 → 監査し、過剰な権限を取り消す","detail":"予期しない GRANT、ロール割り当て、高権限の新規アカウントは、侵害の第 2 段階 (永続化/権限昇格) である可能性がある。最近の権限変更を監査し、正当でないものを取り消して、最小権限の原則に戻す。","steps":["最近の権限変更を監査する: Oracle: SELECT * FROM dba_audit_trail WHERE action_name IN ('GRANT','REVOKE','CREATE USER') ORDER BY timestamp DESC;  SQL Server: default trace / Server Audit 内の GRANT イベントと SELECT * FROM sys.server_permissions;  MySQL: 監査ログ内の GRANT エントリと SELECT * FROM mysql.user;  MongoDB: db.getRoles({showPrivileges:true})。","現在の権限を一覧表示する: Oracle: SELECT grantee, privilege FROM dba_sys_privs WHERE grantee='APP_USER';  PostgreSQL: SELECT * FROM information_schema.role_table_grants WHERE grantee='app_user';  MySQL: SHOW GRANTS FOR 'app_user'@'%';","正当でない過剰な権限を取り消す: Oracle: REVOKE DBA FROM app_user;  PostgreSQL: REVOKE ALL ON ... FROM app_user; ALTER ROLE app_user NOSUPERUSER;  SQL Server: ALTER SERVER ROLE [sysadmin] DROP MEMBER [app_user];  MySQL: REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'app_user'@'%';","攻撃者が作成した可能性のある隠し/予備アカウントを探して削除する (予期しない CREATE USER の記録)。","PUBLIC や広範なロールに付与された過剰な権限を見直し、絞り込む。","変更が正当な変更要求と一致していることを確認する。一致しないものはすべてインシデントの一部として扱い、強化ステップに従う。"],"related":["show-privileges","list-users","create-user-grant"],"playbook":"harden-sql"},"data":{"kind":"solution","title":"データ漏洩 → アクセスを遮断し、影響範囲を特定する","detail":"異常に大きなクエリ/エクスポートや予期しない外部接続は、データ漏洩を示す。まずアクティブな危険な接続を切断し、監査証跡/ログで影響範囲 (どのデータに、誰が、いつアクセスしたか) を特定する。","steps":["アクティブな接続元を確認する: PostgreSQL: SELECT pid, usename, client_addr, state, query FROM pg_stat_activity WHERE client_addr IS NOT NULL;  Oracle: SELECT sid, serial#, username, machine, program FROM v$session;  SQL Server: SELECT * FROM sys.dm_exec_connections;  MongoDB: db.currentOp(true);  Redis: CLIENT LIST。","不審な/外部の接続を直ちに切断し、そのアカウントをロックする (KILL/LOCK コマンド)。","ネットワークレベルで発信元をブロックする: ファイアウォール / pg_hba.conf / listener ACL で不審な IP ブロックを遮断する。","監査ログを確認する: どのテーブルが SELECT/EXPORT されたか、行数、時間帯を特定する (Oracle unified_audit_trail、SQL Server sys.fn_get_audit_file、PostgreSQL pgaudit ログ、MongoDB auditLog)。","エクスポートの痕跡を探す: 大きな結果セット、COPY / SELECT ... INTO OUTFILE、mongoexport、一括読み取りパターン。","影響を受けたデータの範囲 (どのテーブル、どの個人/機密フィールド) と想定されるデータ量を文書化し、法的義務/通知義務を評価して、強化ステップに従う。"],"related":["show-privileges","list-users"],"playbook":"harden-sql"},"harden":{"kind":"solution","title":"インシデント後の恒久的な強化","detail":"緊急対応の後、再発防止のために恒久的な管理策を適用する: 監査の有効化、最小権限の徹底、ネットワークアクセスの制限、インシデントの完全な記録。","steps":["監査を有効化する: 重要なイベント (ログイン、GRANT/REVOKE、機密テーブルへのアクセス) を監査証跡に記録する。詳細は「監査の設定」ツリーに従う。","最小権限: 各アカウントには必要な権限のみを付与し、共有/サービスアカウントを分離し、未使用のアカウントを無効化する。","パスワード/認証ポリシー: 強固なパスワード、定期的なローテーション、可能な場合は多要素認証、集中型の ID 管理 (LDAP/Kerberos)。","ネットワーク制限: データベースはアプリケーションサーバーにのみ公開し (ファイアウォール、セキュリティグループ、pg_hba.conf、listener ACL)、インターネットからの直接アクセスをブロックする。","暗号化: 通信経路では TLS を有効化し、必要に応じて保存データの暗号化を有効化する。","監視/アラート: ログイン失敗の急増、新規 GRANT、異常なデータ量に対するアラートを設定する。","インシデント記録: タイムライン、影響を受けた資産、実施した対応、得られた教訓を報告し、Runbook を更新する。"],"related":["list-users","show-privileges","change-password"]}}},"solver/audit-setup.json":{"id":"audit-setup","title":"監査の設定","icon":"🧾","category":"セキュリティ","intro":"監査したい対象 (ログイン/セッション、DDL/スキーマ変更、データアクセス、権限変更) に応じて、適切なデータベースエンジンでその範囲の監査を有効化し、記録の読み取りと保持/ローテーションの手順を示す診断フロー。","start":"root","nodes":{"root":{"kind":"step","title":"何を監査したいか?","detail":"監査範囲を選択する。すべてを監査するとノイズとコストが増えるため、必要な範囲に絞り込む。ログイン/セッションイベント、DDL/スキーマ変更、データアクセス (DML/SELECT)、権限変更 (GRANT/REVOKE) のどれを追跡したいか?","choices":[{"label":"ログイン / セッション (login、connect)","next":"login"},{"label":"DDL / スキーマ変更 (CREATE/ALTER/DROP)","next":"ddl"},{"label":"データアクセス (DML / SELECT)","next":"dml"},{"label":"権限変更 (GRANT / REVOKE)","next":"grants"},{"label":"監査記録の読み取りと保持 / ローテーション","next":"retention"}]},"login":{"kind":"solution","title":"ログイン / セッションの監査","detail":"成功および失敗したログイン (誰が、どこから、いつ接続したか) を記録する。不正アクセスやブルートフォース試行を検出するための基盤。エンジンごとに該当するポリシーを有効化し、記録を読み取って保持する。","steps":["Oracle (Unified Auditing): CREATE AUDIT POLICY login_pol ACTIONS LOGON, LOGOFF;  AUDIT POLICY login_pol;  (失敗の場合: AUDIT POLICY login_pol WHENEVER NOT SUCCESSFUL;)。","PostgreSQL: postgresql.conf で log_connections=on と log_disconnections=on を設定してリロードする。pgaudit なしで接続がログに記録される。","MySQL/MariaDB: audit_log プラグインをインストールし (INSTALL PLUGIN audit_log ...)、SET GLOBAL audit_log_policy='LOGINS'; を実行する (MariaDB: server_audit_events='CONNECT')。","SQL Server: Server Audit を作成し (CREATE SERVER AUDIT ...)、Server Audit Specification に FAILED_LOGIN_GROUP と SUCCESSFUL_LOGIN_GROUP を追加して、両方を ENABLE する。","MongoDB: --auditDestination file --auditFilter '{ atype: { $in: [\"authenticate\", \"logout\"] } }' で起動する (Enterprise/Percona)。","Redis: ACL LOG で認証/コマンドの失敗試行を追跡する (詳細には 'notify' ではなく ACL ログを使用する)。","Elasticsearch: elasticsearch.yml で xpack.security.audit.enabled: true を設定し、include リストに authentication_success、authentication_failed を追加する。","記録の読み取りと保持/ローテーションについては、ルートの「監査記録の読み取りと保持 / ローテーション」ステップに従う。"],"related":["list-users","change-password"]},"ddl":{"kind":"solution","title":"DDL / スキーマ変更の監査","detail":"CREATE/ALTER/DROP などのスキーマ変更を記録する。不正なオブジェクト変更、隠しテーブル/バックドア、スキーマドリフトの検出に使用する。","steps":["Oracle: CREATE AUDIT POLICY ddl_pol ACTIONS CREATE TABLE, ALTER TABLE, DROP TABLE, CREATE USER, ALTER USER;  AUDIT POLICY ddl_pol;","PostgreSQL (pgaudit): shared_preload_libraries='pgaudit' でロードし、ALTER SYSTEM SET pgaudit.log='ddl'; SELECT pg_reload_conf(); を実行する。","MySQL/MariaDB: audit_log で SET GLOBAL audit_log_policy='ALL'; を実行し、ログ内の DDL 文をフィルタリングする (MariaDB: server_audit_events='QUERY_DDL')。","SQL Server: Database Audit Specification に SCHEMA_OBJECT_CHANGE_GROUP (および DATABASE_OBJECT_CHANGE_GROUP) を追加して ENABLE する。","MongoDB: --auditFilter '{ atype: { $in: [\"createCollection\",\"dropCollection\",\"createIndex\",\"dropIndex\",\"createDatabase\",\"dropDatabase\"] } }'。","Elasticsearch: index_creation/index_deletion 関連のイベントを監査の include リストに追加する。スキーマ (mapping) 変更については、_mapping 呼び出しをリクエストとしてログに記録する。","記録の読み取りと保持/ローテーションについては、ルートの「監査記録の読み取りと保持 / ローテーション」ステップに従う。"],"related":["show-privileges"]},"dml":{"kind":"solution","title":"データアクセス (DML / SELECT) の監査","detail":"機密テーブルへの読み取り/書き込みアクセス (SELECT/INSERT/UPDATE/DELETE) を記録する。大量のログが発生する可能性があるため、監査対象は機密オブジェクトに限定する。漏洩検出とコンプライアンス (KVKK/GDPR) に不可欠。","steps":["範囲を絞り込む: すべてのデータではなく、機密テーブル/列のみを監査する (ノイズとコストを抑えるため)。","Oracle: CREATE AUDIT POLICY dml_pol ACTIONS SELECT, INSERT, UPDATE, DELETE ON HR.SALARIES;  AUDIT POLICY dml_pol;","PostgreSQL (pgaudit): 広範なログ記録には ALTER SYSTEM SET pgaudit.log='read,write'; を使用する。対象を絞ったオブジェクトレベルの監査では、該当テーブルにのみ監査ロールの権限を付与し、pgaudit.role を設定する。","MySQL/MariaDB: audit_log フィルタ (audit_log_filter / MariaDB server_audit_events='QUERY_DML') で該当するテーブル/ユーザーのみをログに記録する。","SQL Server: Database Audit Specification に特定テーブルとプリンシパル (例: public) に対する SELECT、INSERT、UPDATE、DELETE アクションを追加して ENABLE する。","MongoDB: --auditFilter '{ atype: \"authCheck\", \"param.command\": { $in: [\"find\",\"insert\",\"update\",\"delete\"] }, \"param.ns\": \"db.sensitive\" }' (ログ量に注意)。","Elasticsearch: 監査の include リストに access_granted/access_denied を追加し、emit_request_body を使用してクエリの対象インデックスを確認する (機密データの場合、ボディのログ記録には注意する)。","記録の読み取りと保持/ローテーションについては、ルートの「監査記録の読み取りと保持 / ローテーション」ステップに従う。"],"related":["show-privileges","list-users"]},"grants":{"kind":"solution","title":"権限変更 (GRANT / REVOKE) の監査","detail":"権限とロールの変更 (GRANT/REVOKE、ロール割り当て、ユーザー作成) を記録する。権限昇格とバックドアアカウントを検出するための基盤であり、通常はログ量が少なく価値の高い監査。","steps":["Oracle: CREATE AUDIT POLICY priv_pol ACTIONS GRANT, REVOKE, CREATE USER, ALTER USER, CREATE ROLE;  AUDIT POLICY priv_pol;","PostgreSQL (pgaudit): ALTER SYSTEM SET pgaudit.log='role'; SELECT pg_reload_conf();  (GRANT/REVOKE/CREATE ROLE イベントを記録する)。","MySQL/MariaDB: audit_log (ポリシー 'ALL' または DDL) で GRANT/REVOKE/CREATE USER 文をログに記録し、フィルタで ACL 文を残す。","SQL Server: Server Audit Specification に SERVER_PERMISSION_CHANGE_GROUP、SERVER_ROLE_MEMBER_CHANGE_GROUP、DATABASE_PERMISSION_CHANGE_GROUP を追加して ENABLE する。","MongoDB: --auditFilter '{ atype: { $in: [\"grantRolesToUser\",\"revokeRolesFromUser\",\"createUser\",\"dropUser\",\"createRole\"] } }'。","Elasticsearch: ロール/ユーザーの変更については、セキュリティ関連のリクエストイベント (realm/role API 呼び出し) を監査証跡に記録する。","記録の読み取りと保持/ローテーションについては、ルートの「監査記録の読み取りと保持 / ローテーション」ステップに従う。"],"related":["show-privileges","create-user-grant","list-users"]},"retention":{"kind":"solution","title":"監査記録の読み取りと保持 / ローテーション","detail":"監査は、記録が読まれ保持されて初めて役に立つ。ここでは、記録の照会方法、保管場所、および記録の増大を抑える保持/ローテーションポリシーを定義する。","steps":["記録を読み取る: Oracle: SELECT event_timestamp, dbusername, action_name, object_name, sql_text FROM unified_audit_trail ORDER BY event_timestamp DESC;  PostgreSQL: pgaudit の出力はサーバーログファイル (log_directory) に書き込まれる。grep で 'AUDIT:' 行をフィルタリングする。","SQL Server: SELECT * FROM sys.fn_get_audit_file('D:\\audit\\*.sqlaudit', DEFAULT, DEFAULT);  MySQL: audit_log ファイル (JSON/XML) または MariaDB の server_audit.log を読み取る。MongoDB: audit.json を解析する。Elasticsearch: .security-audit-* インデックスを照会する。","保持期間を設定し (コンプライアンス要件に従う。例: 90 日 / 1 年)、ポリシーに明記する。","ローテーション/クリーンアップ: Oracle: DBMS_AUDIT_MGMT.SET_LAST_ARCHIVE_TIMESTAMP と CLEAN_AUDIT_TRAIL で古い記録をアーカイブ/パージする。PostgreSQL/MySQL/MongoDB のファイルログは logrotate でサイズ/時間ごとにローテーションする。","Elasticsearch: 監査インデックス用に ILM ポリシー (rollover + delete) を定義する。","監査記録は、DBA とは別のアクセス権を持つ改ざん不可 (WORM) の場所に送信し (職務分掌)、アクセスを制限する。","ストレージの増加を監視する: 監査がディスクを圧迫したり、パフォーマンスに過度な影響を与えたりしていないかを定期的に確認する。"],"related":["list-users","show-privileges"]}}},"solver/decide-ha.json":{"id":"decide-ha","title":"判断: どの HA/DR ソリューションか?","icon":"🧭","category":"判断ガイド","intro":"高可用性と災害復旧のソリューション選定は、技術ではなく、業務要件 (RTO/RPO)、地理的分散の必要性、コストのバランスから始まる。このツリーは、ダウンタイムとデータ損失の許容度を起点に、同期レプリカ、非同期スタンバイ、自動フェイルオーバークラスタ、バックアップ+PITR の中から適切なアプローチを示す。","start":"root","nodes":{"root":{"kind":"step","title":"データ損失の許容度 (RPO) は?","detail":"最も厳しい制約から始める: 災害時に何秒分のデータを失っても許容できるか? データ損失ゼロ (RPO=0) が必須なら同期レプリケーションが必須。数秒/数分が許容できるなら、非同期ソリューションやより安価なアプローチが選択肢になる。通常、RPO 目標が他のすべての判断を左右する。","choices":[{"label":"データ損失ゼロが必須 (RPO = 0)","next":"rpo_zero"},{"label":"数秒/数分のデータ損失は許容できる","next":"rpo_soft"}]},"rpo_zero":{"kind":"step","title":"自動かつ高速な引き継ぎ (低 RTO) も必要か?","detail":"データ損失ゼロを求めているが、プライマリがダウンしたときにどれだけ早く復旧する必要があるか? 数秒以内の自動フェイルオーバーか、それとも短い手動介入の時間は許容できるか? これにより、単純な同期レプリカと完全自動化されたクラスタのどちらにするかが決まる。","choices":[{"label":"数秒以内の自動フェイルオーバーが必要","next":"sol_cluster"},{"label":"手動/計画的な引き継ぎで十分。損失ゼロが最優先","next":"sol_sync"}]},"rpo_soft":{"kind":"step","title":"別リージョン/別地域 (DR) が必要か?","detail":"ある程度のデータ損失が許容できるなら、本当の問題は耐障害性の範囲: データセンター/リージョン全体の喪失に備える必要があるか、それとも同一リージョン内の単一ノード障害への備えで十分か? 地理的分散が必要なら非同期スタンバイが有力になり、不要ならコスト優先の選択肢を検討する。","choices":[{"label":"はい、地理的災害に備えて別リージョンが必須","next":"sol_async"},{"label":"いいえ、予算とシンプルさが最優先","next":"budget"}]},"budget":{"kind":"step","title":"長い復旧時間 (高 RTO) を許容できるか?","detail":"単一リージョン内にとどまり、ある程度のデータ損失を許容する。最低コストを目指すのか、それとも障害時に迅速に引き継ぐスタンバイノードが欲しいのか? 復旧に数時間かかっても許容できるなら、バックアップ+PITR のみが最も経済的。そうでなければウォームスタンバイが必要。","choices":[{"label":"はい、復旧に数時間かかっても許容できる (最安)","next":"sol_backup"},{"label":"いいえ、数分以内に引き継ぐウォームスタンバイが必要","next":"sol_async"}]},"sol_sync":{"kind":"solution","title":"推奨: 同期レプリカ (データ損失ゼロ)","detail":"プライマリは、少なくとも 1 つのスタンバイが確認応答するまでコミットを完了しない。そのため、プライマリを失っても確認応答済みのトランザクションは失われない (RPO=0)。低レイテンシネットワーク上の単一リージョン内での理想的なソリューション。","steps":["理由: 確認応答済みのトランザクションがスタンバイに書き込まれるまでコミットが完了しないため、データ損失は理論上ゼロ。","適用場面: 金融/重要な OLTP、同一リージョン (同一/隣接のアベイラビリティゾーン)、低 RTT のネットワークが利用可能な場合。","例: PostgreSQL synchronous_commit + synchronous_standby_names、MySQL Group Replication / semisync、Oracle Data Guard SYNC (Maximum Protection/Availability)。","注意: 同期の確認応答はすべてのコミットにネットワークレイテンシを加える。スタンバイが遅延/切断し、同期コピーが 1 つしかない場合、プライマリも書き込みを受け付けなくなる可能性がある。少なくとも 2 つのスタンバイ、または適切なフォールバックを前提に設計する。","注意: 遠隔/高レイテンシのリージョンへ同期レプリケーションしないこと。書き込みパフォーマンスが著しく低下する。地理的 DR には非同期レプリケーションを使用する。"],"related":["replication-status","promote-failover"]},"sol_async":{"kind":"solution","title":"推奨: 非同期スタンバイ (地理的 DR)","detail":"スタンバイは、プライマリのコミットを遅延させることなく、変更をストリームとして適用する。書き込みパフォーマンスを損なわずに別リージョンにコピーを保持する標準的な方法であり、その代わりに小さなデータ損失ウィンドウ (レプリケーション遅延分) を許容する。","steps":["理由: プライマリはスタンバイの確認応答を待たないため、遠隔リージョンへのレプリケーションが書き込みレイテンシを増やさない。","適用場面: リージョン/データセンターレベルの災害復旧が必要で、秒単位のデータ損失が許容できる場合。","例: PostgreSQL ストリーミングレプリケーション (async)、MySQL 非同期レプリケーション、Oracle Data Guard ASYNC (Maximum Performance)。","注意: フェイルオーバー時には遅延分のデータを失う可能性がある。レプリケーション遅延を継続的に監視し、しきい値アラートを設定する。","注意: 引き継ぎは通常、手動または外部のオーケストレーションで行う。明確なフェイルオーバー手順と定期的な訓練が不可欠。"],"related":["replication-status","promote-failover"]},"sol_cluster":{"kind":"solution","title":"推奨: 自動フェイルオーバークラスタ","detail":"ヘルスモニタリング、リーダー選出、自動引き継ぎを組み合わせたクラスタソリューション。低 RTO (数秒以内の自動フェイルオーバー) と、同期コピーによる低/ゼロ RPO の両方を目指す。運用負荷は高くなるが、人手による介入は最小化される。","steps":["理由: クラスタマネージャーがプライマリの障害を自動検出し、正常なコピーを昇格させてトラフィックをリダイレクトする。深夜の手動介入は不要。","適用場面: 低 RTO と低 RPO の両方が必須で、運用チームが追加の複雑さを管理できる場合。","例: PostgreSQL 向け Patroni/etcd、MySQL InnoDB Cluster (Group Replication + MySQL Router)、SQL Server Always On 可用性グループ、Oracle RAC + Data Guard の Fast-Start Failover (自動フェイルオーバーには FSFO とオブザーバーが必要)。","注意: スプリットブレインのリスクは現実的。適切なフェンシング/クォーラム (奇数のノード、信頼性の高い分散ストア) なしにデプロイしないこと。","注意: クラスタ自体が新たな障害要因となる。フェイルオーバーを定期的にリハーサルし、実際の条件下で自動化を検証する。"],"related":["promote-failover","replication-status"]},"sol_backup":{"kind":"solution","title":"推奨: バックアップ + PITR (最も経済的)","detail":"稼働中のスタンバイの代わりに、定期的なバックアップと、WAL/アーカイブログによるポイントインタイムリカバリ (PITR) のみを保持する。最もコストの低いソリューションであり、その代償として復旧に数時間かかる場合がある (高 RTO)。","steps":["理由: 常時稼働する 2 台目のノードのコストがかからない。保持するのはバックアップストレージとアーカイブログのみ。","適用場面: ダウンタイム許容度の高い非重要システム、開発/テスト環境、予算とシンプルさが最優先の場合。","例: 物理バックアップ + アーカイブログによる PITR (PG ベースバックアップ + WAL、Oracle RMAN + archivelog、MySQL xtrabackup + binlog)。","注意: RTO は高い — リストア + ログ適用時間はデータサイズに応じて増加する。測定して、許容できる時間内に収まることを確認する。","注意: テストされていないバックアップはバックアップではない。リストア訓練とバックアップ検証を定期的に実施する。"],"related":["last-backup-status","logical-dump"]}}},"solver/decide-isolation.json":{"id":"decide-isolation","title":"判断: どの分離レベルか?","icon":"🧭","category":"判断ガイド","intro":"トランザクション分離レベルは、同時実行性と一貫性のバランスを決定する。分離レベルが高いほど異常は減るが、ロック/競合とリトライが増える。このツリーは、許容できる読み取り異常 (ダーティ、反復不能、ファントム) に基づき、Read Committed、Repeatable Read/Snapshot、Serializable の中から選択するのに役立つ。","start":"root","nodes":{"root":{"kind":"step","title":"ダーティリードを許容できるか?","detail":"最も基本的な異常から始める: トランザクションが、まだコミットされていない (ロールバックされる可能性がある) データを読めてよいか? まともなアプリケーションでこれを望むものはほとんどなく、最新のエンジンの多くはデフォルトでダーティリードを防止する。緩和するのは、概算/分析用の大まかなカウントと最大速度が必要な場合のみ。","choices":[{"label":"いいえ、コミット済みのデータのみを読む必要がある","next":"committed"},{"label":"はい、大まかな/概算の読み取りで十分 (まれ)","next":"sol_read_uncommitted"}]},"committed":{"kind":"step","title":"同じトランザクション内で再読み取りしたときに同じ結果が必要か?","detail":"ダーティリードを除外した次の質問: トランザクション内で同じ行を 2 回読んだとき、間に誰かがコミットしたために異なる値が見える (反復不能読み取り) こと、または新しい行が現れる (ファントム) ことは問題か? レポート/計算の一貫性が必要なロジックには、通常、一貫したスナップショットが必要。","choices":[{"label":"いいえ、各文が最新のコミット済みデータを参照すればよい","next":"sol_read_committed"},{"label":"はい、トランザクション全体で一貫したスナップショットが必要","next":"consistent"}]},"consistent":{"kind":"step","title":"同時実行トランザクションは論理的に完全に順序付けられる必要があるか?","detail":"一貫した読み取りを求めているが、それで十分か、それとも同時実行トランザクションが 1 つずつ順番に実行されたかのような結果 (serializable) を生む必要があるか? write skew のような微妙な異常 (例: 2 つのトランザクションが異なる行を読み、互いを無効にする形で書き込む) を許容できるなら Snapshot で十分。そうでなければ完全な直列化が必要。","choices":[{"label":"いいえ、一貫したスナップショットで十分","next":"sol_repeatable_read"},{"label":"はい、同時実行の異常は一切許容できない","next":"sol_serializable"}]},"sol_read_uncommitted":{"kind":"solution","title":"推奨: Read Uncommitted (特殊なケースのみ)","detail":"最も低い分離レベルで、ダーティリードを許容する。ロック待機がほぼない状態で読み取れるが、ロールバックされ得るデータが見える可能性がある。汎用アプリケーションには推奨しない。","steps":["理由: 読み取り側が書き込み側のロックを待たない。同時実行性は最大だが、一貫性の保証はない。","適用場面: 精度が重要でない大まかなメトリクス/進捗カウントなどの場合のみ。","注意: PostgreSQL ではこのレベルは Read Committed と同様に動作し、Oracle は Read Uncommitted を一切提供しない。実際のダーティリードが問題になるのは主にロックベースの SQL Server (NOLOCK)。","注意: 「高速化のための NOLOCK」を恒常的な習慣にしないこと。誤った/重複した/欠落した行を読むリスクがある。"]},"sol_read_committed":{"kind":"solution","title":"推奨: Read Committed (OLTP のデフォルト)","detail":"各文は、その時点でコミットされた最新のデータを参照し、ダーティリードは防止される。多くのエンジンのデフォルトであり、一般的な OLTP ワークロードに最適な同時実行性/一貫性のバランスを提供する。","steps":["理由: トランザクションに不必要に長くロックを保持させることなくダーティリードを防止し、高い同時実行性を提供する。","適用場面: 短く対象を絞った OLTP トランザクション。大多数の Web アプリケーションにとって適切なデフォルト。","例: PostgreSQL、SQL Server、Oracle では Read Committed がデフォルト (Oracle では文レベルのスナップショットにより一貫性が提供される)。","注意: 同じトランザクション内の 2 回の読み取りが異なる結果を返す場合がある (反復不能/ファントム)。一貫したレポートが必要なロジックの前提にしないこと。","注意: MySQL/InnoDB のデフォルトは Repeatable Read。移行時はエンジンの違いに注意する。"]},"sol_repeatable_read":{"kind":"solution","title":"推奨: Repeatable Read / Snapshot (一貫した読み取り)","detail":"トランザクションは、開始時 (または最初の読み取り時) に固定された一貫したスナップショット上で動作し、トランザクション中に読み取り結果は変わらない。MVCC により、読み取り側は書き込み側をブロックせず、書き込み側も読み取り側をブロックしない。","steps":["理由: トランザクション全体で固定されたビューを提供し、反復不能読み取り (MVCC エンジンでは実質的にファントムも) を防止するため、読み取り中心のレポート/計算ロジックの一貫性が保たれる。","適用場面: 1 つのトランザクション内で同じデータを複数回読み、一貫した結果が必要なレポート、照合、バッチ計算。","例: MySQL/InnoDB のデフォルト Repeatable Read、SQL Server SNAPSHOT (行のバージョン管理)、PostgreSQL REPEATABLE READ。Oracle の SERIALIZABLE は実際にはスナップショットのセマンティクス。","注意: write skew などの直列化異常は防止できない。業務ルール上必要なら Serializable に引き上げる。","注意: Snapshot/行のバージョン管理は tempdb や undo/バージョンストアの増大を引き起こす可能性がある。長時間トランザクションは古いバージョンを肥大化させる。"]},"sol_serializable":{"kind":"solution","title":"推奨: Serializable (完全な分離)","detail":"最も高い分離レベル: 同時実行トランザクションが、直列に (1 つずつ順番に) 実行されたかのような結果を生む。すべての読み取り異常と write skew を防止する。代償は競合の増加とリトライの必要性。","steps":["理由: 結果が常に有効な直列実行と等価であることを保証し、すべての同時実行異常を排除する。","適用場面: 正確性が重要な不変条件を伴うロジック: 残高/在庫チェック、二重予約が決して起きてはならないケース。","例: PostgreSQL SSI (Serializable Snapshot Isolation)、SQL Server SERIALIZABLE (範囲ロック)。Oracle では真の直列化はアプリケーションレベルで扱う。","注意: 直列化の失敗 (例: PG の 40001) は想定された動作。アプリケーションでトランザクションを自動的に再実行するリトライロジックが必須。","注意: 競合の多い負荷ではスループットが低下する可能性がある。すべてに適用するのではなく、正確性が重要なトランザクションのみに適用する。"]}}},"solver/decide-sqlnosql.json":{"id":"decide-sqlnosql","title":"判断: SQL か NoSQL か (どのデータベースファミリーか)?","icon":"🧭","category":"判断ガイド","intro":"適切なデータベースファミリーの選択は、データモデルの形状、一貫性とスケールの優先度、クエリの複雑さによって決まる。「NoSQL のほうが新しい」といった一般論は誤解を招く。各ファミリーは特定のアクセスパターン向けに設計されている。このツリーは、データの構造を起点に、リレーショナル、ドキュメント、キーバリュー、検索エンジンの中から適切なツールに導き、必要に応じてポリグロットなアプローチを想起させる。","start":"root","nodes":{"root":{"kind":"step","title":"データの性質と主なアクセスパターンは?","detail":"最も決定的な質問から始める: データは強い関連を持つ構造化レコードか、柔軟/可変なスキーマのドキュメントか、単純なキーバリューの検索か、それともテキスト検索のような特殊なニーズか? データの形状とクエリの方法がファミリーをほぼ決定する。","choices":[{"label":"リレーショナル、構造化レコードと複雑なクエリ","next":"relational_check"},{"label":"柔軟/可変なスキーマを持つネストしたドキュメント","next":"sol_document"},{"label":"単純なキーバリュー、極めて低いレイテンシ/キャッシュ","next":"sol_keyvalue"},{"label":"全文検索 / ファセット検索、ログ分析","next":"sol_search"}]},"relational_check":{"kind":"step","title":"強い一貫性 (ACID) と水平スケールのどちらが優先か?","detail":"データはリレーショナルに見えるが、優先度は何か? 複数テーブルの結合、トランザクションの整合性、強い一貫性 (ACID) が不可欠か、それとも単一ノードに収まらない膨大な量を水平スケールすることか? リレーショナルモデルはほとんどのワークロードにとって適切なデフォルトであり、限界に達するのはスケールが実際に単一ノードを超える場合のみ。","choices":[{"label":"ACID、結合、複雑なクエリの整合性が最優先","next":"sol_relational"},{"label":"何よりもスケール。関連/結合は弱い","next":"sol_document"}]},"sol_relational":{"kind":"solution","title":"推奨: リレーショナルデータベース (RDBMS)","detail":"構造化され強く関連したデータを持ち、トランザクションの整合性を必要とするワークロードにとって適切なデフォルト。ACID 保証、成熟した SQL クエリエンジン、結合により、複雑な問いに確実に答えられる。","steps":["理由: ACID トランザクション、外部キーの整合性、強い一貫性に加え、複数テーブルを結合する複雑なクエリを最適化する成熟したプランナーを提供する。","適用場面: 金融、受注/在庫、ERP/CRM など、関連と一貫性が重要な OLTP およびレポートのワークロード。","例: PostgreSQL、MySQL、Oracle、SQL Server。時系列のニーズには PostgreSQL + TimescaleDB などの拡張。","注意: スキーマ変更 (マイグレーション) には規律が必要。スキーマ変更が頻繁で予測不能な場合は、ドキュメントモデルを検討する。","注意: 単一ノードの書き込み/データの上限に達した場合は、リードレプリカ、パーティショニング、必要に応じてシャーディングでスケールする。"],"related":["create-partition"]},"sol_document":{"kind":"solution","title":"推奨: ドキュメントデータベース","detail":"スキーマが頻繁に変化する柔軟でネストしたデータを、自然な形 (JSON 形式のドキュメント) で保存する。主に単一ドキュメント単位で読み書きし、結合が少なく、水平スケールが必要なアプリケーションに適する。","steps":["理由: スキーマが柔軟で、ドキュメントはフィールドの追加・削除が可能。ネストした構造を 1 回の読み取りで取得でき、水平スケール (シャーディング) に適している。","適用場面: カタログ、ユーザープロファイル、コンテンツ/CMS、イベント記録など、ドキュメント中心で構造が可変、かつ急速に進化するデータモデル。","例: MongoDB、Couchbase。リレーショナルの世界では、JSONB (PostgreSQL) が限定的ながら同様の柔軟性を提供する。","注意: 複数ドキュメントにまたがる複雑な結合やレポートは弱い。関連が支配的な場合はリレーショナルモデルのほうが適している。","注意: 一貫性とスキーマ検証の責任の大部分がアプリケーション側に移る。データ品質はコードで保護する。"]},"sol_keyvalue":{"kind":"solution","title":"推奨: キーバリューストア / キャッシュ","detail":"キーによる非常に高速な読み書きが必要で、複雑なクエリを必要としないワークロード向けに設計されている。通常はメモリ上で動作し、マイクロ秒/ミリ秒単位のレイテンシを提供する。キャッシュ、セッション、カウンタなどの用途に最適。","steps":["理由: 単純なキーアクセスに対して極めて低いレイテンシと高いスループットを実現する。インメモリ構造によりリレーショナルデータベースの負荷を軽減する。","適用場面: キャッシュ層、セッションストア、レート制限カウンタ、リーダーボード、一時的なキュー/pub-sub。","例: Redis、Memcached。Redis はリスト/セット/ソート済みセットなどの豊富なデータ構造と永続化オプションも提供する。","注意: 通常、唯一の信頼できる情報源 (single source of truth) にはならない。ソースデータは耐久性のあるデータベースに保持し、派生データ/キャッシュデータをここに保存する。","注意: メモリは限られており高価。エビクションポリシー、TTL、永続化/耐久性の設定を業務要件に合わせて計画する。"]},"sol_search":{"kind":"solution","title":"推奨: 検索 / 分析エンジン","detail":"全文検索、関連度ランキング、ファセットフィルタリング、大量のログ/テキスト分析に特化した転置インデックスベースのエンジン。リレーショナルの LIKE クエリでは実現できない検索体験を提供する。","steps":["理由: 転置インデックスとスコアリングにより、全文検索、オートコンプリート、ファセット、集計を高いパフォーマンスで実行する。","適用場面: 製品/サイト検索、ログとオブザーバビリティの分析、関連度順の検索体験が必要なアプリケーション。","例: Elasticsearch/OpenSearch、Apache Solr。中規模の全文検索であれば PostgreSQL tsvector で十分な場合がある。","注意: 通常、主要な記録システムにはならない。メインデータはリレーショナル/ドキュメント DB に保持し、そこから検索インデックスに供給する (CDC/同期)。","注意: リアルタイムの強い一貫性の保証は弱い (ニアリアルタイムのインデックス作成)。設計時にインデックス作成の遅延を考慮する。"],"related":["setup-cdc-replication"]}}},"solver/decide-shard-replica.json":{"id":"decide-shard-replica","title":"判断: シャーディングかレプリケーションか (スケーリング)?","icon":"🧭","category":"判断ガイド","intro":"データベースのスケーリングの判断は、ボトルネックが読み取りか書き込みか、そしてデータが単一ノードに収まるかどうかによって決まる。誤った戦略は、不要な複雑さか、未解決のボトルネックを意味する。このツリーは、まず最も安価でシンプルな選択肢 (垂直スケーリング、キャッシュ) を想起させ、その上でリードレプリカとシャーディングの正しい選択を支援する。","start":"root","nodes":{"root":{"kind":"step","title":"最もシンプルな方法 (垂直スケーリングとクエリチューニング) を先に試したか?","detail":"分散アーキテクチャに移行する前に、最も安価な改善を取る: ハードウェアの増強 (CPU/RAM/IOPS)、不足しているインデックスの追加、高コストなクエリの修正で、ほとんどのボトルネックは解消する。複雑さを加えるのは、これらを尽くした後に限る。","choices":[{"label":"いいえ / まだ限界に達していない","next":"sol_vertical"},{"label":"はい、垂直スケーリングとチューニングでは不十分","next":"bottleneck"}]},"bottleneck":{"kind":"step","title":"ボトルネックは読み取りか、それとも書き込み/データ量か?","detail":"スケーリング問題の発生源を切り分ける: 大量の読み取りクエリが単一ノードを圧迫している (読み取り中心) のか、それとも書き込みレートや総データサイズが単一ノードの容量を超えている (書き込み/データ量中心) のか? この区別がレプリカとシャーディングの根本的な違い。","choices":[{"label":"読み取りトラフィックが支配的で、書き込みは単一ノードに収まる","next":"read_path"},{"label":"書き込みレートまたはデータ量が単一ノードを超える","next":"sol_sharding"}]},"read_path":{"kind":"step","title":"読み取りは反復的/キャッシュ可能か、それとも最新で多様か?","detail":"読み取りのボトルネックをさらに一段階切り分ける: 同じ結果が何度も読み取られている (キャッシュが非常に有効) のか、それとも読み取りが多様で広範かつ最新のデータを要求している (追加の読み取り容量が必要) のか? これによりキャッシュ層とリードレプリカのどちらにするかが決まる。","choices":[{"label":"同じデータが繰り返し読み取られ、多少の古さは許容できる","next":"sol_cache"},{"label":"多様/最新の読み取りで、純粋な読み取り容量が必要","next":"sol_read_replica"}]},"sol_vertical":{"kind":"solution","title":"推奨: まず垂直スケーリング + クエリチューニング","detail":"分散アーキテクチャに移行する前の、最初かつ最も安価な方法。ハードウェアの増強とクエリ/インデックスの修正で、運用の複雑さを加えることなく、ほとんどのスケーリング問題を解決できる。","steps":["理由: 複雑さとリスクが最も低い。単一ノードにとどまる限り、トランザクション/一貫性モデルは変わらず、アプリケーションコードを分割する必要もない。","適用場面: 単一ノードのハードウェア上限にまだ達していない場合、またはボトルネックが実際には不適切なクエリ/不足しているインデックスに起因する場合。","手順: 低速なクエリをプロファイリングし、不足しているインデックスを追加し、実行計画/統計情報を修正する。その後、CPU/RAM/IOPS を増強する。","注意: 垂直スケーリングには限界があり、コストは指数関数的に増加する。単一ノードは依然として単一障害点 (HA 用にレプリカを別途構築する)。","注意: 上限が近づいたら、次のステップ (レプリカ/シャーディング) を前もって計画する。急な移行はリスクが高い。"]},"sol_read_replica":{"kind":"solution","title":"推奨: リードレプリカ (読み取りのスケーリング)","detail":"書き込みは単一ノード (プライマリ) にとどめ、読み取りトラフィックを 1 つ以上のレプリカに分散する。読み取り中心のワークロードで、純粋な読み取り容量と耐障害性を高める標準的な方法。","steps":["理由: 読み取りクエリが複数のコピーに分散され、プライマリは書き込みのみを処理するため、読み取りスループットがほぼ線形に向上する。","適用場面: 読み取り/書き込み比率の高いワークロード、レポートと分析クエリのプライマリからの分離、同時に HA 用スタンバイも確保したい場合。","例: PostgreSQL ストリーミングレプリカ、MySQL レプリカ + プロキシルーティング、アプリケーションでの読み書き分離 (read-write split)。","注意: 非同期レプリカでは、レプリケーション遅延により read-your-writes の問題 (書き込んだ直後のデータを読めない) が生じる。重要な読み取りはプライマリにルーティングする。","注意: レプリカは書き込みのボトルネックを解決しない。単一の書き込みノードが依然として上限 — 書き込みもボトルネックであればシャーディングが必要。"],"related":["replication-status"]},"sol_cache":{"kind":"solution","title":"推奨: キャッシュ層","detail":"頻繁に再読み取りされる結果を高速なインメモリ層に保持することで、データベースの負荷を大幅に削減する。適切なパターンを使えばデータベースにアクセスせずに応答でき、レイテンシと負荷の両方を低減する。","steps":["理由: 繰り返しの読み取りは、データベースに到達することなくメモリ速度で応答される。費用対効果が最も高い読み取りスケーリングの方法。","適用場面: 同じデータが何度も読み取られ、多少の古さが許容できる場合。例: 製品詳細、設定、参照データ。","例: Redis/Memcached による cache-aside パターン。アプリケーションはまずキャッシュにアクセスし、ミスした場合にデータベースにアクセスする。","注意: キャッシュの無効化は難しい。TTL と、書き込み時の更新/パージ戦略を明示的に設計する。","注意: 強い一貫性が必要な読み取り (金額/在庫) で古いキャッシュに依存しないこと。そうした読み取りはソースから提供する。"]},"sol_sharding":{"kind":"solution","title":"推奨: シャーディング (書き込み/データのスケーリング)","detail":"データはシャードキーで分割され、複数の独立したノードに分散される。各ノードがデータの一部とその書き込みを担当する。書き込みレートと総データ量をスケールする方法だが、大きな複雑さが加わる。","steps":["理由: 書き込みとストレージが複数のノードに分散され、単一書き込みノードおよび単一ノードのデータ上限がなくなり、水平スケーリングが可能になる。","適用場面: 書き込みスループットやデータサイズが単一ノード (およびリードレプリカ) に収まらなくなった場合、他に選択肢が残っていない場合。","例: アプリケーション層でのシャードルーティング、Vitess (MySQL)、Citus (PostgreSQL)、ドキュメント DB の組み込みシャーディング。","注意: シャードキーの選択は重要で、後から変更するのは難しい。不適切なキーはホットスポットと偏った分散を生む。アクセスパターンに合ったカーディナリティの高いキーを選択する。","注意: シャードをまたぐ結合、トランザクション、一意性の確保が難しくなる。アプリケーションの複雑さ、リバランス (リシャーディング)、運用負荷が大幅に増加する。"],"related":["create-partition"]}}},"solver/decide-backup.json":{"id":"decide-backup","title":"判断: どのバックアップ戦略か?","icon":"🧭","category":"判断ガイド","intro":"バックアップ戦略は、許容できるデータ損失量 (RPO)、データサイズ、復旧に必要な速さ (RTO) の 3 つの要素のバランスで選択する。すべてのシナリオに合う単一の方法はない。このツリーは、RPO 目標を起点に、論理ダンプ、物理バックアップ + PITR、スナップショットの間で選択を導き、3-2-1 と検証は譲れない原則であることを想起させる。","start":"root","nodes":{"root":{"kind":"step","title":"データ損失の目標 (RPO) は?","detail":"最も決定的な制約から始める: 災害時に何分/何時間分のデータを失っても許容できるか? ほぼゼロのデータ損失が必要なら、継続的なログアーカイブ (PITR) が必須。日次/週次のバックアップで許容できるなら、よりシンプルな方法で十分。RPO が戦略の枠組みを決める。","choices":[{"label":"ほぼゼロ — 任意の時点に戻れる必要がある","next":"sol_physical_pitr"},{"label":"日次/定期的なバックアップ (数時間の損失) で許容できる","next":"size"},{"label":"まず一般的なベストプラクティス (3-2-1 / 検証) を確認したい","next":"sol_321"}]},"size":{"kind":"step","title":"データサイズと可搬性の要件は?","detail":"定期的なバックアップで十分な場合、次の問題は規模と目的: データベースは小/中規模で、バックアップを別の環境/バージョンに移せるようにしたいのか、それともデータが大きく、数分以内に復旧することが最大の関心事なのか? これにより論理ダンプとスナップショットのどちらにするかが決まる。","choices":[{"label":"小/中規模、可搬性がありバージョン間で互換性がある","next":"sol_logical"},{"label":"大規模データ、復旧は非常に高速である必要がある (低 RTO)","next":"sol_snapshot"}]},"sol_logical":{"kind":"solution","title":"推奨: 論理ダンプ","detail":"データを論理レベル (スキーマ定義 + 行) でエクスポートする。出力は SQL/テキスト (pg_dump の plain 形式、mysqldump) か、ツール固有のバイナリダンプ (pg_dump -Fc、Oracle Data Pump) のいずれか。小/中規模のデータベース、移行、バージョンアップグレード、特定のテーブル/オブジェクトの復旧に適した柔軟で可搬性のある方法。","steps":["理由: 出力は可搬性があり (テキスト形式なら可読)、バージョン/エンジン間の移行や、単一のテーブル/オブジェクトのリストアに適している。","適用場面: 小/中規模のデータ、バージョンアップグレード/移行、開発環境のコピー、論理的 (行レベル) な復旧が必要な場合。","例: PostgreSQL pg_dump/pg_dumpall、MySQL mysqldump、Oracle Data Pump (expdp/impdp。バイナリの .dmp を生成する。DDL をテキストで確認するには impdp SQLFILE= を使用する)。","注意: リストア時にデータを再処理するため、大規模データベースではバックアップ取得とリストアの両方が非常に遅い (高 RTO)。","注意: 単独では低い RPO を実現できない。ポイントインタイムリカバリには物理バックアップ + ログアーカイブが必要。一貫したスナップショットを得るには適切な一貫性オプションを使用する。"],"related":["logical-dump","last-backup-status"]},"sol_physical_pitr":{"kind":"solution","title":"推奨: 物理バックアップ + WAL/アーカイブログ (PITR)","detail":"定期的に物理ベースバックアップを取得し、トランザクションログ (WAL/redo/binlog) を継続的にアーカイブする。これにより任意の時点へのポイントインタイムリカバリが可能になり、データ損失をほぼゼロに抑えられる。","steps":["理由: 継続的なログアーカイブにより、最後のベースバックアップ以降の任意のトランザクションまでロールフォワードし、目的の時点 (例: 誤ったコマンドの直前) に戻れる — 最も低い RPO。","適用場面: 大規模かつ重要な本番データベース、低い RPO と妥当な RTO が必要なシステム。","例: PostgreSQL ベースバックアップ + WAL アーカイブ (pgBackRest/barman)、Oracle RMAN + archivelog、MySQL 物理バックアップ + binlog (xtrabackup)。","注意: 構築と運用がより複雑。アーカイブログが中断や欠落なく流れていることを継続的に監視する — 1 つの欠落で PITR チェーンが途切れる。","注意: ログアーカイブのストアは継続的に増大する。保持ポリシーとストレージ計画がなければディスクが満杯になる。"],"related":["last-backup-status","logical-dump"]},"sol_snapshot":{"kind":"solution","title":"推奨: スナップショット","detail":"ストレージ層または仮想化層で、データのブロックレベルのスナップショットを取得する。非常に大規模なデータベースでもバックアップとリストアが非常に高速。ただし、インフラに依存し、慎重な運用が必要。","steps":["理由: ブロックレベルのコピーがほぼ瞬時に作成され、リストアも非常に高速。大規模データに対して最も低い RTO を実現する。","適用場面: テラバイト規模のデータで、高速な復旧が最優先の場合。ストレージ/クラウド層がスナップショットをサポートしている場合。","例: SAN/LVM スナップショット、クラウドディスクのスナップショット (EBS など)、ZFS/ファイルシステムのスナップショット。データベースエンジンと整合をとってトリガーする。","注意: スナップショットはストレージシステムに依存し、通常は同じインフラ上に存在する。単独では 3-2-1 を満たさない — オフサイトにコピーする。","注意: アプリケーション整合性を確保するには、スナップショット取得時にデータベースが適切なモード (fsfreeze/バックアップモード/ホットバックアップ) である必要がある。そうでなければ「クラッシュ整合性」のバックアップになる。"],"related":["last-backup-status"]},"sol_321":{"kind":"solution","title":"推奨: 3-2-1 ルール + オフサイト + 検証の必須化","detail":"どの方法を選択しても、これらの原則を戦略の上位に置く必要がある。バックアップが存在するだけでは不十分で、異なるメディア、異なる場所に保管し、定期的にテストする必要がある。これは上記すべての選択肢を補完する枠組み。","steps":["3-2-1: 少なくとも 3 つのコピーを、2 種類の異なるメディア/タイプに保持し、1 つのコピーをオフサイトに置く。","オフサイトが必要な理由: 火災、洪水、ランサムウェア、リージョンの喪失により、1 か所にあるすべてのコピーが一度に失われる可能性がある。少なくとも 1 つのコピーは隔離/遠隔地に置く必要がある。","検証は必須: テストされていないバックアップはバックアップではない。実際のリストア訓練を定期的に実施し、復旧時間 (RTO) を測定する。","イミュータビリティ: ランサムウェア対策として、削除/変更できない (immutable/WORM) コピーまたはエアギャップされたコピーを保持する。","注意: バックアップの整合性 (チェックサム) と復旧可能性を自動的に監視し、失敗した/古いバックアップに対するアラートを設定する。バックアップ自体も暗号化する。"],"related":["last-backup-status"]}}},"solver/decide-index.json":{"id":"decide-index","title":"判断: どのインデックスタイプか?","icon":"🧭","category":"判断ガイド","intro":"適切なインデックスタイプは、クエリのアクセスパターン (等価、範囲、テキスト/JSON 検索)、列のカーディナリティ、読み書きのバランスによって決まる。誤ったインデックスは領域を無駄にし、書き込みも遅くする。このツリーは、クエリの形状を起点に B-tree、Hash、Bitmap、GIN/GiST、部分インデックス、カバリングインデックスの選択肢を導き、複合インデックスでは列の順序が重要であることを想起させる。","start":"root","nodes":{"root":{"kind":"step","title":"クエリはこの列をどのように使用しているか?","detail":"アクセスパターンはインデックス選択の最も決定的な要素。列を '=' で照合するだけか、範囲/ソート (>, <, BETWEEN, ORDER BY) を行うか、それとも全文、JSON フィールド、幾何データ/配列を検索するか? ここから始め、ニーズが明確になるまでインデックスタイプを選ばないこと。","choices":[{"label":"等価と範囲/ソートの混在 (=, >, <, BETWEEN, ORDER BY)","next":"cardinality"},{"label":"等価のみ (=)、範囲やソートなし","next":"sol_hash"},{"label":"全文、JSON/JSONB フィールド、配列、または幾何検索","next":"sol_gin_gist"},{"label":"クエリが常に同じ小さな行のサブセットを対象とする (例: WHERE status='active')","next":"sol_partial"}]},"cardinality":{"kind":"step","title":"列のカーディナリティ (個別値の数) は?","detail":"範囲/ソートが必要な場合のデフォルトは B-tree。ただし、読み取り中心のデータウェアハウスで個別値が非常に少ない列 (低カーディナリティ: 性別、ステータス、yes/no) には Bitmap インデックスのほうが適している場合がある。列には一意な値が多いか、それとも少数の値が繰り返されているか?","choices":[{"label":"高カーディナリティ (一意な値が多い) または OLTP ワークロード","next":"coverage"},{"label":"低カーディナリティかつ読み取り中心 / データウェアハウス (DWH)","next":"sol_bitmap"}]},"coverage":{"kind":"step","title":"クエリはインデックス内の列のみを読み取るか?","detail":"アクセスパターンは B-tree に適している。最後の最適化: クエリが返す列とフィルタする列がすべてインデックスに含まれていれば、エンジンはテーブルにアクセスせずインデックスのみで応答できる (index-only / カバリングスキャン)。クエリは少数の列を読み取るのか、それとも行の大部分が必要か?","choices":[{"label":"はい、少数の列で、テーブルにアクセスせずに応答できる","next":"sol_covering"},{"label":"いいえ、標準的なアクセスで十分","next":"sol_btree"}]},"sol_btree":{"kind":"solution","title":"推奨: B-tree (デフォルト)","detail":"B-tree は、等価、範囲、ソート (ORDER BY)、LIKE 'abc%' による前方一致、MIN/MAX など、幅広いアクセスパターンをサポートする平衡木構造。ほとんどのリレーショナルエンジンのデフォルトのインデックスタイプであり、迷ったときの適切な出発点。","steps":["理由: 単一の構造で等価と範囲/ソートの両方に効率よく対応する。最も汎用的なインデックス。","適用場面: OLTP クエリ、WHERE + 範囲 + ORDER BY の組み合わせ、主キー/一意キー。","複合インデックスでは列の順序が重要: 等価条件で使用する最も選択性の高い列を先頭に置き、範囲条件の列は最後にする。(a,b) インデックスは 'a' または 'a,b' のフィルタに有効だが、'b' のみのフィルタには通常有効ではない (左端プレフィックスのルール)。","例: PostgreSQL/Oracle/MySQL(InnoDB)/MSSQL のいずれでもデフォルトの B-tree/B+tree インデックス。","注意: インデックスはすべて書き込み (INSERT/UPDATE/DELETE) のコストとディスク領域を増やす。不要なインデックスや重複したインデックスを保持しないこと。"],"related":["slow-query"]},"sol_hash":{"kind":"solution","title":"推奨: Hash インデックス (等価のみ)","detail":"Hash インデックスは列の値のハッシュを格納し、完全一致 ('=') の検索に限り非常に高速。範囲、ソート、前方一致の検索はサポートしないため、用途は限られる。","steps":["理由: 等価検索に対して平均定数時間 (O(1)) のアクセスを提供する。メモリに収まる非常に大規模な等価検索のワークロードで有利になる場合がある。","適用場面: 列が '=' でのみ使用され、範囲/ソートがまったく不要な場合。","エンジンの違い: PostgreSQL には Hash インデックスがあるが、実際にはほとんどの場合 B-tree で十分かつ柔軟。MySQL(InnoDB) は Hash インデックスを adaptive hash index として内部でのみ管理し、MEMORY エンジンは明示的に hash を使用する。Oracle ではクラスタ/ハッシュクラスタの文脈で登場する。","注意: 範囲、BETWEEN、ORDER BY、LIKE 'abc%' はサポートされない。これらのニーズが生じたら B-tree を選択する。","注意: 通常はデフォルトの B-tree で十分なため、測定せずに hash に切り替えないこと。"],"related":["slow-query"]},"sol_bitmap":{"kind":"solution","title":"推奨: Bitmap インデックス (低カーディナリティ / DWH)","detail":"Bitmap インデックスは個別値ごとにビット配列を保持し、複数の低カーディナリティ条件をビット単位の AND/OR で非常に高速に結合する。データウェアハウスやレポートなど、読み取り中心のワークロードに強い。","steps":["理由: 個別値の少ない列では非常に小さな領域で済み、複数の条件 (WHERE gender=.. AND region=..) をビットマップ演算で効率よく結合する。","適用場面: 低カーディナリティの列、スタースキーマのクエリ、データウェアハウス/レポート、読み取り中心のワークロード。","エンジンの違い: Oracle の典型的な強み。PostgreSQL には永続的な Bitmap インデックスはないが、プランナーが実行時に 'bitmap heap scan' を生成できる。MySQL/MSSQL にはそのような永続的な Bitmap インデックスはない。","注意: 頻繁に更新される (OLTP) テーブルでは使用しないこと。ビットマップのロックにより行レベルの同時実行性が大きく低下する。","注意: 高カーディナリティの列では利点がなくなる。その場合は B-tree を優先する。"],"related":["slow-query"]},"sol_gin_gist":{"kind":"solution","title":"推奨: GIN / GiST (テキスト、JSON、配列、幾何)","detail":"PostgreSQL には、標準の B-tree では扱えないアクセスタイプ向けの専用インデックスファミリーがある。GIN は値内の多数の構成要素 (単語、JSONB キー、配列要素) を指し、GiST は幾何/範囲/最近傍などのクエリに適している。","steps":["理由: これらのデータ型では、「含む/重なる/近い」といったクエリを B-tree で効率よく処理できない。GIN/GiST がこれらを高速化する。","GIN の適用場面: 全文検索 (tsvector)、JSONB のフィールド/キー検索 (@>, ?)、配列の包含クエリ。読み取り中心で書き込みが少ない場合。","GiST の適用場面: 幾何/地理空間 (PostGIS)、範囲型、最近傍 (KNN) クエリ。","エンジンの違い: GIN/GiST は PostgreSQL 固有。MySQL の FULLTEXT および SPATIAL (R-tree) インデックス、Oracle の Oracle Text と Spatial、MSSQL の Full-Text Index が同様の目的を果たす。","注意: GIN は書き込みのコストが高く、作成も遅い (fastupdate で緩和できる)。書き込み中心のテーブルではコストを測定する。"],"related":["slow-query"]},"sol_partial":{"kind":"solution","title":"推奨: 部分 / フィルタ選択インデックス","detail":"部分インデックスは、テーブル全体ではなく条件 (WHERE ...) を満たす行のみをインデックス化する。クエリが常に同じ小さなサブセットを対象とする場合、インデックスははるかに小さく高速になり、書き込みコストも下がる。","steps":["理由: 該当する行のみをインデックス化するため、領域とメンテナンスコストの両方が下がり、頻繁に照会される「ホットな」サブセットがはるかに高速になる。","適用場面: WHERE status='active'、deleted_at IS NULL、priority='high' などの安定した狭い条件。","エンジンの違い: PostgreSQL は 'partial index' (CREATE INDEX ... WHERE ...)、MSSQL は 'filtered index' で直接サポートする。Oracle では同等の手段としてファンクションベース/条件付きインデックスのパターンを使用する。MySQL(InnoDB) は直接サポートしない。","注意: インデックスの WHERE 条件がクエリの条件と一致している必要がある。そうでなければプランナーはインデックスを使用できない。","注意: サブセットが大きくなると利点は小さくなる。条件が安定していることを確認する。"],"related":["slow-query"]},"sol_covering":{"kind":"solution","title":"推奨: カバリング (INCLUDE) インデックス","detail":"カバリングインデックスはクエリが必要とするすべての列を保持し、エンジンがテーブル (ヒープ) にまったくアクセスせずにインデックスのみで応答できるようにする (index-only scan)。少数の列を返す頻繁に実行されるクエリで大幅な高速化が得られる。","steps":["理由: テーブルアクセス (heap fetch) がなくなり、ディスク I/O とレイテンシが顕著に低下する。","適用場面: WHERE + SELECT の列が明確に定まり、結果セットが狭い、頻繁に実行されるクエリ。","エンジンの違い: MSSQL と PostgreSQL は 'INCLUDE' で非キー列をインデックスのリーフに追加する。MySQL(InnoDB) ではセカンダリインデックスがすでに主キーを含むため、複合インデックスでカバリングを実現する。Oracle では、必要なすべての列がインデックスに含まれている場合にインデックスのみのアクセスが行われる。","注意: 余分な/幅の広い INCLUDE 列はインデックスを肥大化させ、書き込みを遅くする。本当に必要な列のみを追加する。","注意: PostgreSQL では、index-only scan に最新の可視性マップが必要。定期的な VACUUM が不可欠。"],"related":["slow-query"]}}},"solver/decide-partition.json":{"id":"decide-partition","title":"判断: どのパーティショニング戦略か?","icon":"🧭","category":"判断ガイド","intro":"パーティショニングは、大きなテーブルを単一の論理名の下で複数の物理的な断片に分割し、古いデータの削除を容易にし、クエリが該当する断片のみを参照できるようにする (パーティションプルーニング)。ただし、小さなテーブルでは複雑さが増すだけ。このツリーは、まずパーティショニングが本当に必要かを問い、その上でアクセスと分布のパターンに基づいて Range、List、Hash、Composite の中から選択を導く。","start":"root","nodes":{"root":{"kind":"step","title":"テーブルは本当にパーティショニングが必要なほど大きいか?","detail":"パーティショニングはパフォーマンスの魔法ではなく、スケールとメンテナンス (ライフサイクル) のためのツール。テーブルが十分に大きくない場合や、クエリがすでにインデックスで十分なパフォーマンスを発揮している場合、パーティショニングは実行計画の複雑さと管理のオーバーヘッドをもたらすだけ。テーブルは数千万行以上/数百 GB に達しているか、それともまだ小/中規模か?","choices":[{"label":"はい、非常に大きい、または古いデータを一括で削除/アーカイブする必要がある","next":"access"},{"label":"いいえ、小/中規模のテーブル、または確信がない","next":"sol_no_partition"}]},"access":{"kind":"step","title":"データにどのようにアクセスし、どのように分割すべきか?","detail":"パーティションキーは、大多数のクエリがフィルタに使う列にすべきであり、そうして初めてプルーニングが機能する。主なアクセスパターンは何か? 日付/連続した範囲 (直近 30 日) か、特定のカテゴリ/リージョンの値か、それとも明確なフィルタがなく負荷を均等に分散したいのか?","choices":[{"label":"日付/シーケンス番号などの連続した範囲 (直近 X 日、月単位)","next":"sol_range"},{"label":"カテゴリ/リージョン/テナントなどの離散的な値の集合","next":"sol_list"},{"label":"明確な範囲/カテゴリがない。目的は負荷の均等な分散","next":"sol_hash"},{"label":"日付と大量データの両方。2 つの次元で分割する必要がある","next":"sol_composite"}]},"sol_no_partition":{"kind":"solution","title":"推奨: (まだ) パーティショニングしない","detail":"小/中規模のテーブルではパーティショニングの利点はない。適切に選んだインデックスと通常のメンテナンスで十分。時期尚早なパーティショニングは実行計画を複雑にし、誤ったキーではプルーニングが効かず、運用のオーバーヘッドが増える。","steps":["理由: 小さなテーブルではフルスキャンやインデックスアクセスがすでに高速。パーティショニングは管理と実行計画の複雑さを増やすだけ。","この状態を維持する場面: 数百万行未満、古いデータを一括削除する必要がない、クエリがインデックスで十分なパフォーマンスを発揮している。","代わりに: 適切なインデックス、必要に応じてアーカイブテーブル、定期的な統計情報/VACUUM/ANALYZE。","注意: 「いずれ大きくなる」という想定で早期にパーティショニングを構築しないこと。増加が実証され、適切なキーが明確になってから切り替える。","エンジンの違い: すべてのエンジンに当てはまる一般原則。PostgreSQL の宣言的パーティショニング、MySQL PARTITION BY、Oracle と MSSQL のパーティショニングは後から容易に追加できる。"],"related":[]},"sol_range":{"kind":"solution","title":"推奨: Range パーティショニング","detail":"Range パーティショニングは、列の連続した範囲 (例: 日付範囲: 月/四半期ごとに 1 パーティション) で行を分割する。時系列や継続的に増加するテーブルにとって最も一般的かつ強力な戦略。","steps":["理由: クエリが日付/範囲でフィルタする場合、エンジンは該当するパーティションのみを読み取る (パーティションプルーニング)。古いデータは単一のコマンド (パーティションの DROP) で即座に削除できる。","適用場面: 時系列、ログ、注文/取引履歴。「直近 N 日」のクエリと時間ベースのアーカイブ。","パーティションキー: 大多数のクエリの WHERE 句に含まれる日付/連続した列を選択する。そうでなければプルーニングは機能しない。","例: PostgreSQL RANGE パーティショニング、Oracle レンジ/インターバルパーティショニング (新規パーティションの自動作成)、MySQL PARTITION BY RANGE (日付には通常 RANGE COLUMNS)、MSSQL パーティション関数/パーティション構成。","注意: 将来の範囲に対する新規パーティションの作成を自動化する (Oracle interval またはスケジュールジョブ)。データが溜まった 'default/maxvalue' パーティションはホットスポットになる。"],"related":[]},"sol_list":{"kind":"solution","title":"推奨: List パーティショニング","detail":"List パーティショニングは、列の離散的で既知の値 (例: region = 'TR','EU','US' やテナント ID) で行をグループ化する。自然で有限のカテゴリが存在する場合、アクセスと管理が明確になる。","steps":["理由: クエリが特定のカテゴリ値でフィルタする場合、そのパーティションのみが読み取られる。カテゴリ単位のメンテナンス/削除が容易になる。","適用場面: リージョン/国、製品タイプ、ステータス、マルチテナントの分離など、離散的で比較的安定した値の集合。","パーティションキー: 値の集合は有限かつ予測可能である必要がある。新しい値が頻繁に追加される場合は、List ではなく Hash を検討する。","例: PostgreSQL LIST パーティショニング、Oracle リストパーティショニング、MySQL PARTITION BY LIST、適切な境界値を持つ MSSQL パーティション構成。","注意: 未定義/新規の値のために 'default' パーティションを保持する。そうしないと行を挿入できずエラーになる。"],"related":[]},"sol_hash":{"kind":"solution","title":"推奨: Hash パーティショニング (均等な分散)","detail":"Hash パーティショニングは、キー列のハッシュに基づき、あらかじめ定めた数のパーティションに行を比較的均等に分散する。自然な範囲/カテゴリがない場合に、ホットスポットを回避し負荷を分散するために使用する。","steps":["理由: 行が均等に分散され、単一のパーティションや主キーの末尾に集中する書き込みのホットスポットが軽減される。","適用場面: 書き込み量が多く、自然な範囲/カテゴリがなく、I/O とサイズの均等化が目的の場合 (例: カーディナリティの高い id)。","パーティションキー: カーディナリティが高く均等に分布する列 (通常は主キー/一意キー) を選択する。","例: PostgreSQL HASH パーティショニング、Oracle ハッシュパーティショニング、MySQL PARTITION BY HASH/KEY。","注意: 範囲クエリにはプルーニングが効かない (ハッシュ化により順序が失われる)。「直近 N 日」のようなクエリはすべてのパーティションをスキャンする。後からパーティション数を変更するには再分散が必要。"],"related":[]},"sol_composite":{"kind":"solution","title":"推奨: Composite (多階層) パーティショニング","detail":"Composite パーティショニングは 2 つの戦略を組み合わせる: まず上位レベルで分割し、次に各パーティションをサブパーティションに分割する (例: Range-by-Hash や Range-by-List)。時間ベースのライフサイクルと、均等な分散/カテゴリの分離の両方が同時に必要な場合に使用する。","steps":["理由: 単一の戦略では不十分な場合に、両方のニーズを同時に満たす。例えば、月単位で分割し (アーカイブ)、月内ではハッシュで分散する (ホットスポット防止)。","適用場面: 非常に大規模な時系列 + 高い同時書き込み、または日付 + リージョン/テナントの二重のアクセスパターン。","例: Oracle コンポジット (range-hash、range-list、list-hash など)。PostgreSQL ではパーティションをさらにパーティショニングして手動で構築する (partition of partition)。MySQL のサブパーティション (RANGE/LIST + HASH/KEY)。","注意: 管理とスキーマの複雑さが最も高い選択肢。両方の次元が実証されたニーズである場合にのみ選択する。","注意: 上位/下位キーの選択を誤るとプルーニングが失われる。両方のレベルがクエリパターンに一致していることを確認する。"],"related":[]}}},"solver/decide-pooling.json":{"id":"decide-pooling","title":"判断: コネクションプーリングをどう構成するか?","icon":"🧭","category":"判断ガイド","intro":"データベース接続はそれぞれメモリとスケジューリングのコストを伴う。接続数が無秩序に増えるとサーバーが遅くなり、ダウンすることさえある。コネクションプールは、少数の永続的な接続を再利用することでこれを解決する。このツリーは、プールの配置場所、使用するモード (session/transaction/statement)、適切なサイズの判断を導き、サーバーレス環境で外部プーラーが必須である理由を強調する。","start":"root","nodes":{"root":{"kind":"step","title":"アプリケーションアーキテクチャはどのように接続するか?","detail":"プーリングの判断はアーキテクチャから始まる。単一の長時間稼働するアプリケーションプロセス (従来型サーバー) か、多数の独立したプロセス/インスタンス (マイクロサービス、多数の Pod) か、それともリクエストごとに生成・消滅するサーバーレス/Lambda 関数か? それぞれで異なるプール配置が必要。","choices":[{"label":"1 つ/少数の長時間稼働するアプリケーションプロセス","next":"sol_app_pool"},{"label":"多数のプロセス/インスタンス/Pod が同じ DB に接続する","next":"middleware"},{"label":"サーバーレス / Lambda / 短命な関数","next":"sol_serverless"},{"label":"まず適切なプールサイズの選び方を知りたい","next":"sol_size"}]},"middleware":{"kind":"step","title":"ミドルウェアのプーラーモードはどう選ぶべきか?","detail":"クライアントが多い場合、ミドルウェアのプーラー (PgBouncer、ProxySQL) が DB 上の接続数を低く保つ。ただし、プールモードはアプリケーションが使用する機能に依存する: セッションに紐づく状態 (プリペアドステートメント、一時テーブル、SET、アドバイザリロック、セッションレベルの機能) に依存しているか、それともすべてが単一のトランザクション内で完結するか?","choices":[{"label":"セッション状態に依存している (SET、一時テーブル、セッションのプリペアドステートメント)","next":"sol_session_mode"},{"label":"トランザクションは短く独立している。セッション状態は保持しない","next":"sol_txn_mode"}]},"sol_app_pool":{"kind":"solution","title":"推奨: アプリケーション内コネクションプール","detail":"1 つ/少数の長時間稼働するプロセスでは、アプリケーション内のプールライブラリ (HikariCP、Go の database/sql の組み込みプール、.NET のコネクションプーリング) でほとんどのニーズを満たせる。接続は一度開かれ、繰り返し再利用される。","steps":["理由: 接続の確立/切断のコストがなくなる。限定的で予測可能な接続数が DB を保護する。","適用場面: 従来型のモノリス、または少数のアプリケーションインスタンス。総接続需要が DB の容量を下回る場合。","例: Java HikariCP、.NET SqlConnection/Npgsql のプーリング、Node pg-pool、Python SQLAlchemy pool。","サイジングについて: プールサイズはコア数/ディスク数に基づいて決める (次の判断)。「多いほどよい」は当てはまらない。","注意: 各アプリケーションインスタンスはそれぞれ独自のプールを開く。インスタンス数 × プールサイズが DB の max_connections を超えてはならない。超える場合はミドルウェアのプーラーに移行する。"],"related":["connection-storm"]},"sol_size":{"kind":"solution","title":"推奨: プールを適切なサイズにする","detail":"プールは小さすぎても (リクエストが待機する) 大きすぎてもいけない。接続が多すぎると CPU のコンテキストスイッチとロック競合が発生し、スループットが低下する。サイズは際限なく増やす数値ではなく、コア数と I/O に基づく小さな数値。","steps":["出発点となる式: 一般的な出発点は プールサイズ ≈ (コア数 × 2) + 実効スピンドル数。SSD/多コアでは「コア数 × 2-4」程度が良い出発点。","小さく保つ理由: DB の実際の並列度はコア数で制限される。余分な接続はキューに並ぶだけで、コンテキストスイッチ/ロック競合によって全体を遅くする。","ルール: 数百の同時クライアントがある場合、解決策はプールを大きくすることではなく、小さなプールを素早く回転させること (短いトランザクション + キューイング)。","総数の上限: (アプリケーションインスタンス数 × プールサイズ) < DB の max_connections。スーパーユーザーとメンテナンス用の接続に余裕を残す。","注意: 式から始めても必ず測定する。待機時間、アクティブ接続数、キューの深さのメトリクスを使ってチューニングする。"],"related":["connection-storm"]},"sol_session_mode":{"kind":"solution","title":"推奨: セッションプールモード","detail":"セッションモードでは、クライアント接続はセッションが終了するまでバックエンドのサーバー接続に固定される。セッションレベルの状態 (SET、一時テーブル、アドバイザリロック、セッションのプリペアドステートメント) は保持されるが、接続の共有は最小限。","steps":["理由: セッション全体を通して状態の保持が必要なアプリケーションにとって唯一の安全なモード。DB に直接接続した場合と同じ動作になる。","適用場面: SET によるセッション変数、一時テーブル、LISTEN/NOTIFY、セッションレベルのプリペアドステートメント、アドバイザリロックを使用するアプリケーション。","例: PgBouncer pool_mode=session。ProxySQL ではセッションに依存するトラフィックを別にルーティングする。","注意: 接続の共有が少ないため、クライアントが多いと利点が小さくなる。可能であればアプリケーションをセッション状態に依存しない形にし、トランザクションモードへの移行を目指す。","エンジンの違い: PostgreSQL には PgBouncer。MySQL 側では ProxySQL が同様の動作を異なる方法で扱い、セッション変数には注意が必要。"],"related":["connection-storm"]},"sol_txn_mode":{"kind":"solution","title":"推奨: トランザクションプールモード","detail":"トランザクションモードでは、サーバー接続はトランザクションの間だけクライアントに貸し出され、トランザクション終了時にプールに戻る。そのため、数千のクライアントが DB 上のごく少数の実接続で動作できる。最も一般的な大規模向けモード。","steps":["理由: 接続がトランザクション単位で受け渡されるため共有度が最も高く、少ない DB 接続で多数のクライアントを支えられる。","適用場面: 短く独立したトランザクション。セッション状態を保持しない (または保持しないように作られた) マイクロサービス/マルチ Pod アーキテクチャ。","例: PgBouncer pool_mode=transaction (最も一般的な構成)、ProxySQL のデフォルトの多重化動作。","注意: セッションにまたがる機能は動作しなくなる: セッションレベルのプリペアドステートメント、一時テーブル、SET、アドバイザリロックは安全ではない。プロトコルレベルの名前付きプリペアドステートメントについては、アプリケーション/プーラーの互換性を確認する。","ステートメントモード: さらに積極的な (statement) モードは、文ごとに接続を受け渡す。トランザクションを使わない読み取り専用の非常に限られたシナリオでのみ検討され、制約が非常に大きい。"],"related":["connection-storm"]},"sol_serverless":{"kind":"solution","title":"推奨: サーバーレスには外部プーラーが必須","detail":"サーバーレス/Lambda 関数は急速にスケールし、各インスタンスが独自の接続を開く。インスタンスは短命で何も共有しないため、アプリケーション内プールはここでは役に立たない。数百/数千のインスタンスが突然起動すると、DB の接続上限を超えてしまう。解決策は DB の前段に置く外部コネクションプール。","steps":["理由: 短命で共有されない関数インスタンスでは、アプリケーション内プールを維持できない。スケールアウト時に接続のストームが発生する。","適用場面: AWS Lambda、Cloud Functions、Azure Functions など、リクエストごとにインスタンスを生成する環境。","例: 独立した層としての PgBouncer/ProxySQL、またはマネージドプーラー (例: AWS RDS Proxy、PostgreSQL 向けの Data API/外部プーラーサービス)。","モード: 通常はトランザクションプールモードが推奨される。関数コードはセッション状態に依存しない形にする。","注意: 関数ごとの同時実行数の上限 (reserved concurrency) も設定する。プーラーと DB の max_connections を合わせてサイジングしないと、プーラー自体がボトルネックになる。"],"related":["connection-storm"]}}},"solver/decide-cache.json":{"id":"decide-cache","title":"判断: どのキャッシュ戦略か?","icon":"🧭","category":"判断ガイド","intro":"キャッシュは頻繁に読み取られるデータをデータベースの前段の高速な層 (例: Redis) に保持し、レイテンシと DB の負荷を下げる。ただし、すべてのデータがキャッシュに適しているわけではなく、誤った無効化は古い/不正確なデータのリスクを生む。このツリーは、まずキャッシュが本当に必要かを確認し、その上で読み書きのパターンに基づいて cache-aside、read-through、write-through、write-behind の中から選択を支援し、スタンピードの防止も扱う。","start":"root","nodes":{"root":{"kind":"step","title":"ワークロードはどのような傾向か: 読み取り中心か、書き込み中心か?","detail":"キャッシュが最も効果を発揮するのは、同じデータが何度も読み取られ (読み取り中心)、頻繁に変更されない場合。まず全体的なパターンを把握する: データは頻繁に読まれ、まれにしか変更されないのか、常に更新されるのか、それともキャッシュを追加する価値があるかどうか確信がないのか?","choices":[{"label":"非常に読み取り中心で、データの変更は比較的まれ","next":"read_pattern"},{"label":"書き込みも多い。書き込まれたデータがすぐに/頻繁に読み取られる","next":"write_pattern"},{"label":"確信がない。本当にキャッシュが必要か?","next":"sol_no_cache"}]},"read_pattern":{"kind":"step","title":"キャッシュへのデータ投入は誰が担うべきか?","detail":"読み取り中心のシナリオでの重要な選択は、誰がキャッシュにデータを投入するか。アプリケーションがキャッシュを明示的に管理し、自ら DB にフォールバックすべきか (柔軟性が高い)、それともキャッシュ層がミス時にバックエンドの DB からデータを取得し、透過的に返すべきか?","choices":[{"label":"アプリケーションが明示的に管理する。柔軟性と制御性が欲しい","next":"sol_cache_aside"},{"label":"ミス時にキャッシュ層が DB から取得する (透過的)","next":"sol_read_through"}]},"write_pattern":{"kind":"step","title":"書き込み時は、一貫性と書き込み速度のどちらが優先か?","detail":"書き込みが多い場合、書き込まれたデータのキャッシュと DB 間の一貫性をどの程度にするかを決める必要がある。書き込みごとにキャッシュと DB を同時に更新して一貫性を保証すべきか (書き込みはやや遅くなる)、それとも書き込みをまずキャッシュに行い、バックグラウンドで非同期に DB へ反映すべきか (書き込みは非常に高速だが損失リスクがある)?","choices":[{"label":"一貫性が重要。読み取りは常に最新でなければならない","next":"sol_write_through"},{"label":"書き込み速度が重要。一貫性の多少の遅れと損失リスクは許容できる","next":"sol_write_behind"}]},"sol_no_cache":{"kind":"solution","title":"推奨: 現時点ではキャッシュを追加しない","detail":"キャッシュは無償ではない: 一貫性の問題 (古いデータ)、追加のインフラ、無効化の複雑さをもたらす。クエリがすでに高速な場合や、データがリクエストごとに変わる場合、キャッシュは利点をもたらさず、障害要因を増やすだけ。","steps":["理由: キャッシュは一貫性、無効化、運用のオーバーヘッドを加える。見返りがなければ純粋な損失になる。","不要な場面: インデックスによりクエリがすでに高速、データが読み取りごとに異なる/ユーザー固有で再利用されない、または書き込みが読み取りを大きく上回る場合。","代わりに: まずインデックス/クエリの最適化、マテリアライズドビュー、または DB 自体のバッファ/プランキャッシュ。","注意: 「念のため」にキャッシュを追加しないこと。測定された読み取りのボトルネックと再利用されるデータがない限り追加しない。","次のステップ: 実際の読み取りのホットスポットが実証されたら、cache-aside から始める。"],"related":["slow-query","high-cpu"]},"sol_cache_aside":{"kind":"solution","title":"推奨: cache-aside (遅延ロード)","detail":"cache-aside では、アプリケーションがまずキャッシュを確認し、データがない場合 (ミス) は DB から読み取ってキャッシュに書き込み、返す。最も一般的で柔軟なパターンであり、キャッシュには実際に要求されたデータのみが格納される。","steps":["理由: シンプルで柔軟、かつ耐障害性が高い。キャッシュが障害を起こしても、アプリケーションは DB にフォールバックして動作し続ける。要求されたデータのみがキャッシュされる。","適用場面: 汎用的な読み取りの高速化。読み取りが多く、書き込みは中程度。Redis/Memcached の典型的な使い方。","無効化: 書き込み時に関連するキーを更新または削除し (write-invalidate)、すべてのキーに妥当な TTL を設定して古さの上限を設ける。","例: Redis GET → ない場合は DB クエリ → SET key value EX <ttl>。","注意: 最初のリクエストは必ずミスになる (コールドスタート)。同じキーが多数のクライアントから同時に要求されると、キャッシュスタンピードが発生する可能性がある — スタンピードの防止 (次の項目) を参照。","スタンピード: 人気のあるキーが期限切れになると、数千のリクエストが一度に DB に殺到する。ロック/single-flight、早期リフレッシュ、またはジッター付きの TTL で防止する。"],"related":["high-cpu","slow-query"]},"sol_read_through":{"kind":"solution","title":"推奨: read-through キャッシュ","detail":"read-through では、アプリケーションはキャッシュとのみやり取りし、ミス時にはキャッシュ層自体が DB からデータを取得して投入する (プロバイダ/ローダー経由)。アプリケーションコードがシンプルになり、投入ロジックが 1 か所に集約される。","steps":["理由: 投入ロジックがキャッシュ層に集約され、アプリケーションコードは「あらゆる場所でミスを処理する」という繰り返しから解放される。","適用場面: 一貫したキャッシュアクセス層 (ライブラリ/サービス) を使用できる読み取り中心のワークロード。","例: キャッシュライブラリ/クライアント (例: ローダーを定義したローカルキャッシュや Redis の前段のアクセス層) がミス時に DB からロードする。","無効化: TTL と書き込み時の無効化は依然として必要。read-through だけでは鮮度は保証されない。","注意: cache-aside と非常によく似ており、違いは「誰が投入するか」。スタンピードのリスクはここにも存在するため、同じ対策を適用する。","エンジンに関する注記: Redis 自体は read-through を行わない。このパターンはアプリケーション/ライブラリ層が提供する。"],"related":["slow-query"]},"sol_write_through":{"kind":"solution","title":"推奨: write-through キャッシュ","detail":"write-through では、すべての書き込みがキャッシュと DB の両方に (同期的に) 行われ、両方が同時に更新される。そのため、キャッシュが DB より遅れることはなく、読み取りは常に最新のデータを参照する。","steps":["理由: キャッシュと DB の一貫性が保たれる。書き込まれたデータがすぐに読み取られる場合でも、古いデータを読むリスクがない。","適用場面: 書き込まれたデータがすぐに頻繁に読み取られ、強い読み取り一貫性が必要なシナリオ。","例: 書き込み時、アプリケーションはまず DB を更新し、直ちにキャッシュのキーを新しい値に設定する (または削除する)。","注意: すべての書き込みが 2 つの対象に行われるため、書き込みレイテンシが増加する。読まれることのないデータまで不必要にキャッシュされる場合もある。2 つの書き込みはアトミックではない (一方が成功し、もう一方が失敗する) ため、不整合を引き起こす可能性がある — エラー時はキャッシュのエントリを削除する。","二重書き込みの落とし穴: DB とキャッシュに別々に書き込むよりも、「DB に書き込み、キャッシュを削除 (無効化) する」アプローチのほうが通常は安全。"],"related":[]},"sol_write_behind":{"kind":"solution","title":"推奨: write-behind (write-back) キャッシュ","detail":"write-behind では、書き込みはまずキャッシュに行われ、直ちにユーザーに応答が返る。DB への書き込みはバックグラウンドで非同期に (バッチ化/遅延して) 行われる。書き込み速度は最も高いが、耐久性と一貫性のリスクを伴う。","steps":["理由: 書き込みレイテンシが大幅に低下し、書き込みをバッチ化して効率よく DB に転送できる。書き込み中心の負荷で DB の負担が軽減される。","適用場面: カウンタ、メトリクス、アクティビティフィードなど、一貫性の多少の遅れが許容できる非常に大量の書き込み。","例: Redis に書き込む → キュー/バックグラウンドワーカーが一定間隔でバッチ単位で DB にフラッシュする。","注意: DB に書き込む前にキャッシュノードがクラッシュすると、データは失われる。耐久性が必要な重要データには使用しないか、耐久性のあるキュー/AOF で保護する。","注意: DB はしばらく古い状態のままになり、DB を直接読み取る他のシステムは古いデータを参照する。一貫性の遅延と損失ウィンドウを意図的に受け入れる。"],"related":[]}}},"solver/decide-datatype.json":{"id":"decide-datatype","title":"判断: 適切なデータ型の選択","icon":"🧭","category":"判断ガイド","intro":"データ型の選択は、後から修正するのが最もコストの高い決定の 1 つ: 誤った型は誤った結果 (例: 金額に float)、領域の浪費、低速なクエリを生む。このツリーは、数値、テキスト、日付/時刻、キー (PK)、半構造化 (JSON)、カテゴリ (ENUM) の各フィールドに適切な型を導き、金額やキャラクタセットなどの典型的な落とし穴を強調する。","start":"root","nodes":{"root":{"kind":"step","title":"どのような種類のデータを格納するか?","detail":"適切な型はデータの性質によって決まる。フィールドはどのカテゴリに該当するか: 数値、テキスト、日付/時刻、テーブルの主キー、柔軟/半構造化 (JSON) データ、または限定されたカテゴリの集合か?","choices":[{"label":"数値 (数量、金額、測定値、カウンタ)","next":"numeric"},{"label":"テキスト (名前、説明、コード)","next":"sol_text"},{"label":"日付および/または時刻","next":"sol_datetime"},{"label":"主キー (PK) を設計している","next":"sol_pk"},{"label":"柔軟/ネスト/可変のフィールド (半構造化データ)","next":"sol_json"},{"label":"限定された既知のカテゴリの集合 (ステータス、種類、優先度)","next":"sol_enum"}]},"numeric":{"kind":"step","title":"数値は整数か小数か — そして金額か?","detail":"数値で最も重要な区別は正確性。値は整数 (数量、ID、カウンタ) か、小数か? 小数の場合、金額/財務上の金額か? 2 進浮動小数点 (FLOAT/DOUBLE) は丸め誤差を生じるため、金額や正確性が必要な場面では決して使用しない。","choices":[{"label":"整数 (数量、カウンタ、id)","next":"sol_integer"},{"label":"金額または正確な小数 (価格、残高、レート)","next":"sol_decimal"}]},"sol_integer":{"kind":"solution","title":"推奨: 整数 (SMALLINT / INT / BIGINT)","detail":"整数の場合、必要な範囲をカバーする最小の型を選ぶ。不必要に大きな型は領域とインデックスサイズを浪費する。ただし、カウンタ/PK など増加し得るフィールドでは、オーバーフローを防ぐために十分な幅が不可欠。","steps":["理由: 適切な幅により、ストレージとインデックス/メモリのフットプリントの両方が最適化され、演算も高速。","SMALLINT/INT の適用場面: 範囲が限られる場合 (年齢、数量、小さなカウンタ) は SMALLINT/INT で十分。","BIGINT の適用場面: 増加し続ける ID/カウンタや、行数が数十億に達し得る PK には BIGINT を選ぶ — INT のオーバーフローは本番障害の深刻な原因。","エンジンの違い: MySQL では INT UNSIGNED で範囲が 2 倍になる。PostgreSQL には UNSIGNED がないため、BIGINT に移行する。Oracle は NUMBER(p)、MSSQL は INT/BIGINT。","注意: 「大きくなるかもしれない」とあらゆる場所に BIGINT を使わないこと。ただし、増加する PK には最初から BIGINT を使うのが安価な保険。"],"related":[]},"sol_decimal":{"kind":"solution","title":"推奨: NUMERIC / DECIMAL — 金額には決して FLOAT を使わない","detail":"金額と正確な小数には固定小数点 (正確な) NUMERIC/DECIMAL を使用する。FLOAT/DOUBLE は 2 進浮動小数点であり、0.1 のような値を正確に格納できない。加算/乗算で端数のずれ、誤った残高、監査上の問題が生じる。","steps":["理由: NUMERIC/DECIMAL は値を 10 進数で正確に格納し、金額の演算で丸め誤差のない正しい結果が得られる。","適用場面: 価格、残高、税、レート、利息など、正確性が必要なすべてのフィールド。適切なスケールを指定する: DECIMAL(precision, scale)、例: 金額には DECIMAL(19,4)。","代替案: 金額を最小単位 (セント) で BIGINT として格納するシステムもある。これも完全な正確性が得られる。","エンジンの違い: PostgreSQL NUMERIC、MySQL DECIMAL、Oracle NUMBER(p,s)、MSSQL DECIMAL/MONEY (MONEY の制約に注意)。","注意: FLOAT/DOUBLE は科学的/測定による近似値と、正確性よりパフォーマンスが優先される場合に限る — 金額には決して使わない。"],"related":[]},"sol_text":{"kind":"solution","title":"推奨: テキスト — VARCHAR vs TEXT vs CHAR","detail":"テキストには、可変長には VARCHAR/TEXT を、真の固定長には CHAR を使用する。最新のエンジンでは VARCHAR と TEXT のストレージ上の違いはほとんど無視できる。本当の判断は、意味上の上限 (長さ制約) を課すかどうか。","steps":["VARCHAR(n): 長さが可変で妥当な上限がある場合 (例: メールアドレス、名前) は VARCHAR(n) を使用する — 上限はデータ検証の手段になる。","TEXT: 長さが予測できない長い自由記述 (説明、本文) には TEXT を使用する。","CHAR(n): 真の固定長 (例: 国コード 'TR'、常に 2 文字) にのみ使用する。短いテキストでは CHAR は末尾を空白で埋めるため、通常は不要。","エンジンの違い: PostgreSQL では VARCHAR と TEXT のパフォーマンスは同じで、上限は制約にすぎない。MySQL では VARCHAR は行内に格納され、TEXT は別に格納される場合があり、インデックス作成にはプレフィックスの上限がある。Oracle では VARCHAR2 を使用する。","キャラクタセット/照合順序: 絵文字と完全な Unicode には、MySQL では必ず utf8mb4 を使用する (古い 'utf8' は 3 バイトで絵文字が壊れる)。照合順序 (例: utf8mb4_0900_ai_ci) はソート/比較の要件に応じて選択する。PostgreSQL では通常、UTF-8 データベース + 適切な照合順序。"],"related":[]},"sol_datetime":{"kind":"solution","title":"推奨: 日付/時刻 — タイムゾーン付き TIMESTAMP","detail":"時点 (イベントの時刻) を格納する場合は、タイムゾーンを考慮する型を選択する。タイムゾーンなしで格納すると、リージョン間/夏時間の切り替え時に計算と比較を誤る。","steps":["理由: タイムゾーンを考慮する型は時点を UTC に正規化し、一貫した比較と変換を提供する。グローバルなシステムには不可欠。","TIMESTAMPTZ の適用場面: PostgreSQL でのイベント/トランザクションの時点には TIMESTAMP WITH TIME ZONE (timestamptz) を使用する。UTC で格納し、表示時にユーザーのタイムゾーンに変換する。","日付または時刻のみ: 暦日には DATE、タイムゾーンに関係しない時刻には TIME、期間には INTERVAL (サポートするエンジンの場合)。","エンジンの違い: PostgreSQL timestamptz (実際には UTC で格納する)。MySQL では TIMESTAMP はタイムゾーンに応じて変換されるが範囲が限られる (2038)。DATETIME は変換されない — アプリケーションで UTC 格納の規律を徹底する。Oracle TIMESTAMP WITH TIME ZONE、MSSQL DATETIMEOFFSET。","注意: 時刻をテキスト (VARCHAR) やエポックの INT として格納すると、ソート、範囲、タイムゾーンの操作が正しく行えない。本物の日付/時刻型を使用する。"],"related":[]},"sol_pk":{"kind":"solution","title":"推奨: 主キー — BIGINT vs UUID","detail":"PK には主に 2 つの選択肢がある: 増加する数値 (BIGINT の identity/シーケンス) または UUID。数値の PK は小さくインデックスに適しているが、予測可能で集中的な採番が必要。UUID は分散して生成できるが、サイズが大きく、ランダムな順序がインデックスに悪影響を与える場合がある。","steps":["BIGINT (増加): 最小かつ最速のインデックス。連続した挿入は B-tree に最適。単一 DB/集中採番でのデフォルトの選択。最初から INT ではなく BIGINT にしておけばオーバーフローに対して安全。","UUID: クライアント/分散システムで衝突なく生成でき、ID を公開してもシーケンス番号が露呈しない。ただし 16 バイト (2×BIGINT) を占める。","UUID の順序が重要: 完全にランダムな UUID (v4) は連続していないため、インデックスへの挿入が分散する (ページ分割、低いキャッシュヒット率)。時系列順の UUID (v7/ULID) はこれをほぼ解消する。","エンジンの違い: PostgreSQL にはネイティブの uuid 型がある。MySQL では UUID を (テキストの CHAR(36) ではなく) BINARY(16) として格納し、可能な場合は順序付きで生成する。MSSQL は uniqueidentifier + NEWSEQUENTIALID、Oracle は RAW(16)。","注意: UUID を VARCHAR/CHAR(36) のテキストとして格納すると、領域とインデックスサイズがおよそ 2〜3 倍になる。バイナリとして格納する。"],"related":[]},"sol_json":{"kind":"solution","title":"推奨: JSON / JSONB — 適度に使用する","detail":"JSON 型は、柔軟なスキーマを持つフィールド、ネストしたフィールド、疎なフィールドに対して強力。ただし、リレーショナルの規律 (制約、インデックス、型安全性) が失われる場合がある。ルール: 固定的で頻繁に照会されるフィールドは通常の列に移し、本当に可変な部分のみを JSON に保持する。","steps":["理由: 可変/任意のフィールドを単一の列に柔軟に格納できる。スキーママイグレーションなしでフィールドを追加できる。","適用場面: 外部 API のペイロード、ユーザー定義フィールド、製品属性など、予測できない構造。","エンジンの違い: PostgreSQL では JSONB (バイナリ、インデックス可能、GIN による @>/? クエリ) を使用する — 単なる JSON よりも優先する。MySQL の JSON 型もバイナリで、生成列 + インデックスで照会する。Oracle 21c+ には JSON 型/OSON がある。2025 より前の MSSQL は JSON を NVARCHAR に保持して関数で処理する。SQL Server 2025 と Azure SQL にはネイティブ (バイナリ) の json 型がある。","注意: 頻繁にフィルタされる JSON フィールドにはインデックスを作成する (PostgreSQL GIN、MySQL 生成列インデックス)。そうしないと、すべてのクエリがドキュメント全体をスキャンする。","注意: すべてを JSON に詰め込まないこと — リレーショナルの整合性、外部キー、型付けが失われる。クエリ/制約が必要なフィールドは本物の列にすべき。"],"related":["decide-sqlnosql"]},"sol_enum":{"kind":"solution","title":"推奨: ENUM vs ルックアップ (参照) テーブル","detail":"限定されたカテゴリの集合には 2 つの選択肢がある: エンジンの ENUM 型、またはルックアップテーブル + 外部キー。ENUM はコンパクトでシンプルだが、値の追加にはスキーマ変更が必要。ルックアップテーブルは柔軟で、追加の属性 (説明、有効フラグ、表示順) を持たせられる。","steps":["ENUM の適用場面: 値が非常に安定していてまれにしか変わらず (例: 性別、曜日)、追加の属性が不要な場合。コンパクトで読みやすい。","ルックアップテーブルの適用場面: 値が時間とともに変わる可能性がある場合、翻訳/説明/表示順/有効フラグなどの追加フィールドが必要な場合、またはレポートで結合する場合 — より柔軟。","エンジンの違い: PostgreSQL と MySQL はネイティブの ENUM 型を提供する (PostgreSQL では ENUM への値の追加に ALTER TYPE が必要で、順序は定義順に従う)。Oracle と MSSQL には組み込みの ENUM がないため、CHECK 制約またはルックアップテーブルを使用する。","注意: ENUM の値の追加/削除はスキーママイグレーションであり、大きなテーブルではロック/コストが発生する可能性がある。頻繁に変わる集合にはルックアップテーブルを優先する。","代替案: 小さく安定した集合には、自由テキスト + CHECK 制約も実用的な中間案。"],"related":[]}}},"solver/decide-capacity.json":{"id":"decide-capacity","title":"判断: サーバーのサイジング","icon":"🧭","category":"判断ガイド","intro":"適切なサイジングはワークロードのプロファイル (OLTP、データウェアハウス、混合) から始まり、実際のボトルネック (CPU、I/O、RAM) を特定する必要がある。鉄則: 頻繁にアクセスされるデータセット (ワーキングセット) が RAM に収まること。まず測定し、次にスケールし、急な負荷に備えて余裕を残す。このツリーは、ワークロードを特定し、ボトルネックに基づいてリソースとスケーリングの方向 (垂直/水平) を選択するのに役立つ。","start":"root","nodes":{"root":{"kind":"step","title":"ワークロードのプロファイルは?","detail":"OLTP と分析の負荷ではまったく異なるリソースプロファイルが必要なため、サイジングはワークロードから始まる。システムの主な処理は何か: 多数の小さく高速なトランザクション (OLTP)、大規模なスキャンと集計を伴うレポート/分析 (DWH)、またはその両方の混合か? 確信がない場合は、まず測定する必要がある。","choices":[{"label":"OLTP — 多数の小さく短いトランザクション (Web/アプリケーション)","next":"bottleneck"},{"label":"分析 / データウェアハウス (DWH) — 大規模なスキャンと集計","next":"sol_dwh"},{"label":"混合ワークロード、または確信がない","next":"sol_measure"},{"label":"ボトルネックは分かっている。垂直と水平のどちらでスケールすべきか?","next":"sol_scale"}]},"bottleneck":{"kind":"step","title":"ボトルネックはどこか: RAM、I/O、CPU?","detail":"OLTP では、やみくもにリソースを追加するのではなく、実際のボトルネックを特定する。メトリクスを確認する: 頻繁にアクセスされるデータが RAM に収まらずディスク読み取りが多い (RAM/I/O) のか、ディスクのレイテンシ/IOPS が不足している (I/O) のか、それともデータはすでにメモリ上にあるが CPU が飽和している (CPU) のか? 誤ったリソースをスケールすると、費用と時間を無駄にする。","choices":[{"label":"頻繁にアクセスされるデータが RAM に収まらず、ディスク読み取りが多い","next":"sol_ram"},{"label":"データはメモリ上にあるが、ディスクのレイテンシ/IOPS が不足している (書き込み中心)","next":"sol_io"},{"label":"データはメモリ上にあり、ディスクも問題ないが、CPU が常に飽和している","next":"sol_cpu"}]},"sol_measure":{"kind":"solution","title":"推奨: まず測定し、次にサイジングする","detail":"推測に基づいてハードウェアを購入すると、ほぼ必ず誤ったサイズになる。ワークロードのプロファイルとボトルネックは実際のメトリクスから明らかになる。サイジングは推測ではなく、測定に基づく反復作業。","steps":["理由: OLTP か DWH か、ボトルネックが CPU、I/O、RAM のいずれかは、実際の負荷の下で測定して初めて明確になる。推測は高くつく間違い。","測定項目: CPU 使用率とランキュー、メモリ/キャッシュヒット率 (buffer cache hit)、ディスクの IOPS とレイテンシ、アクティブ接続数と待機イベント。","エンジンのツール: PostgreSQL pg_stat_* と待機イベント、Oracle AWR/ASH、MySQL Performance Schema、MSSQL DMV と待機統計。","アプローチ: 代表的な負荷でテストし、最も逼迫しているリソースを特定し、そのリソースのみをスケールして再測定する。効果を切り分けられるよう、一度に変更するリソースは 1 つにする。","次のステップ: プロファイルが明確になったら、該当する判断 (OLTP のボトルネック、DWH、または水平/垂直スケーリング) に進む。"],"related":["high-cpu","memory-pressure","slow-query"]},"sol_ram":{"kind":"solution","title":"推奨: RAM を追加する — ワーキングセットはメモリに収める必要がある","detail":"OLTP で最も重要なルール: 頻繁にアクセスされるデータとインデックス (ワーキングセット) がメモリ (バッファ/キャッシュ) に収まること。収まらなければ、すべてのクエリがディスクにアクセスし、レイテンシが急増し、I/O がボトルネックになる。通常、RAM は最も投資効果の高い対象。","steps":["理由: メモリからの読み取りはディスクより数百〜数千倍高速。ワーキングセットが RAM に収まればキャッシュヒット率が上がり、ディスク I/O は激減する。","適用場面: キャッシュヒット率が低い、'disk read' の待機イベントが頻発する、アクティブなデータセットが利用可能な RAM より大きい場合。","方法: DB のメモリ領域を適切にサイジングする — PostgreSQL shared_buffers + OS ページキャッシュ、MySQL innodb_buffer_pool_size (通常は RAM の大部分)、Oracle SGA/buffer cache、MSSQL max server memory。","目標: 理想はワーキングセット + インデックスがメモリに収まること。すべてが収まらない場合でも、少なくとも最も頻繁にアクセスされる「ホットな」部分は収める必要がある。","注意: 物理 RAM のすべてを buffer pool に割り当てないこと。OS、接続ごとのメモリ、他のプロセスのための領域を残す。そうしないとスワップによって全体が遅くなる。"],"related":["memory-pressure","slow-query"]},"sol_io":{"kind":"solution","title":"推奨: I/O 層を強化する (IOPS/レイテンシ)","detail":"データがメモリ上にあっても、書き込み中心の負荷 (commit、WAL/redo/binlog、checkpoint) ではディスクの速度が決定的。ここでの問題は容量ではなく、IOPS とレイテンシ。誤ったディスククラスは、CPU/RAM が高速でもシステムを行き詰まらせる。","steps":["理由: 耐久性のため、すべてのコミットがログをディスクに書き込む。IOPS が低い/レイテンシが高いディスクは、トランザクションのスループットを直接制限する。","適用場面: ディスクのレイテンシが高い、'log/WAL write' の待機が長い、checkpoint 中のボトルネック、書き込み集約型の OLTP。","方法: NVMe/SSD を使用する。トランザクションログをデータファイルとは別の高速なディスクに移す。クラウドでは、十分なプロビジョニング IOPS/スループットを持つディスククラスを選択する (例: provisioned IOPS)。","目標: IOPS とレイテンシの両方の目標を設定する — IOPS だけでなく p99 レイテンシも重要。RAID/ライトキャッシュ (BBU) で書き込みレイテンシを低減できる。","注意: クラウドでは、ディスクのスループットと IOPS がインスタンスサイズにも依存することが多い。ネットワーク接続ディスクのレイテンシはローカル NVMe より高い。"],"related":["disk-full","slow-query"]},"sol_cpu":{"kind":"solution","title":"推奨: CPU のボトルネックを解消する (まずクエリ、次にコア)","detail":"データがメモリ上にありディスクも問題ないのに CPU が飽和している場合、根本原因は通常、非効率なクエリ (不適切な実行計画、不足しているインデックス、多数の小さなクエリ) または過剰な同時実行。コアを追加する前に負荷を減らすほうが、通常は安価で効果的。","steps":["理由: CPU を最も消費するのは、フルスキャン、ソート/ハッシュ、実行計画のコンパイル、多すぎる接続によるコンテキストスイッチ。これらを修正するほうがコアを追加するより安価。","まず最適化: 最も高コストなクエリを特定し (pg_stat_statements / AWR / Performance Schema)、不足しているインデックスを追加し、N+1 クエリを減らし、コネクションプールを縮小する。","次にスケール: クエリが健全でも CPU が飽和している場合は、コア数を増やす (垂直) — 特に同時実行数の高い OLTP。","エンジンに関する注記: 接続が多い = コンテキストスイッチが多い。素早く回転する小さなプールが、コアを増やすより効果的なことが多い (コネクションプールの判断を参照)。","注意: ライセンスがコア単位 (Oracle/MSSQL) の場合、コアの追加は高価。まずクエリを最適化することでコストを抑えられる。"],"related":["high-cpu","slow-query"]},"sol_dwh":{"kind":"solution","title":"推奨: 分析/DWH — スループット、並列処理、水平スケール","detail":"データウェアハウスのワークロードは、大きなテーブルをスキャンして集計する少数の重いクエリで構成される。ここでの優先事項は低レイテンシではなく、高いスキャンスループット、並列処理、そして通常は水平スケール可能なアーキテクチャ。","steps":["理由: クエリはテラバイト単位をスキャンする。個々のトランザクションのレイテンシではなく、ディスク/メモリの帯域幅と並列に動作するコアが決定的。","方法: 高い I/O スループットを持つストレージ、十分な RAM (集計/ハッシュ結合用)、多数のコアとパラレルクエリ。大規模では列指向ストアや MPP アーキテクチャが非常に効率的。","水平スケール: 大規模な DWH では、単一マシンの増強よりも分散/MPP (例: シャーディングされた分析エンジン) のほうが通常はスケールしやすい。パーティショニング + パーティションプルーニングでスキャン量を削減する。","エンジンに関する注記: OLTP の設定を流用しないこと — DWH では、より大きな work_mem/ソート領域、より高い並列度、大きなブロック/先読みが推奨される。","注意: OLTP と DWH を同じサーバーで混在させないこと。重いレポートが OLTP を圧迫する。可能であれば分析を別のレプリカ/データウェアハウスに移す。"],"related":["decide-shard-replica","decide-partition"]},"sol_scale":{"kind":"solution","title":"一般原則: 垂直 vs 水平 + 余裕 + まず測定","detail":"どのリソースをスケールするかと同じくらい、どのようにスケールするかが重要。垂直 (より大きなマシン) はシンプルだが上限と単一障害点がある。水平 (より多くのマシン) はスケールするが複雑さが増す。いずれの場合も、急な負荷に備えて余裕を残し、測定によって判断を検証する。","steps":["垂直 (スケールアップ): 単一マシンのリソース (CPU/RAM/IO) を増強する — 最もシンプルな選択肢で、ほとんどの OLTP にとって最初のステップ。ただし物理的/コスト的な上限と単一障害点がある。","水平 (スケールアウト): リードレプリカ (読み取り負荷向け) またはシャーディング (書き込み/データ量向け) を追加する — ほぼ無制限にスケールできるが、一貫性と運用の複雑さを伴う。","余裕: リソースを 100% で計画しないこと。通常のピーク負荷時に ~30% の余裕を残し、急なスパイク、メンテナンス、増加に対応できるようにする。","まず測定: スケールする前に測定によってボトルネックを確認し、最も逼迫しているリソースを対象にし、変更後に再測定する。","注意: 水平スケーリングはすべての問題を解決するわけではない — 分散トランザクションと結合は高コスト。垂直スケーリングと最適化を尽くしてから切り替える。"],"related":["decide-shard-replica","decide-ha"]}}},"solver/slow-write.json":{"id":"slow-write","title":"書き込みが遅い (INSERT/UPDATE のレイテンシ)","icon":"🐢","category":"パフォーマンス","intro":"INSERT/UPDATE/DELETE の操作が想定より遅い。まず書き込みが何を待っているか (commit/redo、ロック、ディスク、行ごとのオーバーヘッド) を特定し、段階的に根本原因まで掘り下げる。","start":"root","nodes":{"root":{"kind":"step","title":"書き込みは何を待っているか?","detail":"待機イベントを見てボトルネックを分類する: 支配的なのは commit/redo (WAL) の同期か、ロックか、ディスクの書き込みレイテンシか、それとも行ごとのインデックス/トリガーのオーバーヘッドか?","command":{"oracle":"SELECT event, total_waits, ROUND(time_waited/100,1) AS sec_waited\nFROM v$system_event\nWHERE event IN ('log file sync','log file parallel write','enq: TX - row lock contention','db file sequential read')\nORDER BY time_waited DESC;","postgres":"SELECT wait_event_type, wait_event, count(*) AS sessions\nFROM pg_stat_activity\nWHERE state='active'\nGROUP BY 1,2 ORDER BY 3 DESC;","mysql":"SHOW GLOBAL STATUS LIKE 'Innodb_row_lock_waits';\nSHOW GLOBAL STATUS LIKE 'Innodb_os_log_pending_fsyncs';\nSHOW ENGINE INNODB STATUS\\G","mssql":"SELECT TOP 10 wait_type, waiting_tasks_count, wait_time_ms\nFROM sys.dm_os_wait_stats\nWHERE wait_type IN ('WRITELOG','PAGEIOLATCH_EX','LCK_M_X','LCK_M_U')\nORDER BY wait_time_ms DESC;"},"choices":[{"label":"commit / redo (WAL 同期) を待機している","next":"commit"},{"label":"ロックを待機している","next":"lock"},{"label":"行ごとのオーバーヘッド (インデックス/トリガー) が疑われる","next":"overhead"},{"label":"ディスクの書き込みレイテンシが高い","next":"sol_disk"}]},"commit":{"kind":"step","title":"コミットのパターンか、fsync か?","detail":"行ごとに個別にコミットする (autocommit) と、行数と同じ回数だけ redo/ログの同期が発生する。逆に、コミット回数は妥当でも各コミットが fsync を待っている場合、問題はログディスクのレイテンシ。","command":{"oracle":"SELECT name, value FROM v$sysstat WHERE name IN ('user commits','redo writes','redo size');\nSELECT ROUND(time_waited_micro/GREATEST(total_waits,1)/1000,2) AS ms_per_sync FROM v$system_event WHERE event='log file sync';","postgres":"SHOW synchronous_commit;\nSELECT wal_records, wal_fpi, wal_bytes, wal_buffers_full FROM pg_stat_wal; -- wal_sync/wal_sync_time PG14-17; PG18+: pg_stat_io (object = 'wal')","mysql":"SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit';\nSHOW VARIABLES LIKE 'sync_binlog';\nSHOW GLOBAL STATUS LIKE 'Com_commit';","mssql":"SELECT io_stall_write_ms, num_of_writes, io_stall_write_ms/NULLIF(num_of_writes,0) AS ms_per_write\nFROM sys.dm_io_virtual_file_stats(DB_ID(), 2);"},"choices":[{"label":"autocommit / 行ごとのコミット","next":"sol_batch"},{"label":"コミットがログの同期 (fsync) を待機している","next":"sol_disk"}]},"lock":{"kind":"step","title":"誰がロックを保持しているか?","detail":"書き込みがロックを待機している場合: 別のセッションが同じ行/インデックスを保持しているか、多数のセッションが同じ「ホットな」行に書き込もうとしている可能性がある。","command":{"oracle":"SELECT s.sid, s.serial#, s.username, s.blocking_session, s.event, s.seconds_in_wait\nFROM v$session s WHERE s.blocking_session IS NOT NULL;","postgres":"SELECT pid, pg_blocking_pids(pid) AS blocked_by, wait_event, left(query,60) AS query\nFROM pg_stat_activity\nWHERE cardinality(pg_blocking_pids(pid)) > 0;","mysql":"SELECT requesting_engine_transaction_id AS waiter, blocking_engine_transaction_id AS blocker,\n       object_name, lock_type, lock_mode\nFROM performance_schema.data_lock_waits w\nJOIN performance_schema.data_locks l ON l.engine_lock_id = w.blocking_engine_lock_id;","mssql":"SELECT session_id, blocking_session_id, wait_type, wait_time, wait_resource\nFROM sys.dm_exec_requests\nWHERE blocking_session_id <> 0;"},"choices":[{"label":"別のセッションがロックを保持している","next":"sol_lock"},{"label":"多数のセッションが同じホットな行に書き込んでいる","next":"sol_hotrow"}]},"overhead":{"kind":"step","title":"行ごとのオーバーヘッドはどこから来ているか?","detail":"すべての INSERT/UPDATE は、テーブル上のすべてのインデックスも更新し、トリガー/制約があれば起動する。インデックスが多すぎたり、重いトリガーがあったりすると、書き込みが大幅に遅くなる。","command":{"oracle":"SELECT index_name, uniqueness FROM user_indexes WHERE table_name='T';\nSELECT trigger_name, triggering_event FROM user_triggers WHERE table_name='T';","postgres":"SELECT indexname, indexdef FROM pg_indexes WHERE tablename='t';\nSELECT tgname FROM pg_trigger WHERE tgrelid='t'::regclass AND NOT tgisinternal;","mysql":"SHOW INDEX FROM t;\nSHOW TRIGGERS LIKE 't';","mssql":"SELECT name, type_desc FROM sys.indexes WHERE object_id=OBJECT_ID('dbo.t');\nSELECT name, is_disabled FROM sys.triggers WHERE parent_id=OBJECT_ID('dbo.t');"},"choices":[{"label":"テーブルのインデックスが多すぎる / 不要なインデックスがある","next":"sol_index"},{"label":"重いトリガーまたは制約のコストがある","next":"sol_trigger"}]},"sol_batch":{"kind":"solution","title":"根本原因: autocommit / 行ごとのコミット","detail":"行ごとに個別にコミットすると、行数と同じ回数だけ redo/ログの同期が繰り返される。操作をまとめることで、コミット (つまり fsync) の回数を劇的に減らせる。","steps":["アプリケーションで autocommit を無効化し、N 行ごと (例: 500-5000) にコミットするバッチコミットを適用する。","単一行の INSERT ではなく、複数行の INSERT / バルクロードの手段を使用する (Postgres COPY、Oracle bulk insert、MySQL LOAD DATA、MSSQL BULK INSERT)。","プリペアドステートメントを使用して、繰り返しの解析 (ハードパース) のコストを削減する。","変更後、'log file sync' / WRITELOG の待機が減少したことを確認する。"],"related":["active-sessions"]},"sol_disk":{"kind":"solution","title":"根本原因: 低速な redo/ログディスク (fsync のレイテンシ)","detail":"すべてのコミットは、redo/WAL レコードが永続ストレージに書き込まれる (fsync) まで待機する。ログディスクが低速 (書き込みレイテンシが高い、IOPS が不足) だと、すべてのコミットがそのレイテンシを負う。","steps":["ログ/redo ファイルを専用の低レイテンシディスク (できれば NVMe SSD) に移し、データファイルとは物理的に分離する。","ストレージのレイテンシを測定する (ファイル I/O 統計)。書き込みあたりの ms が高い場合は、ハードウェア/RAID のライトキャッシュを見直す。","仮想/クラウド環境では、プロビジョニング IOPS とスループットの上限を引き上げる。","耐久性の要件が許す場合は、グループコミット / コミット遅延の設定 (例: Postgres commit_delay) を検討する。ただし、データ損失のリスクを考慮する。"],"related":[]},"sol_lock":{"kind":"solution","title":"根本原因: 別のセッションがロックを保持している","detail":"書き込みが、別のセッションが保持する行/インデックスのロックを待機している。ブロッカーは通常、長時間実行中のトランザクションか、コミットし忘れたトランザクション。","steps":["ブロッカーのセッションを特定し、何をしているかを調べる (長時間のバッチか、idle in transaction か?)。","ブロッカーが理由もなく開いたまま/長時間続いている場合は、アプリケーションの commit/rollback のパターンを修正する。","緊急時は、ブロッカーを制御された方法で終了する (kill session / pg_terminate_backend / KILL)。","トランザクションは短く保ち、トランザクション内でユーザーの操作を待たないこと。"],"related":["blocking-sessions","current-locks"]},"sol_hotrow":{"kind":"solution","title":"根本原因: ホットな行の競合","detail":"多数のセッションが同じ行 (例: カウンタ、シーケンス番号、残高) に書き込もうとしている。全セッションが同じロックを待つキューに並び、書き込みが直列化される。","steps":["ホットなカウンタのパターンでは、値を並列のバケットに分割し (sharded counter)、読み取り時に合計する。","シーケンス/ID の採番を、集中的な単一行から sequence/identity の仕組みに移す。","更新頻度を減らす: 累計値をアプリケーションでバッファリングし、定期的に書き込む。","操作の順序を標準化し、ロックの保持時間を短縮して競合を減らす。"],"related":["current-locks"]},"sol_index":{"kind":"solution","title":"根本原因: 過剰なインデックスのオーバーヘッド","detail":"テーブル上のすべてのインデックスは書き込みのたびに更新される。インデックスが多い、または未使用のインデックスがあると、INSERT/UPDATE が直接遅くなる。","steps":["未使用/重複したインデックスを特定し (使用統計)、安全に削除する。","幅の広い複合インデックスを簡素化し、同じ先頭列を繰り返すインデックスを統合する。","大規模なバルクロードでは、インデックスを一時的に無効化し、ロード後に再構築することを検討する。","変更後、書き込みレイテンシを再測定し、改善を確認する。"],"related":["slow-queries"]},"sol_trigger":{"kind":"solution","title":"根本原因: 重いトリガー / 制約","detail":"書き込みごとに起動するトリガーや、検証される制約 (特にインデックスのない外部キーのチェック) は、すべての行に追加のコストを加える。","steps":["トリガー本体の重い処理 (例: 同期的なログ書き込み) を非同期/キューベースにする。","参照側 (子) の外部キー列にインデックスを作成する。そうしないと、親での DELETE/UPDATE のたびに子テーブルがフルスキャンされる。","可能であれば、行レベルのトリガーを文レベルに移す。","不要なトリガーロジックや業務ルール化したロジックをアプリケーション層に移す。"],"related":[]}}},"solver/io-bottleneck.json":{"id":"io-bottleneck","title":"高い IO 待機 / ディスクのレイテンシ","icon":"💽","category":"パフォーマンス","intro":"システムがディスク IO を待機している。まず負荷が読み取り中心か書き込み中心かを切り分け、その上で原因 (バッファキャッシュの不足、フルテーブルスキャン、checkpoint ストーム、IOPS の上限、一時領域へのスピル) まで掘り下げる。","start":"root","nodes":{"root":{"kind":"step","title":"IO は読み取り中心か、書き込み中心か?","detail":"ファイル IO 統計を使って、待機が読み取り側 (ディスクからのデータ読み取り) か書き込み側 (redo/checkpoint/データの書き込み) かを判断する。これでツリーが 2 つに分かれる。","command":{"oracle":"SELECT function_name, small_read_reqs+large_read_reqs AS reads, small_write_reqs+large_write_reqs AS writes,\n       small_read_megabytes+large_read_megabytes+small_write_megabytes+large_write_megabytes AS mb\nFROM v$iostat_function ORDER BY mb DESC;","postgres":"SELECT sum(blks_read) AS reads, sum(blks_hit) AS hits FROM pg_stat_database;\nSELECT buffers_checkpoint, buffers_clean, buffers_backend FROM pg_stat_bgwriter;","mysql":"SHOW GLOBAL STATUS LIKE 'Innodb_data_read';\nSHOW GLOBAL STATUS LIKE 'Innodb_data_written';\nSHOW GLOBAL STATUS LIKE 'Innodb_data_reads';","mssql":"SELECT DB_NAME(database_id) AS db, io_stall_read_ms, io_stall_write_ms, num_of_reads, num_of_writes\nFROM sys.dm_io_virtual_file_stats(NULL, NULL)\nORDER BY io_stall_read_ms + io_stall_write_ms DESC;"},"choices":[{"label":"主に読み取り IO","next":"read"},{"label":"主に書き込み IO","next":"write"}]},"read":{"kind":"step","title":"なぜ読み取り IO が高いのか?","detail":"過剰な物理読み取りには主に 3 つの原因がある: バッファキャッシュが小さすぎる (ワーキングセットが RAM に収まらない)、クエリがフルテーブルスキャンを行っている、または大規模なソート/ハッシュ操作が一時領域にスピルしている。","command":{"oracle":"SELECT ROUND((1-(pr.value/(dbg.value+cg.value)))*100,2) AS buffer_hit_pct\nFROM v$sysstat pr, v$sysstat dbg, v$sysstat cg\nWHERE pr.name='physical reads' AND dbg.name='db block gets' AND cg.name='consistent gets';\nSELECT sql_id, disk_reads, executions FROM v$sql ORDER BY disk_reads DESC FETCH FIRST 10 ROWS ONLY;","postgres":"SELECT ROUND(sum(blks_hit)*100.0/nullif(sum(blks_hit)+sum(blks_read),0),2) AS cache_hit_pct FROM pg_stat_database;\nSELECT query, shared_blks_read, temp_blks_read FROM pg_stat_statements ORDER BY shared_blks_read DESC LIMIT 10;","mysql":"SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read_requests';\nSHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_reads';\nSHOW GLOBAL STATUS LIKE 'Created_tmp_disk_tables';","mssql":"SELECT CAST(100.0 * a.cntr_value / NULLIF(b.cntr_value, 0) AS decimal(5,2)) AS buffer_cache_hit_ratio\nFROM sys.dm_os_performance_counters a\nJOIN sys.dm_os_performance_counters b ON b.object_name = a.object_name AND b.counter_name = 'Buffer cache hit ratio base'\nWHERE a.counter_name = 'Buffer cache hit ratio' AND a.object_name LIKE '%Buffer Manager%';"},"choices":[{"label":"バッファキャッシュヒット率が低く、ワーキングセットが収まらない","next":"sol_cache"},{"label":"クエリがフルテーブルスキャンを行っている","next":"sol_scan"},{"label":"大規模なソート/ハッシュが一時領域にスピルしている","next":"sol_spill"}]},"write":{"kind":"step","title":"なぜ書き込み IO が高いのか?","detail":"書き込み側のボトルネックは、定期的な checkpoint/フラッシュが一時的にディスクを飽和させる (checkpoint ストーム) か、ストレージに負荷を維持するだけの IOPS/スループットがないことに起因する。","command":{"oracle":"SELECT event, total_waits, ROUND(time_waited/100,1) AS sec\nFROM v$system_event\nWHERE event IN ('log file parallel write','db file parallel write','checkpoint completed')\nORDER BY time_waited DESC;","postgres":"-- PG17+:\nSELECT num_timed, num_requested, buffers_written FROM pg_stat_checkpointer;\n-- PG16 and earlier:\nSELECT checkpoints_timed, checkpoints_req, buffers_checkpoint, maxwritten_clean\nFROM pg_stat_bgwriter;\nSHOW checkpoint_completion_target;","mysql":"SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';\nSHOW GLOBAL STATUS LIKE 'Innodb_os_log_written';\nSHOW ENGINE INNODB STATUS\\G","mssql":"SELECT cntr_value FROM sys.dm_os_performance_counters WHERE counter_name='Checkpoint pages/sec';\nSELECT cntr_value FROM sys.dm_os_performance_counters WHERE counter_name='Page writes/sec';"},"choices":[{"label":"突発的な checkpoint/フラッシュの波 (checkpoint ストーム)","next":"sol_checkpoint"},{"label":"ストレージが継続的な負荷に追いつけない (IOPS の上限)","next":"sol_iops"}]},"sol_cache":{"kind":"solution","title":"根本原因: バッファキャッシュの不足","detail":"頻繁にアクセスされるデータセット (ワーキングセット) がバッファキャッシュに収まらないため、ブロックが常にディスクから再読み取りされる。ヒット率が低く、物理読み取りが多い。","steps":["バッファ/キャッシュのサイズを増やす: Oracle db_cache_size/SGA、Postgres shared_buffers、MySQL innodb_buffer_pool_size、MSSQL max server memory。","変更前後でヒット率と物理読み取りを比較する。","RAM が物理的に不足している場合は、サーバーのメモリを増設するか、アーカイブ/パーティショニングでワーキングセットを縮小する。","実際のボトルネックが単一のスキャンパターンに起因する場合は、キャッシュヒットのツリーのスキャンの分岐に切り替える。"],"related":["cache-hit-ratio"]},"sol_scan":{"kind":"solution","title":"根本原因: フルテーブルスキャン","detail":"適切なインデックスがないため、クエリが大きなテーブルを端から端までスキャンしている。これにより物理読み取りが多くなるだけでなく、不要なブロックでキャッシュが汚染される。","steps":["物理読み取りが最も多いクエリの実行計画 (EXPLAIN) を取得し、フルスキャンを特定する。","フィルタ列と結合列に適切なインデックスを追加し、実行計画がインデックスアクセスに切り替わることを確認する。","非常に大きなテーブルでは、日付/範囲ベースのパーティショニングでスキャンするデータ量を削減する。","不要な 'SELECT *' ではなく必要な列のみを選択し、読み取るブロック数を減らす。"],"related":["slow-queries"]},"sol_spill":{"kind":"solution","title":"根本原因: 一時領域にスピルするソート/ハッシュ","detail":"大規模なソート、ハッシュ結合、group by の操作が作業メモリに収まらず一時領域 (temp/tempdb) に書き込み、大量の読み書き IO を発生させている。","steps":["作業メモリの設定を引き上げる: Oracle pga_aggregate_target、Postgres work_mem、MySQL sort_buffer_size/join_buffer_size、MSSQL memory grant。","処理量を減らす: フィルタを早期に適用し、不要なソートを除去し、結合順序を改善する。","頻繁に使用するソート/グループ化に適したインデックスを追加し、ディスクへのスピルを防ぐ。","一時領域を高速なディスクに移す。問題が続く場合は、undo/temp の圧迫のツリーでさらに掘り下げる。"],"related":["slow-queries"]},"sol_checkpoint":{"kind":"solution","title":"根本原因: checkpoint ストーム","detail":"ダーティページが長時間蓄積され、短い間隔でまとめてディスクに書き込まれる。この突発的な書き込みの波が定期的に IO を飽和させる。","steps":["checkpoint を時間的に分散させる: Postgres では checkpoint_completion_target を増やし、checkpoint_timeout を調整する。","MySQL では、ストレージに合わせて innodb_io_capacity / innodb_io_capacity_max を設定し、adaptive flushing をチューニングする。","MSSQL では、間接チェックポイント (target_recovery_time) で突発的な波を平準化する。","Oracle では、fast_start_mttr_target で checkpoint の頻度を調整し、redo ログファイルを大きくする。"],"related":[]},"sol_iops":{"kind":"solution","title":"根本原因: IOPS / スループットの不足","detail":"ストレージに、ワークロードが必要とする読み取り+書き込み要求に応えるだけの IOPS または帯域幅がない。キューの深さとレイテンシが恒常的に高い。","steps":["ディスクのレイテンシ (要求あたりの ms) を測定し、ハードウェア/クラウドの IOPS 上限と比較する。","より高速なストレージ (HDD→SSD/NVMe) に移行するか、クラウドでプロビジョニング IOPS/スループットのティアを引き上げる。","データ、redo/ログ、一時領域を異なるディスクに分散して競合を減らす。","恒久的な対策として、総 IO 需要を削減する (インデックス作成、アーカイブ、クエリの最適化)。"],"related":[]}}},"solver/undo-temp-pressure.json":{"id":"undo-temp-pressure","title":"Undo / TempDB / 一時領域の圧迫","icon":"🧯","category":"容量","intro":"undo/ロールバック領域、一時 (temp) 領域、または TempDB が圧迫されている。圧迫がどこにあるかを特定し、大規模なソート/ハッシュ、長時間のクエリ/トランザクション、領域リークなどの根本原因まで掘り下げる。","start":"root","nodes":{"root":{"kind":"step","title":"圧迫はどこか: undo、temp、または tempdb の競合?","detail":"領域の使用状況を見て圧迫の発生源を分類する: undo/ロールバック表領域が満杯になりつつあるのか、一般的な一時 (temp) 領域か、それとも MSSQL の TempDB のページ割り当てラッチの競合か?","command":{"oracle":"SELECT tablespace_name, ROUND(used_percent,1) AS used_pct\nFROM dba_tablespace_usage_metrics\nWHERE tablespace_name LIKE '%UNDO%' OR tablespace_name LIKE 'TEMP%';","postgres":"SELECT datname, temp_files, pg_size_pretty(temp_bytes) AS temp_written\nFROM pg_stat_database ORDER BY temp_bytes DESC;","mysql":"SELECT * FROM information_schema.INNODB_TEMP_TABLE_INFO;\nSHOW GLOBAL STATUS LIKE 'Created_tmp_disk_tables';","mssql":"SELECT SUM(user_object_reserved_page_count)*8/1024 AS user_obj_mb,\n       SUM(internal_object_reserved_page_count)*8/1024 AS internal_obj_mb,\n       SUM(version_store_reserved_page_count)*8/1024 AS version_store_mb\nFROM sys.dm_db_file_space_usage;"},"choices":[{"label":"undo/ロールバック領域が満杯になりつつある (ORA-01555 / ORA-30036)","next":"undo"},{"label":"一時 (temp) 領域が満杯になりつつある (ソート/ハッシュのスピル)","next":"temp"},{"label":"TempDB の割り当てラッチの競合 (PFS/GAM/SGAM)","next":"tempdb"}]},"undo":{"kind":"step","title":"何が undo を消費しているか?","detail":"undo の圧迫は通常 2 種類のいずれか: 長時間の QUERY が開始時点の読み取り一貫性のために古い undo を必要としている (ORA-01555) か、長時間/オープンな TRANSACTION が大量の undo を生成して領域を満杯にし、ORA-30036 を引き起こしている。","command":{"oracle":"SELECT s.sid, s.username, t.used_ublk*8/1024 AS undo_mb, s.status, t.start_time\nFROM v$transaction t JOIN v$session s ON s.taddr=t.addr\nORDER BY undo_mb DESC;\nSELECT MAX(maxquerylen) AS longest_query_sec, MAX(tuned_undoretention) AS tuned_retention FROM v$undostat;","postgres":"SELECT pid, now()-xact_start AS xact_age, state, left(query,60) AS query\nFROM pg_stat_activity WHERE xact_start IS NOT NULL ORDER BY xact_start LIMIT 10;"},"choices":[{"label":"長時間のクエリが古い undo を必要としている (ORA-01555)","next":"sol_undo_query"},{"label":"長時間/オープンなトランザクションが undo を蓄積している (ORA-30036)","next":"sol_undo_tx"}]},"temp":{"kind":"step","title":"何が一時領域を満杯にしているか?","detail":"temp の圧迫は、大規模なソート/ハッシュ操作がディスクにスピルしている (正常だが巨大) か、単一のセッションが temp を保持し続けている (オープンカーソル、リーク、終わらないクエリ) かのいずれかに起因する。","command":{"oracle":"SELECT s.sid, s.username, u.tablespace, u.blocks*8/1024 AS temp_mb, u.sqladdr\nFROM v$tempseg_usage u JOIN v$session s ON s.saddr=u.session_addr\nORDER BY temp_mb DESC;","postgres":"SELECT query, temp_blks_written, temp_blks_read\nFROM pg_stat_statements ORDER BY temp_blks_written DESC LIMIT 10;","mysql":"SELECT event_name, current_number_of_bytes_used\nFROM performance_schema.memory_summary_global_by_event_name\nWHERE event_name LIKE '%temptable%' OR event_name LIKE '%sort%';","mssql":"SELECT session_id, request_id, SUM(internal_objects_alloc_page_count)*8/1024 AS internal_mb\nFROM sys.dm_db_task_space_usage GROUP BY session_id, request_id ORDER BY internal_mb DESC;"},"choices":[{"label":"大規模なソート/ハッシュ操作がディスクにスピルしている","next":"sol_temp_sort"},{"label":"単一のセッションが temp を保持している (リーク/オープンカーソル)","next":"sol_temp_leak"}]},"tempdb":{"kind":"step","title":"TempDB の競合は割り当ての問題か、量の問題か?","detail":"MSSQL の TempDB では 2 種類の問題が発生する: PFS/GAM/SGAM ページでの PAGELATCH の競合 (多数の小さな一時オブジェクト)、または大規模なソート/バージョンストアが量的に TempDB を満杯にすること。","command":{"mssql":"SELECT session_id, wait_type, wait_duration_ms, resource_description\nFROM sys.dm_os_waiting_tasks\nWHERE wait_type LIKE 'PAGELATCH%' AND resource_description LIKE '2:%';\nSELECT COUNT(*) AS tempdb_data_files FROM sys.master_files WHERE database_id=2 AND type=0;"},"choices":[{"label":"PFS/GAM/SGAM のラッチ競合","next":"sol_tempdb_latch"},{"label":"大規模なソート/バージョンストアが TempDB を満杯にしている","next":"sol_temp_sort"}]},"sol_undo_query":{"kind":"solution","title":"根本原因: 長時間のクエリ + undo の不足 (ORA-01555)","detail":"長時間のクエリが読み取り一貫性のために必要とする古い undo が、保持期間の経過または領域不足により上書きされた。","steps":["undo_retention を最長クエリの所要時間 (v$undostat.maxquerylen) を上回る値に引き上げる。","保持期間を領域で裏付けられるよう、UNDO 表領域を拡大するか autoextend を有効化する。","重要なレポートについては、ALTER TABLESPACE undotbs RETENTION GUARANTEE で古い undo を保護する (領域が満杯になると DML が失敗する可能性があるため注意)。","恒久的な対策として、長時間のクエリを最適化するか、スタンバイ/レプリカに移す。"],"related":["slow-queries"]},"sol_undo_tx":{"kind":"solution","title":"根本原因: 長時間/オープンなトランザクションが undo を満杯にした (ORA-30036)","detail":"単一の巨大な DML、またはコミットが遅れたオープンなトランザクションが大量の undo を生成し、UNDO 表領域を拡張できずに ORA-30036 が発生した。","steps":["最も多くの undo を保持しているアクティブなトランザクション (v$transaction.used_ublk) を特定し、その所有者を見つける。","単一の巨大な DML を日付/範囲ごとのチャンクに分け、途中でコミットしながら実行する。","コミット忘れ / idle-in-transaction のセッションをアプリケーション側で修正し、必要に応じて制御された方法で終了する。","一時的には UNDO 表領域に領域を追加し、恒久的にはワークロードに応じて保持期間と領域サイズを計画する。"],"related":["active-sessions"]},"sol_temp_sort":{"kind":"solution","title":"根本原因: 大規模なソート/ハッシュが一時領域を満杯にしている","detail":"メモリに収まらない大規模なソート/ハッシュ/group by の操作が一時領域にスピルし、領域を満杯にする可能性がある。","steps":["作業メモリを増やす: Oracle pga_aggregate_target、Postgres work_mem、MySQL sort_buffer_size、MSSQL memory grant。","クエリを改善する: 不要なソートを除去し、フィルタを早期に適用し、ソート/グループ化の列にインデックスを追加する。","非常に大きなジョブはチャンクに分割する。すべてが同時に temp を保持しないよう、同時実行数を制限する。","一時領域を拡大して高速なディスクに移す。MSSQL TempDB はコア数に基づいて複数ファイルで構成する。"],"related":["slow-queries"]},"sol_temp_leak":{"kind":"solution","title":"根本原因: セッションが一時領域を保持している (リーク)","detail":"クローズされていないカーソル、終わらないクエリ、オープンなままの一時テーブルが原因で、単一のセッションが一時領域を解放しない。","steps":["最も多くの temp を保持しているセッションと、実行中の SQL を特定する。","アプリケーションでカーソル/結果セットと一時テーブルが適切にクローズされていることを確認する。","停滞した/過度に長いセッションを制御された方法で終了し、領域が返却されたことを確認する。","グローバル一時テーブルは、セッション/トランザクションの終了時に自動的にクリーンアップされるよう定義する。"],"related":["active-sessions"]},"sol_tempdb_latch":{"kind":"solution","title":"根本原因: TempDB の PFS/GAM/SGAM ラッチ競合","detail":"多数のセッションが同時に小さな一時オブジェクトを作成すると、TempDB の割り当てマップページ (PFS/GAM/SGAM) で PAGELATCH の競合が発生する。","steps":["TempDB のデータファイル数を CPU コア数に比例させ、同じサイズで構成する (例: 4-8 ファイル、すべて同じサイズ/自動拡張)。","最新の SQL Server では、割り当ての競合を軽減するオプション (memory-optimized tempdb metadata) を有効化する。","一時テーブルの作成を減らす: 不要な #temp テーブルをテーブル変数 / 単一のクエリに置き換える。","変更後、PAGELATCH の待機時間が減少したことを確認する。"],"related":["current-locks"]}}},"solver/long-transaction.json":{"id":"long-transaction","title":"長時間実行中 / オープンなトランザクション","icon":"⏱️","category":"ロック","intro":"長時間実行中またはオープンなトランザクションが、ロック、undo、肥大化を蓄積している。原因となっているトランザクションを見つけ、その種類 (idle in transaction、長時間のバッチ、影響) を判断し、安全に解消する。","start":"root","nodes":{"root":{"kind":"step","title":"最も古いオープンなトランザクションはどれか?","detail":"オープンなトランザクションを開始時刻順に一覧表示する。通常、最も古いものが問題の発生源。その状態を確認する: アクティブに実行中か、それともコミットを待つ 'idle in transaction' か?","command":{"oracle":"SELECT s.sid, s.serial#, s.username, s.status, t.start_time, t.used_ublk*8/1024 AS undo_mb\nFROM v$transaction t JOIN v$session s ON s.taddr=t.addr\nORDER BY t.start_time;","postgres":"SELECT pid, state, now()-xact_start AS xact_age, now()-state_change AS since_change, left(query,60) AS query\nFROM pg_stat_activity\nWHERE xact_start IS NOT NULL ORDER BY xact_start LIMIT 20;","mysql":"SELECT trx_id, trx_state, trx_started, TIMESTAMPDIFF(SECOND,trx_started,NOW()) AS secs, trx_mysql_thread_id, trx_rows_locked\nFROM information_schema.INNODB_TRX ORDER BY trx_started;","mssql":"SELECT s.session_id, s.login_name, t.transaction_begin_time,\n       DATEDIFF(second,t.transaction_begin_time,GETDATE()) AS secs\nFROM sys.dm_tran_active_transactions t\nJOIN sys.dm_tran_session_transactions st ON st.transaction_id=t.transaction_id\nJOIN sys.dm_exec_sessions s ON s.session_id=st.session_id\nORDER BY t.transaction_begin_time;"},"choices":[{"label":"idle in transaction (コミット忘れ、アイドル状態)","next":"idle"},{"label":"アクティブだが非常に長時間実行中のバッチ/DML","next":"batch"},{"label":"トランザクションの継続中にロック/肥大化/undo が蓄積している","next":"impact"}]},"idle":{"kind":"step","title":"なぜ idle in transaction が発生するのか?","detail":"セッションがトランザクションを開いたまま、クエリを実行せずにアイドル状態になっている。つまり commit/rollback が忘れられている。これによりロックと undo が不必要に保持される。アプリケーションの修正で十分か、それとも緊急に終了させる必要があるか?","command":{"postgres":"SELECT pid, now()-state_change AS idle_age, left(query,80) AS last_query\nFROM pg_stat_activity WHERE state='idle in transaction' ORDER BY state_change;","mysql":"SELECT trx.trx_mysql_thread_id, trx.trx_started, p.time AS idle_secs, p.command\nFROM information_schema.INNODB_TRX trx\nJOIN information_schema.PROCESSLIST p ON p.id=trx.trx_mysql_thread_id\nWHERE p.command='Sleep' ORDER BY trx.trx_started;","oracle":"SELECT sid, serial#, status, last_call_et AS idle_secs\nFROM v$session WHERE status='INACTIVE' AND type='USER' AND last_call_et>300;","mssql":"SELECT s.session_id, s.status, DATEDIFF(second,s.last_request_end_time,GETDATE()) AS idle_secs\nFROM sys.dm_exec_sessions s\nWHERE s.session_id IN (SELECT session_id FROM sys.dm_tran_session_transactions)\n  AND s.status='sleeping';"},"choices":[{"label":"アプリケーション/コネクションプールがコミットしない (恒久的な修正)","next":"sol_idle"},{"label":"今すぐ終了させる必要がある","next":"sol_kill"}]},"batch":{"kind":"step","title":"アクティブな長時間トランザクションは何をしているか?","detail":"セッションは実際に実行中 (active)。単一の巨大な DML/レポートか、それとも他のセッションを待たせている、緊急に切断すべきブロッカーか?","command":{"oracle":"SELECT s.sid, s.serial#, sq.sql_text, s.last_call_et AS running_secs\nFROM v$session s JOIN v$sql sq ON sq.sql_id=s.sql_id\nWHERE s.status='ACTIVE' AND s.type='USER' ORDER BY s.last_call_et DESC;","postgres":"SELECT pid, now()-query_start AS run_time, left(query,80) AS query\nFROM pg_stat_activity WHERE state='active' ORDER BY query_start LIMIT 10;","mysql":"SELECT id, time AS run_secs, state, LEFT(info,80) AS query\nFROM information_schema.PROCESSLIST WHERE command<>'Sleep' ORDER BY time DESC;","mssql":"SELECT r.session_id, r.status, r.total_elapsed_time/1000 AS secs, SUBSTRING(t.text,1,80) AS query\nFROM sys.dm_exec_requests r CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t\nORDER BY r.total_elapsed_time DESC;"},"choices":[{"label":"単一の巨大な DML/レポート。分割する必要がある","next":"sol_batch"},{"label":"他のセッションを待たせている。緊急に終了する","next":"sol_kill"}]},"impact":{"kind":"step","title":"長時間トランザクションは何を蓄積しているか?","detail":"長時間トランザクションの副作用を特定する: 主に他のセッションを待たせているロックの滞留か、それとも古い行バージョンを保持してクリーンアップ (VACUUM/undo) を妨げている肥大化か?","command":{"postgres":"SELECT pid, pg_blocking_pids(pid) AS blocked_by FROM pg_stat_activity WHERE cardinality(pg_blocking_pids(pid))>0;\nSELECT max(age(backend_xmin)) AS max_xmin_age FROM pg_stat_activity WHERE backend_xmin IS NOT NULL;","oracle":"SELECT blocking_session, sid, serial#, seconds_in_wait, event\nFROM v$session WHERE blocking_session IS NOT NULL;","mssql":"SELECT session_id, blocking_session_id, wait_type, wait_time\nFROM sys.dm_exec_requests WHERE blocking_session_id<>0;"},"choices":[{"label":"ロックの滞留が他のセッションを待たせている","next":"sol_lock_backlog"},{"label":"古いバージョンの蓄積がクリーンアップを妨げている (undo/肥大化)","next":"sol_bloat"}]},"sol_idle":{"kind":"solution","title":"根本原因: アプリケーションがコミットしない (idle in transaction)","detail":"コネクションプールまたはアプリケーションがトランザクションを開いた後、commit/rollback せずに接続をアイドル状態のままにしている。これによりロックと undo が不必要に保持される。","steps":["アプリケーションコードで、トランザクションを開くすべての経路で commit/rollback を保証する。トランザクション内でユーザー入力や長い IO を待たないこと。","アイドル状態のトランザクションを自動的に切断する: Postgres idle_in_transaction_session_timeout、MySQL の接続/タイムアウト設定、アプリケーションプールの maxLifetime。","コネクションプールを「autocommit 有効、短いトランザクション」の原則に基づいて構成する。","監視を設定する: 長時間の idle-in-transaction セッションに対してアラートを発行する。"],"related":["active-sessions","blocking-sessions"]},"sol_kill":{"kind":"solution","title":"解決策: 原因となっているセッションを安全に終了する","detail":"ブロックしている/長時間のセッションが他を待たせている場合は、制御された方法で終了する必要がある。終了するとロールバックが発生し、領域/時間が必要になる場合があるため注意する。","steps":["重要なジョブを切断しないよう、まずセッションが何か (どのユーザー/アプリケーション、どのジョブ) を確認する。","終了する: Oracle ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE; Postgres SELECT pg_terminate_backend(pid); MySQL KILL thread_id; MSSQL KILL session_id;","大規模な書き込みトランザクションを kill した場合は、ロールバック (undo/ログの巻き戻し) の完了を待つ。","終了後、ロックと待機中のセッションが解消されたことを確認し、根本原因 (アイドル/バッチ) を恒久的に修正する。"],"related":["blocking-sessions"]},"sol_batch":{"kind":"solution","title":"根本原因: 単一の巨大な DML/レポート","detail":"単一のトランザクションで数百万行を処理する DML や、非常に長いレポートは、その実行期間全体にわたってロックと undo/肥大化を蓄積する。","steps":["大規模な DML を日付/範囲/キーごとのチャンクに分割し、各チャンクの後にコミットする。","重いレポートはピーク時間外に移すか、スタンバイ/リードレプリカにオフロードする。","長時間のクエリを最適化して総所要時間 (つまりロック/undo を保持する時間) を短縮する。","バッチジョブを可観測にする: 進捗をログに記録し、中断した箇所から再開できるようにする。"],"related":["slow-queries"]},"sol_lock_backlog":{"kind":"solution","title":"根本原因: ロックの滞留キュー","detail":"長時間トランザクションが保持するロックにより、その後ろに待機キューができている。多数のセッションが同じリソースを待っている。","steps":["ロックチェーンの先頭にあるセッション (head blocker) を特定する。キューを解消できるのはこのノードだけ。","head blocker を短くする (commit/rollback) か、制御された方法で終了し、キューが解消されるのを確認する。","ロックの保持時間を短縮するため、トランザクションを小さくし、一貫したアクセス順序を定める。","必要に応じて、より弱いロックで済むアプローチ (行レベル、適切な分離レベル) に切り替える。"],"related":["blocking-sessions","current-locks"]},"sol_bloat":{"kind":"solution","title":"根本原因: 古いバージョンの蓄積 (undo/肥大化)","detail":"長時間実行中のトランザクションが、それより前の古い行バージョンのクリーンアップを妨げている。Postgres ではテーブル/インデックスの肥大化として、Oracle では undo の圧迫として現れる。","steps":["最も古い xmin/トランザクションを保持しているセッションを見つける (Postgres backend_xmin、Oracle では最も古いアクティブなトランザクション)。","このトランザクションを短縮/終了させ、クリーンアップ (VACUUM / undo の再利用) が再び進むようにする。","Postgres では、トランザクション終了後に肥大化したテーブルに VACUUM を実行する (必要に応じて VACUUM FULL/pg_repack)。","トランザクションを短く保つアプリケーションパターンを恒久的に採用し、autovacuum をより積極的に設定する。"],"related":[]}}},"solver/plan-regression.json":{"id":"plan-regression","title":"クエリの実行計画が劣化した (突然遅くなった)","icon":"📉","category":"パフォーマンス","intro":"昨日は高速だったクエリが、今日は突然遅くなった。通常はオプティマイザがより悪い実行計画に切り替わっている。古い統計情報、パラメータ依存性、データ量の増加、突然の実行計画の変更の中から根本原因を見つけ、実行計画を安定させる。","start":"root","nodes":{"root":{"kind":"step","title":"実行計画は本当に変わったのか、それはいつか?","detail":"同じクエリに複数の実行計画 (plan_hash/plan_generation) があるか、また低速化はいつ始まったか? 直近のデプロイ、アップグレード、パラメータ変更、大規模なデータロードと時期が一致するか?","command":{"oracle":"SELECT sql_id, plan_hash_value, executions, ROUND(elapsed_time/GREATEST(executions,1)/1e6,3) AS sec_per_exec, first_load_time\nFROM v$sql WHERE sql_id='&sqlid' ORDER BY first_load_time;","postgres":"EXPLAIN (ANALYZE, BUFFERS) SELECT /* your query */ 1;\n-- Trend: SELECT query, calls, mean_exec_time FROM pg_stat_statements WHERE query LIKE '%...%';","mysql":"EXPLAIN FORMAT=JSON SELECT /* your query */ 1;\nSELECT DIGEST_TEXT, COUNT_STAR, AVG_TIMER_WAIT/1e9 AS avg_ms\nFROM performance_schema.events_statements_summary_by_digest WHERE DIGEST_TEXT LIKE '%...%';","mssql":"SELECT qs.plan_generation_num, qs.execution_count, qs.total_worker_time/qs.execution_count AS avg_cpu_us, qs.creation_time\nFROM sys.dm_exec_query_stats qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t\nWHERE t.text LIKE '%...%';"},"choices":[{"label":"統計情報が古い可能性がある","next":"stats"},{"label":"同じクエリがパラメータによって異なる動作をする (sniffing/peeking)","next":"sniff"},{"label":"データ量が大幅に増加した","next":"sol_datagrowth"},{"label":"アップグレード/フラッシュ後に実行計画が突然変わった","next":"sol_planflip"}]},"stats":{"kind":"step","title":"統計情報は最新か?","detail":"オプティマイザは統計情報に基づいて判断する。最後の analyze の日付が古い場合や変更カウンタが高い場合、推定値が実際にずれている可能性があり、それが不適切な実行計画につながる。","command":{"oracle":"SELECT table_name, num_rows, last_analyzed, stale_stats\nFROM dba_tab_statistics WHERE table_name='T';","postgres":"SELECT relname, n_live_tup, n_mod_since_analyze, last_analyze, last_autoanalyze\nFROM pg_stat_user_tables WHERE relname='t';","mysql":"SELECT table_name, update_time, table_rows FROM information_schema.tables WHERE table_name='t';\nSHOW INDEX FROM t;","mssql":"SELECT s.name, STATS_DATE(s.object_id,s.stats_id) AS last_updated, p.modification_counter, p.rows\nFROM sys.stats s CROSS APPLY sys.dm_db_stats_properties(s.object_id,s.stats_id) p\nWHERE s.object_id=OBJECT_ID('dbo.t');"},"choices":[{"label":"統計情報が古い/欠落している","next":"sol_stats"},{"label":"統計情報は最新だが、実行計画が依然としてパラメータに依存している","next":"sniff"}]},"sniff":{"kind":"step","title":"パラメータ依存性はあるか?","detail":"クエリは初回実行時のパラメータ値に基づいて実行計画を選択し、キャッシュする (MSSQL parameter sniffing / Oracle bind peeking)。その実行計画は、偏った分布を持つ他の値に対しては不適切な場合がある。","command":{"oracle":"SELECT sql_id, child_number, plan_hash_value, is_bind_sensitive, is_bind_aware\nFROM v$sql WHERE sql_id='&sqlid';","mssql":"SELECT qs.query_hash, qs.execution_count, qs.total_worker_time/qs.execution_count AS avg_cpu_us\nFROM sys.dm_exec_query_stats qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t\nWHERE t.text LIKE '%...%';","postgres":"-- For generic vs custom plan behavior:\nPREPARE p AS SELECT /* your query */ 1;\nEXPLAIN EXECUTE p;"},"choices":[{"label":"はい、パラメータによって実行計画が良し悪しの間で入れ替わる","next":"sol_sniff"},{"label":"適切な実行計画は分かっている。恒久的に固定したい","next":"sol_forceplan"}]},"sol_stats":{"kind":"solution","title":"根本原因: 古い / 欠落した統計情報","detail":"実態と一致しない古い統計情報に基づき、オプティマイザが行数を誤って推定し、不適切な実行計画を選択した。実行計画の劣化の最も一般的な原因。","steps":["影響を受けたテーブルとインデックスの統計情報を新たに収集する: Oracle DBMS_STATS.GATHER_TABLE_STATS、Postgres ANALYZE、MySQL ANALYZE TABLE、MSSQL UPDATE STATISTICS ... WITH FULLSCAN。","偏った分布を持つ列にヒストグラム/拡張統計を作成する。","統計情報の収集後、EXPLAIN で実行計画を確認し、良い実行計画に戻ったことを確認する。","再発防止のため、統計情報の自動収集 (autovacuum/auto update stats) を適切なしきい値で有効にしておく。"],"related":["slow-queries"]},"sol_sniff":{"kind":"solution","title":"根本原因: パラメータ依存性 (sniffing / bind peeking)","detail":"キャッシュされた実行計画は最初に到着したパラメータ値に合わせて選択されており、偏った分布を持つ他の値には不適切。目的は、値に適した実行計画が選択されるようにすること。","steps":["MSSQL では、重要なクエリに OPTION (RECOMPILE) または OPTIMIZE FOR で対象を絞った動作を定義する。頻繁に変わる値には recompile を優先する。","Oracle では、adaptive cursor sharing / bind-aware の動作を使用する。必要に応じて、値の範囲ごとにクエリを分割する。","Postgres では、generic plan と custom plan の選択を観察し、必要に応じて plan_cache_mode で制御する。","恒久的で正確な単一の実行計画が必要な場合は、実行計画の固定による解決策に進む。"],"related":["slow-queries"]},"sol_forceplan":{"kind":"solution","title":"解決策: 適切な実行計画を固定する (baseline / force plan)","detail":"既知の良い実行計画がある場合、オプティマイザがそれから外れないよう固定すれば、劣化を恒久的に止められる。","steps":["Oracle: 良い実行計画に対して SQL Plan Baseline を作成するか (DBMS_SPM)、SQL Plan Management で受け入れる。","MSSQL: Query Store で良い実行計画を選択し、sp_query_store_force_plan で強制する。","MySQL/Postgres: オプティマイザヒント (例: インデックスヒント) または pg_hint_plan で実行計画を制御する。","固定後はパフォーマンスを監視する。データのパターンが根本的に変わった場合は baseline を再評価する。"],"related":[]},"sol_datagrowth":{"kind":"solution","title":"根本原因: データ量が増加し、実行計画が合わなくなった","detail":"テーブルの増大に伴い、以前は理想的だった実行計画 (例: nested loop) がうまくスケールしなくなっている。オプティマイザには、増加を正しく反映した統計情報とアクセスパスが必要。","steps":["オプティマイザが新しい行数を把握できるよう、最新の統計情報を収集する。","増大しているテーブルに適切なインデックスを追加し、スケールしなくなったアクセスパス (例: フルスキャン/nested loop) を修正する。","非常に大きなテーブルでは、日付/範囲ベースのパーティショニングでスキャンするデータを制限する。","増加に合わせてクエリを書き直す (早期のフィルタリング、ページネーション、サマリ/マテリアライズドビュー)。"],"related":["slow-queries"]},"sol_planflip":{"kind":"solution","title":"根本原因: 実行計画の突然の変更 (アップグレード / キャッシュのフラッシュ)","detail":"バージョンアップグレード、パラメータ変更、またはプランキャッシュのクリア後に実行計画が突然変わった。オプティマイザの動作または環境条件が変化している。","steps":["変更のきっかけを特定する: アップグレード/パッチ、オプティマイザのパラメータ、データロード、または再起動/キャッシュのフラッシュ。","パラメータが原因の場合は、変更を元に戻し、制御された方法で再評価する。","オプティマイザが再び外れないよう、既知の良い実行計画を固定する (baseline / force plan)。","アップグレード後の劣化については、オプティマイザの互換性/準備状況の設定を見直す。"],"related":[]}}},"solver/replica-resync.json":{"id":"replica-resync","title":"レプリカの破損 / 再同期が必要","icon":"🔗","category":"レプリケーション","intro":"レプリカ/スタンバイとプライマリの同期が壊れている。レプリケーションが停止しているか、どれだけ遅れているか、位置/GTID チェーンが壊れているかを判断し、エラーのスキップ、待機、再構築 (reseed) の中から適切な方法を選ぶ。スプリットブレインに関する警告を含む。","start":"root","nodes":{"root":{"kind":"step","title":"レプリケーションの全体的な状態は?","detail":"まずレプリケーションの健全性を確認する: 適用スレッドは動作しているか、遅延はどの程度か、エラーはあるか? また、2 つのノードが両方とも書き込みを受け付けていないこと (スプリットブレイン) も確認する。","command":{"mysql":"SHOW REPLICA STATUS\\G\n-- Check: Replica_IO_Running, Replica_SQL_Running, Seconds_Behind_Source, Last_Error, Retrieved/Executed_Gtid_Set","postgres":"-- On the primary:\nSELECT client_addr, state, sent_lsn, replay_lsn, pg_wal_lsn_diff(sent_lsn,replay_lsn) AS lag_bytes FROM pg_stat_replication;\n-- On the replica:\nSELECT status, last_msg_receipt_time, latest_end_lsn FROM pg_stat_wal_receiver;","oracle":"SELECT name, value, unit, time_computed FROM v$dataguard_stats WHERE name IN ('transport lag','apply lag');\nSELECT dest_id, status, error, gap_status FROM v$archive_dest_status WHERE status<>'INACTIVE';","mssql":"SELECT ag.name AS ag, drs.synchronization_state_desc, drs.synchronization_health_desc,\n       drs.log_send_queue_size, drs.redo_queue_size\nFROM sys.dm_hadr_database_replica_states drs\nJOIN sys.availability_groups ag ON ag.group_id=drs.group_id;"},"choices":[{"label":"レプリケーションが停止している / 失敗している","next":"error"},{"label":"動作しているが大きく遅れている (大きな遅延)","next":"lag"},{"label":"GTID/位置が壊れて不整合 — 再構築する","next":"sol_reseed"},{"label":"両方のノードがプライマリとして書き込んでいる (スプリットブレインの疑い)","next":"sol_splitbrain"}]},"error":{"kind":"step","title":"エラーは修復可能か、それとも再構築が必要か?","detail":"適用エラーを調べる。一部のエラー (重複キー、行の欠落) は単一のイベントを安全にスキップすることで解決できる。ただし、データの不整合/破損がある場合、唯一の正しい方法はレプリカの再構築。","command":{"mysql":"SHOW REPLICA STATUS\\G\n-- Check: Last_SQL_Errno, Last_SQL_Error, Last_IO_Errno, Last_IO_Error","postgres":"-- Examine the replica logs (PostgreSQL log): recovery / WAL apply error messages.\nSELECT status, last_msg_receipt_time FROM pg_stat_wal_receiver;","mssql":"SELECT * FROM sys.dm_hadr_automatic_seeding;\nSELECT database_id, synchronization_state_desc, is_suspended, suspend_reason_desc\nFROM sys.dm_hadr_database_replica_states WHERE is_local=1;"},"choices":[{"label":"単一/少数の適用エラー (スキップ可能)","next":"sol_skiperror"},{"label":"修復不能な不整合 / 破損","next":"sol_reseed"}]},"lag":{"kind":"step","title":"遅延は一時的か、恒常的か?","detail":"遅延の推移を時系列で確認する。一時的な負荷の急増の後に解消する (追いつく) のか、それとも増え続けてレプリカがプライマリに追いつけないのか?","command":{"mysql":"SHOW REPLICA STATUS\\G\n-- Measure Seconds_Behind_Source several times: is it decreasing or increasing?","postgres":"-- Measure repeatedly on the replica:\nSELECT now()-pg_last_xact_replay_timestamp() AS replay_lag;","oracle":"SELECT name, value, time_computed FROM v$dataguard_stats WHERE name='apply lag';","mssql":"SELECT drs.redo_queue_size, drs.redo_rate, drs.log_send_queue_size\nFROM sys.dm_hadr_database_replica_states drs WHERE drs.is_local=0;"},"choices":[{"label":"一時的な負荷の急増。遅延は解消しつつある","next":"sol_lag_wait"},{"label":"増え続けている。追いつけない","next":"sol_lag_perm"}]},"sol_skiperror":{"kind":"solution","title":"解決策: 適用エラーを慎重にスキップする","detail":"単一の適用エラー (例: 重複キー) でレプリケーションが停止し、データが実際に整合していると確信できる場合は、そのイベントをスキップしてストリームを継続できる。これは最終手段であり、やみくもなスキップは気付かないうちにデータのずれを生む。","steps":["まずエラーが発生した理由を理解し、影響を受けた行を両側で比較してデータの整合性を確認する。","GTID を使用しない MySQL では、単一のイベントをスキップする: STOP REPLICA; SET GLOBAL sql_replica_skip_counter=1; START REPLICA; (8.0.26 より前: sql_slave_skip_counter。慎重に)。","GTID を使用している場合、失敗したトランザクションをスキップするには、その GTID を空のトランザクションでマークしてからレプリカを開始する。","スキップ後、両側の間で行レベルの整合性チェック (checksum) を実行する。ずれがある場合は reseed に進む。"],"related":["replication-status"]},"sol_reseed":{"kind":"solution","title":"解決策: レプリカを再構築する (reseed / rebuild)","detail":"位置/GTID チェーンが壊れている、データがずれている、または修復不能なエラーがある場合、唯一の信頼できる方法は、プライマリから取得した新しいコピーからレプリカを再構築すること。","steps":["プライマリから一貫したベースバックアップを取得する: MySQL xtrabackup/mysqldump または CLONE、Postgres pg_basebackup、Oracle RMAN duplicate、MSSQL フル+ログバックアップ。","レプリカ上の古い状態をクリーンアップし、バックアップをリストアする (Postgres pg_basebackup -R、MSSQL RESTORE ... WITH NORECOVERY)。","正しい位置/GTID からレプリケーションを開始する: MySQL CHANGE REPLICATION SOURCE TO ...; START REPLICA; MSSQL ではデータベースを AG に再追加する (自動シード処理)。","追いつく過程を監視し、遅延がゼロになったら checksum で両側の整合性を確認する。"],"related":["replication-status"]},"sol_lag_wait":{"kind":"solution","title":"根本原因: 一時的な負荷の急増 (遅延は解消しつつある)","detail":"レプリケーションは健全。プライマリでの一時的な書き込みの集中やネットワークの変動により遅延が生じたが、レプリカは追いつきつつある。","steps":["複数回の測定で、遅延が実際に減少傾向にあることを確認する。","負荷のピークが終わるまで、必要に応じて遅延の影響を受けやすい読み取りのみをプライマリにルーティングする。","再発する場合は、書き込みの集中 (バッチジョブ、ETL) を時間的に分散させるか、ピーク時間外に移す。","一時的な遅延が恒常化する前に検知できるよう、ネットワーク/適用のレイテンシを監視に追加する。"],"related":["replication-status"]},"sol_lag_perm":{"kind":"solution","title":"根本原因: レプリカがプライマリに追いつけない","detail":"適用 (apply/redo) 側が、プライマリが生成する変更の速度についていけず、遅延が増え続けている。通常は、シングルスレッドの適用、低速なレプリカのハードウェア、またはネットワークのボトルネック。","steps":["適用のボトルネックを見つける: 制限しているのはシングルスレッドの適用か、レプリカのディスク/CPU か、それともネットワーク帯域幅か?","並列適用を有効化/増強する: MySQL では複数のレプリカワーカー (replica_parallel_workers)。Postgres/Oracle では適用のリソースを見直す。","レプリカのハードウェアを少なくともプライマリと同等にする (特にディスクの IOPS)。","適用のためのリソースを残すよう、レプリカ上の不要な重い読み取りクエリを減らす。それでも追いつけない場合は、reseed 後に再評価する。"],"related":["replication-status"]},"sol_splitbrain":{"kind":"solution","title":"警告: スプリットブレイン (2 つのプライマリ) — データ損失のリスク","detail":"両方のノードがプライマリのロールで書き込みを受け付けている場合、競合する変更が両側に蓄積される。これは最も危険な状況であり、データ損失につながる可能性がある。書き込みを単一ノードに絞ることが最優先。","steps":["直ちに書き込みを単一ノードに集約する: アプリケーションのトラフィックを厳密に 1 つのプライマリにルーティングし、もう一方を読み取り専用にする/隔離する。","正となる (正しい) ノードを特定する: 業務上の観点から、どちらのデータを有効とみなすかを決定する。","両側の競合する (分岐した) 変更を比較し、採用しない側の重要な変更を手動で調整する。","正となるノードをソースとして、もう一方のノードを reseed で再構築する。その後、二重プライマリを防ぐフェンシング/クォーラムの仕組みを構築する。"],"related":["replication-status"]}}},"solver/cache-hit-low.json":{"id":"cache-hit-low","title":"キャッシュヒット率が低い (buffer/cache hit)","icon":"🎯","category":"パフォーマンス","intro":"キャッシュヒット率が低く、データが常にディスク (またはソース) から読み取られている。問題が DB のバッファ/共有キャッシュにあるのか、Redis/アプリケーションキャッシュにあるのかを判断し、測定して修正する。","start":"root","nodes":{"root":{"kind":"step","title":"どのキャッシュのヒット率が低いか?","detail":"ヒット率を測定して問題を切り分ける: データベースのバッファ/共有キャッシュが低い (物理読み取りが多い) のか、それとも Redis/アプリケーションキャッシュでミスとエビクションが多いのか?","command":{"oracle":"SELECT ROUND((1-(pr.value/(dbg.value+cg.value)))*100,2) AS buffer_hit_pct\nFROM v$sysstat pr, v$sysstat dbg, v$sysstat cg\nWHERE pr.name='physical reads' AND dbg.name='db block gets' AND cg.name='consistent gets';","postgres":"SELECT ROUND(sum(blks_hit)*100.0/nullif(sum(blks_hit)+sum(blks_read),0),2) AS cache_hit_pct\nFROM pg_stat_database;","mysql":"SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read_requests';\nSHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_reads';","mssql":"SELECT cntr_value AS buffer_cache_hit_ratio\nFROM sys.dm_os_performance_counters\nWHERE counter_name='Buffer cache hit ratio' AND object_name LIKE '%Buffer Manager%';","redis":"INFO stats\n# Check the keyspace_hits / keyspace_misses ratio and evicted_keys in INFO memory"},"choices":[{"label":"DB のバッファ/共有キャッシュのヒット率が低い","next":"dbcache"},{"label":"Redis/アプリケーションキャッシュでミス / エビクションが多い","next":"rediscache"}]},"dbcache":{"kind":"step","title":"なぜディスクから読み取っているのか: サイズか、スキャンパターンか?","detail":"バッファヒット率が低い典型的な原因は 2 つ: 頻繁にアクセスされるデータ (ワーキングセット) がメモリに収まらない (キャッシュが小さすぎる)、または大規模なフルテーブルスキャンが 1 回しか使わないブロックでキャッシュを汚染し、有用なページを追い出している。","command":{"oracle":"SELECT component, current_size/1024/1024 AS mb FROM v$sga_dynamic_components WHERE component LIKE '%buffer cache%';\nSELECT sql_id, disk_reads, executions FROM v$sql ORDER BY disk_reads DESC FETCH FIRST 10 ROWS ONLY;","postgres":"SHOW shared_buffers;\nSELECT pg_size_pretty(pg_database_size(current_database())) AS db_size;\nSELECT query, shared_blks_read FROM pg_stat_statements ORDER BY shared_blks_read DESC LIMIT 10;","mysql":"SHOW VARIABLES LIKE 'innodb_buffer_pool_size';\nSELECT ROUND(SUM(data_length+index_length)/1024/1024) AS data_mb FROM information_schema.tables;","mssql":"SELECT physical_memory_kb/1024 AS server_ram_mb FROM sys.dm_os_sys_info;\nSELECT COUNT(*)*8/1024 AS buffer_pool_mb FROM sys.dm_os_buffer_descriptors;"},"choices":[{"label":"ワーキングセットが RAM に収まらない (キャッシュが小さすぎる)","next":"sol_sizing"},{"label":"フルテーブルスキャンがキャッシュを汚染している","next":"sol_scan"}]},"rediscache":{"kind":"step","title":"Redis のミスの原因: maxmemory によるエビクションか、TTL/キー管理か?","detail":"Redis のヒット率が低い場合、メモリが maxmemory に達してキーがエビクトされているか、キーの TTL 管理/キャッシュパターンが弱い (コールドなキー、再利用が少ない) かのいずれか。","command":{"redis":"INFO memory\n# used_memory, maxmemory, maxmemory_policy, evicted_keys\nCONFIG GET maxmemory-policy\nINFO keyspace\n# Key count and expires (keys with TTL) ratio per db"},"choices":[{"label":"maxmemory が満杯、エビクションが多い","next":"sol_maxmem"},{"label":"TTL/キーのパターンが弱い (再利用が少ない)","next":"sol_ttl"}]},"sol_sizing":{"kind":"solution","title":"根本原因: ワーキングセットに対してキャッシュが小さすぎる","detail":"頻繁にアクセスされるデータが割り当てられたバッファ/キャッシュより大きいため、常に追い出されてディスクから再読み取りされている。ヒット率が低く、物理読み取りが多い。","steps":["ワーキングセットをカバーできるようキャッシュを拡大する: Oracle db_cache_size/SGA、Postgres shared_buffers、MySQL innodb_buffer_pool_size、MSSQL max server memory。","物理 RAM が不足している場合はサーバーのメモリを増設する。これは DB のスケールを左右する主要なリソース。","ワーキングセットを縮小する: 古いデータをアーカイブ/パーティショニングし、不要な列/インデックスを削減する。","変更後、ヒット率と物理読み取りを比較して改善を確認する。"],"related":["cache-hit-ratio"]},"sol_scan":{"kind":"solution","title":"根本原因: スキャンパターンがキャッシュを汚染している","detail":"大規模なフルテーブルスキャンが、一度使われて破棄されるブロックでキャッシュを埋め、ホットなページを追い出している。これがヒット率を下げる。","steps":["物理読み取りが最も多いクエリの実行計画を取得し、フルスキャンをインデックスアクセスに変える (適切なインデックスを追加する)。","'SELECT *' ではなく必要な列のみを選択し、スキャンするブロック量を減らす。","大きなテーブルでは、パーティショニングでスキャンを該当する範囲に絞り込む。","重い分析/スキャンのジョブを OLTP のキャッシュから分離する (リードレプリカまたは別の時間帯)。"],"related":["slow-queries","cache-hit-ratio"]},"sol_maxmem":{"kind":"solution","title":"根本原因: Redis の maxmemory によるエビクション","detail":"Redis のメモリが maxmemory の上限に達し、新しいキーの領域を確保するために古いキーがエビクトされている (evicted_keys が増え続ける)。これにより、まだ必要なエントリが失われ、ヒット率が下がる。","steps":["maxmemory を実際のワーキングセットに合わせて引き上げるか、データセットを縮小する。","アクセスパターンに合わせてエビクションポリシーを選択する (例: LRU/LFU: allkeys-lfu はホットとコールドの分離に効果的なことが多い)。","大きい/まれにしか使われない構造を整理する。値を縮小し、不要なフィールドを削除し、適切なデータ型を使用する。","恒常的なニーズであれば Redis をスケールし (RAM の増設またはクラスタ/シャーディング)、evicted_keys の監視を開始する。"],"related":[]},"sol_ttl":{"kind":"solution","title":"根本原因: 弱い TTL / キャッシュパターン","detail":"キーに TTL がまったく設定されずメモリがコールドなデータで埋まっているか、キャッシュパターンの再利用率が低く、ほとんどのリクエストがミスになっている。","steps":["キャッシュされたキーに適切な TTL を設定し、使われなくなったデータが自然に期限切れになるようにする。","頻繁に読み取られる (ホットな) データをキャッシュする。まれにしか使われないデータはキャッシュしない (ヒットしないエントリでキャッシュを埋めない)。","cache-aside パターンでは、ミス後の投入を正しく実装し、'thundering herd' に対してロック/リクエストの重複排除を使用する。","keyspace_hits/misses の比率を監視し、データに基づいて TTL とキー設計を改善する。"],"related":[]}}},"solver/arch-oltp.json":{"id":"arch-oltp","title":"リファレンスアーキテクチャ: 3 層 OLTP アプリケーション","icon":"🏛️","category":"リファレンスアーキテクチャ","intro":"典型的な業務アプリケーション (注文、決済、在庫) は、短く、単一行で、一貫性が重要なトランザクション (OLTP) を大量に実行する。このツリーは、負荷プロファイルの特定から始めて、プライマリのリレーショナルデータベース、コネクションプーラー、リードレプリカ、キャッシュ層、バックアップ + PITR、監視をいつ導入すべきかを段階的に示す。目的は「最初からすべてを追加する」ことではなく、各ボトルネックが実証されるたびに適切なコンポーネントを追加すること。","start":"root","nodes":{"root":{"kind":"step","title":"負荷プロファイルは: トランザクションの構成と一貫性の要件は?","detail":"OLTP アーキテクチャでの最初の判断は、ワークロードが本当にトランザクション型 (ACID を必要とする短い読み書きの混在) かどうか。データは本来リレーショナルで一貫性が重要 (金額、在庫、注文) なのか、ワークロードの大半が読み取りなのか、それとも負荷はまだ非常に低いのか?","choices":[{"label":"短いトランザクション、強い一貫性 (金額/在庫/注文)","next":"primary_db"},{"label":"読み取りが大部分を占め、書き込みは少なく、トラフィックは増加中","next":"scale_reads"},{"label":"負荷は非常に低い。最もシンプルな構成で十分か?","next":"sol_single_node"}]},"primary_db":{"kind":"step","title":"プライマリのデータベースエンジンは選定済みか、スケールに懸念はあるか?","detail":"トランザクションの中核には、リレーショナルエンジン (PostgreSQL、MySQL/InnoDB、Oracle、SQL Server) が適切な基盤。エンジンの選定が明確になったら、次の問題はスケーリング: 現時点では単一インスタンスで十分か、それとも接続数と読み取り負荷が増加しているか?","choices":[{"label":"エンジンは決まっている。現時点では単一インスタンスで十分","next":"sol_single_node"},{"label":"接続数が急増し、リソースが不足しつつある","next":"sol_pooler"},{"label":"読み取り負荷が増加し、プライマリの書き込みインスタンスを圧迫している","next":"scale_reads"}]},"scale_reads":{"kind":"step","title":"読み取りをどうスケールするか: レプリカか、キャッシュか?","detail":"読み取り負荷がプライマリインスタンスを圧迫している場合、補完的な 2 つの選択肢がある。レポート/一覧など多少遅れたデータを許容できる読み取りはリードレプリカにルーティングできる。同じ「ホットな」データが何度も要求される場合は、マイクロ秒レイテンシのキャッシュ (Redis) が DB の負荷を軽減する。","choices":[{"label":"レポート/一覧の読み取りが多い。多少の遅延は許容できる","next":"sol_read_replica"},{"label":"同じ人気データが何度も読み取られる","next":"sol_cache"}]},"sol_single_node":{"kind":"solution","title":"推奨: 単一プライマリ + プール + バックアップから始める","detail":"初期段階ではアーキテクチャをシンプルに保つ: 単一のリレーショナルプライマリインスタンス、その前段のコネクションプール、定期的なバックアップで十分。複雑さを加えるのは、測定されたボトルネックがそれを必要とするときに限る。","steps":["プライマリ DB: PostgreSQL や MySQL/InnoDB などの ACID 準拠のリレーショナルエンジン。スキーマ、制約、インデックスを正しく設定する。","コネクションプール: 最初からアプリケーション側のプール (例: HikariCP) またはサーバー側の PgBouncer を導入する。接続のストームを防ぐ。","バックアップ + PITR: ポイントインタイムリカバリのための日次フルバックアップ + WAL/binlog のアーカイブ。バックアップは別のストレージに保管する。","注意: 初期段階でレプリカ/シャーディング/キャッシュを追加しないこと。測定されていない問題を解決しようとしても、障害要因が増えるだけ。","監視: 最初からレイテンシ、エラー率、接続数のメトリクスを収集し、増加のシグナルを見逃さないようにする。"],"related":["decide-pooling","decide-backup"]},"sol_pooler":{"kind":"solution","title":"推奨: コネクションプーラーを追加する","detail":"OLTP では、各アプリケーションインスタンスが独自に接続を開くと、数千の接続によるメモリとスケジューラのオーバーヘッドでプライマリ DB が行き詰まる。間にプーラーを置くことで、少数の実際の DB 接続を多数のアプリケーションリクエストで共有できる。","steps":["PostgreSQL: PgBouncer (トランザクションプーリングモード) が多数のクライアントを少数のバックエンド接続に集約する。","MySQL: ProxySQL も同様に接続の多重化とルーティングを提供する。","プールサイズ: 一般に CPU コア数に比例する。数十のバックエンド接続で十分。「多いほどよい」は当てはまらない。","注意: トランザクションプーリングでは、セッションレベルの機能 (プリペアドステートメント、一時テーブル、セッション変数) が制限される。それに応じてアプリケーションを作成する。","次のステップ: プールも飽和する場合、問題は接続ではなくクエリ/トランザクションの所要時間。低速なクエリと長時間トランザクションを突き止める。"],"related":["decide-pooling","connection-storm"]},"sol_read_replica":{"kind":"solution","title":"推奨: リードレプリカを追加する","detail":"書き込みはプライマリにとどめ、読み取り専用のトラフィック (レポート、一覧、検索) は、プライマリから供給される 1 つ以上の非同期レプリカにルーティングする。これにより、プライマリは書き込みと一貫性が重要な読み取りに専念できる。","steps":["トポロジー: プライマリ -> 1 つ以上の非同期レプリカ。アプリケーションが読み書きを分離し、読み取りをレプリカに送る。","エンジン: PostgreSQL ストリーミングレプリケーション、MySQL レプリカ、またはマネージドのリードレプリカ。","適用場面: レポート/分析/一覧など、多少の遅延を許容できる読み取り。プライマリの CPU/IO の負荷を減らしたい場合。","注意: レプリケーション遅延により古いデータが読み取られる。「自分の書き込みを直ちに読む」必要があるフローはプライマリから提供する (read-your-writes)。","次のステップ: レプリカでも不十分な場合は、ホットなデータ向けのキャッシュ、または書き込み側のシャーディングを検討する。"],"related":["replication-lag","decide-shard-replica"]},"sol_cache":{"kind":"solution","title":"推奨: キャッシュ層を追加する (Redis)","detail":"同じ人気データ (セッション、カタログ、プロファイル、ページの断片) が繰り返し読み取られる場合は、DB の前段にインメモリキャッシュを置き、大半の読み取りを DB に到達させずに処理する。レイテンシが下がり、プライマリ DB の負荷が軽減される。","steps":["エンジン: Redis (または Memcached) による cache-aside パターン。アプリケーションはまずキャッシュを確認し、ミスした場合は DB から取得してキャッシュに書き込む。","TTL + 無効化: すべてのキーに妥当な TTL を設定する。書き込み時には関連するキーを削除/更新し、古いデータが残らないようにする。","適用場面: 読み取りが多く、データの変更が比較的まれで、同じキーが繰り返し要求される場合。","注意: キャッシュスタンピード。人気のあるキーが期限切れになると、数千のリクエストが一度に DB に殺到する可能性がある。ロック/single-flight とジッター付きの TTL を使用する。","注意: キャッシュを「信頼できる情報源」として扱わないこと。永続的な正のデータは常に DB にあり、キャッシュが障害を起こしてもアプリケーションは DB にフォールバックして動作し続ける必要がある。"],"related":["decide-cache","cache-hit-low"]}}},"solver/arch-dwh.json":{"id":"arch-dwh","title":"リファレンスアーキテクチャ: データウェアハウス / 分析","icon":"🏛️","category":"リファレンスアーキテクチャ","intro":"分析クエリ (レポート、集計、広範なスキャン) は OLTP のトランザクションとは根本的に異なる: 数は少ないが非常に広範で長時間実行されるクエリ。このツリーは、分析を OLTP から分離する判断を起点に、ロード方式 (ETL vs ELT)、列指向/columnstore ストレージ、スタースキーマによるモデリング、パーティショニング + 圧縮、マテリアライズドビューによる事前計算などのコンポーネントを、同時実行性とスループットのトレードオフを考慮しながら段階的に説明する。","start":"root","nodes":{"root":{"kind":"step","title":"分析ワークロードは OLTP と同じデータベースで実行されているか?","detail":"最もよくある間違いは、稼働中のトランザクション DB で重いレポートを実行し、OLTP のレイテンシを悪化させること。最初の判断は分離: 分析はまだ OLTP インスタンスで実行されているのか、別の分析環境を構築しているのか、それともデータをそこへ移す方法を決めようとしているのか?","choices":[{"label":"レポートはまだ稼働中の OLTP で実行されており、OLTP を遅くしている","next":"sol_separate"},{"label":"別のウェアハウスがある。データをどうロードすべきか?","next":"load_method"},{"label":"ウェアハウスはあるがクエリがまだ遅い。どうモデリングすべきか?","next":"model"}]},"load_method":{"kind":"step","title":"変換はどこで行うか: ロード前か、ロード後か?","detail":"ソースからウェアハウスにデータを移す際、ロード前に別の処理層でクレンジング/変換を行う (ETL) のか、それともまず生データをウェアハウスにロードし、強力なウェアハウスエンジン内で SQL によって変換する (ELT) のか? 判断は、ウェアハウスの処理能力とスキーマの柔軟性の必要性によって決まる。","choices":[{"label":"変換は複雑/外部で行う。ロード前に実施する","next":"sol_etl"},{"label":"ウェアハウスは強力。生データでロードし、内部で SQL によって変換する","next":"sol_elt"}]},"model":{"kind":"step","title":"クエリのボトルネックはストレージのレイアウトか、データモデルか?","detail":"分析が遅い場合、主な対策は 2 つある。行指向ストレージでは広範なスキャンが行全体を読み取るが、列指向ストレージは必要な列のみを読み取り、圧縮効率も高い。モデル側では、過度な正規化は多数の結合を生みクエリを遅くする。スタースキーマ (ファクト + ディメンション) は分析を簡素化する。","choices":[{"label":"広範な集計スキャンが遅い。読み取る列は少ない","next":"sol_columnar"},{"label":"結合が多すぎる、複雑な正規化スキーマ","next":"sol_star"},{"label":"同じ重いレポートが繰り返し同じ結果を出している","next":"sol_matview"}]},"sol_separate":{"kind":"solution","title":"推奨: 分析を OLTP から分離する","detail":"トランザクションと分析のワークロードは、同じエンジン上では互いを圧迫する: 長いレポートがロック/IO を保持し、短いトランザクションを遅らせる。分析を別のターゲット (リードレプリカまたは別の分析用ウェアハウス) に移すことで、双方の負荷が軽減される。","steps":["最初のステップ: 軽いレポートは OLTP のリードレプリカに、重い分析は別の分析エンジンにルーティングする。","分析エンジン: 列指向/分析エンジン (例: columnstore を備えた SQL Server、ClickHouse、列指向ウェアハウス) は、広範なスキャンにおいて行指向ストレージより何倍も高速。","同時実行性 vs スループット: OLTP は多数の小さなトランザクション向け (高い同時実行性)、ウェアハウスは少数の巨大なクエリ向け (高いスループット) にチューニングされる。同じマシンで両方を最適化することはできない。","注意: ウェアハウスは「本番のリアルタイムコピー」ではない。一定間隔でロードされる、遅延はあるが分析用に整理されたデータ。","次のステップ: 分離した後、ロード方式 (ETL/ELT) とモデル (スタースキーマ) を決定する。"],"related":["decide-sqlnosql","slow-query"]},"sol_etl":{"kind":"solution","title":"推奨: ETL (ロード前に変換)","detail":"ETL では、データをソースから抽出し (Extract)、別の処理層でクレンジングと変換を行い (Transform)、その後にウェアハウスにロードする (Load)。ウェアハウスには、クリーンでモデルに準拠したデータのみが入る。","steps":["適用場面: 変換が複雑な場合、複数のソースを組み合わせる必要がある場合、または生データ/機密データを決してウェアハウスに入れたくない場合。","フロー: ソース (OLTP/ファイル/API) → 変換層 → ウェアハウスへのバッチロード。","利点: ウェアハウスのストレージをクリーンに保てる。機密データをロード前にマスキングできる。","欠点: 変換は別システムの処理能力に依存し、ウェアハウスの SQL の柔軟性を活かせない。","注意: バッチウィンドウ (例: 夜間) でロードする。ロード中の重いクエリとの衝突を避けるよう計画する。"],"related":["decide-capacity"]},"sol_elt":{"kind":"solution","title":"推奨: ELT (ウェアハウス内で変換)","detail":"ELT では、まず生データをウェアハウスにロードし、変換はウェアハウス自体の強力な SQL エンジン内で行う。最新の列指向ウェアハウスは処理能力が高いため、変換をデータのもとへ持っていくのではなく、データを一度移して内部で処理する。","steps":["適用場面: ウェアハウスエンジンが強力でスケーラブルな場合。生データも保持したい場合 (監査/再処理)。","フロー: ソース → 生データ層 (ステージング) → SQL/変換ビュー → モデル化されたファクト/ディメンション層。","利点: 単一のエンジンで柔軟。生データが保持されるため、後から変換を変更して再生成できる。","欠点: 生の (機密の可能性がある) データがウェアハウスに入る。アクセス制御とマスキングが必須。","注意: 層構造でモデリングする (raw → staging → mart)。再実行が安全になるよう、変換は冪等に記述する。"],"related":["decide-capacity"]},"sol_columnar":{"kind":"solution","title":"推奨: 列指向 / columnstore ストレージ + 圧縮","detail":"分析クエリは通常、全行にわたって少数の列をスキャンする。列指向ストレージはデータを列単位で保持し、必要な列のみを読み取る。類似した値が隣接するため圧縮効率が非常に高く、IO が劇的に減少する。","steps":["エンジン/機能: SQL Server の columnstore インデックス、ClickHouse、列指向ウェアハウス。PostgreSQL 側では列指向の拡張機能。","圧縮: 列指向のレイアウトにより高い圧縮率が得られる。ディスクが少なく、読み取るバイト数が少なく、スキャンが高速。","パーティショニング: 大きなファクトテーブルを日付/範囲でパーティショニングし、パーティションプルーニングによって無関係なパーティションを丸ごとスキップする。","注意: 列指向は、多数の単一行の更新/ポイント読み取りには不向き。OLTP を移さないこと。","同時実行性 vs スループット: 列指向が真価を発揮するのは少数の巨大なスキャンクエリであり、数千の小さな同時クエリではない。"],"related":["decide-partition","io-bottleneck"]},"sol_star":{"kind":"solution","title":"推奨: スタースキーマ (ファクト + ディメンション)","detail":"分析モデルでは、メジャーを保持するファクトテーブルが中心にあり、その周囲を説明的なディメンションテーブルが囲む。過度に正規化されたスキーマと比べて結合の数が減り、クエリがシンプルになり、エンジンがより良い実行計画を生成する。","steps":["構造: 中心にファクト (メジャー + ディメンションキー)。ディメンション (時間、製品、顧客) がその周囲に星形を形成する。","適用場面: レポートが多数のテーブルを結合し、正規化スキーマが結合だらけになっている場合。","非正規化: 分析では意図的な非正規化は普通のこと。一貫性はロード処理 (ETL/ELT) で確保する。","次のステップ: 頻繁に実行される重い集計を、マテリアライズドビューで事前計算する。","注意: OLTP をスタースキーマに変換しないこと。このモデルは分析向けであり、トランザクションの書き込み向けではない。"],"related":["decide-index"]},"sol_matview":{"kind":"solution","title":"推奨: マテリアライズドビューで事前計算する","detail":"同じ重い集計 (日次売上、月次サマリ) が繰り返し実行され同じ結果を出す場合は、結果をマテリアライズドビューに物理的に保存し、レポートが事前計算された結果を読み取るようにする。重い計算は一度だけ実行され、クエリは即座に返る。","steps":["適用場面: 特定のサマリクエリが、同じ大きなテーブルを頻繁かつ繰り返しスキャンする場合。","リフレッシュ: マテリアライズドビューをスケジュールに従ってリフレッシュする (例: 夜間バッチまたは増分)。頻度は鮮度の要件に応じて設定する。","エンジン: PostgreSQL マテリアライズドビュー (REFRESH)、Oracle マテリアライズドビュー (クエリリライトも可能)、SQL Server インデックス付きビュー。","注意: ビューには鮮度のずれが伴う。リアルタイムのデータが必要な場合は、ライブクエリが必須。","次のステップ: リフレッシュのコストが高い場合は、増分リフレッシュまたはパーティション単位のリフレッシュを検討する。"],"related":["decide-partition"]}}},"solver/arch-microservice.json":{"id":"arch-microservice","title":"リファレンスアーキテクチャ: マイクロサービスのデータ層","icon":"🏛️","category":"リファレンスアーキテクチャ","intro":"マイクロサービスで最も重要な判断はデータの所有権: 各サービスは自らのデータを所有し (database-per-service)、他のサービスのテーブルに直接アクセスしてはならない。このツリーは、共有 DB のアンチパターン、分散トランザクションなしでのサービス間の一貫性の実現 (saga + outbox)、CDC によるデータの同期、サービス間のクエリ (API composition vs CQRS の読み取りモデル) を段階的に説明する。目的は、サービスを真に独立させ、個別にデプロイ可能な状態に保つこと。","start":"root","nodes":{"root":{"kind":"step","title":"サービスはどのようにデータを所有しているか: 共有 DB か、サービスごとか?","detail":"データの分離はマイクロサービスアーキテクチャの根幹。サービスは単一の共有データベースを使用している (隠れた依存関係) のか、各サービスが独自のデータベースを持っている (正しいパターン) のか、それとも本当の課題はサービス間の一貫性/クエリなのか? まず現状を把握する。","choices":[{"label":"すべてのサービスが単一の共有 DB を使用している","next":"sol_db_per_service"},{"label":"各サービスが独自の DB を持つが、処理にサービス間の一貫性が必要","next":"consistency"},{"label":"各サービスが独自の DB を持つが、結合したクエリ/レポートが必要","next":"query"}]},"consistency":{"kind":"step","title":"サービス間のワークフローの一貫性をどう保つか?","detail":"複数のサービスにまたがる処理 (注文作成 → 決済 → 在庫の減算) では、従来の分散トランザクション (2PC) は脆弱でスケールしない。代わりに、フローをローカルトランザクション + イベントのステップに分割し (saga)、イベントを確実に発行する (outbox)。どの問題に取り組んでいるか?","choices":[{"label":"複数サービスのワークフローをアトミックに保とうとしている (2PC?)","next":"sol_saga"},{"label":"ローカルの書き込みとイベント発行の一貫性を保てない (二重書き込み)","next":"sol_outbox"}]},"query":{"kind":"step","title":"複数のサービスのデータを表示するクエリをどのように提供しますか?","detail":"データがサービス間に分割されると、単一の結合で統合画面を構築することはできない。主に 2 つの方法がある: 要求時に関連サービスの API を呼び出して結果をマージする (API コンポジション)、またはイベントで更新される事前結合済みの読み取りモデルを維持する (CQRS)。クエリの頻度と複雑さによって選択が決まる。","choices":[{"label":"単純で頻度の低い結合。いくつかのサービスを呼び出してマージすれば十分","next":"sol_api_composition"},{"label":"複雑/頻繁な統合クエリ。既成の読み取りモデルが必要","next":"sol_cqrs"}]},"sol_db_per_service":{"kind":"solution","title":"推奨: Database-per-service (共有 DB を分割する)","detail":"複数のサービスが 1 つのデータベースを共有することは、隠れた危険な依存関係: あるサービスのスキーマ変更が他のサービスを壊し、テーブルの所有権が不明確になり、独立したデプロイが不可能になる。各サービスが自らのデータを所有する必要がある。","steps":["原則: 各サービスは自らのデータベースのみを読み書きする。他のサービスのテーブルに直接アクセスすることはできず、そのサービスの API を通じてのみデータを要求できる。","エンジンの独立性: 各サービスはニーズに合ったエンジンを選択できる (例: 注文には PostgreSQL、カタログには MongoDB、検索には Elasticsearch、カートには Redis)。","アンチパターン: 「共有データベース」: 共通のテーブル、相互の結合、単一のスキーマ。これはマイクロサービスではなく、分散モノリス。","分割: まず論理的な分離 (別スキーマ/ユーザー)、次に物理的な分離。テーブル間の結合を除去する。","注意: 分割後には、一貫性 (saga/outbox) と結合クエリ (composition/CQRS) の問題が生じる。これはこの移行に伴う当然のコスト。"],"related":["decide-isolation","decide-sqlnosql"]},"sol_saga":{"kind":"solution","title":"推奨: Saga パターン (分散トランザクションを避ける)","detail":"複数のサービスにまたがる処理を、単一の分散トランザクション (2PC) でアトミックにしようとしないこと。2PC はロックを保持し、単一点の脆弱性と低い可用性をもたらす。代わりに、フローをそれぞれのサービス内のローカルトランザクションであるステップに分割し、失敗時には補償ステップで取り消す。","steps":["原則: ワークフローをローカルトランザクション + イベントのチェーンとしてモデル化する。各ステップが次のステップをトリガーする。","補償: ステップが失敗した場合、前のステップを取り消す補償アクションを実行する (例: 決済が失敗したら注文をキャンセルする)。","コレオグラフィ vs オーケストレーション: 単純なフローではサービスがイベントで互いをトリガーする (コレオグラフィ)。複雑なフローでは中央のオーケストレーターがステップを管理する。","注意: saga はアトミックではなく、結果整合性を提供する。中間状態が外部から見える場合があるため、それに応じて業務ルールを設計する。","注意: 大規模なマイクロサービスで 2PC/XA を使用しないこと。ブロッキングとロックの保持時間によりシステムが停滞する。"],"related":["decide-isolation","long-transaction"]},"sol_outbox":{"kind":"solution","title":"推奨: トランザクショナルアウトボックス (二重書き込みの落とし穴)","detail":"サービスが自らの DB への書き込みとイベントの発行の両方を行う場合、2 つを別々に行うのは「二重書き込み」の落とし穴: 一方が成功し、もう一方が失敗すると、システムは不整合な状態になる。解決策は、業務データと同じローカルトランザクション内でイベントを outbox テーブルに書き込み、別のプロセスで発行すること。","steps":["原則: 業務レコード + イベントレコードを 1 つのローカルトランザクションで outbox テーブルに書き込む。両方が行われるか、どちらも行われないか (アトミック)。","発行: 別のリレー/CDC プロセスが outbox の行を読み取り、メッセージブローカー (例: Kafka) に発行して、発行済みとしてマークする。","CDC を使う場合: Debezium などの CDC ツールが DB のログ (WAL/binlog) を読み取り、outbox の変更を確実に Kafka へ移す。","冪等性: コンシューマーは同じイベントを複数回受信する可能性がある。イベント ID を使って冪等に処理する (at-least-once の配信を前提とする)。","注意: 「まず DB に書き込み、その後 Kafka に発行する」アプローチをそのまま使わないこと。発行時のクラッシュでイベントが失われる。"],"related":["replication-lag"]},"sol_api_composition":{"kind":"solution","title":"推奨: API composition (リクエスト時に結合)","detail":"結合したデータが必要な場合、呼び出し元 (例: ゲートウェイ/BFF) が該当するサービスの API を呼び出し、結果をメモリ上で結合する。少数のサービスにまたがる単純な結合には最もシンプルな解決策であり、追加のデータコピーを保持しない。","steps":["原則: コンポーザー (API ゲートウェイ/BFF) が service-A と service-B を呼び出し、結果を結合して返す。","適用場面: 結合が単純で、少数のサービスにまたがり、クエリの頻度が中程度の場合。追加の読み取りモデルの保守負担を避けたい場合。","利点: 追加のデータストアや同期が不要。各サービスが自らの最新データを返す。","注意: 多数のサービスや大規模なデータセットにまたがる結合では、レイテンシが累積し、メモリ上の結合も高コストになる。","次のステップ: 結合が複雑になったり非常に頻繁になったりした場合は、CQRS の読み取りモデルに移行する。"],"related":[]},"sol_cqrs":{"kind":"solution","title":"推奨: CQRS の読み取りモデル (イベントで供給)","detail":"複雑で頻繁な結合クエリには、サービスが発行するイベントで供給される、事前に結合されクエリに最適化された読み取りモデル (マテリアライズドビュー/非正規化コピー) を保持する。書き込み側はサービスにとどまり、読み取り側は 1 か所から準備済みのデータを高速に提供する。","steps":["原則: サービスは状態の変化をイベントとして発行する。プロジェクションがこれらのイベントを受信し、読み取りモデルを更新する。","ストアの選択: クエリの種類に応じて読み取りモデルのストアを選ぶ: 検索には Elasticsearch、柔軟なドキュメントには MongoDB、高速なキーアクセスには Redis、リレーショナルなレポートには PostgreSQL。","適用場面: 結合クエリが複雑/頻繁で、低レイテンシが必要であり、API composition のコストが大きくなった場合。","注意: 読み取りモデルは結果整合性。イベントが処理されるまでわずかに遅れる。","冪等性: プロジェクションは同じイベントを 2 回受け取る可能性がある。イベント ID で冪等に更新し、必要に応じて順序/バージョンを追跡する。"],"related":["decide-cache"]}}},"solver/arch-eventdriven.json":{"id":"arch-eventdriven","title":"リファレンスアーキテクチャ: イベント駆動 / CQRS","icon":"🏛️","category":"リファレンスアーキテクチャ","intro":"イベント駆動アーキテクチャでは、サービスは互いを直接呼び出す代わりにイベントログ (例: Kafka) にイベントを発行し、コンシューマーがそれを非同期に処理する。このツリーは、イベント基盤の構築を起点に、イベントソーシング (イベントから状態を導出)、CQRS によるコマンド/クエリの分離、読み取りモデルのプロジェクション、冪等性、結果整合性の許容、「exactly-once 配信」の誤謬を段階的に説明する。目的は、一貫性のトレードオフがよく理解された、疎結合でスケーラブルなシステム。","start":"root","nodes":{"root":{"kind":"step","title":"イベント駆動アーキテクチャでどの判断に直面しているか?","detail":"イベント駆動システムの基盤は、非同期のイベントでサービスを結び付ける永続的なイベントログ。まだ基盤を構築している段階か、イベントから状態を導出したい (イベントソーシング) のか、それとも読み取りと書き込みの経路を分離している (CQRS) のか?","choices":[{"label":"サービスを結び付けるイベント基盤を構築している","next":"sol_event_log"},{"label":"イベント履歴から状態を導出したい","next":"sol_event_sourcing"},{"label":"読み取りと書き込みの経路を分離したい (CQRS)","next":"cqrs_split"}]},"cqrs_split":{"kind":"step","title":"CQRS で読み取り側をどう構築するか、また一貫性の許容度は?","detail":"CQRS では、コマンド (書き込み) 側とクエリ (読み取り) 側が分離され、書き込みイベントが読み取りモデルに供給するプロジェクションを更新する。重要な問い: 読み取りモデルが書き込みより遅れること (結果整合性) を許容できるか、それともすべてのイベントが正確に 1 回だけ処理されることを期待するか?","choices":[{"label":"プロジェクションを介してイベントから読み取りモデルに供給する","next":"sol_read_model"},{"label":"読み取りは最新でなければならない。遅延は許容できない","next":"sol_consistency"},{"label":"イベントを「正確に 1 回」処理したい","next":"sol_idempotency"}]},"sol_event_log":{"kind":"solution","title":"推奨: 永続的なイベントログ基盤","detail":"イベント駆動アーキテクチャの中心には、プロデューサーが書き込み、コンシューマーが自分のペースで読み取る、永続的で順序付けられたイベントログがある。この基盤がサービスを時間とスケールの面で切り離す。","steps":["エンジン: Apache Kafka (または同様のログベースのプラットフォーム): パーティション化され、永続的で、再生可能なイベントログ。","パーティションと順序: 順序が保証されるのはパーティション内のみ。同じエンティティのイベントを同じキーにルーティングして順序を維持する。","コンシューマーの独立性: 各コンシューマーグループは独自のオフセットを保持し、プロデューサーに影響を与えずに再読み取り/巻き戻しができる。","保持期間: 新しいコンシューマーや再処理が履歴を読めるよう、ログを十分な期間保持する。","注意: Kafka はキューではなく再生可能なログ。at-least-once の配信を前提とし、冪等なコンシューマーを作成する。"],"related":[]},"sol_event_sourcing":{"kind":"solution","title":"推奨: イベントソーシング (イベントから状態を導出)","detail":"イベントソーシングでは、エンティティの現在の状態ではなく、それに適用されたすべての (不変の) 変更イベントを保存する。現在の状態は、これらのイベントを順に適用して導出する。完全な監査履歴と、過去の任意の時点に戻る機能を提供する。","steps":["原則: イベントストリームが信頼できる情報源。状態は、最初から (またはスナップショット + 後続のイベントから) イベントを再生して再構築する。","スナップショット: 長いストリームでは、毎回最初から再生するのを避けるため定期的にスナップショットを取得し、その上に後続のイベントを適用する。","利点: 完全な監査証跡、「どのようにしてこの状態に至ったか」への時系列での回答、異なる読み取りモデルを導出する能力。","注意: イベントのスキーマは進化する。イベントは永続的に残るため、古いイベントを読むにはバージョン管理/アップキャストが必要。","注意: すべてのシナリオで必要なわけではない。現在の状態で十分なら、従来の CRUD のほうがシンプル。通常は CQRS と組み合わせて使用する。"],"related":[]},"sol_read_model":{"kind":"solution","title":"推奨: 読み取りモデルのプロジェクション","detail":"CQRS では書き込み側がイベントを生成し、プロジェクションがこれらのイベントを受信して、クエリに最適化された読み取りモデル (非正規化ビュー) を更新する。読み取りはこの準備済みモデルから提供され、書き込み経路から完全に分離されるため、両側が独立してスケールする。","steps":["原則: イベント → プロジェクション → 読み取りストア。読み取りクエリはこの非正規化モデルのみにアクセスする。","ストアの選択: クエリの種類に応じて: 検索には Elasticsearch、柔軟なドキュメントには MongoDB、高速アクセスには Redis、リレーショナルには PostgreSQL。","再構築可能性: 読み取りモデルはイベントから導出されるため、破棄してログを再読み取りすることでゼロから再構築できる。","冪等性: プロジェクションは同じイベントを複数回受け取る可能性がある。イベント ID/バージョンを使って冪等に更新する。","注意: 読み取りモデルは結果整合性。イベントが処理されるまで書き込みより遅れるため、UI もそれに応じて設計する。"],"related":["decide-cache"]},"sol_consistency":{"kind":"solution","title":"推奨: 結果整合性を許容する設計","detail":"イベント駆動/CQRS システムでは、読み取りモデルは書き込みよりわずかに遅れる (結果整合性)。これを「排除」しようとするのではなく、許容するよう設計する。厳密な即時一貫性が必要な少数のフローは分離しておく。","steps":["原則: 大半の業務フローは短い遅延を伴う一貫性を許容できる。ユーザーには「リクエストを受け付けました。処理中です」とフィードバックする。","Read-your-writes: ユーザーが自分の書き込みを直ちに確認する必要がある場合は、その読み取りを書き込み側から/同期的に提供する。","厳密な一貫性が必要な中核部分: 金銭の残高など、絶対的な即時一貫性が必要な処理は、単一のサービス/DB 内で ACID トランザクションとして保持し、イベントで分散させないこと。","注意: 結果整合性を隠さないこと。中間/一時的な状態を画面と業務ルールで明示的に扱う。","注意: 「システム全体を強い一貫性にする」という目標は、イベント駆動アーキテクチャの利点 (スケール、疎結合) を損なう。"],"related":["decide-ha","replication-lag"]},"sol_idempotency":{"kind":"solution","title":"推奨: 冪等性 (exactly-once の誤謬)","detail":"分散メッセージングでは、エンドツーエンドの「exactly-once 配信」は実際には誤謬であり、ネットワークとリトライのためメッセージの重複は避けられない。正しい目標は冪等な処理: 同じイベントを 2 回処理しても、1 回処理した場合と同じ結果になること。","steps":["原則: at-least-once の配信を受け入れ、コンシューマー側で重複を無害にする。","方法: すべてのイベントに一意の ID を付与する。処理済みの ID を記録し、再度届いた場合はスキップする (重複排除)。または本質的に冪等な操作 (upsert、set) を使用する。","Exactly-once のセマンティクス: Kafka の 'exactly-once' 機能は Kafka 自身のトランザクション境界内でのみ適用される。外部 DB への副作用は、冪等性がなければ保証されない。","順序: 同じエンティティのイベントを同じパーティションキーにルーティングして、順序の入れ替わりを避ける。","注意: 「exactly-once 配信を設定したので重複排除は不要」という前提は、本番で不整合を生む。常に冪等に処理する。"],"related":[]}}},"solver/arch-multiregion.json":{"id":"arch-multiregion","title":"リファレンスアーキテクチャ: マルチリージョン / グローバル","icon":"🏛️","category":"リファレンスアーキテクチャ","intro":"ユーザーが地理的に分散している場合や、リージョン規模の災害への耐性が必要な場合、データは複数のリージョンに分散される。このツリーは、読み取りの局所性 (各リージョンのリードレプリカ)、書き込みのトポロジー (シングルリーダー vs マルチリーダー vs クォーラム)、データ所在地/コンプライアンス (GDPR)、競合解決、RPO/RTO とレイテンシのトレードオフを段階的に説明する。基本的な真実: 物理法則により、低レイテンシ、強い一貫性、マルチリージョン書き込みのすべてを同時に完全に実現することはできない。意図的なトレードオフが必須。","start":"root","nodes":{"root":{"kind":"step","title":"なぜマルチリージョンにするのか: 読み取りの局所性、書き込み/耐障害性、それともコンプライアンスか?","detail":"マルチリージョンアーキテクチャはコストが高く複雑。動機を明確にする。遠隔地のユーザーに低い読み取りレイテンシを提供したいのか、リージョン間の書き込み/災害耐性が必要なのか、それとも本当の要件はデータを特定の国に留めること (法的な所在地) なのか?","choices":[{"label":"遠隔地のユーザー向けの高速な読み取り。書き込みは 1 つのリージョンでよい","next":"sol_read_locality"},{"label":"リージョン間の書き込み / リージョン喪失への耐性が必要","next":"write_topology"},{"label":"データは法的に特定の国/リージョンに留める必要がある","next":"sol_data_residency"}]},"write_topology":{"kind":"step","title":"書き込みのトポロジーはどうすべきか: シングルリーダー、マルチリーダー、クォーラム?","detail":"リージョン間の書き込みにおける重要な判断はリーダーシップモデル。すべての書き込みを単一のリージョンに送るのか (シンプルで一貫しているが、遠隔からの書き込みは遅い)、すべてのリージョンが書き込めるのか (書き込みレイテンシは低いが競合が発生する)、それとも過半数のリージョンの確認応答で書き込みを受け付けるのか (クォーラム: 一貫しているがレイテンシが加わる)?","choices":[{"label":"1 つのリージョンが書き込み、他は読み取る (シンプルで一貫している)","next":"sol_single_leader"},{"label":"すべてのリージョンがローカルに書き込める (低い書き込みレイテンシ)","next":"sol_multi_leader"},{"label":"過半数の確認応答で書き込む。一貫性が最優先","next":"sol_quorum"}]},"sol_read_locality":{"kind":"solution","title":"推奨: リージョンごとのリードレプリカ (読み取りの局所性)","detail":"書き込みは単一のプライマリリージョンにとどめ、各ユーザーリージョンにそこから供給されるリードレプリカを配置する。ユーザーは最寄りのレプリカから読み取るため読み取りレイテンシが下がり、書き込みは引き続き単一の拠点に送られるため一貫性モデルはシンプルなまま。","steps":["トポロジー: 1 つのプライマリリージョン (書き込み) → 各ユーザーリージョンの非同期リードレプリカ。","エンジン: PostgreSQL ストリーミングレプリケーション、MySQL のリージョン間レプリカ、またはマネージドのグローバルリードレプリカ。","ルーティング: アプリケーションは読み取りを最寄りのレプリカに、書き込みをプライマリリージョンにルーティングする (geo DNS / スマートルーター)。","注意: リージョン間のレプリケーション遅延により古いデータが読み取られる。read-your-writes が必要なフローはプライマリから読み取る。","RPO/RTO: プライマリリージョンがダウンした場合、非同期レプリカをある程度のデータ損失を伴って昇格できる (RPO > 0)。フェイルオーバー計画を事前に準備する。"],"related":["replication-lag","decide-shard-replica"]},"sol_single_leader":{"kind":"solution","title":"推奨: シングルリーダーの書き込み","detail":"すべての書き込みは単一のリーダーリージョンに送られ、他のリージョンはそのリーダーから非同期に供給されるリードレプリカ。最もシンプルで最も一貫性の強いモデルであり、書き込み地点が 1 つなので競合はない。代償は遠隔リージョンからの高い書き込みレイテンシ。","steps":["原則: 単一の書き込み権限 → 競合なし、シンプルな一貫性モデル。","適用場面: 書き込み量を 1 つのリージョンで処理でき、遠隔からの書き込みレイテンシが許容できる場合。","フェイルオーバー: リーダーリージョンがダウンした場合、レプリカをリーダーに昇格させる。自動/制御されたフェイルオーバーとスプリットブレイン対策が必須。","RPO/RTO: 非同期レプリケーションでは、フェイルオーバー時に少量のデータが失われる可能性がある (RPO)。同期レプリケーションでは RPO=0 になるが、書き込みレイテンシが増加する。","注意: 遠隔地のユーザーからの書き込みは遅い。書き込みの局所性が重要な場合は、マルチリーダーまたはクォーラムを検討する。"],"related":["decide-ha","failover-drill"]},"sol_multi_leader":{"kind":"solution","title":"推奨: マルチリーダーの書き込み + 競合解決","detail":"すべてのリージョンがローカルに書き込めるため書き込みレイテンシは低く、1 つのリージョンが切断されても他のリージョンは書き込みを続けられる。代償は大きい: 2 つのリージョンが同じレコードを異なる内容で更新する可能性があり、競合解決を設計する必要がある。","steps":["原則: すべてのリージョンがリーダー。書き込みは他のリージョンに非同期で伝播され、マージされる。","競合解決: Last-write-wins (シンプルだがデータ損失のリスクあり)、アプリケーション固有のマージ、または CRDT などの競合のないデータ型。","エンジンの例: マルチマスター/マルチリーダー構成 (例: PostgreSQL 向けの EDB Postgres Distributed (BDR)/pgEdge、Redis Enterprise Active-Active (CRDT)、CouchDB)。Cassandra はマルチリーダーではなくリーダーレスであり、LOCAL_ONE/LOCAL_QUORUM によりすべてのリージョンでローカル書き込みが可能となって同様の結果が得られ、競合は last-write-wins (タイムスタンプ) で解決する。","適用場面: 強い一貫性よりも、ローカルの書き込みレイテンシとリージョンの独立性が重要な場合。","注意: 競合解決は最初から設計する。「競合は起きない」という前提は、気付かないうちにデータ損失を生む。一意な ID の生成におけるリージョン間の衝突に注意する。"],"related":["decide-ha"]},"sol_quorum":{"kind":"solution","title":"推奨: クォーラムベースの書き込み (過半数の確認応答)","detail":"書き込みは、リージョン/レプリカの過半数 (クォーラム) が確認応答したときに受け付けられる。読み取りも過半数に対して行えば、最新の値が保証される。リージョンの喪失に強く一貫性も強い。代償は、すべての書き込みが過半数に到達するまでのレイテンシ。","steps":["原則: W + R > N のルールによる過半数の確認応答。少数側のリージョンがダウンしても、システムは一貫して書き込みを続ける。","エンジンの例: コンセンサスベースの分散 DB (例: Raft/Paxos を使用するシステム)、Cassandra の QUORUM 一貫性レベル。","適用場面: リージョン規模の災害への耐性と強い一貫性の両方が必要で、書き込みレイテンシの増加が許容できる場合。","RPO/RTO: 過半数が永続的に書き込むため RPO≈0。リージョン喪失後に過半数が自動的に再形成されれば、RTO も低く抑えられる。","注意: 地理的に離れたリージョン間のクォーラムは、光速によるレイテンシのため、すべての書き込みに数十 ms を加える。リージョンの数と配置は慎重に選択する。"],"related":["decide-ha","decide-shard-replica"]},"sol_data_residency":{"kind":"solution","title":"推奨: データ所在地 / コンプライアンス (GDPR)","detail":"一部のデータ (個人、医療、金融) は、法的に特定の国/リージョンの境界内にとどめる必要がある (例: GDPR)。この場合、アーキテクチャは「どこにでもコピーする」ではなく、データが地理的に固定されるように設計する。","steps":["原則: 個人データ/規制対象データは発生したリージョンに保持する。リージョン外へのレプリケーションを制限または禁止する。","リージョン単位のパーティショニング: ユーザーを登録先のリージョンにルーティングする (geo-partitioning)。各リージョンは自らの居住者のデータを保持する。","グローバルデータ vs ローカルデータ: カタログなどのグローバルデータはどこにでもレプリケートできる。個人データはリージョン内にとどめる。","注意: バックアップとリードレプリカもデータを移動させる。バックアップストレージのリージョンと DR リージョンもコンプライアンスの対象範囲。","注意: 「低レイテンシのためだけにどこにでもコピーしよう」という判断は、規制対象データでは法令違反になり得る。所在地の制約を最初からアーキテクチャに組み込む。"],"related":["security-incident","audit-setup"]}}},"solver/arch-highscale.json":{"id":"arch-highscale","title":"リファレンスアーキテクチャ: 大規模 / 高トラフィック","icon":"🏛️","category":"リファレンスアーキテクチャ","intro":"トラフィックが増加する中でデータベースを守るには、正しい順序がある: まずシンプルで安価な対策、次に複雑な対策。このツリーは、垂直スケーリング → リードレプリカ → シャーディングの順序、キャッシュパターン (cache-aside、write-back)、キュー + バックプレッシャーによるバッファリング、レート制限、バルクヘッド/サーキットブレーカーによるデータベースの隔離、ホットスポットの防止を段階的に説明する。基本原則: シャーディングのように元に戻しにくい判断は最後に回し、まず安価な改善を尽くす。","start":"root","nodes":{"root":{"kind":"step","title":"ボトルネックはどこか: 単一インスタンスが飽和しているのか、読み取りまたは書き込みが多いのか、それともトラフィックが突発的なのか?","detail":"スケーリングの問題を適切な場所で解決するには、まずボトルネックを特定する。単一インスタンスの CPU/メモリが飽和しているのか、読み取りが支配的なのか、書き込みが上限に達しているのか、それとも突発的なトラフィックの急増がデータベースを圧迫しているのか? それぞれ異なるコンポーネントを示す。","choices":[{"label":"単一インスタンスが飽和している。シンプルな対策はまだ試していない","next":"scale_path"},{"label":"読み取りが非常に多く、増加している","next":"sol_cache"},{"label":"突発的なトラフィックの急増 / バースト負荷が DB を圧迫している","next":"protect"}]},"scale_path":{"kind":"step","title":"スケーリングのどの段階にいるか: 垂直、リードレプリカ、シャーディング?","detail":"スケーリングには正しい順序がある。垂直スケーリング (より強力なハードウェア) は最もシンプルな最初のステップ。次に読み取りをレプリカに分散し、単一のプライマリが書き込みを処理しきれなくなって初めて水平分割 (シャーディング) に移行する。現在どこにいるか?","choices":[{"label":"まだハードウェアのスケールアップ / 基本的なチューニングを尽くしていない","next":"sol_vertical"},{"label":"書き込みは 1 つのインスタンスに収まるが、読み取り負荷を分散する必要がある","next":"sol_read_replica"},{"label":"単一のプライマリでは書き込み負荷を処理しきれなくなった","next":"sol_sharding"}]},"protect":{"kind":"step","title":"データベースを負荷からどう保護するか: バッファリング、制限、それとも隔離か?","detail":"スケーリングとは常に DB を大きくすることではなく、多くの場合は DB を過負荷から守ること。突発的な書き込みの急増をキューで平準化するのか、受信リクエストのレートを制限するのか (レート制限)、それとも単一の依存先がシステム全体をダウンさせないようにするのか (バルクヘッド/サーキットブレーカー)?","choices":[{"label":"突発的な書き込みの急増を平準化したい","next":"sol_queue"},{"label":"受信リクエストのレートを制限/公平に配分したい","next":"sol_ratelimit"},{"label":"障害を起こした 1 つの依存先がシステム全体をダウンさせないようにしたい","next":"sol_bulkhead"}]},"sol_vertical":{"kind":"solution","title":"推奨: まず垂直スケーリングと基本的なチューニング","detail":"最も安価でリスクの低いステップは垂直スケーリング: CPU/RAM の増強や高速なディスクの追加と、基本事項 (インデックス、コネクションプーリング、メモリパラメータ) の修正。シャーディングのような複雑な判断の前に、これらの改善を尽くす。","steps":["最初のステップ: ハードウェア (CPU/RAM/NVMe) をスケールアップし、バッファ/キャッシュのメモリパラメータをワークロードに合わせてチューニングする。","安価な改善: 不足しているインデックスを追加し、重いクエリを修正し、前段にコネクションプーラー (PgBouncer/ProxySQL) を置く。「スケール」の問題の大半は、実際にはチューニングの問題。","十分な場合: スケールアップした単一インスタンスが目標のレイテンシ/スループットを満たすなら、そこで止める。これ以上複雑さを加えないこと。","注意: 垂直スケーリングには物理的およびコスト上の上限がある。上限に近づいたら、リードレプリカとキャッシュに移行する。","次のステップ: 読み取りが支配的ならレプリカ + キャッシュ、書き込みが支配的で上限を超えたらシャーディング。"],"related":["decide-capacity","high-cpu"]},"sol_read_replica":{"kind":"solution","title":"推奨: リードレプリカで読み取りを分散する","detail":"書き込みは単一のプライマリにとどめ、読み取り専用のトラフィックを 1 つ以上のレプリカに分散する。シャーディングよりはるかにシンプルで、読み取り中心のワークロードの大半を解決する。プライマリは書き込みと一貫性が重要な読み取りのみに使用する。","steps":["トポロジー: プライマリ (書き込み) → 複数の非同期リードレプリカ。読み取りはロードバランサーを介してレプリカに分散される。","エンジン: PostgreSQL ストリーミングレプリケーション、MySQL レプリカ、マネージドのリードレプリカ。","適用場面: 読み取り/書き込み比率が読み取りに大きく偏っており、書き込みはまだ単一インスタンスで処理できる場合。","注意: レプリケーション遅延により古いデータが読み取られる。read-your-writes が必要な読み取りはプライマリから提供する。","次のステップ: レプリカでも不十分な場合、または実際のボトルネックが書き込みである場合は、キャッシュを追加し、次にシャーディングを検討する。"],"related":["replication-lag","decide-shard-replica"]},"sol_sharding":{"kind":"solution","title":"推奨: 最終手段としてのシャーディング (水平分割)","detail":"単一のプライマリが書き込み負荷を処理できない場合、データをキーで複数の独立した断片 (シャード) に分割し、各シャードが書き込みの一部を担う。強力だが元に戻しにくく、シャードをまたぐクエリとトランザクションを複雑にするため、最後に回す。","steps":["シャードキー: 負荷とデータを均等に分散し、大半のクエリが単一のシャードで完結するキーを選ぶ (例: customer_id)。","方法: ハッシュベース (均等な分散) またはレンジベース (範囲クエリが容易だがホットスポットのリスクあり) の分割。","エンジンの例: MongoDB シャーディング、Citus (PostgreSQL)、Vitess (MySQL)、またはアプリケーションレベルのシャーディング。","注意: シャードをまたぐ結合/トランザクションは高コストで複雑。大半のトランザクションが単一のシャード内で完結するようにスキーマを設計する。","注意: 誤ったキーはホットスポット (1 つのシャードへの負荷の集中) を生む。増加する id/日付のような単調なキーは避け、リシャーディングは難しいことを念頭に置く。"],"related":["decide-shard-replica","decide-partition"]},"sol_cache":{"kind":"solution","title":"推奨: キャッシュパターン (cache-aside + write-back)","detail":"読み取り中心の高トラフィックでは、DB の前段にインメモリキャッシュ (Redis) を置き、大半の読み取りを DB に到達させずに処理する。大量の書き込みには、write-back が書き込みをバッファリングしてバッチで DB にフラッシュし、プライマリの負荷を軽減する。","steps":["Cache-aside: アプリケーションはまず Redis を確認し、ミスした場合は DB から取得してキャッシュに書き込む。これにより読み取り負荷の大半が DB から取り除かれる。","Write-back (write-behind): カウンタ/メトリクスなど非常に大量の書き込みでは、まずキャッシュに書き込み、バックグラウンドでバッチ単位で DB にフラッシュする。","TTL + 無効化: キーに妥当な TTL を設定する。書き込み時には関連するキーを更新/削除し、古いデータが残らないようにする。","注意: キャッシュスタンピード: 人気のあるキーが期限切れになると、数千のリクエストが一度に DB に殺到する。ロック/single-flight、早期リフレッシュ、ジッター付きの TTL を使用する。","注意: write-back では、DB に書き込む前にキャッシュノードがクラッシュするとデータが失われる。重要なデータは耐久性のあるキュー/AOF で保護する。"],"related":["decide-cache","cache-hit-low"]},"sol_queue":{"kind":"solution","title":"推奨: キューによるバッファリング (バックプレッシャー)","detail":"突発的な書き込みの急増が直接 DB に到達しないよう、間に耐久性のあるキュー (例: Kafka/メッセージキュー) を置き、DB が維持できるレートで書き込みを消費する。キューが急増を吸収し、システムは同期的に失敗する代わりに、制御されたレイテンシで動作する (バックプレッシャー)。","steps":["原則: プロデューサーはイベントをキューに書き込み、コンシューマーは維持可能なレートで (場合によってはバッチで) DB に書き込む。","エンジン: Kafka またはメッセージキュー。ピークトラフィックから DB を隔離するバッファとして機能する。","バックプレッシャー: キューが増え続ける場合は、プロデューサーを減速させる/通知する。無制限の蓄積を許さないこと。そうしないとレイテンシが急増する。","適用場面: 書き込みトラフィックが非常に突発的で、即時の同期処理が必須ではない (非同期処理が許容できる) 場合。","注意: キューは非同期性をもたらし、結果は結果整合性になる。コンシューマーを冪等にする (メッセージは再配信される可能性がある)。"],"related":["connection-storm"]},"sol_ratelimit":{"kind":"solution","title":"推奨: レート制限 (リクエストのレートを制限する)","detail":"ソースごとに受信リクエストを制限する (レート制限) ことで、悪用と、単一のクライアントがすべてのリソースを消費することの両方を防ぐ。DB に到達する負荷に上限を設けることで、システムを予測可能かつ公平に保つ。","steps":["配置: 制限は DB の前段 (API ゲートウェイ / アプリケーションのエッジ) で適用する。受け付けたリクエストのみが DB に到達するようにする。","方法: トークンバケット / スライディングウィンドウによるクライアントごとまたはユーザーごとのレート。超過時は 429 を返す。","公平な配分: クォータを使用して、「うるさい隣人」がすべての容量を占有するのを防ぐ。","適用場面: トラフィックが突然急増する可能性がある場合、または悪用/自動化されたクライアントのリスクがある場合。","注意: レート制限は保護策であり、スケーリングではない。実際に容量が必要な場合は、実際のボトルネック (垂直/レプリカ/シャード) も解消する。"],"related":["connection-storm"]},"sol_bulkhead":{"kind":"solution","title":"推奨: バルクヘッド + サーキットブレーカー (隔離)","detail":"依存先 (例: 低速化した DB や外部サービス) がシステム全体をダウンさせないよう、リソースを区画 (バルクヘッド) に分割し、失敗し続ける依存先への呼び出しを一時的に遮断する (サーキットブレーカー)。これにより、部分的な障害がシステム全体に広がらない。","steps":["バルクヘッド: 異なる種類の処理に別々のコネクションプール/スレッドを割り当てる。1 つの低速な経路がプール全体を使い果たし、他の処理を枯渇させてはならない。","サーキットブレーカー: 依存先がエラー/レイテンシのしきい値を超えたら、回路を「オープン」にして一定時間は即座に失敗させる。その後、試行呼び出しで回復を確認する (ハーフオープン)。","タイムアウト: すべての DB/サービス呼び出しに妥当なタイムアウトを設定する。応答のない呼び出しがプールを占有してはならない。","適用場面: 多数の依存先を持つシステムで、1 つのコンポーネントの低速化が連鎖的な障害につながるリスクがある場合。","注意: 回路がオープンのときのグレースフルデグラデーションを設計する: リクエスト全体を拒否するのではなく、キャッシュから古いデータや部分的な結果を返す。"],"related":["connection-storm","high-cpu"]}}},"types/types-functions.json":{"schemaVersion":1,"sections":[{"id":"datatypes","title":"データ型","icon":"🔤","rows":[{"id":"var-text","concept":"可変長テキスト","engines":{"oracle":"VARCHAR2(n)","postgres":"VARCHAR(n) / TEXT","mysql":"VARCHAR(n)","mssql":"NVARCHAR(n)","mongodb":"string","redis":"string (value)","elasticsearch":"text / keyword"},"note":"ES では、全文検索には text を、完全一致/集計には keyword を使用する。"},{"id":"fixed-text","concept":"固定長テキスト","engines":{"oracle":"CHAR(n)","postgres":"CHAR(n)","mysql":"CHAR(n)","mssql":"NCHAR(n)","mongodb":"string","redis":"string","elasticsearch":"keyword"},"note":"ドキュメント/キーバリューシステムには固定長の概念がなく、値は文字列として格納される。"},{"id":"large-text","concept":"大きなテキスト (CLOB/TEXT)","engines":{"oracle":"CLOB","postgres":"TEXT","mysql":"LONGTEXT / TEXT","mssql":"NVARCHAR(MAX)","mongodb":"string","redis":"string (up to 512 MB)","elasticsearch":"text"}},{"id":"int32","concept":"整数 (32 ビット)","engines":{"oracle":"NUMBER(10)","postgres":"INTEGER / INT4","mysql":"INT","mssql":"INT","mongodb":"int (NumberInt / int32)","redis":"string (interpreted as an integer)","elasticsearch":"integer"},"note":"Oracle には独立した INT 型がなく、NUMBER を使用する。"},{"id":"int64","concept":"大きな整数 (64 ビット)","engines":{"oracle":"NUMBER(19)","postgres":"BIGINT / INT8","mysql":"BIGINT","mssql":"BIGINT","mongodb":"long (NumberLong / int64)","redis":"string (INCR 64-bit integer)","elasticsearch":"long"}},{"id":"decimal","concept":"10 進数/正確な数値 (NUMERIC)","engines":{"oracle":"NUMBER(p,s)","postgres":"NUMERIC(p,s) / DECIMAL","mysql":"DECIMAL(p,s)","mssql":"DECIMAL(p,s) / NUMERIC","mongodb":"decimal (Decimal128)","redis":"none, stored as a string","elasticsearch":"scaled_float"},"note":"金額などの正確な値には、float よりもこれらの型が推奨される。"},{"id":"float","concept":"浮動小数点 (FLOAT/DOUBLE)","engines":{"oracle":"BINARY_DOUBLE / FLOAT","postgres":"REAL / DOUBLE PRECISION","mysql":"FLOAT / DOUBLE","mssql":"FLOAT / REAL","mongodb":"double","redis":"none, string (INCRBYFLOAT)","elasticsearch":"float / double"}},{"id":"boolean","concept":"論理値 (BOOLEAN)","engines":{"oracle":"NUMBER(1) / CHAR(1) (BOOLEAN in 23c)","postgres":"BOOLEAN","mysql":"TINYINT(1) / BOOL","mssql":"BIT","mongodb":"bool","redis":"none, 0/1 string or bit","elasticsearch":"boolean"},"note":"Oracle SQL で BOOLEAN 列型が導入されたのは 23c から。それ以前は NUMBER/CHAR で代用する。"},{"id":"date","concept":"日付","engines":{"oracle":"DATE (includes time)","postgres":"DATE","mysql":"DATE","mssql":"DATE","mongodb":"Date (ISODate)","redis":"none (epoch string/number)","elasticsearch":"date (with format)"},"note":"Oracle の DATE 型は日付と時刻の両方を保持し、日付のみではない。"},{"id":"datetime","concept":"日時 (timestamp/datetime)","engines":{"oracle":"TIMESTAMP","postgres":"TIMESTAMP","mysql":"DATETIME / TIMESTAMP","mssql":"DATETIME2","mongodb":"Date (ISODate)","redis":"none (epoch string/number)","elasticsearch":"date"}},{"id":"datetime-tz","concept":"タイムゾーン付き日時","engines":{"oracle":"TIMESTAMP WITH TIME ZONE","postgres":"TIMESTAMPTZ","mysql":"TIMESTAMP (stored as UTC)","mssql":"DATETIMEOFFSET","mongodb":"Date (stored as UTC)","redis":"none (epoch UTC)","elasticsearch":"date (UTC, time zone via format)"},"note":"Mongo と ES は日付を UTC で格納し、タイムゾーンは表示時に適用される。"},{"id":"binary","concept":"バイナリデータ (BLOB/binary)","engines":{"oracle":"BLOB / RAW","postgres":"BYTEA","mysql":"BLOB / VARBINARY","mssql":"VARBINARY(MAX)","mongodb":"BinData (binary)","redis":"string (binary-safe)","elasticsearch":"binary (base64, not searchable)"},"note":"Redis の文字列はバイナリセーフであり、任意のバイト列を保持できる。"},{"id":"uuid","concept":"UUID/GUID","engines":{"oracle":"RAW(16) / SYS_GUID()","postgres":"UUID","mysql":"BINARY(16) / CHAR(36)","mssql":"UNIQUEIDENTIFIER","mongodb":"UUID (BinData subtype 4) / ObjectId","redis":"none, stored as a string","elasticsearch":"keyword"},"note":"Mongo のネイティブな _id は ObjectId。UUID を BinData として格納することもできる。"},{"id":"json","concept":"JSON","engines":{"oracle":"JSON (21c+) / CLOB","postgres":"JSON / JSONB","mysql":"JSON","mssql":"JSON (2025) / NVARCHAR","mongodb":"object (native BSON)","redis":"not native / RedisJSON module","elasticsearch":"object / nested / flattened"},"note":"Postgres では照会/インデックス作成に JSONB が推奨される。MongoDB はもともとドキュメントベース。"},{"id":"auto-increment","concept":"自動採番 (identity/serial)","engines":{"oracle":"GENERATED AS IDENTITY / SEQUENCE","postgres":"SERIAL / GENERATED ... IDENTITY","mysql":"AUTO_INCREMENT","mssql":"IDENTITY(1,1)","mongodb":"none (ObjectId or a counter pattern)","redis":"counter with INCR","elasticsearch":"none (automatic _id)"}},{"id":"enum","concept":"列挙型/固定リスト","engines":{"oracle":"via a CHECK constraint","postgres":"ENUM (CREATE TYPE)","mysql":"ENUM(...)","mssql":"via a CHECK constraint","mongodb":"none (validation with JSON Schema enum)","redis":"none, stored as a string","elasticsearch":"keyword"}},{"id":"array","concept":"配列","engines":{"oracle":"VARRAY / nested table / collection","postgres":"ARRAY (e.g. INTEGER[])","mysql":"none (via JSON array)","mssql":"none (JSON / table variable)","mongodb":"array (native)","redis":"List / Set (native)","elasticsearch":"any field can be an array (native)"},"note":"ES では、すべてのフィールドが暗黙的に配列を保持でき、独立した配列型はない。"},{"id":"ip-address","concept":"IP アドレス","engines":{"oracle":"VARCHAR2 / UTL_INADDR","postgres":"INET / CIDR","mysql":"VARBINARY(16) / INET6_ATON","mssql":"none, via VARCHAR","mongodb":"none, stored as a string","redis":"none, stored as a string","elasticsearch":"ip"},"note":"Postgres と ES のネイティブな IP 型は、範囲/サブネットのクエリをサポートする。"},{"id":"money","concept":"金額","engines":{"oracle":"NUMBER(p,2)","postgres":"MONEY / NUMERIC(p,2)","mysql":"DECIMAL(p,2)","mssql":"MONEY / DECIMAL(p,2)","mongodb":"decimal (Decimal128)","redis":"none, an integer in minor units (cents) is recommended","elasticsearch":"scaled_float"},"note":"丸め誤差を避けるため、金額は float ではなく DECIMAL/Decimal128 で格納する。"},{"id":"spatial","concept":"地理/空間","engines":{"oracle":"SDO_GEOMETRY (Oracle Spatial)","postgres":"GEOMETRY / GEOGRAPHY (PostGIS)","mysql":"GEOMETRY / POINT","mssql":"GEOGRAPHY / GEOMETRY","mongodb":"GeoJSON object (2dsphere index)","redis":"Geo (GEOADD, sorted set based)","elasticsearch":"geo_point / geo_shape"}}]},{"id":"functions","title":"共通関数","icon":"🧩","rows":[{"id":"coalesce","concept":"NULL の場合にデフォルト値を返す (COALESCE/NVL)","engines":{"oracle":"NVL(x, y) / COALESCE","postgres":"COALESCE(x, y)","mysql":"COALESCE(x, y) / IFNULL","mssql":"COALESCE(x, y) / ISNULL","mongodb":"$ifNull: [x, y]","redis":"none (application side)","elasticsearch":"?.field / painless ternary"}},{"id":"nullif-replace","concept":"NULL の場合に置き換える (ISNULL/IFNULL)","engines":{"oracle":"NVL(x, y)","postgres":"COALESCE(x, y)","mysql":"IFNULL(x, y)","mssql":"ISNULL(x, y)","mongodb":"$ifNull: [x, y]","redis":"none","elasticsearch":"painless: doc[f].size()==0 ? y : x"}},{"id":"now","concept":"現在の日時 (NOW/SYSDATE)","engines":{"oracle":"SYSDATE / SYSTIMESTAMP","postgres":"NOW() / CURRENT_TIMESTAMP","mysql":"NOW()","mssql":"GETDATE() / SYSDATETIME()","mongodb":"$$NOW / new Date()","redis":"TIME command","elasticsearch":"now (date math)"}},{"id":"current-date","concept":"現在の日付","engines":{"oracle":"TRUNC(SYSDATE) / CURRENT_DATE","postgres":"CURRENT_DATE","mysql":"CURDATE()","mssql":"CAST(GETDATE() AS DATE)","mongodb":"$dateTrunc / new Date()","redis":"TIME (epoch)","elasticsearch":"now/d"}},{"id":"concat","concept":"テキストの連結 (concat)","engines":{"oracle":"a || b / CONCAT","postgres":"a || b / CONCAT","mysql":"CONCAT(a, b)","mssql":"CONCAT(a, b) / a + b","mongodb":"$concat: [a, b]","redis":"APPEND","elasticsearch":"painless: a + b"},"note":"MySQL では、デフォルトで || は OR を意味する。連結には CONCAT を使用する。"},{"id":"substring","concept":"部分文字列","engines":{"oracle":"SUBSTR(s, p, n)","postgres":"SUBSTRING(s, p, n)","mysql":"SUBSTRING(s, p, n)","mssql":"SUBSTRING(s, p, n)","mongodb":"$substrCP: [s, p, n]","redis":"GETRANGE key start end","elasticsearch":"painless: s.substring(p, e)"}},{"id":"length","concept":"文字列の長さ","engines":{"oracle":"LENGTH(s)","postgres":"LENGTH(s) / CHAR_LENGTH","mysql":"CHAR_LENGTH(s)","mssql":"LEN(s)","mongodb":"$strLenCP: s","redis":"STRLEN key","elasticsearch":"painless: s.length()"}},{"id":"upper-lower","concept":"大文字/小文字","engines":{"oracle":"UPPER(s) / LOWER(s)","postgres":"UPPER(s) / LOWER(s)","mysql":"UPPER(s) / LOWER(s)","mssql":"UPPER(s) / LOWER(s)","mongodb":"$toUpper / $toLower","redis":"none (application side)","elasticsearch":"painless: s.toUpperCase() / lowercase analyzer"}},{"id":"trim","concept":"空白の除去 (TRIM)","engines":{"oracle":"TRIM(s) / LTRIM / RTRIM","postgres":"TRIM(s)","mysql":"TRIM(s)","mssql":"TRIM(s)","mongodb":"$trim: { input: s }","redis":"none","elasticsearch":"painless: s.trim() / trim token filter"}},{"id":"replace","concept":"テキストの置換 (REPLACE)","engines":{"oracle":"REPLACE(s, a, b)","postgres":"REPLACE(s, a, b)","mysql":"REPLACE(s, a, b)","mssql":"REPLACE(s, a, b)","mongodb":"$replaceAll / $replaceOne","redis":"SETRANGE (positional) / none","elasticsearch":"painless: s.replace(a, b)"}},{"id":"cast","concept":"型変換 (CAST/CONVERT)","engines":{"oracle":"CAST(x AS t) / TO_NUMBER","postgres":"CAST(x AS t) / x::t","mysql":"CAST(x AS t) / CONVERT","mssql":"CAST(x AS t) / CONVERT","mongodb":"$convert / $toInt, $toString","redis":"none (everything is a string)","elasticsearch":"painless: Integer.parseInt(...) / runtime field"}},{"id":"date-to-char","concept":"日付をテキストに書式化 (TO_CHAR/FORMAT)","engines":{"oracle":"TO_CHAR(d, 'YYYY-MM-DD')","postgres":"TO_CHAR(d, 'YYYY-MM-DD')","mysql":"DATE_FORMAT(d, '%Y-%m-%d')","mssql":"FORMAT(d, 'yyyy-MM-dd') / CONVERT","mongodb":"$dateToString: { format, date }","redis":"none","elasticsearch":"date field format / painless SimpleDateFormat"}},{"id":"parse-date","concept":"テキストを日付に変換 (TO_DATE/PARSE)","engines":{"oracle":"TO_DATE(s, 'YYYY-MM-DD')","postgres":"TO_DATE(s, 'YYYY-MM-DD')","mysql":"STR_TO_DATE(s, '%Y-%m-%d')","mssql":"CONVERT(date, s) / PARSE","mongodb":"$dateFromString: { dateString: s }","redis":"none","elasticsearch":"automatic parsing via date mapping"}},{"id":"date-add","concept":"日付への加算 (interval/DATEADD)","engines":{"oracle":"d + n / ADD_MONTHS / INTERVAL","postgres":"d + INTERVAL '1 day'","mysql":"DATE_ADD(d, INTERVAL 1 DAY)","mssql":"DATEADD(day, 1, d)","mongodb":"$dateAdd: { startDate, unit, amount }","redis":"none (add to the epoch)","elasticsearch":"date math: now+1d"}},{"id":"date-diff","concept":"2 つの日付の差 (DATEDIFF)","engines":{"oracle":"d1 - d2 (days) / MONTHS_BETWEEN","postgres":"d1 - d2 / AGE(d1, d2)","mysql":"DATEDIFF(d1, d2)","mssql":"DATEDIFF(day, d2, d1)","mongodb":"$dateDiff: { startDate, endDate, unit }","redis":"none (epoch difference)","elasticsearch":"painless: ChronoUnit.DAYS.between(...)"}},{"id":"extract","concept":"日付の要素を抽出 (EXTRACT)","engines":{"oracle":"EXTRACT(YEAR FROM d)","postgres":"EXTRACT(YEAR FROM d) / DATE_PART","mysql":"EXTRACT(YEAR FROM d) / YEAR(d)","mssql":"DATEPART(year, d) / YEAR(d)","mongodb":"$year / $month / $dayOfMonth","redis":"none","elasticsearch":"painless: doc[f].value.year"}},{"id":"round","concept":"丸め (ROUND)","engines":{"oracle":"ROUND(x, n)","postgres":"ROUND(x, n)","mysql":"ROUND(x, n)","mssql":"ROUND(x, n)","mongodb":"$round: [x, n]","redis":"none","elasticsearch":"painless: Math.round(x)"}},{"id":"mod","concept":"剰余 (余り)","engines":{"oracle":"MOD(a, b)","postgres":"MOD(a, b) / a % b","mysql":"MOD(a, b) / a % b","mssql":"a % b","mongodb":"$mod: [a, b]","redis":"none","elasticsearch":"painless: a % b"}},{"id":"case","concept":"条件分岐 (CASE/DECODE)","engines":{"oracle":"CASE ... / DECODE(x, ...)","postgres":"CASE WHEN ... END","mysql":"CASE WHEN ... END / IF()","mssql":"CASE WHEN ... END / IIF()","mongodb":"$cond / $switch","redis":"none","elasticsearch":"painless: if/else"}},{"id":"greatest-least","concept":"最大/最小 (GREATEST/LEAST)","engines":{"oracle":"GREATEST(...) / LEAST(...)","postgres":"GREATEST(...) / LEAST(...)","mysql":"GREATEST(...) / LEAST(...)","mssql":"GREATEST(...) / LEAST(...) (2022+)","mongodb":"$max / $min (expression)","redis":"none","elasticsearch":"painless: Math.max / Math.min"}},{"id":"string-agg","concept":"グループ内での連結 (STRING_AGG/GROUP_CONCAT/LISTAGG)","engines":{"oracle":"LISTAGG(x, ',')","postgres":"STRING_AGG(x, ',')","mysql":"GROUP_CONCAT(x)","mssql":"STRING_AGG(x, ',')","mongodb":"$push + $reduce / $concatArrays","redis":"none","elasticsearch":"terms agg / scripted_metric"}},{"id":"row-number","concept":"行番号 (ROW_NUMBER)","engines":{"oracle":"ROW_NUMBER() OVER (...)","postgres":"ROW_NUMBER() OVER (...)","mysql":"ROW_NUMBER() OVER (...)","mssql":"ROW_NUMBER() OVER (...)","mongodb":"$setWindowFields: { $documentNumber }","redis":"none","elasticsearch":"none (top_hits / bucket_sort)"}},{"id":"limit","concept":"先頭 N 行 (LIMIT/TOP/ROWNUM)","engines":{"oracle":"FETCH FIRST n ROWS ONLY / ROWNUM","postgres":"LIMIT n","mysql":"LIMIT n","mssql":"TOP n / OFFSET-FETCH","mongodb":"$limit: n / .limit(n)","redis":"LRANGE key 0 n-1","elasticsearch":"size: n"}},{"id":"current-user","concept":"現在のユーザー","engines":{"oracle":"USER / SYS_CONTEXT","postgres":"CURRENT_USER","mysql":"CURRENT_USER() / USER()","mssql":"CURRENT_USER / SUSER_SNAME()","mongodb":"connectionStatus / $$USER (none, application side)","redis":"ACL WHOAMI","elasticsearch":"_security/_authenticate API"}},{"id":"gen-uuid","concept":"UUID の生成","engines":{"oracle":"SYS_GUID()","postgres":"gen_random_uuid()","mysql":"UUID()","mssql":"NEWID()","mongodb":"UUID() / ObjectId()","redis":"none (application side)","elasticsearch":"automatic _id / application side"}},{"id":"json-extract","concept":"JSON フィールドの抽出","engines":{"oracle":"JSON_VALUE(j, '$.a')","postgres":"j->>'a' / j #>> '{a}'","mysql":"JSON_EXTRACT(j, '$.a') / j->>'$.a'","mssql":"JSON_VALUE(j, '$.a')","mongodb":"doc.a (native access)","redis":"JSON.GET key $.a (RedisJSON)","elasticsearch":"doc['a'] / field access (native)"}},{"id":"regexp","concept":"正規表現による一致 (REGEXP)","engines":{"oracle":"REGEXP_LIKE(s, p)","postgres":"s ~ p / REGEXP_MATCHES","mysql":"s REGEXP p / REGEXP_LIKE","mssql":"REGEXP_LIKE (2025+) / before: LIKE / CLR","mongodb":"$regex / $regexMatch","redis":"none (SCAN MATCH glob pattern)","elasticsearch":"regexp query"},"note":"SQL Server 2025 (および Azure SQL) で、REGEXP_LIKE、REGEXP_REPLACE、REGEXP_SUBSTR などのネイティブな正規表現関数が追加された (REGEXP_LIKE には互換性レベル 170 が必要)。それ以前のバージョンでは LIKE または CLR 関数が必要。"}]}]},"reference/params-oracle.json":{"engineId":"oracle","engine":"Oracle","order":1,"params":[{"name":"sga_target","default":"0","recommended":"専用サーバーでは RAM の ~60%","unit":"bytes (K/M/G)","dynamic":"dynamic","desc":"自動共有メモリ管理 (ASMM) の SGA 合計サイズを設定する。サブプールを自動的に配分する。","tags":["memory","memory","sga"]},{"name":"sga_max_size","default":"Same as sga_target","recommended":"sga_target と同じか、わずかに上回る値","unit":"bytes (K/M/G)","dynamic":"restart","desc":"実行時に SGA が拡張できる上限を設定する。値を増やすにはインスタンスの再起動が必要。","tags":["memory","memory","sga"]},{"name":"pga_aggregate_target","default":"10M or 20% of the SGA","recommended":"RAM の ~20%","unit":"bytes (K/M/G)","dynamic":"dynamic","desc":"すべてのサーバープロセスが使用する PGA メモリの合計目標値を設定する。ソートおよびハッシュ操作に影響する。","tags":["memory","memory","pga","sort"]},{"name":"pga_aggregate_limit","default":"Greatest of: 2G, 200% of pga_aggregate_target, 3M x processes (not exceeding 120% of physical RAM minus SGA)","recommended":"通常はデフォルト値で十分","unit":"bytes (K/M/G)","dynamic":"dynamic","desc":"インスタンス全体の PGA メモリのハード上限。超過すると、最も多く消費しているセッションのコールが中止される (SYS とバックグラウンドプロセスは除く)。Oracle 12c で導入。","tags":["memory","memory","pga","limit"]},{"name":"memory_target","default":"0","recommended":"0 (SGA/PGA の個別管理が推奨される)","unit":"bytes (K/M/G)","dynamic":"dynamic","desc":"自動メモリ管理 (AMM) により SGA と PGA を単一の目標値にまとめる。大規模システムでは推奨されない。","tags":["memory","memory","amm"]},{"name":"db_cache_size","default":"0 (automatic)","recommended":"sga_target を使用する場合は 0 のままにする","unit":"bytes (K/M/G)","dynamic":"dynamic","desc":"デフォルトのブロックサイズ用のバッファキャッシュのサイズを設定し、データブロックをメモリに保持する。","tags":["memory","memory","cache","buffer"]},{"name":"shared_pool_size","default":"0 (automatic)","recommended":"sga_target を使用する場合は 0 のままにする","unit":"bytes (K/M/G)","dynamic":"dynamic","desc":"共有プールのサイズ。SQL/PLSQL の解析結果、ディクショナリキャッシュ、ライブラリキャッシュを保持する。","tags":["memory","memory","shared","pool"]},{"name":"processes","default":"100 / 300 (depending on version)","recommended":"想定される同時接続数に応じて増やす","unit":"integer","dynamic":"restart","desc":"インスタンスに接続できる OS プロセスの最大数。変更には再起動が必要。","tags":["connection","connection","process","process"]},{"name":"sessions","default":"Derived from processes (1.5x+22)","recommended":"通常はデフォルトの導出値で十分","unit":"integer","dynamic":"restart","desc":"同時に存在できるセッションの最大数。processes の値から自動的に導出される。","tags":["connection","connection","session","session"]},{"name":"open_cursors","default":"50","recommended":"アプリケーションの要件に応じて 300-1000","unit":"integer","dynamic":"dynamic","desc":"1 セッションが同時にオープンしておけるカーソルの最大数を設定する。","tags":["cursor","cursor","session","session"]},{"name":"cursor_sharing","default":"EXACT","recommended":"EXACT (バインド変数を使用)","unit":"EXACT | FORCE","dynamic":"dynamic","desc":"リテラルを含む SQL 文をバインド変数経由で共有するかを決定する。FORCE はリテラルを置き換える。","tags":["cursor","cursor","sql","parse"]},{"name":"optimizer_mode","default":"ALL_ROWS","recommended":"ALL_ROWS","unit":"ALL_ROWS | FIRST_ROWS_n","dynamic":"dynamic","desc":"コストベースオプティマイザの目標を設定する。全体のスループットと最初の行の応答時間のどちらを優先するかを決める。","tags":["optimizer","optimize","plan","sql"]},{"name":"undo_retention","default":"900","recommended":"最長のクエリ/フラッシュバック時間に基づく","unit":"seconds","dynamic":"dynamic","desc":"コミット済み undo データを可能な限り保持する期間を設定する。ORA-01555 のリスクに影響する。","tags":["undo","rollback","retention","flashback"]},{"name":"undo_tablespace","default":"UNDOTBS1","recommended":"十分なサイズの専用 undo 表領域","unit":"string (tablespace name)","dynamic":"dynamic","desc":"自動 undo 管理で使用するアクティブな undo 表領域を設定する。オンラインで変更可能。","tags":["undo","rollback","tablespace"]},{"name":"db_recovery_file_dest_size","default":"0","recommended":"アーカイブログ + バックアップ + フラッシュバックログを保持できる十分なサイズ","unit":"bytes (K/M/G)","dynamic":"dynamic","desc":"高速リカバリ領域 (FRA) の最大ディスクサイズを設定する。アーカイブログとバックアップを保持する。","tags":["recovery","recovery","fra","archive"]},{"name":"db_writer_processes","default":"1 or based on CPU count","recommended":"CPU/8 程度 (書き込み負荷が高い場合は増やす)","unit":"integer","dynamic":"restart","desc":"ダーティブロックをディスクに書き込むデータベースライター (DBWn) プロセスの数を設定し、書き込み負荷を並列化する。","tags":["io","write","dbwr","writer"]},{"name":"parallel_max_servers","default":"parallel_threads_per_cpu x cpu_count x concurrent_parallel_users (1/2/4) x 5; capped at processes - 15","recommended":"ワークロードと CPU 数に基づいて設定する","unit":"integer","dynamic":"dynamic","desc":"インスタンス内で同時に実行できるパラレル実行サーバー (PX) の最大数を制限する。","tags":["parallel","parallel","px","query"]},{"name":"statistics_level","default":"TYPICAL","recommended":"TYPICAL","unit":"BASIC | TYPICAL | ALL","dynamic":"dynamic","desc":"AWR/ADDM と自動統計収集のレベルを設定する。BASIC では多くの診断機能が無効になる。","tags":["statistics","statistics","awr","monitoring"]},{"name":"deferred_segment_creation","default":"TRUE","recommended":"TRUE (空の表の領域を節約)","unit":"TRUE | FALSE","dynamic":"dynamic","desc":"空の表/インデックスの最初のセグメント作成を最初の行が挿入されるまで遅延させ、領域を節約する。","tags":["segment","deferred-segment","space","storage"]},{"name":"audit_trail","default":"NONE (DB in databases created with DBCA)","recommended":"DB または統合監査を使用する","unit":"NONE | DB | DB,EXTENDED | OS | XML","dynamic":"restart","desc":"従来型の監査レコードの書き込み先と方法を決定する。変更には再起動が必要。","tags":["audit","audit","security","security"]},{"name":"compatible","default":"Installed version (e.g., 19.0.0)","recommended":"新バージョンの機能が安定してから引き上げる","unit":"version string","dynamic":"restart","desc":"有効にするバージョン機能を決定する。一度引き上げると下げられず、変更には再起動が必要。","tags":["compatible","compatibility","version","version"]},{"name":"db_block_size","default":"8192","recommended":"8K (OLTP)。作成時にのみ設定","unit":"bytes","dynamic":"restart","desc":"データベースの標準ブロックサイズを設定する。データベース作成時にのみ設定でき、後から変更できない。","tags":["block","block","storage","io"]},{"name":"filesystemio_options","default":"none (platform-dependent)","recommended":"SETALL (ダイレクト + 非同期 I/O)","unit":"none | asynch | directio | setall","dynamic":"restart","desc":"ファイルシステム上のデータファイルに対する非同期 I/O とダイレクト I/O の使用を制御する。","tags":["io","io","async","directio"]},{"name":"log_archive_max_processes","default":"4","recommended":"アーカイブ先の数に応じて増やす","unit":"integer","dynamic":"dynamic","desc":"redo ログをアーカイブする ARCn プロセスの最大数を設定する。アーカイブの遅延を減らすために増やす。","tags":["archive","archive","redo","log"]}]},"reference/params-postgres.json":{"engineId":"postgres","engine":"PostgreSQL","order":2,"params":[{"name":"shared_buffers","default":"128MB","recommended":"RAM の約 25%","unit":"bytes (kB/MB/GB)","dynamic":"restart","desc":"PostgreSQL がデータブロックのキャッシュ用に割り当てる共有メモリ量。変更には再起動が必要。","tags":["memory","memory","cache","buffer"]},{"name":"effective_cache_size","default":"4GB","recommended":"RAM の約 50-75%","unit":"bytes (kB/MB/GB)","dynamic":"dynamic","desc":"OS + PostgreSQL キャッシュの推定合計サイズをプランナに伝える。インデックスの使用に影響する。","tags":["memory","memory","planner","cache"]},{"name":"work_mem","default":"4MB","recommended":"16-64MB (接続数に注意)","unit":"bytes (kB/MB/GB)","dynamic":"dynamic","desc":"ソートおよびハッシュ操作がディスクに書き出す前に使用できるメモリ。実行計画のノードごとに割り当てられる。","tags":["memory","memory","sort","query"]},{"name":"maintenance_work_mem","default":"64MB","recommended":"256MB-1GB","unit":"bytes (kB/MB/GB)","dynamic":"dynamic","desc":"VACUUM、CREATE INDEX、ALTER TABLE などのメンテナンス操作が使用できる最大メモリを設定する。","tags":["memory","memory","vacuum","maintenance"]},{"name":"max_connections","default":"100","recommended":"100-200 (それ以上はプーラーを使用)","unit":"integer","dynamic":"restart","desc":"受け付けるクライアント同時接続の最大数。変更には再起動が必要。","tags":["connection","connection","limit"]},{"name":"wal_buffers","default":"-1 (1/32 of shared_buffers)","recommended":"16MB","unit":"bytes (kB/MB/GB)","dynamic":"restart","desc":"WAL レコードをディスクに書き込む前に保持する共有メモリバッファのサイズを設定する。-1 (自動) の値は最小 64kB、最大 1 WAL セグメント (通常 16MB) に制限される。","tags":["wal","memory","memory","buffer"]},{"name":"max_wal_size","default":"1GB","recommended":"ワークロードに応じて 4-16GB","unit":"bytes (MB/GB)","dynamic":"dynamic","desc":"自動チェックポイントが発生するまでに WAL が増加できるソフト上限を設定する。","tags":["wal","checkpoint","disk"]},{"name":"min_wal_size","default":"80MB","recommended":"1-2GB","unit":"bytes (MB/GB)","dynamic":"dynamic","desc":"WAL ファイルを再利用のために保持する下限。頻繁な再割り当てを抑える。","tags":["wal","checkpoint","disk"]},{"name":"checkpoint_completion_target","default":"0.9","recommended":"0.9","unit":"ratio (0-1)","dynamic":"dynamic","desc":"チェックポイントの書き込みをチェックポイント間隔のどの割合にわたって分散させるかを設定し、I/O のピークを平準化する。デフォルトは PG14 で 0.9 になった。それ以前は 0.5。","tags":["checkpoint","io","wal"]},{"name":"checkpoint_timeout","default":"5min","recommended":"15-30min","unit":"time (s/min)","dynamic":"dynamic","desc":"自動チェックポイント間の最大時間を設定する。増やすと書き込み負荷は減るが、リカバリ時間が長くなる。","tags":["checkpoint","wal","recovery"]},{"name":"random_page_cost","default":"4.0","recommended":"SSD では 1.1","unit":"decimal","dynamic":"dynamic","desc":"ランダムなディスクアクセスに対するプランナの相対コストを設定する。SSD で下げるとインデックススキャンが選ばれやすくなる。","tags":["planner","optimize","io","index"]},{"name":"effective_io_concurrency","default":"1","recommended":"SSD では 200","unit":"integer","dynamic":"dynamic","desc":"ディスクが同時に処理できる I/O 操作数の推定値。ビットマップスキャンのプリフェッチに影響する。デフォルトは PG17 以前で 1、PG18 で 16。","tags":["io","gc","ssd","prefetch"]},{"name":"default_statistics_target","default":"100","recommended":"100 (大きな表では列単位で引き上げる)","unit":"integer","dynamic":"dynamic","desc":"ANALYZE が収集する統計の詳細度を設定する。引き上げるとプランの精度は向上し、analyze 時間は増加する。","tags":["statistics","statistics","analyze","planner"]},{"name":"autovacuum","default":"on","recommended":"on","unit":"on | off","dynamic":"dynamic","desc":"デッドタプルを除去し統計を収集する自動 vacuum プロセスを有効にする。無効にすると肥大化 (bloat) を招く。","tags":["autovacuum","vacuum","maintenance","bloat"]},{"name":"autovacuum_vacuum_scale_factor","default":"0.2","recommended":"大きな表では 0.05-0.1","unit":"ratio (0-1)","dynamic":"dynamic","desc":"vacuum が実行されるまでに変更されるべき表の行の割合を設定する。下げると大きな表がより頻繁にクリーンアップされる。","tags":["autovacuum","vacuum","bloat","maintenance"]},{"name":"autovacuum_max_workers","default":"3","recommended":"3-6 (表が多いシステムでは引き上げる)","unit":"integer","dynamic":"restart","desc":"同時に実行できる autovacuum ワーカープロセスの最大数を設定する。PG17 以前では変更に再起動が必要。PG18 では autovacuum_worker_slots の上限まで reload で変更できる。","tags":["autovacuum","vacuum","worker","maintenance"]},{"name":"synchronous_commit","default":"on","recommended":"on (重要データ)、off (性能優先)","unit":"on | off | local | remote_write | remote_apply","dynamic":"dynamic","desc":"コミットが WAL のディスク書き込みを待つかを決定する。off ではクラッシュ時に少量のデータ損失のリスクがある。","tags":["wal","commit","durability","performance"]},{"name":"wal_level","default":"replica","recommended":"replica (レプリケーション/PITR 用)","unit":"minimal | replica | logical","dynamic":"restart","desc":"WAL に書き込む情報量を決定する。レプリケーションと論理レプリケーションに必要で、変更には再起動が必要。","tags":["wal","replication","replication","pitr"]},{"name":"max_wal_senders","default":"10","recommended":"スタンバイ数 + バックアップ数に基づく","unit":"integer","dynamic":"restart","desc":"WAL を同時にストリーミングできるプロセスの最大数を設定する (スタンバイおよびバックアップ用)。","tags":["wal","replication","replication","standby"]},{"name":"wal_keep_size","default":"0","recommended":"スタンバイの遅延をカバーできる量","unit":"bytes (MB/GB)","dynamic":"dynamic","desc":"スタンバイのために pg_wal に保持する WAL の最小量。レプリケーションスロットがない場合に遅延しているスタンバイを保護する。PG13 で導入され、それ以前は wal_keep_segments (セグメント数) を使用していた。","tags":["wal","replication","replication","standby"]},{"name":"log_min_duration_statement","default":"-1 (disabled)","recommended":"低速クエリの検出には 1000ms","unit":"milliseconds","dynamic":"dynamic","desc":"指定時間より長く実行された文をログに記録する。低速クエリの検出に使用し、-1 で無効になる。","tags":["logging","log","slow-query","slow-query"]},{"name":"idle_in_transaction_session_timeout","default":"0 (disabled)","recommended":"ロックの保持を防ぐには 60000ms","unit":"milliseconds","dynamic":"dynamic","desc":"オープンしたトランザクション内で指定時間アイドル状態のセッションを終了させる。ロックと肥大化のリスクを減らす。","tags":["timeout","transaction","transaction","lock"]},{"name":"statement_timeout","default":"0 (disabled)","recommended":"アプリケーション依存 (OLTP では低く)","unit":"milliseconds","dynamic":"dynamic","desc":"指定時間を超えた文を自動的にキャンセルする。暴走クエリによるリソース消費を防ぐ。","tags":["timeout","query","query","limit"]},{"name":"shared_preload_libraries","default":"'' (empty)","recommended":"pg_stat_statements (監視用)","unit":"string (comma-separated list)","dynamic":"restart","desc":"サーバー起動時にロードされる共有ライブラリを指定する。pg_stat_statements などの拡張はここで設定する。","tags":["extension","extension","preload","monitoring"]},{"name":"max_parallel_workers_per_gather","default":"2","recommended":"2-4 (CPU 数に応じて)","unit":"integer","dynamic":"dynamic","desc":"1 つの Gather/GatherMerge ノードが起動できるパラレルワーカーの最大数を設定する。0 で並列処理が無効になる。","tags":["parallel","parallel","worker","query"]}]},"reference/params-mysql.json":{"engineId":"mysql","engine":"MySQL","order":3,"params":[{"name":"innodb_buffer_pool_size","default":"128MB","recommended":"専用サーバーでは RAM の約 70-80%","unit":"bytes (M/G)","dynamic":"dynamic","desc":"InnoDB がデータとインデックスをキャッシュするメインのメモリプール。8.0 ではオンラインで変更できるが、大きな変更には注意が必要。","tags":["memory","memory sizing","innodb","buffer"]},{"name":"innodb_buffer_pool_instances","default":"1 (or 8 if size>1GB)","recommended":"大きなプールでは 8","unit":"integer","dynamic":"restart","desc":"バッファプールを分割するインスタンス数を設定する。同時実行時の mutex 競合を減らす。変更には再起動が必要。","tags":["memory","memory sizing","innodb","concurrency"]},{"name":"innodb_redo_log_capacity","default":"100MB (8.0.30+)","recommended":"1-8GB (書き込み負荷に応じて。ピーク時の redo 約 1 時間分)","unit":"bytes (M/G)","dynamic":"dynamic","desc":"InnoDB redo ログが占めるディスク領域の合計を設定する。増やすとチェックポイントの負荷とピーク時の書き込み負荷が平準化される。MySQL 8.0.30 で導入され、SET GLOBAL/SET PERSIST により再起動なしで変更できる。従来の innodb_log_file_size (デフォルト 48MB) と innodb_log_files_in_group は 8.0.30 以降非推奨。8.0.30 より前は redo サイズをこの 2 つで設定し、再起動が必要。","tags":["innodb","redo","log","io"]},{"name":"innodb_flush_log_at_trx_commit","default":"1","recommended":"1 (完全な ACID)、2 (性能)","unit":"0 | 1 | 2","dynamic":"dynamic","desc":"コミットごとに redo ログを書き込みディスクに同期するかを制御する。1 で完全な耐久性が得られ、2/0 には損失のリスクがある。","tags":["innodb","commit","durability","acid"]},{"name":"innodb_flush_method","default":"8.0: fsync (Linux) / 8.4: O_DIRECT (if supported); Windows: unbuffered","recommended":"O_DIRECT (Linux)","unit":"fsync | O_DIRECT | O_DIRECT_NO_FSYNC","dynamic":"restart","desc":"InnoDB がデータファイルとログファイルをディスクにフラッシュする方法を定義する。O_DIRECT は二重バッファリングを回避する。変更には再起動が必要。","tags":["innodb","io","flush","gc"]},{"name":"innodb_io_capacity","default":"8.0: 200 / 8.4: 10000","recommended":"ストレージの実際の IOPS に基づく (8.0 の SSD では 1000-2000)","unit":"integer (IOPS)","dynamic":"dynamic","desc":"InnoDB のバックグラウンドタスク (フラッシュ、マージ) が使用する推定ディスク IOPS 容量を設定する。MySQL 8.4 ではデフォルトが innodb_io_capacity=10000、innodb_io_capacity_max=20000 に引き上げられた (8.0 では 200/2000)。","tags":["innodb","io","iops","ssd"]},{"name":"innodb_read_io_threads","default":"8.0: 4 / 8.4: half the number of logical CPUs (minimum 4)","recommended":"4-8 (読み取り負荷に応じて)","unit":"integer","dynamic":"restart","desc":"読み取り I/O 要求を処理する InnoDB バックグラウンドスレッドの数を設定する。変更には再起動が必要。","tags":["innodb","io","thread","read"]},{"name":"innodb_write_io_threads","default":"4","recommended":"4-8 (書き込み負荷に応じて)","unit":"integer","dynamic":"restart","desc":"書き込み I/O 要求を処理する InnoDB バックグラウンドスレッドの数を設定する。変更には再起動が必要。","tags":["innodb","io","thread","write"]},{"name":"max_connections","default":"151","recommended":"ワークロードに応じて 200-500","unit":"integer","dynamic":"dynamic","desc":"許可するクライアント同時接続の最大数を設定する。オンラインで変更可能。","tags":["connection","connections","limit"]},{"name":"thread_cache_size","default":"-1 (autosized)","recommended":"自動。短命な接続が多い場合は増やす","unit":"integer","dynamic":"dynamic","desc":"再利用のためにキャッシュに保持するスレッド数を設定する。新規接続時のスレッド作成を減らす。","tags":["connection","connections","thread","cache"]},{"name":"table_open_cache","default":"4000","recommended":"オープンする表の数に応じて 4000-8000","unit":"integer","dynamic":"dynamic","desc":"全スレッドにわたるオープン表ハンドルのキャッシュサイズを設定する。表を再オープンするオーバーヘッドを減らす。","tags":["cache","table","table cache","open"]},{"name":"tmp_table_size","default":"16MB","recommended":"64-256MB","unit":"bytes (M/G)","dynamic":"dynamic","desc":"インメモリ一時テーブルがディスク上のテーブルに変換されるまでの最大サイズを設定する。max_heap_table_size と連動する。","tags":["memory","memory sizing","temp","temporary table"]},{"name":"max_heap_table_size","default":"16MB","recommended":"tmp_table_size と同じ","unit":"bytes (M/G)","dynamic":"dynamic","desc":"MEMORY エンジンのテーブルとインメモリ一時テーブルが拡大できる最大サイズを設定する。","tags":["memory","memory sizing","temp","heap"]},{"name":"sort_buffer_size","default":"256KB","recommended":"256KB-2MB (接続ごとのコストに注意)","unit":"bytes (K/M)","dynamic":"dynamic","desc":"ORDER BY と GROUP BY のソート用にセッションごとに割り当てられるバッファ。大きくしすぎるとメモリを消費する。","tags":["memory","memory sizing","sort","buffer"]},{"name":"join_buffer_size","default":"256KB","recommended":"256KB-1MB (インデックスでの解決を優先)","unit":"bytes (K/M)","dynamic":"dynamic","desc":"インデックスを使用できない結合用にセッションごとに割り当てられるバッファ。恒久的な対策は適切なインデックスの追加。","tags":["memory","memory sizing","join","buffer"]},{"name":"sync_binlog","default":"1","recommended":"1 (完全な安全性)。高負荷時は 100-1000","unit":"integer","dynamic":"dynamic","desc":"何回のコミットごとにバイナリログをディスクに同期するかを設定する。1 が最も安全で、大きい値は耐久性と引き換えに性能を得る。","tags":["binlog","replication","durability","commit"]},{"name":"binlog_expire_logs_seconds","default":"2592000 (30 days)","recommended":"バックアップ/レプリケーションの期間に合わせる","unit":"seconds","dynamic":"dynamic","desc":"自動パージされるまでバイナリログファイルを保持する期間を設定する。ディスク使用量を制御する。","tags":["binlog","log","retention","replication"]},{"name":"long_query_time","default":"10","recommended":"1 (低速クエリの検出)","unit":"seconds","dynamic":"dynamic","desc":"スロークエリログに記録されるためにクエリが超えるべき時間を設定する。小数値も指定できる。","tags":["slow-query","slow-query-log","log","performance"]},{"name":"slow_query_log","default":"OFF","recommended":"ON (診断用)","unit":"ON | OFF","dynamic":"dynamic","desc":"long_query_time を超えたクエリをスロークエリログに書き込むかを制御する。性能分析時に有効にする。","tags":["slow-query","slow-query-log","log","monitoring"]},{"name":"wait_timeout","default":"28800 (8 hours)","recommended":"アプリケーションのプールに合わせる (例: 600)","unit":"seconds","dynamic":"dynamic","desc":"非対話型接続がクローズされるまでアイドル状態でいられる最大時間を設定する。アイドル接続を整理する。","tags":["timeout","connection","connections","idle"]},{"name":"max_allowed_packet","default":"64MB","recommended":"大きな BLOB/行には 64-256MB","unit":"bytes (M/G)","dynamic":"dynamic","desc":"単一パケットまたは生成/中間行の最大サイズを設定する。大きな BLOB を転送する場合は増やす。","tags":["packet","packet size","blob","network"]},{"name":"innodb_lock_wait_timeout","default":"50","recommended":"OLTP では 10-50","unit":"seconds","dynamic":"dynamic","desc":"InnoDB トランザクションが行ロックを待機してタイムアウトするまでの時間を設定する。","tags":["innodb","lock","lock wait","timeout"]},{"name":"character_set_server","default":"utf8mb4","recommended":"utf8mb4","unit":"text (character set)","dynamic":"dynamic","desc":"サーバーのデフォルト文字セットを設定する。utf8mb4 は完全な Unicode (絵文字を含む) をサポートする。","tags":["charset","character-set","unicode","utf8mb4"]}]},"reference/params-mssql.json":{"engineId":"mssql","engine":"SQL Server","order":4,"params":[{"name":"max server memory (MB)","default":"2147483647","recommended":"総 RAM から OS および他のサービス用の分 (約 10-25%) を差し引いた値","unit":"MB","dynamic":"dynamic","desc":"SQL Server のバッファプールおよびその他のメモリコンシューマが使用できる最大メモリ量を設定する。デフォルトは事実上無制限。サーバー上で他のサービスが動作する場合は、OS に十分なメモリを残すために下げる必要がある。sp_configure で設定し、RECONFIGURE で即時反映される。","tags":["memory","memory limit","buffer pool"]},{"name":"min server memory (MB)","default":"0","recommended":"重要なインスタンスでは max に対して妥当な下限","unit":"MB","dynamic":"dynamic","desc":"SQL Server が一度割り当てた後は OS に解放しない最小メモリ量。メモリ不足時に SQL Server がメモリを過度に解放するのを防ぐために使用する。sp_configure で設定し、RECONFIGURE で反映される。","tags":["memory","memory limit"]},{"name":"max degree of parallelism","default":"0","recommended":"通常は 8 または NUMA ノードあたりの物理コア数","unit":"count","dynamic":"dynamic","desc":"1 つのクエリがパラレル実行で使用できるプロセッサ (コア) の最大数を制限する。0 はすべてのコアを使用可能であることを意味する。OLTP ワークロードでは過度な並列処理を避けるために制限する。sp_configure + RECONFIGURE で即時反映される。","tags":["parallelism","parallel query","maxdop","cpu"]},{"name":"cost threshold for parallelism","default":"5","recommended":"最新のハードウェアでは 25-50","unit":"cost","dynamic":"dynamic","desc":"実行計画がパラレル実行されるために達するべき推定コストの最小しきい値。デフォルトの 5 は非常に低く、小さなクエリが不必要に並列化される。引き上げるとサーバー全体の並列処理の挙動が改善する。sp_configure + RECONFIGURE で即時反映される。","tags":["parallelism","parallel query","cpu"]},{"name":"max worker threads","default":"0","recommended":"0 (SQL Server に計算させる)","unit":"count","dynamic":"dynamic","desc":"クライアント要求を処理するために SQL Server が作成できるワーカースレッドの最大数を設定する。0 ではプロセッサ数とアーキテクチャに基づいて自動計算される。詳細オプションであり、sp_configure + RECONFIGURE で再起動なしに適用される (sys.configurations.is_dynamic = 1)。","tags":["threads","worker","cpu","concurrency"]},{"name":"optimize for ad hoc workloads","default":"0","recommended":"1 (on)","unit":"0/1","dynamic":"dynamic","desc":"1 回だけ実行されるアドホッククエリについて、初回実行時に完全なプランではなく小さなコンパイル済みプランスタブをキャッシュする。プランキャッシュが単一使用のプランで埋まるのを防ぎ、メモリ使用を改善する。sp_configure + RECONFIGURE で即時反映される。","tags":["plan cache","memory","memory usage"]},{"name":"backup compression default","default":"0","recommended":"1 (on)","unit":"0/1","dynamic":"dynamic","desc":"新しいバックアップをデフォルトで圧縮する。圧縮により多少の CPU と引き換えにバックアップサイズとバックアップ時間が大幅に減る。sp_configure + RECONFIGURE で即時反映される。","tags":["backup","backup size","compression","backup compression"]},{"name":"fill factor (%)","default":"0","recommended":"0 または 90-100 (ワークロードに応じて)","unit":"%","dynamic":"restart","desc":"インデックスの作成または再構築 (REBUILD) 時にリーフレベルのページをどの程度埋めるかをパーセントで設定する。0 と 100 はページを完全に埋める。低い値はページ分割を減らすが、ディスクとメモリの使用量が増える。サーバーレベルのデフォルトは sp_configure で変更するが、サービスを再起動するまで反映されない (is_dynamic = 0)。インデックスごとの FILLFACTOR オプションは即時に使用できる。","tags":["index","page split","storage","disk usage"]},{"name":"recovery interval (min)","default":"0","recommended":"0 (自動)","unit":"minutes","dynamic":"dynamic","desc":"自動チェックポイントの頻度を、目標とする最大復旧時間で設定する。0 では SQL Server がデータベースごとに目標復旧時間を自動管理する。sp_configure + RECONFIGURE で即時反映される。","tags":["checkpoint","recovery","crash recovery"]},{"name":"remote query timeout (s)","default":"600","recommended":"ワークロードに応じて 600 または 0 (無制限)","unit":"seconds","dynamic":"dynamic","desc":"リモートクエリ (リンクサーバー経由) の応答をサーバーがタイムアウトまで待機する時間。0 は無期限に待機することを意味する。sp_configure + RECONFIGURE で即時反映される。","tags":["timeout","remote","linked server"]},{"name":"network packet size (B)","default":"4096","recommended":"4096 (特別な場合を除き変更しない)","unit":"bytes","dynamic":"dynamic","desc":"ネットワーク上のデータ転送に使用するパケットサイズ。非常に大きなデータを転送する特殊な一括操作を除き、デフォルトが推奨される。誤った設定は性能を低下させる可能性がある。sp_configure + RECONFIGURE で反映される。","tags":["network","network packet","packet"]},{"name":"データベース互換性レベル (ALTER DATABASE)","default":"Depends on server version","recommended":"テスト済みの最新レベル","unit":"level","dynamic":"dynamic","desc":"データベースがどの SQL Server バージョンの動作とクエリオプティマイザモデルで動作するかを決定する。ALTER DATABASE ... SET COMPATIBILITY_LEVEL でデータベースごとに設定し、即時反映される。カーディナリティ推定などのオプティマイザ機能に影響する。","tags":["database","compatibility level","optimizer","compatibility"]},{"name":"MAXDOP (データベーススコープ構成)","default":"0 (inherits the server setting)","recommended":"データベースのワークロードに適した値","unit":"count","dynamic":"dynamic","desc":"サーバー全体の max degree of parallelism 設定をデータベースレベルで上書きする。ALTER DATABASE SCOPED CONFIGURATION SET MAXDOP で設定し、即時反映される。データベースごとに異なる並列処理の挙動を可能にする。","tags":["parallelism","parallel query","maxdop","database scoped"]},{"name":"tempdb ファイル数 (推奨)","default":"SQL Server 2016+ setup: equal to the number of logical cores, at most 8 (1 before)","recommended":"論理コア数と同数、最大 8 (必要に応じて 4 ずつ増やす)","unit":"count","dynamic":"dynamic","desc":"tempdb のデータファイル数は割り当てページの競合を減らすうえで重要。一般的な推奨はコア数 (最大 8) まで同じサイズのファイルを使用すること。ALTER DATABASE tempdb ADD FILE で追加したファイルは再起動なしで即時に使用される。ただし既存ファイルがいっぱいの場合は、比例フィルのバランスのためにすべてのファイルを同じサイズにそろえる。tempdb ファイルの削除 (REMOVE FILE) は、ファイルが空にならないため再起動後にしかできないことが多い。","tags":["tempdb","storage","data files","contention"]},{"name":"トレースフラグ 1117 / 1118 (注記)","default":"Default behavior for tempdb in SQL 2016+","recommended":"SQL 2016+ では通常不要。旧バージョンでは on","unit":"flag","dynamic":"restart","desc":"TF 1117 はファイルグループ内のすべてのファイルを同時に拡張させる。TF 1118 は混合エクステントではなく単一エクステントの割り当てを強制する。SQL Server 2016 以降、これらの動作は tempdb のデフォルトであるため、フラグは通常不要。起動フラグとして追加した場合は再起動が必要。","tags":["trace flag","tempdb","note"]},{"name":"トレースフラグ 3226","default":"Off","recommended":"On (成功したバックアップのメッセージを抑制)","unit":"flag","dynamic":"dynamic","desc":"成功したバックアップ操作が SQL Server エラーログと Windows イベントログに書き込まれるのを防ぐ。ログバックアップが頻繁なシステムで、ログが不要なメッセージで埋まる (ログスパム) のを防ぐ。DBCC TRACEON(3226, -1) で実行時に即時有効にできる。再起動後も維持するには、起動パラメータとして -T3226 も追加する。","tags":["trace flag","backup","backup messages","log"]},{"name":"lock pages in memory (Windows ポリシーの注記)","default":"Off","recommended":"特定のシナリオでサービスアカウントに付与する","unit":"policy","dynamic":"restart","desc":"SQL Server サービスアカウントが自身のメモリページを OS によってディスクにページアウトされないようにする Windows ユーザー権利ポリシー。メモリ不足時の性能の変動を抑えられるが、慎重に構成する必要がある。ポリシーの変更にはサービスの再起動が必要。","tags":["memory","memory paging","windows","policy","note"]}]},"reference/params-mongodb.json":{"engineId":"mongodb","engine":"MongoDB","order":5,"params":[{"name":"storage.wiredTiger.engineConfig.cacheSizeGB","default":"(RAM - 1GB) * 0.5","recommended":"デフォルトのまま、または利用可能な RAM の約 50%","unit":"GB","dynamic":"restart","desc":"WiredTiger ストレージエンジンの内部キャッシュに割り当てるメモリ量をギガバイト単位で設定する。デフォルトでは (総 RAM - 1GB) の半分が使用される。値の手動設定は特別な場合にのみ必要で、mongod の再起動が必要。","tags":["memory","memory","cache","wiredtiger"]},{"name":"net.maxIncomingConnections","default":"1000000 (effectively limited by OS limits)","recommended":"ワークロードと OS の ulimit に応じて","unit":"count","dynamic":"restart","desc":"mongod または mongos インスタンスが受け付ける同時着信接続の最大数を制限する。値が OS のファイルディスクリプタ/接続の上限 (ulimit) より大きい場合は効果がなく、実際の上限は OS が決める (db.serverStatus().connections の current + available で確認できる)。変更は設定ファイルで行い、再起動が必要。","tags":["network","network","connections","connection"]},{"name":"operationProfiling.slowOpThresholdMs","default":"100","recommended":"ワークロードに応じて 100 またはそれ以下","unit":"ms","dynamic":"dynamic","desc":"操作が低速とみなされ、プロファイラとログに記録される時間のしきい値をミリ秒で設定する。しきい値を超えた操作は診断しやすいように記録される。db.setProfilingLevel() で実行時に即時変更できる。","tags":["profiling","slow query","slow query","monitoring"]},{"name":"replication.oplogSizeMB","default":"~5% of disk size (max 50GB)","recommended":"メンテナンス時間帯をカバーできる十分なサイズ","unit":"MB","dynamic":"dynamic","desc":"レプリカセットメンバーで操作を格納する oplog コレクションの最大サイズをメガバイトで設定する。oplog が十分に大きければ、遅延したメンバーはフル再同期なしで追いつける。稼働中のレプリカセットで replSetResizeOplog コマンドにより即時変更できる。","tags":["replication","oplog","replica set"]},{"name":"security.authorization","default":"disabled","recommended":"enabled (ロールベースのアクセス制御)","unit":"enabled/disabled","dynamic":"restart","desc":"ロールベースのアクセス制御 (RBAC) を有効にする。有効時、クライアントは認証と認可を受ける必要がある。本番環境では常に有効にする必要がある。設定ファイルで設定し、再起動が必要。","tags":["security","security","authorization","authorization","rbac"]},{"name":"net.compression.compressors","default":"snappy,zstd,zlib","recommended":"snappy,zstd (デフォルトで問題ない)","unit":"list","dynamic":"restart","desc":"クライアントおよびクラスタ内のネットワークトラフィックで使用できる圧縮アルゴリズムとその優先順位を設定する。多少の CPU コストと引き換えにネットワーク帯域の使用量を減らす。設定ファイルで設定し、再起動が必要。","tags":["network","network","compression","compression"]},{"name":"storage.wiredTiger.collectionConfig.blockCompressor","default":"snappy","recommended":"snappy (速度) または zstd (高圧縮)","unit":"algorithm","dynamic":"restart","desc":"WiredTiger がコレクションデータをディスクに書き込む際のブロック圧縮アルゴリズムを設定する。snappy は速度を優先し、zlib と zstd はより高い圧縮率を提供する。設定後に作成されたコレクションにのみ適用され、再起動が必要。","tags":["storage","storage","compression","compression","wiredtiger"]},{"name":"storage.directoryPerDB","default":"false","recommended":"ディスクを分けたい場合は true","unit":"true/false","dynamic":"restart","desc":"各データベースのデータを別々のサブディレクトリに格納し、データベースごとに異なるディスクボリュームに配置できるようにする。空のデータディレクトリでのみ有効にできる。変更は設定ファイルで行い、再起動が必要。","tags":["storage","storage","directory"]},{"name":"setParameter.cursorTimeoutMillis","default":"600000","recommended":"ワークロードに応じてデフォルト (10 分)","unit":"ms","dynamic":"dynamic","desc":"アイドル状態のカーソルがサーバーによって自動的にクローズされるまでの待機時間をミリ秒で設定する。放置されたカーソルによるリソース消費を防ぐ。db.adminCommand({setParameter:1}) で実行時に即時変更できる。","tags":["cursor","timeout","setparameter"]},{"name":"setParameter.transactionLifetimeLimitSeconds","default":"60","recommended":"長いトランザクションが必要でない限りデフォルト","unit":"seconds","dynamic":"dynamic","desc":"マルチドキュメントトランザクションが自動的に中止されるまでオープンしていられる最大時間を秒で設定する。長時間実行のトランザクションがリソースと WiredTiger キャッシュを占有するのを防ぐ。setParameter で即時変更できる。","tags":["transaction","transaction","setparameter"]},{"name":"setParameter.maxTransactionLockRequestTimeoutMillis","default":"5","recommended":"ロック競合に応じてデフォルト","unit":"ms","dynamic":"dynamic","desc":"トランザクションが必要なロックの取得をタイムアウトまで待機する最大時間をミリ秒で設定する。ロック待機の挙動を調整することで、トランザクションが長時間ブロックされるのを防ぐ。setParameter で即時変更できる。","tags":["transaction","lock","lock","setparameter"]},{"name":"net.tls.mode","default":"disabled","recommended":"requireTLS (本番環境)","unit":"mode","dynamic":"restart","desc":"サーバーにおける TLS/SSL 暗号化接続の使用を決定する。requireTLS はすべての接続に暗号化を強制し、preferTLS と allowTLS は移行期間用の中間モードを提供する。証明書の設定と併せて使用し、再起動が必要。","tags":["security","security","tls","ssl","encryption"]},{"name":"storage.syncPeriodSecs","default":"60","recommended":"60 (デフォルトを変更しない)","unit":"seconds","dynamic":"dynamic","desc":"WiredTiger がチェックポイントを取得する頻度、つまりメモリ上のデータをディスクにフラッシュする間隔を秒で設定する。デフォルトはほとんどのワークロードに適しており、変更は一般に推奨されない。設定ファイルで設定する。実行時に db.adminCommand({ setParameter: 1, syncdelay: <seconds> }) で再起動なしに変更することもできる。","tags":["storage","storage","checkpoint","sync"]},{"name":"replication.enableMajorityReadConcern","default":"true","recommended":"true (5.0+ では変更不可)","unit":"true/false","dynamic":"restart","desc":"majority read concern レベルの使用を可能にする。このレベルは過半数のメンバーに書き込まれ、ロールバックされないデータの読み取りを保証する。MongoDB 5.0 以降この設定は変更できず常に true。旧バージョンでは (例: PSA 構成で) false に設定できた。設定ファイルで設定し、再起動が必要。","tags":["replication","read concern","replica set"]},{"name":"processManagement.fork","default":"false","recommended":"systemd の場合は false、手動デーモンの場合は true","unit":"true/false","dynamic":"restart","desc":"mongod プロセスを fork させ、デーモンとしてバックグラウンドで実行する。systemd などのサービスマネージャを使う場合はプロセス管理をサービスマネージャが行うため、通常は false のままにする。設定ファイルで設定し、起動時の挙動に影響する。","tags":["process","process","daemon","fork"]}]},"reference/params-redis.json":{"engineId":"redis","engine":"Redis","order":6,"params":[{"name":"maxmemory","default":"0 (unlimited)","recommended":"物理 RAM の約 70-75%","unit":"bytes","dynamic":"dynamic","desc":"Redis がデータに使用できる最大メモリ量を設定する。0 は無制限の使用を意味し、メモリ不足を招く可能性があるため、上限の設定が強く推奨される。CONFIG SET maxmemory で即時変更できる。","tags":["memory","memory"]},{"name":"maxmemory-policy","default":"noeviction","recommended":"キャッシュでは allkeys-lru、それ以外は noeviction","unit":"policy","dynamic":"dynamic","desc":"maxmemory の上限に達したときに Redis がどのキーをどのように削除 (eviction) するかを決めるポリシー。noeviction は書き込みエラーを返し、allkeys-lru は最も長く使われていないキーを削除する。CONFIG SET で即時変更できる。","tags":["memory","memory","eviction","cache"]},{"name":"maxclients","default":"10000","recommended":"ワークロードと OS の ulimit に基づく","unit":"count","dynamic":"dynamic","desc":"受け付けるクライアント同時接続の最大数を設定する。OS のファイルディスクリプタの上限によってこの値が制限されることがある。CONFIG SET maxclients で即時変更できる。","tags":["connections","connection","clients"]},{"name":"appendonly","default":"no","recommended":"永続化が必要な場合は yes","unit":"yes/no","dynamic":"dynamic","desc":"AOF (Append Only File) 永続化の仕組みを有効にする。有効時、すべての書き込み操作がログファイルに追記される。RDB スナップショットよりデータ損失のリスクが小さい。CONFIG SET appendonly yes で即時有効にできる。","tags":["persistence","persistence","aof"]},{"name":"appendfsync","default":"everysec","recommended":"everysec (バランス型)","unit":"policy","dynamic":"dynamic","desc":"AOF ファイルをディスクに同期 (fsync) する頻度を設定する。always は書き込みごとに同期し最も安全だが低速。everysec は毎秒 1 回同期し、性能と耐久性のバランスをとる。no は同期を OS に任せる。CONFIG SET で即時変更できる。","tags":["persistence","persistence","aof","fsync"]},{"name":"save","default":"3600 1 300 100 60 10000","recommended":"ワークロード依存、または無効 (AOF のみ)","unit":"rule","dynamic":"dynamic","desc":"RDB スナップショットをディスクに保存する条件 (一定時間内の一定数の変更) を定義する。空の値を設定すると RDB スナップショットが完全に無効になる。CONFIG SET save で即時変更できる。","tags":["persistence","persistence","rdb","snapshot"]},{"name":"tcp-keepalive","default":"300","recommended":"300 (デフォルトで問題ない)","unit":"seconds","dynamic":"dynamic","desc":"Redis がクライアント接続に TCP keepalive ACK を送信する間隔を秒で設定する。切断された接続を検出してクローズし、ハーフオープン接続を整理する。CONFIG SET で即時変更できる。","tags":["network","network","tcp","keepalive"]},{"name":"timeout","default":"0","recommended":"0 (接続をクローズしない) または妥当なアイドル時間","unit":"seconds","dynamic":"dynamic","desc":"クライアント接続がアイドル状態でいられる最大時間を秒で設定する。超過すると接続はクローズされる。0 はクライアントが無期限にアイドル状態でいられることを意味する。CONFIG SET timeout で即時変更できる。","tags":["connections","connection","timeout","idle"]},{"name":"hz","default":"10","recommended":"10 (高負荷のシステムでは最大 100)","unit":"Hz","dynamic":"dynamic","desc":"Redis がバックグラウンドタスク (キーの期限切れ処理、クライアントタイムアウトの確認など) を 1 秒間に何回実行するかを設定する。値を大きくすると制御は精密になるが、CPU 使用率が増える。CONFIG SET hz で即時変更できる。","tags":["performance","cpu","background"]},{"name":"activedefrag","default":"no","recommended":"メモリの断片化が大きい場合は yes","unit":"yes/no","dynamic":"dynamic","desc":"アクティブなメモリデフラグを有効にし、稼働中にデータを再配置してメモリの断片化を減らす。断片化の大きい長時間稼働のインスタンスで有用。CONFIG SET activedefrag yes で即時有効にできる。","tags":["memory","memory","defragmentation"]},{"name":"maxmemory-samples","default":"5","recommended":"5 (より正確な eviction のために引き上げ可能)","unit":"count","dynamic":"dynamic","desc":"LRU および LFU の eviction アルゴリズムがキーを選ぶ際にサンプリングするキーの数を設定する。値を大きくすると本来の LRU/LFU の挙動に近づくが、CPU 消費がわずかに増える。CONFIG SET で即時変更できる。","tags":["memory","memory","eviction","lru"]},{"name":"io-threads","default":"1","recommended":"マルチコアサーバーでは 2-4 (コア数に応じて)","unit":"count","dynamic":"restart","desc":"クライアントソケットへの書き込みと読み取りに使用する I/O スレッドの数を設定する。ネットワークトラフィックの多いマルチコアシステムでスループットを向上できる。この設定は設定ファイルでのみ変更でき、再起動が必要。","tags":["performance","threads","io","cpu"]},{"name":"repl-backlog-size","default":"1mb","recommended":"書き込みレートと停止時間に基づいて大きめに","unit":"bytes","dynamic":"dynamic","desc":"レプリカの接続が切れた際の部分再同期のためにプライマリで保持するレプリケーションバッファのサイズを設定する。十分なサイズがあれば、短時間の停止後にレプリカはフル同期なしで追いつける。CONFIG SET で即時変更できる。","tags":["replication","replication","backlog"]},{"name":"repl-diskless-sync","default":"yes","recommended":"yes (高速ネットワークの場合)","unit":"yes/no","dynamic":"dynamic","desc":"フル同期時に RDB データをディスクに書き込まず、ソケット経由で直接レプリカに送信する。ディスク I/O がボトルネックのシステムで同期を高速化する。CONFIG SET repl-diskless-sync で即時変更できる。","tags":["replication","replication","diskless","sync"]},{"name":"requirepass","default":"(empty)","recommended":"強力なパスワードを設定する","unit":"password","dynamic":"dynamic","desc":"クライアントがコマンドを実行する前に AUTH で認証する際のパスワードを設定する。Redis への不正アクセスを防ぐため、強力なパスワードを設定する必要がある。CONFIG SET requirepass で即時変更できる。","tags":["security","security","authentication","password"]},{"name":"cluster-enabled","default":"no","recommended":"水平スケーリングが必要な場合は yes","unit":"yes/no","dynamic":"restart","desc":"Redis Cluster モードを有効にする。有効時、データはハッシュスロットによって複数のノードに分散される。水平スケーリングと自動データ分割に使用する。この設定は設定ファイルでのみ変更でき、再起動が必要。","tags":["cluster","cluster","scaling","scaling"]},{"name":"cluster-node-timeout","default":"15000","recommended":"15000 またはネットワーク遅延に合わせて調整した値","unit":"ms","dynamic":"dynamic","desc":"クラスタモードで、ノードが応答しないまま到達不能 (fail) とみなされるまでの最大時間をミリ秒で設定する。フェイルオーバーの挙動とクラスタの安定性に直接影響する。CONFIG SET で即時変更できる。","tags":["cluster","cluster","timeout","failover"]},{"name":"aof-use-rdb-preamble","default":"yes","recommended":"yes (高速な再ロード)","unit":"yes/no","dynamic":"dynamic","desc":"AOF の書き換え時にファイル先頭にコンパクトな RDB スナップショットを書き込み、その後に増分の AOF コマンドを続けるハイブリッド永続化形式を有効にする。再起動時の AOF ロード時間が短縮される。CONFIG SET で即時変更できる。","tags":["persistence","persistence","aof","rdb"]}]},"reference/params-elasticsearch.json":{"engineId":"elasticsearch","engine":"Elasticsearch","order":7,"params":[{"name":"-Xms / -Xmx (JVM ヒープ)","default":"Automatic depending on version (half of RAM)","recommended":"物理 RAM の 50%、最大約 30-31GB (Xms=Xmx)","unit":"GB","dynamic":"restart","desc":"JVM ヒープの初期サイズ (-Xms) と最大サイズ (-Xmx) を設定する。両者は同じ値に設定する。総 RAM の半分、および圧縮オブジェクトポインタが適用されなくなる約 32GB の上限を超えないことが推奨される。jvm.options で設定し、ノードの再起動が必要。","tags":["memory","memory","jvm","heap"]},{"name":"indices.memory.index_buffer_size","default":"10%","recommended":"10% (インデックス作成の負荷が高い場合は増やせる)","unit":"% / bytes","dynamic":"restart","desc":"インデックス作成中に新しいドキュメントを保持するメモリバッファに割り当てるヒープの割合を設定する。このバッファを増やすと、書き込み中心のワークロードでインデックス作成のスループットが向上する場合がある。elasticsearch.yml でノードごとに設定し、再起動が必要。","tags":["memory","memory","indexing","buffer"]},{"name":"thread_pool.write.queue_size","default":"10000","recommended":"10000 (キューでの拒否が発生する場合は慎重に増やす)","unit":"count","dynamic":"restart","desc":"index、delete、bulk の書き込み操作用スレッドプールのキュー長を設定する。キューが満杯になると要求は拒否される。値を上げすぎるとメモリ不足を招くことがある。elasticsearch.yml で設定し、再起動が必要。","tags":["thread pool","write","queue","queue"]},{"name":"thread_pool.search.queue_size","default":"1000","recommended":"1000 (検索の拒否が発生する場合は慎重に増やす)","unit":"count","dynamic":"restart","desc":"検索操作用スレッドプールのキュー長を設定する。同時検索がプールの容量を超えると要求はこのキューで待機し、キューが満杯になると拒否される。elasticsearch.yml で設定し、再起動が必要。","tags":["thread pool","search","search","queue"]},{"name":"indices.fielddata.cache.size","default":"unbounded","recommended":"20-40% などの上限 (メモリ保護のため)","unit":"% / bytes","dynamic":"restart","desc":"text フィールドでのソートと集計に使用する fielddata キャッシュの最大サイズを設定する。デフォルトは無制限なので、メモリ枯渇を防ぐために上限の設定が推奨される。elasticsearch.yml で設定し、再起動が必要。","tags":["memory","memory","fielddata","cache"]},{"name":"index.number_of_shards","default":"1","recommended":"データ量に基づく。シャードあたり 10-50GB を目安","unit":"count","dynamic":"restart","desc":"インデックスを分割するプライマリシャードの数を設定する。静的なインデックス設定 (再起動ではなく、インデックス作成時にのみ指定可能) であり、既存のインデックスで直接変更することはできない。新しいインデックス + _reindex で新たなインデックスを作成するか、_split (倍数化) / _shrink (約数への削減) API で変更する。シャードが多すぎるとクラスタのオーバーヘッドが増え、少なすぎるとスケーリングが制限される。","tags":["index","index","shard","scaling"]},{"name":"index.number_of_replicas","default":"1","recommended":"本番環境では最低 1 (高可用性のため)","unit":"count","dynamic":"dynamic","desc":"各プライマリシャードに対して保持するレプリカシャードの数を設定する。レプリカは高可用性と読み取り性能の両方を提供する。この設定は _settings API で稼働中のインデックスに対して即時変更できる。","tags":["index","index","replica","availability"]},{"name":"index.refresh_interval","default":"1s","recommended":"インデックス作成の負荷が高い場合は 30s または -1 (一時的に)","unit":"duration","dynamic":"dynamic","desc":"新たにインデックスされたドキュメントを検索可能にする refresh 操作の実行頻度を設定する。値を大きくするか、一括ロード中に -1 に設定すると、インデックス作成のスループットが大幅に向上する。_settings API で即時変更できる。","tags":["index","index","refresh","indexing"]},{"name":"indices.breaker.total.limit","default":"95%","recommended":"95% (デフォルト。慎重に変更する)","unit":"%","dynamic":"dynamic","desc":"すべてのサーキットブレーカーが合計で使用できるヒープの最大割合を設定し、ノードが OutOfMemory でクラッシュするのを防ぐ。_cluster/settings API でクラスタ全体に即時変更できる。","tags":["memory","memory","circuit breaker","stability"]},{"name":"cluster.routing.allocation.disk.watermark.low","default":"85%","recommended":"85% (デフォルトで問題ない)","unit":"% / bytes","dynamic":"dynamic","desc":"ノードのディスク使用率がこのしきい値を超えると、Elasticsearch はそのノードへの新しいシャードの割り当てを停止する (既存のシャードは残る)。ディスク満杯を防ぐための最初の警告レベル。_cluster/settings API で即時変更できる。","tags":["disk","allocation","watermark","storage"]},{"name":"cluster.routing.allocation.disk.watermark.high","default":"90%","recommended":"90% (デフォルトで問題ない)","unit":"% / bytes","dynamic":"dynamic","desc":"ノードのディスク使用率がこのしきい値を超えると、Elasticsearch はこのノードから他のノードへシャードの再配置を開始する。ディスクが逼迫しているノードの負荷を軽減する。_cluster/settings API で即時変更できる。","tags":["disk","allocation","watermark","storage"]},{"name":"cluster.routing.allocation.disk.watermark.flood_stage","default":"95%","recommended":"95% (デフォルトで問題ない)","unit":"% / bytes","dynamic":"dynamic","desc":"ディスク使用率がこの重大なしきい値を超えると、該当ノード上にシャードを持つインデックスは読み取り専用 (read-only-allow-delete) モードになり、書き込みがブロックされる。ディスクが完全に満杯になる前にデータ破損を防ぐ。7.4+ ではディスク使用率が high watermark を下回るとブロックは自動的に解除される。8.x では大容量ディスクの場合、割合ではなく max_headroom (デフォルトの空き容量 100GB) が決定要因となる。_cluster/settings API で即時変更できる。","tags":["disk","allocation","watermark","read-only"]},{"name":"index.translog.durability","default":"request","recommended":"request (耐久性) または async (性能)","unit":"mode","dynamic":"dynamic","desc":"トランザクションログ (translog) をディスクに同期 (fsync) するタイミングを設定する。request は要求ごとに同期してデータ損失を最小化する。async は定期的に同期して性能を向上させるが、クラッシュ時にデータ損失のリスクがある。_settings API で即時変更できる。","tags":["translog","durability","durability","indexing"]},{"name":"indices.recovery.max_bytes_per_sec","default":"40mb","recommended":"ネットワークとディスクの容量に応じて増やせる","unit":"bytes/s","dynamic":"dynamic","desc":"シャードのリカバリ中のノードあたりの最大データ転送速度を設定する。値を大きくするとリカバリは速くなるが、通常のワークロードのネットワークとディスクのリソースを消費することがある。_cluster/settings API で即時変更できる。","tags":["recovery","recovery","throttle","network"]},{"name":"action.destructive_requires_name","default":"true","recommended":"true (破壊的なワイルドカード操作をブロック)","unit":"true/false","dynamic":"dynamic","desc":"ワイルドカード (*) や _all によるインデックス削除などの破壊的な操作をブロックし、インデックス名の明示的な指定を必須にする。誤ってすべてのインデックスを削除するのを防ぐ重要な安全設定。_cluster/settings API で即時変更できる。","tags":["security","security","destructive","safety"]},{"name":"discovery.seed_hosts","default":"(empty / 127.0.0.1)","recommended":"クラスタ内の master-eligible ノードのアドレス","unit":"list","dynamic":"restart","desc":"ノードがクラスタに参加するために接続するシードホスト (master-eligible ノード) のアドレス一覧を設定する。クラスタのディスカバリとノード同士の検出に必要。elasticsearch.yml で設定し、再起動が必要。","tags":["discovery","cluster","cluster","network"]}]},"reference/waits-oracle.json":{"engineId":"oracle","engine":"Oracle","order":1,"waits":[{"name":"log file sync","kind":"wait","meaning":"セッションが COMMIT (または ROLLBACK) を発行し、LGWR プロセスが redo レコードをオンライン redo ログファイルに書き込んで応答するのを待機している。","causes":"redo ログ I/O の低速、非常に頻繁な小さいコミット、過負荷の LGWR プロセス、CPU 不足による LGWR の遅延、低速ディスク上の redo ログ。","action":"コミット頻度を減らす (バッチコミット)、redo ログファイルを高速/低レイテンシのディスク (SSD) に移動する、不要なコミットを削除する、COMMIT NOWAIT/BATCH は損失を許容できる処理に限って検討する (警告: 耐久性が低下し、コミット済みに見えるトランザクションがクラッシュ時に失われる可能性がある)、ログライターの I/O レイテンシ (log file parallel write) を測定する。","tags":["commit","redo","io","lgwr"]},{"name":"db file sequential read","kind":"wait","meaning":"セッションがシングルブロックの物理読み取りを実行しており、ブロックがディスクからバッファキャッシュに読み込まれるのを待機している。通常はインデックスアクセス時や ROWID による表ブロックの読み取り時に発生する。","causes":"インデックススキャン、非効率なアクセスプラン、小さいバッファキャッシュ、低速なディスクサブシステム、物理読み取りの多さによりキャッシュにないブロック。","action":"SQL をチューニングして不要な読み取りを減らす、適切なインデックスを追加する、バッファキャッシュのサイズを増やす、I/O サブシステムを改善する、AWR/ASH で読み取りの多い上位クエリを特定する。","tags":["io","index","single-block","read"]},{"name":"db file scattered read","kind":"wait","meaning":"セッションがマルチブロックの物理読み取りを実行しており、複数のブロックがディスクから読み込まれるのを待機している。通常は全表スキャンまたは高速全インデックススキャン時に発生する。","causes":"全表スキャン、インデックスの欠落または未使用、非効率な実行計画、大きな表のスキャン、不正確なオプティマイザ統計。","action":"インデックスを追加して不要なフルスキャンを防ぐ、実行計画を見直す、統計を更新する、db_file_multiblock_read_count の設定を確認する、本当に必要なフルスキャンは並列化を検討する。","tags":["io","full-scan","multi-block","read"]},{"name":"direct path read","kind":"wait","meaning":"セッションがバッファキャッシュを経由せずにブロックを PGA に直接読み込んでいる。通常はパラレルクエリ、大きな表のスキャン、LOB の読み取り時に発生する。","causes":"パラレル全表スキャン、シリアルダイレクトパスリードの判断 (adaptive direct read)、大きな表のスキャン、一時表領域 (temp) の読み取り、LOB アクセス。","action":"クエリのチューニングで大規模スキャンの必要性を減らす、PGA サイズを評価する、temp の使用量が多い場合はソート/ハッシュ操作を最適化する、I/O 帯域を増やす。","tags":["io","direct-path","parallel","read"]},{"name":"direct path write","kind":"wait","meaning":"セッションがバッファキャッシュを経由せずにブロックをディスクに直接書き込んでいる。通常はダイレクトパスインサート、ソートの書き出し、LOB の書き込み時に発生する。","causes":"ダイレクトパス INSERT (APPEND) 操作、一時表領域へのソート/ハッシュの書き出し、パラレル DML、LOB の書き込み、低速な temp ディスクまたはデータディスク。","action":"ソート/ハッシュ操作用の PGA を増やして temp への書き出しを減らす、temp 表領域を高速ディスクに配置する、不要なダイレクトパスロードを見直す、I/O 性能を改善する。","tags":["io","direct-path","temp","write"]},{"name":"buffer busy waits","kind":"wait","meaning":"セッションがバッファキャッシュ内のブロックにアクセスしようとしているが、そのブロックが別のセッションによって互換性のないモードで使用されているため、解放を待機している。","causes":"同じブロックへの激しい同時アクセス (ホットブロック)、freelist/ASSM の不足、連番インデックスでの右端ブロックの競合 (right-hand index growth)、DML 負荷の高いセグメント。","action":"ホットブロックを分散する (ハッシュパーティショニング、リバースキーインデックス)、ASSM を使用する、freelist/freelist group を増やす、連番キーを生成する表ではシーケンスのキャッシュと分散を改善する。","tags":["concurrency","buffer","hot-block","contention"]},{"name":"read by other session","kind":"wait","meaning":"このセッションが必要とするブロックを別のセッションがすでにディスクから読み込んでおり、このセッションは同じブロックの読み込み完了を待機している。","causes":"同じホットブロックに対する同時物理読み取り要求、小さいバッファキャッシュ、低速な I/O、多数のセッションによる人気のインデックスや表ブロックへの同時アクセス。","action":"バッファキャッシュを増やして物理読み取りを減らす、ホットセグメントを特定してアクセスプランを改善する、I/O レイテンシを下げる、不要なフルスキャンを排除する。","tags":["io","concurrency","read","hot-block"]},{"name":"latch: cache buffers chains","kind":"wait","meaning":"セッションがバッファキャッシュのハッシュチェーンを保護するラッチの取得を待機している。バッファキャッシュ内のブロックを探す際にシリアライズが発生している。","causes":"過剰な論理 I/O を生む非効率な SQL、ホットブロックへの激しい同時アクセス、ネステッドループによる同一ブロックへの繰り返しアクセス、非常に人気のあるインデックスのルート/ブランチブロック。","action":"SQL をチューニングして論理読み取りを減らす、不要なネステッドループアクセスを排除する、ホットブロックを分散する、AWR/ASH で buffer gets の多いクエリを見つけて修正する。","tags":["latch","concurrency","logical-io","buffer"]},{"name":"cursor: pin S wait on X","kind":"wait","meaning":"セッションが mutex でカーソルを共有 (S) モードで pin しようとしているが、別のセッションが同じカーソルを排他 (X) モードで保持しているため待機している。","causes":"高いハード/ソフトパース率、非常に頻繁にパースされる人気の SQL、バインド変数を使わないリテラルクエリ、子カーソルの増殖、多数のセッションによる同一 SQL の同時パース。","action":"バインド変数を使用してパース負荷を減らす、アプリケーションでカーソルをキャッシュする (session_cached_cursors)、不要な再パースを減らす、バージョン数の多い SQL を修正する。","tags":["mutex","parse","cursor","concurrency"]},{"name":"library cache lock","kind":"wait","meaning":"セッションがライブラリキャッシュ内のオブジェクト (パッケージ、ビュー、表定義) のハンドルに対するロックの取得を待機している。通常はオブジェクト定義への同時アクセス/変更時に発生する。","causes":"使用中のオブジェクトに対する DDL、継続的に再コンパイルされるパッケージ/ビュー、無効なオブジェクト、多数の同時接続とパース、権限 (grant) の変更。","action":"DDL をオフピーク時に実行する、不要なコンパイルを防ぐ、無効なオブジェクトを修正する、アプリケーション側の過剰な接続/パースのループを減らす。","tags":["library-cache","concurrency","ddl","parse"]},{"name":"library cache: mutex X","kind":"wait","meaning":"セッションがライブラリキャッシュ内のオブジェクトを排他 (X) モードで保護するための mutex の取得を待機している。通常はパースが多い状況やオブジェクトハンドルの競合時に発生する。","causes":"過剰なパース (ハード/ソフト)、バインドなしの多様なリテラル SQL、子カーソル数の多さ、頻繁なオブジェクトの無効化、多数のセッションによる同一オブジェクトへの同時アクセス。","action":"バインド変数とカーソルキャッシュを使用してパースを減らす、SQL のリテラルを標準化する、バージョン数の多い問題を修正する、アプリケーションの接続の挙動を改善する。","tags":["mutex","library-cache","parse","concurrency"]},{"name":"enq: TX - row lock contention","kind":"wait","meaning":"セッションが別のトランザクションによってロックされた行を変更しようとしており、そのトランザクションがコミット/ロールバックして行ロックを解放するのを待機している。","causes":"同じ行に対する同時 UPDATE/DELETE、コミットしない長時間実行のトランザクション、設計の悪いアプリケーションのワークフロー、一意キー/外部キーによる間接的な行ロック、ハングしたセッション。","action":"トランザクションを短く保ち速やかにコミットする、競合するアクセスパターンを再設計する、必要に応じて SELECT FOR UPDATE で順序付けたアクセスを強制する、ASH でブロッキングセッションを見つけて解消する。","tags":["lock","transaction","row-lock","contention"]},{"name":"enq: TX - allocate ITL entry","kind":"wait","meaning":"セッションがブロック上で処理するためにそのブロック内の ITL (Interested Transaction List) スロットを必要としているが、空きの ITL スロットが残っていないため待機している。","causes":"低い INITRANS 設定、小さいブロックサイズ、同一ブロック内の多数の同時トランザクション、DML が集中する高密度のブロック。","action":"表/インデックスの INITRANS を増やす、PCTFREE を上げてブロックあたりの行数を減らす、ホットブロックを分散する、必要に応じてオブジェクトを再構築する。","tags":["lock","transaction","itl","block"]},{"name":"gc buffer busy acquire","kind":"wait","meaning":"RAC 環境で、セッションがグローバルキャッシュ経由でブロックを取得しようとしているが、同じインスタンス上の別のセッションがすでに同じブロックに対するグローバル要求を開始しているため待機している。","causes":"RAC のインスタンス間でのホットブロックの共有、インターコネクトの性能不足、連番インデックスでの右端の競合、適切に分割されていないワークロード、多量のグローバルキャッシュトラフィック。","action":"ワークロードをインスタンス間で適切に分割する (アプリケーションアフィニティ/サービス)、ホットセグメントを分散する (リバースキー/パーティション)、インターコネクトのレイテンシを改善する、AWR の RAC セクションと GV$ ビューで gc 競合を分析する。","tags":["rac","global-cache","concurrency","interconnect"]},{"name":"gc cr block busy","kind":"wait","meaning":"RAC 環境で、セッションが別のインスタンスに読み取り一貫性 (CR) 用のブロックを要求し、そのインスタンスがブロックを準備してインターコネクト経由で送信するのを待機している。","causes":"インスタンス間でのホットブロックの共有、低速または飽和したインターコネクト、多量の redo/コミットトラフィック、適切に分割されていないワークロード、過剰なグローバルキャッシュ CR 要求。","action":"ワークロードのアフィニティを改善する、インターコネクトの帯域とレイテンシを最適化する、ホットブロックを減らす、コミットと DML のパターンを見直す、RAC をチューニングする。","tags":["rac","global-cache","cr","interconnect"]},{"name":"log file switch (checkpoint incomplete)","kind":"wait","meaning":"セッションが新しい redo ログに切り替えようとしているが、次のログファイルのチェックポイントがまだ完了していないため LGWR がそのログを再利用できず、すべての redo 生成が停止している。","causes":"小さすぎる、または少なすぎる redo ログファイル、低速な DBWR/チェックポイント I/O、高い redo 生成レート、不十分なロググループ数。","action":"redo ログファイルを拡大しグループを追加する、DBWR/チェックポイントの I/O 性能を改善する、redo 生成を減らすアプリケーションの最適化を行う、ログスイッチの頻度を監視する。","tags":["redo","checkpoint","log-switch","io"]},{"name":"free buffer waits","kind":"wait","meaning":"セッションが新しいブロックを読み込むためにバッファキャッシュ内のクリーン/空きバッファを探しているが、DBWR がダーティバッファを十分な速さでディスクに書き込めないため、空きバッファを待機している。","causes":"低速な DBWR の書き込み I/O、小さいバッファキャッシュ、多量の DML によるダーティバッファの急速な生成、不十分なチェックポイント速度、飽和したディスクサブシステム。","action":"データファイルの書き込み I/O を高速化する、バッファキャッシュのサイズを増やす、DBWR プロセス数 (db_writer_processes) を評価する、DML の負荷とチェックポイントの設定を見直す。","tags":["buffer","dbwr","io","checkpoint"]},{"name":"バッファキャッシュヒット率","kind":"metric","meaning":"要求されたブロックのうち、ディスクに行かずにバッファキャッシュから提供されたものの割合。論理読み取りの何パーセントが物理読み取りを必要としなかったかを示す。","causes":"低い比率は通常、小さいバッファキャッシュ、非効率なフルスキャン、コールドキャッシュ、または多い物理読み取りが原因。単独では誤解を招くことがあり、高い比率が悪い SQL を隠している場合もある。","action":"比率だけを目標にしない。待機イベントや物理読み取りの傾向と併せて評価する。非効率な SQL をチューニングし、不要な論理読み取りを減らし、ワークロードに合わせてキャッシュをサイジングする。","tags":["metric","buffer-cache","ratio","memory"]},{"name":"平均アクティブセッション数","kind":"metric","meaning":"ある期間に同時にアクティブ (CPU 上で実行中またはイベントで待機中) だったセッションの平均数。データベース全体の負荷とボトルネックの強さを要約する。","causes":"高い AAS は CPU の飽和、I/O 待機、ロック/ラッチの競合、または同時実行性の増加が原因となりうる。CPU コア数に近づく、または超える値はリソースのボトルネックを示す。","action":"AAS を CPU コア数と比較する、ASH で支配的な待機クラス (CPU/IO/同時実行性) を特定する、最も負荷を生む SQL とセッションをチューニングする、リソースまたは同時実行性の問題を解消する。","tags":["metric","load","ash","sessions"]}]},"reference/waits-postgres.json":{"engineId":"postgres","engine":"PostgreSQL","order":2,"waits":[{"name":"LWLock:WALWrite","kind":"wait","meaning":"セッションが WAL バッファをディスクに書き込むために必要な軽量ロックを待機している。通常はコミット時の WAL 書き込みのシリアライズが原因。","causes":"低速な WAL ディスク I/O、非常に頻繁/小さいコミット、高い書き込み負荷、不十分な WAL 書き込み帯域、WAL を同時に書き込む多数のバックエンド。","action":"WAL を高速/低レイテンシのディスクに移動する、コミットをグループ化する (synchronous_commit、commit_delay を評価)、wal_buffers を増やす、不要な書き込み操作を減らす。","tags":["wal","lwlock","commit","io"]},{"name":"LWLock:BufferContent","kind":"wait","meaning":"セッションが共有バッファプール内のバッファについて、ページ内容を保護する軽量ロックを待機している。ページへの同時アクセスによる競合を示す。","causes":"同じページへの激しい同時読み書き (ホットページ)、連番インデックスでの右端の競合、更新の集中する小さな表、高い同時実行性。","action":"ホットページを分散する (fillfactor の設定、パーティショニング)、連番キーの競合を減らす、更新の集中する行を再構成する、同時アクセスのパターンを見直す。","tags":["lwlock","buffer","concurrency","contention"]},{"name":"Lock:transactionid","kind":"wait","meaning":"セッションが変更しようとしている行をロックしている別のトランザクションの終了 (コミット/ロールバック) を待機している。ロック待機の対象は相手トランザクションの ID。","causes":"同じ行に対する同時 UPDATE/DELETE、コミットしない長時間実行のトランザクション、idle-in-transaction のセッション、設計の悪い競合するワークフロー。","action":"トランザクションを短く保ち速やかにコミットする、idle-in-transaction のセッションを制限する (idle_in_transaction_session_timeout)、競合するアクセスパターンを再設計する、pg_stat_activity でブロッキングしているクエリを特定する。","tags":["lock","transaction","row-lock","contention"]},{"name":"Lock:tuple","kind":"wait","meaning":"セッションが特定のタプル (行) に対するロックの取得を待機している。複数のセッションが同じ行の更新/ロックのために待ち行列を作るときに発生する。","causes":"同じ行に対する同時 SELECT FOR UPDATE/UPDATE、ホット行の競合 (例: カウンター行)、長時間保持される行ロック、高い同時実行性。","action":"ホット行の更新を分散またはキューイングする、トランザクション時間を短縮する、カウンターなどの競合パターンを再設計する (例: バッチ更新)、FOR UPDATE SKIP LOCKED を検討する。","tags":["lock","tuple","row-lock","contention"]},{"name":"Lock:relation","kind":"wait","meaning":"セッションが表/インデックス (リレーション) に対する表レベルのロックの取得を待機している。通常は DDL と DML の互換性のないロックモード間の競合で発生する。","causes":"クエリ実行中の ALTER/DROP/TRUNCATE などの DDL、強いロックを必要とする VACUUM FULL、互換性のないモードでの同一表への同時アクセス、長時間実行のクエリ。","action":"DDL は短い lock_timeout を設定して閑散時に実行する、VACUUM FULL ではなく通常の autovacuum を使用する、長時間のクエリを監視する、表へのアクセスをシリアライズする操作を見直す。","tags":["lock","relation","ddl","table-lock"]},{"name":"IO:DataFileRead","kind":"wait","meaning":"セッションがデータファイルのページがディスクから共有バッファに読み込まれるのを待機している。要求されたページがキャッシュにないときに発生する物理読み取りの待機。","causes":"小さい shared_buffers、非効率な実行計画と大規模スキャン、コールドキャッシュ、低速なディスクサブシステム、不十分なインデックスの使用。","action":"ワークロードに合わせて shared_buffers と OS のページキャッシュを調整する、非効率なクエリと欠落したインデックスを修正する、I/O 性能を改善する、effective_cache_size を正しく設定する。","tags":["io","read","buffer","disk"]},{"name":"IO:WALSync","kind":"wait","meaning":"セッションが WAL がディスクに永続的に書き込まれる (fsync/同期) のを待機している。コミットの耐久性のために WAL が物理的にフラッシュされるのを待っている。","causes":"ストレージの fsync レイテンシの大きさ、非常に頻繁なコミット、低性能な WAL ディスク、ライトバックキャッシュのないディスク、高い書き込み負荷。","action":"WAL ディスクを fsync レイテンシの小さい高速ストレージに移動する、コミットをグループ化する (commit_delay/commit_siblings)、業務要件に照らして synchronous_commit を評価する、ストレージ層を改善する。","tags":["wal","io","fsync","commit"]},{"name":"IO:DataFileWrite","kind":"wait","meaning":"セッションがダーティなデータページがディスクに書き込まれるのを待機している。通常はバックエンド自身がバッファプール内でクリーンなページを確保するために書き込むときに発生する。","causes":"データディスクの書き込み I/O の低速、チェックポイントの混雑、バックグラウンドライターの不足、小さいバッファプール、高い書き込み負荷によるバックエンド自身の書き込み。","action":"チェックポイントを平準化する (checkpoint_completion_target、max_wal_size)、バックグラウンドライターを調整する (bgwriter_lru_maxpages)、ディスクの書き込み性能を改善する、shared_buffers を見直す。","tags":["io","write","checkpoint","bgwriter"]},{"name":"Client:ClientRead","kind":"wait","meaning":"バックエンドがクライアントからの次のコマンド/データを待機している。サーバーがアイドル状態で、クライアントからのデータ送信を待っているときに発生する。","causes":"低速なネットワーク、idle-in-transaction のセッション、クライアントアプリケーションのデータ送受信の遅さ、大きな結果セットの消費の遅さ、コネクションプールの問題。","action":"アプリケーション側とネットワークのレイテンシを調べる、idle-in-transaction のセッションを制限する、結果を効率的に消費する (例: カーソル/バッチ)、コネクションプールを改善する。この待機は通常、データベースのボトルネックではない。","tags":["client","network","idle","application"]},{"name":"IPC:ProcArrayGroupUpdate","kind":"wait","meaning":"セッションが、グループリーダーのバックエンドが自身のトランザクションの終了を ProcArray にグループとして記録するのを待機している。コミット時の ProcArray 更新のシリアライズ。","causes":"非常に高いコミット/トランザクションレート、過剰な同時短時間トランザクション、多い接続数、激しいスナップショット/ProcArray アクセス。","action":"トランザクションレートと同時接続数を管理する (コネクションプール)、不要な短時間トランザクションを減らす、非常に高い同時実行時は接続数を制限する、ワークロードを平準化する。","tags":["ipc","commit","procarray","concurrency"]},{"name":"LWLock:LockManager","kind":"wait","meaning":"セッションが重量ロックテーブルを保護するロックマネージャの軽量ロックを待機している。ロックの取得/解放操作のシリアライズが原因。","causes":"多数の表/パーティションにアクセスするクエリ (fast-path ロックの上限を超過)、高い同時実行性、過剰にパーティション化された表、多数のロックを取得/解放するワークロード。","action":"クエリごとにアクセスするパーティション/表の数を減らす (パーティションプルーニング)、過剰なパーティション化を見直す、コネクションプールで同時実行性を管理する、不要なロックを取る操作を簡素化する。","tags":["lwlock","lock-manager","concurrency","partitioning"]},{"name":"Timeout:VacuumDelay","kind":"wait","meaning":"vacuum/autovacuum プロセスがコストベースの vacuum 遅延により意図的に一時停止している。I/O 負荷を制限するための意図的な待機。","causes":"vacuum_cost_delay/autovacuum_vacuum_cost_delay の設定によるスロットリング、低い cost_limit、多数の表をクリーンアップする vacuum、積極的でない autovacuum 設定。","action":"vacuum が遅すぎて肥大化/デッドタプルが蓄積している場合は、cost_limit を上げ cost_delay を下げる、autovacuum ワーカー数としきい値を調整する、I/O 容量とのバランスをとる。","tags":["vacuum","timeout","throttle","maintenance"]},{"name":"キャッシュヒット率","kind":"metric","meaning":"ブロック要求のうち、ディスクに行かずに shared buffers から提供されたものの割合。pg_stat_database の blks_hit と blks_read から算出する。","causes":"低い比率は通常、小さい shared_buffers、非効率な大規模スキャン、コールドキャッシュ、またはメモリ不足を示す。OS のページキャッシュも読み取りを提供するため、比率だけでは誤解を招くことがある。","action":"比率は待機イベントや I/O の傾向と併せて解釈する、shared_buffers と effective_cache_size を調整する、非効率なクエリを修正する。継続的に低い場合はメモリと実行計画を調べる。","tags":["metric","cache","ratio","memory"]},{"name":"レプリケーション遅延","kind":"metric","meaning":"スタンバイ/レプリカサーバーがプライマリの生成した WAL の適用でどれだけ遅れているか。バイト (LSN の差) または秒単位の遅延で測定する。","causes":"低速なネットワーク、スタンバイ上の高いクエリ負荷 (特にリプレイの競合)、スタンバイのディスク I/O の低速、プライマリの高い書き込みレート、リカバリを遅らせる長時間の読み取りクエリ。","action":"pg_stat_replication で write/flush/replay の遅延を監視する、ネットワークとスタンバイの I/O 性能を改善する、競合する長時間クエリを管理する (hot_standby_feedback/max_standby_streaming_delay)、同期レプリケーションの必要性を見直す。","tags":["metric","replication","lag","standby"]}]},"reference/waits-mysql.json":{"engineId":"mysql","engine":"MySQL","order":3,"waits":[{"name":"wait/synch/mutex/innodb/buf_pool_LRU_list_mutex","kind":"wait","meaning":"スレッドが InnoDB バッファプールの LRU リストを保護する mutex を待機している。ページの読み込み/削除時のシリアライズを示す。8.0 では従来の単一の buf_pool_mutex が分割され、他の関連インストゥルメントは buf_pool_free_list_mutex、buf_pool_flush_state_mutex、buf_pool_zip_mutex。","causes":"高い同時実行性での激しいバッファプールアクセス、単一のバッファプールインスタンス、頻繁なページの読み込み/削除、小さすぎるバッファプール。","action":"innodb_buffer_pool_instances を増やして mutex を分割する、innodb_buffer_pool_size をワーキングセットに合わせてサイジングする、クエリをチューニングして物理読み取りを減らす、同時実行性を管理する。","tags":["innodb","mutex","buffer-pool","concurrency"]},{"name":"wait/io/file/innodb/innodb_data_file","kind":"wait","meaning":"スレッドが InnoDB データファイル (ibd/ibdata) に対する物理ファイル I/O (読み取り/書き込み) の完了を待機している。","causes":"低速なディスクサブシステム、小さいバッファプールによる多数の物理読み取り、大きな表のスキャン、チェックポイント/フラッシュの負荷、不十分な I/O 容量。","action":"バッファプールを拡大する、非効率なクエリと欠落したインデックスを修正する、高速ストレージ (SSD/NVMe) に移行する、innodb_io_capacity をストレージに合わせて設定する、フラッシュの挙動を見直す。","tags":["innodb","io","datafile","disk"]},{"name":"wait/lock/table/sql/handler","kind":"wait","meaning":"スレッドが SQL レイヤーの表レベルのハンドラロック (テーブルロック) の取得を待機している。互換性のないモードでの表への同時アクセス時に発生する。","causes":"テーブルロックを必要とする操作、MyISAM など表レベルロックのストレージエンジン、LOCK TABLES 文、DDL と DML の競合、長時間実行のクエリ。","action":"行レベルロックの InnoDB を使用する、LOCK TABLES の使用を減らす、DDL は活動の少ない時間に実行する、長時間のクエリを最適化する、表へのアクセスをシリアライズするパターンを見直す。","tags":["lock","table-lock","sql-layer","contention"]},{"name":"wait/synch/mutex/sql/LOCK_open","kind":"wait","meaning":"スレッドがオープン中の表定義/オブジェクトディクショナリを保護する LOCK_open mutex を待機している。表のオープン/クローズ操作のシリアライズ。","causes":"多数の異なる表への継続的なアクセス、小さい table_open_cache/table_definition_cache、頻繁な表のオープンとクローズ、高い同時実行性、多すぎる表/パーティション。","action":"table_open_cache と table_open_cache_instances を増やす、table_definition_cache を調整する、過剰な表/パーティション数を見直す、不必要に頻繁な表のオープンを減らす。","tags":["mutex","table-cache","sql-layer","concurrency"]},{"name":"行ロック待機","kind":"wait","meaning":"トランザクションが別のトランザクションの保持する InnoDB 行ロックの解放を待機している。行レベルのロック競合を示す。","causes":"同じ行に対する同時 UPDATE/DELETE、コミットしない長時間実行のトランザクション、インデックスの欠落による広いロック範囲 (ギャップロック)、ホット行の競合、デッドロックのサイクル。","action":"トランザクションを短く保ち速やかにコミットする、適切なインデックスを追加してロックされる行の範囲を狭める、競合するパターンを再設計する、デッドロックを監視する (SHOW ENGINE INNODB STATUS)、分離レベルを見直す。","tags":["innodb","row-lock","transaction","contention"]},{"name":"ログファイル待機","kind":"wait","meaning":"スレッドが InnoDB redo ログバッファの空き領域の確保、または redo ログのディスクへの書き込みを待機している。通常はログバッファのフラッシュ/チェックポイントの負荷が高いときに発生する。","causes":"小さい redo ログ (8.0.30+ では innodb_redo_log_capacity、それ以前は innodb_log_file_size × innodb_log_files_in_group)、低速なログディスク、高い書き込みレート、頻繁なフラッシュ (innodb_flush_log_at_trx_commit=1 で頻繁なコミット)、不十分なログバッファ。","action":"redo 容量 (8.0.30+ では innodb_redo_log_capacity、動的。それ以前は innodb_log_file_size、再起動が必要) と innodb_log_buffer_size を増やす、redo ログを高速ディスクに移動する、コミットパターンを見直す、耐久性の要件に照らしてフラッシュ設定を評価する。","tags":["innodb","redo","log","io"]},{"name":"wait/io/file/innodb/innodb_log_file","kind":"wait","meaning":"スレッドが InnoDB redo ログファイルに対する物理 I/O (書き込みと fsync) の完了を待機している。コミットの耐久性のために redo がディスクに到達するのを待っている。","causes":"ストレージの fsync レイテンシの大きさ、innodb_flush_log_at_trx_commit=1 での非常に頻繁なコミット、低性能なログディスク、高い書き込み負荷。","action":"redo ログディスクを低レイテンシの高速ストレージに移動する、可能な場合はコミットをグループ化する、業務要件に照らして innodb_flush_log_at_trx_commit を評価する、ストレージ層を改善する。","tags":["innodb","redo","fsync","commit"]},{"name":"wait/synch/mutex/innodb/log_writer_mutex","kind":"wait","meaning":"スレッドが InnoDB redo ログライタースレッドの構造を保護する mutex を待機している。redo サブシステムは 8.0 で再設計され、従来の単一の log_sys_mutex の代わりに log_writer_mutex、log_flusher_mutex、log_checkpointer_mutex などの個別のインストゥルメントがある。","causes":"非常に高い書き込み/コミットレート、多量の redo 生成、ログライター/フラッシャースレッドの競合、低速なログディスク、小さいログバッファ。","action":"書き込み負荷とコミット頻度を平準化する、redo 生成を減らすバッチ操作を検討する、ログバッファを調整する、使用中の MySQL バージョンの redo ログのスケーラビリティ改善を活用する。","tags":["innodb","mutex","redo","concurrency"]},{"name":"Innodb_buffer_pool_wait_free","kind":"metric","meaning":"スレッドがバッファプール内に空きページを見つけられず、空きページを得るためにダーティページのフラッシュを待たなければならなかった回数。継続的な増加はバッファプールの逼迫を示す。","causes":"小さいバッファプール、低速なフラッシュ/書き込み I/O、低い innodb_io_capacity、高い書き込み負荷による急速なダーティページの生成、チェックポイントの遅延。","action":"innodb_buffer_pool_size を増やす、innodb_io_capacity/io_capacity_max をストレージに合わせて設定する、書き込み I/O 性能を改善する、ダーティページの割合 (innodb_max_dirty_pages_pct) を見直す。","tags":["metric","innodb","buffer-pool","flush"]},{"name":"Threads_running","kind":"metric","meaning":"その時点でアイドルではなく、アクティブにクエリを実行しているスレッドの数。サーバー上の瞬間的な同時実行数と、競合の強さの目安を示す。","causes":"クエリの急増、低速クエリの滞留、ロック/mutex の競合によるスレッドの停滞、CPU の飽和、サンダリングハード効果。","action":"Threads_running が急増した場合は、低速/ブロックされたクエリを特定する (SHOW PROCESSLIST)、クエリをチューニングする、コネクションプールとスレッドプールで同時実行性を制限する、競合の原因を取り除く。","tags":["metric","concurrency","threads","load"]},{"name":"Innodb_row_lock_time_avg","kind":"metric","meaning":"行ロックの取得待ちに費やされた平均時間 (ミリ秒)。行レベルのロック競合の深刻度を示す。","causes":"同じ行への激しい同時アクセス、長いトランザクション、インデックスの欠落による広いロック範囲、デッドロック/ロック待機タイムアウトに近い待機。","action":"トランザクション時間を短縮する、適切なインデックスでロックの範囲を狭める、競合するアクセスパターンを再設計する、innodb_lock_wait_timeout と分離レベルを見直す。","tags":["metric","innodb","row-lock","contention"]},{"name":"history list length","kind":"metric","meaning":"InnoDB の undo ログ内でまだパージされていない (古い行バージョンを保持している) トランザクションの数。MVCC のために保持される古いバージョンの蓄積を示す。","causes":"長時間オープンしたままのトランザクション (特に長い読み取りトランザクション)、低速なパージスレッド、高い DML レート、未コミット/アイドルのトランザクション。","action":"長時間実行中およびアイドルのトランザクションを特定して終了させる、パージスレッド数を調整する (innodb_purge_threads)、アプリケーションでトランザクションを短く保つ。HLL が大きいと性能と肥大化の問題を招く。","tags":["metric","innodb","undo","mvcc"]},{"name":"Innodb_data_reads","kind":"metric","meaning":"InnoDB がディスクから実行した物理読み取り要求の総数。バッファプールで提供できずディスクに行った読み取り負荷を示す。","causes":"小さいバッファプール、コールドキャッシュ、非効率なクエリと大規模スキャン、インデックスの欠落、メモリより大きいワーキングセット。","action":"バッファプールのサイズを増やす、非効率なクエリと欠落したインデックスを修正する、物理読み取りの傾向をバッファプールのヒット率と併せて監視する、I/O 性能を改善する。","tags":["metric","innodb","io","read"]},{"name":"Innodb_buffer_pool_read_requests","kind":"metric","meaning":"InnoDB バッファプールから提供された論理読み取り要求の総数。Innodb_buffer_pool_reads (バッファプールに見つからずディスクから読み込まれたページ数) と併せてバッファプールのヒット率の算出に使用する。","causes":"高い値は活発なクエリ活動を示す。この値に対する Innodb_buffer_pool_reads の割合が高い (ヒット率が低い) 場合は、メモリ不足または非効率なアクセスがある。","action":"バッファプールのヒット率 (1 - Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests) を監視する。低い場合はバッファプールを拡大してクエリを最適化し、過剰な論理読み取りを生む非効率なクエリをチューニングする。","tags":["metric","innodb","buffer-pool","logical-io"]}]},"reference/waits-mssql.json":{"engineId":"mssql","engine":"SQL Server","order":4,"waits":[{"name":"CXPACKET","kind":"wait","meaning":"パラレルクエリ実行中にスレッドが同期するときに発生する待機。パラレルプランの演算子間での作業の分配/照合が保留中のときに発生する。","causes":"高い並列度、不均一な作業分配 (スキュー)、無制限/高い MAXDOP (0) と低い cost threshold for parallelism (デフォルト 5)、インデックスの欠落による大規模なパラレルスキャン、非効率なプラン。","action":"cost threshold for parallelism と MAXDOP をワークロードに合わせて調整する、欠落したインデックスと統計を修正する、CXPACKET 単独を問題とみなさない。CXCONSUMER を使って実際の待機を切り分け、非効率なパラレルプランを対象にする。","tags":["parallelism","cxpacket","query","cpu"]},{"name":"CXCONSUMER","kind":"wait","meaning":"パラレルプランで、コンシューマスレッドがプロデューサスレッドからのデータ到着を待機している。通常は無害な並列処理の待機。","causes":"通常のパラレル実行中のコンシューマスレッドの待機、不均一なデータフロー、プロデューサ側の遅延、非効率なパラレルプラン。","action":"CXCONSUMER はほとんどの場合無害で、単独では対処不要。実際のボトルネックを見つけるには、プロデューサ側の根本的な待機タイプ (IO、LCK など) とプランの効率に注目する。","tags":["parallelism","cxconsumer","query","benign"]},{"name":"PAGEIOLATCH_SH","kind":"wait","meaning":"スレッドがデータページをディスクからバッファプールに読み込む間、共有 (SH) モードで保護するためのラッチを待機している。読み取りの物理 I/O 待機。","causes":"低速なディスク I/O、メモリ不足 (小さいバッファプール)、大規模スキャンとインデックスの欠落、コールドキャッシュ、高い物理読み取り負荷。","action":"メモリ (max server memory) とバッファプールを評価する、非効率なクエリと欠落したインデックスを修正する、ストレージの I/O レイテンシを改善する、読み取りの多いクエリを特定してチューニングする。","tags":["io","pageiolatch","read","buffer-pool"]},{"name":"PAGEIOLATCH_EX","kind":"wait","meaning":"スレッドがディスクから読み込まれるデータページを排他 (EX) モードで保護するためのラッチを待機している。通常は変更のために読み込まれるページの物理 I/O を待っている。","causes":"低速なディスク I/O、高い書き込みワークロード、メモリ不足、チェックポイント/lazy writer の負荷、大量のデータ変更を行う操作。","action":"ストレージの書き込み/読み取り性能を改善する、バッファプールのメモリを増やす、書き込みの多い操作をバッチ化して効率化する、tempdb とデータディスクの I/O を分離して測定する。","tags":["io","pageiolatch","write","buffer-pool"]},{"name":"PAGELATCH_UP","kind":"wait","meaning":"スレッドがすでにメモリ上にあるページを更新 (UP) モードで保護するためのラッチを待機している。物理 I/O ではなく、メモリ上のページへの同時アクセスの競合。","causes":"メモリ上のホットページの競合、特に tempdb のシステムページ (PFS/GAM/SGAM) の競合、tempdb オブジェクトの激しい同時作成、最終ページ (ホットページ) への挿入の競合。","action":"tempdb をコア数に合わせた同じサイズのデータファイルに分割する、tempdb の競合を減らす、ホットページのパターンを分散する、不要な tempdb の使用 (spill など) を排除する。","tags":["pagelatch","tempdb","concurrency","contention"]},{"name":"PAGELATCH_EX","kind":"wait","meaning":"スレッドがメモリ上のページを排他 (EX) モードで保護するためのラッチを待機している。通常は昇順 (連番) キーを持つ表での最終ページへの挿入の競合で発生する。","causes":"連番/昇順キーを持つインデックスでの最終ページへの挿入の競合、tempdb のシステムページの競合、ホットページへの激しい同時書き込み、高い挿入レート。","action":"最終ページの競合には OPTIMIZE_FOR_SEQUENTIAL_KEY = ON (SQL Server 2019+) またはキーの分散 (ハッシュ/GUID/リバースインデックス) を使用する、tempdb を複数のファイルに分割する、多量の挿入パターンを再設計する。","tags":["pagelatch","last-page-insert","concurrency","contention"]},{"name":"LCK_M_X","kind":"wait","meaning":"スレッドがリソース (行/ページ/表) に対する排他ロックの取得を待機している。通常はデータを変更 (UPDATE/DELETE/INSERT) するために他のロックの解放を待っている。","causes":"長時間実行のトランザクション、同じリソースへの同時変更、ロックエスカレーション、インデックスの欠落による広いロック範囲、ブロッキングセッション。","action":"トランザクションを短く保ち速やかにコミットする、適切なインデックスでロックの範囲を狭める、ブロッキングしているクエリを特定する (sys.dm_exec_requests/blocking)、ロックエスカレーションと分離レベルを見直す、必要に応じて RCSI を検討する。","tags":["lock","exclusive","blocking","transaction"]},{"name":"LCK_M_U","kind":"wait","meaning":"スレッドがリソースに対する更新ロックの取得を待機している。UPDATE のスキャン中、行を読み取って変更の準備をする際に他のロックの解放を待っている。","causes":"同じ行への同時更新、長いトランザクション、インデックスの欠落によりスキャンロックされる多数の行、ブロッキングセッション、ロック競合。","action":"UPDATE 文に適切なインデックスを追加してスキャン/ロックされる行数を減らす、トランザクション時間を短縮する、ブロッキングチェーンを分析する、分離レベルと RCSI のオプションを評価する。","tags":["lock","update-lock","blocking","transaction"]},{"name":"WRITELOG","kind":"wait","meaning":"スレッドがトランザクションログレコードのディスクへの書き込み (ログフラッシュ) を待機している。通常はコミット時にログが永続化されるのを待っている。","causes":"ログディスクの I/O の低速、非常に頻繁/小さいコミット、高い書き込み負荷、ログディスクとデータディスクの競合、同期 Always On レプリケーションの影響。","action":"トランザクションログを高速・低レイテンシのディスクに移動する、コミットをバッチ化する、不必要に頻繁なコミットを減らす、遅延持続性 (delayed durability) を検討する (適切な場合)、ログ I/O のレイテンシを測定する。","tags":["log","writelog","commit","io"]},{"name":"ASYNC_NETWORK_IO","kind":"wait","meaning":"SQL Server が結果を送信する準備ができているが、クライアントがデータを十分な速さで消費しないためネットワーク/クライアント側で待機している。通常はアプリケーション側のボトルネック。","causes":"クライアントアプリケーションの結果処理の遅さ (行単位の消費)、大きな結果セット、低速なネットワーク、アプリケーションでの RBAR 処理、クライアントのリソース不足。","action":"アプリケーションで結果を高速かつまとめて消費する、不必要に大きな結果セットを減らす (必要な列/行のみ)、ネットワークのレイテンシを確認する。これは通常 SQL Server ではなくクライアント/ネットワークの問題。","tags":["network","client","application","async"]},{"name":"SOS_SCHEDULER_YIELD","kind":"wait","meaning":"スレッドが CPU のタイムスライス (クォンタム) を使い切り、自発的にスケジューラを譲るときに発生する待機。主に CPU の負荷または CPU 集中型の処理を示す。","causes":"CPU バウンドの重いクエリ、高い同時実行性と CPU の飽和、スピンロックの競合、多数の論理読み取りを行う非効率なクエリ。","action":"CPU を消費する非効率なクエリ (インデックスの欠落、悪いプラン) を特定してチューニングする、論理読み取りを減らす、CPU 容量と同時実行性を評価する。高い状態が続く場合はハードウェア/プランのボトルネックを調査する。","tags":["cpu","scheduler","cpu-bound","yield"]},{"name":"RESOURCE_SEMAPHORE","kind":"wait","meaning":"クエリが実行に必要なメモリ許可 (memory grant) を待機している。十分なクエリメモリが空くまで実行を開始できない。","causes":"過剰なメモリを要求するクエリ (大規模なソート/ハッシュ)、誤った (過大な) カーディナリティ推定、サーバーメモリの不足、メモリを多く使う多数の同時クエリ、古い統計。","action":"統計を更新して過剰なメモリ許可の推定を修正する、大規模なソート/ハッシュを必要とするクエリを最適化する (インデックス、フィルタ)、Resource Governor と max server memory の設定を見直す、メモリを多く使う同時負荷を制限する。","tags":["memory","memory-grant","query","resource"]},{"name":"THREADPOOL","kind":"wait","meaning":"新しいタスクを実行できるワーカースレッドがないため、タスクがスレッドプールの空きスレッドを待機している。深刻なワーカースレッドの枯渇を示す重大な待機タイプ。","causes":"長いブロッキングによって保持されたスレッド、非常に多い同時接続、不十分な max worker threads、激しい並列処理、デッドロック/長いロックチェーン。","action":"ブロッキングチェーンを緊急に解消する、コネクションプールで同時接続を管理する、長時間保持されるロックを排除する、max worker threads の設定を見直す。根本原因を見つけるには DAC で接続する。","tags":["threadpool","worker-thread","blocking","critical"]},{"name":"HADR_SYNC_COMMIT","kind":"wait","meaning":"Always On の同期レプリカで、プライマリがトランザクションをコミットする前にログレコードがセカンダリレプリカで書き込み確定 (harden) されるのを待機している。同期コミットのレイテンシ。","causes":"セカンダリレプリカへの低速/高レイテンシのネットワーク、セカンダリでのログディスク I/O の低速、過負荷のセカンダリ、地理的に離れたレプリカ、高い書き込みレート。","action":"レプリカ間のネットワークのレイテンシと帯域を改善する、セカンダリのログディスク性能を上げる、セカンダリの負荷を平準化する。レイテンシが重要な場合は同期/非同期レプリカのトポロジを見直す。","tags":["alwayson","replication","sync-commit","hadr"]},{"name":"Page Life Expectancy","kind":"metric","meaning":"データページが (メモリから追い出されずに) バッファプールに留まる平均秒数を示すメトリック。メモリ不足の重要な指標。","causes":"低い、または急速に低下する PLE はメモリ不足、非効率な大規模スキャン、メモリより大きいワーキングセット、またはメモリの不足を意味する。NUMA ノードごとにも評価する必要がある。","action":"固定のしきい値ではなく PLE の傾向と急な低下を見る、バッファプールのメモリ (max server memory) を評価する、メモリを多く消費する非効率なクエリをチューニングする、NUMA ノードごとに PLE を監視する。","tags":["metric","memory","buffer-pool","ple"]},{"name":"バッファキャッシュヒット率","kind":"metric","meaning":"データページ要求のうち、ディスクに行かずにバッファキャッシュから満たされたものの割合。メモリから読み込まれたページの割合を示す。","causes":"最新のシステムではこの比率は通常非常に高く (先行読み取りのおかげで)、低い値は深刻なメモリ不足を示す。高い比率だけでは良好な性能は保証されない。","action":"このメトリックは単独ではなく PLE、PAGEIOLATCH 待機、物理読み取りの傾向と併せて解釈する。メモリ不足の兆候がある場合は、バッファプールのメモリを増やし、非効率なクエリを修正する。","tags":["metric","memory","buffer-pool","ratio"]}]},"reference/waits-mongodb.json":{"engineId":"mongodb","engine":"MongoDB","order":5,"waits":[{"name":"WiredTiger キャッシュ使用率 %","kind":"metric","meaning":"WiredTiger ストレージエンジンに割り当てられた内部キャッシュのうち使用中の量。データをメモリに保持する負荷を示す (デフォルトの目標しきい値は約 80%)。","causes":"キャッシュより大きいワーキングセット、小さすぎるキャッシュ、大規模スキャン、激しい読み取り/書き込み、多数のオープントランザクション。","action":"WiredTiger キャッシュサイズ (storage.wiredTiger.engineConfig.cacheSizeGB) と RAM を評価する、ワーキングセットを縮小するインデックスを追加する、使用率が 80% の目標と 95% の eviction しきい値に近づくにつれて eviction の負荷とレイテンシを監視する。","tags":["metric","wiredtiger","cache","memory"]},{"name":"WiredTiger ダーティキャッシュ %","kind":"metric","meaning":"WiredTiger キャッシュ内でまだディスクに書き込まれていない (ダーティな) データの割合。書き込み負荷とチェックポイント/eviction の負荷を示す (ダーティ eviction のしきい値は通常約 20%)。","causes":"高い書き込み負荷、低速なディスク I/O、大規模/長時間の書き込み、チェックポイントの負荷、書き込みレートに追いつけないキャッシュ。","action":"ダーティの割合が eviction しきい値 (20%) に近づいている場合は、ディスクの書き込み性能を改善する、書き込み負荷を平準化する、キャッシュサイズを評価する、長い書き込みとチェックポイント間隔を見直す。","tags":["metric","wiredtiger","cache","write"]},{"name":"利用可能なチケット (read/write)","kind":"metric","meaning":"WiredTiger が同時の読み取り/書き込み操作に付与する同時実行チケットの残数。ゼロになると新しい操作はチケット待ちのキューに入る。","causes":"チケットを長時間保持する低速な操作、ディスク I/O のボトルネック、ロック/競合、負荷の急増、長時間実行のクエリによるチケットの枯渇。","action":"利用可能なチケットがゼロに近づきキューが形成される場合は、低速なクエリを最適化する (インデックスを追加)、ディスク I/O を改善する、負荷を平準化する。チケットの枯渇は通常、より根深い I/O/競合のボトルネックの症状。","tags":["metric","wiredtiger","concurrency","tickets"]},{"name":"グローバルロックキュー","kind":"metric","meaning":"グローバル/データベース/コレクションのロックを待機している読み取り (readers) と書き込み (writers) 操作のキュー長。ロック競合下で待機している操作の数を示す。","causes":"長時間保持されるロック、激しい書き込み競合、長時間実行の操作、DDL 操作とインデックス構築の開始/終了時に短時間取得される排他的なコレクションロック (4.2+ のハイブリッド構築。フォアグラウンド構築はもう存在しない)、低速な I/O により長時間保持されるロック。","action":"キューが継続的に満杯の場合は、長時間実行の操作を特定して最適化する (currentOp)、インデックス構築などの DDL をオフピーク時に予定する、I/O を改善する、競合する書き込みパターンを見直す。","tags":["metric","lock","queue","concurrency"]},{"name":"レプリケーション遅延 (セカンダリ)","kind":"metric","meaning":"セカンダリメンバーがプライマリの oplog の適用でどれだけ (秒) 遅れているか。レプリカセットメンバー間のデータの遅延を示す。","causes":"低速なネットワーク、セカンダリのディスク I/O の低速、セカンダリ上の高い読み取り負荷、プライマリの高い書き込みレート、セカンダリのハードウェア不足、長時間実行の操作。","action":"rs.printSecondaryReplicationInfo で遅延を監視する、ネットワークとセカンダリの I/O 性能を改善する、セカンダリの負荷を平準化する、oplog サイズを十分に保つ、write concern の要件を見直す。","tags":["metric","replication","lag","secondary"]},{"name":"oplog ウィンドウ","kind":"metric","meaning":"oplog に保持されている最も古い操作と最新の操作の間の時間幅 (時間)。セカンダリが同期を失わずにどれだけ遅れられるかを示す。","causes":"小さい oplog サイズ、突然の高い書き込みレート、長時間オフラインのセカンダリ、レプリケーション負荷の増加。","action":"oplog ウィンドウが縮小した場合は oplog サイズを増やす、セカンダリの遅延をウィンドウ未満に保つ、書き込み負荷とバックアップ/同期の要件を見直す。ウィンドウを超えた場合はフル再同期が必要。","tags":["metric","replication","oplog","window"]},{"name":"ページフォールト","kind":"metric","meaning":"メモリにないデータページを OS がディスクから取得しなければならないページフォールト (特にハードフォールト) の数。データがメモリからディスクにあふれていることを示す。","causes":"RAM より大きいワーキングセット、メモリ不足、大規模スキャン、キャッシュの逼迫、他のプロセスによるメモリ消費。","action":"サーバーのメモリ/ワーキングセットを評価する、インデックスを追加してスキャンするデータを減らす、WiredTiger キャッシュと OS メモリのバランスをとる、ハードページフォールトの増加を I/O レイテンシと併せて監視する。","tags":["metric","memory","page-fault","io"]},{"name":"現在の接続数 (connections current)","kind":"metric","meaning":"現在サーバーにオープンしているクライアント接続の数。コネクションプールの使用状況と最大値への近さを示す。","causes":"誤設定されたコネクションプール、接続リーク、クライアントの急増、長時間保持される接続、マイクロサービスからの過剰な接続。","action":"接続数をサーバーの上限 (maxIncomingConnections) と比較する、アプリケーション側でコネクションプールを正しくサイジングする、接続リークを修正し急増を監視する。","tags":["metric","connections","pool","capacity"]},{"name":"scanAndOrder / COLLSCAN 比率","kind":"metric","meaning":"インデックスを使わずにコレクションをフルスキャンする (COLLSCAN) か、メモリ内でソートする (scanAndOrder) クエリの割合。インデックスの非効率さの指標。","causes":"インデックスの欠落または不適切なインデックス、クエリに合わないソートキー、フィルタのない広範なクエリ、不適切なクエリパターン。","action":"低速なクエリとそのプランを確認する (explain)、クエリとソートのパターンに合った複合インデックスを追加する、COLLSCAN と scanAndOrder を生むクエリを修正する、検査/返却ドキュメント数の比率を監視する。","tags":["metric","index","collscan","query"]},{"name":"キュー内の操作","kind":"metric","meaning":"ロックまたはリソースを待機しているためにキューに入っている (まだアクティブに実行できない) 読み取りおよび書き込み操作の数。システムが需要を満たせていないことを示す。","causes":"ロック競合、チケットの枯渇、I/O のボトルネック、長時間実行のクエリ、負荷の急増、低速なディスク。","action":"キューが増加する場合は、アクティブな操作と長時間実行の操作を調査して最適化する (currentOp)、インデックスと I/O を改善する、負荷を平準化する、チケットとロック競合のメトリックと併せて根本原因を特定する。","tags":["metric","queue","concurrency","load"]}]},"reference/waits-redis.json":{"engineId":"redis","engine":"Redis","order":6,"waits":[{"name":"keyspace ヒット率","kind":"metric","meaning":"キー検索のうちメモリ内で見つかったものの割合。keyspace_hits と keyspace_misses から算出する。Redis がキャッシュとしてどれだけ効果的に機能しているかを示す。","causes":"低い比率は、メモリ不足による eviction、短い TTL、コールドキャッシュ、キャッシュされたことのない一意キーの多数の検索、または不適切なキー設計を示す。","action":"ヒット率を hits/(hits+misses) として監視する。低い場合はメモリ/eviction ポリシーと TTL を見直し、頻繁にアクセスされるデータを事前にウォームアップし、キー設計とキャッシュ戦略を改善する。","tags":["metric","cache","hit-ratio","keyspace"]},{"name":"evicted_keys","kind":"metric","meaning":"maxmemory の上限に達したときに eviction ポリシーによってメモリから削除されたキーの数。メモリ逼迫の直接的な指標。","causes":"maxmemory の上限超過、メモリ不足、TTL のないキーの蓄積、メモリより大きいデータ量、不適切な eviction ポリシー。","action":"eviction が継続的に増加している場合は、メモリを追加するかデータ量を減らす、ワークロードに合わせて maxmemory-policy (例: allkeys-lru/volatile-lru) を選ぶ、TTL の使い方とビッグキーを見直す。","tags":["metric","memory","eviction","maxmemory"]},{"name":"blocked_clients","kind":"metric","meaning":"BLPOP、BRPOP、WAIT、XREAD BLOCK などのブロッキングコマンドでイベント/データを待機しているクライアントの数。キューのコンシューマパターンでは正常だが、異常な増加は警告サイン。","causes":"ブロッキングのリスト/ストリームコマンドを使用するコンシューマ、プロデューサ側からデータが届かない、WAIT によるレプリカの確認応答待ち、コンシューマとプロデューサの不均衡。","action":"ブロックされたクライアント数を想定するコンシューマモデルと比較する。異常に増加した場合はプロデューサ側とレプリケーションの確認応答を調査し、キューの消費レートを平準化する。","tags":["metric","clients","blocking","queue"]},{"name":"mem_fragmentation_ratio","kind":"metric","meaning":"OS が Redis に割り当てた物理メモリ (RSS) と Redis が実際に使用しているメモリの比率。メモリの断片化またはスワップを示す。","causes":"1 を明確に超える値はメモリの断片化を示し、1 未満の値は Redis が (ディスクに) スワップアウトされたことを示す。可変サイズのキーと削除/挿入のサイクルは断片化を増やす。","action":"断片化が大きい場合は activedefrag の有効化または再起動を検討する。1 未満の場合はスワップを調査してメモリを追加する。アロケータ (jemalloc) の挙動とビッグキーのパターンを見直す。","tags":["metric","memory","fragmentation","swap"]},{"name":"instantaneous_ops_per_sec","kind":"metric","meaning":"Redis が現在 1 秒あたりに処理しているコマンド数 (瞬間スループット)。ワークロードの強さとトラフィックの急変を示す。","causes":"トラフィックの急増、バッチジョブの負荷、非効率なクライアントのアクセスパターン、個別コマンドの代わりにパイプラインを使っていない、激しい読み取り/書き込みのバースト。","action":"スループットをレイテンシや CPU と併せて監視する、急な低下/急増をトラフィックや低速コマンドと関連付ける、パイプライン/バッチ化で効率を改善する、キャパシティを計画する。","tags":["metric","throughput","ops","load"]},{"name":"rdb_last_bgsave_status","kind":"metric","meaning":"最後の RDB バックグラウンド保存 (BGSAVE) の成否。永続化スナップショットが正常に取得されたかを示す。","causes":"失敗 (err) の状態は、ディスク満杯/空き容量不足、fork に必要なメモリの不足、ディスク I/O エラー、権限の問題、または過負荷が原因となりうる。","action":"状態が 'err' の場合は、ディスク容量、fork に必要なメモリ (overcommit の設定)、ディスクの健全性を確認し、ログを確認する。失敗した BGSAVE はデータ損失のリスクを生むため、永続化の設定を見直す。","tags":["metric","persistence","rdb","bgsave"]},{"name":"master_link_status","kind":"metric","meaning":"レプリカからマスターへのレプリケーションリンクの状態 (up/down)。レプリカとマスター間の接続が健全かを示す。","causes":"'down' の状態は、ネットワーク障害、マスターへの到達不能、レプリケーション同期エラー、認証の問題、またはマスターの過負荷が原因となりうる。","action":"状態が 'down' の場合は、ネットワーク接続、マスターへの到達性、auth の設定を確認し、レプリカのログを確認し、master_repl_offset の遅延を監視し、同期が完了したことを確認する。","tags":["metric","replication","master-link","availability"]},{"name":"レイテンシ (slowlog)","kind":"metric","meaning":"slowlog とレイテンシ監視で検出される、設定したしきい値を超える低速コマンドのレイテンシ。シングルスレッドの Redis では、1 つのコマンドが他のコマンドをブロックするリスクを示す。","causes":"時間計算量の大きいコマンド (KEYS、大きな SORT、大きなコレクションへの SMEMBERS/HGETALL)、ビッグキー、低速な Lua スクリプト、fork/永続化による一時停止、スワップ。","action":"SLOWLOG と LATENCY コマンドで低速コマンドを特定する、O(N) コマンド (KEYS の代わりに SCAN) とビッグキーを排除する、スクリプトを最適化する、fork/AOF/RDB による一時停止を監視する。","tags":["metric","latency","slowlog","performance"]},{"name":"expired_keys","kind":"metric","meaning":"TTL が期限切れになったために削除されたキーの総数。TTL ベースの期限切れの挙動とメモリ回収の指標。","causes":"TTL を持つキーの期限切れは正常。急な変化は TTL ポリシーの変更、大量のキーの期限切れ、または想定外の削除パターンを示す可能性がある。","action":"expired と evicted を区別する (expired は健全な TTL の挙動、evicted はメモリの逼迫)、期限切れの急な波がキャッシュミスと負荷に与える影響を監視する、TTL の分布を分散させる。","tags":["metric","ttl","expiration","keyspace"]},{"name":"connected_clients vs maxclients","kind":"metric","meaning":"現在の接続クライアント数が設定された maxclients の上限にどれだけ近いか。接続容量が枯渇するリスクを示す。","causes":"接続リーク、誤設定されたコネクションプール、クライアントの急増、長時間保持されるアイドル接続、多数のマイクロサービス接続。","action":"接続クライアント数を maxclients と比較する。上限に近づいた場合は、コネクションプールを正しくサイジングする、接続リークを修正する、アイドル接続のタイムアウトを設定する、必要に応じて maxclients を増やす。","tags":["metric","connections","maxclients","capacity"]}]},"reference/waits-elasticsearch.json":{"engineId":"elasticsearch","engine":"Elasticsearch","order":7,"waits":[{"name":"JVM ヒープ使用率 %","kind":"metric","meaning":"ノードの JVM ヒープの使用率。高く継続的に満杯のヒープはメモリの逼迫と激しい GC のリスクを意味する。","causes":"過剰な fielddata/集計のメモリ、多すぎるシャード、激しい bulk/クエリ負荷、大きなマッピング、小さすぎるヒープ、メモリリークのパターン。","action":"ヒープ使用率を監視する (特に GC 後も 75% を超える場合は対処する)、シャード数を減らす、重い集計と fielddata の使用を制限する、ヒープは RAM の半分以下かつ 32GB 未満に保つ。","tags":["metric","jvm","heap","memory"]},{"name":"GC 時間/頻度","kind":"metric","meaning":"JVM ガベージコレクションの時間と頻度。長い/頻繁な GC の一時停止はノードを応答不能にし、性能を低下させる。","causes":"高いヒープの逼迫、旧世代 (old gen) の大きな蓄積、重い集計/fielddata、小さすぎるヒープ、多すぎるシャード、長時間実行の大きなクエリ。","action":"長い一時停止 (特に old GC) の根本原因であるヒープの逼迫を解消する、メモリを多く使うクエリを最適化する、シャード数を減らす。頻繁で長い GC はノードの不安定化の早期警告。","tags":["metric","jvm","gc","pause"]},{"name":"thread_pool write の拒否","kind":"metric","meaning":"write (インデックス作成/bulk) スレッドプールのキューが満杯だったために拒否されたインデックス作成要求の数。ノードが書き込み負荷を処理できていないことを示す。","causes":"過剰な bulk/インデックス作成レート、低速なディスク I/O、bulk ではなく多数の小さな要求、ノード容量の不足、refresh の負荷。","action":"インデックス作成要求は適切なサイズの bulk で送信する、書き込みレートをノード容量に合わせて抑える (バックオフ)、ディスク I/O を改善する、refresh_interval を増やす、キャパシティを拡張する。","tags":["metric","thread-pool","indexing","rejection"]},{"name":"thread_pool search の拒否","kind":"metric","meaning":"search スレッドプールのキューが満杯だったために拒否された検索要求の数。ノードがクエリ負荷を処理できていないことを示す。","causes":"過剰な同時クエリ、重い/低速な集計、多すぎるシャードへのアクセス、非効率なクエリ、ノード/CPU 容量の不足。","action":"クライアント側でクエリの同時実行数を制限する、重いクエリと集計を最適化する、不要なシャードへのファンアウトを減らす (ルーティング/フィルタリング)、ノードを追加しレプリカシャード数を増やす (検索はレプリカシャードでも処理される)、キャパシティを拡張する。","tags":["metric","thread-pool","search","rejection"]},{"name":"インデックス作成/検索レイテンシ","kind":"metric","meaning":"インデックス作成と検索操作の平均レイテンシ。index_time_in_millis と query_time_in_millis のメトリックから導出され、ユーザーが体感する応答時間を反映する。","causes":"低速なディスク I/O、重いクエリ/集計、GC の一時停止、多いシャード数、refresh/merge の負荷、リソース不足。","action":"slow log で低速なクエリを特定して最適化する、インデックス作成のために bulk と refresh_interval を調整する、ディスクとヒープの性能を改善する、レイテンシをスレッドプールの拒否や GC と併せて解釈する。","tags":["metric","latency","indexing","search"]},{"name":"refresh/flush 時間","kind":"metric","meaning":"新しいドキュメントを検索可能にする refresh と、translog を Lucene に永続化する flush に費やされた時間。インデックス作成のオーバーヘッドを示す。","causes":"頻繁すぎる refresh (低い refresh_interval)、低速なディスク I/O、激しいインデックス作成、大きな translog、多数の小さなセグメント。","action":"激しいインデックス作成中は refresh_interval を増やす (例: 30s) か一時的に無効にする、ディスク I/O を改善する、bulk サイズを調整する、セグメントのマージの挙動を見直す。","tags":["metric","refresh","flush","indexing"]},{"name":"未割り当てシャード","kind":"metric","meaning":"どのノードにも割り当てられていないシャードの数。未割り当てのプライマリはデータにアクセスできないこと (red ヘルス) を、未割り当てのレプリカは耐久性/容量のリスクを意味する。","causes":"ノードの障害/離脱、ディスク watermark の超過、ノード数に対して大きすぎるレプリカ設定、割り当てルール/フィルタ、シャードのリカバリ中の遅延。","action":"cluster allocation explain API で原因を特定する、障害ノードを復旧する、ディスク容量/watermark の問題を修正する、レプリカ数と割り当てルールを見直す。red 状態を優先して対処する。","tags":["metric","shards","allocation","cluster-health"]},{"name":"ディスク watermark %","kind":"metric","meaning":"Elasticsearch のシャード配置に影響する low/high/flood-stage のしきい値 (デフォルト 85%/90%/95%) に対するノードのディスク使用率。","causes":"ディスクの逼迫、データの増加、ストレージ不足、不均衡なシャード分散、古いインデックスが削除されていない。","action":"low watermark では新しいシャードがノードに割り当てられなくなり、high watermark ではシャードが他のノードに再配置され、flood-stage ではインデックスが読み取り専用になる。ディスク領域を空ける (古いインデックスの削除/ILM の使用)、ストレージを拡張する、シャード分散を平準化する、watermark のしきい値を監視する。","tags":["metric","disk","watermark","storage"]},{"name":"fielddata/query キャッシュの eviction","kind":"metric","meaning":"メモリの上限により fielddata キャッシュと query (filter) キャッシュから削除されたエントリの数。キャッシュの非効率さとメモリの逼迫を示す。","causes":"多い fielddata の使用 (text フィールドでのソート/集計)、小さいキャッシュ上限、多様なクエリフィルタ、メモリの逼迫、再利用されないフィルタ。","action":"text フィールドでは fielddata ではなく keyword/doc_values を使用する、重い fielddata の集計を制限する、キャッシュサイズを見直す。頻繁な eviction はヒープの逼迫と併せて評価する。","tags":["metric","cache","fielddata","eviction"]},{"name":"サーキットブレーカーの発動","kind":"metric","meaning":"サーキットブレーカー (parent/fielddata/request ブレーカー) が要求がメモリを超えると予測して拒否した回数。ノードを OOM から守る安全機構。","causes":"過剰なメモリを要求する集計/クエリ、多い fielddata の使用、大きな bulk 要求、全般的なヒープの逼迫、非常に大きな結果セット。","action":"サーキットブレーカーの発動はヒープの逼迫の兆候として扱う、メモリを多く使うクエリを最適化する、fielddata/集計の使用を減らす、bulk サイズを小さくする、ヒープとシャード数を見直す。","tags":["metric","circuit-breaker","memory","oom"]},{"name":"保留中のタスク (pending tasks)","kind":"metric","meaning":"マスターノードによる処理を待っているクラスタ状態更新タスクのキュー。マスターがクラスタ管理の負荷に追いつけていないことを示す。","causes":"多数のインデックス/シャード、頻繁なマッピング/設定の変更、マスターノードのリソース不足、大きなクラスタ状態、ネットワーク/マスター選出の問題。","action":"キューが継続的に満杯の場合は、シャード/インデックスの数を減らす、頻繁な動的マッピング更新を制限する、専用のマスターノードを分離する、クラスタ状態のサイズとマスターのリソースを見直す。","tags":["metric","master","cluster-state","queue"]}]},"reference/alerts-oracle.json":{"engineId":"oracle","engine":"Oracle Database","order":1,"alerts":[{"metric":"バッファキャッシュヒット率","warn":"< 95%","crit":"< 90%","tool":"V$SYSSTAT / V$BUFFER_POOL_STATISTICS","note":"バッファキャッシュヒット率は、データブロックのうちディスクに行かずにメモリから読み込まれた割合を示す。低い値は物理読み取りの増加と SGA の不足を示す。単独では誤解を招くことがあるため、常に AWR レポートの物理読み取りと併せて評価する。","tags":["memory","cache","sga"]},{"metric":"表領域使用率 (%used)","warn":"> 85%","crit":"> 95%","tool":"DBA_TABLESPACE_USAGE_METRICS","note":"表領域の使用率が 100% に達すると新しいエクステントを割り当てられず、ORA-01653 などのエラーで操作が停止する。autoextend が有効でもディスクの上限に注意する。DBA_TABLESPACE_USAGE_METRICS ビューは自動拡張ファイルと固定サイズファイルの両方について正しい割合を示す。","tags":["disk","tablespace","capacity"]},{"metric":"PGA メモリ使用量","warn":"> 90% pga_aggregate_target","crit":"> 100% (オーバーアロケーション)","tool":"V$PGASTAT / V$PGA_TARGET_ADVICE","note":"PGA の目標値を超えると、ソートとハッシュの操作がディスク (temp) にあふれ、クエリが遅くなる。over allocation count が継続的に増加している場合は目標値が不足している。サーバーメモリに照らして pga_aggregate_target の設定を見直す。","tags":["memory","pga","temp"]},{"metric":"TEMP 表領域の使用量","warn":"> 80%","crit":"> 95%","tool":"V$TEMPSEG_USAGE / V$SORT_SEGMENT / DBA_TEMP_FREE_SPACE","note":"TEMP 領域は大規模なソート、ハッシュ結合、グローバル一時表の操作に使用される。満杯になると ORA-01652 が発生し、クエリが失敗する。急な逼迫は通常、悪いプランのクエリ 1 つ、または過大なデータをソートするクエリが原因。","tags":["temp","disk","sort"]},{"metric":"平均アクティブセッション数 (AAS)","warn":"> CPU コア数","crit":"> CPU コア数の 2 倍","tool":"V$ACTIVE_SESSION_HISTORY / OEM","note":"平均アクティブセッション数はデータベースの現在の負荷を 1 つの数値に要約する。値が CPU コア数を超える場合、セッションは CPU または待機イベントで待ち行列になっている。コア数の倍数で推移する場合はボトルネック分析が必要。","tags":["cpu","load","session"]},{"metric":"Data Guard の適用遅延","warn":"> 60 s","crit":"> 300 s","tool":"V$DATAGUARD_STATS (適用遅延)","note":"適用遅延 (apply lag) は、スタンバイデータベースがプライマリからどれだけ遅れているかを示す。適用遅延が大きいとフェイルオーバー時に適用する redo の量が増え、リカバリ時間 (RTO) が長くなる。redo がスタンバイに到達していればデータは失われない。潜在的なデータ損失 (RPO) は転送遅延 (transport lag) で決まる。転送遅延と併せて確認し、ネットワークと redo 適用のどちらが遅いかを判断する。","tags":["replication","dataguard","lag"]},{"metric":"高速リカバリ領域 (FRA) の使用量","warn":"> 85%","crit":"> 95%","tool":"V$RECOVERY_FILE_DEST / V$RECOVERY_AREA_USAGE","note":"FRA が満杯になるとアーカイブログの生成が停止し、データベース全体がハングする。本番システムで最もよくある停止原因の 1 つ。RMAN の削除ポリシーと db_recovery_file_dest_size の値を定期的に確認する。","tags":["disk","fra","archivelog"]},{"metric":"ブロッキングセッション数","warn":">= 1 (> 30 s)","crit":">= 1 (> 120 s)","tool":"V$LOCK / V$SESSION (blocking_session)","note":"あるセッションが保持するロックによって他のセッションが待たされると、アプリケーション全体に連鎖的な遅延が発生する。長時間続くブロッキングは通常、未コミットのトランザクションまたはアプリケーションのバグが原因。ブロッキングチェーンの根元のセッションを特定し、必要に応じて終了させる。","tags":["lock","blocking","concurrency"]},{"metric":"無効なオブジェクト数","warn":"> 0","crit":"> 50","tool":"DBA_OBJECTS (status='INVALID')","note":"無効なパッケージ、ビュー、トリガーは実行時に予期しないエラーを引き起こす可能性がある。通常は DDL の変更後に発生する。UTL_RECOMP.RECOMP_PARALLEL または utlrp.sql で再コンパイルして解消し、無効のままのオブジェクトは根本原因を調査する。","tags":["object","compile","maintenance"]},{"metric":"最長実行クエリ","warn":"> 5 分","crit":"> 30 分","tool":"V$SQL / V$SESSION_LONGOPS","note":"長時間実行のクエリ 1 つがリソースを独占し、他の操作も遅くすることがある。バッチジョブを除き、OLTP システムで数分間実行されるクエリは通常、インデックスの欠落または悪いプランが原因。SQL Monitor レポートでプランと実際の行数を調べる。","tags":["query","performance","sql"]},{"metric":"アラートログの ORA エラー","warn":">= 1 (非重大)","crit":"ORA-00600 / ORA-07445 / ORA-04031","tool":"アラートログ / V$DIAG_ALERT_EXT","note":"アラートログはデータベースの健全性の記録。ORA-00600 と ORA-07445 はデータ破損を示す可能性のある内部エラーで、ORA-04031 は共有プールのメモリ枯渇を示す。これらのエラーが出た場合は直ちに調査し、必要に応じて Oracle Support に共有する。","tags":["error","alertlog","monitoring"]},{"metric":"redo ログスイッチの頻度","warn":"> 6 / 時間","crit":"> 12 / 時間","tool":"V$LOG_HISTORY","note":"非常に頻繁な redo ログスイッチは、ログファイルのサイズ不足とチェックポイントの負荷を示す。ピーク時でも 15-20 分ごとのスイッチが理想。過度に頻繁なスイッチは IO とアーカイブの負荷を増やすため、redo ロググループの拡大を検討する。","tags":["redo","io","checkpoint"]},{"metric":"最後に成功した RMAN バックアップからの経過時間","warn":"> 24 時間","crit":"> 48 時間","tool":"V$RMAN_BACKUP_JOB_DETAILS","note":"バックアップの経過時間は復旧できる最新の時点を決め、データ損失のリスクを直接反映する。失敗またはスキップされたバックアップに気付かないと、障害時に戻る手段がない。ポイントインタイムリカバリを保証するため、アーカイブログのバックアップも別途監視する。","tags":["backup","rman","recovery"]},{"metric":"ディスク IO レイテンシ (db file sequential read)","warn":"> 10 ms","crit":"> 20 ms","tool":"V$SYSTEM_EVENT / AWR","note":"シングルブロック読み取りの平均待機時間はストレージ層の性能を示す。最新のフラッシュ/SSD システムではこの値は数ミリ秒であるべき。継続的に高いレイテンシはストレージのボトルネックまたは過剰な物理読み取りを示すため、SGA とストレージ層を併せて評価する。","tags":["io","disk","latency"]}]},"reference/alerts-postgres.json":{"engineId":"postgres","engine":"PostgreSQL","order":2,"alerts":[{"metric":"キャッシュヒット率","warn":"< 99%","crit":"< 95%","tool":"pg_stat_database / postgres_exporter","note":"キャッシュヒット率は shared_buffers だけで提供されたブロックの割合。OS のキャッシュで提供された読み取りも blks_read として数えられるため、この比率は実際のディスク読み取りを実態より悪く見せることがある。健全な PostgreSQL の OLTP システムではこの比率は 99% を超えるべき。低い値はメモリ不足またはコールドキャッシュを示す。blks_hit と blks_read から算出する。","tags":["memory","cache"]},{"metric":"接続数 (connections vs max_connections)","warn":"> 80%","crit":"> 90%","tool":"pg_stat_activity / max_connections","note":"アクティブな接続が max_connections の上限に近づくと、新規接続が失敗する。各接続はメモリを消費するため、接続数が多いとメモリの逼迫も生じる。PgBouncer などのコネクションプーラーでバックエンド数を低く保つことが推奨される。","tags":["connection","limit","pool"]},{"metric":"レプリケーション遅延","warn":"> 10 MB","crit":"> 100 MB","tool":"pg_stat_replication (replay_lag / lsn diff)","note":"レプリケーション遅延は、スタンバイがプライマリから遅れている WAL の量 (バイト)。遅延が大きいと読み取りレプリカのデータが古くなり、フェイルオーバー時にデータ損失のリスクがある。バイト単位の LSN の差を replay_lag の時間と併せて監視する。","tags":["replication","lag","standby"]},{"metric":"最も古いトランザクションの経過時間","warn":"> 5 分","crit":"> 30 分","tool":"pg_stat_activity (xact_start)","note":"長時間オープンしたままのトランザクションは VACUUM によるデッドタプルの除去を妨げ、表の肥大化を招く。'idle in transaction' 状態のセッションも不必要にロックを保持する。そのようなセッションを特定し、idle_in_transaction_session_timeout で制限する。","tags":["query","vacuum","transaction"]},{"metric":"デッドロック","warn":"> 1 / 分","crit":"> 5 / 分","tool":"pg_stat_database (deadlocks)","note":"デッドロックは 2 つのトランザクションが互いのロックを待つときに発生し、PostgreSQL は一方をキャンセルして解消する。たまのデッドロックは起こりうるが、頻繁な場合はアプリケーションのロック順序が一貫していないことを示す。log_lock_waits を有効にして、どのクエリが競合しているかを確認する。","tags":["lock","deadlock","concurrency"]},{"metric":"一時ファイルの使用量","warn":"> 1 GB / 時間","crit":"> 10 GB / 時間","tool":"pg_stat_database (temp_bytes)","note":"一時ファイルは work_mem に収まらないソートとハッシュの操作がディスクにあふれたときに作成される。一時ファイルの使用量が多いと、遅延とディスクの逼迫の両方を引き起こす。頻繁にあふれるクエリについては work_mem の増加またはクエリの最適化を検討する。","tags":["temp","disk","work_mem"]},{"metric":"autovacuum の遅れ (デッドタプル)","warn":"> 10% デッドタプル","crit":"> 20% デッドタプル","tool":"pg_stat_user_tables (n_dead_tup)","note":"デッドタプルの割合の上昇は、autovacuum が追いつけず表の肥大化が進んでいることを示す。肥大化した表は領域を占有し、スキャンも遅くする。更新の多い表では autovacuum_vacuum_scale_factor を下げてクリーンアップをより頻繁に実行させる。","tags":["vacuum","bloat","maintenance"]},{"metric":"ディスク使用量 (データディレクトリ)","warn":"> 85%","crit":"> 95%","tool":"df / node_exporter","note":"PostgreSQL にはディスクが満杯になる前の自己防衛機構がない。データディスクが満杯になると書き込みは 'could not extend file' / 53100 で失敗し、WAL (pg_wal) のディスクが満杯になるとサーバーは PANIC で停止する。WAL と一時ファイルは急激な増加の原因となりうるため、早期の対処が重要。","tags":["disk","capacity"]},{"metric":"WAL の保持 (レプリケーションスロットの遅延)","warn":"> 1 GB","crit":"> 10 GB","tool":"pg_replication_slots (restart_lsn)","note":"未使用または遅延しているレプリケーションスロットは WAL ファイルの削除を妨げ、pg_wal ディレクトリを肥大化させる。最終的にディスク満杯に至ることがある。使われていないスロットを特定して削除し、max_slot_wal_keep_size で上限を設定する。","tags":["wal","slot","disk"]},{"metric":"チェックポイントの頻度 (要求によるチェックポイント)","warn":"> 10% requested の割合","crit":"> 30% requested の割合","tool":"PG16 以前: pg_stat_bgwriter (checkpoints_req) / PG17+: pg_stat_checkpointer (num_requested)","note":"時間指定のチェックポイントに対する要求によるチェックポイントの割合が上昇する場合は、max_wal_size が小さすぎる。頻繁なチェックポイントは IO のスパイクと性能低下を引き起こす。負荷を分散させるため max_wal_size と checkpoint_completion_target の設定を見直す。","tags":["checkpoint","wal","io"]},{"metric":"最後に成功したバックアップからの経過時間","warn":"> 24 時間","crit":"> 48 時間","tool":"pgBackRest / barman info","note":"バックアップの経過時間は戻れる最新の時点を決め、RPO を直接表す。ポイントインタイムリカバリには途切れのないバックアップチェーンと WAL アーカイブが必要。バックアップは取得するだけでなく、定期的なリストアテストで有効性を検証する必要がある。","tags":["backup","recovery","rpo"]},{"metric":"ディスク IO レイテンシ","warn":"> 10 ms","crit":"> 20 ms","tool":"node_exporter / iostat","note":"ストレージの読み取り/書き込みレイテンシはクエリ時間に直接影響する。最新の SSD システムではこの値は数ミリ秒であるべき。継続的に高いレイテンシはディスクのボトルネックまたは過剰な物理読み取りを示すため、shared_buffers とストレージ層を併せて評価する。","tags":["io","disk","latency"]},{"metric":"トランザクション ID の周回 (age)","warn":"> 10 億","crit":"> 15 億","tool":"pg_database (age(datfrozenxid))","note":"トランザクション ID の age が 20 億に近づくと、PostgreSQL はデータ損失を防ぐためにすべての書き込みを停止する (周回防止)。これは PostgreSQL で最も危険な障害の 1 つ。datfrozenxid の age を監視し、autovacuum の凍結 (freeze) 処理が遅れていないことを確認する。","tags":["wraparound","vacuum","critical"]}]},"reference/alerts-mysql.json":{"engineId":"mysql","engine":"MySQL","order":3,"alerts":[{"metric":"InnoDB バッファプールのヒット率","warn":"< 99%","crit":"< 95%","tool":"SHOW ENGINE INNODB STATUS / mysqld_exporter","note":"バッファプールヒット率は、データページとインデックスページのうちディスクに行かずにメモリから読み込まれた割合。低い値は innodb_buffer_pool_size がワーキングセットに対して小さすぎることを示す。専用サーバーでは通常、メモリの約 70-80% をバッファプールに割り当てる (共有サーバーではより少なく)。","tags":["memory","cache","innodb"]},{"metric":"接続数 (Threads_connected vs max_connections)","warn":"> 80%","crit":"> 90%","tool":"SHOW STATUS / max_connections","note":"接続数が max_connections の上限に近づくと、新規接続は 'Too many connections' で拒否される。Max_used_connections は過去のピークを示す。アプリケーション側のコネクションプールで同時接続数を制御する。","tags":["connections","limit","thread"]},{"metric":"レプリカ遅延 (Seconds_Behind_Source)","warn":"> 30 s","crit":"> 300 s","tool":"SHOW REPLICA STATUS","note":"Seconds_Behind_Source はレプリカがソースからどれだけ遅れているかを秒で示す。遅延が大きいと読み取りレプリカのデータが古くなり、フェイルオーバーのリスクがある。シングルスレッドの適用では大きなトランザクションの間に値が誤解を招くことがあるため、GTID の差と併せて確認する。","tags":["replication","lag","replica"]},{"metric":"InnoDB 行ロック待機時間","warn":"平均 > 1 s","crit":"平均 > 5 s","tool":"SHOW STATUS (Innodb_row_lock_time_avg)","note":"平均行ロック待機時間は、トランザクションが互いをどれだけ待たせているかを示す。高い値は競合の激しい更新または長時間実行のトランザクションを示す。Innodb_row_lock_waits と併せて確認し、performance_schema で競合しているクエリを特定する。","tags":["lock","blocking","innodb"]},{"metric":"History list length (undo)","warn":"> 100000","crit":"> 1000000","tool":"SHOW ENGINE INNODB STATUS","note":"history list length はパージされていない undo レコードの数で、長時間オープンしたままのトランザクションによって増加する。高い値はパージが遅れていること、および MVCC により読み取り性能が低下していることを示す。長時間実行のトランザクションを特定して終了させ、リストが縮小できるようにする。","tags":["undo","transaction","mvcc"]},{"metric":"失敗した接続 (Aborted_connects)","warn":"> 5 / 分","crit":"> 20 / 分","tool":"SHOW STATUS (Aborted_connects)","note":"Aborted_connects は認証またはハンドシェイク中に失敗した接続を数える。急増は誤ったパスワード、ネットワークの問題、または攻撃の試みを示す可能性がある。Aborted_clients と併せて確認し、どこで接続が切れているかを判断する。","tags":["connections","error","security"]},{"metric":"ディスクに書き込まれた一時テーブル","warn":"> 25% の割合","crit":"> 50% の割合","tool":"SHOW STATUS (Created_tmp_disk_tables)","note":"インメモリ一時テーブルがディスクにあふれる割合は、クエリが tmp_table_size の上限を超えていることを示す。ディスク上の一時テーブルはクエリを顕著に遅くする。GROUP BY や BLOB/TEXT 列を含むクエリを最適化し、tmp_table_size と max_heap_table_size の増加を検討する。","tags":["temp","disk","query"]},{"metric":"低速クエリ","warn":"> 5 / 分","crit":"> 20 / 分","tool":"スロークエリログ / Slow_queries ステータス","note":"long_query_time のしきい値を超えたクエリはスロークエリログに書き込まれ、性能問題の主な発生源となる。頻繁な低速クエリはインデックスの欠落または書き方の悪いクエリを示す。pt-query-digest でログを分析し、最もコストの高いクエリを優先する。","tags":["query","performance","slowlog"]},{"metric":"CPU 使用率","warn":"> 80%","crit":"> 90%","tool":"node_exporter / top","note":"継続的に高い CPU 使用率は、重いクエリ、インデックスの欠落、または多すぎる接続が原因となりうる。短時間のピークは正常だが、継続的な飽和はクエリの待ち行列を引き起こす。performance_schema またはスロークエリログで CPU を最も消費するクエリを特定する。","tags":["cpu","load"]},{"metric":"ディスク使用量 (データディレクトリ)","warn":"> 85%","crit":"> 95%","tool":"df / node_exporter","note":"データディレクトリが満杯になると MySQL は書き込めなくなり、表のエラーが発生する。binlog ファイル、undo 表領域、一時表領域 (ibtmp1) の増加は急にディスクを満杯にすることがある。redo ログは固定サイズ (8.0.30+ では #innodb_redo、innodb_redo_log_capacity)。古い binlog が binlog_expire_logs_seconds によってパージされていることを確認する。","tags":["disk","capacity","binlog"]},{"metric":"最長実行クエリ","warn":"> 60 s","crit":"> 300 s","tool":"SHOW PROCESSLIST / information_schema.PROCESSLIST","note":"長時間実行のクエリ 1 つが、ロックの保持とリソースの消費によって他のトランザクションに影響することがある。OLTP システムで数分間実行されるクエリは通常、悪いプランが原因。EXPLAIN でプランを調べ、必要に応じてクエリを kill して最適化する。","tags":["query","performance"]},{"metric":"最後に成功したバックアップからの経過時間","warn":"> 24 時間","crit":"> 48 時間","tool":"xtrabackup / mysqldump のジョブログ","note":"バックアップの経過時間は戻れる最新の時点、つまり RPO を決める。binlog のバックアップと組み合わせるとポイントインタイムリカバリが可能になる。バックアップを取得するだけでは不十分で、定期的なリストアテストで有効性を検証する。","tags":["backup","recovery","rpo"]},{"metric":"ディスク IO レイテンシ","warn":"> 10 ms","crit":"> 20 ms","tool":"iostat / node_exporter","note":"ストレージのレイテンシはクエリ時間に直結し、特にバッファプールに収まらないワークロードで重要。最新の SSD システムでは数ミリ秒が想定される。高いレイテンシはディスクのボトルネックまたは過剰な物理読み取りを示すため、バッファプールのサイズも見直す。","tags":["io","disk","latency"]}]},"reference/alerts-mssql.json":{"engineId":"mssql","engine":"SQL Server","order":4,"alerts":[{"metric":"Page Life Expectancy (PLE)","warn":"< 900 s","crit":"< 300 s","tool":"sys.dm_os_performance_counters","note":"Page Life Expectancy は、データページがバッファプールから追い出されるまでメモリに留まれる推定時間を秒で示す。低い値はメモリの逼迫と、ページがキャッシュから素早く追い出されていることを示す。NUMA ノードごとに個別に監視し、急な低下はメモリ不足として扱う。","tags":["memory","cache","ple"]},{"metric":"バッファキャッシュヒット率","warn":"< 98%","crit":"< 95%","tool":"sys.dm_os_performance_counters","note":"バッファキャッシュヒット率は、ページのうちディスクに行かずにメモリから読み込まれた割合。SQL Server ではこの値は通常非常に高いため、PLE と併せて評価する。単独では誤解を招くことがあるため、メモリのボトルネックを分析する際は PLE を主要なメトリックとして使用する。","tags":["memory","cache"]},{"metric":"ブロックされたプロセス","warn":">= 1 (> 5 s)","crit":">= 1 (> 30 s)","tool":"sys.dm_exec_requests (blocking_session_id)","note":"あるセッションが保持するロックによって他のセッションが待たされると、ブロッキングチェーンが形成され、アプリケーション全体が遅くなる。長時間続くブロッキングは通常、未コミットのトランザクションまたは不適切な分離レベルが原因。blocked process report で先頭のブロッカー (head blocker) を特定する。","tags":["lock","blocking","concurrency"]},{"metric":"トランザクションログ使用率 (%used)","warn":"> 75%","crit":"> 90%","tool":"sys.dm_db_log_space_usage / DBCC SQLPERF(LOGSPACE)","note":"トランザクションログが満杯になるとデータベースは書き込めなくなり、エラー 9002 で停止する。FULL 復旧モデルでは、ログバックアップを取得しないとログは増え続ける。ログバックアップの頻度と VLF 数を監視し、ログが切り捨てられ再利用されていることを確認する。","tags":["log","disk","recovery"]},{"metric":"tempdb 使用率 (%used)","warn":"> 80%","crit":"> 95%","tool":"sys.dm_db_file_space_usage","note":"tempdb は一時テーブル、ソート、バージョンストア、ハッシュ操作で共有される。満杯になるとサーバー全体のクエリが失敗する。急な増加は通常、大きなクエリまたは長時間実行のスナップショットトランザクションが原因。バージョンストアのサイズは別途監視する。","tags":["tempdb","disk","sort"]},{"metric":"最長実行クエリ","warn":"> 60 s","crit":"> 300 s","tool":"sys.dm_exec_requests / Query Store","note":"長時間実行のクエリ 1 つが、ロックの保持とリソースの消費によって他の処理に影響することがある。OLTP システムで数分間実行されるクエリは通常、インデックスの欠落、パラメータスニッフィング、または悪いプランが原因。Query Store でプランの後退 (regression) を調査する。","tags":["query","performance"]},{"metric":"Availability Group の redo キュー","warn":"> 1 MB","crit":"> 100 MB","tool":"sys.dm_hadr_database_replica_states","note":"redo キューは、セカンダリレプリカでまだ適用を待っているログの量を示す。redo キューが大きいとフェイルオーバー後のリカバリ時間 (RTO) が長くなり、読み取り可能レプリカのデータが古くなる。redo_rate と併せて調べ、遅延がいつ解消するかを予測する。","tags":["replication","ag","lag"]},{"metric":"デッドロックの発生率","warn":"> 1 / 分","crit":"> 5 / 分","tool":"system_health XEvent / パフォーマンスカウンター","note":"デッドロックは 2 つのトランザクションが互いのロックを待つときに発生し、SQL Server は一方を victim として選んで解消する。たまのデッドロックは起こりうるが、頻繁な場合はロック順序が一貫していないことを示す。system_health 拡張イベントセッションからデッドロックグラフを取り出し、競合しているクエリを修正する。","tags":["lock","deadlock","concurrency"]},{"metric":"ワーカースレッドの使用率","warn":"> 80%","crit":"> 90%","tool":"sys.dm_os_schedulers / max worker threads","note":"ワーカースレッドプールが枯渇すると、新しい要求は THREADPOOL 待機でキューに入り、サーバーが応答しなくなることがある。通常は長時間のブロッキングまたは過剰な同時接続が原因。ブロッキングチェーンを解消してスレッドの逼迫を減らす。","tags":["cpu","thread","load"]},{"metric":"CPU 使用率","warn":"> 80%","crit":"> 90%","tool":"sys.dm_os_ring_buffers / Performance Monitor","note":"継続的に高い CPU は、重いクエリ、インデックスの欠落、または悪いプランが原因となりうる。短時間のピークは正常だが、継続的な飽和はクエリの待ち行列を引き起こす。sys.dm_exec_query_stats で CPU を最も消費するクエリを特定する。","tags":["cpu","load"]},{"metric":"最後に成功したバックアップからの経過時間","warn":"> 24 時間 (フル)","crit":"> 48 時間 (フル)","tool":"msdb.dbo.backupset","note":"バックアップの経過時間は戻れる最新の時点と RPO を決める。FULL 復旧モデルではログバックアップによりポイントインタイムリカバリが可能。復旧可能性を保証するためにフル、差分、ログのバックアップチェーンを監視し、定期的にリストアテストを実施する。","tags":["backup","recovery","rpo"]},{"metric":"ディスク IO レイテンシ (平均読み取り/書き込み)","warn":"> 15 ms","crit":"> 30 ms","tool":"sys.dm_io_virtual_file_stats","note":"ファイルごとの平均読み取り/書き込みレイテンシはストレージの性能を示す。データファイルでは 15 ms 程度、ログファイルではそれより低い値が想定される。継続的に高いレイテンシはストレージのボトルネックを示す。sys.dm_io_virtual_file_stats で最も遅いファイルを特定する。","tags":["io","disk","latency"]}]},"reference/alerts-mongodb.json":{"engineId":"mongodb","engine":"MongoDB","order":5,"alerts":[{"metric":"WiredTiger キャッシュのダーティ率","warn":"> 5%","crit":"> 20%","tool":"db.serverStatus().wiredTiger.cache","note":"ダーティキャッシュ率は、WiredTiger キャッシュ内でまだディスクに書き込まれていない変更済みページの割合。20% を超えると eviction の逼迫と書き込みのボトルネックを意味し、MongoDB はアプリケーションスレッドに eviction を強制する。キャッシュサイズとディスクの書き込みスループットを併せて評価する。","tags":["memory","cache","wiredtiger"]},{"metric":"WiredTiger キャッシュ使用率 (used %)","warn":"> 80%","crit":"> 95%","tool":"db.serverStatus().wiredTiger.cache","note":"キャッシュ使用率が 80% の eviction 目標を超えると、WiredTiger はページを積極的に追い出し始め、性能が低下する。ワーキングセットがキャッシュに収まらない場合、物理読み取りが増加する。wiredTigerCacheSizeGB の設定とサーバーメモリを見直す。","tags":["memory","cache","wiredtiger"]},{"metric":"利用可能なチケット (read/write tickets)","warn":"available/totalTickets < 20% または queueLength > 0 (継続)","crit":"available = 0 かつ queueLength が増え続ける","tool":"db.serverStatus().wiredTiger.concurrentTransactions","note":"WiredTiger はチケット方式で同時の読み取り/書き込み操作を制限する。7.0 より前のデフォルトは固定の 128 チケット。7.0+ ではチケット数が動的に調整される (storageEngineConcurrencyAdjustmentAlgorithm: throughputProbing) ため、絶対数ではなく available/totalTickets の比率と queueLength を監視する。チケットが枯渇して操作がキューに入るのは深刻なボトルネックの兆候であり、通常は低速なクエリまたはディスク I/O の飽和が原因。","tags":["concurrency","ticket","bottleneck"]},{"metric":"レプリケーション遅延","warn":"> 10 s","crit":"> 60 s","tool":"rs.printSecondaryReplicationInfo()","note":"レプリケーション遅延は、セカンダリメンバーがプライマリからどれだけ遅れているかを秒で示す。遅延が大きいと、read preference によっては古いデータが返され、フェイルオーバー時にデータ損失のリスクがある。通常はセカンダリのディスク I/O またはネットワークのボトルネック、あるいは長時間実行の操作が原因。","tags":["replication","lag","replicaset"]},{"metric":"接続の使用率 (connections %)","warn":"> 80%","crit":"> 90%","tool":"db.serverStatus().connections","note":"アクティブな接続が設定された上限に近づくと、新規接続が拒否される。各接続はメモリとスレッドを消費するため、接続数が多いとリソースの逼迫も生じる。アプリケーション側でコネクションプールを正しくサイジングし、接続ストームを防ぐ。","tags":["connection","limit","pool"]},{"metric":"ページフォールト率","warn":"> 100 / s","crit":"> 1000 / s","tool":"db.serverStatus() / extra_info page_faults","note":"ページフォールトは、データがメモリになくディスクから取得しなければならないときに発生する。フォールト率が高いと、ワーキングセットがメモリに収まらず、システムがディスクバウンドで動作していることを示す。継続的に高い値にはメモリの増設またはクエリ/インデックスの最適化が必要。","tags":["memory","disk","pagefault"]},{"metric":"キュー内の操作","warn":"> 10","crit":"> 50","tool":"db.serverStatus().globalLock.currentQueue","note":"globalLock の currentQueue は、ロックまたはリソースを待ってキューに入っている読み取り/書き込みの数を示す。キューが継続的に満杯の場合、サーバーが流入する負荷に追いつけていないことを示す。チケットの枯渇やディスク I/O と併せて調べ、ボトルネックの発生源を特定する。","tags":["concurrency","queue","lock"]},{"metric":"oplog ウィンドウ","warn":"< 24 時間","crit":"< 6 時間","tool":"rs.printReplicationInfo()","note":"oplog ウィンドウは oplog がカバーする時間幅で、セカンダリが切断されたままでも再同期できる期間を決める。ウィンドウが狭まると、遅れたメンバーはフル再同期が必要になる。書き込み負荷が増えるとウィンドウは短くなるため、それに合わせて oplog サイズを拡大する。","tags":["oplog","replication","recovery"]},{"metric":"最長実行クエリ","warn":"> 30 s","crit":"> 120 s","tool":"db.currentOp() / スロークエリログ","note":"長時間実行のクエリはリソースの消費とロックの保持によって他の操作に影響する。通常はインデックスの欠落によるコレクションスキャン (COLLSCAN) を行うクエリが原因。プロファイラと currentOp で低速な操作を特定し、適切なインデックスを追加する。","tags":["query","performance","index"]},{"metric":"CPU 使用率","warn":"> 80%","crit":"> 90%","tool":"node_exporter / mongostat","note":"継続的に高い CPU は、インデックスのないクエリ、重い集計操作、または過剰な接続が原因となりうる。短時間のピークは正常だが、継続的な飽和は操作の待ち行列を引き起こす。プロファイラで CPU を最も消費するクエリを特定して最適化する。","tags":["cpu","load"]},{"metric":"ディスク使用量 (dbPath)","warn":"> 85%","crit":"> 95%","tool":"df / node_exporter","note":"データディレクトリが満杯になると MongoDB は書き込めなくなり、破損につながる可能性がある。WiredTiger の圧縮は役立つが、ジャーナルと増大するコレクションによってディスクが急速に埋まることがある。キャパシティプランニングを行い、TTL インデックスで不要なデータを自動的に削除する。","tags":["disk","capacity"]},{"metric":"最後に成功したバックアップからの経過時間","warn":"> 24 時間","crit":"> 48 時間","tool":"mongodump / Ops Manager / スナップショットの記録","note":"バックアップの経過時間は戻れる最新の時点と RPO を決める。oplog と組み合わせるとポイントインタイムリカバリが可能になる。バックアップを取得するだけでは不十分で、定期的なリストアテストで検証し、シャードクラスタでは一貫性のあるスナップショットが取得されていることを確認する。","tags":["backup","recovery","rpo"]}]},"reference/alerts-redis.json":{"engineId":"redis","engine":"Redis","order":6,"alerts":[{"metric":"メモリ使用量 (used_memory vs maxmemory)","warn":"> 80%","crit":"> 95%","tool":"INFO memory / redis_exporter","note":"used_memory と maxmemory の比率は、Redis のメモリのうちどれだけが使用中かを示す。上限に達すると、maxmemory-policy に従ってキーが削除 (eviction) されるか、書き込みが拒否される。メモリの増加を追跡し、予期しない OOM と eviction の波を防ぐ。","tags":["memory","maxmemory","capacity"]},{"metric":"Keyspace ヒット率","warn":"< 90%","crit":"< 80%","tool":"INFO stats (keyspace_hits/misses)","note":"ヒット率は要求されたキーのうちキャッシュ内で見つかった割合で、keyspace_hits と keyspace_misses から算出する。低い比率はキャッシュの非効率な使用、誤った TTL、またはコールドキャッシュを示す。キャッシュ用途のワークロードではこの比率はできるだけ高くあるべき。","tags":["cache","hit","performance"]},{"metric":"eviction されたキー(evicted_keys)","warn":"> 1 / s","crit":"> 100 / s","tool":"INFO stats (evicted_keys)","note":"evicted_keys は、メモリが満杯のために maxmemory-policy に基づいて削除されたキーの数。継続的な eviction はメモリが不足しており、重要なデータが失われる可能性があることを示す。メモリの増設、または TTL 戦略やデータモデルの見直しで eviction を減らす。","tags":["memory","eviction","maxmemory"]},{"metric":"ブロックされたクライアント (blocked_clients)","warn":"> 50","crit":"> 200","tool":"INFO clients (blocked_clients)","note":"blocked_clients は、BLPOP/BRPOP/WAIT などのブロッキングコマンドで待機しているクライアントの数。想定より高い値は、コンシューマが追いついていないか、キューのバックログが増えていることを示す。キューベースのワークロードではプロデューサ/コンシューマのバランスを確認する。","tags":["client","blocking","queue"]},{"metric":"メモリ断片化率 (mem_fragmentation_ratio)","warn":"> 1.5","crit":"> 2.0","tool":"INFO memory","note":"断片化率は OS から取得したメモリを Redis が使用しているメモリで割った値。1.5 を超えると過剰な断片化を示し、1.0 未満はメモリがスワップにあふれていることを示し、非常に危険。activedefrag の有効化または再起動で断片化を減らせる。","tags":["memory","fragmentation"]},{"metric":"マスターリンクの状態 (master_link_status)","warn":"down (< 10 s)","crit":"down (> 30 s)","tool":"INFO replication (master_link_status)","note":"master_link_status は、レプリカからマスターへの接続の状態 (up/down) を示す。'down' はレプリケーションが切断され、レプリカが古いデータを提供していることを意味する。長時間の切断にはフル再同期が必要になるため、ネットワークとマスターの健全性を直ちに確認する。","tags":["replication","master","connection"]},{"metric":"レプリケーション遅延 (master_repl_offset の差)","warn":"> 1 MB","crit":"> 10 MB","tool":"INFO replication (オフセットの差)","note":"マスターとレプリカのオフセットの差は、レプリカがどれだけ遅れているかをバイトで示す。差が大きいとフェイルオーバー時のデータ損失のリスクと読み取りレプリカでの不整合を意味する。ネットワークのレイテンシとレプリカの負荷を調べ、差が縮まることを確認する。","tags":["replication","lag","offset"]},{"metric":"最後の RDB bgsave の状態 (rdb_last_bgsave_status)","warn":"err (最後の試行)","crit":"err (> 24 時間)","tool":"INFO persistence","note":"rdb_last_bgsave_status は、最後のバックグラウンドスナップショットが成功した (ok) かどうかを示す。bgsave の失敗は永続化が機能していないことを意味し、再起動時にデータ損失のリスクがある。通常はディスク満杯または fork 用のメモリ不足が原因。","tags":["backup","persistence","rdb"]},{"metric":"接続の使用率 (connected_clients)","warn":"> 80% maxclients","crit":"> 90% maxclients","tool":"INFO clients / maxclients","note":"connected_clients が maxclients の上限に近づくと、新規接続が拒否される。接続リークや誤設定されたプールが急増の原因となりうる。アプリケーション側でコネクションプールを正しく設定し、アイドル接続をクローズする。","tags":["connection","limit","client"]},{"metric":"瞬間的なコマンドレイテンシ","warn":"> 1 ms","crit":"> 10 ms","tool":"redis-cli --latency / LATENCY DOCTOR","note":"Redis はシングルスレッドのため、コマンドのレイテンシは通常マイクロ秒単位。レイテンシの上昇は、低速なコマンド (KEYS、大きな SORT)、fork 中のブロッキング、またはスワップの使用が原因となりうる。slowlog と LATENCY コマンドで原因を特定する。","tags":["latency","performance","slowlog"]},{"metric":"CPU 使用率","warn":"> 80% (単一コア)","crit":"> 90% (単一コア)","tool":"top / redis_exporter","note":"Redis のメインスレッドは単一コアを使用するため、1 つのコアが飽和するとサーバー全体が遅くなる。高い CPU は、コストの高いコマンド、多すぎる接続、または Lua スクリプトが原因となりうる。SLOWLOG でコストの高いコマンドを特定し、必要に応じてワークロードを複数のインスタンスに分割する。","tags":["cpu","load"]},{"metric":"拒否された接続 (rejected_connections)","warn":"> 0","crit":"> 10 / 分","tool":"INFO stats (rejected_connections)","note":"rejected_connections は、maxclients の上限に達したために拒否された接続の数。ゼロより大きい値は、クライアントが処理されずアプリケーションでエラーが発生していることを意味する。maxclients の値と接続リークを直ちに調査する。","tags":["connection","error","limit"]}]},"reference/alerts-elasticsearch.json":{"engineId":"elasticsearch","engine":"Elasticsearch","order":7,"alerts":[{"metric":"JVM ヒープ使用率","warn":"> 75%","crit":"> 85%","tool":"_nodes/stats/jvm / elasticsearch_exporter","note":"JVM ヒープ使用率はノードのメモリの逼迫を示す。継続的に 75% を超える値は頻繁な GC と OutOfMemory の可能性を意味する。ヒープが 85% を超えると、ノードが応答しなくなるかクラスタから離脱することがある。ヒープはサーバーメモリの約半分、かつ 30-31 GB 以下にサイジングする。","tags":["memory","jvm","heap"]},{"metric":"未割り当てシャード数 (unassigned shards)","warn":">= 1 (レプリカ)","crit":">= 1 (プライマリ)","tool":"_cluster/health / _cat/shards","note":"未割り当てシャードは、データの一部にアクセスできないか、レプリケートされていないことを意味する。未割り当てのプライマリシャードはデータ損失のリスクを、未割り当てのレプリカは冗長性の喪失を意味し、クラスタは yellow/red になる。_cluster/allocation/explain で原因を特定する。","tags":["shard","cluster","health"]},{"metric":"ディスク watermark の使用率","warn":"> 85% (low)","crit":"> 90% (high) / > 95% (flood_stage)","tool":"_nodes/stats/fs / _cat/allocation","note":"Elasticsearch はディスク使用率に応じて段階的に対処する。85% の low watermark でノードへの新しいシャードの割り当てを停止し、90% の high watermark で既存のシャードを他のノードに再配置し、95% の flood_stage でインデックスに read_only_allow_delete ブロックをかける。8.x では大容量ディスクの場合、割合よりも max_headroom の値 (low 200GB / high 150GB / flood 100GB の空き) が優先される。7.4+ ではディスク使用率が high watermark を下回るとブロックは自動的に解除されるが、watermark を超える前にディスクを空けておく。","tags":["disk","watermark","capacity"]},{"metric":"スレッドプールで拒否された操作 (rejected)","warn":"> 0 (write/search)","crit":"> 100 / 分","tool":"_cat/thread_pool / _nodes/stats/thread_pool","note":"スレッドプールのキューが満杯になると、着信要求は拒否される。write プールでの拒否はインデックス作成の損失を、search プールでの拒否はクエリの失敗を意味する。継続的な拒否は、ノードが流入する負荷に追いつけていないことを示す。bulk サイズと同時実行数を減らして負荷を平準化する。","tags":["threadpool","rejected","load"]},{"metric":"GC の一時停止時間 (old gen GC pause)","warn":"> 1 s","crit":"> 5 s","tool":"GC ログ / _nodes/stats/jvm","note":"長い GC の一時停止中、ノードは応答できずマスターとの接続を失うことがあり、シャードの再割り当てが発生する。頻繁で長い旧世代 (old generation) の GC はヒープの逼迫の症状。ヒープサイズと、メモリを多く使う集計および fielddata の使用を見直す。","tags":["jvm","gc","pause"]},{"metric":"インデックス作成レイテンシ","warn":"> 50 ms","crit":"> 200 ms","tool":"_nodes/stats/indices (index_time/index_total)","note":"平均インデックス作成時間はドキュメントの書き込み性能を示し、index_time_in_millis を index_total で割って算出する。値の上昇はディスク IO のボトルネック、重いアナライザチェーン、または refresh の負荷を示す。bulk サイズと refresh_interval の設定を最適化する。","tags":["indexing","latency","performance"]},{"metric":"検索レイテンシ","warn":"> 100 ms","crit":"> 500 ms","tool":"_nodes/stats/indices (query_time/query_total)","note":"平均クエリ時間はユーザーが体感する検索性能を直接反映し、query_time_in_millis を query_total で割って算出する。値の上昇は、重い集計、多すぎるシャード、またはコールドキャッシュが原因となりうる。slow log を有効にしてコストの高いクエリを特定する。","tags":["search","latency","performance"]},{"metric":"保留中のタスク (pending tasks)","warn":"> 10","crit":"> 100","tool":"_cluster/pending_tasks","note":"保留中のタスクは、マスターノードがまだ適用していないクラスタ状態の変更 (マッピング、シャードの割り当てなど)。継続的な蓄積は、マスターが過負荷であるか、クラスタ状態が大きくなりすぎていることを示す。過剰なシャード数を減らしてマスターの負荷を軽減する。","tags":["cluster","master","queue"]},{"metric":"サーキットブレーカーの発動","warn":"> 0 (発動)","crit":"> 10 / 分","tool":"_nodes/stats/breakers","note":"サーキットブレーカーは、操作がメモリを過剰に消費してノードが OutOfMemory に陥るのを防ぐために要求をキャンセルする。頻繁な発動は、重い集計または大きな要求によるメモリの逼迫を示す。tripped の回数を監視し、問題のあるクエリを軽量化する。","tags":["memory","breaker","jvm"]},{"metric":"クラスタのヘルス状態 (cluster status)","warn":"yellow","crit":"red","tool":"_cluster/health","note":"クラスタの状態は green (すべてのシャードが割り当て済み)、yellow (レプリカが欠落)、red (プライマリが欠落し、データにアクセス不可) のいずれか。red は一部のデータが失われたかアクセスできないため、直ちに対処が必要。yellow は冗長性の喪失を示し、無視してはならない。","tags":["cluster","health","shard"]},{"metric":"CPU 使用率","warn":"> 80%","crit":"> 90%","tool":"_nodes/stats/os / node_exporter","note":"継続的に高い CPU は、重いクエリ、過剰なインデックス作成、またはマージ操作が原因となりうる。短時間のピークは正常だが、継続的な飽和はクエリとインデックス作成の待ち行列を引き起こす。hot threads API (_nodes/hot_threads) で CPU を最も消費する操作を特定する。","tags":["cpu","load"]},{"metric":"最後に成功したスナップショットからの経過時間","warn":"> 24 時間","crit":"> 48 時間","tool":"_snapshot/_status / SLM","note":"スナップショットの経過時間は戻れる最新の時点と RPO を決める。Snapshot Lifecycle Management (SLM) で自動的かつ定期的なバックアップを確保する。失敗またはスキップされたスナップショットに気付かないと、障害時にデータを復旧できない。スナップショットの状態を定期的に確認する。","tags":["backup","snapshot","rpo"]}]},"cloud/cloud-ops-1.json":{"category":"接続・バックアップ・レプリカ","categoryId":"cloud-core","order":1,"providers":[{"id":"aws-rds","name":"AWS RDS","color":"#B85C00"},{"id":"aws-aurora","name":"Aurora","color":"#7B3FE4"},{"id":"gcp-cloudsql","name":"Cloud SQL","color":"#C5372C"},{"id":"azure-sql","name":"Azure SQL","color":"#0067B8"},{"id":"mongodb-atlas","name":"Atlas","color":"#00843D"}],"concepts":[{"id":"list-instances","title":"インスタンス/データベースの一覧表示","aliases":["list","instances","list all"],"providers":{"aws-rds":{"command":"aws rds describe-db-instances --query 'DBInstances[].DBInstanceIdentifier'","note":"すべての RDS インスタンスの識別子を一覧表示する。リージョンを指定するには --region を追加する。","danger":"safe"},"aws-aurora":{"command":"aws rds describe-db-clusters --query 'DBClusters[].DBClusterIdentifier'","note":"Aurora クラスタの識別子を一覧表示する。クラスタのメンバーは DBClusterMembers フィールドで確認する。","danger":"safe"},"gcp-cloudsql":{"command":"gcloud sql instances list","note":"プロジェクト内のすべての Cloud SQL インスタンスを一覧表示する。プロジェクトを指定するには --project を追加する。","danger":"safe"},"azure-sql":{"command":"az sql db list -g <rg> -s <server>","note":"指定したリソースグループ (-g) と論理サーバー (-s) 内のデータベースを一覧表示する。サーバーの一覧は 'az sql server list' で表示する。","danger":"safe"},"mongodb-atlas":{"command":"atlas clusters list","note":"Atlas プロジェクト内のすべてのクラスタを一覧表示する。プロジェクトを指定するには --projectId を追加する。","danger":"safe"}}},{"id":"connect","title":"インスタンスへの接続 (エンドポイントの確認 + 接続)","aliases":["connect","endpoint","connection string","connect to"],"providers":{"aws-rds":{"command":"aws rds describe-db-instances --db-instance-identifier <id> --query 'DBInstances[0].Endpoint.Address'","note":"インスタンスの接続アドレス (ホスト) を返す。ポートは Endpoint.Port から取得し、psql/mysql クライアントで接続する。","danger":"safe"},"aws-aurora":{"command":"aws rds describe-db-clusters --db-cluster-identifier <id> --query 'DBClusters[0].Endpoint'","note":"クラスタのライターエンドポイントを返す。読み取り専用アクセスには ReaderEndpoint フィールドを使用する。","danger":"safe"},"gcp-cloudsql":{"command":"gcloud sql instances describe <instance> --format='value(ipAddresses[].ipAddress)'","note":"インスタンスの IP アドレスを返す。安全な接続には Cloud SQL Auth Proxy が推奨される。","danger":"safe"},"azure-sql":{"command":"az sql db show-connection-string -s <server> -n <db> -c ado.net","note":"指定したクライアントタイプ (-c: ado.net、jdbc、odbc、php など) の接続文字列を生成する。ユーザー/パスワードは自分で入力する。","danger":"safe"},"mongodb-atlas":{"command":"atlas clusters connectionStrings describe <clusterName>","note":"クラスタの標準接続文字列と SRV 接続文字列を返す。IP アクセスリストのエントリとデータベースユーザーが必要。","danger":"safe"}}},{"id":"take-snapshot","title":"手動バックアップ/スナップショットの取得","aliases":["snapshot","backup","backup"],"providers":{"aws-rds":{"command":"aws rds create-db-snapshot --db-instance-identifier <id> --db-snapshot-identifier <snap-id>","note":"インスタンスの手動スナップショットを取得する (手動で削除するまで保持される)。短時間の I/O 停止が発生することがある。","danger":"caution"},"aws-aurora":{"command":"aws rds create-db-cluster-snapshot --db-cluster-identifier <id> --db-cluster-snapshot-identifier <snap-id>","note":"Aurora クラスタの手動スナップショットを取得する。Aurora のバックアップは継続的に行われるため、これは固定のコピーとなる。","danger":"caution"},"gcp-cloudsql":{"command":"gcloud sql backups create --instance=<instance>","note":"インスタンスのオンデマンドバックアップを作成する。操作中に短時間の性能への影響が生じることがある。","danger":"caution"},"azure-sql":{"command":"az sql db export -s <server> -n <db> -u <user> -p <pwd> --admin-user <adm> --admin-password <pwd> --storage-key <key> --storage-key-type StorageAccessKey --storage-uri https://<acct>.blob.core.windows.net/<container>/<file>.bacpac","note":"Azure SQL は自動的にバックアップされる。持ち運び可能な手動バックアップとして、データベースを BACPAC にエクスポートする。ポイントインタイムリストアは別の機能。","danger":"caution"},"mongodb-atlas":{"command":"atlas backups snapshots create <clusterName>","note":"クラスタのオンデマンドバックアップスナップショットを開始する。Cloud Backup が有効である必要がある。","danger":"caution"}}},{"id":"restore-pitr","title":"特定時点へのリストア (ポイントインタイムリストア)","aliases":["pitr","restore","point-in-time","roll back"],"providers":{"aws-rds":{"command":"aws rds restore-db-instance-to-point-in-time --source-db-instance-identifier <src> --target-db-instance-identifier <new> --restore-time 2026-07-03T10:00:00Z","note":"ソースインスタンスから指定時刻の状態で新しいインスタンスを作成する。既存のインスタンスは上書きされない。最新の時点にリストアするには --use-latest-restorable-time を使用する。","danger":"caution"},"aws-aurora":{"command":"aws rds restore-db-cluster-to-point-in-time --source-db-cluster-identifier <src> --db-cluster-identifier <new> --restore-to-time 2026-07-03T10:00:00Z","note":"Aurora クラスタを指定時刻の状態で新しいクラスタとしてリストアする。その後 create-db-instance でインスタンスを追加する必要がある。","danger":"caution"},"gcp-cloudsql":{"command":"gcloud sql instances clone <src> <new> --point-in-time '2026-07-03T10:00:00Z'","note":"ソースインスタンスの指定時刻のクローンを新しいインスタンスとして作成する。ソースでバイナリ/WAL ロギングが有効である必要がある。","danger":"caution"},"azure-sql":{"command":"az sql db restore -g <rg> -s <server> -n <db> --dest-name <new-db> --time '2026-07-03T10:00:00'","note":"データベースを指定時刻の状態で新しいデータベースとしてリストアする。ソースデータベースは保持される。時刻は UTC。","danger":"caution"},"mongodb-atlas":{"command":"atlas backups restores start pointInTime --clusterName <cluster> --pointInTimeUTCMillis <ms> --targetClusterName <target> --targetProjectId <projId>","note":"Continuous Cloud Backup を使用して指定した UTC 時刻へのリストアを開始する。ターゲットクラスタは上書きされるため、慎重に実行する。","danger":"danger"}}},{"id":"read-replica","title":"リードレプリカの作成","aliases":["replica","read replica","read replica"],"providers":{"aws-rds":{"command":"aws rds create-db-instance-read-replica --db-instance-identifier <replica-id> --source-db-instance-identifier <src>","note":"ソースインスタンスから非同期のリードレプリカを作成する。クロスリージョンのコピーには --source-region を使用する。","danger":"caution"},"aws-aurora":{"command":"aws rds create-db-instance --db-instance-identifier <reader-id> --db-cluster-identifier <cluster> --engine aurora-postgresql --db-instance-class db.r6g.large","note":"Aurora では、リーダーはクラスタに追加されるインスタンスで、クラスタのストレージを共有する。engine の値はクラスタに合わせて設定する (aurora-mysql / aurora-postgresql)。","danger":"caution"},"gcp-cloudsql":{"command":"gcloud sql instances create <replica> --master-instance-name=<src> --region=<region>","note":"プライマリ (マスター) インスタンスからリードレプリカを作成する。ソースでバイナリロギングが有効である必要がある。","danger":"caution"},"azure-sql":{"command":"az sql db replica create -g <rg> -s <server> -n <db> --partner-server <target-server>","note":"データベースのアクティブ geo レプリケーションによる読み取り可能なセカンダリを別のサーバー上に作成する。ターゲットサーバーが存在している必要がある。","danger":"caution"},"mongodb-atlas":{"command":"atlas clusters update <clusterName> --file cluster.json","note":"Atlas クラスタはすでにレプリケートされたレプリカセット。追加の読み取り容量が必要な場合は、replicationSpecs の下に readOnly または analytics ノードを追加して更新する。","danger":"caution"}}},{"id":"failover","title":"フェイルオーバー","aliases":["failover","fail over","switch to standby"],"providers":{"aws-rds":{"command":"aws rds reboot-db-instance --db-instance-identifier <id> --force-failover","note":"Multi-AZ インスタンスで、スタンバイへのフェイルオーバーを引き起こす再起動を強制する。短時間のダウンタイムが発生する。","danger":"danger"},"aws-aurora":{"command":"aws rds failover-db-cluster --db-cluster-identifier <cluster> --target-db-instance-identifier <reader>","note":"Aurora クラスタ内のリーダーを新しいライターに昇格させる。ターゲットを指定しない場合は適切なレプリカが選ばれる。短時間のダウンタイムが発生する。","danger":"danger"},"gcp-cloudsql":{"command":"gcloud sql instances failover <instance>","note":"HA (高可用性) インスタンスをスタンバイゾーンにフェイルオーバーさせる。HA が有効なインスタンスでのみ機能し、ダウンタイムが発生する。","danger":"danger"},"azure-sql":{"command":"az sql failover-group set-primary -g <rg> -s <secondary-server> -n <fog-name>","note":"自動フェイルオーバーグループ内のセカンダリサーバーにプライマリの役割を移す (計画的フェイルオーバー)。--allow-data-loss で強制できるが、データ損失のリスクがある。","danger":"danger"},"mongodb-atlas":{"command":"atlas clusters failover <clusterName>","note":"Atlas は自動的にフェイルオーバーする。このコマンドはテスト用に手動フェイルオーバーを実行する。プライマリノードが変わるため、アプリケーションは再接続する必要がある。","danger":"danger"}}}]},"cloud/cloud-ops-2.json":{"category":"構成・スケーリング・監視","categoryId":"cloud-config","order":2,"providers":[{"id":"aws-rds","name":"AWS RDS","color":"#B85C00"},{"id":"aws-aurora","name":"Aurora","color":"#7B3FE4"},{"id":"gcp-cloudsql","name":"Cloud SQL","color":"#C5372C"},{"id":"azure-sql","name":"Azure SQL","color":"#0067B8"},{"id":"mongodb-atlas","name":"Atlas","color":"#00843D"}],"concepts":[{"id":"scale-instance","title":"インスタンスサイズの変更 (垂直スケーリング)","aliases":["scale","size","resize","scale up","vertical"],"providers":{"aws-rds":{"command":"aws rds modify-db-instance --db-instance-identifier <id> --db-instance-class db.r6g.xlarge --apply-immediately","note":"--apply-immediately は変更を即時に適用し、インスタンスを再起動する (短時間のダウンタイム)。このフラグがない場合、変更は次のメンテナンスウィンドウで適用される。Multi-AZ インスタンスではダウンタイムはおおむねフェイルオーバー時間まで短縮される。","danger":"caution"},"aws-aurora":{"command":"aws rds modify-db-instance --db-instance-identifier <writer-or-reader-id> --db-instance-class db.r6g.2xlarge --apply-immediately","note":"Aurora では各インスタンス (ライターとリーダー) を個別にスケーリングする。変わるのはクラスタではなくインスタンスのサイズ。ダウンタイムを最小化するには、先にリーダーをスケーリングし、その後フェイルオーバーしてライターを置き換える。Serverless v2 では最小/最大 ACU でスケーリングする。","danger":"caution"},"gcp-cloudsql":{"command":"gcloud sql instances patch <id> --tier db-custom-4-16384","note":"カスタムマシンタイプは db-custom-CPU-MEMORY の形式で指定する (例: 4 vCPU、16384 MB RAM)。変更によりインスタンスが再起動し、短時間のダウンタイムが発生する。事前定義のティア (例: db-n1-standard-4) も使用できる。","danger":"caution"},"azure-sql":{"command":"az sql db update -g <rg> -s <server> -n <db> --service-objective S3","note":"DTU モデルでは S3/P2 などのサービス目標を使用し、vCore モデルでは --edition GeneralPurpose --family Gen5 --capacity 4 を使用する。スケーリングはオンラインで実行されるが、操作の終盤に数秒間の短い接続断が発生することがある。","danger":"caution"},"mongodb-atlas":{"command":"atlas clusters update <name> --tier M30","note":"Atlas はレプリカセットのノードをローリング方式でリサイズするため、ダウンタイムはない。--projectId フラグまたはデフォルトプロジェクトが必要。ダウングレード時はディスクとメモリの上限に注意する。","danger":"caution"}}},{"id":"parameter-group","title":"パラメータの変更 (パラメータグループ / フラグ / サーバー構成)","aliases":["parameter","parameter group","flags","config","setting"],"providers":{"aws-rds":{"command":"aws rds modify-db-parameter-group --db-parameter-group-name <pg> --parameters \"ParameterName=max_connections,ParameterValue=500,ApplyMethod=pending-reboot\"","note":"動的パラメータには ApplyMethod=immediate、静的パラメータには pending-reboot を使用する。パラメータグループはインスタンスにアタッチされている必要があり、静的パラメータの変更は再起動後に反映される。グループの作成には create-db-parameter-group を使用する。","danger":"caution"},"aws-aurora":{"command":"aws rds modify-db-cluster-parameter-group --db-cluster-parameter-group-name <cpg> --parameters \"ParameterName=innodb_lock_wait_timeout,ParameterValue=100,ApplyMethod=immediate\"","note":"Aurora では、クラスタ全体のパラメータは DB クラスタパラメータグループで、インスタンス固有のパラメータは DB パラメータグループ (modify-db-parameter-group) で管理する。静的パラメータにはクラスタ全体の再起動が必要。","danger":"caution"},"gcp-cloudsql":{"command":"gcloud sql instances patch <id> --database-flags max_connections=500,log_min_duration_statement=1000","note":"--database-flags はすべてのフラグを一度に設定する。リストに含まれない設定済みのフラグはリセットされるため、すべてをまとめて指定する。一部のフラグはインスタンスの再起動が必要。現在のフラグは 'gcloud sql instances describe <id>' で確認する。","danger":"caution"},"azure-sql":{"command":"az sql db configure -g <rg> -s <server> -n <db> ...   # DB-level settings via T-SQL: ALTER DATABASE SCOPED CONFIGURATION SET MAXDOP = 4;","note":"Azure SQL では、従来のサーバー構成の代わりに、設定の多くを T-SQL で適用する: ALTER DATABASE SCOPED CONFIGURATION ...。サーバーレベルの sp_configure は限定的。エラスティックプール/データベースのオプションには 'az sql db update' のフラグを使用する。","danger":"caution"},"mongodb-atlas":{"command":"atlas clusters advancedSettings update <name> --oplogMinRetentionHours 24 --oplogSizeMB 20480","note":"Atlas では、低レベルの MongoDB プロセス引数は 'advancedSettings' (oplog、全文検索、インデックスの深さなど) で限定的にしか設定できない。ほとんどのサーバーパラメータは Atlas によって管理され、直接変更できない。","danger":"caution"}}},{"id":"monitoring","title":"メトリックと性能の確認","aliases":["monitoring","metric","observability","performance","insights"],"providers":{"aws-rds":{"command":"aws cloudwatch get-metric-statistics --namespace AWS/RDS --metric-name CPUUtilization --dimensions Name=DBInstanceIdentifier,Value=<id> --start-time 2026-07-05T00:00:00Z --end-time 2026-07-05T01:00:00Z --period 300 --statistics Average","note":"基本的なメトリック (CPU、接続、IOPS、レイテンシ) は CloudWatch の AWS/RDS 名前空間にある。クエリレベルの分析には Performance Insights を有効にする: 'aws pi get-resource-metrics --service-type RDS ...'、またはコンソールの Performance Insights ダッシュボードを使用する。","danger":"safe"},"aws-aurora":{"command":"aws cloudwatch get-metric-statistics --namespace AWS/RDS --metric-name AuroraReplicaLag --dimensions Name=DBInstanceIdentifier,Value=<reader-id> --start-time 2026-07-05T00:00:00Z --end-time 2026-07-05T01:00:00Z --period 60 --statistics Maximum","note":"Aurora 固有のメトリック (AuroraReplicaLag、VolumeReadIOPs、CommitLatency、buffer cache hit) も AWS/RDS 名前空間にある。Aurora では Performance Insights が推奨され、上位 SQL と待機イベントの分析を提供する。","danger":"safe"},"gcp-cloudsql":{"command":"gcloud monitoring time-series list --filter='metric.type=\"cloudsql.googleapis.com/database/cpu/utilization\" AND resource.labels.database_id=\"<project>:<id>\"' --interval-start-time=2026-07-05T00:00:00Z --interval-end-time=2026-07-05T01:00:00Z","note":"Cloud SQL のメトリックは Cloud Monitoring の cloudsql.googleapis.com/... にある。クエリレベルの分析には Cloud SQL Query Insights を有効にする (コンソールまたは API)。最も遅いクエリと待機イベントが表示される。","danger":"safe"},"azure-sql":{"command":"az monitor metrics list --resource <db-resource-id> --metric \"cpu_percent\" --interval PT5M --start-time 2026-07-05T00:00:00Z --end-time 2026-07-05T01:00:00Z","note":"cpu_percent、dtu_consumption_percent、storage_percent、connection_successful などのメトリックは Azure Monitor から取得する。クエリ性能には Query Performance Insight と Intelligent Insights (Azure SQL Analytics) のダッシュボードを使用する。","danger":"safe"},"mongodb-atlas":{"command":"atlas metrics processes <host>:<port> --granularity PT5M --period P1D --type SYSTEM_CPU_USER,QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED","note":"プロセスレベルの測定値は 'atlas metrics processes'、ディスクの測定値は 'atlas metrics disks' で取得する。低速クエリの推奨には Performance Advisor を使用する: 'atlas performanceAdvisor slowQueryLogs list' と 'atlas performanceAdvisor suggestedIndexes list'。","danger":"safe"}}},{"id":"maintenance-window","title":"メンテナンスウィンドウと更新の管理","aliases":["maintenance","maintenance window","window","update","patch"],"providers":{"aws-rds":{"command":"aws rds modify-db-instance --db-instance-identifier <id> --preferred-maintenance-window Sun:03:00-Sun:04:00   # apply pending maintenance now: aws rds apply-pending-maintenance-action --resource-identifier <arn> --apply-action system-update --opt-in-type immediate","note":"ウィンドウは UTC で ddd:hh24:mi-ddd:hh24:mi の形式で指定し、最低 30 分以上である必要がある。保留中のメンテナンスは 'aws rds describe-pending-maintenance-actions' で一覧表示し、apply-pending-maintenance-action で即時または次のウィンドウで適用する。","danger":"caution"},"aws-aurora":{"command":"aws rds modify-db-cluster --db-cluster-identifier <cluster> --preferred-maintenance-window Sun:03:00-Sun:04:00","note":"Aurora では、クラスタレベルのメンテナンスウィンドウを modify-db-cluster で、インスタンスレベルのウィンドウを modify-db-instance で設定する。保留中のエンジン/OS の更新は apply-pending-maintenance-action で管理する。エンジンバージョンのアップグレードにはダウンタイムが必要な場合がある。","danger":"caution"},"gcp-cloudsql":{"command":"gcloud sql instances patch <id> --maintenance-window-day SUN --maintenance-window-hour 3 --maintenance-release-channel production","note":"曜日 (MON..SUN)、時刻 (0-23、インスタンスのローカル/UTC 時刻)、リリースチャネル (production または preview) を設定する。--deny-maintenance-period-* フラグでメンテナンスを行わない期間も定義できる。","danger":"caution"},"azure-sql":{"command":"az sql db update -g <rg> -s <server> -n <db> --maint-config-id SQL_Default   # or custom: /subscriptions/<sub>/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL_<Region>_DB_1","note":"Azure SQL のメンテナンスウィンドウは、事前定義の Maintenance Configuration (デフォルトの代わりに平日/週末の夜間ウィンドウ) を割り当てて管理する。構成の一覧は 'az maintenance public-configuration list' で表示する。","danger":"caution"},"mongodb-atlas":{"command":"atlas maintenanceWindows update --dayOfWeek 1 --hourOfDay 3 --projectId <projectId>   # defer: atlas maintenanceWindows defer","note":"dayOfWeek は 1=日曜日 ... 7=土曜日、hourOfDay は 0-23 (UTC)。保留中のメンテナンスを 1 週間延期するには 'atlas maintenanceWindows defer'、即時開始するには 'atlas maintenanceWindows start' を使用する。","danger":"caution"}}},{"id":"encryption","title":"暗号化 (保存時) の状態の確認/構成","aliases":["encryption","encryption at rest","at-rest","kms","tde","cmek"],"providers":{"aws-rds":{"command":"aws rds describe-db-instances --db-instance-identifier <id> --query 'DBInstances[0].[StorageEncrypted,KmsKeyId]'   # at creation: aws rds create-db-instance ... --storage-encrypted --kms-key-id <kms-arn>","note":"RDS の保存時の暗号化はインスタンスの作成時にのみ有効にできる。既存の暗号化されていないインスタンスで有効にするには、スナップショットの暗号化コピーを作成し、そこからリストアする。キーは AWS KMS で管理される。","danger":"caution"},"aws-aurora":{"command":"aws rds describe-db-clusters --db-cluster-identifier <cluster> --query 'DBClusters[0].[StorageEncrypted,KmsKeyId]'   # at creation: aws rds create-db-cluster ... --storage-encrypted --kms-key-id <kms-arn>","note":"Aurora では、暗号化はクラスタレベルで作成時にのみ設定する。既存の暗号化されていないクラスタを暗号化するには、スナップショットを暗号化してコピーし、リストアする。すべてのインスタンスとバックアップは同じ KMS キーを使用する。","danger":"caution"},"gcp-cloudsql":{"command":"gcloud sql instances create <id> --disk-encryption-key projects/<project>/locations/<region>/keyRings/<ring>/cryptoKeys/<key>   # to view: gcloud sql instances describe <id> --format='value(diskEncryptionConfiguration.kmsKeyName)'","note":"Cloud SQL はデフォルトで Google 管理のキーにより暗号化される。顧客管理のキー (CMEK) は、インスタンス作成時に --disk-encryption-key でのみ割り当てられる。Cloud SQL のサービスアカウントにキーの暗号化/復号の権限を付与する必要がある。","danger":"caution"},"azure-sql":{"command":"az sql db tde set -g <rg> -s <server> -d <db> --status Enabled   # or T-SQL: ALTER DATABASE <db> SET ENCRYPTION ON;   # status: az sql db tde show -g <rg> -s <server> -d <db>","note":"Azure SQL では、保存時の暗号化は Transparent Data Encryption (TDE) によって提供され、新しいデータベースではデフォルトで有効。独自のキーを使用するには、サーバーレベルで 'az sql server tde-key set' (Azure Key Vault / BYOK) を構成する。","danger":"caution"},"mongodb-atlas":{"command":"atlas clusters describe <name> --output json | jq '.encryptionAtRestProvider'   # enable BYOK: atlas encryptionAtRest enable AWS --awsKmsMasterKeyID <keyId> --awsKmsRegion <region> --awsKmsRoleID <roleId>","note":"Atlas では、データはデフォルトで保存時に暗号化される。さらに、AWS KMS / Azure Key Vault / GCP KMS による顧客キー (BYOK) のエンベロープ暗号化を 'atlas encryptionAtRest' でプロジェクト全体に有効にし、クラスタに適用する。","danger":"caution"}}},{"id":"storage-autoscale","title":"ストレージの拡張 / オートスケーリングの有効化","aliases":["storage","disk space","autoscale","grow","disk"],"providers":{"aws-rds":{"command":"aws rds modify-db-instance --db-instance-identifier <id> --allocated-storage 200 --max-allocated-storage 1000 --apply-immediately","note":"--allocated-storage は現在のサイズを、--max-allocated-storage はストレージのオートスケーリングの上限を設定する。ストレージの拡張はオンラインで行われる。ただし、ストレージの変更の間隔は最低 6 時間空ける必要があり、ストレージは縮小できない。","danger":"caution"},"aws-aurora":{"command":"# Aurora storage is automatic; no manual setting required\naws rds describe-db-clusters --db-cluster-identifier <cluster> --query 'DBClusters[0].AllocatedStorage'","note":"Aurora のストレージは完全に自動でスケーリングし (10 GB 単位、エンジンに応じて最大 128 TB)、使用に応じて拡大する。--allocated-storage / --max-allocated-storage は設定しない。使用量を監視するだけでよく、サイズ管理は不要。","danger":"safe"},"gcp-cloudsql":{"command":"gcloud sql instances patch <id> --storage-auto-increase --storage-size 200GB   # upper limit: --storage-auto-increase-limit 1000","note":"--storage-auto-increase はディスクが満杯に近づいたときの自動拡張を有効にし、--storage-auto-increase-limit は上限を設定する (0 = 無制限)。ストレージは拡張のみ可能で、縮小できない。初期サイズと上限は慎重に選ぶ。","danger":"caution"},"azure-sql":{"command":"az sql db update -g <rg> -s <server> -n <db> --max-size 500GB","note":"Azure SQL では、データベースの最大サイズを --max-size で設定し、データベースは割り当てられた領域内で自動的に拡大する。最大サイズは選択したサービスティア/vCore の上限に依存する。Hyperscale ティアではストレージが自動的に、ほぼ無制限にスケーリングする。","danger":"caution"},"mongodb-atlas":{"command":"atlas clusters update <name> --diskSizeGB 200   # for autoscaling, diskGBEnabled=true via extended configuration (advancedSettings / API)","note":"ディスクサイズは --diskSizeGB で増やす。Atlas では、M10 以上のクラスタでストレージのオートスケーリング (Auto-scale storage) がデフォルトで有効になっており、ディスクが 90% に達すると自動的に拡大する。有効化/無効化はクラスタ構成 (autoScaling.diskGBEnabled) で管理する。","danger":"caution"}}}]},"guide/best-practices.json":{"topics":[{"id":"indexing-strategy","title":"インデックス戦略","category":"パフォーマンス","summary":"インデックスは読み取りクエリを高速化するが、書き込みとストレージのコストを増やす。必要性と測定に基づいて追加する。","points":["WHERE、JOIN、ORDER BY の列を対象にする。複合インデックスでは最も選択性の高い列を先頭に置く (左端プレフィックスの原則)。","カバリングインデックスを使用する: クエリに必要なすべての列をインデックスに含め、表へのアクセス (ルックアップ) をなくす。","未使用および冗長なインデックス (重複、または別のインデックスのプレフィックス) を特定して削除する。すべてのインデックスは INSERT/UPDATE/DELETE を遅くする。","カーディナリティの低い列 (例: 性別、boolean) に単独の B-tree インデックスを作成しない。必要に応じて部分インデックス/フィルタ選択インデックスを使用する。","EXPLAIN/EXPLAIN ANALYZE でインデックスが実際に使用されていることを確認する。関数や型変換はインデックスを無効にする (WHERE UPPER(name) のように)。"],"level":"junior"},{"id":"normalization","title":"正規化と非正規化","category":"設計","summary":"正規化はデータの整合性と冗長性のなさを保証する。非正規化は読み取り性能のための意図的なトレードオフ。","points":["OLTP システムではデフォルトで 3NF を目標にする。データの冗長性と更新時異常を防ぐ。","非正規化は測定されたパフォーマンスのボトルネックがある場合にのみ行い、その理由を明確にする。","非正規化したデータの一貫性は、トリガー、マテリアライズドビュー、またはアプリケーション層で保証する。","レポート/分析のワークロードには、別の非正規化スキーマ (スタースキーマ) またはリードレプリカを検討する。","早すぎる非正規化は技術的負債。まず適切なインデックスとクエリで問題の解決を試みる。"],"level":"senior"},{"id":"data-types","title":"適切なデータ型の選択","category":"設計","summary":"正しく、可能な限り小さいデータ型は、ストレージ、インデックスサイズ、性能を直接改善する。","points":["要件を満たす最小の型を選ぶ: 年齢には SMALLINT、金額には DECIMAL/NUMERIC (FLOAT は決して使わない)。","時刻データは常にタイムゾーン付き (TIMESTAMPTZ / UTC) で保存する。ローカル時刻での保存は避ける。","固定された限定的な値の集合には ENUM またはルックアップテーブルを使用する。自由入力を許すのではなく制約を設ける。","可変長のテキストは、不必要に大きい VARCHAR(255) ではなく、実際の要件に合わせたサイズにするか TEXT を使用する。","UUID を PK に使用する場合はインデックスの断片化に注意する。連番の UUID (v7) または BIGINT identity を検討する。","NULL のセマンティクスは意図的に選ぶ。「不明」と「空」の違いを設計で明確にする。"],"level":"junior"},{"id":"naming-conventions","title":"命名規則","category":"設計","summary":"一貫した命名は可読性、保守、チーム内のコミュニケーションを容易にする。最初から標準を定める。","points":["1 つの規則を選び、どこにでも適用する: snake_case は広く使われ、大文字小文字の区別の問題にも強い。","表名を単数形にするか複数形にするかを決める。意味のある、省略しない列名を優先する。","外部キーは参照元が明らかになるように命名し (例: customer_id)、インデックス/制約には標準のプレフィックス (fk_、ix_、uq_) を付ける。","予約語 (order、user、group) を表名/列名に使用しない。","boolean の列は is_/has_ のプレフィックスで明示し、日付の列には _at、_date などの一貫したサフィックスを付ける。"],"level":"junior"},{"id":"partitioning-strategy","title":"パーティショニング戦略","category":"パフォーマンス","summary":"パーティショニングは大きな表を管理しやすい単位に分割する。メンテナンス、パージ、クエリの性能を改善する。","points":["パーティションキーはクエリとアーカイブのパターンに基づいて選ぶ。時系列データには日付ベースの RANGE パーティショニングが最も一般的。","パーティションプルーニングが機能していることを確認する: クエリの WHERE 句にパーティションキーが含まれている必要があり、そうでない場合はすべてのパーティションがスキャンされる。","古いデータは削除するのではなく、パーティションの DROP/DETACH で即時に、ほぼロックなしでパージする。","過剰なパーティション数はプランニングとメタデータのコストを増やす。妥当な粒度 (月次/週次) を選ぶ。","将来のパーティションを自動的に作成するメンテナンスジョブを設定する。対応するパーティションがない書き込みによるエラーを防ぐ。"],"level":"senior"},{"id":"connection-pooling","title":"コネクションプーリング","category":"運用","summary":"コネクションプールは接続確立の高いコストをなくし、データベースを接続の殺到から守る。","points":["要求ごとに新しい接続をオープンしない。アプリケーションまたは中間層 (PgBouncer、HikariCP) でプールを使用する。","プールは CPU コア数とワークロードに基づいてサイジングする。大きすぎるプールはデータベースを詰まらせる (通常は小さいプールのほうがよい)。","接続の有効期間、アイドル、取得タイムアウトの値を意図的に設定する。リーク検出を有効にする。","データベースの max_connections の上限に照らしてプールを計画する。複数のアプリケーションインスタンスの合計を考慮する。","接続がすぐにプールに戻るよう短いトランザクションを使用する。トランザクション内で外部 I/O を待たない。"],"level":"senior"},{"id":"transaction-design","title":"トランザクションの設計 (短く、アトミックに)","category":"パフォーマンス","summary":"トランザクションは短く、アトミックで、1 つの論理的な作業単位をカバーするべき。これによりロック時間が最小化される。","points":["トランザクションはできるだけ短く保つ。ユーザー操作、外部 API 呼び出し、長い計算をトランザクションに含めない。","一緒に成功または失敗しなければならない操作だけを 1 つのトランザクションにまとめる。","ロックの競合を減らすため、行は常に同じ順序で更新する (デッドロック防止の基本)。","不必要に広いロックを避ける。読み取り専用の操作を不要なトランザクションブロックに入れない。","エラー時の明確なロールバック経路を定義する。部分的なコミットやオープンしたままのトランザクションを残さない。","長い一括操作はバッチ単位でコミットする。単一の巨大なトランザクションは WAL/undo の肥大化を招く。"],"level":"senior"},{"id":"isolation-levels","title":"分離レベルの選択","category":"パフォーマンス","summary":"分離レベルは一貫性と同時実行性のバランスを決める。業務ルールに基づいて意図的に選ぶ。","points":["異常の種類を理解する: ダーティリード、ノンリピータブルリード、ファントムリード。どのレベルがどれを防ぐかを理解する。","ほとんどの OLTP では Read Committed で十分。本当に必要な場合にのみ上げる。","重要な金額/在庫の操作には Serializable または明示的なロック (SELECT ... FOR UPDATE) を使用する。","Serializable では、シリアライズ失敗に対する自動リトライのロジックを追加する。","MVCC とロックベースのエンジンの挙動の違いを理解する。同じレベルでもエンジンによって保証が異なる場合がある。"],"level":"expert"},{"id":"deadlock-prevention","title":"デッドロックの防止","category":"パフォーマンス","summary":"デッドロックはトランザクションが互いのリソースを待つときに発生する。設計によって大部分を防止できる。","points":["リソース/行には常に一貫した同じ順序でアクセスする。順序の違いはデッドロックの最も一般的な原因。","トランザクションを短く保ち、ロックの数を減らす。不必要に広範な更新を避ける。","必要に応じて、早期のロック (SELECT ... FOR UPDATE) で競合を予測可能にする。","アプリケーションでデッドロックのエラーを捕捉し、トランザクションを自動的にリトライする。デッドロックを完全になくすことは多くの場合不可能。","デッドロックのログ/グラフを定期的に確認する。繰り返し発生するパターンはインデックスまたはアクセス順序の変更で解消する。"],"level":"expert"},{"id":"sharding-strategy","title":"シャーディング / 水平スケーリング戦略","category":"設計","summary":"シャーディングはデータを複数のノードに分散して単一サーバーの限界を克服する。大きな複雑さを伴うため、最後の手段とするべき。","points":["まず垂直スケーリング、インデックス作成、キャッシュ、リードレプリカを使い尽くす。本当に必要な場合にのみシャーディングする。","シャードキーは慎重に選ぶ: シャードをまたぐクエリが少なく、ホットスポットを生まずに均等に分散する必要がある。","リバランス (リシャーディング) には consistent hashing または仮想シャードを使用する。最初から増加に備えて計画する。","シャードをまたぐ JOIN と分散トランザクションはコストが高い。それらを最小化するようにスキーマを設計する。","グローバルに一意な ID の生成 (snowflake 方式の連番 ID など) とシャードのルーティング層を解決する。"],"level":"expert"},{"id":"backup-strategy","title":"バックアップ戦略 (3-2-1)","category":"バックアップと HA","summary":"堅牢なバックアップ戦略は障害に対する最後の防衛線。テストされるまでバックアップはバックアップとみなされない。","points":["3-2-1 ルールを適用する: 3 つのコピー、2 種類の異なるメディア、1 つのコピーをオフサイト (別拠点/別リージョン) に置く。","フル + 増分バックアップを WAL/binlog のアーカイブと組み合わせ、ポイントインタイムリカバリ (PITR) を可能にする。","バックアップは実際にリストアして定期的にテストする。テストされていないバックアップはバックアップではない。","バックアップは保存時と転送時の両方で暗号化する。アクセスを制限し、保持期間をポリシーで定める。","ランサムウェアに備えて、変更不可 (immutable) またはエアギャップのコピーを保持する。"],"level":"junior"},{"id":"hadr-design","title":"HA/DR の設計と RPO/RTO","category":"バックアップと HA","summary":"高可用性と災害復旧の設計は、業務上の目標を RPO と RTO の指標として定義することから始まる。","points":["RPO (許容できるデータ損失) と RTO (許容できるダウンタイム) の目標を業務部門と共に定義する。","同期レプリケーションは RPO をほぼゼロにするがレイテンシを増やす。非同期は性能が良いがデータ損失のリスクがある。","自動フェイルオーバーを構成し、定期的なフェイルオーバー訓練で実際に機能することを確認する。","スプリットブレインを防ぐためにクォーラム/witness の仕組みを使用する。両方のノードがマスターになることを決して許さない。","DR 環境は物理的に異なるリージョンに置く。単一のリージョン/データセンターの障害に耐えられるようにする。"],"level":"expert"},{"id":"capacity-planning","title":"キャパシティプランニングと増加","category":"運用","summary":"キャパシティプランニングは、増加傾向に先んじてリソースを用意することで、予期しない停止を防ぐ。","points":["データ増加率、IOPS、CPU、メモリ、接続の使用量を継続的に測定し、傾向を導き出す。","ディスク使用率に早期のしきい値アラート (例: 75%/85%) を設定する。容量が尽きる前に対処する。","予測に基づいて増加を計画する。ピーク負荷と季節変動を考慮する。","接続数、表/インデックスの肥大化、アーカイブの必要性を定期的に見直す。","ボトルネックに達する前にスケーリングの方針 (垂直、レプリカ、パーティショニング/シャーディング) を決める。"],"level":"senior"},{"id":"migration-strategy","title":"移行戦略 (最小ダウンタイム)","category":"運用","summary":"スキーマとデータの移行は、ダウンタイムを最小化する元に戻せる計画に従い、可能な限りオンラインで行うべき。","points":["すべての移行を元に戻せる、冪等なものとして設計する。ロールバック計画なしに本番環境に適用しない。","大きな表でブロッキングする DDL を避ける。オンラインスキーマ変更ツール (PG: pg-osc/pgroll、MySQL: gh-ost、pt-osc) を使用する。","後方/前方互換の変更には expand-contract パターンを適用する: まず追加し、デプロイし、その後古いものを削除する。","大量のデータは小さなバッチで移動する。単一の巨大な UPDATE でロックと WAL の肥大化を生まない。","移行は、まず実際のデータ量を持つ本番同等の環境でリハーサルし、所要時間を測定する。","切り替えのタイミング、検証手順、ロールバックの判断を事前に文書化した計画に落とし込む。"],"level":"senior"},{"id":"schema-versioning","title":"スキーマのバージョン管理 (Flyway/Liquibase)","category":"運用","summary":"スキーマ変更は、コードと共に管理され、バージョン付けされ、自動的に適用される移行で管理するべき。手動の介入はエラーを招きやすい。","points":["すべてのスキーマ変更を Flyway/Liquibase などのツールでバージョン管理し、ソース管理に保持する。","本番環境で DDL を手動で実行しない。すべての変更はレビュー済みの移行ファイルを経由する。","移行は順序付けられ一意に保つ。適用済みの移行ファイルを変更せず、新しい移行で修正する。","CI/CD パイプラインで移行を自動的に適用して検証する。環境間のスキーマの一貫性を保証する。","アプリケーションコードとスキーマのバージョンを歩調を合わせて進める。後方互換の移行には expand-contract パターンを採用する。"],"level":"senior"},{"id":"least-privilege","title":"最小権限の原則","category":"セキュリティ","summary":"すべてのユーザーとアプリケーションは、業務に必要な権限だけを持つべき。過剰な権限は攻撃対象領域を広げる。","points":["アプリケーションには権限を限定した個別のアカウントを使用する。superuser/admin として接続しない。","権限はユーザーに直接ではなくロールに付与する。アクセスはロールのメンバーシップで管理する。","必要な表と操作 (SELECT/INSERT/UPDATE) のみを許可する。広範な GRANT ALL は避ける。","権限を定期的に見直し、未使用のものを取り消す。従業員/サービスがいなくなったら直ちにアクセスを削除する。","シークレット (パスワード、接続文字列) をコードに埋め込まない。シークレットマネージャー (vault) を使用し、定期的にローテーションする。"],"level":"junior"},{"id":"encryption-basics","title":"暗号化の基本 (保存時/転送時)","category":"セキュリティ","summary":"データは保存時と転送時の両方で暗号化するべき。暗号化はコンプライアンスとデータ漏えいに対する基本的な保護。","points":["転送時は TLS を強制する。暗号化されていない接続を拒否し、証明書の検証を有効にする。","保存時の暗号化 (TDE またはディスク/ボリュームの暗号化) を適用し、盗まれたディスク/バックアップが読み取れないようにする。","キー管理を重視する: キーは別の KMS/HSM に保管し、定期的にローテーションする。","クレジットカード番号や国民 ID などの機密性の高いフィールドは、アプリケーション層でも追加で暗号化する (フィールドレベル)。","バックアップも暗号化する。本番環境の保護をバックアップとレプリカにも拡張する。","テスト/開発環境では機密データをマスキングまたは匿名化する (データマスキング)。"],"level":"senior"},{"id":"monitoring-basics","title":"監視の基本 (ゴールデンシグナル)","category":"運用","summary":"効果的な監視とは、正しいメトリックを収集し、意味のあるしきい値でアラートを出すこと。ユーザーが気付く前に問題を捉える。","points":["ゴールデンシグナルを監視する: レイテンシ、トラフィック、エラー率、飽和度。","データベース固有のメトリックを追加する: 低速クエリ、ロック/待機時間、接続数、キャッシュヒット率、レプリケーション遅延。","アラートは症状ではなく影響と対処可能なしきい値に結び付ける。ノイズの多いアラートはアラート疲れを招く。","スロークエリログとクエリ統計 (pg_stat_statements など) を常時有効にし、定期的に確認する。","メトリックを履歴として保持する。傾向とキャパシティプランニングのためのベースラインを作る。","ディスクの残り容量やバックアップの成否などの重要な状態には常にアラートを設定する。"],"level":"junior"},{"id":"query-design","title":"クエリ設計と N+1 の防止","category":"パフォーマンス","summary":"効率的なクエリは、最小限のラウンドトリップで必要なデータだけを取得する。N+1 は最も一般的で最も気付きにくい性能のバグ。","points":["SELECT * ではなく必要な列だけを選択する。ネットワーク、メモリ、カバリングインデックスの機会が改善する。","N+1 問題を防ぐ: ループ内の個別クエリではなく JOIN またはバッチ (IN) クエリを使用する。ORM では eager loading を有効にする。","大きな結果セットはページングする。大量データでは OFFSET よりキーセット (seek) ページングを優先する。","業務ロジックは可能な限りクエリに任せる。表全体を取得してアプリケーションでフィルタ/集計しない。","EXPLAIN ANALYZE で実際のプランと行の推定値を調べる。全表スキャンと誤推定を排除する。","頻繁に実行されるコストの高い集計クエリは、マテリアライズドビューまたは事前計算したサマリーテーブルで支える。"],"level":"junior"},{"id":"large-table-management","title":"大きな表の管理 (アーカイブ/パーティショニング)","category":"パフォーマンス","summary":"増え続ける表は、時間とともにクエリ、メンテナンス、バックアップを遅くする。アーカイブとパーティショニングで制御する。","points":["ホット (アクティブ) なデータとコールド (過去) のデータを分ける。古いデータはアーカイブ表または安価なストレージに移動する。","表を日付/範囲でパーティション化する。古いデータは DELETE ではなくパーティションの DROP で即時にパージする。","大規模な削除/更新は小さなバッチで行う。単一の巨大な DELETE はロック、WAL の肥大化、表の肥大化を生む。","肥大化と表/インデックスのサイズを定期的に監視する。必要に応じてオンラインの再編成 (VACUUM/reorg) を行う。","頻繁なクエリに合うインデックスを保持する。大きな表で不要なインデックスを維持するコストは非常に高い。"],"level":"senior"},{"id":"caching-strategy","title":"キャッシュ戦略","category":"パフォーマンス","summary":"キャッシュは繰り返しの読み取りをデータベースから切り離してレイテンシと負荷を下げる。本当の課題は無効化。","points":["キャッシュはコストが高く、頻繁に読まれ、めったに変わらないデータに使用する。すべてをキャッシュしようとしない。","無効化の戦略を選ぶ: TTL、書き込み時の更新 (write-through)、または書き込み時の削除 (write-invalidate)。","古いデータの許容度を業務ルールに基づいて定義する。厳密な一貫性が必要な箇所ではキャッシュに頼らない。","キャッシュスタンピード (多数の要求が空のキャッシュを同時に埋めようとする現象) をロックまたはリクエストの集約で防ぐ。","キャッシュヒット率を監視する。ヒット率が低い場合、キャッシュが価値を提供していないことを示す。","キャッシュは高速化の層であり、永続的な状態ではない。キャッシュが失われてもシステムは正しく動作し続ける必要がある。"],"level":"senior"},{"id":"statistics-maintenance","title":"統計とメンテナンスの規律","category":"運用","summary":"最新の統計と定期的なメンテナンスにより、クエリプランナが正しい判断を行い、性能が時間とともに劣化しないようにする。","points":["統計を最新に保つ (ANALYZE / auto-analyze)。古い統計はプランナを誤ったプランへと導く。","デッド行と肥大化を除去するため、VACUUM/クリーンアップを定期的に実行する。MVCC エンジンでは極めて重要。","インデックスの断片化を監視し、必要に応じてオンラインで再構築する (REINDEX/rebuild)。","一括ロード後は統計を手動で更新する。プランナが古い分布で動作するのを防ぐ。","メンテナンスジョブはトラフィックの少ない時間帯に予定し、所要時間/影響を監視して自動化する。","プランの後退 (急に遅くなるクエリ) に注意する。最初に確認すべきは統計の鮮度。"],"level":"senior"}]},"guide/best-practices-2.json":{"topics":[{"id":"iac","title":"インフラストラクチャのコード化 (IaC)","category":"運用","summary":"データベースサーバー、ネットワーク、構成は手作業ではなくバージョン管理されたコードで定義するべき。それにより環境が再現可能、監査可能、元に戻せるものになる。","points":["サーバー、パラメータグループ、ネットワーク、ユーザーの定義を Terraform/Pulumi/CloudFormation などのツールでコードとして保持し、ソース管理下に置く。","コンソールでの手動変更 (click-ops) を禁止する。ドリフト検出を実行し、コードから逸脱したリソースを修正する。","環境 (dev/stage/prod) 間の違いは変数で管理する。本番同等の環境を同じモジュールから構築する。","state ファイルはリモートに置きロックする (例: S3 + DynamoDB lock)。シークレットを平文で state に漏らさない。","変更は plan/apply のフローでレビューする。本番環境の前に承認ゲートを置く。"],"level":"senior"},{"id":"automation-idempotency","title":"自動化と冪等性","category":"運用","summary":"運用タスクは、手動で繰り返すコマンドから、何回実行しても同じ結果を生む冪等な自動化へと置き換えるべき。","points":["すべてのスクリプトを冪等に書き、再実行しても失敗せず状態を壊さないようにする (例: CREATE ではなく CREATE IF NOT EXISTS)。","定期的なメンテナンスタスク (バックアップ、クリーンアップ、統計) はスケジュールされ、ログが記録される自動化に結び付ける。手動の実行に任せない。","スクリプトに明示的な前提条件のチェックと安全な終了処理を組み込む。途中で止まった操作を再実行したら、止まった箇所から完了させるべき。","自動化はコード (Ansible/スクリプト + CI) から実行する。本番環境で誰かがターミナルにコマンドを入力することに依存しない。","重要な操作には dry-run のサポートを用意する。適用する前に影響を示す。"],"level":"senior"},{"id":"observability","title":"オブザーバビリティ (メトリック/ログ/トレース)","category":"運用","summary":"オブザーバビリティはメトリック、ログ、分散トレースを組み合わせ、「何が起きたか」から「なぜ起きたか」へと進めるようにする。","points":["3 つのシグナルをすべて併せて収集する: メトリック (傾向)、ログ (コンテキスト)、トレース (リクエストの経路)。どれか 1 つだけでは根本原因は明らかにならない。","クエリをエンドツーエンドでトレースする: アプリケーションのトレースとデータベースのレイテンシを関連付ける (OpenTelemetry などの標準を使用)。","correlation/trace id 付きの構造化 (JSON) ログを出力する。自由記述のログは検索を困難にする。","カーディナリティの高いラベルを避ける。カーディナリティの爆発とコストを制御する。","SLO を定義し、エラーバジェットを追跡する。オブザーバビリティを業務目標に結び付ける。"],"level":"senior"},{"id":"alerting-strategy","title":"アラート戦略 (低ノイズ、対処可能)","category":"運用","summary":"良いアラート戦略は、実際に対処可能な状況でのみ人を起こす。ノイズはアラート疲れと燃え尽きを招く。","points":["症状ではなく影響とユーザー体験 (SLO 違反) に対してアラートを出す。メトリックの変動ごとに呼び出さない。","すべてのアラートには明確な担当者、条件、ランブックが必要。対処が定義されていないアラートには価値がない。","しきい値にはヒステリシスと継続時間 (for: 5m) を使用する。瞬間的なスパイクでアラートが発火しないようにする。","呼び出し (paging) と通知 (チケット/メール) を分ける。即時の対応が必要なものだけで呼び出す。","アラートを定期的に見直す。常に発火して無視されているものは修正するか削除する。","バックアップの失敗、ディスク満杯、レプリケーションの停止などの静かな障害を常にカバーする。"],"level":"senior"},{"id":"dr-testing","title":"DR/フェイルオーバー訓練の規律","category":"バックアップと HA","summary":"災害復旧計画は、定期的で現実的な訓練で検証されて初めて信頼できる。テストされていない計画は単なる仮定。","points":["フェイルオーバーとリストアの訓練を予定し、定期的に実施する。年に一度見直すだけの紙の計画では不十分。","訓練のたびに実際の RTO と RPO を測定する。目標との差を報告し、改善する。","計画的フェイルオーバーは実際のトラフィックがある本番同等の環境でリハーサルする。スタンバイを起動・停止するだけで済ませない。","リージョンの喪失、ディスク障害、データ破損などのシナリオを game day でシミュレーションする。","訓練のたびに得られた教訓をランブックに記録する。勘で覚えている手順を自動化に置き換える。"],"level":"expert"},{"id":"blue-green-deploy","title":"ブルーグリーン / ゼロダウンタイムデプロイ","category":"運用","summary":"ブルーグリーンとカナリアのデプロイは、新バージョンを旧バージョンと並行して稼働させ、トラフィックを段階的に移すことで、ダウンタイムとリスクを最小化する。","points":["2 つの本番環境 (blue/green) を維持する。新バージョンを待機中の環境にデプロイして検証し、その後トラフィックを一度に切り替える。","問題が発生したら、直ちにトラフィックを旧環境に戻す。ロールバックに再デプロイを必要としないようにする。","カナリアでは、トラフィックのわずかな割合を新バージョンに送り、メトリックを監視しながら段階的に増やす。","データベーススキーマをデプロイから切り離す: 両方のコードバージョンが同じスキーマで動作する必要がある (expand-contract)。","ヘルスチェックと自動ロールバックのしきい値を事前に定義する。人による手動の判断を待つ時間を短縮する。"],"level":"senior"},{"id":"expand-contract","title":"後方互換のスキーマ変更 (expand-contract)","category":"設計","summary":"expand-contract パターンは、スキーマ変更を追加 (expand)、移行、最後に古いものの削除 (contract) に分割し、ゼロダウンタイムでの移行を可能にする。","points":["まず expand: 新しい列/表を、古いものを壊さずに後方互換な方法 (NULL 許可またはデフォルト値付き) で追加する。","dual-write または dual-read を使い、アプリケーションが旧スキーマと新スキーマの両方で動作するようにデプロイする。","データを新しい構造にバックグラウンドで小さなバッチで移行して検証する。単一の巨大な移行でロックしない。","すべてのインスタンスが新バージョンに移行し、検証が完了してから contract する: 古い列/コードを削除する。","各ステップを別々のデプロイで行う。「追加と旧の削除を同時に」は決して行わない。そうするとロールバックが不可能になる。","NOT NULL などの制約は、データの一貫性が取れてから最後に追加する。"],"level":"expert"},{"id":"secrets-management","title":"シークレット管理 (パスワード/キー)","category":"セキュリティ","summary":"データベースのパスワード、API キー、接続文字列はコードや構成に埋め込んではならない。中央のシークレットマネージャーで安全に保管し、ローテーションするべき。","points":["シークレットをコード、リポジトリ、env ファイル、イメージに埋め込まない。Vault、AWS Secrets Manager、KMS などのシークレットストアを使用する。","シークレットは実行時にアプリケーションに注入する。平文でディスクに残さない。","パスワードとキーを定期的にローテーションする。可能な場合は短命で自動生成される認証情報を使用する。","アクセスは最小権限と監査ログで付与する。誰がいつどのシークレットにアクセスしたかを追跡できる必要がある。","コードベースで漏えいしたシークレットをスキャンする (git-secrets、trufflehog)。漏えいしたシークレットは直ちに無効化してローテーションする。","人によるアクセスは、個人に紐づく恒久的なものではなく、一時的かつ承認ベース (just-in-time) にする。"],"level":"senior"},{"id":"cost-optimization","title":"クラウドのコスト最適化","category":"運用","summary":"クラウドデータベースのコストは、適正サイジング、ストレージの階層化、未使用リソースの整理によって、性能を犠牲にせずに大幅に削減できる。","points":["インスタンスは実際の使用状況のメトリックに基づいてサイジングする。使用率が継続的に低いサーバーはダウンサイズする (適正サイジング)。","予測可能なベースライン負荷にはリザーブドキャパシティ/Savings Plans を使用する。変動する負荷はオンデマンドのままにする。","コールドデータを安価なストレージ階層に移動する。ホットデータとめったにアクセスされないデータを分ける。","未使用のリソースを整理する: 孤立したスナップショット、アイドルのレプリカ、放置されたテスト用データベースはコストの漏れ。","タグでコストを担当者に割り当て、予算アラートを設定する。想定外のコストは月末ではなく即座に把握する。","バックアップの保持期間とレプリカ数を業務上の必要性に照らして見直す。過剰はリスクでありコストでもある。"],"level":"senior"},{"id":"multi-tenancy","title":"マルチテナント設計","category":"設計","summary":"マルチテナントシステムでは、分離モデル (共有テーブル、別スキーマ、別データベース) はセキュリティ、コスト、スケーラビリティの間の意図的なトレードオフ。","points":["分離モデルを選ぶ: 共有テーブル (tenant_id)、テナントごとのスキーマ、またはテナントごとのデータベース。それぞれコストと分離のバランスが異なる。","共有モデルでは、すべてのクエリに tenant_id のフィルタを適用する。行レベルセキュリティ (RLS) でエンジンレベルで漏えいがないことを保証する。","関連するインデックスでは tenant_id を先頭に置く。テナントをまたぐスキャンとホットスポットを防ぐ。","noisy neighbor 効果に対してリソースの上限とクォータを適用する。1 つのテナントが他のテナントのリソースを枯渇させてはならない。","大規模またはプレミアムのテナントを別スキーマ/データベースに移す経路 (テナント移行) を最初から設計する。","バックアップ、削除、データのポータビリティをテナント単位で考える。KVKK/GDPR の削除要求に応えられる必要がある。"],"level":"expert"},{"id":"time-series-design","title":"時系列データの設計","category":"設計","summary":"時系列データは書き込み量が多く、時間ベースのクエリパターンを持つため特殊。日付ベースのパーティショニング、ロールアップ、保持ポリシーで設計するべき。","points":["タイムスタンプベースの RANGE パーティショニングでデータを分割する。古いデータはパーティションの DROP で低コストにパージする。","生データをそのまま蓄積するのではなく、一定間隔のサマリー (ロールアップ/continuous aggregate) を生成する。クエリはサマリーに対して高速に実行させる。","インデックスでは時刻とタグ (tag/source) の要素を先頭に置く。典型的なクエリパターンは「特定のソース、特定の範囲」。","適切なツールを選ぶ: 大量データでは、TimescaleDB や ClickHouse などの時系列エンジンがリレーショナルエンジンよりはるかに効率的な場合がある。","保持ポリシーを最初から定義する。生データは短く、集計データは長く保持する。","時刻は常に UTC で保存する。ローカル時刻と夏時間の変化はクエリ層で処理する。"],"level":"senior"},{"id":"event-sourcing","title":"イベントソーシング / CQRS の基本","category":"設計","summary":"イベントソーシングは状態ではなく、状態を変更するイベントを記録する。CQRS は読み取りと書き込みのモデルを分離し、それぞれが独立してスケールできるようにする。","points":["現在の状態を上書きするのではなく、変更不可のイベントストリームを蓄積する。現在の状態はイベントを再生して導出する。","CQRS では、書き込みモデル (コマンド) と読み取りモデル (クエリ) を分離する。読み取り側は非正規化されたプロジェクションで高速化する。","イベントスキーマをバージョン管理し、後方互換を保って進化させる。古いイベントは決して削除せず、upcasting で新しいバージョンに変換する。","読み取りプロジェクションは結果整合性になることを受け入れ、その遅延を設計で考慮する。","長いイベントストリームを毎回最初から再生するコストを避けるため、スナップショットを取得する。","このパターンはどこでも使うのではなく、監査証跡、複雑な業務ルール、時間経過に伴う履歴が必要なドメインで使用する。それがもたらす複雑さを過小評価しない。"],"level":"expert"},{"id":"data-retention","title":"データ保持とアーカイブのポリシー","category":"運用","summary":"すべてのデータを永久に保持するわけではない。法令、業務、コストの要件に基づいて定義された保持とアーカイブのポリシーは、コンプライアンスと性能の両方をもたらす。","points":["データの種類ごとに業務および法令 (KVKK/GDPR) の要件に基づいて保持期間を定義する。漠然とした「念のため保持する」はポリシーではない。","期限切れのデータは自動的にアーカイブまたは削除する。手動のクリーンアップに任せない。忘れられている間に表が肥大化する。","ホットデータは高速ストレージに、アーカイブは安価/コールドストレージに置く。アクセス頻度で階層化する。","個人データの削除/匿名化の要求 (削除権) に対応する仕組みを最初から設計する。","アーカイブしたデータは必要なときに取り出してクエリできる状態に保つ。アーカイブがアクセス不能を意味してはならない。","削除を監査ログに記録する。何が、いつ、なぜ削除されたかを追跡できる必要がある。"],"level":"senior"},{"id":"change-management","title":"変更管理と本番環境の安全性","category":"運用","summary":"本番データベースへのすべての変更は、レビューされ、元に戻せて、追跡可能であるべき。統制されていない手動の介入はダウンタイムの最も一般的な原因。","points":["本番環境でアドホックな DDL/DML を手作業で実行しない。すべての変更はピアレビューされた移行またはスクリプトを経由するべき。","変更はロールバック計画を用意したうえでトラフィックの少ない時間帯に適用する。計画なしに本番環境に触れない。","リスクの高いコマンドは、まず実際のデータ量を持つ本番同等の環境でリハーサルする。所要時間とロックの影響を測定する。","本番環境へのアクセスを制限して監査する: 誰がいつどのコマンドを実行したかをログに記録する必要がある (just-in-time アクセス)。","削除/更新の前に WHERE 句と影響を受ける行数を確認する。トランザクション内で実行し、まず SELECT で確認する。","変更は変更カレンダーに登録して事前に周知する。予告なしの本番変更で他チームを驚かせない。"],"level":"senior"}]},"guide/best-practices-3.json":{"topics":[{"id":"plan-reading-expert","title":"実行計画の読み方","category":"パフォーマンス","summary":"実行計画はオプティマイザの推定値と選択した物理演算子を示す。ボトルネックは推定行数と実際の行数の乖離に潜んでいる。","points":["アクセス方法を区別する: Full/Table Scan は大きな表での広範な読み取り、Index Seek/Range Scan は選択性の高い述語、Index Full Scan は順序付きの読み取り用。Rows Removed by Filter や述語/アクセスの分離は、どこで選択性が失われているかを示す。","結合方法をワークロードに合わせる: Nested Loop は小さな外部集合 + インデックス付きの内部集合に最適、Hash Join は大規模な等価結合、Merge Join は事前にソートされた 2 つの集合に適する。誤った選択は通常、悪いカーディナリティ推定の結果。","カーディナリティ推定の誤りを探す: EXPLAIN ANALYZE (PG)、DBMS_XPLAN ALLSTATS LAST (Oracle)、SET STATISTICS PROFILE (MSSQL) で推定行数と実際の行数を比較する。10 倍を超える乖離は、プランの選択が根本的に誤っている可能性を示す。","プランは実際のコストで読む: 最も時間/論理読み取り (logical reads、buffers) を消費している演算子を見つける。オプティマイザの「コスト」単位は推定値であり、実際のボトルネックではない。","spill/一時領域の警告を捉える: メモリに収まらずディスクにあふれる Hash/Sort 演算子 (PG の 'Sort Method: external merge'、MSSQL のプラン内の SpillToTempDb を伴う Sort/Hash Warning) は work_mem/ソート領域の不足を示す。","演算子ツリーは内側から外側へ、下から上へ読む: 内側のノードが先に実行され、行は上へ流れる。演算子ごとの総コストは loops と実際の時間を掛けて算出する。"],"level":"expert"},{"id":"parameter-sniffing-deep","title":"パラメータスニッフィングとバインドピーク","category":"パフォーマンス","summary":"オプティマイザは最初の呼び出しのパラメータ値に基づいてプランを作成しキャッシュする。分布の異なる後続の値がそのプランを引き継ぐと、性能が劇的に変わることがある。","points":["症状を見極める: 同じクエリがあるパラメータでは高速で、別のパラメータでは非常に遅い。キャッシュされたプランが非典型的な「最初の」値でコンパイルされたことを示す。","分布の偏った列ではリスクが高い。ヒストグラムはオプティマイザを値に敏感にする一方、単一のキャッシュされたプランは値に無関係なままであり、この緊張関係が問題の原因。","MSSQL では、OPTION (RECOMPILE) は実行のたびにプランを作成し、OPTIMIZE FOR UNKNOWN は平均密度に基づくバランスの取れたプランを選び、OPTIMIZE FOR (@p = value) は典型的な値を固定する。","Oracle では、適応カーソル共有 (adaptive cursor sharing) と bind-aware カーソルが偏った値に対して異なるプランを生成する。PG では、custom プランと generic プランの選択を plan_cache_mode で制御する。","恒久的な対策としては、値ごとにプランを分ける: 文の分割、フィルタ選択/部分インデックス、または非常に非典型的な値のための専用のアクセスパスを設計する。","OLTP では、過剰な RECOMPILE は CPU とコンパイル (ハードパース) のコストを増やす。頻繁に実行されるクエリでは測定してバランスを保つ。"],"level":"expert"},{"id":"plan-stability","title":"プランの安定性: ベースライン、ヒント、プランガイド","category":"パフォーマンス","summary":"重要なクエリの検証済みプランを固定し、統計/バージョンの変更時の予期しないプランの後退を防ぐために、エンジン固有の永続化の仕組みを使用する。","points":["Oracle では、SQL Plan Baselines (SPM) で承認済みのプランを固定する。新しいプランは「承認 (accepted)」されるまで候補として収集されるだけで、evolve によって制御された形で検証される。","MSSQL では、Query Store でプランの後退を検出し、'Force Plan' で既知の良好なプランを強制する。Automatic Plan Correction でこれを自動化できる。","PostgreSQL には組み込みのプラン固定機能がない。安定性は pg_hint_plan 拡張、またはクエリの書き換え、拡張統計、インデックス設計によって得る。","ヒントは最後の手段として、理由とコメントを付けて使用する。ヒントは物理スキーマとデータ分布を前提としており、それらが変わると有害になる。","ベースライン/強制プランの一覧を定期的に監査する。固定したプランはデータの増加とともに最適性を失うことがあるため、「安定しているが遅い」という罠に陥らない。","バージョンアップグレードの前に重要なクエリのプランを取得する。オプティマイザの挙動の変化に対する安全網としてベースラインを準備する。"],"level":"expert"},{"id":"latch-mutex-contention","title":"ラッチ、mutex、スピンロックの競合","category":"パフォーマンス","summary":"ラッチ/mutex はメモリ上の構造を保護する軽量ロック。高い同時実行性のもとでは、それらの競合がスピンロックのループで CPU を消費し、スケーリングが止まる。","points":["ロックとラッチを区別する: ロックは論理データ (行/表) をトランザクションの間保護し、ラッチは物理的なメモリ構造 (バッファ、ハッシュチェーン) をマイクロ秒単位で保護する。診断方法も異なる。","Oracle では、'cache buffers chains' のラッチ競合は通常ホットブロックを示す。頻繁に読まれる小さな表や、単調増加するインデックスの先端 (右端インデックス) がよくある原因。","連番で増加するキー (identity/sequence) での挿入は最終ページ/ブロックの競合 (ホットページ、PAGELATCH) を引き起こす。ハッシュパーティショニング、リバースキーインデックス、またはランダム化したキーで分散する。","MSSQL では、スピンロックの統計と PAGELATCH_* 待機を監視する。tempdb の割り当て競合には、複数のデータファイルと適切な tempdb 構成を使用する。","スピンロックの競合は、高い CPU と低いスループットとして現れる。対策はコード/アーキテクチャのレベルで競合を減らすことであり、ハードウェアの追加はしばしば状況を悪化させる。","NUMA を意識した設計と接続数の制限 (プーリング) はラッチの競合を減らす。過剰な並列処理はラッチの負荷を増やすことがある。"],"level":"expert"},{"id":"wait-event-methodology","title":"待機イベント分析の方法論","category":"パフォーマンス","summary":"性能は推測ではなく、システムがどこで待機に時間を費やしているかを測定して管理する。トップダウンの待機分析は、ボトルネックを体系的に絞り込む科学的な方法。","points":["DB time を構成要素に分解する: CPU で費やされた時間と待機時間を分ける。最も大きな構成要素から始め、マイクロ最適化に流されない。","上位の待機イベントを特定する: Oracle では ASH/AWR と 'Top Wait Events'、PG では pg_stat_activity + pg_wait_sampling、MSSQL では sys.dm_os_wait_stats と Query Store を使用する。","待機クラスを解釈する: I/O 待機はストレージ/プラン、ロック待機は同時実行性の設計、ラッチ待機はホットスポット、ネットワーク/コミット待機は構成の問題を示す。","セッション/クエリのレベルまで掘り下げる: 総待機から始め、最も寄与している SQL、そしてその SQL のプランへと進んで原因を切り分ける (ドリルダウン)。","測定をワークロードの時間帯に結び付ける: 累積カウンタは 2 時点間の差分 (デルタ) を取る。合計値は誤解を招き、重要なのはレートと時間間隔。","アイドル/無害な待機をノイズとして除外する。すべての待機が問題なのではなく、重要なのはユーザーの応答時間に寄与するフォアグラウンドの待機。"],"level":"expert"},{"id":"plan-regression-detection","title":"実行計画の後退の検出","category":"パフォーマンス","summary":"急に遅くなったクエリは、通常コードの変更ではなくプランの変更が原因。後退を事前に検出するほうが、事後の火消しよりも安上がり。","points":["プランの履歴を保持して比較する: MSSQL Query Store と Oracle AWR/SQL Monitor で、同じ sql_id/query_hash のプランの変化と所要時間/リソースの傾向を追跡する。","後退のきっかけを特定する: 統計の更新、データ量の増加、バージョンアップグレード、パラメータの変更、削除されたインデックスが最も一般的な原因。","自動アラートを設定する: プランハッシュが変わり、平均所要時間/論理読み取りがしきい値を超えたときにアラートを出す。累積ではなく実行ごとのメトリックを追跡する。","迅速なロールバックの経路を用意する: Force Plan (MSSQL) または SQL Plan Baseline (Oracle) で既知の良好なプランを一時的に固定し、根本原因は後で修正する。","統計に起因する後退では、ロックされた/現在の統計とヒストグラムの鮮度を調べる。自動統計収集が重要な時間帯に予定されている場合がある。","アップグレードの前に回帰テストを実施する: 代表的なワークロードを旧オプティマイザと新オプティマイザで再生し、プランの差異を報告する (Oracle SPA のようなアプローチ)。"],"level":"expert"},{"id":"mvcc-vacuum-internals","title":"MVCC と vacuum/undo の内部構造","category":"内部構造","summary":"MVCC は古い行バージョンを保持することで読み取りと書き込みのブロッキングを防ぐ。これらのバージョンをどのように、どこに保持するか (undo か表の内部か) がメンテナンス戦略を決める。","points":["PostgreSQL では、古いバージョンはデッドタプルとして表自体の中に残る。VACUUM がそれらを除去し、そうしないと肥大化とインデックスの増大が発生する。","Oracle と MySQL/InnoDB は古いバージョンを undo/ロールバックセグメントに保持する。長時間実行の読み取りが undo を使い果たすと、'ORA-01555 snapshot too old' などのエラーが発生する。","autovacuum をワークロードに合わせて調整する: 更新/削除の多い表では scale factor を下げ、cost delay を減らす。負荷の高い表には表単位の設定を与える。","可視性マップを健全に保つ。インデックスオンリースキャンと凍結タプルの追跡はこれに依存しており、放置すると性能が低下する。","トランザクション ID の周回リスクを監視する: PG では datfrozenxid/age のメトリックを追跡し、業務時間中に積極的/周回防止 (anti-wraparound) の vacuum が始まらないようにする。","HOT (Heap-Only Tuple) 更新を促す: インデックス付きの列を変更しない更新は、インデックスを増やさずにその場で行われる。適切な fillfactor がこれを支える。"],"level":"expert"},{"id":"wal-redo-log-mechanics","title":"WAL/redo/トランザクションログの仕組み","category":"内部構造","summary":"耐久性は、データページがディスクに書き込まれる前に変更をログに書き込むことで実現される。ログストリームのレートとサイズが耐久性と書き込み性能の両方を決める。","points":["ログ先行書き込み (write-ahead) の原則を理解する: コミットが返るには、関連するログレコードが永続ストレージ上にあれば十分。ダーティなデータページは後で遅延して書き込まれる。","グループコミットとログフラッシュの挙動を調整する: PG では commit_delay/synchronous_commit、Oracle ではログライターの挙動で、fsync の頻度とワークロードの耐久性の要件のバランスをとる。","ログの生成レート (WAL/redo の生成) を監視する。急な増加は、一括更新、チェックポイント後のフルページイメージ (full_page_writes/FPI)、またはインデックスのメンテナンスを示し、DR の遅延を増やす。","ログはリカバリだけでなくレプリケーションと CDC の情報源でもある。論理レプリケーションと WAL シッピングはこのストリームから供給されるため、それに合わせてアーカイブ/クリーンアップのポリシーを設計する。","ログディスクをデータディスクから分離し、低レイテンシのストレージに配置する。ログの書き込みはシーケンシャルでレイテンシに敏感であり、コミットのスループットはそれに直接依存する。","制御されないログの増加に備える: MSSQL では正しい復旧モデルと定期的なログバックアップを使用し、PG ではアーカイブ/レプリケーションスロットが遅れていないことを確認する。"],"level":"expert"},{"id":"buffer-pool-management","title":"バッファ/共有プールの管理と eviction","category":"内部構造","summary":"バッファプールはホットデータをメモリに保持してディスク I/O を減らす。どのページをいつ追い出すかを決めるアルゴリズムが、ヒット率と安定性を左右する。","points":["バッファキャッシュヒット率だけを目標にしない。高い比率でも物理読み取りのレイテンシを隠していることがあるため、I/O の絶対量と待機時間も確認する。","eviction のアルゴリズムを理解する: 純粋な LRU がシーケンシャルスキャンで汚染されるのに対し、PG は clock-sweep、Oracle は touch-count/LRU の変種、InnoDB は midpoint insertion の LRU を使用する。","単発の大規模スキャンがホットデータをプールから追い出す (キャッシュ汚染) のを防ぐ。別のバッファプール、またはスキャンに配慮したアクセス戦略で保護する。","ダーティページの割合と書き込み負荷を管理する: ダーティページが多すぎるとチェックポイント時に I/O のスパイクが生じ、書き込みが積極的すぎると不要な I/O が発生する。バランスを測定する。","メモリはワーキングセットに合わせてサイジングする。目標はデータ全体ではなく、アクティブにアクセスされる集合をカバーすることであり、過大なサイジングは効果が逓減する。","Oracle の共有プールでは、ライブラリ/ディクショナリキャッシュの競合と頻繁なハードパースを監視する。リテラル SQL ではなくバインド変数を使用すると共有プールの負荷が減る。"],"level":"expert"},{"id":"checkpoint-tuning","title":"チェックポイントのチューニング","category":"内部構造","summary":"チェックポイントはダーティページをディスクに書き込むことでリカバリ時間を短縮する。頻繁すぎるチェックポイントは I/O のピークを、少なすぎるチェックポイントは長いリカバリを生むため、このトレードオフを調整する必要がある。","points":["リカバリ時間と実行時の I/O のバランスをとる: まれなチェックポイントは書き込み負荷が少ない代わりにクラッシュリカバリが長くなり、頻繁なチェックポイントはその逆になる。","PG では checkpoint_timeout と max_wal_size でチェックポイントを時間的に分散させる。checkpoint_completion_target で書き込みを間隔全体に分散させ、I/O のピークを平準化する。","MSSQL の間接チェックポイント (target recovery time) は継続的なバックグラウンドの書き込みを提供する。急で大きなチェックポイントの波を防ぎ、レイテンシを予測可能にする。","チェックポイントの頻度をログ/WAL の生成レートと関連付ける。書き込みの多い期間には、時間トリガーではなくサイズトリガーが発動しているかを監視する。","full_page_writes (PG) はチェックポイント後の最初の変更時にページ全体をログに記録する。チェックポイントが頻繁すぎると WAL の量が膨らみ、DR とディスクのコストが増える。","'checkpoint sink' の症状を捉える: チェックポイント中の書き込みレイテンシの上昇と fsync の待機。ストレージのキューと分散を見直す。"],"level":"expert"},{"id":"statistics-strategy","title":"統計収集の戦略","category":"内部構造","summary":"オプティマイザの判断の質は統計の鮮度と解像度に依存する。サンプリング率、ヒストグラム、拡張統計がカーディナリティ推定を決める。","points":["サンプリング率はデータサイズと偏りに基づいて選ぶ: サンプルが小さすぎると偏った分布で誤った推定を生み、大きすぎると不要な収集コストが発生する。","ヒストグラムで偏りをモデル化する: PG の default_statistics_target、Oracle の FREQUENCY/HYBRID ヒストグラム、MSSQL の統計ヒストグラムは、頻出値や不均衡な値をオプティマイザに示す。","拡張統計で列間の相関を捉える: PG の CREATE STATISTICS (ndistinct/dependencies) と Oracle の拡張統計は、相互に依存する列での推定誤りを修正する。","収集のスケジュールをワークロードから切り離す: 自動統計/収集ジョブが重要な時間帯に実行されて I/O とプランの不安定さを引き起こすのを防ぐ。","急速に増加する表での古い統計のリスクを管理する。しきい値ベースの自動更新は遅れることがあるため、重要な表には手動/スケジュールによる収集を追加する。","統計の変更がプランの後退を引き起こしうることを理解する。重要な環境では統計をロックする (locked stats) か、pending publish で制御された形で公開する。"],"level":"expert"},{"id":"partition-pruning-join","title":"パーティションプルーニングとパーティション単位の結合","category":"スケール/アーキテクチャ","summary":"パーティショニングは表を分割するだけではない。本当の利点は、クエリが無関係なパーティションを読まないこと (プルーニング) と、結合がパーティションごとに並列に実行されること。","points":["パーティションキーは最も頻繁で選択性の高いフィルタに基づいて選ぶ。プルーニングはクエリの述語にパーティションキーが含まれる場合にのみ機能し、そうでない場合はすべてのパーティションがスキャンされる。","静的プルーニングと動的プルーニングを区別する: 定数の述語はコンパイル時に、バインド/結合の値は実行時に (runtime pruning) パーティションを除外する。それに合わせてプランを確認する。","パーティション単位の結合 (partition-wise join) では、両方の表を互換性のある方式で同じキーでパーティション化する。オプティマイザは大きな結合をパーティションごとの小さな結合に分解し、並列化する。","パーティションの数と粒度のバランスをとる: パーティションが多すぎるとメタデータとプランニングのコストが増え、少なすぎるとプルーニングが弱くなる。アクセスパターンに合わせてサイジングする。","ライフサイクル管理をパーティショニングと組み合わせる: 古いパーティションを DETACH/DROP またはアーカイブする。DELETE の代わりに、即時でログの少ないクリーンアップが可能になる。","キーを隠す関数/型変換や式はプルーニングを無効にすることを覚えておく。スキャンされるパーティションの数を EXPLAIN で確認する。"],"level":"expert"},{"id":"shard-key-selection","title":"シャードキーの選択とホットスポット","category":"スケール/アーキテクチャ","summary":"シャードキーは分散システムの命運を決める。悪い選択は負荷を単一のノードに集中させ (ホットシャード)、スケーリングを止め、シャードをまたぐクエリを高コストにする。","points":["負荷を均等に分散するカーディナリティの高いキーを選ぶ。カーディナリティの低いキーや時間的/単調増加のキーは負荷を単一のシャードに集中させ、ホットスポットを生む。","最も頻繁なクエリが単一のシャードで解決されるようにキーを設計する。シャードをまたぐ (scatter-gather) クエリはレイテンシと調整のコストを増大させる。","ハッシュシャーディングは負荷を均等にするが範囲クエリを分散させる。レンジシャーディングは範囲クエリに適するがホットスポットのリスクを高める。アクセスパターンに基づいて選ぶ。","consistent hashing でノードの追加/削除時の再分散を最小化する。固定の剰余ハッシュでは、ノード数が変わるとほぼすべてのデータが移動する。","リシャーディングの計画を最初から設計する。後からキーを変更するのは高コストでリスクが高いため、増加のシナリオを事前にモデル化する。","テナント/顧客で分割する場合は、巨大なテナント (whale) が単一のシャードを埋め尽くさないよう、専用のシャードまたはサブパーティショニング (分割) の戦略を用意する。"],"level":"expert"},{"id":"read-write-splitting","title":"読み書きの分離とレプリカのルーティング","category":"スケール/アーキテクチャ","summary":"読み取りをレプリカにルーティングすると書き込み側のプライマリの負荷が軽減する。ただし、レプリケーション遅延が一貫性の保証を損なうことがあるため、ルーティングは意図的に行う必要がある。","points":["読み取り負荷をレプリカに分散する場合は、レプリケーション遅延を継続的に監視する。古いレプリカはユーザーに古いデータを見せることがある。","read-your-writes (書き込んだユーザーが直後に読み取る) を必要とするフローはプライマリにルーティングするか、causal reads/トークンで最新のレプリカを保証する。","ルーティングはアプリケーションではなくインフラ層で行う: プロキシ/ルーターで透過的に分散する (MySQL では ProxySQL。PG では PgBouncer が読み書きを分離しないため、Pgpool-II または読み取り/書き込みのエンドポイントを分けた HAProxy。MSSQL では application intent による読み取り専用ルーティング)。","遅延のしきい値を超えたレプリカはプールから外す。遅延の大きいレプリカに読み取りを送ると、「スケーリング」という錯覚のもとでデータの不整合が生じる。","分析/レポートなどの重く遅延を許容できる読み取りは専用のレプリカに隔離する。OLTP のレプリカをその負荷から守る。","フェイルオーバーのシナリオで読み取りのルーティングが自動的に更新されることをテストする。新しいプライマリを認識しないルーターはスプリットブレインまたはダウンタイムを引き起こす。"],"level":"expert"},{"id":"connection-pool-sizing","title":"コネクションプールのサイジングの計算","category":"スケール/アーキテクチャ","summary":"プールサイズは直感ではなく、リトルの法則とコア数に基づく計算で決める。接続が多すぎると競合とコンテキストスイッチによってスループットが低下する。","points":["リトルの法則を適用する: 必要な同時実行数 ≈ 要求レート (スループット) × 平均処理時間。目標の同時実行数は推測ではなく測定値から導き出す。","小さいプールのほうが速いことが多い: アクティブな接続が物理的なコア/ディスクの並列度を超えると、CPU のコンテキストスイッチとラッチの競合がスループットを下げる。","大まかな出発点として、コア数に近い数の接続のコアプールを使用し (例: PgBouncer の背後に少数の実接続)、負荷をかけて測定しながら調整する。","アプリケーション側のプールはデータベースの max_connections と併せて計画する。N 個のアプリケーションインスタンス × プールサイズがデータベースの上限を超えてはならない。","PG のように接続ごとのプロセスコストが高いエンジンでは、PgBouncer/トランザクションプーリングを使用する。すべての接続がメモリとスケジューリングのコストを伴う。","プールの飽和、キューの待機時間、タイムアウトを監視する。継続的に増えるキューはボトルネックまたはサイズ不足のシグナルであるため、やみくもにプールを大きくしない。"],"level":"expert"},{"id":"lock-escalation-deadlock","title":"ロックエスカレーションとデッドロック防止のパターン","category":"信頼性","summary":"多数の行ロックはテーブルロックへとエスカレーションし、同時実行性を損なうことがある。デッドロックは一貫しないロック順序の回避可能な結果。","points":["ロックエスカレーションを引き起こす大規模な一括操作を分割する (バッチ/チャンク)。単一のトランザクションで数百万行をロックすると、エスカレーションとブロッキングが発生する。","デッドロックを防ぐ基本のパターンは一貫したロック順序: すべてのコードパスが同じ順序でリソースをロックする必要がある (例: 主キーの順)。","トランザクションを短く保ち、単一のアトミックな作業単位を行う。ユーザー操作、リモート呼び出し、長い計算を含むトランザクションは不必要に長くロックを保持する。","分離レベルは意図的に選ぶ: 不必要に高い分離は過剰なロックを、不必要に低い分離は異常を引き起こす。MVCC エンジンでは読み取りはすでにほとんどのロックを回避している。","デッドロックのグラフ/トレースを収集する (MSSQL のデッドロックグラフ、PG の log_lock_waits、Oracle のトレース)。victim をログに記録し、繰り返し発生するパターンを根本原因まで追跡する。","リトライのロジックを実装する: デッドロックの victim となったトランザクションを冪等にリトライする。設計上避けられない競合に対する安全網となる。"],"level":"expert"},{"id":"long-transaction-bloat","title":"長いトランザクションと肥大化/undo の管理","category":"信頼性","summary":"オープンしたままの長いトランザクションは、MVCC エンジンで古いバージョンのクリーンアップを妨げ、肥大化、undo の逼迫、性能の崩壊という連鎖を引き起こす。","points":["長時間実行/オープンしたままのトランザクションを監視しアラートを出す: PG の idle in transaction や Oracle のアクティブな undo を保持する長いクエリは、クリーンアップ (vacuum/undo の回収) を止める。","PG では、単一の長いトランザクションが VACUUM によるデッドタプルの除去を妨げる。表とインデックスが肥大化し、1 つの「ゾンビ」セッションがデータベース全体を遅くすることがある。","idle_in_transaction_session_timeout と statement_timeout で滞留したトランザクションを自動的に終了させる。アプリケーションのリークに対する防衛線を築く。","Oracle/InnoDB では、長い読み取りが undo を使い果たし 'snapshot too old' を発生させる。undo 領域/保持期間はワークロード内で最も長いクエリに合わせてサイジングする。","バッチジョブは短いコミット間隔で分割する。単一の巨大なトランザクションは undo/WAL を蓄積し、ロールバック時間を危険なほど長くする。","既存の肥大化を測定して回収する: pgstattuple で肥大化を測定し、VACUUM FULL/pg_repack またはオンラインの再編成で領域とインデックスの効率を取り戻す。"],"level":"expert"},{"id":"dr-game-day","title":"DR 訓練 (game day) と RPO/RTO の検証","category":"信頼性","summary":"テストされていないバックアップとフェイルオーバーの計画は仮定にすぎない。DR の能力は、現実的な訓練で RPO/RTO を測定して初めて証明される。","points":["RPO と RTO を業務要件から導き出し、実際に測定する: バックアップ/レプリケーションの遅延が RPO を、リカバリ + 検証の時間が RTO を決める。目標と実際を比較する。","バックアップを定期的かつ自動的にリストアする: 一度もリストアされていないバックアップはシュレーディンガーのバックアップ。リストアテストがなければ、バックアップが存在するという主張は検証されていない。","game day の訓練を、現実的な障害シナリオ (プライマリの喪失、リージョンの停止、データ破損) を用いて本番に近い環境で計画する。","フェイルオーバーとフェイルバックの手順をエンドツーエンドで実行する。DNS/接続のルーティング、アプリケーションの再接続、レプリカの昇格を含める。","ポイントインタイムリカバリ (PITR) の能力を証明する: 論理的な破損のシナリオで、ログアーカイブ + フルバックアップにより特定の時点に戻れることをテストする。","すべての訓練から、測定した RTO/RPO、想定外の事象、アクション項目を導き出す。ランブックを更新し、次の訓練で改善を確認する。"],"level":"expert"},{"id":"observability-slo","title":"オブザーバビリティと SLO/ゴールデンシグナル","category":"信頼性","summary":"データベースを業務への影響で管理するには、ゴールデンシグナル (レイテンシ、トラフィック、エラー、飽和度) を SLO に結び付け、エラーバジェットで優先順位を付ける。","points":["4 つのゴールデンシグナルを監視する: レイテンシ、トラフィック (スループット)、エラー率 (errors)、飽和度 (saturation)。根本原因まで掘り下げなくても健全性を要約できる。","レイテンシは平均ではなくパーセンタイル (p95/p99) で測定する。平均はテールレイテンシと最悪のユーザー体験を隠す。","SLO とエラーバジェットを定義する。低レベルのメトリックの変動ごとではなく症状 (SLO 違反) に対してアラートを出し、アラート疲れを防ぐ。","リソースに USE (Utilization, Saturation, Errors) メソッドを適用する: CPU、メモリ、ディスク I/O、コネクションプールの飽和を個別に観察する。","層をまたいで監視を関連付ける: クエリ -> 待機イベント -> リソースの飽和 -> 業務メトリックの連鎖を単一の時間軸で確認する。","メトリック + ログ + トレースを併せて構築する。メトリックだけでは「何が」に答えるのみで、ログ/トレースが「なぜ」に答える。それらがないと MTTR が長くなる。"],"level":"expert"},{"id":"least-privilege-roles","title":"最小権限とロールの設計","category":"セキュリティ","summary":"各アカウントが業務に必要な最小限の権限だけを持つことで、侵害時の影響範囲が狭まる。ロールは権限を直接付与する代わりに管理しやすい抽象化を提供する。","points":["権限はユーザーではなくロールに付与する。ロールは機能 (reader、writer、DDL、運用) ごとに設計し、直接の付与を避けてユーザーをロールに割り当てる。","アプリケーションのアカウントには必要なオブジェクトと操作の権限だけを与える。本番環境のアプリケーションアカウントに DDL、SUPERUSER/DBA、広範なスキーマ権限があってはならない。","人による管理者アクセスを個人に紐づけて監査する: 共有の管理者アカウントではなく、個人の ID + 必要時の権限昇格 (JIT/break-glass) アクセスを使用する。","PUBLIC/デフォルトの広範な権限を取り消す。デフォルト権限とスキーマレベルの制御を構成し、新しいオブジェクトにデフォルトの権限が漏れるのを防ぐ。","特権アカウントを定期的に見直す (アクセスの再認定)。未使用のアカウント、退職者のアカウント、過剰な権限を持つアカウントを定期的に整理する。","職務の分離を徹底する。同じ人物が本番環境を変更し、監査証跡も消去できてはならないため、監査の書き込みを別の権限で保護する。"],"level":"expert"},{"id":"encryption-decision","title":"暗号化の判断: 保存時、転送時、TDE","category":"セキュリティ","summary":"暗号化は脅威モデルに基づいて選ぶ。各層はそれぞれ異なる攻撃から保護し、キー管理は暗号化アルゴリズムよりも重要であることが多い。","points":["脅威を明確にする: 保存時 (ディスク/バックアップの盗難)、転送時 (ネットワークの盗聴)、アプリケーションレベル (DBA を含め誰にも見せない) はそれぞれ異なる保護であり、どれが必要かを判断する。","転送時については、クライアント-サーバー間の接続に TLS を強制する。証明書の検証を無効にしない。無効にすると中間者 (MITM) 攻撃に対して無防備になる。","保存時については、TDE とファイルシステム/ディスク暗号化の選択肢を比較する。TDE はデータファイルとバックアップを保護するが、メモリ上のデータや権限を持つ DBA のアクセスは保護しない。","最も機密性の高いフィールドには、アプリケーション/列レベルの暗号化、または Always Encrypted のようなクライアント側の方式を使用し、DBA でさえ平文を見られないようにする。","キー管理を重視する: キーはデータとは別の KMS/HSM に保管し、ローテーションとアクセス制御を計画する。キーが漏えいすれば暗号化は無意味になる。","性能と機能への影響を測定する: 暗号化された列ではインデックス作成/検索が制限され、TDE は CPU コストを増やす。判断は測定に基づくトレードオフとして行う。"],"level":"expert"},{"id":"audit-strategy","title":"監査戦略","category":"セキュリティ","summary":"監査証跡はセキュリティイベントとコンプライアンス要件の証拠となる。何を記録するか、証跡をどこに送るか、どれだけ保持するかが、ノイズと証拠のバランスを決める。","points":["監査対象を脅威とコンプライアンスから導き出す: 特権操作、ログイン/ログイン失敗、スキーマ (DDL) の変更、機密データへのアクセスを優先する。","すべてを記録するという罠に陥らない。過剰な監査は性能を低下させ、シグナルをノイズに埋もれさせるため、重要なイベントを選択的かつ目的を持って対象にする。","監査証跡は、本番の DBA が変更できない別の安全な出力先 (外部のログコレクター/SIEM) に書き込む。職務の分離によって証跡の改ざんを防ぐ。","エンジンの機能を活用する: Oracle の Unified/Fine-Grained Audit、MSSQL の SQL Audit、PG の pgAudit で詳細度を要件に合わせて調整する。","保持期間をコンプライアンス要件 (KVKK/GDPR/PCI-DSS など) に従って設定し、アーカイブ/クリーンアップのポリシーを自動化する。証跡の完全性を保つ。","証跡を収集するだけでなく、定期的に確認しアラートに結び付ける: 監査は死蔵されたアーカイブとしてではなく、異常を検知して対処につなげたときに初めて価値を生む。"],"level":"expert"}]},"guide/best-practices-4.json":{"topics":[{"id":"oracle-rac-cache-fusion","title":"Oracle RAC: Cache Fusion とインターコネクト","category":"Oracle","summary":"RAC では複数のインスタンスが同じデータベースを共有する。Cache Fusion はディスクを経由せず、インターコネクト経由でノード間でブロックを転送することで一貫性を維持する。","points":["インスタンスが別のインスタンスのバッファキャッシュにあるブロックを必要とする場合、Cache Fusion はプライベートインターコネクト経由で RAM から RAM へ転送する。ディスクに書き込んで読み戻す (disk ping) ことはしない。","Global Cache Service (GCS/LMS プロセス) はブロックの所有権とモード (共有/排他) を管理し、Global Enqueue Service (GES) はロックとエンキューを管理する。","すべてのブロックにはマスターノードがある。ブロックの所在は Global Resource Directory で追跡され、アクセスの集中度に基づいて DRM (Dynamic Resource Mastering) で再マスタリングできる。","インターコネクトには専用の低レイテンシのネットワークが必要。ジャンボフレーム (MTU 9000) と、必要に応じて RDMA/RoCE または InfiniBand を使用し、パブリックネットワークとは決して共有しない。","'gc buffer busy' と 'gc cr/current block busy' の待機イベントはホットブロックの競合を示す。シーケンスの CACHE の拡大、リバースキーインデックス、またはパーティショニングによる負荷の分散が有効な場合がある。","gc blocks lost の統計値が増え続ける場合は、インターコネクトでパケットロスが発生している。NIC、スイッチのバッファ、ソケットバッファのサイズ (rmem/wmem) を見直す。"],"level":"expert"},{"id":"oracle-rac-node-eviction","title":"Oracle RAC: ノードの eviction とスプリットブレイン","category":"Oracle","summary":"Clusterware はスプリットブレインを防ぐため、応答しないノードをクラスタから除外 (evict) する。ネットワークハートビート、ディスクハートビート、投票ディスクの過半数に基づいて判断する。","points":["CSSD は 2 つの別々のハートビートを監視する: インターコネクト経由のネットワークハートビート (misscount、デフォルト 30 s) と投票ディスク経由のディスクハートビート (disktimeout、デフォルト 200 s)。","スプリットブレインでは、存続するサブクラスタ (コホート) は投票ディスクの過半数で決まる。そのため投票ディスクの数は奇数 (3 または 5) であり、別々の障害グループに配置する必要がある。","eviction は通常、ノードの再起動、または再起動なしのフェンシング (スタックのみの再起動) によって行われる。目的は障害のあるノードが共有ストレージに書き込むのを止めること。","eviction のよくある原因: インターコネクトの喪失、高負荷下で CPU が割り当てられない CSSD、投票ディスクの I/O レイテンシ、OCR/投票ディスクへのアクセスの問題。","根本原因の分析では、ocssd.log、CSSD のトレース、アラートログ、OS のメッセージを CHM/oclumon (Cluster Health Monitor) のデータと併せて確認する。"],"level":"expert"},{"id":"oracle-asm-redundancy-rebalance","title":"Oracle ASM: ディスクグループの冗長性とリバランス","category":"Oracle","summary":"ASM はディスクグループ内のディスクにデータをストライピングし、障害グループ単位でミラーリングすることでデータを保護する。ディスクの追加または削除時にはエクステントを自動的にリバランスする。","points":["冗長性レベル: EXTERNAL (ミラーリングなし、保護はストレージアレイに任せる)、NORMAL (2 コピー、ディスク 1 本の喪失に耐える)、HIGH (3 コピー、2 本の同時喪失に耐える)。","ASM はディスクではなく障害グループをミラーリングする。プライマリエクステントはある障害グループに、ミラーコピーは別の障害グループに置かれるため、障害グループ全体が故障してもデータは失われない。","ディスクの追加または削除はエクステントを再分散するリバランスを引き起こす。ASM_POWER_LIMIT (0-1024) で速度とリソース消費のバランスを設定する。","AU (Allocation Unit) のサイズはディスクグループの作成時に設定する。大規模なデータベースでは 4 MB の AU が I/O 効率を向上させる。","投票ディスクと OCR は normal/high 冗長性のディスクグループに格納できる。quorum 障害グループは投票ディスク専用で、データエクステントは保持しない。"],"level":"expert"},{"id":"oracle-data-guard-modes","title":"Oracle Data Guard: スタンバイの種類と保護モード","category":"Oracle","summary":"Data Guard は redo をスタンバイに転送することで災害復旧を提供する。フィジカル/ロジカルスタンバイの選択と 3 つの保護モードが、データ損失と可用性のバランスを決める。","points":["フィジカルスタンバイはプライマリとブロック単位で同一のコピー (Redo Apply/MRP)。Active Data Guard を使用すると、オープンした状態で読み取り専用のクエリを実行できる。ロジカルスタンバイは redo を SQL に変換して適用し (SQL Apply)、異なる構造/インデックスを持つことができる。","Maximum Performance (デフォルト): redo は非同期 (ASYNC) で転送され、プライマリは確認応答を待たない。性能への影響はゼロだが、わずかなデータ損失リスクがある。","Maximum Availability: redo は同期 (SYNC/AFFIRM) で転送される。スタンバイに到達できない場合、プライマリは停止せず MAX PERFORMANCE の動作にフォールバックし、スタンバイ復帰時に再同期する。","Maximum Protection: 少なくとも 1 つのスタンバイが確認応答するまでプライマリはコミットしない。データ損失ゼロを保証するが、すべてのスタンバイを失うとプライマリは停止する。","Fast-Start Failover (FSFO) はオブザーバープロセスを使い、プライマリ障害時に自動でフェイルオーバーする。FastStartFailoverThreshold と同期転送により RPO=0 を目指す。","スタンバイの適用ラグは v$dataguard_stats と 'apply lag'/'transport lag' メトリクスで監視する。リアルタイム適用では redo がアーカイブされる前に適用される。"],"level":"expert"},{"id":"oracle-exadata-offload","title":"Oracle Exadata: Smart Scan とストレージインデックス","category":"Oracle","summary":"Exadata ではストレージセルがクエリ処理の一部を引き受け (オフロード)、関連データのみを DB ノードに返す。Smart Scan、ストレージインデックス、HCC により I/O が劇的に削減される。","points":["全表スキャンのクエリでは、Smart Scan がストレージセル内で述語フィルタリングと列プロジェクションを行う。ブロックではなく必要な行/列のみが DB ノードに返されるため、インターコネクトのトラフィックが減る。","Smart Scan はダイレクトパス読み取りでのみ動作し、バッファキャッシュから読み取るブロックや一部の操作では機能しない。効果は 'cell physical IO bytes eligible for predicate offload' と 'cell physical IO interconnect bytes returned by smart scan' 統計で測定する ('cell physical IO bytes saved by storage index' はストレージインデックスによる削減分のみを示す)。","ストレージインデックスは 1 MB のストレージリージョンごとに列の最小値/最大値をメモリに保持する。クエリ述語が範囲外であれば、そのリージョンは読み取らずにスキップされる (ネガティブインデックスのように動作する)。","ストレージインデックスは永続化されず、メモリ上にあり、セルの再起動時に再構築される。物理的に整列されたデータ (クラスタリング) はスキップ率を高める。","HCC (Hybrid Columnar Compression) は Compression Unit 内でデータを列単位に圧縮する。QUERY LOW/HIGH はクエリの多いデータ向け、ARCHIVE LOW/HIGH はアクセス頻度の低いアーカイブデータ向けで、高い CPU コストと引き換えに非常に高い圧縮率を実現する。"],"level":"expert"},{"id":"oracle-awr-ash-analysis","title":"Oracle AWR と ASH による性能分析","category":"Oracle","summary":"AWR は定期的に性能スナップショットを収集し、ASH はアクティブセッションを毎秒サンプリングする。両者を組み合わせ、待機イベントの観点から「時間がどこで消費されたか」に答える。","points":["デフォルトで AWR は 60 分ごとにスナップショットを取得し 8 日間保持する。2 つのスナップショット間の AWR レポートは、どの SQL と待機イベントが DB Time を消費したかを示す (Diagnostics Pack ライセンスが必要)。","分析は常に 'Top 10 Foreground Events by Total Wait Time' と DB Time から始める。個々の統計に埋もれず、そこで CPU・I/O・同時実行のバランスを確認する。","ASH は v$active_session_history を毎秒サンプリングし、短命で突発的な問題 (スパイク) を捕捉する。AWR では見逃される一時的なロック/ラッチの嵐を、SQL_ID とブロッキングセッション単位で明らかにする。","Average Active Sessions (AAS = DB Time / 経過時間) はシステム負荷を 1 つの数値で要約する。AAS が CPU コア数を超えていれば飽和を示す。","SQL チューニングでは、AWR の 'SQL ordered by Elapsed Time/Gets' セクションから最も高コストな SQL_ID を取り出し、ASH でその SQL がどのステップで待機しているかを確認し、SQL Monitor レポートで計画を行ごとに調べる。"],"level":"expert"},{"id":"oracle-scn-read-consistency","title":"Oracle の SCN と読み取り一貫性","category":"Oracle","summary":"System Change Number (SCN) はデータベースの論理クロックである。Oracle はクエリ開始時点の SCN に基づき undo から一貫性のあるイメージを構築し (読み取り一貫性)、読み取り側を書き込み側から分離する。","points":["SCN はコミットごとに単調増加し、redo/undo、制御ファイル、ブロックヘッダーに記録される。ブロックの最終変更 SCN がクエリ SCN より大きい場合、そのブロックは「ロールバック」される。","読み取り一貫性のため、Oracle は現在のブロックの CR (Consistent Read) コピーを作成し、undo を使ってクエリ開始 SCN まで戻す。これにより「読み取りは書き込みをブロックせず、書き込みは読み取りをブロックしない」。","undo が不足するか undo_retention を超えると、長時間実行クエリは 'ORA-01555 snapshot too old' となる。対処は undo 表領域の拡張、保存期間の調整、またはクエリの短縮。","文レベルの一貫性では SQL 文ごとに個別の SCN を使う。SERIALIZABLE または読み取り専用トランザクションでは、トランザクション開始時の単一の SCN をすべての文で維持する。","RAC では SCN がすべてのインスタンス間で同期される (Lamport または broadcast-on-commit)。グローバルな一貫性のため、SCN の進行はノード間で調整される。"],"level":"expert"},{"id":"postgres-patroni-failover","title":"PostgreSQL: Patroni による自動フェイルオーバー","category":"PostgreSQL","summary":"Patroni は PostgreSQL クラスタの状態を分散合意ストア (DCS) に保持し、リーダー選出と自動フェイルオーバーを提供する。watchdog によりスプリットブレインを防止する。","points":["クラスタの状態とリーダーロックは etcd/Consul/ZooKeeper などの DCS に保持される。リーダーは TTL 付きのロックを定期的に更新し、更新できなければロックが失効して新たなリーダー選出が始まる。","フェイルオーバー時、Patroni は最も新しいレプリカ (LSN が最大のもの) を選ぶ。新リーダーが昇格し、他のレプリカはそこに再接続する (reinitialize/rewind)。","watchdog (softdog) はハードウェアレベルの安全網で、旧リーダーが DCS との接続を失うとマシンをリセットし、2 つのノードが同時にリーダーになること (スプリットブレイン) を防ぐ。","maximum_lag_on_failover は、大きく遅延したレプリカがリーダーになりデータ損失を起こすことを防ぐ。synchronous_mode で RPO=0 を目指せるが、書き込みレイテンシは増加する。","クライアントはノードに直接接続せず、Patroni の REST ヘルスチェックを使う HAProxy、または VIP 経由で接続する。これによりリーダー変更時にトラフィックが自動的に新リーダーへルーティングされる。","DCS の過半数 (クォーラム) は必須で、3 または 5 メンバーの etcd クラスタを使う。DCS に到達できない場合、Patroni は安全側に倒し、現在のリーダーを読み取り専用に降格させることがある。"],"level":"expert"},{"id":"postgres-logical-replication-upgrade","title":"PostgreSQL: 論理レプリケーションによる無停止メジャーアップグレード","category":"PostgreSQL","summary":"論理レプリケーションはバージョンをまたいで行の変更を転送できるため、ほぼ無停止でのメジャーバージョンアップグレードを可能にする。旧バージョンと新バージョンはしばらく並行稼働する。","points":["論理レプリケーションは WAL から変更を論理的にデコードする (INSERT/UPDATE/DELETE)。物理レプリケーションと異なり、異なるメジャーバージョンや異なるプラットフォーム間でも動作する。","手順: 新バージョンに空のスキーマを作成し、旧バージョンに PUBLICATION、新バージョンに SUBSCRIPTION を定義する。まずテーブルがコピーされ (初期同期)、その後ライブの変更が流れ始める。","すべてのテーブルに REPLICA IDENTITY が必要。主キーのないテーブルで UPDATE/DELETE をレプリケートするには REPLICA IDENTITY FULL が必要で、ない場合はエラーになる。","DDL の変更は自動でレプリケートされず、シーケンスの現在値も引き継がれない。切り替え時に新バージョンでシーケンスを手動で進めないと、キーの競合が発生する。","切り替え時は旧バージョンに書き込むアプリケーションを短時間停止し、ラグがゼロになったら (pg_stat_replication で確認) アプリケーションを新バージョンに向ける。必要に応じて、迅速なロールバック用に逆方向のサブスクリプションを用意しておく。","制限事項: ラージオブジェクトと一部の DDL はレプリケートされない。wal_level=logical と十分な max_replication_slots/max_wal_senders の設定が必要。"],"level":"expert"},{"id":"postgres-pgvector-similarity","title":"PostgreSQL: pgvector による類似検索","category":"PostgreSQL","summary":"pgvector はベクトル埋め込みを格納し、近似最近傍 (ANN) 検索を行う。HNSW と IVFFlat のインデックスで精度・速度・メモリのトレードオフを決める。","points":["距離演算子はユースケースで選ぶ: <-> は L2 (ユークリッド)、<=> はコサイン、<#> は内積。インデックスはクエリと同じ演算子クラスを使う必要があり、そうでなければ使用されない。","HNSW は多層グラフを構築する。高い再現率と高速なクエリが得られるが、より多くのメモリを必要とし構築は遅い。m (接続数) と ef_construction で構築品質を、ef_search でクエリ時の精度を調整する。","IVFFlat はベクトルを lists 個のクラスタに分割し、クエリごとに probes 個のクラスタのみをスキャンする。メモリ使用量は少ないが、インデックスはデータのロード後に作成する必要がある (空のテーブルではクラスタに意味がない)。","IVFFlat では、100 万行までは lists ≈ rows/1000、100 万行超では ≈ sqrt(rows) から始める。probes を増やすと再現率は上がるがクエリは遅くなるため、このトレードオフは測定して調整する。","ANN は近似結果を返す。100% の正確性が必要な場合は、インデックスを使わない厳密なスキャンが必要。フィルタ付き (WHERE) 検索ではインデックスの再現率が低下しうるため、必要に応じて iterative scan や部分インデックスを検討する。","ベクトルの次元数と行数がメモリ要件を決める。構築中は maintenance_work_mem を十分大きく保つこと。そうでないと HNSW の構築がディスクに溢れ、非常に遅くなる。"],"level":"expert"},{"id":"postgres-citus-distributed","title":"PostgreSQL: Citus による分散スケーリング","category":"PostgreSQL","summary":"Citus は分散列でテーブルをシャードに分割してワーカーノードに分散し、PostgreSQL を水平スケールする。分散列の選択が性能を決める。","points":["コーディネーターノードがクエリを受け取り、分散列に基づいて該当シャードへルーティングする。ワーカーノードはシャードを格納し並列処理する。シャードは標準の PostgreSQL テーブル (ハッシュ範囲で分割) である。","分散列は大半のクエリと JOIN の共通フィルタにする (例: tenant_id)。同じ列値の行は同じシャードに入るため、JOIN と外部キーは同一ノード内でローカルに完結する (コロケーション)。","コロケーションは重要である。結合されるテーブル同士は、同じ分散列とシャード数で分散されていれば、ノード間のデータシャッフル (再パーティション) なしで実行される。","頻繁に全シャードと結合される小さなテーブルは参照テーブルにする。すべてのワーカーに完全にコピーされ、分散 JOIN のネットワークコストを排除する。","分散列を含まないクエリは全シャードにファンアウトし、高コストになる。マルチテナント SaaS では tenant_id でフィルタすることでクエリが単一シャードに絞られる (ルーター実行)。"],"level":"expert"},{"id":"postgres-timescaledb-hypertable","title":"PostgreSQL: TimescaleDB のハイパーテーブルと連続集約","category":"PostgreSQL","summary":"TimescaleDB は、時系列データを時間間隔のチャンクに自動分割するハイパーテーブルと、事前計算された連続集約によってスケールする。","points":["ハイパーテーブルは外部からは単一のテーブルに見えるが、内部では時間 (および任意で空間) 列でチャンクに分割されている。クエリは該当時間範囲のチャンクのみにアクセスする (チャンク除外)。","chunk_time_interval は、最もアクティブなチャンクがメモリ (shared_buffers) に収まるように設定する。小さすぎるとチャンク/計画のオーバーヘッドが過大になり、大きすぎると除外が効きにくくなる。","連続集約は増分リフレッシュされるマテリアライズドビューである。変更された時間バケットのみを再計算するリフレッシュポリシーにより、バックグラウンドで最新に保たれる。","リアルタイム集約では、連続集約がマテリアライズ済みの古いデータと生テーブル内の最新データを組み合わせ、クエリ時に最新の結果を返す。","古いチャンクは列指向圧縮で大幅に縮小できる。保持ポリシーは、一定期間より古いチャンクを drop_chunks で自動削除する (行単位の DELETE よりはるかに低コスト)。"],"level":"expert"},{"id":"postgres-vacuum-xid-wraparound","title":"PostgreSQL: VACUUM と XID 周回","category":"PostgreSQL","summary":"MVCC は不要な行バージョン (dead tuple) を残す。VACUUM はそれらを除去して行を「凍結」済みとし、32 ビットのトランザクション ID (XID) の周回によるデータ損失を防ぐ。","points":["PostgreSQL は 32 ビットの循環する XID を使い、すべての行バージョンに xmin が刻まれる。十分に古い行が凍結されていないと、XID 周回時に「過去」のトランザクションが「未来」にあるように見え、行が突然不可視になりうる。","autovacuum は 2 つの仕事をする: 通常のクリーンアップ (dead tuple、肥大化) と凍結。autovacuum_freeze_max_age に近づいたテーブルでは、autovacuum が無効でも必須の「周回防止」VACUUM が起動される。","周回が近づくと警告がログに記録される。上限に非常に近づくと、データベースはデータ損失を防ぐため新規書き込みを拒否して読み取り専用になり、対処は積極的な VACUUM (FREEZE) の実行となる。","最も古い未凍結 XID は pg_database.datfrozenxid と age() で監視する。長時間開いたままのトランザクション (idle in transaction) や未使用のレプリケーションスロットは VACUUM の進行を妨げ、肥大化と周回リスクを高める。","書き込み負荷が高いと autovacuum が追いつかず肥大化が起こる。autovacuum_vacuum_cost_limit を上げ、naptime を下げ、大きい/ホットなテーブルにはテーブル固有の autovacuum 設定を適用する。","VACUUM は通常、領域を OS に返却せず、再利用可能としてマークする。物理的な縮小には VACUUM FULL (テーブルをロック) または pg_repack (オンライン) が必要。"],"level":"expert"},{"id":"mysql-innodb-cluster","title":"MySQL: Group Replication と InnoDB Cluster","category":"MySQL","summary":"InnoDB Cluster は Group Replication に基づく過半数 (クォーラム) クラスタで、MySQL Router によりアプリケーションに単一の接続ポイントを提供して高可用性を実現する。","points":["Group Replication は Paxos ベースのグループ通信層を通じてトランザクションをグループに伝播する。トランザクションはグループの過半数 (クォーラム) が合意して初めてコミットされ、自動フェイルオーバーと一貫性を実現する。","シングルプライマリモード (デフォルト) では 1 ノードのみで書き込みが可能で、プライマリ障害時にグループが自動的に新プライマリを選出する。マルチプライマリモードではすべてのノードが書き込みを受け付けるが、競合 (certification) の処理がより複雑になる。","MySQL Router はクラスタのメタデータを読み取り、アプリケーションに 2 つのポートを提供する: 書き込みは現在のプライマリ (6446)、読み取りはレプリカ (6447) へ。フェイルオーバー時はアプリケーションの接続を変えずにルーティングが更新される。","過半数の喪失 (例: 3 ノード中 2 ノードの喪失) はグループをブロックする。スプリットブレインを防ぐためクラスタは新規書き込みを受け付けず、復旧は group_replication_force_members で手動で行う。","Group Replication には行ベースの binlog (ROW 形式)、GTID、InnoDB が必要。すべてのテーブルに主キーが必須で、ない場合ノードはクラスタに参加できない。","新規参加ノードは、まず既存のドナーからの状態転送 (分散リカバリ: clone プラグインまたは binlog) で同期し、その後ライブストリームに切り替わる。"],"level":"expert"},{"id":"mysql-semisync-replication","title":"MySQL: 準同期レプリケーション","category":"MySQL","summary":"準同期レプリケーションでは、プライマリがコミットを確認応答する前に、少なくとも 1 つのレプリカがトランザクションをリレーログに受信するまで待機し、データ損失を減らす。","points":["非同期レプリケーションでは、プライマリはレプリカを待たずにコミットを確認応答するため、プライマリがクラッシュすると未転送のトランザクションが失われる。準同期は少なくとも N 個のレプリカからの受信確認を待つ (rpl_semi_sync_source_wait_for_replica_count)。","AFTER_SYNC (デフォルト、推奨): プライマリはまずレプリカの確認応答を受け取り、その後クライアントにコミットを返す。これにより、クライアントが「成功」と認識したすべてのトランザクションが少なくとも 1 つのレプリカに存在することが保証される。","AFTER_COMMIT モードでは、プライマリはまずローカルでコミットし、その後レプリカを待つ。レプリカが遅延すると、他のセッションがまだレプリケートされていないデータを参照する可能性がある (ファントムリードに類似)。","rpl_semi_sync_source_timeout を超えると、プライマリは停止せず自動的に非同期にフォールバックし、レプリカが戻ると準同期に復帰する。したがって「保証」は条件付きである。","準同期が保証するのは「受信」であり、「レプリカでの適用」ではない。厳密な RPO=0 には Group Replication または外部の合意層がより適している。"],"level":"expert"},{"id":"mysql-undo-purge","title":"MySQL InnoDB: undo 表領域とパージ","category":"MySQL","summary":"InnoDB は MVCC のため古い行バージョンを undo ログに保持する。パージスレッドは、どの読み取りからも不要になった undo レコードと不要なバージョンを除去する。","points":["すべての変更はロールバックと一貫性読み取りのための undo ログレコードを生成する。長時間実行トランザクションは古いリードビューを生かし続け、パージの進行を妨げて undo を増大させる (history list length が増加する)。","history list length (SHOW ENGINE INNODB STATUS) が増え続ける場合、パージが追いついていない。主な原因は通常、長時間開いたトランザクションやアクティブに保たれた古い読み取り (例: mysqldump --single-transaction)。","innodb_purge_threads はパージの並列度を制御し、innodb_max_purge_lag はパージが大きく遅れた際に DML に人為的な遅延を加え、負荷がパージを圧倒するのを防ぐ。","MySQL 8 では undo は個別の undo 表領域に保持され、増大した undo ファイルは自動切捨て (innodb_undo_log_truncate) で縮小できる。旧バージョンでは undo はシステム表領域に置かれ、縮小しなかった。","肥大化した undo は一貫性読み取りにより長いバージョンチェーンをたどらせる (I/O と CPU)。短いトランザクションと autocommit の規律が undo の負荷を最小化する。"],"level":"expert"},{"id":"mysql-buffer-pool-lru","title":"MySQL InnoDB: バッファプールインスタンスと LRU","category":"MySQL","summary":"InnoDB バッファプールはデータページとインデックスページをメモリに保持する。ミッドポイント挿入の LRU アルゴリズムにより、テーブルスキャンがホットなデータをメモリから追い出すことを防ぐ。","points":["専用データベースサーバーでは、バッファプールは通常 RAM の ~70-80% に設定する (innodb_buffer_pool_size。共有サーバーではより低く)。目的は頻繁にアクセスされるワーキングセットをメモリに保持し、ディスク I/O を最小化すること。","LRU リストは「young」(ホット) と「old」(コールド) のサブリストに分かれる。新たに読み込まれたページはリストの先頭ではなく old 領域の先頭 (ミッドポイント、~37%) に挿入されるため、一度きりのスキャンがホットなページを追い出さない。","old 領域のページは、innodb_old_blocks_time 経過後に再度アクセスされた場合にのみ young に昇格する。これにより大規模な全表スキャンがバッファプールを汚染することを防ぐ。","innodb_buffer_pool_instances はプールを複数の独立したインスタンスに分割する。各インスタンスが独自のミューテックスを持つため、高い同時実行下でバッファプールのミューテックス競合が減少する (大規模なプールで有効)。","バッファプールのヒット率と空き/ダーティページのバランスを監視する。大量のダーティページと積極的なフラッシュは「チェックポイントストーム」を引き起こしうる。innodb_io_capacity はストレージに応じてフラッシュ速度を設定する。"],"level":"expert"},{"id":"sqlserver-always-on-ag","title":"SQL Server: Always On 可用性グループ","category":"SQL Server","summary":"可用性グループはデータベースのグループを同期/非同期レプリカへレプリケートする。WSFC 上で自動フェイルオーバー、読み取り可能レプリカ、読み取り専用ルーティングを提供する。","points":["同期コミットレプリカでは、プライマリはセカンダリがログレコードを確定 (harden) するまで待ってからコミットする。RPO=0 を実現するが、レプリカが遅延するとプライマリのコミットレイテンシが増加する。","非同期コミットレプリカはプライマリを待たせない。遠隔の災害復旧 (DR) サイトに適するが、フェイルオーバーで一部のデータを失う可能性があり (RPO>0)、強制手動フェイルオーバー (FORCE_FAILOVER_ALLOW_DATA_LOSS) のみがサポートされる。","自動フェイルオーバーは、同期コミットかつ「自動フェイルオーバー」モードのレプリカのペア間でのみ、WSFC クォーラムが維持されている場合に発生する。ヘルスチェックは sp_server_diagnostics とデータベース正常性検出で行われる。","読み取り可能セカンダリレプリカはプライマリからレポート処理をオフロードする。読み取り専用ルーティングにより、ApplicationIntent=ReadOnly で接続するクライアントはリスナー経由で読み取り可能レプリカへ自動的にルーティングされる。","読み取り可能レプリカ上のクエリは自動的にスナップショット分離を使う。そのためプライマリでは変更された行に 14 バイトのバージョンタグが付加され、セカンダリでは tempdb のバージョンストアに負荷がかかる。また redo の適用が遅れると、レプリカ上のデータが古くなりうる。","AG リスナーは仮想ネットワーク名 + IP によりクライアントに単一の接続ポイントを提供する。フェイルオーバー時にリスナーは新プライマリへ移動し、アプリケーションは接続文字列を変えずに動作を続ける。"],"level":"expert"},{"id":"sqlserver-columnstore","title":"SQL Server: 列ストアインデックスとバッチモード","category":"SQL Server","summary":"列ストアインデックスはデータを列単位で高圧縮して格納する。バッチモード処理とセグメント除外により、分析クエリが大幅に高速化される。","points":["データは行グループ (~100 万行) 内の列セグメントに分割され、各セグメントが圧縮される。クエリが必要とする列のみが読み取られるため、I/O が大幅に減少する。","各セグメントは最小値/最大値のメタデータを保持する。クエリ述語がセグメントの値範囲外であれば、そのセグメントは読み取らずにスキップされる (セグメント除外)。そのためデータをソート順でロードすることが非常に重要。","バッチモードは行を 1 行ずつではなく ~900 行のグループで処理し、CPU サイクルあたりの処理量を増やす。集計と結合では行モードより何倍も高速 (SQL 2019+ では行ストアでもバッチモードが可能)。","クラスタ化列ストアは大規模な分析/DW のファクトテーブルに最適。OLTP と分析の混在ワークロードでは、行ストアテーブル上の非クラスタ化列ストアによりリアルタイム運用分析 (HTAP) を構築できる。","ホットな (まだ圧縮されていない) 行はデルタストアに行単位で保持され、満杯になると tuple mover により圧縮される。小さなロードを多数行うと断片化が生じるため、一括ロードを優先する。"],"level":"expert"},{"id":"sqlserver-inmemory-oltp","title":"SQL Server: In-Memory OLTP (Hekaton)","category":"SQL Server","summary":"In-Memory OLTP は、メモリ最適化テーブルをロック/ラッチフリーの構造とネイティブコンパイルされたプロシージャで処理し、高同時実行 OLTP ワークロードのボトルネックを解消する。","points":["メモリ最適化テーブルは完全にメモリ上に保持され、すべての行バージョンもメモリ上に存在する。同時実行はロックフリーの楽観的 MVCC で処理され、従来のラッチとロックの競合が排除される。","永続性のため、変更は引き続きログに書き込まれ、チェックポイントファイル (data/delta) にフラッシュされる。SCHEMA_ONLY テーブルはログに記録されず、再起動時に空になる (例: 一時的なステージング/セッションデータに最適)。","ネイティブコンパイルストアドプロシージャは T-SQL をマシンコード (DLL) にコンパイルし、解釈のオーバーヘッドを排除する。メモリ最適化テーブルのみにアクセスでき、T-SQL の限定的なサブセットをサポートする。","同時実行が楽観的であるため、競合は実行時に検出される。書き込み-書き込み競合はトランザクションをエラーでロールバックする (再試行が必要) ため、アプリケーションに再試行ロジックを組み込む必要がある。","最適なシナリオ: 非常に高い挿入レート (例: IoT/テレメトリの取込み)、ロック/ラッチのボトルネックがあるホットテーブル、tempdb を使う一時テーブル。すべてのデータがメモリに収まる必要があり、メモリ負荷を綿密に監視する必要がある。"],"level":"expert"},{"id":"sqlserver-query-store","title":"SQL Server: Query Store による計画管理","category":"SQL Server","summary":"Query Store はクエリテキスト、実行計画、実行時統計を永続化する。計画の劣化 (リグレッション) を検出し、特定の計画を強制できる。","points":["Query Store は、各クエリが時間とともに使用したすべての計画を、計画ごとの実行時間/CPU/読み取りメトリクスとともにデータベース内に保持する。「なぜこのクエリは昨日は速く今日は遅いのか」に履歴データで答える。","計画のリグレッション (新たにコンパイルされた計画が旧計画より悪い) は 'Regressed Queries' と 'Top Resource Consumers' レポートで見つける。既知の良好な計画を sys.sp_query_store_force_plan で強制して安定性を回復する。","SQL Server 2022 の Query Store ヒントにより、計画の強制やクエリテキストの変更なしにヒント (例: RECOMPILE、MAXDOP) を適用できる。サードパーティアプリケーションのクエリのチューニングに強力。","自動プラン修正 (自動チューニング、FORCE_LAST_GOOD_PLAN) はリグレッションを検出し、以前の良好な計画を自動的に強制し、改善がなければ元に戻す。本番環境では監視下で有効にする。","キャプチャモード (ALL/AUTO/CUSTOM) とストレージサイズを正しく設定する。AUTO はまれ/重要でないクエリを除外してオーバーヘッドと領域を削減する。満杯になった Query Store は読み取り専用モードに切り替わり、データ収集を停止する。"],"level":"expert"},{"id":"mongodb-sharding-deep","title":"MongoDB: シャーディング、チャンク、バランサー","category":"MongoDB","summary":"MongoDB はシャードキーでデータをチャンクに分割してシャード間に分散する。バランサーがチャンクを均等化し、シャードキーの選択が分散とクエリのルーティングを決める。","points":["データはシャードキーの範囲でチャンクに分割され、チャンクがシャード間に分散される。mongos ルーターはシャードキーを見てクエリを該当シャードのみにルーティングし (targeted)、そうでなければ全シャードにブロードキャストする (scatter-gather)。","良いシャードキーはカーディナリティが高く、頻度が低く、単調増加しない。単調増加するキー (例: timestamp/ObjectId) はすべての新規書き込みを単一シャードに集中させ (ホットスポット)、ハッシュシャーディングはそれを分散させる。","シャード間でチャンク数が不均衡になると、バランサーがバックグラウンドでチャンクを移行する。移行中もソースとターゲット間の一貫性は保たれるが、I/O コストが発生するため、メンテナンスウィンドウにスケジュールできる。","jumbo チャンクは最大チャンクサイズを超え、シャードキーのカーディナリティが低いため分割できないチャンクである。移行できず不均衡を生む。対処はより選択性の高い (複合) シャードキー。","ゾーンシャーディング (タグ認識) は特定のシャードキー範囲を特定のシャードに固定する。地理やハードウェアに基づくデータ配置の制御に使われる (例: EU のデータを EU リージョンのシャードに置く)。","最新バージョンではチャンク数の代わりにサイズベースのバランシングと自動デフラグが導入されているが、原則は同じ: targeted クエリのためには、すべての読み取り/書き込みにシャードキーが含まれている必要がある。"],"level":"expert"},{"id":"mongodb-oplog-election","title":"MongoDB: レプリカセットの oplog と選出","category":"MongoDB","summary":"レプリカセットでは、プライマリが書き込み操作を oplog に記録し、セカンダリがそれを適用する。プライマリ障害時は Raft に似た選出で新プライマリが選ばれる。","points":["oplog は capped コレクションで、プライマリ上のすべての変更を冪等 (安全に再適用可能) な形で記録する。セカンダリは oplog を追跡 (tail) して適用し、同期を保つ。","oplog のサイズがレプリケーションウィンドウを決める。セカンダリが oplog のカバー範囲より長くオフラインになると「stale」となり、完全な再同期 (initial sync) が必要になるため、oplog はワークロードに対応できるサイズにする必要がある。","プライマリ障害時、セカンダリは Raft に似たプロトコルで投票し、過半数の票を得た候補がプライマリになる。そのため過半数を維持できるよう、投票数は奇数に保つ (必要なら arbiter を使う)。","writeConcern 'majority' は書き込みがノードの過半数に到達したことを保証するため、フェイルオーバー時にロールバックされない (ロールバック保護)。w:1 は高速だが、プライマリ障害時に書き込みが失われうる。","readConcern と read preference が読み取りの鮮度を制御する。セカンダリからの読み取りは負荷を分散するが、レプリケーションラグにより古いデータを返しうる。'majority'/'linearizable' はより強い保証を与える。","ネットワーク分断後に旧プライマリが少数派になると、セカンダリに降格する。新プライマリに再参加する際、未コミットの書き込みをロールバックファイルに移す (majority の write concern でこれを防げる)。"],"level":"expert"},{"id":"mongodb-wiredtiger-checkpoint","title":"MongoDB: WiredTiger のチェックポイントとジャーナル","category":"MongoDB","summary":"WiredTiger は定期的なチェックポイントと先行書き込みジャーナルで永続性を提供する。ドキュメントレベルの同時実行制御と圧縮により高いスループットを実現する。","points":["デフォルトで WiredTiger は約 60 秒ごとにチェックポイントを取り、一貫性のあるメモリ内スナップショットをディスクに書き込む。チェックポイント間の永続性は、すべての書き込みをジャーナル (WAL) に記録することで保たれる。","ジャーナルがない場合、クラッシュすると最後のチェックポイント以降の書き込みが失われる。ジャーナルがあれば、リカバリは最後のチェックポイントをロードし、以降の操作をジャーナルから再実行する。","ドキュメントレベルの同時実行制御により、同じコレクション内の異なるドキュメントを同時に更新できる。MVCC スナップショットが一貫性のある読み取りを提供する。","WiredTiger キャッシュ (デフォルトで RAM の ~50%) は頻繁にアクセスされるデータとインデックスを保持する。ワーキングセットがキャッシュに収まらないとエビクションとディスク I/O が増加し、キャッシュの飽和は性能を著しく低下させる。","ストレージ圧縮のデフォルトは snappy (速度と圧縮率のバランス)。zstd/zlib はより高い圧縮率を得られるが、より多くの CPU を必要とする。インデックスはさらにプレフィックス圧縮で縮小される。"],"level":"expert"},{"id":"redis-cluster-hashslot","title":"Redis Cluster: ハッシュスロットとリシャーディング","category":"Redis","summary":"Redis Cluster はキー空間を 16384 個のハッシュスロットに分割してノード間に分散し、水平スケールする。クライアントは MOVED/ASK リダイレクトで正しいノードを見つける。","points":["各キーは CRC16(key) mod 16384 でスロットに対応付けられる。各マスターは特定のスロット範囲を所有するため、クラスタは中央ルーターなしでデータを分散する。","クライアントが誤ったノードにアクセスすると、ノードは MOVED でスロットの恒久的な所有者を示し、クライアントはスロットマップを更新する。リシャーディング中は、移行中のスロットに一時的な ASK リダイレクトが使われる。","リシャーディングはスロット (とその中のキー) をあるノードから別のノードへオンラインで移動する。移行はキーごとに行われ、クラスタはその間もサービスを継続する。","複数キー操作 (MSET、トランザクション、Lua) は同じスロット内のキーでのみ動作する。関連キーを同じスロットにまとめるにはハッシュタグ ({...}) を使う。例: user:{123}:name と user:{123}:email。","高可用性のため、各マスターに少なくとも 1 つのレプリカを持たせる。マスター障害時にはそのレプリカが昇格する。クラスタはマスターの過半数で判断し、過半数を失うと書き込みが停止する。","いずれかのスロットが未割り当てまたはマスター不在の場合、クラスタはすべての書き込みを拒否する (cluster-require-full-coverage が有効な場合)。16384 個すべてのスロットが割り当てられている必要がある。"],"level":"expert"},{"id":"redis-replication-psync","title":"Redis: レプリケーションと PSYNC","category":"Redis","summary":"Redis の非同期レプリケーションでは、マスターがデータスナップショットをレプリカに転送し、その後のコマンドをストリーミングする。短い切断の後、PSYNC は部分再同期を行う。","points":["初期同期時、マスターは RDB スナップショットを生成してレプリカに送信する (完全再同期)。その間に受け付けた書き込みはレプリケーションバックログバッファに蓄え、RDB の後にストリーミングする。","PSYNC はレプリカのレプリケーションオフセットとマスターのレプリケーション ID を追跡する。短い切断の後、取りこぼしたデータがまだバックログバッファにあれば欠落部分のみを送信し (部分再同期)、高コストな完全再同期を回避する。","repl-backlog-size は許容できる切断時間を決める。書き込みレートが高い場合、小さいバックログでは切断時に完全再同期が強制され、マスターでの RDB 生成とネットワークコストが発生する。","レプリケーションは非同期: マスターはレプリカを待たずに書き込みを確認応答するため、マスターが突然クラッシュすると最新の書き込みが失われうる。WAIT コマンドで指定数のレプリカが受信するまで待機できるが、真の同期保証ではない。","ディスクレスレプリケーション (repl-diskless-sync) では、マスターは RDB をディスクに書かずにソケットへ直接ストリーミングできる。ディスクが遅くネットワークが速い環境で初期同期を高速化する。"],"level":"expert"},{"id":"redis-memory-fragmentation","title":"Redis: メモリ断片化と jemalloc","category":"Redis","summary":"Redis はデフォルトで jemalloc を使う。可変サイズの割り当てと解放により時間とともにメモリ断片化が生じ、RSS が実際に使用しているデータより大きく見える。","points":["mem_fragmentation_ratio = used_memory_rss / used_memory。1 に近いのが理想で、1 を明らかに上回る (例: >1.5) と断片化を示し、1 未満はデータがディスクにスワップされていることを示す (悪い状態)。","断片化は、異なるサイズのキーが絶えず作成・削除され、jemalloc のアリーナに使えない隙間が残ることで生じる。大きな値の頻繁な変更は状況を悪化させる。","アクティブデフラグ (activedefrag yes) は jemalloc の助けを借りて実行時にメモリブロックを圧縮し、断片化を減らす。オーバーヘッドを抑えるため、しきい値 (active-defrag-ignore-bytes、-threshold-lower/upper) を調整する。","maxmemory と maxmemory-policy を正しく設定する。jemalloc が実際に割り当てる RSS は maxmemory を超えうるため、OS の OOM を避けるよう maxmemory は RAM より低く保つ。","used_memory が低いのに RSS が高いままの場合、再起動 (またはフェイルオーバーで再起動したノード) で通常は断片化がリセットされ、恒久的に解消する。ほとんどの場合、アクティブデフラグで再起動の必要性は減る。"],"level":"expert"},{"id":"elasticsearch-shard-sizing","title":"Elasticsearch: シャードのサイジング","category":"Elasticsearch","summary":"各シャードは Lucene インデックスであり、固定のリソースコストを伴う。小さすぎるシャードの過多 (オーバーシャーディング) や大きすぎるシャードは、性能と安定性を低下させる。","points":["目安: シャードは 10-50 GB の範囲に保つ。非常に大きいシャードはリカバリとリバランスを遅くし、非常に小さいシャード (オーバーシャーディング) はクラスタ状態とヒープに不要な負荷をかける。","すべてのシャード、特にすべてのマップされたフィールドがヒープを消費する。従来の「ヒープ 1 GB あたり ~20 シャード」というルールは 8.3 以降は適用されない (シャードあたりのヒープオーバーヘッドが大幅に減少した)。現在の指針は、データノード上でインデックスごとのマップされたフィールド 1 つにつき ~1 KB のヒープとオーバーヘッドを見込み、ノードあたりのシャード数を cluster.max_shards_per_node (デフォルト 1000) 未満に保つこと。シャードが多すぎると依然としてクラスタ状態が増大し、調整オーバーヘッドが増加する。","クエリレイテンシはシャード数に関係する: クエリは関連するすべてのシャードにファンアウトし、結果がマージされる。必要以上のシャードは調整オーバーヘッドにより小さなクエリさえ遅くする。","時系列/ログデータには、1 つの巨大なインデックスではなく時間ベースのインデックス (データストリーム) を使う。これにより古いデータのインデックス単位の移動/削除 (ILM) が低コストになり、シャードが管理しやすくなる。","プライマリシャード数はインデックス作成時に固定され、後から変更できない (reindex/split/shrink によってのみ可能)。したがって増加見込みに基づいて事前に正しく計画する。一方、レプリカ数は動的に調整できる。"],"level":"expert"},{"id":"elasticsearch-ilm-tiers","title":"Elasticsearch: ILM と hot-warm-cold-frozen 階層","category":"Elasticsearch","summary":"Index Lifecycle Management は、ライフサイクルフェーズに応じてインデックスをコスト/性能の階層間で自動的に移動し、時系列データを経済的に管理する。","points":["ILM ポリシーはインデックスを各フェーズに移動させる: hot (アクティブな書き込み + 頻繁なクエリ、高速 SSD)、warm (書き込み終了、時折のクエリ)、cold (まれなクエリ、安価なハードウェア)、frozen (非常にまれ、searchable snapshot によりオブジェクトストレージから提供)。","ロールオーバーは、hot インデックスが指定のサイズ/経過期間/ドキュメント数に達すると新しいインデックスを開く。これにより単一のインデックスが無限に増大せず、各フェーズがインデックス単位で管理される。","frozen 階層は searchable snapshot によりデータをオブジェクトストレージ (S3/blob) に保持し、必要なときにのみ部分的にメモリへ取り込む。ディスクコストを大幅に削減するが、クエリレイテンシは増加する。","warm/cold へ移動する際は、force merge、shrink、レプリカ削減でストレージとヒープを最適化する。これらのフェーズではデータが変更されないため、セグメントを単一セグメントまでマージできる。","データ階層をノードロール (data_hot/data_warm/data_cold/data_frozen) に対応付ける。ILM はシャード割り当てフィルタを使い、適切なハードウェアを持つノードにインデックスを配置する。"],"level":"expert"},{"id":"elasticsearch-segment-merge","title":"Elasticsearch: セグメントマージと force merge","category":"Elasticsearch","summary":"Lucene はリフレッシュのたびに新しい不変セグメントを作成する。バックグラウンドマージがセグメントを結合・除去し、force merge は慎重に使うべき手動操作である。","points":["各リフレッシュ (デフォルト 1 s) が新しいセグメントを生成し、削除はセグメント内で「tombstone」としてマークされる。小さなセグメントが多いと読み取りが遅くなるため、バックグラウンドマージがそれらを結合する。","削除/更新されたドキュメントは、マージ時にのみディスクから物理的に除去される。更新負荷が高いと「deleted docs」がセグメントに蓄積し、ディスク/メモリ使用量が膨らむ。","もう書き込まれない (読み取り専用) インデックスでは、1 セグメントまでの force merge がクエリ速度とディスク効率を向上させる。これは ILM の warm フェーズの典型的なステップである。","アクティブに書き込まれているインデックスでは決して force merge を実行しないこと。生成される非常に大きなセグメントは通常のマージサイクルに入らず、以降の削除がクリーンアップされず、長時間にわたって I/O とヒープを圧迫する。","一括ロード中に refresh_interval を一時的に増やす (例: -1 または 30s) と、より少なく大きなセグメントが生成され、マージ負荷が減り書き込みスループットが向上する。"],"level":"expert"},{"id":"elasticsearch-node-roles","title":"Elasticsearch: ノードロールとクラスタトポロジー","category":"Elasticsearch","summary":"Elasticsearch のノードは master、data、coordinating、ingest などのロールを担う。大規模クラスタではロールを分離することで安定性とスケーラビリティが得られる。","points":["master 適格ノードはクラスタ状態 (インデックス、シャード配置、マッピング) を管理する。安定した選出のため奇数 (通常 3) の専用 master ノードを使い、スプリットブレインを防ぐためクォーラム (過半数) に依拠する。","データノードはシャードをホストし、インデックス作成とクエリの I/O を処理する。CPU/RAM/ディスクを最も消費し、データ階層 (hot/warm/cold/frozen) に分けることができる。","coordinating 専用ノードは他のロールを持たず、リクエストを該当シャードに分配して結果をマージする (scatter-gather)。重い検索/集計のマージを引き受けてデータノードを保護し、ロードバランサーとして機能する。","ingest ノードはインデックス作成前にパイプラインでデータを処理する (変換、エンリッチメント)。重い ingest パイプラインを専用 ingest ノードに移すと、データノードのクエリ性能が保護される。","master ノードに重いクエリ/データ負荷を決して共有させないこと。負荷で master が遅くなるとクラスタ状態の更新が遅れ、クラスタ全体が不安定になる (シャード割り当ての遅延、選出)。"],"level":"expert"}]},"guide/glossary.json":{"terms":[{"term":"ACID","full":"原子性 (Atomicity)、一貫性 (Consistency)、分離性 (Isolation)、永続性 (Durability)","definition":"トランザクションを信頼できるものにする 4 つの中核特性: Atomicity (原子性: すべてか無か)、Consistency (一貫性: ルールが保たれる)、Isolation (分離性: 同時実行トランザクションが互いを壊さない)、Durability (永続性: コミットされたデータは失われない)。リレーショナルデータベースのトランザクション保証である。","tags":["transaction","transaction","acid","consistency","consistency"]},{"term":"BASE","full":"Basically Available (基本的に利用可能)、Soft state (ソフトステート)、Eventually consistent (結果整合性)","definition":"分散システムや NoSQL システムで好まれる、ACID の代替となる緩やかな一貫性のアプローチ。システムは常に利用可能であることを優先し、データが時間をかけて一貫性を持つこと (結果整合性) を受け入れる。厳密な一貫性と引き換えにスケーラビリティを得る。","tags":["base","distributed","distributed","eventual-consistency","nosql"]},{"term":"MVCC","full":"Multi-Version Concurrency Control","definition":"同じ行の複数バージョンを保持し、読み取り側と書き込み側が互いをロックせずに動作できるようにする同時実行制御方式。各トランザクションはデータの独自のスナップショットを参照するため、読み取りは書き込みをブロックせず、書き込みは読み取りをブロックしない。PostgreSQL や Oracle などで使われる。","tags":["concurrency","concurrency","lock","mvcc","snapshot"]},{"term":"WAL","full":"Write-Ahead Log","definition":"変更がデータファイルに書き込まれる前に、ログレコードをディスクへ永続的に書き込むという原則。クラッシュリカバリと永続性はこれにより保証される。PostgreSQL では WAL、SQL Server ではトランザクションログと呼ばれる。","tags":["wal","log","recovery","recovery","durability"]},{"term":"Redo ログ (Redo Log)","full":"","definition":"データベースに加えられた変更を記録し、クラッシュで失われた作業の再適用 (redo) に使われるログ。リカバリ中、コミット済みだがまだディスクに書き込まれていない変更をロールフォワードする。Oracle の redo ログは WAL の一般概念に相当する。","tags":["redo","log","recovery","recovery","oracle"]},{"term":"Undo / ロールバックセグメント (Rollback Segment)","full":"","definition":"トランザクションが変更したデータの変更前イメージを格納する領域。2 つの目的を持つ: ロールバックによる変更の取り消しと、MVCC 下で読み取り側に古いバージョンを提供すること。Oracle では undo/ロールバックセグメント、他のシステムでは undo/バージョンストアと呼ばれる。","tags":["undo","rollback","rollback","mvcc","segment"]},{"term":"バッファプール / バッファキャッシュ (Buffer Pool / Buffer Cache)","full":"","definition":"頻繁に使われるデータページとインデックスページを保持するメモリキャッシュ。ディスク読み取りは高コストなため、データベース性能はここでのヒット率 (キャッシュヒット率) に大きく依存する。MySQL InnoDB ではバッファプール、SQL Server ではバッファキャッシュと呼ばれる。","tags":["buffer-pool","buffer-cache","cache","cache","memory"]},{"term":"ダーティページ (Dirty Page)","full":"","definition":"メモリ上で変更されたが、まだディスクに書き込まれていないデータページ。永続性は WAL で保護され、ページ自体はチェックポイントまたはバックグラウンドライターがディスクにフラッシュするまでダーティのままとなる。ダーティページが多すぎるとリカバリ時間が長くなる。","tags":["dirty-page","dirty-page","memory","checkpoint","io"]},{"term":"LSN","full":"ログシーケンス番号 (Log Sequence Number)","definition":"WAL/トランザクションログ内のすべてのレコードに割り当てられる、連続的に増加する一意のシーケンス番号。ページがどのログレコードまで最新か、リカバリをどこから継続すべきかの判断に使われる。レプリケーションの進行状況の追跡にも使われる。","tags":["lsn","log","sequence-number","recovery","replication"]},{"term":"SCN","full":"システム変更番号 (System Change Number)","definition":"Oracle において、データベース内のすべてのコミットポイントに割り当てられる単調増加の論理タイムスタンプ。読み取り一貫性、MVCC、リカバリ時のイベントの順序付けに使われる。Oracle における LSN の対応物と考えられる。","tags":["scn","oracle","timestamp","read-consistency","commit"]},{"term":"分離レベル (Isolation Level)","full":"分離レベル (Isolation Level)","definition":"同時実行トランザクションが互いの変更をどの程度参照できるかを決める設定。レベルは Read Uncommitted、Read Committed、Repeatable Read、Serializable で、レベルが上がるほど一貫性は高まり同時実行性は下がる。ダーティリード/反復不能読み取り/ファントムリードの異常を制御する。","tags":["isolation","isolation-level","transaction","concurrency","concurrency"]},{"term":"ダーティリード (Dirty Read)","full":"","definition":"他のトランザクションがまだコミットしていない (ロールバックする可能性のある) 変更を、あるトランザクションが読み取ること。読み取ったデータが無効になりうるため、一貫性の異常である。Read Uncommitted 分離レベルでのみ起こりうる。","tags":["dirty-read","anomaly","isolation","transaction","consistency"]},{"term":"反復不能読み取り (Non-repeatable Read)","full":"","definition":"同一トランザクション内で同じ行を 2 回読み取った際に、間に別のトランザクションがコミットしたため異なる値が見えること。Read Committed で起こりうるが、Repeatable Read 以上では防止される。","tags":["non-repeatable-read","anomaly","isolation","transaction","non-repeatable"]},{"term":"ファントムリード (Phantom Read)","full":"","definition":"同一トランザクション内で同じ条件のクエリを再実行した際に、間に挿入/削除が行われたため行の集合が変わること (新たな「ファントム」行が現れる)。SQL 標準では Serializable で防止される。PostgreSQL では Repeatable Read でも防止される。","tags":["phantom-read","phantom","anomaly","serializable","isolation"]},{"term":"デッドロック (Deadlock)","full":"","definition":"2 つ以上のトランザクションが互いに相手の保持するロックを待ち、いずれも進めなくなる状態。データベースはこれを検出し、通常は最もコストの低いトランザクションを「犠牲者」として選んでロールバックし、循環を断ち切る。常に同じ順序でロックを取得するとリスクが減る。","tags":["deadlock","deadlock","lock","lock","concurrency"]},{"term":"ロックエスカレーション (Lock Escalation)","full":"","definition":"トランザクションが多数の行/ページロックを保持すると、データベースがそれらを単一のより粗いロック (例: テーブルロック) に変換すること。ロック管理のメモリは減るが、同時実行性が下がりブロッキングが増えうる。特に SQL Server で見られる。","tags":["lock-escalation","lock","lock","concurrency","sql-server"]},{"term":"ラッチ (Latch)","full":"","definition":"メモリ内の構造 (例: バッファプールのページ) をごく短時間保護するために使われる、軽量で低コストな同時実行ロック。トランザクションロックと異なり、論理データではなく物理的なメモリ構造を保護し、ごく短時間のみ保持される。","tags":["latch","lock","memory","concurrency","internal"]},{"term":"B-Tree インデックス (B-Tree Index)","full":"B-tree インデックス (Balanced Tree Index)","definition":"データをソート済みの平衡木構造で保持する、最も一般的なインデックスタイプ。等価検索と範囲検索、ソート、前方一致検索に効率的。大半のデータベースでデフォルトのインデックスタイプである。","tags":["btree","index","index","search","range"]},{"term":"ハッシュインデックス (Hash Index)","full":"","definition":"キーをハッシュ関数に通して位置を特定するインデックスタイプ。完全一致 (=) の検索に対してのみ非常に高速で、範囲検索やソートには使えない。例えば PostgreSQL や MySQL の Memory テーブルで利用できる。","tags":["hash-index","index","index","equality","search"]},{"term":"ビットマップインデックス (Bitmap Index)","full":"","definition":"カーディナリティの低い列 (異なる値が少ない) に適した、異なる値ごとにビット配列を保持するインデックス。複数の条件を AND/OR で高速に組み合わせられる。データウェアハウス/OLAP ワークロードに有効だが、書き込みが多い環境では非効率。","tags":["bitmap-index","index","index","olap","cardinality"]},{"term":"カバリングインデックス (Covering Index)","full":"","definition":"クエリが必要とするすべての列を含むインデックス。テーブル (ヒープ/クラスタ化) にアクセスせず、インデックスだけでクエリを処理できる。高コストな行ルックアップを排除して性能を向上させる。INCLUDE 列で作成できる。","tags":["covering-index","index","index","performance","lookup"]},{"term":"クラスタ化インデックス (Clustered Index)","full":"","definition":"テーブルの行をインデックスキー順に物理的に並べて保持するインデックス。テーブル自体がその順序で格納される。1 テーブルに 1 つのみ作成可能。範囲検索に高速で、InnoDB では主キーが常にクラスタ化される。","tags":["clustered-index","index","index","physical","primary-key"]},{"term":"カーディナリティ (Cardinality)","full":"","definition":"列内の異なる値の数。高カーディナリティ (例: email) は異なる値が多く、低カーディナリティ (例: 性別) は少ないことを意味する。オプティマイザがインデックスを選び、計画コストを見積もる際の重要な尺度である。","tags":["cardinality","cardinality","statistics","optimizer","distinct"]},{"term":"選択性 (Selectivity)","full":"","definition":"フィルタ条件が全行のうちどれだけ小さな割合を返すかを示す。選択性が高い (行が少ない) とインデックスの使用が有利になり、選択性が低い (行が多い) と全表スキャンの方が安価になりうる。オプティマイザが計画の選択に使う。","tags":["selectivity","selectivity","optimizer","index","statistics"]},{"term":"実行計画 (Execution Plan)","full":"","definition":"オプティマイザがクエリを実行するために選んだステップ (スキャン方式、結合方式、ソートなど) を示す道筋。EXPLAIN/EXPLAIN ANALYZE で調べると性能問題の根本原因がわかる。推定コストと実コストの比較が重要。","tags":["execution-plan","query-plan","explain","optimizer","performance"]},{"term":"コストベースオプティマイザ (Cost-Based Optimizer)","full":"CBO","definition":"統計情報から可能な実行計画のコストを見積もり、最も安価なものを選ぶクエリオプティマイザ。正しい判断には最新の統計情報が不可欠で、古い統計情報は悪い計画につながる。現代のデータベースにおける標準的なアプローチである。","tags":["cbo","optimizer","cost","statistics","query-plan"]},{"term":"統計情報","full":"統計情報","definition":"オプティマイザが行数、カーディナリティ、値の分布を見積もれるよう、テーブル/インデックスについて収集されるメタデータ。最新の統計情報は良いクエリ計画を意味し、古くなったら ANALYZE/UPDATE STATISTICS で更新する必要がある。性能低下の最も一般的な原因の 1 つである。","tags":["statistics","statistics","optimizer","analyze","query-plan"]},{"term":"ヒストグラム (Histogram)","full":"","definition":"列内の値の分布を範囲 (バケット) に分けて要約する統計構造。特に偏った分布で、オプティマイザがより正確に行数を見積もれるようにする。統計情報の構成要素である。","tags":["histogram","statistics","statistics","optimizer","distribution"]},{"term":"パーティション (Partition)","full":"","definition":"大きなテーブルを、論理的には単一のテーブルのまま、物理的に小さな部分 (例: 日付や範囲) に分割する手法。クエリは該当部分のみをスキャンし (パーティションプルーニング)、メンテナンスとアーカイブが容易になる。シャーディングとの違い: 同一サーバー/インスタンス内に留まる。","tags":["partition","partitioning","scaling","pruning","big-data"]},{"term":"シャーディング","full":"","definition":"シャードキーに従って、データを複数の独立したサーバー/データベースに水平分散する方法。単一マシンの限界を超えた水平スケーリングを実現するが、クエリとトランザクションの管理が複雑になる。パーティショニングとの違い: データが異なるノードに分散される。","tags":["sharding","scaling","distributed","distributed","horizontal-scaling"]},{"term":"レプリケーション (同期/非同期)","full":"","definition":"プライマリノードから 1 つ以上のコピー (レプリカ) へデータを複製すること。同期レプリケーションではコミットがレプリカの確認応答を待ち (データ損失なし、レイテンシ増)、非同期レプリケーションでは待たない (高速だが、レプリカが遅れているとデータ損失の可能性がある)。HA と読み取りスケーリングに使われる。","tags":["replication","replication","synchronous","asynchronous","ha"]},{"term":"論理レプリケーションと物理レプリケーション","full":"","definition":"物理レプリケーションはディスクブロック/WAL レベルで完全なコピーを作成する (同一バージョン、データベース全体)。論理レプリケーションは行/SQL レベルで変更を転送し、テーブルの選択的なレプリケーションや、バージョン間・異なるスキーマ間の転送を可能にする。CDC とアップグレードのシナリオでは論理レプリケーションが好まれる。","tags":["logical-replication","physical-replication","replication","cdc","wal"]},{"term":"フェイルオーバー","full":"","definition":"プライマリノードの障害時に、自動または手動でスタンバイノードへサービスを移すこと。ダウンタイムを最小化する。RPO はどれだけのデータを失いうるか、RTO は復旧にどれだけかかるかを決める。計画外の障害時に機能する。","tags":["failover","ha","high-availability","standby","rpo"]},{"term":"スイッチオーバー (Switchover)","full":"","definition":"プライマリとスタンバイの役割を計画的かつ制御された形で交換すること (例: メンテナンスのため)。フェイルオーバーとの違い: 障害ではなく計画的な操作であり、通常はデータ損失なしで行われる。","tags":["switchover","planned","ha","maintenance","standby"]},{"term":"RPO","full":"目標復旧時点 (Recovery Point Objective)","definition":"災害後に許容できる最大のデータ損失量 (時間で表す)。例えば RPO が 5 分なら、最大 5 分間のデータ損失が許容される。バックアップ頻度とレプリケーション方式はこの目標を満たすように選ぶ。","tags":["rpo","data-loss","dr","disaster-recovery","backup"]},{"term":"RTO","full":"目標復旧時間 (Recovery Time Objective)","definition":"停止後にシステムが再び稼働するまでの最大目標時間。例えば RTO が 1 時間なら、遅くとも 1 時間以内にサービスが復旧しなければならない。HA/DR アーキテクチャと自動化のレベルはこの目標に基づいて設計される。","tags":["rto","recovery-time","dr","disaster-recovery","ha"]},{"term":"HA","full":"高可用性 (High Availability)","definition":"障害が発生しても、中断なく、またはごくわずかな中断でシステムがサービスを継続するという設計目標。冗長化、自動フェイルオーバー、ヘルスチェックによって実現される。通常は稼働率 (例: 99.99%) で表される。","tags":["ha","high-availability","high-availability","failover","redundancy"]},{"term":"DR","full":"ディザスタリカバリ (Disaster Recovery)","definition":"火災、洪水、リージョン全体の停止などの大規模災害の後に、通常は地理的に離れたリージョンでシステムとデータを復旧させるための計画とプロセス。RPO と RTO の目標で測定される。HA は日常的な障害、DR は大規模災害に焦点を当てる。","tags":["dr","disaster-recovery","disaster-recovery","rpo","rto"]},{"term":"クォーラム (Quorum)","full":"","definition":"分散システムにおいて、決定 (例: リーダー選出や書き込み確認) が有効となるために必要なノードの最小過半数 (通常 N/2 + 1)。スプリットブレインを防ぎ、一貫性を保つために使われる。クラスタのサイズがほとんど奇数であるのはこのためである。","tags":["quorum","majority","distributed","distributed","split-brain"]},{"term":"スプリットブレイン (Split-Brain)","full":"","definition":"ネットワーク分断後、クラスタの両側がともに自分がプライマリだと認識し、独立して書き込みを続ける状態。データの競合と破損につながる。クォーラムとフェンシングの仕組みで防止する。HA クラスタで最も危険な障害シナリオの 1 つである。","tags":["split-brain","distributed","quorum","ha","consistency"]},{"term":"TDE","full":"透過的データ暗号化 (Transparent Data Encryption)","definition":"データベースファイル (データとログ) をディスク上で暗号化した状態に保つ、アプリケーションに透過的な暗号化方式。ディスクやバックアップファイルが盗まれてもデータを保護する (保存データ)。ネットワーク上のデータ (転送中) は保護しないため、それには TLS が必要。","tags":["tde","encryption","encryption","security","security"]},{"term":"RBAC","full":"Role-Based Access Control","definition":"権限をユーザーに直接ではなくロールに割り当て、ユーザーをロールのメンバーにするアクセス制御モデル。権限管理を簡素化し、最小権限の原則を適用しやすくする。ユーザー数が増えても管理をスケーラブルに保つ。","tags":["rbac","role","privilege","security","security"]},{"term":"コネクションプール (Connection Pool)","full":"","definition":"アプリケーションのデータベース接続を繰り返し開閉する代わりに、事前に接続を作成して再利用するプール。接続確立コストを下げ、リソース消費を制限し、負荷を制御する。過剰な接続を防いでデータベースを保護する。","tags":["connection-pool","connection-pool","performance","resource","application"]},{"term":"プリペアドステートメント (Prepared Statement)","full":"","definition":"SQL 文を一度だけ解析・計画し、その後異なるパラメータ値で繰り返し実行する仕組み。計画の再利用により性能を向上させ、SQL インジェクションに対するセキュリティを提供する。バインド変数と組み合わせて使う。","tags":["prepared-statement","bind","security","sql-injection","performance"]},{"term":"バインド変数 (Bind Variable)","full":"","definition":"値を SQL テキストに埋め込む代わりに、プレースホルダ経由で渡すパラメータ。同じクエリが異なる値ごとに再計画されるのを防いで計画キャッシュを効率的に使い、SQL インジェクションを防止する。リテラル値が頻繁に変わるクエリで重要。","tags":["bind-variable","parameter","prepared-statement","plan-cache","security"]},{"term":"パラメータスニッフィング (Parameter Sniffing)","full":"","definition":"オプティマイザが、準備済み/パラメータ化クエリの計画を初回実行時のパラメータ値に基づいて生成・キャッシュすること。その値が典型的でない場合、後続の異なる値で性能の悪い計画が定着しうる。対処には計画の再コンパイル (recompile) やオプティマイザヒントがある。","tags":["parameter-sniffing","plan-cache","optimizer","performance","sql-server"]},{"term":"VACUUM / 肥大化 (Bloat)","full":"","definition":"MVCC により、削除/更新された行の不要なバージョンがテーブルに蓄積する。この膨張を肥大化 (bloat) と呼ぶ。VACUUM はこれらの不要な行の領域を回収し、統計情報を更新する (PostgreSQL)。定期的に実行しないとディスクが膨らみ、性能が低下する。","tags":["vacuum","bloat","bloated","mvcc","postgresql"]},{"term":"コンパクション (Compaction)","full":"","definition":"LSM ツリーベースのストア (例: Cassandra、RocksDB) で、多数の小さなデータファイルをマージし、不要/廃止されたレコードを除去する処理。読み取り性能を向上させ、ディスク領域を回収する。LSM の世界における VACUUM に相当する。","tags":["compaction","lsm-tree","merge","cassandra","rocksdb"]},{"term":"Oplog","full":"操作ログ (Operations Log)","definition":"MongoDB において、プライマリに適用されたすべての書き込み操作が順に記録される、固定サイズ (capped) の特殊なコレクション。レプリカセットのメンバーはここから読み取ってプライマリとの同期を保つ。CDC とレプリケーションの基盤である。","tags":["oplog","mongodb","replication","cdc","log"]},{"term":"Binlog","full":"バイナリログ (Binary Log)","definition":"MySQL において、データを変更するすべての操作 (または行の変更) を記録するバイナリログ。レプリケーション、ポイントインタイムリカバリ、CDC に使われる。row、statement、mixed 形式で保持できる。","tags":["binlog","mysql","replication","cdc","recovery"]},{"term":"CDC","full":"変更データキャプチャ (Change Data Capture)","definition":"データベースの挿入/更新/削除の変更を捕捉し、他のシステム (データウェアハウス、検索エンジン、メッセージキュー) へストリーミングする手法。通常はトランザクションログ (binlog、WAL、oplog) を読み取って低オーバーヘッドで動作する。リアルタイムデータ統合の基盤である。","tags":["cdc","change-data-capture","data-streaming","binlog","integration"]},{"term":"マテリアライズドビュー (Materialized View)","full":"","definition":"クエリの結果をディスクに物理的に格納するビュー。通常のビューと異なり、クエリのたびに再計算されない。高コストな集計と結合を高速化するが、データが古くなるためリフレッシュで更新する必要がある。OLAP/レポーティングで一般的。","tags":["materialized-view","view","cache","olap","reporting"]},{"term":"外部キー (Foreign Key)","full":"","definition":"あるテーブルの列が別のテーブルの主キー/候補キーを参照できるようにする参照整合性制約。存在しない行への参照を防ぎ、関係を保つ。ON DELETE/UPDATE CASCADE などのルールで従属行の動作を定義する。","tags":["foreign-key","foreign-key","integrity","relationship","constraint"]},{"term":"正規化 (Normalization)","full":"正規化 (Normalization)","definition":"冗長性を減らし不整合のリスクを下げるため、データを関連するテーブルに分割するプロセス (1NF、2NF、3NF などの正規形)。更新異常を防ぎ、OLTP システムで好まれる。その代わり、クエリにより多くの結合が必要になりうる。","tags":["normalization","normalization","design","oltp","redundancy"]},{"term":"非正規化 (Denormalization)","full":"非正規化 (Denormalization)","definition":"結合の数を減らし読み取り性能を向上させるため、意図的にデータを重複させる手法。クエリは高速化するが、データの重複と更新の複雑さを招く。レポーティング/OLAP や読み取り中心のワークロードで好まれる。","tags":["denormalization","denormalization","performance","olap","read"]},{"term":"OLTP","full":"オンライントランザクション処理 (Online Transaction Processing)","definition":"短く頻繁で同時実行される多数のトランザクション (挿入/更新/削除、単一行の読み取り) を処理するシステムの種類。例: 銀行、EC。低レイテンシと高い同時実行性を必要とし、通常は正規化して設計される。OLAP の運用系の対となる。","tags":["oltp","transaction","transaction","operational","normalization"]},{"term":"OLAP","full":"オンライン分析処理 (Online Analytical Processing)","definition":"大規模なデータセットに対して複雑な集計・分析クエリを実行するシステムの種類。例: レポーティング、BI。少数だが重いクエリが実行され、通常は非正規化かつ列指向で設計される。OLTP の分析系の対となる。","tags":["olap","analytics","reporting","data-warehouse","columnar"]},{"term":"ETL","full":"Extract, Transform, Load","definition":"ソースからデータを抽出し (Extract)、業務ルールに従って変換し (Transform)、ターゲットシステム (通常はデータウェアハウス) にロードする (Load) プロセス。ロード後にターゲット側で変換を行う変種を ELT と呼ぶ。データ統合の古典的なアプローチである。","tags":["etl","data-integration","data-warehouse","elt","transformation"]},{"term":"ホット/コールドデータ (Hot/Cold Data)","full":"","definition":"頻繁にアクセスされる最新のデータを「ホット」、まれにしかアクセスされない古い/アーカイブデータを「コールド」と呼ぶ。ホットデータは高速/高価なストレージに、コールドデータは安価/低速なストレージに置く (データ階層化)。コストと性能のバランスをとる戦略である。","tags":["hot-data","cold-data","hot-cold","archive","tiering"]},{"term":"インデックスの断片化 (Index Fragmentation)","full":"","definition":"時間とともに挿入/削除/更新により、インデックスページの論理順序が物理順序から乖離し、ページの充填率が低下すること。不要な I/O と領域の無駄を生み、性能を低下させる。REBUILD または REORGANIZE で解消する。","tags":["index-fragmentation","fragmentation","index","maintenance","performance"]},{"term":"2 フェーズコミット (Two-Phase Commit)","full":"2PC","definition":"複数のデータベース/リソースにまたがる分散トランザクションに原子的なコミットを提供するプロトコル。2 つのフェーズで動作する: まずコーディネーターがすべての参加者に準備ができたかを問い (prepare)、全員が同意すればコミットし、1 つでも拒否すれば全員がロールバックする。低速で、コーディネーターの障害に弱い。","tags":["two-phase-commit","2pc","distributed","distributed","atomic"]}]},"guide/glossary-2.json":{"terms":[{"term":"LSM ツリー (LSM Tree)","full":"ログ構造化マージツリー (Log-Structured Merge Tree)","definition":"書き込みをまずメモリ内の構造 (memtable) に蓄積し、ソート済みのブロックとしてディスクにフラッシュするストレージ構造。ランダム書き込みをシーケンシャル書き込みに変えて高い書き込みスループットを実現する。読み取りは複数のレベルをスキャンする。RocksDB、Cassandra、LevelDB の基盤である。","tags":["storage","storage engine","lsm","write"]},{"term":"B+ ツリー (B+ Tree)","full":"","definition":"すべてのデータをリーフノードに保持し、内部ノードはルーティングキーのみを含む平衡木構造。連結されたリーフが範囲スキャンを高速化する。リレーショナルデータベースのインデックスで最も一般的な構造である。","tags":["index","index structure","storage","storage engine","btree"]},{"term":"ブルームフィルタ (Bloom Filter)","full":"","definition":"要素が集合に含まれるかを少ないメモリで判定する確率的データ構造。「確実にない」または「おそらくある」と答える。偽陽性はありうるが偽陰性はない。LSM ベースのエンジンで不要なディスク読み取りを避けるために使われる。","tags":["storage","storage engine","probabilistic","filter","performance"]},{"term":"コンシステントハッシュ (Consistent Hashing)","full":"","definition":"ノードの追加・削除時に移動するキーをごく一部に抑える分散方式。キーとノードは仮想的なリング上に配置される。分散キャッシュや NoSQL システムのデータ分散に使われる。","tags":["distributed systems","distributed","hashing","sharding","scaling"]},{"term":"ベクタークロック (Vector Clock)","full":"","definition":"分散システムでイベントの因果順序を追跡するため、ノードごとにカウンタを保持する構造。2 つの更新が一方から派生したものか、同時 (競合) かを判定する。競合検出と結果整合性に使われる。","tags":["distributed systems","distributed","clock","causality","consistency"]},{"term":"ゴシッププロトコル (Gossip Protocol)","full":"","definition":"各ノードが定期的に、ランダムに選んだ少数のピアへ自身の状態を広め、情報が感染症のようにクラスタ全体に行き渡る通信方式。中央のコーディネーターを必要とせず、スケーラブルで耐障害性がある。Cassandra と Consul のメンバーシップ管理に使われる。","tags":["distributed systems","distributed","gossip","cluster","membership"]},{"term":"Raft","full":"","definition":"Paxos より理解しやすいよう設計された合意アルゴリズム。リーダーを選出し、すべての書き込みをリーダー経由でレプリケートされるログに追記し、過半数の確認応答で永続化する。etcd と Consul で使われる。","tags":["distributed systems","distributed","consensus","raft","replication"]},{"term":"Paxos","full":"","definition":"信頼性の低いネットワーク上で、過半数が単一の値に合意することを保証する古典的な合意アルゴリズム。正しいが実装が複雑とされ、多くの分散システムの理論的基盤となっている。Google Chubby などのシステムで使われる。","tags":["distributed systems","distributed","consensus","paxos","agreement"]},{"term":"リーダー選出 (Leader Election)","full":"","definition":"分散クラスタにおいて、特定のタスクを調整する単一のノード (リーダー) を選ぶプロセス。現在のリーダーが障害を起こすと、新しいリーダーが自動的に選出される。スプリットブレインを防ぐため、通常は過半数 (クォーラム) の承認を必要とする。","tags":["distributed systems","distributed","leader","election","coordination"]},{"term":"クォーラム書き込み/読み取り (Quorum Write/Read)","full":"","definition":"読み取りまたは書き込みが有効とみなされるために必要な最小ノード数。W + R > N が成り立つとき、最新のデータへの到達が保証される。一貫性と可用性のトレードオフを調整できるようにする。","tags":["distributed systems","distributed","quorum","consistency","replication"]},{"term":"WAL シッピング (WAL Shipping)","full":"WAL シッピング (Write-Ahead Log Shipping)","definition":"プライマリサーバーが生成した WAL レコードをスタンバイサーバーに送り、そこで再生すること。これによりスタンバイはプライマリデータベースのほぼ最新のコピーを保持する。PostgreSQL のストリーミングレプリケーションの基盤である。","tags":["replication","replication","wal","high-availability","standby"]},{"term":"ログシッピング (Log Shipping)","full":"","definition":"トランザクションログのバックアップを定期的にスタンバイサーバーにコピーしてリストアすることで動作する、シンプルなレプリケーション方式。ストリーミングより遅延は大きいが、セットアップが容易。SQL Server の災害復旧で一般的に使われる。","tags":["replication","replication","log","backup","standby"]},{"term":"スナップショット分離 (Snapshot Isolation)","full":"","definition":"各トランザクションが、開始時点のデータの一貫したスナップショットを参照する分離レベル。読み取りは書き込みをブロックしないが、write skew などの一部の異常は起こりうる。MVCC とともに実装される。","tags":["isolation level","isolation","mvcc","snapshot","concurrency"]},{"term":"Serializable Snapshot Isolation (SSI)","full":"Serializable Snapshot Isolation","definition":"危険な読み取り-書き込み依存関係を追跡することで、スナップショット分離の上に真の直列化可能性を提供する方式。競合が検出されると、いずれかのトランザクションがロールバックされる。PostgreSQL の SERIALIZABLE レベルで使われる。","tags":["isolation level","isolation","serializable","ssi","concurrency"]},{"term":"ギャップロック (Gap Lock)","full":"","definition":"インデックスレコード間のギャップ (まだ存在しない範囲) に対するロックで、その範囲への新しい行の挿入を防ぐ。ファントムリードの防止に使われる。InnoDB の REPEATABLE READ レベルで機能する。","tags":["locking","lock","innodb","phantom","concurrency"]},{"term":"ネクストキーロック (Next-Key Lock)","full":"","definition":"インデックスレコードに対するロックと、その前のギャップに対するロック (ギャップロック) の組み合わせ。既存の行と範囲の両方を保護してファントム挿入を防ぐ。InnoDB のデフォルトの行ロック動作である。","tags":["locking","lock","innodb","gap","concurrency"]},{"term":"楽観的ロック (Optimistic Locking)","full":"","definition":"競合はまれであると仮定してロックを取らずに処理し、コミット時にのみデータが変更されたかを確認する方式。通常はバージョン番号またはタイムスタンプで実装される。競合が見つかれば操作を再試行する。","tags":["locking","lock","optimistic","concurrency","concurrency"]},{"term":"悲観的ロック (Pessimistic Locking)","full":"","definition":"競合が起こると仮定し、データの読み取りまたは変更時に即座にロックを取る方式。他のトランザクションはロックが解放されるまで待つ。競合の多い環境でデータの整合性を保護するが、同時実行性を下げる。","tags":["locking","lock","pessimistic","concurrency","concurrency"]},{"term":"冪等性 (Idempotency)","full":"","definition":"操作を 1 回実行しても複数回実行しても同じ結果になる性質。ネットワークエラー後の安全な再試行を可能にする。分散システムでは重複リクエストによる副作用を防ぐ。","tags":["distributed systems","distributed","idempotent","retry","reliability"]},{"term":"サーキットブレーカー (Circuit Breaker)","full":"","definition":"失敗し続けるサービスへの呼出しを一時的に遮断してシステムを保護する設計パターン。回路が「open」の間はリクエストが即座に拒否され、しばらくすると試行の呼出しが行われる。連鎖障害を防ぐ。","tags":["distributed systems","distributed","fault tolerance","resilience","pattern"]},{"term":"Saga パターン (Saga Pattern)","full":"","definition":"複数のサービスにまたがる長時間実行トランザクションを、各ステップをローカルトランザクションとし、失敗時には補償トランザクションを使うことで管理するパターン。分散環境で ACID の代わりに結果整合性を提供する。マイクロサービスアーキテクチャで一般的。","tags":["distributed systems","distributed","saga","microservices","pattern"]},{"term":"Outbox パターン (Outbox Pattern)","full":"","definition":"データベースの更新とメッセージの発行を原子的にするため、同じトランザクション内でメッセージを「outbox」テーブルに書き込むパターン。別のプロセスがこのテーブルを読み取ってメッセージを発行する。これによりデータとイベント発行の不整合を防ぐ。","tags":["distributed systems","distributed","outbox","messaging","pattern"]},{"term":"ファンアウト (Fan-out)","full":"","definition":"単一の操作を多数のサブ操作やターゲットに分配すること。例: 投稿を数千人のフォロワーのフィードに書き込む。書き込み時 (write fan-out) または読み取り時 (read fan-out) に行える。スケーリングにおける重要な設計判断である。","tags":["distributed systems","distributed","scaling","fanout","architecture"]},{"term":"ホットスポット (Hotspot)","full":"","definition":"特定のノード、パーティション、キーに負荷が過度に集中すること。その箇所がボトルネックとなり、システム全体の性能を制限する。不適切に選ばれたシャーディングキーがよくある原因である。","tags":["distributed systems","distributed","hotspot","performance","sharding"]},{"term":"スキュー (データの偏り)","full":"","definition":"パーティション間でデータや負荷が不均等に分布すること。一部のパーティションが溢れ、他は空のままとなり、並列処理の効率が下がる。キーの選択やソルティングで均衡させる。","tags":["distributed systems","distributed","skew","imbalance","sharding"]},{"term":"部分インデックス (Partial Index)","full":"","definition":"WHERE 条件を満たすテーブル行のみを対象とするインデックス。インデックスサイズを減らし、メンテナンスを安価にし、頻繁にクエリされるサブセットを高速化する。例えばアクティブな行のみをインデックス化するのに使われる。","tags":["index","index type","postgresql","partial","performance"]},{"term":"式インデックス (Expression Index)","full":"","definition":"列ではなく、式や関数の結果に対して作成するインデックス。例えば LOWER(email) に作成すると、大文字小文字を区別しない検索が高速化される。クエリは同じ式を使う必要がある。","tags":["index","index type","expression","function","performance"]},{"term":"GIN インデックス (GIN Index)","full":"汎用転置インデックス (Generalized Inverted Index)","definition":"値の中の複数の構成要素をインデックス化する転置インデックスの一種。配列、JSONB、全文検索など、1 つのフィールドに多数のキーが含まれる場合に最適。PostgreSQL で使われる。","tags":["index","index type","postgresql","gin","jsonb"]},{"term":"GiST インデックス (GiST Index)","full":"汎用検索ツリー (Generalized Search Tree)","definition":"木ベースの拡張可能なインデックスフレームワークで、異なるデータ型に対して独自の検索戦略を定義できる。地理空間 (geometry)、範囲、最近傍のクエリに適している。PostGIS の基盤である。","tags":["index","index type","postgresql","gist","geospatial"]},{"term":"TOAST","full":"The Oversized-Attribute Storage Technique (過大属性格納技法)","definition":"ページに収まらない大きなフィールド値を圧縮し、別の領域に格納する PostgreSQL の手法。大きなテキストや JSONB の値は透過的に分割される。メインテーブルをコンパクトに保つことで性能を維持する。","tags":["storage","storage engine","postgresql","toast","large-values"]},{"term":"インデックスオンリースキャン (Index-Only Scan)","full":"","definition":"必要なデータがすべてインデックス内にあるため、テーブルを一切読まずにインデックスだけから結果を生成するスキャン。ディスクアクセスを大幅に減らす。PostgreSQL では可視性マップと連携して動作する。","tags":["index","index scan","scan","performance","postgresql"]},{"term":"HTAP","full":"トランザクション/分析ハイブリッド処理 (Hybrid Transactional/Analytical Processing)","definition":"トランザクション (OLTP) と分析 (OLAP) の両方のワークロードを単一のシステムで併せて実行するアプローチ。分析のために別のストアへデータを移動する (ETL) 遅延を排除する。通常は行ストアと列ストアを組み合わせる。","tags":["analytics","oltp","olap","htap","architecture"]},{"term":"シャーディングキー (Sharding Key)","full":"","definition":"行がどのシャードに配置されるかを決める 1 つ以上の列。適切に選ばれたキーは負荷を均等に分散し、ホットスポットを防ぐ。不適切な選択はデータの偏りと高コストなシャード間クエリにつながる。","tags":["distributed systems","distributed","sharding","key","scaling"]},{"term":"リバランス (Rebalancing)","full":"","definition":"ノードの追加・削除時や負荷が不均衡になった際に、パーティション間でデータを再分配すること。目的は負荷を均等化し、リソースを効率的に使うこと。実行中はネットワークと I/O のコストが発生する。","tags":["distributed systems","distributed","rebalancing","scaling","sharding"]},{"term":"フェンシング (Fencing)","full":"","definition":"古くなった、または孤立したノードが共有リソースに書き込むのを阻止し、データ破損を防ぐ仕組み。通常は増加する「fencing token」を使い、古いリクエストを拒否する。スプリットブレインの影響を限定する。","tags":["distributed systems","distributed","fencing","safety","split-brain"]},{"term":"ウォーターマーク (Watermark)","full":"","definition":"ストリーム処理システムにおいて、特定の時刻までのすべてのイベントが到着したとみなされることを示す進行マーカー。遅れて到着したイベントの処理や、ウィンドウ計算をいつ閉じるかの判断に使われる。","tags":["stream processing","streaming","watermark","event time","event"]},{"term":"トゥームストーン (Tombstone)","full":"","definition":"レコードが削除されたことを示すために書き込まれる特殊なマーカー。データが即座に物理削除されない LSM や分散システムで、削除がすべてのレプリカに伝播することを保証する。実際のクリーンアップはコンパクション時に行われる。","tags":["storage","storage engine","lsm","tombstone","delete"]},{"term":"コンパクション (LSM)","full":"","definition":"LSM ツリーにおいて、ディスク上のソート済みファイル (SSTable) をマージして書き直すこと。古いバージョンとトゥームストーンを除去して、読み取り性能とディスク使用量を改善する。バックグラウンドで実行され、書き込み負荷を生む。","tags":["storage","storage engine","lsm","compaction","maintenance"]},{"term":"リードリペア (Read Repair)","full":"","definition":"読み取り時にレプリカ間の不整合が検出された場合、最新の値を遅れているノードに書き込んで修復する手法。システムは通常の読み取りトラフィックを通じて自ら一貫性を回復する。Cassandra などのシステムで使われる。","tags":["distributed systems","distributed","repair","consistency","replication"]},{"term":"ヒンテッドハンドオフ (Hinted Handoff)","full":"","definition":"ターゲットノードに一時的に到達できない間、書き込みを別のノードに「hint」として保存し、ノードの復帰時に配信すること。一時的な障害の間も書き込みが失われないことを保証する。結果整合性を支える。","tags":["distributed systems","distributed","handoff","availability","replication"]},{"term":"結果整合性 (Eventual Consistency)","full":"","definition":"新たな更新が止まれば、すべてのレプリカが最終的に同じ値に収束することを保証する弱い一貫性モデル。短時間の不整合を許容する代わりに、高い可用性と低レイテンシを提供する。多くの NoSQL システムでデフォルトである。","tags":["distributed systems","distributed","consistency","eventual","nosql"]},{"term":"強い一貫性 (Strong Consistency)","full":"","definition":"書き込みが完了すると、すべての読み取り側が即座に最新の値を参照する一貫性モデル。直感的に使えるが、調整を必要とするためレイテンシと可用性のコストが高い。金融システムで好まれる。","tags":["distributed systems","distributed","consistency","strong","strong consistency"]},{"term":"線形化可能性 (Linearizability)","full":"","definition":"各操作が開始から終了までの間のある一瞬に効果を発揮したように見え、すべての操作が単一のリアルタイム順序に収まることを保証する、最も強い一貫性レベル。システムは単一のコピーであるかのように振る舞う。実装は高コストである。","tags":["distributed systems","distributed","consistency","linearizability","strong consistency"]},{"term":"2 相ロック (Two-Phase Locking, 2PL)","full":"2 相ロック (Two-Phase Locking)","definition":"トランザクションがまずロックの取得のみを行い (成長フェーズ)、その後ロックの解放のみを行う (縮退フェーズ) という 2 相のロック規則。この規律が直列化可能性を保証する。厳格な形式 (Strict 2PL) では、ロックはコミットまで保持される。","tags":["locking","lock","2pl","serializable","concurrency"]},{"term":"デッドロック検出 (Deadlock Detection)","full":"","definition":"2 つ以上のトランザクションが互いに保持するロックを待ち合うデッドロックを検出する仕組み。通常は待機グラフ (wait-for graph) で循環を探して見つけ、1 つのトランザクションを犠牲者として選んでロールバックする。これにより処理が再び流れ始める。","tags":["locking","lock","deadlock","deadlock detection","concurrency"]}]},"guide/glossary-3.json":{"terms":[{"term":"書き込み増幅 (Write Amplification)","full":"書き込み増幅 (Write Amplification)","definition":"単一の論理書き込みが、ストレージ層ではるかに多くの物理書き込みを引き起こすこと (LSM コンパクション、ページの書き直し、WAL、SSD ブロック消去)。値が高いとディスクが摩耗し、書き込みスループットが低下する。","tags":["storage","lsm","performance","ssd"]},{"term":"読み取り増幅 (Read Amplification)","full":"読み取り増幅 (Read Amplification)","definition":"単一の論理読み取りが、実際には複数の物理的/内部的な読み取りを必要とすること。LSM ツリーで多数のレベルにわたってキーを探すのが典型例で、ブルームフィルタとコンパクションで軽減される。","tags":["storage","lsm","performance"]},{"term":"LSM-tree","full":"ログ構造化マージツリー (Log-Structured Merge Tree)","definition":"書き込みをまずメモリ内の構造 (memtable) で吸収し、ソート済みブロック (SSTable) としてディスクにフラッシュし、バックグラウンドでマージする (コンパクション) データ構造。書き込み中心のワークロードに最適で、RocksDB と Cassandra で使われる。","tags":["storage","lsm","write-heavy"]},{"term":"B+tree","full":"B+ ツリー (B+ Tree)","definition":"リレーショナルデータベースのインデックスの古典的な構造。すべてのデータはリーフノードに保持され、リーフは連結リストでつながっている。ポイント検索と範囲検索でバランスのとれた読み取り性能を提供する。","tags":["index","btree","storage"]},{"term":"フィルファクタ (Fill Factor)","full":"フィルファクタ (Fill Factor)","definition":"インデックス/テーブルのページを初期にどれだけ満たすかを指定する比率。空き領域を残すと、将来の更新/挿入時のページ分割が減る。PG では fillfactor、MSSQL では fill factor。","tags":["index","storage","tuning"]},{"term":"HOT 更新 (HOT Update)","full":"ヒープオンリータプル更新 (Heap-Only Tuple Update)","definition":"PostgreSQL において、インデックス付き列を変更しない更新は、新しい行バージョンを同じページに作成し、インデックスを更新しない。インデックスの肥大化を抑え、更新コストを下げる。","tags":["postgres","mvcc","update","performance"]},{"term":"肥大化 (Bloat)","full":"テーブル/インデックスの肥大化 (Table/Index Bloat)","definition":"MVCC エンジンで、クリーンアップされていない不要な行バージョンや空ページにより、テーブル/インデックスが必要以上の領域を占めること。スキャンコストを増加させる。領域は VACUUM/reorg で回収する。","tags":["mvcc","postgres","maintenance","bloat"]},{"term":"Autovacuum","full":"自動 VACUUM (Automatic VACUUM)","definition":"dead tuple のクリーンアップ、統計情報の収集、トランザクション ID の凍結を自動で行う PostgreSQL のバックグラウンドプロセス。しきい値とコストのパラメータでワークロードに合わせて調整する。","tags":["postgres","vacuum","maintenance"]},{"term":"凍結 / 周回 (Freeze / Wraparound)","full":"トランザクション ID の凍結 / 周回 (Transaction ID Freeze / Wraparound)","definition":"PostgreSQL において、32 ビットのトランザクション ID の周回を防ぐため、古い行を「frozen」としてマークすること。怠ると、データベースはデータ損失を防ぐため書き込みの受付を停止する。","tags":["postgres","mvcc","vacuum","wraparound"]},{"term":"チェックポイント (Checkpoint)","full":"チェックポイント (Checkpoint)","definition":"メモリ上のダーティページがディスクに書き込まれ、リカバリの開始点が記録されるイベント。クラッシュリカバリ時間を短縮する。頻度は I/O のピークとリカバリ時間のトレードオフとなる。","tags":["recovery","wal","internals","checkpoint"]},{"term":"ファジーチェックポイント (Fuzzy Checkpoint)","full":"ファジーチェックポイント (Fuzzy Checkpoint)","definition":"システムを停止させずに、ダーティページをバックグラウンドで時間をかけて継続的に書き込むチェックポイントの種類。急激な I/O の増加 (チェックポイントスパイク) を避けて、応答時間を予測可能に保つ。","tags":["recovery","checkpoint","internals"]},{"term":"Redo","full":"Redo ログ / ロールフォワード (Redo Log / Roll Forward)","definition":"リカバリ時にトランザクションによる変更を再適用 (ロールフォワード) するために保持される記録。クラッシュ前にディスクに到達していなかったコミット済みの変更を復元する。","tags":["recovery","oracle","wal","redo"]},{"term":"Undo","full":"Undo ログ / ロールバック (Undo Log / Rollback)","definition":"トランザクションのロールバックと、MVCC のための古い行バージョンの提供に使われる記録。Oracle/InnoDB では、古いバージョンは undo セグメントから読み取られる。","tags":["mvcc","oracle","innodb","undo","rollback"]},{"term":"MVCC スナップショット (MVCC Snapshot)","full":"MVCC スナップショット (MVCC Snapshot)","definition":"トランザクションが一貫性のある読み取りを行えるよう、どの行バージョンが可視かを決める論理的な時点のビュー。トランザクションまたは文の開始時に取得される (分離レベルによる)。","tags":["mvcc","concurrency","isolation","snapshot"]},{"term":"分離の異常 (Isolation Anomaly)","full":"分離の異常 (Isolation Anomalies)","definition":"不十分な分離のもとで同時実行トランザクションが生む不整合: ダーティリード (未コミットデータの読み取り)、反復不能読み取り (同じ行が変わる)、ファントム (新しい行が現れる)、write skew (一見独立した書き込みが合わさってルールを破る)。","tags":["isolation","concurrency","anomaly","acid"]},{"term":"2PL","full":"2 相ロック (Two-Phase Locking)","definition":"ロックで直列化可能性を保証するプロトコル: トランザクションはまずロックの取得のみを行い (成長フェーズ)、ある時点以降は解放のみを行う (縮退フェーズ)。Strict 2PL はロックをコミットまで保持する。","tags":["concurrency","locking","serializable","2pl"]},{"term":"MVTO","full":"多版タイムスタンプ順序制御 (Multi-Version Timestamp Ordering)","definition":"トランザクションにタイムスタンプを割り当て、それに従ってマルチバージョンデータへの読み取り/書き込みを順序付ける同時実行制御方式。ロックの代わりにタイムスタンプで競合を解決する。","tags":["concurrency","mvcc","timestamp","protocol"]},{"term":"ミューテックス (Mutex)","full":"相互排他 (Mutual Exclusion)","definition":"一度に 1 つのスレッドのみがリソースにアクセスすることを保証する相互排他プリミティブ。データベースでは共有メモリ構造の保護においてラッチに似た役割を果たす。","tags":["concurrency","internals","mutex"]},{"term":"スピンロック (Spinlock)","full":"スピンロック (Spinlock)","definition":"ロックが解放されるまで、スレッドをスリープさせる代わりにループさせる (ビジーウェイト) ごく短時間のロック。非常に短いクリティカルセクションでは低コストだが、競合時には CPU を消費する。","tags":["concurrency","internals","spinlock","cpu"]},{"term":"バッファプール (Buffer Pool)","full":"バッファプール / バッファキャッシュ (Buffer Pool / Buffer Cache)","definition":"頻繁にアクセスされるデータページをメモリに保持してディスク I/O を減らすキャッシュ。エビクションアルゴリズム (LRU、clock-sweep) がどのページを追い出すかを決め、サイズはワーキングセットに応じて設定する。","tags":["memory","cache","internals","buffer"]},{"term":"ワーキングセット (Working Set)","full":"ワーキングセット (Working Set)","definition":"ワークロードが特定の時間枠内でアクティブにアクセスするデータの集合。バッファプールがこの集合を保持できる大きさであれば物理 I/O は最小化される。総データサイズとは異なる。","tags":["memory","cache","sizing","performance"]},{"term":"スキュー (Skew)","full":"データスキュー (Data Skew)","definition":"値が均等に分布せず、一部の値がはるかに頻繁に出現する状態。カーディナリティの誤推定、パラメータスニッフィングの問題、シャーディングのホットスポットの主な要因であり、ヒストグラムで対処する。","tags":["statistics","distribution","skew","performance"]},{"term":"プランキャッシュ (Plan Cache)","full":"プランキャッシュ (Plan Cache)","definition":"コンパイル済みの実行計画を再利用のために格納するメモリ領域。ハードパースのコストを回避するが、パラメータスニッフィングと古い計画のリスクを伴う。MSSQL では plan cache、Oracle では library cache。","tags":["optimizer","plan-cache","parsing"]},{"term":"ハード/ソフトパース (Hard/Soft Parse)","full":"ハードパース / ソフトパース (Hard Parse / Soft Parse)","definition":"ハードパース: SQL を一から解析・最適化し、計画を生成する (高コスト)。ソフトパース: キャッシュ内の既存の計画を見つけて再利用する (低コスト)。バインド変数はソフトパースの比率を高める。","tags":["parsing","oracle","performance","plan-cache"]},{"term":"コネクションストーム (Connection Storming)","full":"コネクションストーム (Connection Storm)","definition":"短時間に大量の新規データベース接続が同時に開かれること。接続確立のコストとメモリ負荷でデータベースを圧倒する。通常はプールの枯渇や再接続の波が原因である。","tags":["connections","pooling","overload"]},{"term":"サンダリングハード (Thundering Herd)","full":"サンダリングハード問題 (Thundering Herd Problem)","definition":"あるイベント (キャッシュの期限切れ、ロックの解放、サービスの復帰) の後に、多数のクライアントが同時に同じリソースへ殺到すること。バックプレッシャー、ジッター、single-flight パターンで緩和する。","tags":["concurrency","cache","overload","resilience"]},{"term":"バックプレッシャー (Backpressure)","full":"バックプレッシャー (Backpressure)","definition":"システムが処理しきれない負荷を受け入れる代わりに、生産者を減速させたり拒否したりすること (キュー上限、レート制限)。過負荷で崩壊する代わりに、緩やかな性能低下 (graceful degradation) を可能にする。","tags":["resilience","flow-control","overload"]},{"term":"リース (Lease)","full":"リース (Lease)","definition":"ノードに一定期間付与され、期限が切れると自動的に無効になるリーダーシップ/リソースの権利。時間制限があるため、停止したノードがいつまでもリーダーであり続けることを防ぐ。","tags":["distributed","leader-election","lease"]},{"term":"Read-Your-Writes","full":"Read-Your-Writes 一貫性 (Read-Your-Writes Consistency)","definition":"ユーザーが直後の読み取りで必ず自分の変更を参照できることを保証するセッション一貫性。ラグのあるレプリカにルーティングする場合は、特別なルーティング/トークンで実現する。","tags":["distributed","consistency","session","replication"]},{"term":"因果一貫性 (Causal Consistency)","full":"因果一貫性 (Causal Consistency)","definition":"結果整合性より強い一貫性モデルで、因果関係のある操作がすべてのノードで同じ順序で見えることを保証する。無関係な (同時の) 操作は異なる順序で見えることがある。","tags":["distributed","consistency","causal"]},{"term":"CAP","full":"一貫性 (Consistency)、可用性 (Availability)、分断耐性 (Partition tolerance)","definition":"ネットワーク分断中、分散システムは一貫性と可用性のどちらか一方しか選べないとする定理。分断がなければ、このトレードオフは必須ではない。","tags":["distributed","cap","consistency","theory"]},{"term":"PACELC","full":"PACELC 定理 (PACELC Theorem)","definition":"CAP を拡張したモデル: 分断時 (P) は可用性 (A) と一貫性 (C) の間で、それ以外 (E) はレイテンシ (L) と一貫性 (C) の間で選択する。通常運用時のレイテンシと一貫性のトレードオフもカバーする。","tags":["distributed","cap","pacelc","latency","theory"]},{"term":"ホットパーティション (Hot Partition)","full":"ホットパーティション / ホットスポット (Hot Partition / Hot Spot)","definition":"単一のパーティション/シャードに負荷が不釣り合いに集中すること。低カーディナリティ、時間ベース、または単調増加のシャードキーが原因で、そのノードがボトルネックとなりスケーリングが止まる。","tags":["distributed","sharding","hot-spot","skew"]},{"term":"列ストア (Columnstore)","full":"列指向ストレージ (Column-Oriented Storage)","definition":"データを行単位ではなく列単位で格納する形式。分析クエリは必要な列のみを読み取り、高い圧縮率とベクトル化実行の恩恵を受ける。OLAP に最適。","tags":["olap","columnar","analytics","compression"]},{"term":"ベクトル化実行 (Vectorized Execution)","full":"ベクトル化実行 (Vectorized Execution)","definition":"クエリ演算子が行ごとではなく、列値のブロック (バッチ) 単位で処理すること。CPU キャッシュと SIMD をより有効に使い、分析クエリのスループットを大幅に向上させる。","tags":["olap","execution","performance","columnar"]},{"term":"ゾーンマップ / Min-Max (Zone Map / Min-Max)","full":"ゾーンマップ / Min-Max インデックス (Zone Map / Min-Max Index)","definition":"データブロックごとに列の最小値と最大値を格納する軽量なメタデータ。クエリ述語に一致しえないブロックを読み取らずにスキップし (ブロックスキップ)、スキャンコストを削減する。","tags":["olap","index","pruning","columnar"]},{"term":"論理レプリケーション","full":"論理レプリケーション","definition":"物理ブロックではなく、行レベルの変更 (論理イベント) をパブリッシュ/サブスクライブするレプリケーション。テーブルの選択、バージョン間、双方向のシナリオが可能。PG の publication/subscription で提供される。","tags":["replication","postgres","logical","cdc"]},{"term":"GTID","full":"グローバルトランザクション識別子 (Global Transaction Identifier)","definition":"MySQL レプリケーションですべてのトランザクションに割り当てられるグローバルに一意な識別子。レプリカの位置をファイル/オフセットではなくトランザクション ID で追跡することで、フェイルオーバーと再構成を安全かつ簡単にする。","tags":["mysql","replication","gtid","failover"]},{"term":"最高水位標 (High Water Mark)","full":"最高水位標 (High Water Mark)","definition":"セグメント/テーブルでこれまでに使用された最も高いブロック境界。Oracle では全表スキャンがこの境界まで読み取る。大量削除後も下がらないため、空ブロックのスキャンや肥大化につながりうる。","tags":["oracle","storage","internals","scan"]}]},"playbooks/playbooks.json":{"schemaVersion":1,"playbooks":[{"id":"db-slow","title":"データベースが遅い","icon":"🐢","symptom":"アプリケーション全体が遅い。クエリに通常よりはるかに長い時間がかかり、ユーザーから苦情が出ている。","steps":[{"title":"まず何が遅いのかを正確に明らかにする","detail":"すべてが遅いのか、特定のクエリ/画面なのか。いつ始まり、デプロイ/パッチ/データ増加と重なるか。システム全体か、単一の DB か。これにより調査対象を CPU、I/O、ロック、計画変更のいずれか 1 つの軸に絞り込む。"},{"title":"アクティブセッションと待機イベントを確認する","detail":"今何が実行され、何が待機しているか。支配的な待機イベント (I/O、ロック、ログ) がボトルネックを示す。","engines":{"oracle":"SELECT sid, username, status, event, sql_id FROM v$session WHERE status='ACTIVE' AND type='USER';","postgres":"SELECT pid, state, wait_event_type, wait_event, query FROM pg_stat_activity WHERE state='active';","mysql":"SELECT id, user, command, time, state, info FROM information_schema.processlist WHERE command<>'Sleep' ORDER BY time DESC;","mssql":"SELECT session_id, status, wait_type, wait_time, blocking_session_id FROM sys.dm_exec_requests WHERE session_id IN (SELECT session_id FROM sys.dm_exec_sessions WHERE is_user_process = 1);","mongodb":"db.currentOp({ active: true, secs_running: { $gt: 1 } })","redis":"SLOWLOG GET 10"}},{"title":"ブロッキングを確認する","detail":"遅延の最も一般的な原因は、1 つのセッションが他をブロックしていること。ブロッキングセッションを見つけ、チェーンの先頭を特定する。","engines":{"oracle":"SELECT blocking_session, sid, seconds_in_wait, event FROM v$session WHERE blocking_session IS NOT NULL;","postgres":"SELECT pid, pg_blocking_pids(pid) AS blocked_by, query FROM pg_stat_activity WHERE cardinality(pg_blocking_pids(pid))>0;","mysql":"SELECT * FROM sys.innodb_lock_waits\\G","mssql":"SELECT session_id, blocking_session_id, wait_type FROM sys.dm_exec_requests WHERE blocking_session_id<>0;"}},{"title":"最も高コストなクエリを抽出する","detail":"最もリソースを消費している上位 10 件のクエリを見つける。通常、問題の 90% は少数のクエリに起因する。","engines":{"oracle":"SELECT sql_id, elapsed_time/1e6 sec, executions, sql_text FROM v$sql ORDER BY elapsed_time DESC FETCH FIRST 10 ROWS ONLY;","postgres":"SELECT calls, total_exec_time, mean_exec_time, query FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 10;","mysql":"SELECT digest_text, count_star, sum_timer_wait/1e12 sec FROM performance_schema.events_statements_summary_by_digest ORDER BY sum_timer_wait DESC LIMIT 10;","mssql":"SELECT TOP 10 total_elapsed_time/execution_count avg_us, execution_count, SUBSTRING(t.text,1,200) FROM sys.dm_exec_query_stats qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t ORDER BY total_elapsed_time DESC;"}},{"title":"疑わしいクエリの計画を調べる","detail":"遅いクエリの EXPLAIN を取得する。全表スキャン、インデックスの欠如、不適切な結合順序、古い統計情報を探す。計画が突然変わった場合は、統計情報の収集を検討する。","engines":{"oracle":"SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('&sql_id', NULL, 'ALLSTATS LAST'));","postgres":"EXPLAIN (ANALYZE, BUFFERS) <query>;","mysql":"EXPLAIN ANALYZE <query>;","mssql":"SET STATISTICS PROFILE ON; <query>; SET STATISTICS PROFILE OFF;","mongodb":"db.my_collection.find({...}).explain('executionStats')  // COLLSCAN or IXSCAN?"}},{"title":"システムリソースを確認する","detail":"OS レベルで CPU、I/O 待機 (iowait)、メモリ、ディスク使用量を確認する。キャッシュヒット率を確認し、低ければメモリのボトルネックの可能性がある。問題が DB の外にあることもある (ディスクフル、ノイジーネイバー VM)。"},{"title":"判断: 応急処置か恒久対策か","detail":"即時の緩和: 暴走クエリを強制終了し、欠けているインデックスを追加し、統計情報を収集する。恒久対策: クエリ/インデックスを再設計し、メモリ設定を修正し、計画の安定性を確保する (ベースライン/ヒント)。"}],"related":["active-sessions","blocking-sessions","top-slow-queries","explain-plan","cache-hit-ratio"]},{"id":"disk-full","title":"ディスク / 表領域が満杯","icon":"💽","symptom":"'unable to extend'、'disk full'、'log file full' エラー。書き込みが停止しつつある。","steps":[{"title":"慌てず、まず何が満杯かを特定する","detail":"データファイル、トランザクションログ、アーカイブ/redo 領域、temp、OS ディスクのどれか。誤った場所をクリーンアップしても効果はない。OS レベルでは df -h でディスクを、DB 内では領域ビューを確認する。"},{"title":"使用量を測定する","detail":"どの表領域/ファイル/ディレクトリが、何パーセント満杯か。","engines":{"oracle":"SELECT d.tablespace_name, ROUND((1-(d.alloc-NVL(f.free,0))/d.maxb)*100,1) pct_free FROM (SELECT tablespace_name, SUM(bytes) alloc, SUM(GREATEST(bytes,maxbytes)) maxb FROM dba_data_files GROUP BY tablespace_name) d LEFT JOIN (SELECT tablespace_name, SUM(bytes) free FROM dba_free_space GROUP BY tablespace_name) f ON f.tablespace_name = d.tablespace_name;","postgres":"SELECT datname, pg_size_pretty(pg_database_size(datname)) FROM pg_database ORDER BY 2 DESC; -- use OS df for the disk","mysql":"SELECT table_schema, ROUND(SUM(data_length+index_length)/1048576,1) mb FROM information_schema.tables GROUP BY table_schema ORDER BY mb DESC;","mssql":"SELECT name, size/128.0 size_mb, size/128.0 - CAST(FILEPROPERTY(name,'SpaceUsed') AS int)/128.0 free_mb FROM sys.database_files;","redis":"INFO memory  # used_memory vs maxmemory"}},{"title":"最大の消費元を見つける","detail":"最大のテーブル/セグメント、最大のログ/アーカイブファイル、不要な古いバックアップを特定する。ほとんどの場合、単一の暴走テーブルか蓄積したアーカイブログが原因である。","engines":{"oracle":"SELECT segment_name, bytes/1048576 mb FROM dba_segments ORDER BY bytes DESC FETCH FIRST 10 ROWS ONLY;","postgres":"SELECT relname, pg_size_pretty(pg_total_relation_size(relid)) FROM pg_statio_user_tables ORDER BY pg_total_relation_size(relid) DESC LIMIT 10;","mssql":"SELECT TOP 10 OBJECT_NAME(object_id), SUM(reserved_page_count)*8/1024 mb FROM sys.dm_db_partition_stats GROUP BY object_id ORDER BY mb DESC;"}},{"title":"領域を安全に回収する (応急)","detail":"ログ/アーカイブの場合: バックアップしてから古いアーカイブログ/バックアップを削除する (Oracle: RMAN delete archivelog、MSSQL: ログバックアップを取ってログを圧縮)。Redis では maxmemory-policy とエビクション。稼働中のデータファイルを決して手動で削除しないこと。バックアップなしにアーカイブログを決して削除しないこと。"},{"title":"容量を恒久的に増やす","detail":"データファイルに領域を追加するか autoextend を有効にし (Oracle: ALTER DATABASE DATAFILE ... AUTOEXTEND ON MAXSIZE)、ディスクを拡張し、表領域を追加する。根本原因を修正する: ログローテーション、アーカイブクリーンアップジョブ、保持ポリシー。"},{"title":"再発を防止する","detail":"ディスク使用量のアラート (80%/90% のしきい値) を設定し、アーカイブ/ログのクリーンアップを自動化し、保持ポリシーを明確に定義する。このプレイブックを再び開く必要がないようにする。"}],"related":["free-space","largest-tables","database-size","reclaim-space","last-backup-status"]},{"id":"blocking","title":"ブロッキングとロックの危機","icon":"🔒","symptom":"クエリがハングする、'lock wait timeout'、多数のセッションが待機しているが CPU は低い。","steps":[{"title":"ブロッキングチェーンの先頭 (根本ブロッカー) を見つける","detail":"誰が誰をブロックしているかを把握する。真の原因は、自身は何も待たずに他を待たせているセッションである。チェーンの最上位のセッションに集中する。","engines":{"oracle":"SELECT blocking_session, sid, serial#, username, seconds_in_wait, sql_id FROM v$session WHERE blocking_session IS NOT NULL ORDER BY seconds_in_wait DESC;","postgres":"SELECT pid, usename, pg_blocking_pids(pid) blocked_by, state, query FROM pg_stat_activity WHERE cardinality(pg_blocking_pids(pid))>0;","mysql":"SELECT waiting_pid, waiting_query, blocking_pid, blocking_query FROM sys.innodb_lock_waits;","mssql":"SELECT session_id, blocking_session_id, wait_type, wait_resource FROM sys.dm_exec_requests WHERE blocking_session_id<>0;","mongodb":"db.currentOp({ waitingForLock: true })"}},{"title":"根本ブロッカーが何をしているかを把握する","detail":"開いたまま未コミットのトランザクションか。アプリケーションが 'idle in transaction' のまま放置したか。長いバッチか。やみくもに強制終了する前に正体を把握する。もうすぐ終わるかもしれない。","engines":{"oracle":"SELECT s.sid, s.prev_sql_id, t.start_time, t.used_ublk FROM v$transaction t JOIN v$session s ON t.ses_addr=s.saddr;","postgres":"SELECT pid, state, xact_start, now()-xact_start age, query FROM pg_stat_activity WHERE pid=<root_pid>;"}},{"title":"判断: 待つか、アプリケーション側で解決するか、強制終了するか","detail":"もうすぐ終わるなら待つ。アプリケーションがコミット/ロールバックできるなら、それを実行させる。そうでなく業務が停止しているなら、根本ブロッカーを終了する。強制終了の前に影響 (ロールバック時間、データ) を考慮する。"},{"title":"必要に応じて根本ブロッカーを終了する","detail":"チェーンの先頭のセッションのみを強制終了する。その下のセッションは自動的に解放される。","engines":{"oracle":"ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;","postgres":"SELECT pg_terminate_backend(<root_pid>);","mysql":"KILL <root_id>;","mssql":"KILL <root_session_id>;","mongodb":"db.killOp(<opid>)"}},{"title":"根本原因を修正する","detail":"インデックスの欠如が広範なロックを引き起こしている可能性、アプリケーションがトランザクションを長く開きすぎている可能性、分離レベルが誤っている可能性がある。インデックスを追加し、トランザクションを短くし、'idle in transaction' のタイムアウトを設定し、適切な分離レベルを選ぶ。"}],"related":["blocking-sessions","kill-session","open-transactions"]},{"id":"connection-storm","title":"コネクションストーム (接続数過多)","icon":"🌊","symptom":"'too many connections'、'ORA-00018'、'remaining connection slots reserved' — 新規接続が拒否されている。","steps":[{"title":"現在の状態を測定する","detail":"接続数はいくつで、上限はいくつか。アクティブとアイドルはそれぞれいくつか。","engines":{"oracle":"SELECT COUNT(*) total, SUM(CASE WHEN status='ACTIVE' THEN 1 ELSE 0 END) active FROM v$session WHERE type='USER';","postgres":"SELECT count(*), state FROM pg_stat_activity WHERE backend_type = 'client backend' GROUP BY state;","mysql":"SHOW STATUS LIKE 'Threads_connected'; SHOW VARIABLES LIKE 'max_connections';","mssql":"SELECT COUNT(*), status FROM sys.dm_exec_sessions WHERE is_user_process=1 GROUP BY status;","redis":"INFO clients"}},{"title":"発生元を特定する: 誰が、どこから","detail":"どのアプリケーション/ホスト/ユーザーが接続を開いているか。通常は単一のアプリケーションサーバーのプールが膨張しているか、接続リーク (大量の idle in transaction セッション) がある。","engines":{"postgres":"SELECT client_addr, usename, state, count(*) FROM pg_stat_activity WHERE backend_type = 'client backend' GROUP BY 1,2,3 ORDER BY 4 DESC;","mysql":"SELECT host, user, count(*) FROM information_schema.processlist GROUP BY host, user ORDER BY 3 DESC;","mssql":"SELECT host_name, program_name, login_name, COUNT(*) FROM sys.dm_exec_sessions WHERE is_user_process=1 GROUP BY host_name, program_name, login_name ORDER BY 4 DESC;"}},{"title":"すぐに余裕を確保する","detail":"長時間アイドル/idle in transaction の接続をクリーンアップする。必要なら、問題のアプリケーションの接続を一括で切断する。管理者ログイン用に予約されたスロット (PG superuser_reserved_connections) を使う。"},{"title":"正しい対策: コネクションプーリング","detail":"max_connections を無制限に上げるとメモリを消費し、問題を先送りするだけである。正しい対策は、アプリケーション側のコネクションプール (HikariCP、PgBouncer、ProxySQL) を妥当なプールサイズで使うこと。プールサイズは通常 (コア数*2 + ディスク数) 程度 — ツール > Connection Pool 計算ツールを参照。"},{"title":"リークと再発を防止する","detail":"アプリケーションが接続を確実にクローズするようにする (finally/using)。idle_in_transaction_session_timeout と wait_timeout を設定する。接続数のアラートを設定する。"}],"related":["connection-count","kill-session","open-transactions"]},{"id":"replication-lag","title":"レプリケーションの遅延 / 停止","icon":"🔁","symptom":"スタンバイ/レプリカが遅延している、または完全に停止している。読み取りレプリカが古いデータを表示している。","steps":[{"title":"ラグの大きさと、増加中か一定か","detail":"ラグは秒/バイトでどれだけか。一定のずれか、継続的に増加しているか。増加しているならレプリカは適用に追いつけておらず、一定なら一時的な停滞があった。","engines":{"oracle":"SELECT name, value, unit FROM v$dataguard_stats WHERE name LIKE '%lag%';","postgres":"SELECT client_addr, state, write_lag, flush_lag, replay_lag FROM pg_stat_replication;","mysql":"SHOW REPLICA STATUS\\G  -- Seconds_Behind_Source","mssql":"SELECT ar.replica_server_name, drs.redo_queue_size, drs.log_send_queue_size FROM sys.dm_hadr_database_replica_states drs JOIN sys.availability_replicas ar ON drs.replica_id=ar.replica_id;","redis":"INFO replication  # master_repl_offset vs slave offset"}},{"title":"レプリケーションは動作しているか、エラーはあるか","detail":"IO/SQL スレッドの状態、適用プロセスはどうか。接続が切れていないか。エラー (例: 競合する行、存在しないテーブル) があれば適用は停止している。エラーメッセージを読む。","engines":{"mysql":"SHOW REPLICA STATUS\\G  -- Replica_IO_Running / Replica_SQL_Running / Last_Error","postgres":"SELECT status, last_msg_receipt_time, latest_end_lsn FROM pg_stat_wal_receiver;  -- on the standby","oracle":"SELECT process, status, sequence#, thread# FROM v$managed_standby WHERE process LIKE 'MRP%' OR process LIKE 'RFS%';"}},{"title":"ボトルネックを見つける","detail":"なぜ追いつけないのか。シングルスレッドの適用と重い書き込み負荷 (PG/MySQL は主に直列に適用する)、スタンバイの I/O ボトルネック、ネットワーク、あるいは適用をブロックする長いクエリ (PG hot_standby_feedback / リカバリ競合) か。"},{"title":"ラグを解消する","detail":"適用を高速化する: 並列適用を有効にし (MySQL replica_parallel_workers — 8.0.26 より前は slave_parallel_workers。PG にはないがリカバリ設定がある)、スタンバイの I/O を改善し、適用をブロックするクエリを解消する。エラーで停止した場合: エラーを修正し (競合する行を手動で解決)、レプリケーションを再開する。"},{"title":"壊れている場合は再構築する","detail":"レプリカが大きく遅延している/壊れている場合は、再同期が最もクリーンである: 新しいバックアップからスタンバイを再構築する (PG pg_basebackup、MySQL clone/xtrabackup、Oracle RMAN duplicate)。重要: 再構築の前に原因を特定すること。さもなければ再発する。"}],"related":["replication-status","list-replicas","promote-failover"]},{"id":"high-cpu","title":"高い CPU 使用率","icon":"🔥","symptom":"サーバーの CPU が 90% 以上。システム全体が遅く、ロードアベレージが高い。","steps":[{"title":"実際に DB が CPU を消費しているかを確認する","detail":"OS レベルで top/mpstat を使い、CPU を消費しているプロセスが本当に DB かを確認する。隣接プロセスやバックアップ/アンチウイルスが消費元であることもある。iowait が高ければ、問題は CPU ではなくディスクである。"},{"title":"CPU を最も使用しているクエリを見つける","detail":"CPU 時間順に上位のクエリを抽出する。通常は少数のクエリ (悪い計画、全表スキャン、インデックスの欠如) が CPU を消費している。","engines":{"oracle":"SELECT sql_id, cpu_time/1e6 cpu_sec, executions, sql_text FROM v$sql ORDER BY cpu_time DESC FETCH FIRST 10 ROWS ONLY;","postgres":"SELECT query, calls, total_exec_time, mean_exec_time FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 10;","mysql":"SELECT digest_text, count_star, sum_timer_wait/1e12 sec FROM performance_schema.events_statements_summary_by_digest ORDER BY sum_timer_wait DESC LIMIT 10;","mssql":"SELECT TOP 10 total_worker_time/execution_count avg_cpu, execution_count, SUBSTRING(t.text,1,200) FROM sys.dm_exec_query_stats q CROSS APPLY sys.dm_exec_sql_text(q.sql_handle) t ORDER BY total_worker_time DESC;"}},{"title":"計画/インデックスの問題を確認する","detail":"問題のクエリの計画を取得する。全表スキャン、ネステッドループの爆発、ハッシュ結合のスピル、パラメータスニッフィング/古い統計情報による悪い計画が CPU を消費する。インデックスを追加するか、統計情報を収集する。"},{"title":"即座に緩和する","detail":"暴走クエリを強制終了し、必要に応じて Resource Manager/Resource Governor で制限する。突然始まった負荷については、直近のデプロイ/パラメータ変更を確認する。"},{"title":"恒久的に修正する","detail":"クエリ/インデックスを修正し、計画の安定性を確保し、統計情報収集ジョブをスケジュールする。CPU が常に 100% なら、スケーリング (CPU の追加、読み取りレプリカへの読み取りの分散) が必要になりうる。"}],"related":["top-slow-queries","explain-plan","active-sessions","update-statistics"]},{"id":"memory-pressure","title":"メモリ負荷 / OOM","icon":"🧠","symptom":"OOM killer がプロセスを強制終了する、'out of memory'、低いキャッシュヒット率、過剰なスワップ、Redis の 'OOM command not allowed'。","steps":[{"title":"誰がメモリを消費しているか","detail":"DB に割り当てられたメモリ (バッファプール/SGA)、セッションごとのメモリ (PGA/sort/work_mem)、OS 全体のどれか。OS レベルで free/vmstat を、DB 内でメモリビューを確認する。","engines":{"oracle":"SELECT component, current_size/1048576 mb FROM v$memory_dynamic_components WHERE current_size>0;","postgres":"SHOW shared_buffers; SHOW work_mem; -- work_mem * connections * number of sorts can blow up in total","mysql":"SHOW VARIABLES LIKE 'innodb_buffer_pool_size'; SHOW STATUS LIKE 'Innodb_buffer_pool%';","redis":"INFO memory  # used_memory, maxmemory, mem_fragmentation_ratio"}},{"title":"設定と負荷を切り分ける","detail":"メモリ設定の合計が物理 RAM を超えていないか (オーバーコミット)。shared_buffers + (work_mem * 同時実行数) を計算する。あるいは一時的な負荷 (巨大なソート/ハッシュ、多数の接続) か。"},{"title":"Redis 固有: エビクションと断片化","detail":"used_memory が maxmemory に達している場合は maxmemory-policy を確認する (noeviction では書き込みが拒否される)。mem_fragmentation_ratio が高ければ MEMORY PURGE / activedefrag を使う。大きなキーは --bigkeys で見つける。","engines":{"redis":"CONFIG GET maxmemory-policy\nMEMORY DOCTOR\nredis-cli --bigkeys"}},{"title":"即座に緩和する","detail":"メモリを食っている暴走クエリ/セッションを強制終了し、work_mem などのセッションメモリを一時的に下げ、不要な接続を切断する。システムがスワップしているなら、スワップからの脱出が最優先。"},{"title":"適切にサイジングする","detail":"ツール > Memory/Buffer Pool 計算ツールで RAM を適切に配分する。一般則: 専用サーバーではバッファプール/SGA は RAM の ~70-80%。セッションメモリの合計に同時実行数を掛け、RAM を超えないようにする。必要なら RAM を追加する。"}],"related":["cache-hit-ratio","show-config-param","reclaim-space"]},{"id":"log-growth","title":"トランザクションログ / undo の肥大化","icon":"📈","symptom":"トランザクションログファイルまたは undo/redo 領域が急速に増大している。'log full'、'ORA-01555 snapshot too old'、'unable to extend undo'。","steps":[{"title":"ログを増大させている開いたトランザクションを見つける","detail":"最も古いアクティブトランザクションが終了するまで、ログ/undo はクリアできない。単一の長時間開いたトランザクションがログ全体を固定していることがある。","engines":{"oracle":"SELECT s.sid, s.username, t.start_time, t.used_ublk FROM v$transaction t JOIN v$session s ON t.ses_addr=s.saddr ORDER BY t.start_time;","postgres":"SELECT pid, state, xact_start, now()-xact_start age, query FROM pg_stat_activity WHERE xact_start IS NOT NULL ORDER BY xact_start;","mysql":"SELECT trx_id, trx_started, trx_mysql_thread_id FROM information_schema.innodb_trx ORDER BY trx_started;","mssql":"DBCC OPENTRAN;"}},{"title":"エンジン固有の根本原因を把握する","detail":"MSSQL: FULL 復旧モデルでは、ログバックアップを取らないとログは際限なく増大する。Oracle: ORA-01555 = undo の保持期間/サイズ不足 + 長いクエリ。PG: レプリケーションスロットが進まないと WAL が蓄積し、長いトランザクションは VACUUM をブロックする。"},{"title":"MSSQL ログに対する正しい対処","detail":"ログバックアップ (BACKUP LOG) を取る — これでログが再利用可能になる。復旧モデルが本当に SIMPLE であるべきなら変更する。その後、必要なら (必要な場合のみ) ログを圧縮する。","engines":{"mssql":"BACKUP LOG [DB] TO DISK='C:\\backup\\DB_log.trn';\n-- Then, if needed: DBCC SHRINKFILE (N'DB_log', 512);"}},{"title":"PG の WAL / レプリケーションスロットの確認","detail":"進まない (非アクティブな) レプリケーションスロットは WAL の蓄積を引き起こす。削除する前にスロットの所有者 (slot_type、database、plugin) を確認する: 一時的に切断されたスタンバイや、論理サブスクライバー/CDC (例: Debezium) かもしれない。スロットを削除すると、接続していたスタンバイは再構築が必要になり、サブスクライバー/CDC 側は再同期が必要になる。本当に未使用の場合のみ削除する。恒久的な保護には max_slot_wal_keep_size (PG13+) で上限を設定する。","engines":{"postgres":"SELECT slot_name, active, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) retained FROM pg_replication_slots ORDER BY 3 DESC;\n-- If unneeded: SELECT pg_drop_replication_slot('slot_name');"}},{"title":"undo/保持期間を調整し、再発を防止する","detail":"Oracle: UNDO 表領域を拡張し、長いクエリに合わせて undo_retention を設定する (または RETENTION GUARANTEE)。アプリケーションで長時間開いたトランザクションを防ぐ。ログバックアップジョブが実行されていることを監視する。"}],"related":["open-transactions","reclaim-space","last-backup-status"]},{"id":"deadlocks","title":"デッドロック分析","icon":"♻️","symptom":"'deadlock detected'、'ORA-00060'、'chosen as deadlock victim' — トランザクションが互いをロックし、1 つが中断される。","steps":[{"title":"デッドロックは正常だが、頻発すべきではない","detail":"DB はデッドロックを検出し、犠牲者を選んで解決する — これは設計どおりの動作である。目標は頻度を減らすこと。アプリケーションは犠牲になったトランザクションを再試行すべきである。まずデッドロックグラフを取得する。"},{"title":"デッドロックグラフ/詳細を取得する","detail":"どの 2 つ (以上) のセッションが、どのリソースとどのロックモードで競合したか。","engines":{"oracle":"-- Check the trace file referenced in the alert log (deadlock graph). Also:\nSELECT * FROM dba_hist_active_sess_history WHERE event LIKE 'enq: TX%' ORDER BY sample_time DESC;","postgres":"-- log_lock_waits=on; deadlock details are in postgresql.log. Check the deadlock_timeout setting.","mysql":"SHOW ENGINE INNODB STATUS\\G  -- LATEST DETECTED DEADLOCK section","mssql":"-- Deadlock XML in the system_health Extended Events session (ring_buffer, recent events):\nSELECT x.ev.value('@timestamp','datetime2') AS event_time, x.ev.query('.') AS deadlock_xml\nFROM (SELECT CAST(t.target_data AS XML) td FROM sys.dm_xe_session_targets t\n      JOIN sys.dm_xe_sessions s ON s.address = t.event_session_address\n      WHERE s.name = N'system_health' AND t.target_name = N'ring_buffer') r\nCROSS APPLY r.td.nodes('//RingBufferTarget/event[@name=\"xml_deadlock_report\"]') AS x(ev);\n-- For longer history, the event_file target:\n-- SELECT CAST(event_data AS XML) FROM sys.fn_xe_file_target_read_file(N'system_health*.xel', NULL, NULL, NULL) WHERE object_name = N'xml_deadlock_report';"}},{"title":"競合パターンを解消する","detail":"最も一般的な原因: 2 つのトランザクションがリソースに逆の順序でアクセスしていること。すべてのコードパスで同じ順序でリソースにアクセスする。2 番目に多い原因: インデックスの欠如による広範な範囲ロック — 必要なインデックスを追加する。"},{"title":"ロックの期間と範囲を縮小する","detail":"トランザクションを短く保つ (トランザクション内にユーザー操作を含めない)。適切な分離レベルを選ぶ。必要な場合は行ロックを早期に取得する (決定的な順序での SELECT ... FOR UPDATE)。"},{"title":"アプリケーションでの再試行は必須","detail":"デッドロックを完全になくすことはできない。犠牲になったトランザクションに自動再試行 (指数バックオフ) を実装する。これによりユーザーにエラーを見せずに済む。"}],"related":["blocking-sessions","open-transactions","list-indexes"]},{"id":"db-down","title":"データベースがオープンしない / 到達不能","icon":"🚨","symptom":"サービスに接続できない、'connection refused'、インスタンスが起動しない、リスナーが応答しない。","steps":[{"title":"どこで壊れているか: ネットワーク、サービス、インスタンス","detail":"サーバーに到達できるか (ping/ssh)。DB プロセス/サービスは動作しているか (ps/systemctl/services.msc)。ポートはリッスンしているか (ss -ltnp / telnet host port)。これで問題をネットワーク / サービス / データベースインスタンスのいずれかの層に特定する。"},{"title":"サービスとリスナーを確認する","detail":"DB プロセスが起動していなければ起動を試みる。起動しているのに接続が失敗する場合は、リスナー/ポートと認証層を確認する。","engines":{"oracle":"-- OS: lsnrctl status  (listener)\n-- SQL*Plus: STARTUP;  (if the instance is down)\nSELECT status FROM v$instance;","postgres":"-- OS: systemctl status postgresql ; pg_isready -h host\n-- Logs: the last lines tell why it did not start","mysql":"-- OS: systemctl status mysqld ; mysqladmin ping","mssql":"-- Services / SQL Server Configuration Manager; SQL Server Error Log","redis":"redis-cli ping  # expect PONG"}},{"title":"ログを読む — 答えはそこにある","detail":"DB がオープンしない場合、理由はログに書かれている: alert log (Oracle)、postgresql.log / 起動ログ、mysqld エラーログ、SQL Server ERRORLOG、redis ログ。ディスクフル、ファイルの破損、権限、ポートの競合、ファイルの欠落 — すべてここに現れる。"},{"title":"一般的な原因に対処する: ディスク、権限、ポート、破損","detail":"ディスクが 100% 満杯ではないか (最も一般的な原因)。データディレクトリの権限が壊れていないか。ポートが別のプロセスに使われていないか。(クラッシュ後に) リカバリが必要か。制御ファイル/redo ログが破損していないか。ログのメッセージに基づき、それぞれに対処する。"},{"title":"復旧し、インシデント記録を残す","detail":"クラッシュリカバリは通常自動で完了するので、辛抱強く待つ。破損がある場合はバックアップ/PITR から復旧する (破損プレイブックを参照)。その後、根本原因分析 (RCA) を書く: 何が起きたか、なぜか、再発をどう防ぐか。"}],"related":["version-uptime","connect-cli","last-backup-status"]},{"id":"corruption","title":"データ破損","icon":"🧯","symptom":"'ORA-01578'、'page corruption'、'checksum mismatch'、'MISCONF'、読み取り時の I/O 一貫性エラー。","steps":[{"title":"冷静さを保ち、拡大を止める","detail":"慌てた介入は事態を悪化させる。まず範囲を特定し、可能なら影響を受けたオブジェクトへの書き込みを停止する。ハードウェア関連 (ディスク/コントローラー) であれば OS/ハードウェアのログも確認する — DB を直してもディスクは直らない。"},{"title":"範囲を特定する: どれだけ破損しているか","detail":"単一のブロック/ページ/オブジェクトか、広範囲か。整合性チェックを実行する。","engines":{"oracle":"RMAN> VALIDATE DATABASE;  -- or: SELECT * FROM v$database_block_corruption;","postgres":"-- With data_checksums enabled it shows up in the logs; check indexes/heap with pg_amcheck:\n-- pg_amcheck --heapallindexed -d mydb","mysql":"CHECK TABLE customer;  -- for InnoDB, innodb_force_recovery is the last resort","mssql":"DBCC CHECKDB ('MyDB') WITH NO_INFOMSGS, ALL_ERRORMSGS;","redis":"redis-check-rdb dump.rdb\n# AOF (Redis 7+ multi-part: under appendonlydir/, pass the manifest file):\nredis-check-aof appendonlydir/appendonly.aof.manifest\n# --fix TRUNCATES everything after the corrupted point (writes in that part are lost); back up the directory first:\n# redis-check-aof --fix appendonlydir/appendonly.aof.manifest"}},{"title":"優先事項: バックアップからの復旧","detail":"破損時の最も安全な方法は、正常なバックアップからのリストアである。ブロック/ページレベルの復旧がサポートされていれば、破損部分のみを復旧する (Oracle RMAN BLOCKRECOVER、MSSQL ページリストア)。修復ツール (DBCC REPAIR_ALLOW_DATA_LOSS、innodb_force_recovery) はデータ損失を引き起こす — 最後の手段である。"},{"title":"整合性を検証する","detail":"復旧後、チェック (DBCC CHECKDB / RMAN VALIDATE / CHECK TABLE) を再実行し、クリーンな結果になることを確認する。アプリケーション側でもデータの整合性 (行数、重要な合計値) を検証する。"},{"title":"根本原因: 通常はハードウェア","detail":"破損は通常、ディスク/メモリ/コントローラーの障害に起因する。ハードウェアをテスト/交換し、チェックサムを有効にし (data_checksums、PAGE_VERIFY CHECKSUM)、バックアップと検証の運用を強化する。DBCC CHECKDB / RMAN VALIDATE を定期的にスケジュールする。"}],"related":["last-backup-status","restore-dump","db-down"]},{"id":"long-running-query","title":"長時間実行クエリ / ジョブ","icon":"⏱️","symptom":"単一のクエリ/ジョブが何時間も終わらずに実行されている。リソースを消費するか、他に影響を与えている。","steps":[{"title":"クエリとその実行時間を把握する","detail":"どのクエリが、どれだけの時間実行されているか。どのユーザー/アプリケーションか。","engines":{"oracle":"SELECT sid, serial#, sql_id, last_call_et/60 running_min, username FROM v$session WHERE status='ACTIVE' AND type='USER' ORDER BY last_call_et DESC;","postgres":"SELECT pid, now()-query_start dur, usename, query FROM pg_stat_activity WHERE state='active' ORDER BY query_start;","mysql":"SELECT id, user, time, state, info FROM information_schema.processlist WHERE command='Query' ORDER BY time DESC;","mssql":"SELECT session_id, total_elapsed_time/1000 sec, status, command FROM sys.dm_exec_requests WHERE session_id IN (SELECT session_id FROM sys.dm_exec_sessions WHERE is_user_process = 1) ORDER BY total_elapsed_time DESC;","mongodb":"db.currentOp({ active: true, secs_running: { $gt: 60 } })"}},{"title":"進行しているか、停止しているか","detail":"本当に実行中か、それともロックを待っているか。進捗指標を確認する (Oracle v$session_longops、PG pg_stat_progress_* ビュー)。待機している場合は、ブロッキングのプレイブックに切り替える。","engines":{"oracle":"SELECT sid, opname, sofar, totalwork, ROUND(sofar/NULLIF(totalwork,0)*100,1) pct, time_remaining FROM v$session_longops WHERE sofar<totalwork;","postgres":"SELECT * FROM pg_stat_progress_create_index;  -- or pg_stat_progress_vacuum / _cluster / _analyze"}},{"title":"判断: 待つか、キャンセルするか","detail":"進行中でまもなく終わるなら待つ (キャンセルによるロールバックのコストでさらに時間がかかることがある)。停止している、誤って実行されている、または本番に影響している場合は終了する。キャンセルの前にロールバック時間を考慮する。"},{"title":"必要に応じて終了する","detail":"まずクエリのみのキャンセル (セッションは維持) を優先し、効かなければセッションを強制終了する。","engines":{"oracle":"ALTER SYSTEM CANCEL SQL 'sid,serial#';  -- 18c+; otherwise KILL SESSION","postgres":"SELECT pg_cancel_backend(pid);  -- otherwise pg_terminate_backend(pid)","mysql":"KILL QUERY <id>;","mssql":"KILL <session_id>;","mongodb":"db.killOp(<opid>)"}},{"title":"恒久的に修正する","detail":"クエリを最適化し (インデックス、計画、ページネーション/バッチ化)、重いジョブはオフピーク時間に移し、必要なら分割して実行する。定期的なレポートには、マテリアライズドビュー / 読み取りレプリカを検討する。"}],"related":["active-sessions","kill-session","explain-plan","top-slow-queries"]},{"id":"xid-wraparound","title":"Postgres の XID 周回 / autovacuum の危機","icon":"🧬","symptom":"'database is not accepting commands to avoid wraparound data loss'。autovacuum が追いつかず、datfrozenxid が古くなっている。","steps":[{"title":"緊急度を把握する","detail":"PostgreSQL のトランザクション ID は 32 ビットである。枯渇が近づくと、サーバーはデータ損失を防ぐため書き込みを停止する。これは重大で時間的制約のある状況である。良い知らせ: 解決可能である。必要なのはパニックではなく規律である。"},{"title":"どれだけ近づいているかを測定する","detail":"各データベースの最も古い未凍結 XID の経過年齢を抽出する。autovacuum_freeze_max_age (デフォルト 200M) への近さが危険度を示す。","engines":{"postgres":"SELECT datname, age(datfrozenxid) AS xid_age\nFROM pg_database ORDER BY xid_age DESC;"}},{"title":"最も古いテーブルを見つける","detail":"問題は通常、少数の大きい/頻繁に書き込まれるテーブルに起因する。最も古い relfrozenxid の値に集中する。","engines":{"postgres":"SELECT relname, age(relfrozenxid) AS xid_age\nFROM pg_class WHERE relkind IN ('r','m','t')\nORDER BY xid_age DESC LIMIT 20;"}},{"title":"VACUUM をブロックしているものを取り除く","detail":"長時間開いたトランザクション、放棄されたレプリケーションスロット、準備済みトランザクションはクリーンアップ (凍結) をブロックする。それらを見つけて解消する — さもなければ VACUUM はどれだけ長く実行しても進まない。","engines":{"postgres":"SELECT pid, now()-xact_start AS age, state FROM pg_stat_activity WHERE xact_start IS NOT NULL ORDER BY age DESC;\nSELECT slot_name, active FROM pg_replication_slots WHERE NOT active;\nSELECT * FROM pg_prepared_xacts;"}},{"title":"積極的な FREEZE を実行する","detail":"ブロッカーがなくなったら、最も古いテーブルから凍結を強制する。サーバーが新しいトランザクション ID の割り当てを停止していても、シングルユーザーモード (postgres --single) には切り替えないこと: 現在の PostgreSQL ドキュメントでは、もはや不要であり避けるべきとされている。通常モードでスーパーユーザーとして接続し VACUUM を実行すれば十分である。PG14+ では周回が近づくと VACUUM の failsafe 機構が作動する。","engines":{"postgres":"VACUUM (FREEZE, VERBOSE) oldest_table;\n-- Entire database: vacuumdb --all --freeze --jobs=4"}},{"title":"恒久対策: autovacuum を強化して監視する","detail":"autovacuum_vacuum_cost_limit を上げ、autovacuum_naptime を下げ、書き込みの多いテーブルにはテーブル固有のストレージパラメータを設定する。age(datfrozenxid) にアラートを設定し、この危機を二度と経験しないようにする。"}],"related":["open-transactions","reclaim-space"]},{"id":"tempdb-contention","title":"tempdb の競合 (SQL Server)","icon":"🌀","symptom":"PAGELATCH_UP/EX 待機、tempdb の割り当てページ (PFS/GAM/SGAM) の競合、全般的な遅延。","steps":[{"title":"競合を確認する","detail":"tempdb のシステムページ (2:1:1 など) での PAGELATCH 待機は、割り当ての競合を示す。","engines":{"mssql":"SELECT session_id, wait_type, wait_duration_ms, resource_description\nFROM sys.dm_os_waiting_tasks\nWHERE wait_type LIKE 'PAGELATCH%' AND resource_description LIKE '2:%'\nORDER BY wait_duration_ms DESC;"}},{"title":"tempdb の使用状況を内訳する","detail":"誰が tempdb をどれだけ使っているか。内部オブジェクト (ソート/ハッシュのスピル)、バージョンストア、ユーザーオブジェクトのどれか。","engines":{"mssql":"SELECT * FROM sys.dm_db_file_space_usage;\nSELECT TOP 10 session_id, user_objects_alloc_page_count, internal_objects_alloc_page_count\nFROM sys.dm_db_task_space_usage ORDER BY internal_objects_alloc_page_count DESC;"}},{"title":"ファイル構成を修正する","detail":"tempdb には同じサイズの複数のデータファイルを、CPU コア数と同数 (最大 8) 使う。SQL 2016+ ではセットアップ時にこれが推奨され、旧バージョンではトレースフラグ 1117/1118 を使う。ファイルは高速ディスク (ローカル NVMe) に置く。"},{"title":"暴走クエリを見つける","detail":"大きなソート/ハッシュのスピルを伴うクエリが tempdb を膨張させる。メモリ許可が不十分なクエリや悪い計画のクエリを対象とし、インデックス/計画でスピルを減らす。","engines":{"mssql":"SELECT TOP 10 t.text, mg.requested_memory_kb, mg.granted_memory_kb\nFROM sys.dm_exec_query_memory_grants mg CROSS APPLY sys.dm_exec_sql_text(mg.sql_handle) t\nORDER BY mg.requested_memory_kb DESC;"}},{"title":"他のデータベースでの類似事象","detail":"同じ「一時領域の競合」は、Oracle では TEMP 表領域 (v$tempseg_usage / v$sort_usage)、PostgreSQL では temp_files と work_mem の超過である。根本的な対処は常に同じ: スピルするクエリを修正し、一時領域を高速化する。"}],"related":["free-space","top-slow-queries","reclaim-space"]},{"id":"cert-expiry","title":"TLS / 証明書の期限切れ","icon":"🔐","symptom":"'certificate has expired'、'SSL handshake failed'、クライアントが突然接続できなくなる (コード変更なし)。","steps":[{"title":"どこで壊れているか: サーバー、クライアント、CA のどれか","detail":"期限切れになったのはサーバー証明書か、クライアント証明書か、チェーン内の CA か。症状は通常「昨日は動いていたが今日は動かない、コードは変更していない」である。"},{"title":"有効期限を確認する","detail":"証明書の有効期限をサーバーから直接読み取る (データベースに依存しない迅速な方法)。","engines":{"postgres":"openssl s_client -connect host:5432 -starttls postgres </dev/null 2>/dev/null | openssl x509 -noout -dates","mongodb":"openssl s_client -connect host:27017 </dev/null 2>/dev/null | openssl x509 -noout -enddate","redis":"openssl s_client -connect host:6379 </dev/null 2>/dev/null | openssl x509 -noout -enddate"}},{"title":"新しい証明書をインストールしてロードする","detail":"証明書を置き換え、ほとんどの場合は再起動せずにサービスをリロードする。","engines":{"postgres":"-- Renew ssl_cert_file/ssl_key_file, then:\nSELECT pg_reload_conf();","mysql":"ALTER INSTANCE RELOAD TLS;","mssql":"-- SQL Server Configuration Manager > Certificate; a service restart is required","mongodb":"// Renew the net.tls.certificateKeyFile file (at the same path), then load it without a restart (5.0+):\ndb.adminCommand({rotateCertificates: 1})","redis":"CONFIG SET tls-cert-file /path/new.crt\nCONFIG SET tls-key-file /path/new.key","elasticsearch":"# ES watches the certificate/key files (PEM, PKCS#12) defined under xpack.security.*.ssl and\n# reloads them automatically when the file at the SAME path changes (no restart needed).\n# If the path, file name or keystore password changes, a rolling restart is required.\n# Note: POST _nodes/reload_secure_settings is only for reloadable keystore settings, not for TLS certificates.\n# Verify: check the new expiry date with openssl s_client and look in the ES logs for\n# an entry showing the certificate was reloaded."}},{"title":"検証する","detail":"上記の openssl コマンドで、新しい証明書で TLS ハンドシェイクが成功し、有効期限が延長されたことを確認する。クライアントでエンドツーエンドに接続する。"},{"title":"恒久対策: 二度と起こさない","detail":"証明書の有効期限の 30 日前にアラートを設定する。自動更新 (ACME/Let's Encrypt、HashiCorp Vault、cert-manager) を使う。更新後のリロードを自動化する。"}],"related":["connect-cli"]},{"id":"upgrade-rollback","title":"バージョンアップグレード / パッチのロールバック","icon":"⏪","symptom":"アップグレード/パッチ後の問題: 性能のリグレッション、アプリケーションの非互換、データベースがオープンしない。","steps":[{"title":"まず立ち止まる: フォールバック計画はあるか","detail":"本番のアップグレード前にフルバックアップと (可能なら) ストレージスナップショットを取っていない場合、最も安全な道は前進して修正すること (fix forward) である。ほとんどのデータベースでは、ロールバックはバックアップからのリストアを意味する。このステップは本来アップグレード前に計画しておくべきものである。"},{"title":"問題を分類する","detail":"オプティマイザの計画リグレッション (クエリが遅くなった) か、アプリケーション/ドライバーの非互換か、オープン不能/破損か。それにより解決の道筋は大きく異なる。"},{"title":"データベース別のロールバック方法","detail":"Oracle: datapatch によるパッチのロールバック、または Flashback Database (保証付きリストアポイントを作成していた場合)。PostgreSQL: pg_upgrade 後のロールバック = 旧バイナリ + 旧データディレクトリのバックアップ。MySQL: インプレースのダウングレードは一般にサポートされない — バックアップからリストアする。SQL Server: ダウングレードはない — アップグレード前のバックアップからリストアする。いずれの場合も、スナップショット/バックアップが保険である。"},{"title":"計画のリグレッションの場合: ロールバックせずに修正する","detail":"通常、バージョン全体をロールバックする必要はなく、変わったのは計画だけである。","engines":{"oracle":"ALTER SYSTEM SET optimizer_features_enable='19.1.0';  -- pin to the old behavior\n-- or lock in the good plan with a SQL Plan Baseline","postgres":"ANALYZE;  -- fresh statistics first\n-- if needed, temporarily: steer the plan with settings such as SET enable_nestloop=off;"}},{"title":"恒久対策: 次回に向けて","detail":"まずステージングで実際のワークロードを使ってアップグレードをテストし、カナリア/ローリングアップグレードを適用し、保証付きリストアポイント / スナップショットを取り、フォールバック手順を文書化する。"}],"related":["last-backup-status","restore-dump","version-uptime"]},{"id":"es-red-cluster","title":"Elasticsearch の red/yellow クラスタと未割り当てシャード","icon":"🟥","symptom":"_cluster/health が 'red' または 'yellow'。未割り当てシャード。読み取り/書き込みが制限されているか、データにアクセスできない。","steps":[{"title":"色と原因","detail":"yellow = レプリカシャードが未割り当て (データは存在するが、冗長性が低下している)。red = 少なくとも 1 つのプライマリシャードが欠落している (そのデータにはアクセスできない)。まずどちらか、そしてその理由を特定する。","engines":{"elasticsearch":"GET _cluster/health?level=indices\nGET _cluster/allocation/explain"}},{"title":"未割り当てシャードとその理由を一覧表示する","detail":"unassigned.reason 列が根本原因を示す (NODE_LEFT、ALLOCATION_FAILED、DISK など)。","engines":{"elasticsearch":"GET _cat/shards?v&h=index,shard,prirep,state,unassigned.reason&s=state"}},{"title":"一般的な原因に対処する","detail":"1) ディスクウォーターマーク → low を超えるとノードは新しいシャードを受け取らず、flood_stage ではインデックスが読み取り専用になる。2) ノードがダウンした / 離脱した。3) 割り当てが無効のまま放置された。4) レプリカ数 > 割り当て可能なノード数。"},{"title":"修正する","detail":"該当する原因に応じてブロックを解除する。","engines":{"elasticsearch":"# If disk space was freed, remove the read-only block (7.4+ also lifts it automatically once below the high watermark):\nPUT _all/_settings {\"index.blocks.read_only_allow_delete\": null}\n# If allocation was left restricted, return it to the default (all):\nPUT _cluster/settings {\"persistent\":{\"cluster.routing.allocation.enable\":null}}\n# Retry failed allocations:\nPOST _cluster/reroute?retry_failed=true"}},{"title":"それでも red で、プライマリが本当に失われた場合","detail":"影響を受けたインデックスをスナップショットからリストアするか、ソースデータから再インデックスする (_reindex)。恒久対策: ディスクウォーターマークのアラート、適切なレプリカ数 (≥1)、ノードのヘルス監視。"}],"related":["replication-status","list-replicas","free-space"]},{"id":"time-skew","title":"クロックスキュー / NTP の問題","icon":"⏱️","symptom":"クラスタノード間の時刻のずれ。レプリケーション/選出の不整合、'certificate not yet valid'、ログ内の時刻の飛び。","steps":[{"title":"症状を見分ける","detail":"クロックスキューは気づきにくい: Mongo/Redis Sentinel の選出のフラッピング、TLS の 'not yet valid/expired' エラー、Kerberos エラー、ログ内でタイムスタンプが逆行する。分散システムでは「説明のつかない」異常の多くの根源である。"},{"title":"差を測定する","detail":"各ノードで時刻ソースとオフセットを比較する: `timedatectl`、`chronyc tracking` (または `ntpq -p`)、ノード間での `date -u`。何 ms/s ずれているか。"},{"title":"NTP/chrony を修正する","detail":"chronyd/ntpd は動作しているか、時刻ソースに到達できるか、同期しているか。サービスを起動してソースを修正する。オフセットが大きい場合は慎重にステップ調整する (急激な時刻の飛びが一部の DB に影響することがある)。"},{"title":"影響を受けたコンポーネントを検証する","detail":"時刻を修正した後に確認する: MongoDB レプリカセットの選出は安定しているか、Redis Sentinel/Cluster は正常か、TLS ハンドシェイクは成功するか、レプリケーションラグのメトリクスは回復したか。"},{"title":"恒久対策","detail":"すべてのノードで NTP を必須とし、オフセットを監視する (アラート: >100ms)。仮想マシンではホストとゲストの時刻同期設定を明確にし、できれば単一の信頼できる時刻ソース階層を使う。"}],"related":["replication-status"]}]},"playbooks/hadr.json":{"schemaVersion":1,"playbooks":[{"id":"hadr-oracle-dataguard","title":"Oracle Data Guard (フィジカルスタンバイ) の構築","icon":"🛡️","symptom":"目標: フィジカルスタンバイ (Data Guard) で Oracle の災害復旧と高可用性を構築し、プライマリ障害時にスタンバイへ切り替えられるようにする。","steps":[{"title":"プライマリを FORCE LOGGING と ARCHIVELOG モードにする","detail":"スタンバイがプライマリと一貫性を保つには、すべての変更が redo に書き込まれる必要がある。FORCE LOGGING は NOLOGGING 操作もログに記録する。ARCHIVELOG モードにするにはデータベースを MOUNT 状態で起動する。","engines":{"oracle":"ALTER DATABASE FORCE LOGGING;\n-- For ARCHIVELOG:\nSHUTDOWN IMMEDIATE;\nSTARTUP MOUNT;\nALTER DATABASE ARCHIVELOG;\nALTER DATABASE OPEN;"}},{"title":"スタンバイ REDO ログファイルを追加する","detail":"スタンバイ REDO ログ (SRL) はオンライン REDO ログより 1 グループ多く、同じサイズにする。プライマリとスタンバイの両方に作成し、リアルタイム適用に必要である。例では、オンライン REDO が 200M なら SRL も 200M とする。","engines":{"oracle":"ALTER DATABASE ADD STANDBY LOGFILE ('/u01/oradata/srl01.log') SIZE 200M;\nALTER DATABASE ADD STANDBY LOGFILE ('/u01/oradata/srl02.log') SIZE 200M;\nALTER DATABASE ADD STANDBY LOGFILE ('/u01/oradata/srl03.log') SIZE 200M;\nALTER DATABASE ADD STANDBY LOGFILE ('/u01/oradata/srl04.log') SIZE 200M;"}},{"title":"log_archive_dest と関連パラメータを設定する","detail":"プライマリで、redo をスタンバイに転送する dest_2 を定義する。DB_UNIQUE_NAME、LOG_ARCHIVE_CONFIG (両側の db_unique_name)、FAL_SERVER、STANDBY_FILE_MANAGEMENT=AUTO を設定する。これによりスタンバイ上でファイルが自動的に作成される。","engines":{"oracle":"ALTER SYSTEM SET LOG_ARCHIVE_CONFIG='DG_CONFIG=(orcl_prim,orcl_stby)';\nALTER SYSTEM SET LOG_ARCHIVE_DEST_2='SERVICE=orcl_stby ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=orcl_stby';\nALTER SYSTEM SET FAL_SERVER='orcl_stby';  -- for role changes; on the standby FAL_SERVER='orcl_prim'\nALTER SYSTEM SET STANDBY_FILE_MANAGEMENT=AUTO;"}},{"title":"RMAN DUPLICATE FOR STANDBY でスタンバイを作成する","detail":"スタンバイサーバーでパスワードファイルと静的リスナー/tnsnames を設定した後、RMAN でプライマリとスタンバイ (AUXILIARY) に接続する。FROM ACTIVE DATABASE はバックアップなしでネットワーク経由でコピーし、DORECOVER は redo を適用する。","engines":{"oracle":"rman TARGET sys/password@orcl_prim AUXILIARY sys/password@orcl_stby\nRUN {\n  DUPLICATE TARGET DATABASE FOR STANDBY FROM ACTIVE DATABASE\n  DORECOVER\n  NOFILENAMECHECK;\n}"}},{"title":"REDO 適用 (MRP) を開始して検証する","detail":"スタンバイが MOUNT 状態のときに管理リカバリを開始する。リアルタイム適用には USING CURRENT LOGFILE を使う。v$managed_standby で適用プロセス (MRP0) が実行中であることを確認する。","engines":{"oracle":"ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT FROM SESSION;\nSELECT process, status, sequence# FROM v$managed_standby WHERE process LIKE 'MRP%';"}},{"title":"Data Guard Broker を有効にする","detail":"ブローカーは構成を一元化し、フェイルオーバー/スイッチオーバーを単一のコマンドにする。両方のインスタンスで DG_BROKER_START=TRUE を設定し、dgmgrl で構成を作成して有効にする。12c+ ではブローカーが redo 転送を管理する: LOG_ARCHIVE_DEST_2 を手動で設定していると ADD DATABASE は ORA-16698 で失敗するため、先に ALTER SYSTEM SET LOG_ARCHIVE_DEST_2='' でクリアする。","engines":{"oracle":"ALTER SYSTEM SET DG_BROKER_START=TRUE;\n-- In dgmgrl:\nCREATE CONFIGURATION dgconf AS PRIMARY DATABASE IS orcl_prim CONNECT IDENTIFIER IS orcl_prim;\nADD DATABASE orcl_stby AS CONNECT IDENTIFIER IS orcl_stby;\nENABLE CONFIGURATION;"}},{"title":"同期の差を監視し、テストを完了する","detail":"プライマリとスタンバイ間のシーケンスの差は継続的に監視する必要がある。差の拡大はネットワーク/適用のボトルネックを示す。dgmgrl の SHOW CONFIGURATION は 'SUCCESS' を示すべきである。必要に応じてスイッチオーバーでロール変更をテストする。","engines":{"oracle":"-- dgmgrl (SHOW DATABASE shows the Transport Lag / Apply Lag values):\nSHOW CONFIGURATION;\nSHOW DATABASE orcl_stby;\n-- SQL (standby): SELECT name, value FROM v$dataguard_stats WHERE name LIKE '%lag';"}}],"related":["replication-status","promote-failover","last-backup-status"]},{"id":"hadr-mssql-alwayson","title":"SQL Server Always On 可用性グループの構築","icon":"🔁","symptom":"目標: Always On 可用性グループ (AG) で、SQL Server の自動フェイルオーバーと読み取り可能セカンダリレプリカを構築する。","steps":[{"title":"Windows Server フェールオーバー クラスター (WSFC) を構築する","detail":"Always On は基盤となる WSFC に依存する。すべてのノードにフェールオーバー クラスタリング機能をインストールし、ネットワークと監視 (witness) を構成する。PowerShell でクラスタを作成する。","engines":{"mssql":"-- PowerShell (the Failover-Clustering feature must be installed on every node):\nNew-Cluster -Name sqlclu -Node node1,node2 -StaticAddress 10.0.0.50\n-- Witness:\nSet-ClusterQuorum -NodeAndFileShareMajority \\\\fs01\\quorum"}},{"title":"各インスタンスで Always On を有効にする","detail":"SQL Server 構成マネージャーまたは PowerShell で Always On 可用性グループ機能を有効にする。その後 SQL Server サービスを再起動する。これによりクラスタのメンバーシップがインスタンスに結び付けられる。","engines":{"mssql":"-- PowerShell:\nEnable-SqlAlwaysOn -ServerInstance node1\\SQL01 -Force\nEnable-SqlAlwaysOn -ServerInstance node2\\SQL01 -Force"}},{"title":"データベースをバックアップし、セカンダリで WITH NORECOVERY でリストアする","detail":"AG に追加するデータベースは FULL 復旧モデルである必要がある。プライマリでフルバックアップとログバックアップを取り、セカンダリで WITH NORECOVERY でリストアする (redo を受け取り続けられるように)。これは手動シーディングであり、代替は自動シーディングである。","engines":{"mssql":"-- On the primary:\nBACKUP DATABASE app TO DISK='\\\\fs01\\bak\\app.bak';\nBACKUP LOG app TO DISK='\\\\fs01\\bak\\app.trn';\n-- On the secondary:\nRESTORE DATABASE app FROM DISK='\\\\fs01\\bak\\app.bak' WITH NORECOVERY;\nRESTORE LOG app FROM DISK='\\\\fs01\\bak\\app.trn' WITH NORECOVERY;"}},{"title":"エンドポイントを作成し、可用性グループを定義する","detail":"ノード間の redo トラフィック用に、ポート 5022 で HADR エンドポイントを作成する。同期モード (SYNCHRONOUS_COMMIT) はデータ損失ゼロの自動フェイルオーバーを提供し、非同期 (ASYNCHRONOUS_COMMIT) は遅延があるが遠隔 DR 向けに高性能である。","engines":{"mssql":"CREATE ENDPOINT hadr_endpoint STATE=STARTED\n  AS TCP (LISTENER_PORT=5022)\n  FOR DATA_MIRRORING (ROLE=ALL, ENCRYPTION=REQUIRED ALGORITHM AES);\n\nCREATE AVAILABILITY GROUP appag\n  FOR DATABASE app\n  REPLICA ON\n    'NODE1\\SQL01' WITH (ENDPOINT_URL='TCP://node1:5022', AVAILABILITY_MODE=SYNCHRONOUS_COMMIT, FAILOVER_MODE=AUTOMATIC, SECONDARY_ROLE(ALLOW_CONNECTIONS=ALL)),\n    'NODE2\\SQL01' WITH (ENDPOINT_URL='TCP://node2:5022', AVAILABILITY_MODE=SYNCHRONOUS_COMMIT, FAILOVER_MODE=AUTOMATIC, SECONDARY_ROLE(ALLOW_CONNECTIONS=ALL));"}},{"title":"セカンダリを AG に参加させ、データベースを参加させる","detail":"セカンダリインスタンスで AG に JOIN し、リストアしたデータベースを AG に追加する。この手順は手動シーディングを使った場合に必要で、自動シーディングではプライマリ側で SET(SEEDING_MODE) により処理される。","engines":{"mssql":"-- On the secondary:\nALTER AVAILABILITY GROUP appag JOIN;\nALTER DATABASE app SET HADR AVAILABILITY GROUP = appag;"}},{"title":"可用性グループリスナーを作成する","detail":"リスナーはアプリケーションが接続する仮想名と IP である。フェイルオーバー後、接続は自動的に新プライマリにリダイレクトされる。アプリケーションの接続文字列でこの名前と MultiSubnetFailover=True を使う。","engines":{"mssql":"ALTER AVAILABILITY GROUP appag\n  ADD LISTENER 'appag-listener' (WITH IP ((N'10.0.0.60', N'255.255.255.0')), PORT=1433);"}},{"title":"フェイルオーバーをテストし、同期状態を検証する","detail":"同期が 'HEALTHY' になったら、計画的フェイルオーバーでロール変更をテストする。自動フェイルオーバーには、同期モードかつ FAILOVER_MODE=AUTOMATIC である必要がある。sys.dm_hadr_availability_replica_states で状態を監視する。","engines":{"mssql":"SELECT ag.name, ars.role_desc, ars.synchronization_health_desc\nFROM sys.dm_hadr_availability_replica_states ars\nJOIN sys.availability_groups ag ON ag.group_id=ars.group_id;\n-- Planned failover (on the node that will become the new primary):\nALTER AVAILABILITY GROUP appag FAILOVER;"}}],"related":["replication-status","promote-failover","list-replicas"]},{"id":"hadr-postgres-streaming","title":"PostgreSQL ストリーミングレプリケーション + 自動フェイルオーバー","icon":"🐘","symptom":"目標: ストリーミングレプリケーションで PostgreSQL のホットスタンバイを構築し、自動フェイルオーバーのために Patroni/repmgr を追加する。","steps":[{"title":"プライマリで WAL と接続のパラメータを設定する","detail":"ストリーミングレプリケーションには、wal_level が少なくとも 'replica' である必要がある。max_wal_senders はレプリカ数 + バックアップ接続数をカバーし、wal_keep_size またはレプリケーションスロットで WAL の早期削除を防ぐ必要がある。変更には再起動が必要。","engines":{"postgres":"ALTER SYSTEM SET wal_level = 'replica';\nALTER SYSTEM SET max_wal_senders = 10;\nALTER SYSTEM SET max_replication_slots = 10;\nALTER SYSTEM SET hot_standby = on;\n-- To apply the postgresql.conf change:\n-- systemctl restart postgresql"}},{"title":"レプリケーションロールと pg_hba のアクセスを定義する","detail":"スタンバイが接続に使う REPLICATION 属性付きのロールを作成する。スタンバイの IP から 'replication' データベースへのアクセスを許可する行を pg_hba.conf に追加し、pg_reload_conf() でリロードする。","engines":{"postgres":"CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'secret';\n-- Add to pg_hba.conf:\n-- host replication replicator 10.0.0.20/32 scram-sha-256\nSELECT pg_reload_conf();"}},{"title":"プライマリに永続的なレプリケーションスロットを作成する","detail":"物理レプリケーションスロットは、スタンバイが遅延しても、プライマリが必要な WAL を削除するのを防ぐ。スロット管理は wal_keep_size より安全である。スロット名はスタンバイの構成で使う。","engines":{"postgres":"SELECT pg_create_physical_replication_slot('standby1_slot');\nSELECT slot_name, active, restart_lsn FROM pg_replication_slots;"}},{"title":"スタンバイサーバーで pg_basebackup によりベースバックアップを取る","detail":"スタンバイのデータディレクトリを空にした状態で、プライマリからフルコピーを取る。-R フラグは standby.signal ファイルと primary_conninfo を自動的に書き込み、-C でスロットも作成できる。スロット名は -S で渡す。","engines":{"postgres":"pg_basebackup -h 10.0.0.10 -U replicator -D /var/lib/pgsql/data \\\n  -R -X stream -S standby1_slot -P -v"}},{"title":"primary_conninfo と hot_standby を確認し、スタンバイを起動する","detail":"-R により書き込まれた postgresql.auto.conf 内の primary_conninfo (host、user、slot) を確認する。standby.signal ファイルの有無がスタンバイモードを決める。hot_standby=on ならスタンバイは読み取り専用クエリを受け付ける。サービスを起動する。","engines":{"postgres":"-- Expected in postgresql.auto.conf:\n-- primary_conninfo = 'host=10.0.0.10 user=replicator password=secret'\n-- primary_slot_name = 'standby1_slot'\n-- systemctl start postgresql\nSELECT pg_is_in_recovery();  -- should return true on the standby"}},{"title":"プライマリからレプリケーションラグを監視する","detail":"プライマリでは、pg_stat_replication が各スタンバイの送信済み/再生済み LSN とラグを示す。write/flush/replay のラグは小さく保たれるべきである。同期レプリカを使う場合、sync_state は 'sync' となる。","engines":{"postgres":"SELECT client_addr, state, sync_state,\n       pg_wal_lsn_diff(sent_lsn, replay_lsn) AS replay_lag_bytes,\n       write_lag, flush_lag, replay_lag\nFROM pg_stat_replication;"}},{"title":"自動フェイルオーバーのために Patroni または repmgr を追加する","detail":"素のストリーミングレプリケーションでは手動の promote が必要。自動フェイルオーバーにはクラスタマネージャーが必要である: Patroni (etcd/Consul 上のリーダー選出 + 自動 promote) または repmgr (repmgrd による監視/フェイルオーバー)。アプリケーション側には HAProxy/pgBouncer で単一のエンドポイントを提供する。手動 promote が必要な場合: pg_ctl promote。promote の前に、旧プライマリが確実に停止しており、アプリケーションが書き込めないことを確認する (スプリットブレインのリスク)。旧プライマリを新プライマリのスタンバイとして再参加させるには pg_rewind が必要で、そのためには wal_log_hints = on またはデータチェックサムが有効である必要がある。","engines":{"postgres":"-- Manual promote (if there is no cluster manager):\npg_ctl promote -D /var/lib/pgsql/data\n-- or via SQL:\nSELECT pg_promote();\n-- With Patroni: patronictl -c /etc/patroni.yml switchover mycluster"}}],"related":["replication-status","list-replicas","promote-failover"]},{"id":"hadr-mysql-innodb-cluster","title":"MySQL InnoDB Cluster (Group Replication) の構築","icon":"🐬","symptom":"目標: InnoDB Cluster (Group Replication + MySQL Shell + MySQL Router) を使い、MySQL の自動フェイルオーバー付き高可用性を構築する。","steps":[{"title":"前提条件を満たす","detail":"InnoDB Cluster には、すべてのノードで MySQL 8.0+、一意の server_id、GTID モード、InnoDB ストレージエンジンが必要。すべてのインスタンスがネットワーク上で相互に到達可能で、テーブルに主キーがある必要がある。管理用に clusterAdmin ユーザーを用意する。","engines":{"mysql":"-- my.cnf on each instance:\n-- server_id unique, gtid_mode=ON, enforce_gtid_consistency=ON\nCREATE USER 'icadmin'@'%' IDENTIFIED BY 'secret';\nGRANT ALL PRIVILEGES ON *.* TO 'icadmin'@'%' WITH GRANT OPTION;"}},{"title":"MySQL Shell で各インスタンスを構成する","detail":"mysqlsh で dba.configureInstance() を実行すると、各ノードが Group Replication に適した状態になる。不足しているパラメータを修正し、必要に応じて再起動を求める。すべてのノードで繰り返す。","engines":{"mysql":"-- mysqlsh:\ndba.configureInstance('icadmin@node1:3306')\ndba.configureInstance('icadmin@node2:3306')\ndba.configureInstance('icadmin@node3:3306')"}},{"title":"クラスタを作成する (シードノード)","detail":"1 つのノードに接続し、dba.createCluster() でクラスタを開始する。このノードが最初のプライマリになる。クラスタオブジェクトが返され、以降の追加に使われる。","engines":{"mysql":"-- mysqlsh, while connected to node1:\nvar cluster = dba.createCluster('appCluster')"}},{"title":"他のインスタンスをクラスタに追加する","detail":"cluster.addInstance() でセカンダリノードを追加する。recoveryMethod には clone (物理クローン、新規ノードに高速) または incremental (GTID 経由) を選ぶ。少なくとも 3 ノードで奇数の過半数と自動フェイルオーバーが得られる。","engines":{"mysql":"-- mysqlsh:\ncluster.addInstance('icadmin@node2:3306', {recoveryMethod: 'clone'})\ncluster.addInstance('icadmin@node3:3306', {recoveryMethod: 'clone'})"}},{"title":"MySQL Router をブートストラップする","detail":"MySQL Router はアプリケーションとクラスタの間でルーティングを行う。読み取り/書き込み (6446) と読み取り専用 (6447) のポートを公開し、プライマリが変わるとトラフィックを自動的にリダイレクトする。ブートストラップはクラスタのメタデータから構成を生成する。","engines":{"mysql":"mysqlrouter --bootstrap icadmin@node1:3306 --user=mysqlrouter --directory /etc/mysqlrouter\n# Then: mysqlrouter -c /etc/mysqlrouter/mysqlrouter.conf &"}},{"title":"クラスタの状態を確認し、フェイルオーバーを検証する","detail":"cluster.status() は各ノードのロール (R/W プライマリ、R/O セカンダリ) と状態 (ONLINE) を示す。clusterName とトポロジーが正常であるべきである。プライマリを停止し、新プライマリが自動的に選出されることを観察してフェイルオーバーをテストする。","engines":{"mysql":"-- mysqlsh:\nvar cluster = dba.getCluster('appCluster')\ncluster.status()\n-- Members via SQL:\nSELECT member_host, member_role, member_state FROM performance_schema.replication_group_members;"}}],"related":["replication-status","list-replicas","promote-failover"]},{"id":"hadr-mongodb-replicaset","title":"MongoDB レプリカセット + シャーディングの構築","icon":"🍃","symptom":"目標: MongoDB の自動フェイルオーバー付きレプリカセットを構築し、水平スケーリングのためにシャードクラスタに拡張する。","steps":[{"title":"同じ replSet 名で mongod プロセスを起動する","detail":"各レプリカセットメンバーを同じ --replSet 名と到達可能な --bind_ip で起動する。本番では keyFile または TLS による内部認証が推奨される。明確な過半数のため、投票メンバーは奇数にする。","engines":{"mongodb":"mongod --replSet rs0 --port 27017 --dbpath /data/n1 --bind_ip localhost,10.0.0.11\nmongod --replSet rs0 --port 27017 --dbpath /data/n2 --bind_ip localhost,10.0.0.12\nmongod --replSet rs0 --port 27017 --dbpath /data/n3 --bind_ip localhost,10.0.0.13"}},{"title":"レプリカセットを初期化する","detail":"mongosh で 1 つのメンバーに接続し、rs.initiate() を呼び出してすべてのメンバーを定義する。これにより最初の選出が起動され、プライマリが選ばれる。rs.status() で PRIMARY/SECONDARY のロールを確認する。","engines":{"mongodb":"rs.initiate({\n  _id: 'rs0',\n  members: [\n    { _id: 0, host: '10.0.0.11:27017' },\n    { _id: 1, host: '10.0.0.12:27017' },\n    { _id: 2, host: '10.0.0.13:27017' }\n  ]\n})\nrs.status()"}},{"title":"メンバーを追加し、優先度と必要なら arbiter を設定する","detail":"後からメンバーを rs.add() で追加する。priority はどのメンバーがプライマリになりやすいかを決める (0 = プライマリにならない)。arbiter は投票のみを行いデータを持たない。データノードが偶数の場合のタイブレーカーとして使われるが、データの安全性のためには実メンバーが好ましい。arbiter ベースのトポロジー (特に PSA) では、データノードがダウンすると majority の write concern を満たせず書き込みが待機する。5.0+ では arbiter を追加する前に、setDefaultRWConcern でクラスタ全体のデフォルト write concern を明示的に設定する必要がある場合がある。","engines":{"mongodb":"rs.add({ host: '10.0.0.14:27017', priority: 0.5 })\n// Arbiter only if really needed (a data-bearing member is preferred):\nrs.addArb('10.0.0.15:27017')\n// change priority:\ncfg = rs.conf(); cfg.members[0].priority = 2; rs.reconfig(cfg)"}},{"title":"シャーディング用に config サーバーのレプリカセットを構築する","detail":"シャードクラスタのメタデータは config サーバーのレプリカセット (--configsvr) に保持される。それ自体もレプリカセットとして初期化され、高可用性のため 3 メンバーが推奨される。","engines":{"mongodb":"mongod --configsvr --replSet cfgrs --port 27019 --dbpath /data/cfg1 --bind_ip localhost,10.0.0.21\n-- mongosh (on the config server):\nrs.initiate({ _id: 'cfgrs', configsvr: true, members: [\n  { _id: 0, host: '10.0.0.21:27019' },\n  { _id: 1, host: '10.0.0.22:27019' },\n  { _id: 2, host: '10.0.0.23:27019' } ] })"}},{"title":"シャードのレプリカセットと mongos ルーターを起動する","detail":"各シャードは --shardsvr で起動された独立したレプリカセットである (データの永続性はシャード内のレプリケーションによる)。mongos ルーターは config サーバーを指定して起動し、アプリケーションは mongos に接続する。","engines":{"mongodb":"mongod --shardsvr --replSet shard1rs --port 27018 --dbpath /data/s1 --bind_ip localhost,10.0.0.31\n# initiate shard1rs with rs.initiate, then mongos:\nmongos --configdb cfgrs/10.0.0.21:27019,10.0.0.22:27019,10.0.0.23:27019 --port 27017 --bind_ip localhost,10.0.0.40"}},{"title":"シャードを追加し、コレクションをシャーディングする","detail":"mongos に接続し、sh.addShard() で各シャードのレプリカセットを追加する。データベースでシャーディングを有効にし、sh.shardCollection() でシャードキーによりコレクションを分散する。キーの選択は重要である: 高いカーディナリティと均等な分布を持つべきである。sh.status() でチャンクの分布を監視する。","engines":{"mongodb":"sh.addShard('shard1rs/10.0.0.31:27018')\nsh.addShard('shard2rs/10.0.0.32:27018')\nsh.enableSharding('appdb')\nsh.shardCollection('appdb.events', { customer_id: 'hashed' })\nsh.status()"}}],"related":["replication-status","list-replicas","promote-failover"]},{"id":"hadr-redis-sentinel","title":"Redis Sentinel + Cluster による高可用性","icon":"⚡","symptom":"目標: Sentinel を使い Redis の自動フェイルオーバー付きマスター-レプリカ構成を構築する。水平スケーリングが必要なら Redis Cluster モードに切り替える。","steps":[{"title":"マスターとレプリカを構成する","detail":"1 つのマスターと少なくとも 2 つのレプリカを実行する。レプリカは REPLICAOF でマスターに追従する (redis.conf に 'replicaof <host> <port>' と書くこともできる)。永続化のため AOF または RDB を有効にし、requirepass/masterauth による認証を推奨する。","engines":{"redis":"# at runtime on the replica nodes:\nREPLICAOF 10.0.0.10 6379\n# to make it persistent, redis.conf:\n# replicaof 10.0.0.10 6379\n# masterauth secret\nINFO replication"}},{"title":"Sentinel を monitor とクォーラムで構成する","detail":"各 Sentinel ノードの sentinel.conf で、監視するマスターとクォーラムを定義する。quorum は、マスターを「ダウン」とみなすのに必要な Sentinel の最小数である。本番では 3 台の別々のサーバーに 3 つの Sentinel を置くことが推奨される (スプリットブレイン対策)。","engines":{"redis":"# sentinel.conf:\nsentinel monitor mymaster 10.0.0.10 6379 2\nsentinel down-after-milliseconds mymaster 5000\nsentinel failover-timeout mymaster 60000\nsentinel parallel-syncs mymaster 1"}},{"title":"Sentinel プロセスを起動する","detail":"各ノードで Sentinel を起動する。Sentinel は互いとレプリカを自動的に検出し、実行時に構成をファイルへ書き込む。そのため sentinel.conf は書き込み可能である必要がある。","engines":{"redis":"redis-sentinel /etc/redis/sentinel.conf\n# or:\nredis-server /etc/redis/sentinel.conf --sentinel"}},{"title":"Sentinel 経由で状態を照会し、フェイルオーバーをテストする","detail":"SENTINEL コマンドで現在のマスターとレプリカを照会する。アプリケーションは Sentinel に 'get-master-addr-by-name' を照会して現在のマスターを知るべきである。計画的フェイルオーバーで自動切り替えを検証する。","engines":{"redis":"SENTINEL master mymaster\nSENTINEL get-master-addr-by-name mymaster\nSENTINEL replicas mymaster\n# planned switchover:\nSENTINEL failover mymaster"}},{"title":"代替: Redis Cluster でデータを分割する","detail":"単一マスターのメモリ/スループットで足りない場合は Redis Cluster を使う: データは 16384 個のハッシュスロットに分割されて複数のマスターに分散され、各マスターが独自のレプリカを持つ。アプリケーションはクラスタ対応クライアントを使う必要がある。redis-cli --cluster create で構築する。","engines":{"redis":"redis-cli --cluster create \\\n  10.0.0.11:6379 10.0.0.12:6379 10.0.0.13:6379 \\\n  10.0.0.21:6379 10.0.0.22:6379 10.0.0.23:6379 \\\n  --cluster-replicas 1"}},{"title":"クラスタの状態を検証する","detail":"クラスタ作成後、すべてのスロットが割り当てられ、ノードが接続されていることを確認する。cluster_state は 'ok' で、16384 個すべてのスロットが割り当て済みと表示されるべきである。CLUSTER コマンドでノードとスロットの分布を監視する。","engines":{"redis":"redis-cli --cluster check 10.0.0.11:6379\nredis-cli -c -h 10.0.0.11 CLUSTER INFO\nredis-cli -c -h 10.0.0.11 CLUSTER NODES"}}],"related":["replication-status","list-replicas","promote-failover"]},{"id":"hadr-elasticsearch-ha","title":"Elasticsearch の耐障害性: レプリカ + スナップショット + CCR","icon":"🔎","symptom":"目標: レプリカシャード、専用 master/data ノード、スナップショットバックアップ (SLM)、クラスタ間レプリケーション (CCR) により、Elasticsearch の耐障害性を構築する。","steps":[{"title":"ロールを分離する: 専用 master ノードと data ノード","detail":"クラスタの安定性のため、投票権を持つ master 適格ノード (できれば 3 つ、奇数の過半数) をデータワークロードから分離する。elasticsearch.yml の node.roles でロールを割り当て、ディスカバリ用に seed hosts を定義する。3 つの master がスプリットブレインを防ぐ。","engines":{"elasticsearch":"# elasticsearch.yml on master nodes:\n# node.roles: [ master ]\n# on data nodes:\n# node.roles: [ data, ingest ]\n# discovery.seed_hosts: [ m1, m2, m3 ]\n# cluster.initial_master_nodes: [ m1, m2, m3 ]"}},{"title":"インデックスのレプリカ数を設定する","detail":"number_of_replicas は各プライマリシャードについて保持されるコピー数である。data ノードを 1 つ失ってもデータが利用可能であるよう、少なくとも 1 にする。稼働中のインデックスで動的に変更でき、レプリカ数は data ノード数より少なくなければならない。","engines":{"elasticsearch":"PUT /orders/_settings\n{\n  \"index\": { \"number_of_replicas\": 1 }\n}\n# default via template (composable template; the old _template API is legacy):\n# PUT _index_template/order-tpl { \"index_patterns\": [\"order*\"], \"template\": { \"settings\": { \"number_of_replicas\": 1 } } }"}},{"title":"スナップショットリポジトリを定義する","detail":"バックアップはリポジトリに取得される: 共有ファイルシステム (fs) または S3/GCS/Azure プラグイン。クラスタが削除されてもデータを復旧できるよう、リポジトリはクラスタ外の永続的なストレージに置く必要がある。","engines":{"elasticsearch":"PUT /_snapshot/backup_repo\n{\n  \"type\": \"fs\",\n  \"settings\": { \"location\": \"/mnt/es_backups\", \"compress\": true }\n}"}},{"title":"SLM で自動スナップショットをスケジュールする","detail":"Snapshot Lifecycle Management (SLM) は定期的にスナップショットを取得し、保持ポリシーを適用する。cron 式で頻度、対象インデックス、保持するスナップショット数を定義する。","engines":{"elasticsearch":"PUT /_slm/policy/daily_backup\n{\n  \"schedule\": \"0 30 1 * * ?\",\n  \"name\": \"<daily-{now/d}>\",\n  \"repository\": \"backup_repo\",\n  \"config\": { \"indices\": [\"*\"] },\n  \"retention\": { \"expire_after\": \"30d\", \"min_count\": 5, \"max_count\": 50 }\n}"}},{"title":"スナップショットとリストアを検証する","detail":"SLM ポリシーを手動で実行して動作を確認する。スナップショットの状態は SUCCESS になるべきである。テストされていないバックアップはバックアップではないため、リストアテストを定期的に行う。","engines":{"elasticsearch":"POST /_slm/policy/daily_backup/_execute\nGET /_snapshot/backup_repo/_all\n# restore:\nPOST /_snapshot/backup_repo/<snapshot_name>/_restore"}},{"title":"Cross-Cluster Replication (CCR) で遠隔 DR を構築する","detail":"リージョン間の災害復旧では、2 つ目のクラスタ (follower) がリモートのプライマリクラスタ (leader) 内のインデックスに追従する。まずリモートクラスタを定義し、次に follower インデックスを leader に接続する。leader 上の変更は自動的に流れる。CCR は Platinum (商用) 機能である。","engines":{"elasticsearch":"# define the remote cluster on the follower cluster:\nPUT /_cluster/settings\n{ \"persistent\": { \"cluster\": { \"remote\": { \"primary\": { \"seeds\": [\"leader1:9300\"] } } } } }\n# create the follower index:\nPUT /orders-follower/_ccr/follow\n{ \"remote_cluster\": \"primary\", \"leader_index\": \"orders\" }"}}],"related":["replication-status","list-replicas","last-backup-status"]}]},"playbooks/security.json":{"schemaVersion":1,"playbooks":[{"id":"harden-sql","title":"セキュリティ強化: SQL データベース (Oracle、PostgreSQL、MySQL、SQL Server)","icon":"🔒","symptom":"目標: CIS 方式でリレーショナルデータベースを強化する — デフォルトアカウント、強力なパスワードポリシー、最小権限、ネットワーク制限、TLS、監査、暗号化 (TDE)。","steps":[{"title":"デフォルト/不要なアカウントを削除またはロックし、サンプルスキーマを削除する","detail":"インストールに付属するデフォルトアカウントとサンプルスキーマは、よく知られた攻撃対象領域である。使わないものはロックまたは削除し、最上位/サービスアカウントの名前を変更する。","engines":{"oracle":"-- Lock unused default accounts and expire their passwords:\nALTER USER SCOTT ACCOUNT LOCK PASSWORD EXPIRE;\nALTER USER HR ACCOUNT LOCK PASSWORD EXPIRE;\n-- Audit locked/open accounts:\nSELECT username, account_status FROM dba_users ORDER BY account_status;\n-- Remove sample schemas: $ORACLE_HOME/demo/schema/drop_sch.sql","postgres":"-- Keep the default superuser 'postgres' role; do NOT drop/rename it.\n-- Audit roles:\nSELECT rolname, rolsuper, rolcanlogin FROM pg_roles ORDER BY rolsuper DESC;\n-- Remove unneeded login roles:\nDROP ROLE IF EXISTS test_user;\n-- Drop sample/test databases: DROP DATABASE IF EXISTS test;","mysql":"# Interactive hardening wizard (removes anonymous users, the test DB, remote root):\nmysql_secure_installation\n-- Manual: remove anonymous and test accounts:\nDROP USER IF EXISTS ''@'localhost';\nDROP USER IF EXISTS ''@'%';\nDROP DATABASE IF EXISTS test;\nDELETE FROM mysql.db WHERE Db LIKE 'test%'; FLUSH PRIVILEGES;","mssql":"-- Disable and rename the 'sa' account:\nALTER LOGIN sa DISABLE;\nALTER LOGIN sa WITH NAME = [sa_disabled_acct];\n-- Restrict the guest user — only in USER databases\n-- (guest must stay enabled in master, tempdb and msdb; disabling it in tempdb/msdb causes problems):\nUSE appdb;\nREVOKE CONNECT FROM guest;\n-- Remove sample DBs: DROP DATABASE AdventureWorks;"}},{"title":"強力なパスワードポリシーと有効期限を適用する","detail":"弱いパスワードや変更されないパスワードは最も一般的な侵入口である。ログイン試行回数の制限、複雑さ、パスワードの有効期間を適用し、パスワードは強力なハッシュで保存する。","engines":{"oracle":"-- Attempt limit, lifetime and complexity via a profile:\nCREATE PROFILE app_profile LIMIT\n  FAILED_LOGIN_ATTEMPTS 5\n  PASSWORD_LIFE_TIME 90\n  PASSWORD_REUSE_MAX 10\n  PASSWORD_VERIFY_FUNCTION ora12c_verify_function;\nALTER USER app_user PROFILE app_profile;","postgres":"-- Strong hash algorithm (SCRAM):\nSHOW password_encryption;              -- should be 'scram-sha-256'\nALTER SYSTEM SET password_encryption = 'scram-sha-256';\n-- Load the passwordcheck extension for complexity:\n-- shared_preload_libraries = 'passwordcheck'\n-- Lifetime: ALTER ROLE app_user VALID UNTIL '2026-12-31';","mysql":"-- Install the validate_password component and set the policy:\nINSTALL COMPONENT 'file://component_validate_password';\nSET PERSIST validate_password.policy = 'STRONG';\nSET PERSIST validate_password.length = 14;\n-- Attempt limit and lifetime:\nALTER USER app_user PASSWORD EXPIRE INTERVAL 90 DAY\n  FAILED_LOGIN_ATTEMPTS 5 PASSWORD_LOCK_TIME 1;","mssql":"-- Enforce the Windows password policy and expiration on the login:\nALTER LOGIN app_user WITH CHECK_POLICY = ON, CHECK_EXPIRATION = ON;\n-- Audit policy/expiration status:\nSELECT name, is_policy_checked, is_expiration_checked\nFROM sys.sql_logins;"}},{"title":"最小権限: PUBLIC/広範な権限を取り消し、ロールベースで権限を付与する","detail":"全員 (PUBLIC) に付与された広範な権限は横展開を容易にする。それらを取り消し、ロールを作成して必要なものだけを付与する。","engines":{"oracle":"-- Revoke dangerous PUBLIC privileges:\nREVOKE EXECUTE ON UTL_HTTP FROM PUBLIC;\nREVOKE EXECUTE ON UTL_FILE FROM PUBLIC;\nREVOKE EXECUTE ON DBMS_SCHEDULER FROM PUBLIC;\n-- Role-based privileges:\nCREATE ROLE app_read;\nGRANT SELECT ON app.orders TO app_read;\nGRANT app_read TO app_user;","postgres":"-- Revoke the default PUBLIC privileges on the schema:\nREVOKE ALL ON DATABASE appdb FROM PUBLIC;\nREVOKE CREATE ON SCHEMA public FROM PUBLIC;\n-- Role-based, read-only access:\nCREATE ROLE app_read NOLOGIN;\nGRANT USAGE ON SCHEMA app TO app_read;\nGRANT SELECT ON ALL TABLES IN SCHEMA app TO app_read;\nGRANT app_read TO app_user;","mysql":"-- Audit and revoke broad global privileges:\nSHOW GRANTS FOR app_user;\nREVOKE ALL PRIVILEGES, GRANT OPTION FROM app_user;\n-- Role-based, object-level privileges (MySQL 8+):\nCREATE ROLE app_read;\nGRANT SELECT ON appdb.* TO app_read;\nGRANT app_read TO app_user;\nSET DEFAULT ROLE app_read TO app_user;","mssql":"-- Revoke excessive privileges granted to the public role:\nREVOKE SELECT ON SCHEMA::dbo FROM public;\n-- Role-based privileges:\nCREATE ROLE app_read;\nGRANT SELECT ON SCHEMA::app TO app_read;\nALTER ROLE app_read ADD MEMBER app_user;\n-- At server level: limit fixed server roles (sysadmin)."}},{"title":"ネットワーク/アクセスを制限する — 既知のクライアントのみ接続可能にする","detail":"データベースが全世界に対して公開でリッスンしないようにする。リッスンアドレスを制限し、ホスト/IP ベースのアクセスルールを適用し、ファイアウォールでポートを制限する。","engines":{"oracle":"# listener.ora / sqlnet.ora — valid node checking:\nTCP.VALIDNODE_CHECKING = YES\nTCP.INVITED_NODES = (10.0.0.5, 10.0.0.6)\nTCP.EXCLUDED_NODES = (0.0.0.0/0)\n# After the change: lsnrctl reload","postgres":"# postgresql.conf — listen only on specific interfaces:\nlisten_addresses = '10.0.0.10,localhost'\n# pg_hba.conf — host/IP + strong authentication:\nhostssl appdb app_user 10.0.0.0/24 scram-sha-256\nhost    all      all       0.0.0.0/0      reject\n# Reload: SELECT pg_reload_conf();","mysql":"# my.cnf — bind only to a specific interface:\n[mysqld]\nbind-address = 10.0.0.10\n-- Host-based user (only from the application server):\nCREATE USER 'app_user'@'10.0.0.5'\n  IDENTIFIED BY '****' REQUIRE SSL;\n-- Never give remote root the '%' host.","mssql":"# Limit the TCP port with the firewall (application subnet only):\nNew-NetFirewallRule -DisplayName 'SQL-1433' -Direction Inbound `\n  -Protocol TCP -LocalPort 1433 -RemoteAddress 10.0.0.0/24 -Action Allow\n-- Audit listening addresses:\nSELECT * FROM sys.dm_tcp_listener_states;\n-- Disable the SQL Browser service if not used."}},{"title":"TLS/暗号化接続を強制する","detail":"ネットワークトラフィックは受動的な盗聴にさらされている。サーバー証明書を構成し、クライアントに暗号化接続を必須とする。","engines":{"oracle":"# sqlnet.ora — TCPS/TLS (server certificate in the wallet):\nWALLET_LOCATION = (SOURCE=(METHOD=FILE)(METHOD_DATA=(DIRECTORY=/etc/oracle/wallet)))\nSSL_CLIENT_AUTHENTICATION = FALSE\nSSL_VERSION = 1.2\n# Listen only on TCPS (port 2484) in listener.ora. Note: SQLNET.ENCRYPTION_SERVER is Native Network Encryption, not TLS.","postgres":"# postgresql.conf:\nssl = on\nssl_cert_file = 'server.crt'\nssl_key_file  = 'server.key'\nssl_min_protocol_version = 'TLSv1.2'\n# Use 'hostssl' lines in pg_hba.conf; reject unencrypted connections over plain 'host'.","mysql":"# my.cnf:\n[mysqld]\nrequire_secure_transport = ON\nssl_cert = /etc/mysql/server-cert.pem\nssl_key  = /etc/mysql/server-key.pem\nssl_ca   = /etc/mysql/ca.pem\n-- At user level: ALTER USER app_user REQUIRE SSL;","mssql":"-- Force connection encryption (SQL Server Configuration Manager):\n-- Protocols for MSSQLSERVER > Properties > Force Encryption = Yes\n-- Assign a certificate; then restart the service.\n-- Check the status:\nSELECT session_id, encrypt_option FROM sys.dm_exec_connections;"}},{"title":"監査を有効にする — 誰が何をしたかを可視化する","detail":"監査証跡は特権アクセスと不審な活動の監視に不可欠である。ログイン、権限変更、機密オブジェクトへのアクセスを記録する。","engines":{"oracle":"-- Create and enable a policy with Unified Auditing:\nCREATE AUDIT POLICY sec_pol\n  ACTIONS LOGON, LOGOFF, ALTER USER, GRANT, CREATE USER, DROP USER;\nAUDIT POLICY sec_pol;\n-- View the records:\nSELECT * FROM unified_audit_trail ORDER BY event_timestamp DESC;","postgres":"# With the pgaudit extension:\n# postgresql.conf:\nshared_preload_libraries = 'pgaudit'\npgaudit.log = 'ddl, role, write'\n-- Create the extension:\nCREATE EXTENSION pgaudit;\n-- log_connections = on and log_disconnections = on should also be enabled.","mysql":"-- Load the Enterprise/Percona audit_log plugin:\nINSTALL PLUGIN audit_log SONAME 'audit_log.so';\nSET PERSIST audit_log_policy = 'ALL';\n-- MariaDB: server_audit plugin\n-- INSTALL SONAME 'server_audit'; SET GLOBAL server_audit_logging=ON;","mssql":"-- Create and start a Server Audit:\nCREATE SERVER AUDIT sec_audit\n  TO FILE (FILEPATH = 'C:\\SQLAudit\\');\nALTER SERVER AUDIT sec_audit WITH (STATE = ON);\nCREATE SERVER AUDIT SPECIFICATION sec_spec\n  FOR SERVER AUDIT sec_audit\n  ADD (FAILED_LOGIN_GROUP), ADD (DATABASE_ROLE_MEMBER_CHANGE_GROUP)\n  WITH (STATE = ON);"}},{"title":"データ暗号化を適用する (保存時 / TDE)","detail":"ディスク、バックアップ、ファイルが盗まれても、データは読めない状態でなければならない。列/表領域/データベースレベルで保存データの暗号化 (TDE) を有効にする。","engines":{"oracle":"-- Transparent Data Encryption (keystore + tablespace):\nADMINISTER KEY MANAGEMENT CREATE KEYSTORE '/etc/oracle/wallet'\n  IDENTIFIED BY \"WalletPwd1\";\nADMINISTER KEY MANAGEMENT SET KEY IDENTIFIED BY \"WalletPwd1\" WITH BACKUP;\nCREATE TABLESPACE sec_ts DATAFILE '/u01/sec01.dbf' SIZE 100M\n  ENCRYPTION USING 'AES256' DEFAULT STORAGE(ENCRYPT);","postgres":"-- There is no built-in block-level TDE; two common approaches:\n-- 1) Column-level pgcrypto:\nCREATE EXTENSION pgcrypto;\nINSERT INTO t(ssn) VALUES (pgp_sym_encrypt('123-45', 'my_key'));\nSELECT pgp_sym_decrypt(ssn, 'my_key') FROM t;\n-- 2) File system/block encryption (LUKS) or an EDB/Cybertec TDE build.","mysql":"# InnoDB tablespace encryption — keyring COMPONENT (8.0.24+; the keyring_file plugin was removed in 8.4)\n# 1) Global manifest in the mysqld binary directory: mysqld.my\n{ \"components\": \"file://component_keyring_file\" }\n# 2) In plugin_dir: component_keyring_file.cnf\n{ \"path\": \"/var/lib/mysql-keyring/component_keyring_file\", \"read_only\": false }\n# 3) Restart the server; verify:\n-- SELECT * FROM performance_schema.keyring_component_status;\n-- Encrypt the table:\nALTER TABLE app.orders ENCRYPTION = 'Y';\n-- For new tables: SET PERSIST default_table_encryption = ON;\n# Before 8.0.24 (8.0 only): early-plugin-load = keyring_file.so + keyring_file_data\n# WARNING: back up the keyring file SEPARATELY from the data directory and securely;\n# if the keyring is lost, encrypted tables and their backups become permanently unreadable.","mssql":"-- Transparent Data Encryption (DEK + certificate) — the key and certificate must be in master:\nUSE master;\nCREATE MASTER KEY ENCRYPTION BY PASSWORD = '<StrongPassword1>';\nCREATE CERTIFICATE tde_cert WITH SUBJECT = 'TDE Cert';\n-- MANDATORY: back up the certificate with its private key immediately and store it off the server.\n-- Without this backup, if the server is lost the encrypted DB and its backups CANNOT be restored.\nBACKUP CERTIFICATE tde_cert TO FILE = 'D:\\secure\\tde_cert.cer'\n  WITH PRIVATE KEY (FILE = 'D:\\secure\\tde_cert.pvk',\n    ENCRYPTION BY PASSWORD = '<CertBackupPassword1>');\nUSE appdb;\nCREATE DATABASE ENCRYPTION KEY\n  WITH ALGORITHM = AES_256 ENCRYPTION BY SERVER CERTIFICATE tde_cert;\nALTER DATABASE appdb SET ENCRYPTION ON;\n-- Progress: SELECT DB_NAME(database_id), encryption_state, percent_complete FROM sys.dm_database_encryption_keys;"}},{"title":"パッチを最新に保ち、不要な機能を無効にする","detail":"既知の脆弱性は最も悪用されるリスクである。セキュリティパッチを定期的に適用し、使わないプロトコル、プラグイン、機能を無効にする (攻撃対象領域を縮小する)。","engines":{"oracle":"-- Check the installed version and patches:\nSELECT version_full FROM v$instance;\n-- Apply the quarterly Critical Patch Update (CPU): OPatch/opatchauto\n-- Remove unused components (e.g. XML DB, APEX) and\n-- disable the external procedure (extproc) listener.","postgres":"# Check the version and minor patch level:\nSELECT version();\n# Upgrade to the current minor release with the package manager (e.g. latest 16.x).\n# Remove unused extensions: DROP EXTENSION IF EXISTS ...;\n# postgresql.conf: do not load unused language/PL extensions.","mysql":"-- Check the version: SELECT VERSION();\n-- Upgrade to the LTS/security release (8.0.x/8.4 LTS).\n-- Disable local file reading:\nSET PERSIST local_infile = OFF;\n-- Remove unused plugins: UNINSTALL PLUGIN ...;","mssql":"-- Check the product version/patch level:\nSELECT SERVERPROPERTY('ProductVersion'), SERVERPROPERTY('ProductLevel');\n-- Apply the latest Cumulative Update (CU).\n-- Disable unused features (with sp_configure):\nEXEC sp_configure 'xp_cmdshell', 0; RECONFIGURE;\nEXEC sp_configure 'Ole Automation Procedures', 0; RECONFIGURE;"}}],"related":["list-users","create-user-grant","enable-audit","change-password"]},{"id":"harden-nosql","title":"セキュリティ強化: MongoDB / Redis / Elasticsearch","icon":"🛡️","symptom":"目標: CIS 方式で NoSQL/データストアを強化する — 認証、ネットワーク制限、危険なコマンドのブロック、TLS、最小権限ロール、監査。","steps":[{"title":"認証を有効にする — 未認証のアクセスを遮断する","detail":"これらの製品はデフォルトで認証が無効のまま出荷されることが多く、インターネットに公開されたままにすると侵害される。認証を有効にし、管理者ユーザーを作成する。","engines":{"mongodb":"// mongod.conf:\nsecurity:\n  authorization: enabled\n// Create an administrator user (first time, via the localhost exception):\nuse admin\ndb.createUser({ user: \"admin\", pwd: passwordPrompt(),\n  roles: [ { role: \"userAdminAnyDatabase\", db: \"admin\" } ] })\n// Then connect with: mongosh -u admin --authenticationDatabase admin","redis":"# redis.conf — ACL (Redis 6+): disable the default user, define named users:\nuser default off\nuser admin on >AdminPassword789! ~* &* +@all\nuser app on >AppPassword456! ~app:* +@read +@write\n# Note: requirepass is a legacy compatibility setting that only sets the 'default' user's password;\n# do not confuse it with ACL users. You can also keep users in an aclfile (persisted with ACL SAVE).","elasticsearch":"# 8.x: security (authentication + TLS) is configured automatically on first start; elasticsearch.yml:\nxpack.security.enabled: true\n# Set/reset the password of the 'elastic' user:\nbin/elasticsearch-reset-password -u elastic\n# (elasticsearch-setup-passwords is deprecated since 8.0)\n# Create separate users with dedicated roles for Kibana/clients instead of 'elastic'."}},{"title":"ネットワークを制限する — 必要なインターフェースとポートのみを開く","detail":"サービスが 0.0.0.0 で全世界に対してリッスンしないようにする。バインドアドレスを内部インターフェース/ループバックに固定し、保護モードを有効にする。","engines":{"mongodb":"# mongod.conf — internal interface + loopback only:\nnet:\n  bindIp: 127.0.0.1,10.0.0.10\n  port: 27017\n# Never use bindIpAll: true; limit the port with a firewall.","redis":"# redis.conf:\nbind 127.0.0.1 10.0.0.10\nprotected-mode yes\nport 6379\n# protected-mode blocks external access when no password is set;\n# still limit 6379 with a firewall.","elasticsearch":"# elasticsearch.yml — pin the listening interface:\nnetwork.host: 10.0.0.10\nhttp.port: 9200\ntransport.port: 9300\n# Open only the required ports in the firewall;\n# 9300 (transport) must never be exposed externally."}},{"title":"危険なコマンドを制限する","detail":"1 つのコマンドですべてのデータが消えうる。破壊的/管理用のコマンドの名前を変更するか削除し、またはワイルドカード指定をブロックする。","engines":{"mongodb":"// Use role-based control instead of a separate command block:\n// Grant destructive privileges (dropDatabase, dropCollection) only to\n// dbAdmin/clusterAdmin roles; do not grant them to the application user.\ndb.grantRolesToUser(\"app\", [ { role: \"readWrite\", db: \"appdb\" } ])\n// Do NOT grant dbAdmin/root to the application user.","redis":"# For Redis 6+ the preferred way is ACLs (do not give the application user dangerous commands):\n# ACL SETUSER app ... -@dangerous\n# Legacy method — disable/rename commands in redis.conf:\nrename-command FLUSHALL \"\"\nrename-command FLUSHDB \"\"\nrename-command KEYS \"\"\nrename-command DEBUG \"\"\n# Caution: renaming CONFIG can break Sentinel, CONFIG REWRITE and management tools.","elasticsearch":"# elasticsearch.yml — block wildcard/all-index deletion:\naction.destructive_requires_name: true\n# This rejects DELETE /* or DELETE /_all;\n# bulk deletion is not possible without naming the index explicitly."}},{"title":"TLS/暗号化接続を有効にする","detail":"認証情報とデータは、開かれたネットワーク上を暗号化されずに流れてはならない。クライアントとノード間のトラフィックに TLS を有効にする。","engines":{"mongodb":"# mongod.conf — client TLS:\nnet:\n  tls:\n    mode: requireTLS\n    certificateKeyFile: /etc/ssl/mongodb.pem\n    CAFile: /etc/ssl/ca.pem\n# Client: mongosh --tls --tlsCAFile ca.pem","redis":"# redis.conf — enable TLS, close the plain port:\nport 0\ntls-port 6379\ntls-cert-file /etc/redis/redis.crt\ntls-key-file  /etc/redis/redis.key\ntls-ca-cert-file /etc/redis/ca.crt","elasticsearch":"# elasticsearch.yml — HTTP and transport TLS:\nxpack.security.http.ssl.enabled: true\nxpack.security.http.ssl.keystore.path: http.p12\nxpack.security.transport.ssl.enabled: true\nxpack.security.transport.ssl.verification_mode: certificate\nxpack.security.transport.ssl.keystore.path: transport.p12"}},{"title":"最小権限のロールを付与する — 広範なロールを避ける","detail":"各ユーザーには業務に必要なアクセスのみを与える。広範な/管理用のロールの代わりに、特定のデータベース、キーパターン、インデックスに限定したきめ細かなロールを使う。","engines":{"mongodb":"// Instead of broad readWrite, grant only on the required DB;\n// define a custom role if needed:\ndb.createRole({ role: \"ordersRW\",\n  privileges: [ { resource: { db: \"appdb\", collection: \"orders\" },\n    actions: [ \"find\", \"insert\", \"update\" ] } ], roles: [] })\ndb.grantRolesToUser(\"app\", [ { role: \"ordersRW\", db: \"appdb\" } ])","redis":"# Limit by key pattern and command category with ACLs:\nACL SETUSER app on >AppPassword456! ~app:* +@read +@write -@dangerous\n# Only keys with the 'app:' prefix, read/write; dangerous commands forbidden.\nACL LIST\nACL WHOAMI","elasticsearch":"# Define a fine-grained role (read-only on specific indices):\nPOST /_security/role/orders_read\n{ \"indices\": [ { \"names\": [ \"orders-*\" ],\n    \"privileges\": [ \"read\" ] } ] }\n# Assign it to the user:\nPOST /_security/user/app\n{ \"password\": \"...\", \"roles\": [ \"orders_read\" ] }"}},{"title":"監査/ロギングを有効にする — アクセスと変更を監視する","detail":"不正アクセスの試行と管理操作は記録しなければならない。監査ログを有効にし、中央の場所に送る。","engines":{"mongodb":"# Auditing (requires MongoDB Enterprise) — mongod.conf:\nauditLog:\n  destination: file\n  format: JSON\n  path: /var/log/mongodb/audit.json\n# Filter: capture events such as authenticate, createUser, dropDatabase.","redis":"# Redis has no full audit; use ACL LOG to see rejected\n# authentication/command attempts:\nACL LOG\nACL LOG RESET\n# Also: route the loglevel notice and logfile settings to a central collector.","elasticsearch":"# elasticsearch.yml — enable security auditing:\nxpack.security.audit.enabled: true\nxpack.security.audit.logfile.events.include:\n  [ authentication_failed, access_denied, connection_denied ]\n# Records are written to the <cluster>_audit.json file."}}],"related":["list-users","create-user-grant","enable-audit","change-password"]}]},"playbooks/cloud.json":{"schemaVersion":1,"playbooks":[{"id":"cloud-managed-db","title":"クラウドマネージドデータベース (RDS/Aurora/Cloud SQL/Atlas/Azure SQL)","icon":"☁️","symptom":"目標: クラウドマネージドデータベースとセルフマネージドのインストールの主な違いを学び、クラウドでバックアップ、パラメータ、フェイルオーバー、監視、アップグレード、接続がどのように機能するかを理解する。","steps":[{"title":"考え方の転換: アクセスするのはサーバーではなくサービス","detail":"マネージドデータベースでは、OS、ファイルシステム、データベースプロセスへのシェルアクセスはない。SSH でのログイン、構成ファイルの手動編集、スーパーユーザー化はできない。得られるのはプロバイダーの管理 API/コンソールと通常の SQL 接続のみである。AWS RDS/Aurora: 管理はリソース (インスタンス/クラスタ) レベルで、サーバーは隠されている。GCP Cloud SQL: インスタンス API のみで OS はない。MongoDB Atlas: フルマネージドのクラスタで、mongod へのアクセスはない。Azure SQL Database: PaaS で、下層のサーバーも OS も見えない (Managed Instance ではやや多くの制御が可能)。そのため「ファイルを見る」「プロセスを強制終了する」「OS ツールを実行する」といったセルフマネージドでの反射的な対応の多くは通用しない。"},{"title":"バックアップ: 自動スナップショット + ポイントインタイムリカバリ (PITR)","detail":"バックアップをスケジュールする必要はなく、プロバイダーが自動的に取得する。復旧は通常「特定の時点へのリストア」(PITR) またはスナップショットからの新規インスタンス作成であり、既存のインスタンスは上書きされない。AWS RDS/Aurora: 自動バックアップ + 保持期間。秒単位の精度での PITR リストアは新しいインスタンス/クラスタとして開かれる。手動スナップショットも可能。GCP Cloud SQL: 自動バックアップ + バイナリログによる PITR。リストアは新しいインスタンスに行われる。MongoDB Atlas: 継続的なクラウドバックアップ + PITR (M10+)。スナップショットからのリストア。Azure SQL: 組込みの自動バックアップ、1-35 日の保持、任意の時点への PITR と削除された DB のリストア。共通ルール: バックアップ構成 (ウィンドウ、保持期間) を確認し、定期的にリストアテストを行う。"},{"title":"パラメータ: 構成ファイルではなくパラメータグループ / フラグ","detail":"postgresql.conf や my.cnf を手動で編集する代わりに、プロバイダーのパラメータ抽象化を使う。一部のパラメータはロックされており、一部は再起動が必要 (静的) である。AWS RDS/Aurora: DB パラメータグループ (およびクラスタパラメータグループ) で設定する。動的パラメータは即座に、静的パラメータは再起動時に適用される。GCP Cloud SQL: 「データベースフラグ」をコンソール/gcloud から設定する。MongoDB Atlas: 限定的な「Additional Settings」+ oplog サイズなど。内部パラメータの大半は管理対象。Azure SQL: サーバーレベルの設定の大半は管理対象で、SCOPED CONFIGURATION とサービス階層の選択で動作が変わる。適用前に、パラメータが動的か静的かを確認する。"},{"title":"高可用性 / フェイルオーバー: マネージドの Multi-AZ とレプリカ","detail":"フェイルオーバーを自分で構築するのではなく、チェックボックスをオンにしてプロバイダーに任せる。スタンバイと自動フェイルオーバーは管理され、接続は安定したエンドポイントを通じて新プライマリにリダイレクトされる。AWS RDS: Multi-AZ (同期スタンバイ、自動フェイルオーバー)。Aurora: マルチコピーストレージ + 自動フェイルオーバー、クラスタエンドポイントはライターを指す。GCP Cloud SQL: ワンクリックの HA 構成 (リージョナル、セカンダリゾーンにスタンバイ)。読み取りレプリカは別途追加する。MongoDB Atlas: レプリカセットが組込みで、マルチリージョン/マルチクラウドのデプロイが可能、フェイルオーバーは自動。Azure SQL: 組込みの HA (Business Critical ではローカルレプリカ)、ゾーン冗長オプション、リージョン間のアクティブ geo レプリケーション / フェイルオーバーグループ。アプリケーションは常にエンドポイントに接続し、固定 IP には決して接続しないこと。"},{"title":"監視: プロバイダーのメトリクスとログサービス","detail":"OS ツール (top、iostat) を実行できないため、プロバイダーのメトリクスプラットフォームで監視する。CPU、接続数、IOPS、レプリケーションラグ、ストレージのメトリクスはそこにある。AWS: CloudWatch メトリクス + Enhanced Monitoring + Performance Insights (クエリレベルの分析)。GCP Cloud SQL: Cloud Monitoring (旧 Stackdriver) + Query Insights。MongoDB Atlas: 組込みの Atlas メトリクス/チャート + Performance Advisor + リアルタイムパネル。Azure SQL: Azure Monitor + SQL Analytics + Query Performance Insight。しきい値アラーム (ストレージ使用量、CPU、接続数上限、レプリカラグ) を必ず設定する。"},{"title":"バージョンアップグレードとメンテナンス: コンソールから、メンテナンスウィンドウ内で","detail":"バイナリを手動で更新する代わりにターゲットバージョンを選ぶ。マイナーバージョンのパッチはほぼ自動で、メジャーバージョンのアップグレードは計画的に行い、通常はダウンタイム/HA フェイルオーバーを伴う。AWS RDS/Aurora: エンジンバージョンの選択 + 自動マイナーアップグレードのオプション + Blue/Green Deployments による低リスクのメジャーアップグレード。GCP Cloud SQL: メンテナンスウィンドウ + セルフサービスのメジャーバージョンアップグレード。MongoDB Atlas: ワンクリックのバージョンアップグレード、ローリング方式でほぼ無停止。Azure SQL: プラットフォームが自動的にパッチを適用する (バージョンの概念はほぼ抽象化されている)。動作は互換性レベルで制御する。必ずまずテスト/ステージングのコピーで試し、メンテナンスウィンドウは業務時間外にスケジュールする。"},{"title":"接続とセキュリティ: エンドポイント + IAM/TLS","detail":"接続は常にプロバイダーが提供する DNS エンドポイントを経由し、暗号化される (TLS)。ネットワークアクセスと ID はクラウドの ID システムに結び付けられる。AWS RDS/Aurora: インスタンス/クラスタエンドポイント + ネットワーク用の Security Group + 任意の IAM データベース認証 + TLS (rds-ca 証明書)。GCP Cloud SQL: パブリック IP + Authorized Networks またはプライベート IP/VPC、Cloud SQL Auth Proxy、IAM データベース認証、TLS。MongoDB Atlas: SRV 接続文字列 (mongodb+srv://)、IP アクセスリスト + プライベートエンドポイント/ピアリング、SCRAM または IAM/X.509、TLS 必須。Azure SQL: サーバー FQDN エンドポイント + ファイアウォール/Private Link + Microsoft Entra ID (旧 Azure AD) 認証 + TLS 必須。ルール: 接続文字列には固定 IP ではなくエンドポイントを使い、TLS を強制し、可能な場合はクラウドの IAM ID で接続する。"}],"related":["last-backup-status","promote-failover","connect-cli"]}]},"playbooks/automation.json":{"schemaVersion":1,"playbooks":[{"id":"auto-ansible","title":"Ansible によるデータベース自動化","icon":"🤖","symptom":"目標: Ansible により、データベースのインストール、構成、ユーザー、バックアップのタスクを再現可能かつ冪等にする (同じプレイブックを再実行してもシステムが壊れない)。","steps":[{"title":"インベントリとグループを定義する","detail":"インベントリ内でサーバーをデータベースのロールごとにグループ化し、プライマリ、レプリカ、バックアップサーバーを別々のグループに入れる。静的な INI/YAML インベントリ、またはクラウド用の動的インベントリ (aws_ec2、gcp_compute) を使う。グループ変数は group_vars/ に、ホスト固有の変数は host_vars/ に置く。","engines":{"postgres":"[pg_primary]\ndb1.example.local\n\n[pg_replica]\ndb2.example.local\n\n[postgres:children]\npg_primary\npg_replica"}},{"title":"適切なコレクションをインストールする (community.postgresql / community.mysql / community.mongodb)","detail":"現在の Ansible core はデータベースモジュールを個別のコレクションで提供している。使用するエンジンのコレクションを requirements.yml でインストールする。PostgreSQL には community.postgresql (postgresql_db、postgresql_user、postgresql_privs)、MySQL/MariaDB には community.mysql (mysql_db、mysql_user)、MongoDB には community.mongodb を使う。ターゲットホストには対応する Python クライアント (psycopg2、PyMySQL、pymongo) がインストールされている必要がある。","engines":{"postgres":"# requirements.yml\ncollections:\n  - name: community.postgresql\n\n# install:\nansible-galaxy collection install -r requirements.yml","mysql":"collections:\n  - name: community.mysql","mongodb":"collections:\n  - name: community.mongodb"}},{"title":"Ansible Vault でシークレットを暗号化する","detail":"データベースのパスワード、レプリケーションのシークレット、スーパーユーザーの認証情報を平文のまま放置せず、ansible-vault で暗号化された変数ファイルに保持する。実行時に --ask-vault-pass または --vault-password-file で復号する。これによりシークレットを Git に安全に保存でき、プレイブックは冪等のまま保たれる。","engines":{"postgres":"ansible-vault create group_vars/postgres/vault.yml\n# contents:\nvault_pg_admin_password: \"S3cret!\"\n\n# run:\nansible-playbook site.yml --ask-vault-pass"}},{"title":"ロール構造を構築する (roles/postgres、roles/mysql)","detail":"エンジンごとに 1 つのロールを作成し、ロジックを tasks/、defaults/、templates/、handlers/ のサブフォルダに分割する。この構造は再利用性を高める: デフォルト値は defaults/main.yml、jinja2 の構成テンプレートは templates/、「変更があった場合のみ再起動」のロジックは handlers/ に置く。ロールの雛形は ansible-galaxy init roles/postgres で作成できる。","engines":{"postgres":"ansible-galaxy init roles/postgres\n# roles/postgres/\n#   defaults/main.yml\n#   tasks/main.yml\n#   templates/postgresql.conf.j2\n#   handlers/main.yml"}},{"title":"インストールと構成のタスクを冪等に書く","detail":"パッケージをインストールし、データディレクトリを初期化し、postgresql.conf/my.cnf をテンプレートから生成する。構成が変わった場合はハンドラー経由でサービスを再起動する。モジュールは冪等である: インストール済みのパッケージは再インストールされず、ファイルが変わっていなければハンドラーは起動されない。template モジュールで構成テンプレートを生成し、'notify' でハンドラーに結び付ける。","engines":{"postgres":"- name: postgresql.conf template\n  ansible.builtin.template:\n    src: postgresql.conf.j2\n    dest: /etc/postgresql/16/main/postgresql.conf\n  notify: restart postgresql\n\n# handlers/main.yml\n- name: restart postgresql\n  ansible.builtin.service:\n    name: postgresql\n    state: restarted","mysql":"- name: my.cnf template\n  ansible.builtin.template:\n    src: my.cnf.j2\n    dest: /etc/mysql/my.cnf\n  notify: restart mysql"}},{"title":"データベースとユーザーのタスクを定義する","detail":"モジュールでデータベース、ユーザー、権限を作成し、パスワードは Vault の変数から取得する。community.postgresql のモジュールは冪等である: ユーザー/DB が存在すれば再作成せず、差分のみを適用する。権限は postgresql_privs で別途付与する。MySQL では mysql_user の priv フィールドを使う。","engines":{"postgres":"- name: application database\n  community.postgresql.postgresql_db:\n    name: appdb\n    state: present\n\n- name: application user\n  community.postgresql.postgresql_user:\n    name: app_user\n    password: \"{{ vault_app_password }}\"\n    db: appdb\n    state: present","mysql":"- name: application user\n  community.mysql.mysql_user:\n    name: app_user\n    password: \"{{ vault_app_password }}\"\n    priv: 'appdb.*:ALL'\n    state: present"}},{"title":"バックアップタスクとスケジュールを追加する","detail":"バックアップスクリプトをテンプレートからデプロイし、ansible.builtin.cron でスケジュールする。これによりバックアップジョブもコードとして管理される。バックアップ先ディレクトリ、保持期間、スケジュールは変数にする。cron モジュールは冪等で、エントリを 'name' で識別するため、再実行しても重複しない。","engines":{"postgres":"- name: nightly backup (cron)\n  ansible.builtin.cron:\n    name: \"pg dump nightly\"\n    minute: \"0\"\n    hour: \"2\"\n    job: \"pg_dump -Fc appdb > /backup/appdb_$(date +\\\\%F).dump\""}}],"related":["schedule-job","check-version","logical-dump"]},{"id":"auto-terraform","title":"Terraform によるデータベースのプロビジョニング (IaC)","icon":"🏗️","symptom":"目標: Terraform でデータベースインフラ (インスタンス、パラメータグループ、ネットワーク) をコードとして定義し (Infrastructure as Code)、plan/apply のフロー、リモートステート、ドリフト管理を構築する。","steps":[{"title":"プロバイダーを選択して構成する (aws / google / azurerm)","detail":"使用するクラウドのプロバイダーを定義し、バージョンを固定する。required_providers ブロックで、AWS には hashicorp/aws、GCP には hashicorp/google、Azure には hashicorp/azurerm のプロバイダーを固定する。バージョン固定によりチーム全体で一貫した動作が保証される。","engines":{"postgres":"terraform {\n  required_providers {\n    aws = {\n      source  = \"hashicorp/aws\"\n      version = \"~> 5.0\"\n    }\n  }\n}\n\nprovider \"aws\" {\n  region = \"eu-central-1\"\n}"}},{"title":"リモートステートとロックを構築する","detail":"ステートファイルをローカルに保持せず、チーム作業とセキュリティのためにリモートバックエンドを使う。一般的な選択肢は、AWS では S3 バックエンド + DynamoDB のロックテーブル、GCP では gcs バックエンド、Azure では azurerm バックエンド (Storage Account) である。リモートステートはロックにより同時の apply を防ぎ、ステートを唯一の信頼できる情報源にする。ステートにはパスワードが平文で含まれうるため、バックエンドは暗号化しアクセスを制限する。","engines":{"postgres":"terraform {\n  backend \"s3\" {\n    bucket         = \"company-tfstate\"\n    key            = \"db/terraform.tfstate\"\n    region         = \"eu-central-1\"\n    dynamodb_table = \"tf-lock\"\n    encrypt        = true\n  }\n}"}},{"title":"データベースリソースを定義する","detail":"使用するエンジンとクラウドのメインリソースを書く: AWS では aws_db_instance (Aurora では aws_rds_cluster)、GCP では google_sql_database_instance、Azure では azurerm_mssql_database (SQL Server の場合、azurerm_mssql_server 配下)。エンジン、バージョン、クラス、ストレージ、バックアップウィンドウをここで指定する。","engines":{"postgres":"resource \"aws_db_instance\" \"pg\" {\n  identifier        = \"app-db\"\n  engine            = \"postgres\"\n  engine_version    = \"16\"\n  instance_class    = \"db.t3.medium\"\n  allocated_storage = 50\n  db_name           = \"appdb\"\n  username          = \"pgadmin\"\n  password          = var.db_password\n  backup_retention_period = 7\n}","mssql":"resource \"azurerm_mssql_database\" \"db\" {\n  name      = \"appdb\"\n  server_id = azurerm_mssql_server.srv.id\n  sku_name  = \"S1\"\n}"}},{"title":"パラメータグループをコードとして書く","detail":"データベースの設定 (max_connections、work_mem、文字セット) は、コンソールで手動で設定するのではなくパラメータリソースで定義する。AWS では aws_db_parameter_group、GCP では google_sql_database_instance 内の settings.database_flags、Azure ではサーバー構成リソースを使う。これにより設定がバージョン管理され、再現可能になる。","engines":{"postgres":"resource \"aws_db_parameter_group\" \"pg\" {\n  name   = \"app-pg16\"\n  family = \"postgres16\"\n\n  parameter {\n    name  = \"max_connections\"\n    value = \"200\"\n  }\n}\n# inside aws_db_instance:\n# parameter_group_name = aws_db_parameter_group.pg.name"}},{"title":"シークレットを変数とシークレットマネージャー経由で渡す","detail":"パスワードを .tf ファイルにハードコードせず、機密変数 (variable ... sensitive = true) として定義し、値は TF_VAR_ 環境変数、シークレットマネージャー (AWS Secrets Manager、Vault)、または CI のシークレットで渡す。注意: 値はステートファイルに書き込まれるため、リモートステートは暗号化する必要がある。最もクリーンな方法は、パスワードを Terraform に一切渡さず、シークレットマネージャーのリソースから読み取ることである。","engines":{"postgres":"variable \"db_password\" {\n  type      = string\n  sensitive = true\n}\n\n# CI/shell:\nexport TF_VAR_db_password=\"$(vault kv get -field=pw secret/db)\""}},{"title":"plan と apply のフローを実行する","detail":"まず terraform init でプロバイダー/バックエンドを準備し、terraform plan で何が変わるかを確認し、承認してから terraform apply で適用する。plan の出力を確認せずに apply しないこと。CI での安全なフローは、'plan' を PR のコメントとして投稿し、人による承認後に apply することである。破壊的な変更 (例: インスタンスの再作成) は plan 出力の -/+ マーカーで見つける。","engines":{"postgres":"terraform init\nterraform plan -out=plan.tfplan\nterraform apply plan.tfplan"}},{"title":"ドリフトを検出して修正する","detail":"誰かがコンソールで手動変更を行うと、実際のインフラとステートが乖離する (ドリフト)。「何も変わっていないはずなのに」terraform plan に差分が現れることでドリフトが明らかになり、差分は terraform refresh/plan で読み取れる。変更をコードに反映するか、apply でインフラをコードの状態に戻す。原則として手動変更は禁止し、コードを唯一の信頼できる情報源とする。","engines":{"postgres":"# drift check (when no changes are expected):\nterraform plan\n# expect 'No changes'; any diff means drift\n# bring an existing resource into state with import:\nterraform import aws_db_instance.pg app-db"}}],"related":["check-version","apply-patch","schedule-job"]},{"id":"auto-k8s-operator","title":"Kubernetes 上のデータベース (オペレーター)","icon":"☸️","symptom":"目標: オペレーターを使って Kubernetes 上でデータベースを実行する。素の StatefulSet ではなく、オペレーターが提供する自動フェイルオーバー、永続ストレージ、バックアップの機能を使う。","steps":[{"title":"なぜオペレーターか: StatefulSet だけでは不十分","detail":"素の StatefulSet は安定した ID と PVC を持つ Pod を提供するが、フェイルオーバー、レプリケーションの構築、バックアップ、アップグレードのロジックは提供しない。オペレーターは、このデータベース固有の運用知識をコントローラー + カスタムリソース (CRD) としてパッケージ化する。'Cluster' という CR を書けば、オペレーターがその背後の StatefulSet、Service、Secret、バックアップジョブを管理する。本番では、オペレーターでデータベースを実行する方法が一般に好まれる。","engines":{"postgres":"# operators for PostgreSQL:\n#  - CloudNativePG (CNPG)\n#  - Zalando postgres-operator\n#  - Crunchy PGO"}},{"title":"オペレーターを選択してインストールする","detail":"エンジンに合ったオペレーターを選ぶ: PostgreSQL には CloudNativePG または Zalando postgres-operator。MySQL と MongoDB には Percona のオペレーター (Percona Operator for MySQL / for MongoDB) が一般的である。オペレーターは Helm またはバンドルマニフェストでインストールする。この手順でクラスタに CRD とコントローラー Pod が追加される。","engines":{"postgres":"# CloudNativePG installation\nkubectl apply --server-side -f \\\n  https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/main/releases/cnpg-1.24.0.yaml","mysql":"# Percona Operator for MySQL (Helm)\nhelm install my-op percona/pxc-operator","mongodb":"# Percona Operator for MongoDB (Helm)\nhelm install psmdb-op percona/psmdb-operator"}},{"title":"ストレージを計画する (StorageClass / PVC)","detail":"データベースの状態は PVC に保持される。使用する StorageClass を CR で指定する。低レイテンシのブロックストレージ、理想的にはローカルに近い SSD を提供する StorageClass を選ぶ。ネットワークファイルシステム (NFS) は大半のデータベースで推奨されない。縮小は難しいため、PVC のサイズと拡張可能性 (allowVolumeExpansion) は最初から正しく設定する。","engines":{"postgres":"spec:\n  storage:\n    storageClass: fast-ssd\n    size: 50Gi"}},{"title":"Cluster CR を適用する (レプリカと自動フェイルオーバー)","detail":"CR でインスタンス/レプリカの数を指定する。オペレーターは同期/非同期レプリケーションを構築し、プライマリ障害時にはレプリカを昇格させて自動フェイルオーバーを行う。アプリケーションはオペレーターが作成する '-rw' (読み取り/書き込み) Service に接続すべきである。このサービスは常に現在のプライマリを指すため、フェイルオーバー中も接続先は変わらない。","engines":{"postgres":"apiVersion: postgresql.cnpg.io/v1\nkind: Cluster\nmetadata:\n  name: app-db\nspec:\n  instances: 3\n  storage:\n    storageClass: fast-ssd\n    size: 50Gi\n# the application connects to: app-db-rw"}},{"title":"CR 経由でバックアップを S3 に書き込む","detail":"オペレーターはバックアップも宣言的に管理する: CR でプライマリのバックアップ先 (オブジェクトストレージ/S3) と WAL アーカイブを定義する。CloudNativePG では S3 の詳細を spec.backup.barmanObjectStore で指定する (1.26 以降は非推奨。新規デプロイでは Barman Cloud Plugin とその ObjectStore リソースを使う)。継続的な WAL アーカイブ + ベースバックアップでポイントインタイムリカバリが可能になる。認証情報は Kubernetes Secret から参照する。","engines":{"postgres":"spec:\n  backup:\n    barmanObjectStore:\n      destinationPath: s3://company-backup/app-db\n      s3Credentials:\n        accessKeyId:\n          name: s3-creds\n          key: ACCESS_KEY_ID\n        secretAccessKey:\n          name: s3-creds\n          key: SECRET_ACCESS_KEY"}},{"title":"スケジュールバックアップとリストアの CR","detail":"単発のバックアップには Backup CR を、スケジュールバックアップには ScheduledBackup CR を作成し、cron 式で定期的にベースバックアップを取る。リストアも宣言的である: 'bootstrap.recovery' で既存のオブジェクトストアのバックアップから新しい Cluster をブートストラップする。リストア訓練を定期的に行うこと。バックアップを取るだけでは不十分で、復旧をテストする。","engines":{"postgres":"apiVersion: postgresql.cnpg.io/v1\nkind: ScheduledBackup\nmetadata:\n  name: nightly-backup\nspec:\n  schedule: \"0 0 2 * * *\"\n  cluster:\n    name: app-db"}}],"related":["setup-cdc-replication","logical-dump","restore-dump"]},{"id":"auto-schema-migration","title":"スキーママイグレーションの CI/CD (Flyway/Liquibase)","icon":"🧬","symptom":"目標: データベーススキーマの変更をバージョン管理されたマイグレーションファイルで管理し、Flyway または Liquibase を使って CI/CD 内で自動的かつ制御された形で適用する。","steps":[{"title":"バージョン付きのマイグレーションファイルを作成する (Vxxx__name.sql)","detail":"すべてのスキーマ変更を、増加するバージョン番号付きの名前のファイルに書く。Flyway の規約は V<version>__<description>.sql である (例: V1__initial_schemas.sql、V2__orders_table.sql)。これらのファイルは Git で管理され、バージョン順に適用される。適用済みのマイグレーションは追跡テーブル (Flyway では flyway_schema_history) に記録されるため、各マイグレーションは正確に 1 回だけ実行される。","engines":{"postgres":"-- V2__orders_table.sql\nCREATE TABLE orders (\n  id       bigserial PRIMARY KEY,\n  amount    numeric(12,2) NOT NULL,\n  created_at   timestamptz DEFAULT now()\n);"}},{"title":"チェックサムで不変性を維持する","detail":"Flyway/Liquibase は適用済みの各マイグレーションのチェックサムを保存する。適用済みのファイルを後から編集するとチェックサムが一致しなくなり、ツールはエラーになる。ルール: 適用済みのマイグレーションは決して編集しないこと。修正は新しいバージョンのファイルで行う。これによりすべての環境 (dev/staging/prod) が同じ履歴を共有することが保証される。","engines":{"postgres":"# repair on checksum mismatch (use with care):\nflyway repair\n# the right way: add the change in a new Vx file"}},{"title":"既存のデータベースをベースライン化する","detail":"履歴のない、すでにデータが入ったデータベースにマイグレーションツールを導入する場合は baseline を使う。現在の状態を「開始バージョン」として扱い、既存のオブジェクトを再作成しようとしない。baselineVersion より後のマイグレーションが適用される。一から構築する環境ではベースラインは不要で、マイグレーションは V1 から実行される。","engines":{"postgres":"flyway baseline -baselineVersion=1 -baselineDescription=\"existing schema\""}},{"title":"CI パイプラインで自動的にマイグレーションする","detail":"CI のステップでマイグレーションツールを実行し、テスト用とステージング用のデータベースに変更を自動的に適用する。migrate コマンドは新しい (未適用の) ファイルのみを実行し、冪等である。まず一時的な (エフェメラルな) データベースにマイグレーションを適用して検証すると、壊れた SQL が本番に到達する前に検出できる。スキーマはアプリケーションコードのデプロイより前にマイグレーションする必要がある (後方互換の変更で)。","engines":{"postgres":"# CI step (Flyway)\nflyway -url=jdbc:postgresql://staging/appdb \\\n  -user=ci -password=$PW migrate","mysql":"flyway -url=jdbc:mysql://staging/appdb \\\n  -user=ci -password=$PW migrate"}},{"title":"本番に手動承認ゲートを追加する","detail":"テスト/ステージングは自動とし、本番の migrate には手動承認を必須とする。CI/CD に「承認ゲート」(手動承認) のステップを追加する。承認前に 'flyway info' または 'liquibase status' でどのマイグレーションが実行されるかを示す。問題が起きた場合にロールバックできるよう、本番に適用する前に必ず最新のバックアップを取る。","engines":{"postgres":"# what will run before approval?\nflyway info\n# liquibase equivalent:\nliquibase status --verbose"}},{"title":"可逆性とロールバック戦略を定義する","detail":"Flyway Community には自動 undo がないため、前進のみ (forward-only) のマイグレーション原則を採用する: 誤りを取り消すのではなく、それを修正する新しいマイグレーションを書く。Liquibase の changeset では rollback ブロックを定義でき、'liquibase rollback' でロールバックできる。最も堅牢な戦略: 変更を小さく後方互換に保ち、リスクのある操作 (列の削除) の前にバックアップを取り、文書化したロールバック計画を用意する。","engines":{"postgres":"-- Liquibase rollback example (inside a changeset)\n--changeset dev:2\nCREATE TABLE orders (...);\n--rollback DROP TABLE orders;"}}],"related":["apply-patch","logical-dump","check-version"]},{"id":"auto-backup","title":"自動バックアップ (pgBackRest/Barman/Xtrabackup/cron)","icon":"💾","symptom":"目標: データベースのバックアップを自動化し、スケジュールされたフル + 増分 + WAL/binlog アーカイブ、保持、検証、オフサイトコピーによる信頼性の高い復旧チェーンを構築する。","steps":[{"title":"適切なバックアップツールを選ぶ","detail":"エンジンに合ったツールを選ぶ: PostgreSQL には pgBackRest または Barman (物理バックアップ + WAL アーカイブ + PITR)。MySQL/MariaDB には Percona XtraBackup (オンライン物理バックアップ)、小規模なデータセットには mysqldump/mydumper (論理)。物理ツールは大規模データベースで高速かつ一貫性のあるバックアップとポイントインタイムリカバリを提供する。論理ダンプは移植性があるが、大規模データでは遅い。","engines":{"postgres":"# pgBackRest or Barman","mysql":"# physical: xtrabackup\n# logical: mysqldump / mydumper"}},{"title":"フル + 増分 + 継続的アーカイブのチェーンを構築する","detail":"週次/日次のフルバックアップ、その間の増分/差分バックアップ、継続的な WAL (PostgreSQL) または binlog (MySQL) のアーカイブで、ポイントインタイムリカバリを構築する。pgBackRest は full/diff/incremental のバックアップ種別と WAL アーカイブを管理する。PostgreSQL では archive_command で pgBackRest を指定する。増分バックアップ + アーカイブにより任意の時点に戻れる。","engines":{"postgres":"# postgresql.conf\narchive_mode = on\narchive_command = 'pgbackrest --stanza=appdb archive-push %p'\n\n# full backup\npgbackrest --stanza=appdb --type=full backup\n# incremental\npgbackrest --stanza=appdb --type=incr backup","mysql":"# full\nxtrabackup --backup --target-dir=/backup/full\n# incremental\nxtrabackup --backup --target-dir=/backup/incr1 \\\n  --incremental-basedir=/backup/full"}},{"title":"cron/タイマーでバックアップをスケジュールする","detail":"cron または systemd タイマーでバックアップコマンドを定期的に実行する: 例えば日曜の夜にフルバックアップ、他の夜は増分。業務時間外にスケジュールし、full と incr のジョブが重ならないようにする。出力ログをどこかに書き込み、失敗時にはアラートを上げる。","engines":{"postgres":"# crontab\n0 1 * * 0 pgbackrest --stanza=appdb --type=full backup\n0 1 * * 1-6 pgbackrest --stanza=appdb --type=incr backup"}},{"title":"保持ポリシーを定義する","detail":"バックアップを際限なく蓄積せず、保持するフルバックアップ数とアーカイブの日数を設定し、古いものはツールに自動で期限切れにさせる。pgBackRest では repo1-retention-full とアーカイブの保持設定で、Barman では retention_policy で管理する。保持期間は復旧目標 (何日前まで戻る必要があるか) に合わせる必要がある。","engines":{"postgres":"# pgbackrest.conf\n[global]\nrepo1-retention-full=4\nrepo1-retention-archive=8","mysql":"# purge old backups with cron (example)\nfind /backup -type d -mtime +14 -exec rm -rf {} +"}},{"title":"バックアップをオフサイト / S3 にコピーする","detail":"バックアップはデータベースと同じマシン/リージョンに置いたままにしてはならない。別の場所またはオブジェクトストレージ (S3、GCS) にコピーする。pgBackRest は S3 互換ストレージに直接書き込める。それ以外の場合は rsync/rclone でオフサイトのターゲットに同期する。災害時 (ローカルディスク/リージョンの喪失) に助けになるのはオフサイトのコピーだけである。","engines":{"postgres":"# pgbackrest.conf S3 repository\n[global]\nrepo1-type=s3\nrepo1-s3-bucket=company-backup\nrepo1-s3-region=eu-central-1\nrepo1-s3-endpoint=s3.eu-central-1.amazonaws.com"}},{"title":"バックアップを検証する","detail":"バックアップが存在しても、リストアできるとは限らない。整合性を定期的に検証する。pgBackRest では 'verify' コマンドとアーカイブの一貫性チェック、XtraBackup では prepare (--prepare) ステップの成功が、バックアップが健全であることを示す。毎回のバックアップ後に検証を自動実行し、失敗時にはアラームを上げる。","engines":{"postgres":"pgbackrest --stanza=appdb verify","mysql":"# make the backup consistent (verification)\nxtrabackup --prepare --target-dir=/backup/full"}},{"title":"定期的なリストア訓練を行う","detail":"最も重要なステップ: 定期的にバックアップを別のサーバーへ実際にリストアし、データベースがオープンしデータに一貫性があることを検証する。この訓練により、復旧時間 (RTO) を測定し、インシデント以外の場で手順の不備を見つけられる。テストされていないバックアップはバックアップではない。","engines":{"postgres":"# restore + PITR on a separate server\npgbackrest --stanza=appdb \\\n  --type=time --target=\"2026-07-01 03:00:00\" restore","mysql":"# copy the prepared backup back to the data directory\nxtrabackup --copy-back --target-dir=/backup/full"}}],"related":["logical-dump","restore-dump","schedule-job"]},{"id":"auto-gitops-bluegreen","title":"GitOps と blue-green / 無停止デプロイ","icon":"🟦","symptom":"目標: スキーマとアプリケーションの変更をダウンタイムなしでデプロイする。expand-contract マイグレーション、blue-green 環境、フィーチャーフラグ、自動ロールバックで無停止に近づける。","steps":[{"title":"GitOps: Git を唯一の信頼できる情報源にする","detail":"インフラ、スキーママイグレーション、アプリケーションのバージョンを Git で定義する。デプロイはリポジトリへのマージによってトリガーされる (GitOps)。リコンサイラー (Argo CD/Flux または CI/CD) が望ましい状態を実環境に適用する。これによりすべての変更が監査可能かつ再現可能になり、必要に応じて以前のコミットに戻せる。","engines":{"postgres":"# repo/\n#   migrations/  (Vxxx__*.sql)\n#   k8s/         (Deployment, Service)\n#   flags/       (feature flag config)"}},{"title":"スキーマを後方互換に変更する (expand-contract)","detail":"無停止のためには、スキーマを破壊的な 1 ステップで変更せず、2 つのフェーズに分ける。EXPAND: 旧コードと新コードが同時に動作できるよう新しい構造 (新しい列/テーブル) を追加する (NULL 許容列、デフォルト付き、二重書き込み)。アプリケーションが新しい構造に移行した後に CONTRACT: 使われなくなった古い列/テーブルを別のマイグレーションで削除する。これによりデプロイ中も旧バージョンと新バージョンのアプリケーションが問題なく並行稼働する。","engines":{"postgres":"-- EXPAND (V5): backward-compatible addition\nALTER TABLE customer ADD COLUMN email text;\n\n-- for a while the code writes/reads both columns\n\n-- CONTRACT (V9): drop the old column\nALTER TABLE customer DROP COLUMN mail_old;"}},{"title":"リスクのある動作をフィーチャーフラグの背後に置く","detail":"新しいコードパス (新しい列の読み取りなど) をフィーチャーフラグの背後で条件付きで実行する。スキーマの準備ができたらフラグをオンにし、問題があればデプロイに触れずにオフにする。フラグはコードのデプロイ (deploy) と機能の有効化 (release) を分離する。expand フェーズは出荷されるが、動作の変更は制御された形で有効化され、迅速に元に戻せる。","engines":{"postgres":"-- application layer (pseudocode)\n-- if flag('new_email_field'):\n--     SELECT email FROM customer ...\n-- else:\n--     SELECT mail_old FROM customer ..."}},{"title":"blue-green 環境を構築する","detail":"2 つの同一の環境を保持する: 'blue' (本番稼働中) と 'green' (新バージョン)。新しいアプリケーションバージョンを green にデプロイし、実トラフィックを受ける前に検証する。準備ができたらルーター/トラフィックを green に切り替える。重要な点: データベースは通常共有されているため、スキーマは両方のバージョンと互換でなければならない (expand-contract がこれを保証する)。切り替え時に接続先が変わっても、スキーマの互換性によりダウンタイムは発生しない。","engines":{"postgres":"# traffic is switched to green (new version)\n# shared DB: schema must be compatible with both blue and green"}},{"title":"監視でデプロイを検証する (カナリア/観察)","detail":"すべてのトラフィックを切り替える前に、エラー率、レイテンシ、データベースのエラー/ロック数、レプリケーションラグなどのメトリクスを監視する。必要に応じてトラフィックのごく一部 (カナリア) を green に送って観察する。ヘルス指標が良好ならトラフィックを段階的に増やし、悪ければ先に進まない。監視は自動ロールバックの判断材料となる。","engines":{"postgres":"-- live health queries\nSELECT count(*) FROM pg_stat_activity WHERE wait_event_type='Lock';\nSELECT * FROM pg_stat_replication;"}},{"title":"自動ロールバックを準備する","detail":"メトリクスがしきい値を超えたら、デプロイは自動的にロールバックされなければならない: blue-green では、トラフィックを素早く blue (旧バージョン) に戻す。blue はまだ稼働しているため、アプリケーションのロールバックは即時である。スキーマ側のロールバックは通常不要である: expand-contract により新しいスキーマは旧コードとも互換であるため、アプリケーションをロールバックすれば十分である。そのため、スキーマの変更はアプリケーションのデプロイから独立させ、常に後方互換に保つべきである。","engines":{"postgres":"# traffic instantly returns to blue (application rollback)\n# schema is not rolled back: expand-contract is compatible with old code\n# if truly needed: write a new corrective migration"}}],"related":["setup-cdc-replication","apply-patch","check-version"]}]},"install/index.json":{"schemaVersion":1,"categories":[{"id":"install","title":"インストール"},{"id":"ha","title":"高可用性とレプリケーション"},{"id":"backup","title":"バックアップとリカバリ"},{"id":"ops","title":"日常運用と障害対応"},{"id":"pooling","title":"接続と負荷分散"},{"id":"patch","title":"パッチとマイナーアップデート"},{"id":"upgrade","title":"メジャーアップグレードと移行"},{"id":"monitoring","title":"監視と管理"},{"id":"security","title":"セキュリティと堅牢化"}],"guides":[{"id":"pg-install","file":"install/guides/pg-install.json","group":"PostgreSQL","engineId":"postgres","category":"install","title":"PostgreSQL 単一サーバーのインストール（本番運用向け）","summary":"PGDG リポジトリから単一サーバーに本番運用向けの PostgreSQL をインストールします。独立したデータ・ディレクトリ、data checksums、RAM/CPU から算出した設定、安全なアクセス制御（peer + scram-sha-256）、ログ出力、pg_stat_statements、ファイアウォール、SELinux を扱います。完了時には、稼働中で検証済みのクラスタと、バックアップ / 監視のチェックリストが揃います","level":"初級","duration":"30–45 分","topology":"サーバー 1 台","tags":["postgresql","postgres","インストール","install","pgdg","initdb","チューニング","rhel","ubuntu"],"order":1,"steps":23,"scenarios":[]},{"id":"pg-streaming","file":"install/guides/pg-streaming.json","group":"PostgreSQL","engineId":"postgres","category":"ha","title":"PostgreSQL ストリーミングレプリケーション (primary + standby)","summary":"構築済みの primary に pg_basebackup で 1 台以上の hot standby を追加し (レプリケーションユーザー、pg_hba、replication slot、非同期または同期 ANY/FIRST モード、遅延監視)、Patroni を使わないこのクラスタの運用 runbook を生成します: 計画 switchover、手動 failover (pg_promote)、旧 primary の pg_rewi","level":"中級","duration":"45〜90 分","topology":"1 primary + 1..N standby","tags":["postgresql","streaming replication","レプリケーション","standby","hot standby","pg_basebackup","replication slot","synchronous","同期レプリケーション","failover","switchover","pg_promote","pg_rewind","ha","cascading","delayed standby","recovery_min_apply_delay","slot 削除","pg_wal 満杯","synchronous_standby_names","standby 再構築"],"order":2,"steps":24,"scenarios":[{"k":"mode","v":"install","l":"構築: primary に standby を追加する","m":"standby の追加 / 再構築 ストリーミングレプリケーション 構築 standby 追加 hot standby pg_basebackup read replica 参照用レプリカ physical replication 物理レプリケーション standby.signal primary_conninfo 構築済みの primary に pg_basebackup で 1 台以上の hot standby を追加します (slot、同期/非同期、監視)。primary は稼働したままですが、初回コピーは primary にディスクとネットワークの負荷をかけます。"},{"k":"mode","v":"switchover","l":"計画 switchover (ロール切り替え、データ損失なし)","m":"ロール切り替え switchover planned switchover ロール切り替え 計画切り替え primary メンテナンス standby を primary にする pg_promote pg_ctl promote 計画メンテナンス: primary を正常停止し、最初の standby を昇格させ、旧 primary を standby として戻します。データ損失はなく、書き込み停止は通常 1 分未満です。"},{"k":"mode","v":"failover","l":"手動 failover (primary 障害、standby を昇格)","m":"ロール切り替え could not connect to the primary server Connection refused primary down primary 障害 primary 接続不可 failover manual failover promote standby pg_promote split-brain could not receive data from WAL stream primary サーバー喪失 primary が停止した、または到達できない場合: 旧 primary を隔離 (fencing) し、最新の standby を手動で昇格させます。非同期モードでは直近のトランザクションが失われる可能性があります。"},{"k":"mode","v":"rejoin","l":"旧 primary を pg_rewind で standby として再参加させる","m":"ロール切り替え requested timeline is not a child of this server's history target server must be shut down cleanly could not find previous WAL record pg_rewind diverged timeline 旧 primary 再参加 rejoin old primary failover 後、旧 primary を pg_rewind で新 primary に同期させ、standby として再参加させます。フルコピーよりはるかに高速です。"},{"k":"mode","v":"cascade","l":"standby から供給される新しい standby を追加する (カスケード)","m":"standby の追加 / 再構築 cascading replication cascade standby カスケードレプリケーション standby から standby 遠隔データセンター DR standby 新しい standby は WAL を primary ではなく最初の standby から受け取ります。遠隔データセンターや standby が多い構成で、primary のネットワーク/WAL 送信負荷を減らせます。primary には影響しません。"},{"k":"mode","v":"delayed","l":"遅延 (delayed) standby を構築する","m":"standby の追加 / 再構築 recovery_min_apply_delay delayed standby 遅延 standby 誤削除 DROP TABLE 取り消し accidental delete pg_wal_replay_pause WAL を数時間遅れで適用する standby (`recovery_min_apply_delay`): 誤って削除したデータをバックアップからリストアせずに復旧するためのものです。failover 候補ではありません。"},{"k":"mode","v":"rebuild","l":"standby をゼロから再構築する","m":"standby の追加 / 再構築 requested WAL segment has already been removed could not receive data from WAL stream database system identifier differs wal_status lost exceeds max_slot_wal_keep_size standby 再構築 standby 破損 re-clone standby could not start WAL streaming wal_removed standby 遅延 standby が大きく遅れた、必要な WAL が削除された、または破損した場合: データディレクトリを退避し、primary から再コピーします。primary には影響しません。"},{"k":"mode","v":"slotclean","l":"pg_wal が増え続けディスクが逼迫する (未使用 slot の削除)","m":"メンテナンスとトラブルシューティング No space left on device could not write to file \"pg_wal pg_wal 満杯 pg_wal 肥大化 WAL 肥大化 ディスクフル replication slot inactive max_slot_wal_keep_size pg_wal ディレクトリ 大きい WAL disk full WAL が溜まる原因 (非アクティブな slot、アーカイブ失敗、wal_keep_size) を特定し、未使用の replication slot を削除して WAL 領域を回収します。primary は稼働したままです。"},{"k":"mode","v":"syncchg","l":"同期 standby の追加 / 除外 (synchronous_standby_names)","m":"メンテナンスとトラブルシューティング canceling wait for synchronous replication synchronous_standby_names COMMIT 待機 commit hangs sync standby 同期 standby sync_state potential synchronous_commit フォームのモード (ANY/FIRST, k) に従って同期リストを書き直すか、非同期に戻します。reload で反映され、再起動は不要です。設定を誤るとコミットが待機したままになるため、先に確認します。"}]},{"id":"pg-patroni","file":"install/guides/pg-patroni.json","group":"PostgreSQL","engineId":"postgres","category":"ha","title":"Patroni + etcd + HAProxy による自動 failover クラスタ","summary":"自動 failover 対応の PostgreSQL クラスタを構築・運用します。各ノードの PostgreSQL は Patroni が管理し、leader 選出は 3（または 5）メンバーの etcd で行われます。アプリケーションは HAProxy の書き込み（5000）・読み取り（5001）ポートに、必要に応じて keepalived の VIP 経由で接続します。構築に加え、稼働中クラスタ向けの運用シナリオがあります。ヘルスチ","level":"上級","duration":"2～3 時間","topology":"PostgreSQL + etcd ノード 3 台（共用または別）+ HAProxy（+ VIP）","tags":["postgresql","patroni","etcd","haproxy","keepalived","vip","自動フェイルオーバー","auto failover","switchover","ha","high availability","cluster","クラスタ","patronictl","dcs","reinit","pg_rewind","edit-config","pause","resume","etcdctl member","quorum","failsafe","ノード追加","ノード削除","patroni upgrade","クラスタ停止"],"order":3,"steps":40,"scenarios":[{"k":"mode","v":"install","l":"構築: 新しい Patroni クラスタ","m":"構築 patroni 構築 patroni install etcd 構築 haproxy 自動フェイルオーバー automatic failover high availability 高可用性 HA クラスタ etcd + Patroni + HAProxy（+ VIP）クラスタをゼロから構築します。サーバーに PostgreSQL クラスタがあってはいけません。initdb は Patroni が実行します（pg-install は適用しません）。"},{"k":"mode","v":"ops","l":"運用 runbook: switchover、failover テスト、メンテナンスモード、パラメータ変更","m":"確認と訓練 failover テスト failover test 訓練 DR drill runbook 構築直後のクラスタで基本操作を順に試します。状態確認、switchover、failover テスト（leader を停止するため短時間の書き込み停止あり）、メンテナンスモード、パラメータ変更です。メンテナンスウィンドウ内で実施してください。"},{"k":"mode","v":"health","l":"クラスタは正常か（ヘルスチェック）","m":"確認と訓練 patronictl list Pending restart Maintenance mode: on start failed patroni health クラスタ状態 replica lag レプリケーション遅延 タイムライン不一致 読み取り専用: ロール、遅延、タイムライン、REST API、etcd の健全性、スロット、保留中の再起動、メンテナンスモード。"},{"k":"mode","v":"switchover","l":"計画 switchover（leader を別ノードへ移す）","m":"ロール変更 candidate name does not match with sync_standby Switchover failed does not exist in cluster or is tagged as nofailover switchover leader 変更 ロール切り替え 計画メンテナンス メンテナンス前に leader ロールを制御された形でレプリカへ移します。数秒の書き込み停止があり、データ損失はありません。"},{"k":"mode","v":"rejoin","l":"failover 後、旧 leader が再参加しない（pg_rewind / reinit）","m":"ロール変更 requested timeline is not a child of this server's history could not find previous WAL record pg_rewind: error target server needs to use either data checksums or wal_log_hints start failed diverged 旧 leader failover 後 pg_rewind: fatal could not find common ancestor timeline history mismatch クラッシュした旧 leader は起動するとレプリカとして参加するはずです。pg_rewind が失敗した場合は、データディレクトリを leader から再構築します。"},{"k":"mode","v":"reinit","l":"レプリカをゼロから再構築する（reinit）","m":"メンバーのメンテナンス requested WAL segment has already been removed could not receive data from WAL stream invalid record length invalid page patronictl reinit レプリカ破損 レプリカ遅延 rebuild replica replica start failed creating replica レプリカが破損している、大きく遅れている、または WAL を失った場合です。データディレクトリを削除し、leader（またはバックアップ）から再構築します。leader には影響しません。"},{"k":"mode","v":"addmember","l":"クラスタに新しいノードを追加する","m":"メンバーのメンテナンス ノード追加 add member 新規レプリカ scale out クラスタ拡張 新しいノードはフォームのリストの末尾に追加してください。ソフトウェアがインストールされ、既存ノードの pg_hba と HAProxy が更新され、レプリカとして参加します。"},{"k":"mode","v":"rmmember","l":"クラスタからノードを削除する","m":"メンバーのメンテナンス ノード削除 remove member decommission サーバー撤去 レプリカ削除 レプリカであるノードを恒久的に削除します。Patroni を停止し、DCS の登録とスロットを削除し、HAProxy から外します。"},{"k":"mode","v":"editcfg","l":"PostgreSQL または Patroni の設定を変更する（edit-config）","m":"設定とメンテナンス edit-config Pending restart postgresql.conf の設定が消えた ALTER SYSTEM パラメータ変更 max_connections shared_buffers change parameter work_mem パラメータが消えた 設定が反映されない 設定は DCS に書き込まれ、全ノードに適用されます。再起動が必要な設定は `restart --pending`（レプリカから先に）。"},{"k":"mode","v":"pause","l":"メンテナンスのため自動 failover を止める（pause / resume）","m":"設定とメンテナンス Maintenance mode: on patronictl pause patronictl resume maintenance mode メンテナンスモード 自動フェイルオーバー無効化 pause 中の Patroni は PostgreSQL に手を出さず、failover も行いません。ネットワーク・etcd のメンテナンスや手動作業に使います。作業が終わったら resume します。"},{"k":"mode","v":"upgrade","l":"Patroni ソフトウェアをアップグレードする（rolling）","m":"設定とメンテナンス patroni upgrade patroni 更新 patroni バージョン dnf update patroni apt upgrade patroni patroni 3 to 4 クラスタを pause にし、ノードごとに Patroni を更新して再起動します。PostgreSQL は停止せず、failover も起きません。"},{"k":"mode","v":"stopstart","l":"クラスタ全体を停止 / 起動する（正しい順序）","m":"設定とメンテナンス クラスタ停止 クラスタ起動 shutdown order 全停止 計画停止 データセンターメンテナンス 停電 計画的な全停止（ストレージ、データセンターのメンテナンス）: レプリカ、leader、最後に etcd の順に停止し、起動は逆順です。"},{"k":"mode","v":"etcdmember","l":"etcd メンバーを交換または追加する（etcdctl member）","m":"etcd（DCS） etcdserver: unhealthy cluster member has already been bootstrapped Peer URLs already exists member count is unequal etcdctl member etcd member add etcd member remove etcd メンバー unhealthy 故障した etcd メンバーを外して新しいサーバーを追加します（またはメンバー数を増やします）。Patroni の etcd ホストリストも更新します。"},{"k":"mode","v":"dcsloss","l":"etcd のクォーラム喪失: leader が読み取り専用になった","m":"etcd（DCS） Failed to get list of machines DCS is not accessible demoting self etcdserver: request timed out etcdserver: no leader cannot execute INSERT in a read-only transaction quorum failsafe etcd quorum lost leader 不在 no leader etcd のクォーラムがないと Patroni は leader を読み取り専用にし、failover も行われません。etcd を復旧するか、1 メンバーから再構築します。"}]},{"id":"pg-pgbouncer","file":"install/guides/pg-pgbouncer.json","group":"PostgreSQL","engineId":"postgres","category":"pooling","title":"PgBouncer 接続プール","summary":"PGDG リポジトリからの PgBouncer のインストール: transaction または session のプールモード、auth_query (SECURITY DEFINER 関数) または userlist.txt による scram-sha-256 認証、データベースの max_connections と CPU 数から算出したプールサイズ、systemd、オプションで so_reuseport によるマルチプロセス。最","level":"中級","duration":"30〜45 分","topology":"PgBouncer はデータベースサーバー上または別サーバー上。Patroni では HAProxy/VIP の前段","tags":["postgresql","pgbouncer","connection pool","接続プール","pooling","transaction pooling","auth_query","userlist","scram-sha-256","so_reuseport","max_client_conn","default_pool_size","patroni","haproxy","vip","フェイルオーバー"],"order":4,"steps":15,"scenarios":[]},{"id":"pg-pgbackrest","file":"install/guides/pg-pgbackrest.json","group":"PostgreSQL","engineId":"postgres","category":"backup","title":"pgBackRest によるバックアップと PITR","summary":"pgBackRest によるフル / 差分 / 増分バックアップ、継続的 WAL アーカイブ、ポイントインタイムリカバリ (PITR)。単一サーバー、ストリーミングレプリケーション (primary + standby) または Patroni クラスタに対応し、リポジトリは同じサーバー、別のバックアップサーバー (SSH)、S3 互換オブジェクトストレージのいずれにも置けます。暗号化、圧縮、保持ポリシー、cron/systemd によ","level":"中級","duration":"45～90 分","topology":"サーバー 1 台、primary + standby、または Patroni クラスタ。バックアップサーバーは任意","tags":["postgresql","pgbackrest","バックアップ","backup","restore","pitr","wal","archive","s3","minio","暗号化","retention","リカバリ","patroni","streaming","standby","cron","backup-standby","systemd timer","delta restore","db-include","target-action","restore point","xid","lsn","clone","クローン","障害復旧","disaster recovery","verify","expire","type=standby","リストア訓練"],"order":10,"steps":28,"scenarios":[{"k":"purpose","v":"kur","l":"pgBackRest のインストール + 初回バックアップ + テストリストア","m":"インストール stanza-create archive_command archive-push pgbackrest インストール pgbackrest install バックアップ設定 backup setup バックアップ計画 full diff incr 定期バックアップ ERROR: [087] archive_mode must be enabled WAL アーカイブ設定 初回バックアップ pgBackRest が未導入の場合: ソフトウェア、リポジトリ、WAL アーカイブ、初回バックアップ、スケジュール、テストリストア。"},{"k":"purpose","v":"geri","l":"障害時: インプレースリストア (最新状態または指定時刻まで)","m":"リストア (同じサーバー) recovery_target_time recovery_target_xid recovery_target_lsn pg_create_restore_point PITR point in time recovery ポイントインタイムリカバリ 誤って削除 DROP TABLE DELETE without WHERE UPDATE without WHERE TRUNCATE restore point restore to time データを元に戻す データベースをその場で、バックアップとアーカイブに含まれる任意の時点に戻します: 最新、時刻、xid、LSN、restore point のいずれか。クラスタは停止し、目標時点以降の変更は失われます。"},{"k":"purpose","v":"delta","l":"データディレクトリに破損または削除されたファイルがある (delta restore で修復)","m":"リストア (同じサーバー) invalid page in block could not read block page verification failed checksum verification failed could not open file \"base/ could not access status of transaction missing chunk number No such file or directory could not read file 破損ブロック data corruption block corruption 削除されたデータファイル ERROR:  could not read block PANIC:  could not open file PANIC:  could not read file \"global/pg_control"},{"k":"purpose","v":"dbinc","l":"1 つのデータベースだけを戻す (--db-include)","m":"リストア (同じサーバー) db-include DROP DATABASE 単一データベース single database restore データベース削除 テーブル復元 table restore 単一テーブルのリストア クラスタは稼働したままです: 対象データベースだけを一時インスタンス (別ディレクトリ・別ポート) にリストアし、pg_dump で取り出して本番サーバーに別名でロードします。削除された単一テーブルもこのカードで対応します (そこから `pg_dump -t`)。"},{"k":"purpose","v":"clone","l":"バックアップを別サーバーにリストアする (クローン / テスト / レポーティング)","m":"新サーバー: クローン、障害復旧、standby repo1-cipher-pass clone クローン テスト環境 テスト環境のリフレッシュ refresh test staging 新サーバーへのリストア レポーティングサーバー 暗号化リポジトリ 本番サーバーには触れません。バックアップを新しいサーバーに展開し、WAL アーカイブを無効にするため、クローンが本番のリポジトリに書き込むことはありません。暗号化リポジトリでは暗号鍵が必要です。"},{"k":"purpose","v":"dr","l":"サーバーを完全に喪失: バックアップを新サーバーに展開して置き換える","m":"新サーバー: クローン、障害復旧、standby PANIC: could not locate a valid checkpoint record 障害復旧 disaster recovery DR サーバー喪失 ディスク障害 server lost データディレクトリ消失 新しい primary 暗号化リポジトリ could not open file \"global/pg_control\" サーバーが起動しない PostgreSQL が起動しない ディスクまたはサーバーの喪失: 新サーバーをバックアップから起動して新しい primary にします。WAL アーカイブとバックアップは同じ stanza で継続します。旧サーバーは必ず停止したままにしてください。"},{"k":"purpose","v":"standby","l":"バックアップから新しい standby を構築する (--type=standby)","m":"新サーバー: クローン、障害復旧、standby type=standby standby 構築 レプリカ追加 バックアップから standby standby rebuild pg_basebackup の代わり add standby primary にコピー負荷をかけずに新しい standby を作成します: ファイルはバックアップから取得し、不足分の WAL はアーカイブとストリーミングで補います。primary は稼働したままです。"},{"k":"purpose","v":"verify","l":"バックアップは本当に健全か (info / check / verify とリストア訓練)","m":"確認と保守 ERROR: [082] ERROR: [028] ERROR: [056] pgbackrest verify pgbackrest check pgbackrest info バックアップ検証 backup verification restore test リストア訓練 最新バックアップはいつか verify command バックアップは健全か restore drill 月次検証 読み取り専用の確認と、本番サーバーに触れずに別ディレクトリで行うリストア訓練。月次の検証ジョブ (cron) も設定します。"},{"k":"purpose","v":"retention","l":"保持期間を変更して古いバックアップを削除する (expire)","m":"確認と保守 No space left on device WARN: option 'repo1-retention-full' is not set repo1-retention-full expire retention 保持 リポジトリ満杯 バックアップディスク満杯 古いバックアップ削除 リポジトリ容量不足 バケット満杯 バックアップディスクが満杯 repo1-retention-full/diff の設定を変更し、まず --dry-run で削除対象を表示してから expire を実行します。削除したバックアップは元に戻せません。"}]},{"id":"pg-pitr-basebackup","file":"install/guides/pg-pitr-basebackup.json","group":"PostgreSQL","engineId":"postgres","category":"backup","title":"pg_basebackup + WAL アーカイブによるバックアップと PITR (pgBackRest なし)","summary":"追加ツールをインストールせず、PostgreSQL 標準のツールで物理バックアップを行います: archive_command による継続的な WAL アーカイブ、pg_basebackup による夜間のベースバックアップ、pg_archivecleanup による保持管理。特定の時刻 / トランザクション / リストアポイントへのリカバリ (recovery.signal、restore_command、recovery_target","level":"中級","duration":"45〜90 分","topology":"サーバー 1 台。streaming または Patroni では、アーカイブディレクトリを全ノードで共有 (NFS)","tags":["postgresql","pg_basebackup","archive_command","restore_command","pitr","point in time recovery","recovery.signal","recovery_target_time","pg_archivecleanup","WAL アーカイブ","タイムライン","ベースバックアップ","バックアップ","リストア","pg_verifybackup","cron","リストア訓練"],"order":12,"steps":14,"scenarios":[{"k":"op","v":"kur","l":"WAL アーカイブと夜間のベースバックアップを構築する","m":"構築 archive_mode archive_command archive_timeout pg_stat_archiver wal_level WAL アーカイブ WAL archiving continuous archiving 継続的アーカイブ 設定 pg_basebackup cron ベースバックアップ 夜間バックアップ スケジュール nightly backup WAL アーカイブ 設定 初期構築: archive_command による継続的な WAL アーカイブ、pg_basebackup スクリプト、/etc/cron.d によるスケジュール、保持期間と WAL の削除。archive_mode のために一度だけ短い再起動が必要です。"},{"k":"op","v":"pitr","l":"特定の時点に戻す (PITR: 時刻、xid、LSN、リストアポイント)","m":"リストア recovery ended before configured recovery target was reached requested recovery stop point is before consistent recovery point PITR point in time recovery point in time recovery.signal restore_command recovery_target_time recovery_target_xid recovery_target_lsn recovery_target_name pg_create_restore_point DROP TABLE TRUNCATE 誤って削除 accidental delete 特定時点へのリカバリ サーバー消失 FATAL:  could not locate r"},{"k":"op","v":"drill","l":"リストア訓練 (別ディレクトリで、本番に触れずに)","m":"確認とメンテナンス backup successfully verified pg_verifybackup pg_amcheck restore test restore drill リストア訓練 バックアップ 検証 backup verify RTO バックアップ リストアできるか バックアップが実際にリストアできることを証明するため (月 1 回を推奨): 最新のベースバックアップを検証し (pg_verifybackup)、別のディレクトリに展開して、アーカイブを使い別のポートで起動します。所要時間 (RTO) を計測します。本番には触れません。"},{"k":"op","v":"cleanup","l":"古いベースバックアップと WAL アーカイブを削除する","m":"確認とメンテナンス No space left on device could not write to file archive command failed pg_archivecleanup アーカイブ ディスク 一杯 アーカイブ 満杯 disk full 古いバックアップ 削除 バックアップ 保持期間 retention pg_wal 肥大化 archive_status .ready アーカイブまたはバックアップのディスクが一杯になりつつある、または保持期間を変更した場合: 古いベースバックアップを削除し、pg_archivecleanup で最も古いバックアップより前の WAL を削除します (まずドライラン)。データベースは稼働したままです。"}]},{"id":"pg-logical-repl","file":"install/guides/pg-logical-repl.json","group":"PostgreSQL","engineId":"postgres","category":"ha","title":"PostgreSQL 論理レプリケーション (パブリケーション / サブスクリプション)","summary":"2 つの PostgreSQL クラスタ間のテーブル単位の論理レプリケーションです: wal_level=logical、レプリカアイデンティティの確認、パブリケーションとサブスクリプション、初期同期、監視、コンフリクトの対処、シーケンスの手動同期。バージョン間の移行 (メジャーアップグレード、サーバー移設) のために、ダウンタイムを数秒に抑える最終切り替え (cutover) の手順も含みます。","level":"上級","duration":"45〜90 分 (+ 初期コピーの時間)","topology":"2 台のサーバー: パブリッシャー (publisher) + サブスクライバー (subscriber)。パブリッシャーは単一サーバー、ストリーミングレプリケーション、Patroni クラスタのいずれでもよい","tags":["postgresql","logical replication","論理レプリケーション","publication","subscription","cdc","移行","migration","upgrade","conflict","replica identity","sequence","patroni","failover slot","permanent slots","sync_replication_slots"],"order":15,"steps":25,"scenarios":[{"k":"purpose","v":"sync","l":"継続的なレプリケーション (レポート、連携、部分コピー)","m":"logical replication publication subscription CREATE SUBSCRIPTION テーブルレプリケーション 部分レプリケーション 選択したテーブルを継続的に別のクラスタへ流します (レポート用サーバー、データウェアハウスへの供給、サービス間連携)。サブスクライバーは書き込み可能なままです。"},{"k":"purpose","v":"migrate","l":"移行: 新サーバー / 新メジャーバージョン + 最終切り替え (cutover)","m":"ゼロダウンタイム アップグレード near zero downtime cutover サーバー移行 logical upgrade 数秒のダウンタイムで新サーバーまたは新メジャーバージョンへ移行します: 初期コピーと継続的な同期の後、短時間書き込みを止めて最終切り替え (cutover) を行います。"}]},{"id":"pg-dump-restore","file":"install/guides/pg-dump-restore.json","group":"PostgreSQL","engineId":"postgres","category":"backup","title":"PostgreSQL の論理バックアップとリストア (pg_dump / pg_restore)","summary":"pg_dump、pg_dumpall、pg_restore を使い、テーブル、スキーマ、データベース、またはクラスタ全体の単位で論理バックアップとリストアを行います。構造のみ (DDL) またはデータのみ、別サーバー/別バージョンへの移行、ダンプからの単一テーブルのリストア、systemd/cron によるスケジュール実行・検証・保持期間付きのバックアップを扱います。どの手順も最後に行数を比較して検証します。streaming repl","level":"中級","duration":"20〜90 分 (データ量による)","topology":"サーバー 1 台、streaming replication (primary + standby)、または Patroni クラスタ。移行時は移行元 + 移行先、リモートからのスケジュールバックアップではさらにバックアップサーバー","tags":["postgresql","postgres","pg_dump","pg_restore","pg_dumpall","論理バックアップ","logical backup","エクスポート","インポート","ダンプ","restore","リストア","データベース移行","migration","アップグレード","globals","systemd timer","cron","pgpass","バックアップ","patroni","streaming replication","レプリカ","standby","haproxy","hot standby","pg_wrapper","cron.d","flock"],"order":15,"steps":9,"scenarios":[{"k":"mode","v":"tables","l":"単一テーブルのエクスポート / インポート","m":"エクスポート / インポート pg_dump -t テーブル エクスポート テーブル インポート table export 単一テーブル バックアップ no matching tables were found 選択したテーブルの構造とデータ (インデックス、制約、トリガーを含む) をダンプし、別のデータベースにロードします。"},{"k":"mode","v":"schema","l":"スキーマのエクスポート / インポート","m":"エクスポート / インポート pg_dump -n スキーマ エクスポート schema export no matching schemas were found スキーマ内のすべてのオブジェクト (テーブル、ビュー、関数、シーケンス) をダンプします。"},{"k":"mode","v":"db","l":"単一データベースのバックアップ / リストア","m":"エクスポート / インポート pg_dump pg_restore データベース ダンプ database backup database restore errors ignored on restore データベース全体 (構造 + データ) を 1 つのダンプに取得し、同じデータベースまたは別のデータベースにリストアします。ロール (globals) は含まれません。"},{"k":"mode","v":"cluster","l":"クラスタ全体 (ロール + テーブル空間 + 全データベース)","m":"エクスポート / インポート pg_dumpall pg_dumpall -g globals クラスタ全体 バックアップ ロール バックアップ pg_dumpall -g で globals を、データベースごとに個別の pg_dump を取得します。リストアは一時的なテストクラスタでリハーサルします。"},{"k":"mode","v":"ddl","l":"スキーマ構造のみ (DDL)","m":"構造とデータを分ける pg_dump -s --schema-only DDL エクスポート 構造のみ データを含まないテーブル、インデックス、ビュー、関数の定義。レビュー、バージョン管理、空の環境の構築に使います。"},{"k":"mode","v":"data","l":"データのみ","m":"構造とデータを分ける pg_dump -a --data-only データのみ --disable-triggers circular foreign-key constraints 移行先に構造がすでにある状態で、行 (COPY) だけを転送します。"},{"k":"mode","v":"migrate","l":"別サーバー / 別バージョンへの移行","m":"移行とリカバリ サーバー移行 migration dump restore upgrade aborting because of server version mismatch 新バージョンへ移行 移行先サーバーで新バージョンの pg_dump がネットワーク経由で移行元に接続し、パイプまたはファイルで転送します。"},{"k":"mode","v":"partial","l":"ダンプから単一テーブル / オブジェクトをリストアする","m":"移行とリカバリ 単一テーブル リストア pg_restore -L pg_restore --list DROP TABLE 削除したテーブル 削除した行 誤って削除 table restore 既存の custom/directory 形式のダンプから、リストファイル (-L) を使って 1 つのテーブルとそのインデックス、制約、データだけをリストアします。"},{"k":"mode","v":"sched","l":"スケジュールバックアップ (systemd timer / cron)","m":"スケジュールバックアップ pg_dump cron systemd timer 自動バックアップ scheduled backup 日次バックアップ バックアップ 保持期間 毎日の globals + データベースのバックアップ、読み取り可能性の検証、保持期間、ログ、失敗通知。"}]},{"id":"pg-minor-update","file":"install/guides/pg-minor-update.json","group":"PostgreSQL","engineId":"postgres","category":"patch","title":"PostgreSQL マイナー・バージョンの更新（パッチ）","summary":"同じメジャー・バージョン内でのマイナー・アップデート（例: 17.4 → 17.x）の手順です。リリースノートの確認、バックアップ、ロールバック用に現在の RPM/deb パッケージを保存する作業を含みます。単一サーバーでは短時間の停止で行います。ストリーミング・レプリケーション構成のクラスタでは、まずスタンバイを更新し、その後 switchover によりプライマリを更新します（rolling）。Patroni クラスタでは、repl","level":"中級","duration":"20–60 分","topology":"サーバー 1 台、プライマリ + スタンバイ、または Patroni クラスタ","tags":["postgresql","minor","patch","マイナー・アップデート","update","upgrade","rolling","switchover","dnf","apt","ダウングレード","ロールバック","拡張機能","patroni","patronictl","failover"],"order":20,"steps":17,"scenarios":[{"k":"purpose","v":"upd","l":"マイナー・アップデート","m":"minor update マイナー・バージョン 更新 patch CVE セキュリティ・アップデート dnf upgrade postgresql apt upgrade postgresql 同じメジャー・バージョン内で新しいマイナー・バージョンに移行します（例: 17.4 → 17.6）。セキュリティ修正とバグ修正です。単一サーバーでは短時間の停止、クラスタでは rolling で行います。"},{"k":"purpose","v":"rb","l":"ロールバック: 以前のマイナー・バージョンに戻す（ダウングレード）","m":"ダウングレード ロールバック ロールバック 以前のバージョンに戻す undefined symbol 新しいマイナー・バージョンで不具合やリグレッションが見つかった場合、保存しておいた旧バージョンの RPM/deb で元に戻します。データ・ディレクトリは変わりません。"}]},{"id":"pg-major-upgrade","file":"install/guides/pg-major-upgrade.json","group":"PostgreSQL","engineId":"postgres","category":"upgrade","title":"PostgreSQL メジャーアップグレード (pg_upgrade / ロジカルレプリケーション)","summary":"メジャーバージョンのアップグレード (例: 16 → 17): 方式の選択 (pg_upgrade --link / --copy / --clone、またはロジカルレプリケーションによるほぼ無停止の移行)、pg_upgrade --check、拡張機能の互換性、設定の移行、統計情報の再収集、rsync または pg_basebackup によるスタンバイの再構築、旧クラスタの削除、切り戻し手順書。シングルサーバ、ストリーミングレプリケ","level":"上級","duration":"1〜3 時間 (+ データ量に依存)","topology":"同一サーバでのインプレース (pg_upgrade。シングルサーバ、プライマリ + スタンバイ、または Patroni クラスタ) または新サーバへ (ロジカル)","tags":["postgresql","メジャー","upgrade","バージョンアップ","pg_upgrade","pg_upgradecluster","link","clone","ロジカルレプリケーション","移行","マイグレーション","rsync","切り戻し","patroni","patronictl remove","レプリカ","ストリーミングレプリケーション"],"order":30,"steps":24,"scenarios":[{"k":"purpose","v":"upg","l":"メジャーアップグレード","m":"メジャーアップグレード pg_upgrade pg_upgradecluster バージョンアップ メジャーバージョン postgresql 17 アップグレード postgresql 18 アップグレード メジャーバージョンのアップグレード (例: 16 → 17): 事前チェック、バックアップ、pg_upgrade またはロジカルレプリケーション、検証、後片付け。"},{"k":"purpose","v":"rb","l":"切り戻し (アップグレード失敗 / 中止)","m":"アップグレード 切り戻し 切り戻し pg_control.old database files are incompatible with server アップグレード 失敗 アップグレードが途中で止まった、または新バージョンで問題が発生した: 旧バージョンに戻します。--link で新クラスタを起動済みの場合、戻せるのはバックアップからのみです。"}]},{"id":"pg-security","file":"install/guides/pg-security.json","group":"PostgreSQL","engineId":"postgres","category":"security","title":"PostgreSQL セキュリティ強化 (状態監査、ネットワーク、TLS、認証、権限、監査ログ、暗号化)","summary":"インストールガイドではありません。稼働中の PostgreSQL サーバーのセキュリティ上の不備を見つけて塞ぎます。まず読み取り専用の 状態監査 が検出事項を重大度順に一覧し、各検出事項がどのカードにつながるかを示します。その後、各領域を一つずつ、または全部を順番に対処します: リッスンアドレス、ファイアウォールと pg_hba、TLS とクライアント側の sslmode=verify-full、scram-sha-256 と post","level":"中級","duration":"5 分 (監査) – 3 時間 (完全な強化)","topology":"単一の PostgreSQL サーバー + アプリケーションサーバー (クライアント側の検証)。レプリカ/Patroni 環境は注記で扱います","tags":["postgresql","postgres","セキュリティ","security","hardening","セキュリティ強化","cis benchmark","pg_hba","tls","ssl","sslmode","verify-full","scram-sha-256","md5","pgaudit","audit","監査","public schema","権限","ロール","luks","pgcrypto","暗号化","encryption","firewall"],"order":40,"steps":3,"scenarios":[{"k":"scenario","v":"scan","l":"状態監査: どこに不備があるか (読み取り専用)","m":"ここから開始 セキュリティ監査 security audit hardening check CIS セキュリティ上の不備 脆弱性 vulnerability ペネトレーションテスト 指摘事項 監査レポート 監査クエリ CIS チェック セキュリティスキャン security scan 最初に実行するスキャンです。pg_hba、リッスンアドレス、TLS、md5 パスワード、スーパーユーザー、PUBLIC 権限、監査ログ、ファイル権限、ファイアウォールを確認し、何も変更しません。"},{"k":"scenario","v":"all","l":"完全な強化 (全領域を順番に)","m":"ここから開始 hardening セキュリティ強化 全面的なセキュリティ対策 full hardening CIS benchmark 適用 STIG 新規構築、または一度も強化していないサーバー: 全領域を安全な順序で適用します。PostgreSQL を 1〜2 回再起動します (メンテナンスウィンドウが必要です)。"},{"k":"scenario","v":"net","l":"ネットワークと接続: 誰がどこから接続できるか (listen、ファイアウォール、pg_hba)","m":"ネットワークと認証 pg_hba.conf 0.0.0.0/0 trust listen_addresses firewall no pg_hba.conf entry pg_hba.conf rejects connection ポート 5432 開放 FATAL: no pg_hba.conf entry for host 28000 Connection refused listen_addresses = * host all all 0.0.0.0/0 外部からのアクセス アクセス制限 PostgreSQL が全インターフェースでリッスンしている、pg_hba に 0.0.0.0/0 や trust がある、ポートが誰にでも開いている。listen_addresses を変更すると再起動が必要です。"},{"k":"scenario","v":"tls","l":"接続を暗号化する (TLS、sslmode=verify-full)","m":"ネットワークと認証 ssl tls sslmode verify-full hostssl certificate verify failed SSL off no encryption server.crt 証明書 期限切れ certificate expired SSL error: certificate verify failed does not match host name root certificate file does not exist server does not support SSL, but SSL was required self-signed certificate 証明書チェーン certificate chain hostnossl ssl = off、またはクライアントが証明書を検証していない。サーバー証明書、hostssl、クライアント側の "},{"k":"scenario","v":"auth","l":"認証とパスワード (scram-sha-256、postgres のリモートログイン)","m":"ネットワークと認証 md5 scram-sha-256 password_encryption password authentication failed authentication method 10 not supported postgres リモートログイン パスワードポリシー password policy 28P01 FATAL: password authentication failed for user SCRAM authentication requires libpq version 10 or above pass-the-hash VALID UNTIL パスワード 有効期限 md5/password 方式、md5 ハッシュのパスワード、postgres ユーザーがネットワーク経由でログインできる状態。scram-sha-256 への移行と個人用 DBA ア"},{"k":"scenario","v":"priv","l":"最小権限: ロール、PUBLIC、アプリケーションアカウント","m":"権限と監査証跡 public schema PUBLIC GRANT REVOKE superuser least privilege 最小権限 permission denied for schema ロール設計 DEFAULT PRIVILEGES 42501 permission denied for table must be owner of table pg_read_server_files pg_execute_server_program SECURITY DEFINER REASSIGN OWNED 権限レポート アプリケーションアカウントがテーブルの所有者またはスーパーユーザーで、public スキーマに誰でも書き込める。読み取り/書き込み/所有者ロールと権限レポート。停止はありません。"},{"k":"scenario","v":"audit","l":"監査: 誰が何をしたか (pgaudit、集中ログ)","m":"権限と監査証跡 pgaudit audit 監査証跡 audit log AUDIT: SESSION log_connections syslog SIEM 個人情報保護法 (APPI) PCI shared_preload_libraries could not access file \"pgaudit\" pgaudit must be loaded via shared_preload_libraries log_statement 誰が何をしたか who changed 監査人やセキュリティチームが DDL とロール変更の記録を求めている。pgaudit の導入とログの集中サーバーへの転送。再起動が 1 回必要です。"},{"k":"scenario","v":"tde","l":"保存データを暗号化する (LUKS / pgcrypto)","m":"データとバックアップ TDE transparent data encryption ディスク暗号化 encryption at rest LUKS dm-crypt pgcrypto pg_tde cryptsetup luksFormat pgp_sym_encrypt at-rest encryption ディスクやバックアップの盗難に対する保護が求められている。PostgreSQL には組み込みの TDE はありません: ディスクレベルの LUKS (移行時に停止あり) か、列レベルの pgcrypto です。"},{"k":"scenario","v":"backup","l":"バックアップのセキュリティ (暗号化バックアップ、権限)","m":"データとバックアップ バックアップ暗号化 backup encryption repo-cipher-type pgbackrest cipher gpg .pgpass バックアップ 権限 cipher: none repo-cipher-pass 暗号化されていないバックアップ unencrypted backup バックアップファイルが暗号化されていない、または誰でも読めるディレクトリにある。pgBackRest のリポジトリ暗号化または pg_dump + GPG、.pgpass とディレクトリ権限。停止はありません。"},{"k":"scenario","v":"os","l":"OS 側 (サービスアカウント、権限、コアダンプ、SELinux)","m":"サーバーとバージョン SELinux permissive chmod 700 data directory has invalid permissions core dump postgres アカウント sudo avc: denied LimitCORE core dumped passwd -l postgres アカウントに使用可能なパスワードがある、データディレクトリの権限が緩い、SELinux が Permissive/Disabled。コアダンプの設定は次回の再起動で有効になります。"},{"k":"scenario","v":"patch","l":"パッチとバージョン: サポート対象のバージョンか","m":"サーバーとバージョン EOL end of life サポート終了 マイナーバージョン CVE セキュリティパッチ security release out of support server_version パッチ計画 minor update pgsql-announce バージョン、サポート終了日、未適用のマイナーアップデートを確認します。適用はパッチガイドにつながります。読み取り専用です。"}]},{"id":"mysql-install","file":"install/guides/mysql-install.json","group":"MySQL","engineId":"mysql","category":"install","title":"MySQL シングルサーバーのインストール (本番対応)","summary":"MySQL 8.4 LTS (または 8.0) のサーバー 1 台を公式リポジトリからゼロから本番対応でインストールします。データ、binlog、ログ用の個別ディレクトリ、RAM/CPU/ディスク種別から算出した my.cnf、GTID と binlog の保持期間、スロークエリログ、SELinux/AppArmor、root アクセスの制限、アプリケーションユーザーまでを扱います。最終的に、検証済みで最初のバックアップも取得済みのイン","level":"初級","duration":"30–45 分","topology":"サーバー 1 台","tags":["mysql","インストール","install","8.4","lts","innodb","my.cnf","チューニング","gtid","binlog","rhel","ubuntu"],"order":1,"steps":24,"scenarios":[]},{"id":"mysql-replication","file":"install/guides/mysql-replication.json","group":"MySQL","engineId":"mysql","category":"ha","title":"MySQL GTID レプリケーション (非同期 / 準同期)","summary":"インストール済みの MySQL サーバーで、1 ソース + N レプリカの GTID ベースのレプリケーションを構築します。レプリケーションユーザー、clone プラグインまたは mysqldump による既存データの転送、SOURCE_AUTO_POSITION、TLS、任意の準同期 (semi-sync)、super_read_only のレプリカ、遅延の監視、手動フェイルオーバー手順を扱います。最終的に、書き込みをソースで、読み取","level":"中級","duration":"45–90 分","topology":"ソース 1 台 + レプリカ 1..5 台","tags":["mysql","レプリケーション","replication","gtid","semi-sync","準同期レプリケーション","レプリカ","ソース","クローン","フェイルオーバー","read_only"],"order":2,"steps":21,"scenarios":[]},{"id":"mysql-innodb-cluster","file":"install/guides/mysql-innodb-cluster.json","group":"MySQL","engineId":"mysql","category":"ha","title":"MySQL InnoDB Cluster (Group Replication + MySQL Router)","summary":"同一データセンター内のインストール済み MySQL サーバー 3 台 (または 5–9 台) から single-primary の InnoDB Cluster を構築します。MySQL Shell AdminAPI による dba.configureInstance、createCluster、clone を使った addInstance、MySQL Router の bootstrap (6446 RW / 6447 RO)、cl","level":"上級","duration":"90–120 分","topology":"MySQL ノード 3–9 台 + Router サーバー 1 台","tags":["mysql","innodb cluster","グループレプリケーション","mysql shell","mysqlsh","adminapi","mysql router","高可用性","フェイルオーバー","クォーラム","クローン","シングルプライマリ"],"order":3,"steps":39,"scenarios":[]},{"id":"mysql-xtrabackup","file":"install/guides/mysql-xtrabackup.json","group":"MySQL","engineId":"mysql","category":"backup","title":"Percona XtraBackup によるバックアップ、リストア、PITR","summary":"Percona XtraBackup による物理バックアップです。対応する XtraBackup バージョンのインストール、auth_socket を使うバックアップユーザー、圧縮/暗号化付きのフル + 増分バックアップスクリプト、systemd timer または cron によるスケジュール、binlog のコピー、リストア訓練までを扱います。シナリオカードでは、フルリストア、増分チェーンからのリストア、特定時点への復旧 (PITR","level":"中級","duration":"45–90 分","topology":"サーバー 1 台 (単体サーバー、source、replica、InnoDB Cluster の secondary のいずれか)。バックアップ領域はローカルディスクまたは NFS","tags":["mysql","xtrabackup","percona","バックアップ","backup","restore","incremental","pitr","binlog","復旧","zstd","暗号化","replica","slave-info","safe-slave-backup","innodb cluster","cron","systemd timer","flock"],"order":4,"steps":26,"scenarios":[{"k":"scenario","v":"setup","l":"バックアップを構築し、スケジュールし、リストアを試す (全手順)","m":"構築と訓練 xtrabackup インストール バックアップスクリプト backup script systemd timer cron リストア訓練 xtrabackup バックアップ 物理バックアップ physical backup hot backup incremental backup full backup percona-xtrabackup XtraBackup のインストール、バックアップユーザー、フル + 増分バックアップスクリプト、スケジュール、リストア訓練 (PITR を含む)。初めて構築する場合はこれを選びます。バックアップはサーバー稼働中に取得します。ダウンタイムはなく、ディスク/CPU 負荷が増えるだけです。"},{"k":"scenario","v":"r_full","l":"フルリストア: 最新のフルバックアップに戻す","m":"リストア restore リストアする copy-back datadir 消失 InnoDB: corruption MY-011971 MY-012592 Database page corruption mysqld が起動しない full restore ERROR 2002 Can't connect to local MySQL server through socket MY-012574 Unable to lock ./ibdata1 datadir 削除 ディスク障害 disk failure データ消失 データディレクトリが失われた/破損した、またはサーバーが起動しない場合です。チェーンのフルバックアップに戻せば十分です。リストアの間、MySQL は停止しています。"},{"k":"scenario","v":"r_inc","l":"フル + 増分チェーンからのリストア (最新の増分まで)","m":"リストア incremental restore apply-log-only incremental-dir to_lsn from_lsn This incremental backup seems not to be proper for the target 増分チェーン incremental chain xtrabackup_checkpoints applying incremental 最新の増分バックアップ (または任意の増分) の時点に戻したい場合です。フルバックアップの上に増分を `--apply-log-only` で順番に適用します。リストアの間、MySQL は停止しています。"},{"k":"scenario","v":"r_pitr","l":"特定時点への復旧 (PITR): 誤った DELETE / DROP の直前へ","m":"時点復旧 PITR point in time 誤って削除 DROP TABLE 誤った DELETE TRUNCATE mysqlbinlog stop-datetime stop-position exclude-gtids binlog replay 誤った UPDATE WHERE なしの DELETE accidental delete accidental drop DROP DATABASE 元に戻す undo delete binlog による復旧 誤って削除または破損したデータの復旧です。最新のバックアップをリストアし、binlog を問題のトランザクションの直前まで (時刻、位置、GTID のいずれかで) 適用します。リストアの間 MySQL は停止し、問題発生後の書き込みもすべて失われます。影響が 1 テーブルだけなら、先に単一テーブルのシナリオを検討してください。"},{"k":"scenario","v":"r_table","l":"単一テーブルをリストアする (--export + IMPORT TABLESPACE)","m":"時点復旧 単一テーブル single table restore IMPORT TABLESPACE DISCARD TABLESPACE transportable tablespace --export .cfg ERROR 1808 ERROR 1812 Schema mismatch ERROR 1813 Tablespace exists ERROR 1146 Table doesn't exist tablespace is missing 1 テーブルだけ戻す table restore ibd ファイル 1 つのテーブルのバックアップ時点の内容だけが必要な場合です。サーバー全体をリストアせず、テーブルをバックアップから `t_restore` という名前でインポートし、そこからデータを修正します。サーバーは稼働したままです。"},{"k":"scenario","v":"r_replica","l":"バックアップから新しいレプリカを構築する","m":"移行とクローン 新規レプリカ レプリカ構築 xtrabackup_binlog_info xtrabackup_slave_info gtid_purged slave-info replication from backup 1236 バックアップからレプリカを構築 seed replica Could not find first log file name in binary log index file purged required binary logs 1236 レプリカ再構築 新しい (または再構築する) レプリカを、ネットワーク経由の clone ではなく既存の XtraBackup バックアップから準備し、source に接続したい場合です (大容量データ、source の負荷)。source には影響しません。ターゲットサーバーのデータは置き換えられます。"},{"k":"scenario","v":"r_other","l":"バックアップを別サーバーにリストアする (移行、テスト、クローン)","m":"移行とクローン 別サーバー テストサーバー restore test 移行 migration クローン clone to test rsync server_uuid テスト環境にロード バックアップ検証 restore drill バックアップを開く サーバー移行 本番バックアップをテスト/開発サーバーで開く、サーバーを移行する、あるいはバックアップが本当にリストアできるかを別サーバーで確認したい場合です。ソースサーバーには影響しません。"}]},{"id":"mysql-upgrade","file":"install/guides/mysql-upgrade.json","group":"MySQL","engineId":"mysql","category":"upgrade","title":"MySQL 8.0 → 8.4 LTS アップグレード (in-place)","summary":"インストール済みの MySQL 8.0 を同じサーバー上で (in-place) 8.4 LTS にアップグレードします: 単一サーバー、source + レプリカ (先にレプリカ、最後に source)、または InnoDB Cluster (Router → Shell → メタデータ → secondary を 1 台ずつ → 最後に primary)。各サーバーでの util.checkForServerUpgrade による事","level":"中級","duration":"60～120 分 (データサイズによる)","topology":"サーバー 1 台、source + レプリカ、または InnoDB Cluster (3 台以上のメンバー + MySQL Router サーバー)","tags":["mysql","upgrade","8.0","8.4","lts","アップグレード","checkForServerUpgrade","mysql_native_password","authentication_policy","rollback","切り戻し","innodb cluster","group replication","mysql router","upgradeMetadata","setPrimaryInstance","rolling upgrade"],"order":5,"steps":18,"scenarios":[]},{"id":"mysql-repl-ops","file":"install/guides/mysql-repl-ops.json","group":"MySQL","engineId":"mysql","category":"ops","title":"MySQL レプリケーションの日常運用と障害シナリオ (8.0 / 8.4)","summary":"構築済みの source + replica トポロジー (async / semi-sync、GTID またはバイナリログポジション) の日常運用と障害復旧の runbook です。ヘルスチェックと遅延確認、計画 switchover、failover、旧 source の再参加、replica の再構築 (clone / XtraBackup / mysqldump)、errant GTID、1062/1032 エラー、遅延 rep","level":"上級","duration":"5 分 (確認) – 2 時間 (再構築)","topology":"1 source + 1..5 replica (async / semi-sync)","tags":["mysql","レプリケーション","replication","gtid","errant gtid","errant transaction","switchover","failover","replica","source","super_read_only","semi-sync","show replica status","seconds_behind_source","レプリケーション遅延","lag","1062","1032","1236","duplicate entry","can't find record","gtid_next","sql_replica_skip_counter","source_delay","遅延レプリカ","delayed replica","clone","xtrabackup","mysqldump","purge binary logs","binlog_expire_logs_seconds","wait_for_executed_gtid_set","change replication source to","runbook","8.0","8.4"],"order":12,"steps":5,"scenarios":[{"k":"scenario","v":"health","l":"状態と遅延の確認 (レプリケーションは正常か)","m":"監視と確認 SHOW REPLICA STATUS SHOW SLAVE STATUS Seconds_Behind_Source Seconds_Behind_Master Replica_IO_Running Slave_IO_Running Replica_SQL_Running: No レプリケーション遅延 replication lag replica lag Rpl_semi_sync_source_status 1045 2003 2026 Error connecting to source レプリケーション状態 Replica_IO_Running: No Replica_IO_Running: Connecting Slave_IO_Running: No Slave_SQL_Running: No Seconds_Behind_Source: NULL Last_IO"},{"k":"scenario","v":"switchover","l":"計画 switchover (source ロールを replica に引き継ぐ)","m":"ロール変更 switchover 計画切り替え ロール変更 role change promote replica ソース 変更 メンテナンス 計画メンテナンス graceful takeover graceful-master-takeover ソース 入れ替え プライマリ 変更 change primary 新ソース source と replica は正常で、メンテナンス、ハードウェア交換、アップグレードのために source ロールを計画的に replica へ引き継ぎます。書き込みは数分間止まりますが、データ損失はありません。切り戻しは同じシナリオを逆方向に実行します。"},{"k":"scenario","v":"failover","l":"source 喪失: 最も進んだ replica へ failover する","m":"ロール変更 failover ソース クラッシュ source down master down primary down Error connecting to source Can't connect to MySQL server 2003 2013 Lost connection 最も進んだレプリカ most advanced replica Replica_IO_Running: Connecting Slave_IO_Running: Connecting 2005 Unknown MySQL server host error reconnecting to source ソース 到達不能 ソース 停止 プライマリ クラッシュ サーバー クラッシュ server crashed source がクラッシュしたか到達不能で、すぐには復帰しません (replica 側の IO ス"},{"k":"scenario","v":"rejoin","l":"failover 後に旧 source を replica として再参加させる","m":"ロール変更 旧ソース old source old master rejoin 再参加 errant split brain 1236 旧プライマリ old primary 旧マスター 復帰 split-brain Replica has more GTIDs than the source has Slave has more GTIDs than the master has 再参加 reintegrate failover が完了し、旧 source サーバーが復帰しました。まず書き込みを禁止してバイナリログをコピーし、errant transaction を確認します。問題がなければそのまま replica にし、あれば新しい source から再構築します。新しい source の停止はありません。"},{"k":"scenario","v":"rebuild","l":"replica をゼロから再構築する (clone / XtraBackup / mysqldump)","m":"リカバリ 1236 Cannot replicate because the source purged required binary logs purged required binary logs 再構築 rebuild replica reseed clone instance 新規レプリカ データ不整合 data drift Could not find first log file name in binary log index file the source has purged binary logs containing GTIDs that the replica requires the master has purged binary logs containing GTIDs that the slave requires Got fatal error 123"},{"k":"scenario","v":"errant","l":"Errant GTID: source にないトランザクションが replica にある","m":"リカバリ errant gtid errant transaction gtid_subtract extra gtid 余分な gtid Having extra GTID events incompatible GTID set 1236 GTID_SUBTRACT gtid_executed 差分 レプリカへの書き込み write on replica super_read_only 無効 Replica has more GTIDs than the source has replica に直接書き込まれた (super_read_only が無効だった間) トランザクション、または旧 source から残ったトランザクションがあります。failover 時にこれらのトランザクションが他の replica に伝播するか、1236 でレプリケーションが停止します。対処は、空のトランザ"},{"k":"scenario","v":"sqlerr","l":"レプリケーション停止: 1062 Duplicate entry / 1032 Can't find record","m":"リカバリ 1062 1032 1452 1146 1007 1008 Duplicate entry Can't find record HA_ERR_KEY_NOT_FOUND HA_ERR_FOUND_DUPP_KEY Could not execute Write_rows event Could not execute Update_rows event Could not execute Delete_rows event Replica_SQL_Running: No Slave_SQL_Running: No Coordinator stopped because there were error(s) in the worker(s) sql_slave_skip_counter sql_replica_skip_counter gtid_next MY-010584 10"},{"k":"scenario","v":"delayed","l":"遅延 replica (SOURCE_DELAY): 設定する、または削除されたデータを復旧する","m":"日常運用 SOURCE_DELAY MASTER_DELAY delayed replica 遅延レプリカ 誤削除 DROP TABLE 誤った DELETE SQL_Delay SQL_BEFORE_GTIDS SQL_Remaining_Delay 誤って DELETE WHERE なし DELETE accidental delete accidental drop dropped table テーブル 削除 データ復旧 UNTIL SQL_BEFORE_GTIDS replica を意図的に N 秒遅らせておく (遅延の設定 / 解除)、または誤って削除・変更されたデータ (DROP、WHERE なしの DELETE/UPDATE) を、遅延 replica に適用される前にそこから取り戻す場合です。source は稼働したままです。"},{"k":"scenario","v":"repoint","l":"replica を別の source に移す (チェーン / 接続先変更)","m":"日常運用 repoint change source チェーンレプリケーション chained replication intermediate 中間レプリカ relay replica CHANGE MASTER TO CHANGE REPLICATION SOURCE TO cascading replication カスケードレプリケーション レプリカ 接続先変更 SOURCE_HOST 変更 MASTER_HOST 変更 log_replica_updates replica を別の replica の配下 (チェーン / 中間 replica) に付け替える、または source に戻す場合です。データはコピーせず、接続先だけを変えます。移動する replica は数秒間停止します。"},{"k":"scenario","v":"binlog","l":"バイナリログの削除と保持期間 (ディスクが逼迫)","m":"日常運用 PURGE BINARY LOGS PURGE MASTER LOGS binlog_expire_logs_seconds expire_logs_days binlog ディスクフル No space left on device errno 28 binlog 削除 binlog retention Disk is full writing OS errno 28 1867 was not purged because it was being read 1373 Target log not found in binlog index binlog 増加 binlog_expire_logs_auto_purge binlog_transaction_compression バイナリログがディスクを圧迫している、または保持期間を設定したい場合です。replica と PI"}]},{"id":"mysql-ic-ops","file":"install/guides/mysql-ic-ops.json","group":"MySQL","engineId":"mysql","category":"ops","title":"MySQL InnoDB Cluster の日常運用と障害シナリオ (MySQL Shell 8.4)","summary":"構築手順ではありません。すでに稼働している InnoDB Cluster (Group Replication + MySQL Router、MySQL Shell AdminAPI で構築) の日常運用と障害復旧のための、シナリオ別ランブックです。シナリオ・カードを選択してください: ヘルスチェック、メンバーの追加 (clone / incremental) と削除 (force を含む)、障害メンバーの再参加、クラスタ全体停止後の再","level":"上級","duration":"5 分 (確認) – 1 時間 (メンバー追加)","topology":"MySQL ノード 3–9 台 (single-primary) + MySQL Router","tags":["mysql","innodb cluster","group replication","mysql shell","mysqlsh","adminapi","cluster.status","addinstance","removeinstance","rejoininstance","rebootclusterfromcompleteoutage","forcequorumusingpartitionof","setprimaryinstance","setoption","setinstanceoption","rescan","mysql router","bootstrap","quorum","no_quorum","スプリットブレイン","expelTimeout","memberWeight","autoRejoinTries","exitStateAction","consistency","clone","MISSING","UNREACHABLE","RECOVERING","ERROR","ランブック","8.4"],"order":13,"steps":5,"scenarios":[{"k":"scenario","v":"health","l":"クラスタ状態とヘルスチェック (すべて正常か)","m":"監視と確認 cluster.status status() OK_PARTIAL OK_NO_TOLERANCE OK_NO_TOLERANCE_PARTIAL instanceErrors replicationLag flow control RECOVERING applier queue クラスタ状態 Cluster is ONLINE and can tolerate can tolerate up to ONE failure ヘルスチェック health check キューが増加 replication_group_members group_replication_member_stats クラスタの状態確認 読取り専用: `cluster.status({extended: 1})`、メンバーのロール/状態/バージョン、適用キュー、Router 一覧、エラーログを確認しま"},{"k":"scenario","v":"add","l":"新しいメンバーを追加する (addInstance: clone / incremental)","m":"メンバー addInstance メンバー追加 ノード追加 add instance recoveryMethod clone incremental 3092 Having extra GTID events MYSQLSH 51166 The target instance must be either cloned or fully provisioned Clone Donor Error 容量拡張 耐障害性向上 OK_NO_TOLERANCE クラスタに新しい MySQL ノードを追加したい、耐障害性を上げたい (3 → 5)、または削除したノードを戻したい場合です。クラスタは書込み可能なままですが、clone 中はドナーにディスク/ネットワーク負荷がかかり、新しいノードは再起動します。"},{"k":"scenario","v":"remove","l":"メンバーを削除する (removeInstance、必要なら force)","m":"メンバー removeInstance メンバー削除 ノード削除 remove instance force MISSING decommission Cluster.removeInstance is not reachable and cannot be safely removed ノード撤去 縮小 サーバー撤去 ノードをクラスタから恒久的に外したい (ハードウェア返却、縮小) 場合、またはノードが失われてメタデータから削除する必要がある (`force`) 場合です。セカンダリの削除では停止は発生しません。プライマリを削除すると数秒間の書込み停止が発生します。"},{"k":"scenario","v":"rejoin","l":"障害メンバーを再参加させる (MISSING / ERROR / OFFLINE)","m":"障害と復旧 rejoinInstance MISSING ERROR OFFLINE UNREACHABLE expelled グループから除外 member was expelled MY-011735 MY-011526 incompatible GTID set (MISSING) This member has more executed transactions than those present in the group has an incompatible GTID set with the seed instance Error connecting to all peers Member join failed group_replication is stopped メンバー停止 メンバー OFFLINE member expelled auto-rejoin メン"},{"k":"scenario","v":"reboot","l":"クラスタ全体が停止した: 再起動する (rebootClusterFromCompleteOutage)","m":"障害と復旧 rebootClusterFromCompleteOutage complete outage 完全停止 全ノード停止 停電 Group Replication is not active OFFLINE Unable to find a cluster PRIMARY member The cluster is offline Dba.rebootClusterFromCompleteOutage Dba.getCluster: This function is not available through a session to a standalone instance metadata exists, instance belongs to that metadata, but GR is not active group_replication_bootstrap_g"},{"k":"scenario","v":"quorum","l":"過半数喪失 (NO_QUORUM): 残ったメンバーで強制的にクォーラムを構成する","m":"障害と復旧 NO_QUORUM forceQuorumUsingPartitionOf quorum 過半数喪失 split-brain スプリットブレイン UNREACHABLE majority partition 3100 Cluster has no quorum cannot process write transactions split-brain! Instance is not part of the majority group 書込みが止まる writes hang forceQuorum メンバーの過半数が同時に失われ (例: 3 台中 2 台)、残ったメンバーが `NO_QUORUM` により書込みを停止した場合です (書込みはハングします)。失われたメンバーが確実に停止していることを確認できれば、残ったパーティションでクラスタを再稼働させます。誤用するとスプリッ"},{"k":"scenario","v":"switch","l":"計画的なプライマリ切替え (setPrimaryInstance)","m":"ロールとルーティング setPrimaryInstance プライマリ変更 switchover プライマリ移譲 The appointed primary member has a version that is greater group_replication_set_as_primary Cluster.setPrimaryInstance runningTransactionsTimeout 計画的プライマリ切替え プライマリ移動 planned switchover メンテナンス (OS パッチ、ハードウェア)、負荷分散、DR 訓練のために、プライマリ・ロールを特定のセカンダリへ計画的に移したい場合です。書込みは数秒間待機し、実行中のトランザクションは完了まで待たれます。Router は新しいプライマリへ自動的にルーティングします。"},{"k":"scenario","v":"router","l":"Router を追加する、または再 bootstrap する","m":"ロールとルーティング mysqlrouter MySQL Router bootstrap --force routerErrors re-bootstrap Router listRouters removeRouterMetadata 6446 6447 previously configured in this host Unable to connect to the metadata server Unable to fetch all configuration options The provided server is currently not in a InnoDB cluster group with quorum mysqlrouter.service failed Router が接続できない Router のインストール 新しいアプリケーション・サーバーに Ro"},{"k":"scenario","v":"options","l":"クラスタ・オプションを変更する (consistency、expelTimeout、memberWeight…)","m":"構成 setOption setInstanceOption consistency BEFORE_ON_PRIMARY_FAILOVER expelTimeout group_replication_member_expel_timeout memberWeight autoRejoinTries exitStateAction OFFLINE_MODE READ_ONLY options() group_replication_consistency group_replication_member_weight group_replication_autorejoin_tries group_replication_exit_state_action メンバーが頻繁に除外される フェイルオーバー優先度 フェイルオーバー時の整合性、ネットワークが不安定な際にメンバーが除外されるまでの時"},{"k":"scenario","v":"rescan","l":"メタデータを実際のグループと同期する (rescan)","m":"構成 rescan metadata is not managed not registered in the metadata newlyDiscoveredInstances unavailableInstances instanceErrors obsolete Use cluster.rescan() Instance is not managed by InnoDB cluster Use cluster.rescan() to repair メタデータ不整合 メタデータのずれ `cluster.status()` が、メタデータにないメンバー、またはもうグループにない古いエントリに言及している場合です (手動で `START GROUP_REPLICATION` を実行した、古いメンバーを削除していない、サーバーを再構築した など)。停止は発生せず、メタデータのみが更新されます"}]},{"id":"mysql-logical-backup","file":"install/guides/mysql-logical-backup.json","group":"MySQL","engineId":"mysql","category":"backup","title":"MySQL の論理バックアップとリストア (mysqldump、MySQL Shell)","summary":"mysqldump または MySQL Shell (util.dumpInstance / dumpSchemas / dumpTables + util.loadDump) による論理バックアップとリストアを扱います。テーブル、スキーマ、インスタンス全体、構造のみまたはデータのみ、別サーバーへの移行、フルダンプからの単一テーブルの抽出、systemd/cron によるスケジュール実行で login-path によるパスワードなし接続","level":"中級","duration":"20〜90 分 (データ量による)","topology":"サーバー 1 台 (移行とインスタンスのリストアではターゲットサーバーを追加)","tags":["mysql","mysqldump","mysql shell","mysqlsh","dumpInstance","dumpSchemas","dumpTables","loadDump","論理バックアップ","logical backup","export","import","リストア","restore","移行","migration","login-path","mysql_config_editor","systemd timer","cron","バックアップ","レプリカ","dump-replica","source-data","innodb cluster","cron","systemd timer","flock","login-path"],"order":15,"steps":8,"scenarios":[{"k":"mode","v":"table","l":"テーブルのエクスポート / インポート","m":"バックアップとリストア テーブル バックアップ table export テーブル コピー copy table mysqldump テーブル 1 つまたは複数のテーブルをバックアップする、別のスキーマ/サーバーにコピーする、またはリストアする場合です。ソースは稼働したままで、InnoDB テーブルではロックを取得しません。"},{"k":"mode","v":"schema","l":"スキーマ (データベース) をバックアップ / リストアする","m":"バックアップとリストア スキーマ バックアップ データベース バックアップ database backup dumpSchemas mysqldump database データベース (スキーマ) 全体をバックアップする、または別のスキーマ/サーバーにロードする場合です。ソースは稼働したままです。ターゲットで同名のテーブルは削除されて再作成されます。"},{"k":"mode","v":"instance","l":"インスタンス全体 (ユーザー + 全スキーマ)","m":"バックアップとリストア 全データベース all databases dumpInstance ユーザー 移行 full logical backup バックアップはこのサーバーで取得し、リストアは空のサーバーで行います。ユーザー、権限、全スキーマが対象です。サーバーの再構築や、バージョン/プラットフォームの変更に使います。"},{"k":"mode","v":"ddl","l":"構造のみ (DDL)","m":"構造とデータを分離 構造のみ schema only no-data ddlOnly CREATE TABLE export テーブル、ビュー、トリガー、プロシージャ、イベントの定義のみで、データは含みません。スキーマの比較、空の環境の構築、構造のバージョン管理に使います。"},{"k":"mode","v":"data","l":"データのみ","m":"構造とデータを分離 データのみ data only no-create-info dataOnly データ転送 ターゲットに構造が用意されている状態で行だけを転送します (例: テストデータの更新)。ロード中にターゲットのトリガーが動作する可能性があり、ガイドではこれを確認します。"},{"k":"mode","v":"migrate","l":"別サーバーへの移行","m":"移行 移行 migration サーバー 移行 新サーバー 移行 8.0 to 8.4 migration dump and load HeatWave 移行 ターゲットサーバーで作業し、ソースにはネットワーク経由で login-path を使って接続します。切り替え時にアプリケーションの書き込みを止め、停止時間はダンプ + ロードの所要時間になります。サーバー、OS、バージョンの変更に使います。"},{"k":"mode","v":"extract","l":"フルダンプから単一テーブルを抽出","m":"復旧 単一テーブル リストア ダンプ テーブル 抽出 extract table from dump DROP TABLE 復旧 削除された行 ERROR 1146 Table doesn't exist フルダンプがあり、1 つのテーブルだけが必要な場合です (削除された行、DROP されたテーブル)。元のスキーマには触れずに別のスキーマへ抽出するか、削除されたテーブルを元に戻します。"},{"k":"mode","v":"sched","l":"スケジュールバックアップ (systemd timer / cron)","m":"スケジュールバックアップ スケジュール バックアップ scheduled backup cron mysqldump systemd timer 自動バックアップ 夜間バックアップ 毎日決まった時刻に自動で論理バックアップを取得します。専用のバックアップユーザー、login-path、スクリプト、systemd timer または cron、保存期間、エラー通知を構成します。ソースは稼働したままです。"}]},{"id":"mysql-security","file":"install/guides/mysql-security.json","group":"MySQL","engineId":"mysql","category":"security","title":"MySQL セキュリティ強化（状態診断、ネットワーク、TLS、認証、権限、監査、暗号化）","summary":"インストールガイドではありません。稼働中の MySQL 8.4 / 8.0 サーバーのセキュリティ上の弱点を見つけて塞ぎます。まず読み取り専用の 状態診断 が検出事項を重要度順に一覧し、各検出事項がどのカードにつながるかを示します。その後、各領域を個別に、またはすべてを順番に対処します。対象は bind_address、firewall とアカウントのホスト制限、TLS・require_secure_transport・クライアント側の","level":"中級","duration":"5 分（診断）～3 時間（全面的な強化）","topology":"単一の MySQL サーバー + アプリケーションサーバー（クライアント側の検証）。レプリカ / InnoDB Cluster は注記を参照","tags":["mysql","セキュリティ","security","hardening","セキュリティ強化","cis benchmark","tls","ssl","require_secure_transport","verify_identity","caching_sha2_password","mysql_native_password","validate_password","audit_log","監査","percona","tde","keyring","innodb 暗号化","root","匿名ユーザー","権限","ロール","login-path"],"order":40,"steps":2,"scenarios":[{"k":"scenario","v":"scan","l":"状態診断：どこに弱点があるか（読み取り専用）","m":"はじめに セキュリティ診断 security audit hardening check CIS セキュリティホール 脆弱性 vulnerability ペネトレーションテスト 指摘事項 mysql_secure_installation 監査クエリ セキュリティスキャン security scan 重大 最初に実行するスキャンです。匿名・パスワードなし・リモート root のアカウント、任意の場所（%）からのアクセス、弱い認証プラグイン、グローバル権限、TLS、監査、暗号化、ファイル権限、firewall を確認します。何も変更しません。"},{"k":"scenario","v":"all","l":"全面的な強化（すべてを順番に）","m":"はじめに hardening セキュリティ強化 セキュリティ全面対応 full hardening CIS benchmark 適用 STIG 新規構築直後、または一度も強化していないサーバー向けです。すべての領域を安全な順序で適用します。MySQL を数回再起動するため、メンテナンスウィンドウが必要です。"},{"k":"scenario","v":"net","l":"ネットワークと接続：誰がどこから接続できるか（bind_address、firewall、ホスト制限）","m":"ネットワークと認証 bind_address 0.0.0.0 '%' host '%' firewall 3306 33060 Host is not allowed to connect ERROR 1130 ERROR 2003 Can't connect to MySQL server skip_name_resolve 外部からのアクセス アクセス制限 MySQL がすべてのインターフェースで待ち受けており、アカウントのホストが '%'、ポートが誰にでも開いている状態です。bind_address を変更すると再起動が必要です。"},{"k":"scenario","v":"tls","l":"接続を暗号化する（TLS、require_secure_transport、VERIFY_IDENTITY）","m":"ネットワークと認証 ssl tls require_secure_transport ssl-mode VERIFY_IDENTITY VERIFY_CA ERROR 3159 Connections using insecure transport are prohibited server-cert.pem 証明書 有効期限 ERROR 2026 SSL connection error certificate verify failed ERROR 3888 証明書チェーン certificate chain 自動生成された自己署名証明書を使っている、暗号化されていない接続を受け付けている、またはクライアントが証明書を検証していない状態です。ALTER INSTANCE RELOAD TLS により無停止で対応できます。"},{"k":"scenario","v":"auth","l":"認証とパスワード（caching_sha2、パスワードポリシー、root）","m":"ネットワークと認証 mysql_native_password caching_sha2_password validate_password password_history FAILED_LOGIN_ATTEMPTS リモート root anonymous user 匿名ユーザー ERROR 1045 Access denied Plugin 'mysql_native_password' is not loaded ERROR 1524 ERROR 1819 ERROR 3955 ERROR 3118 Account is locked ERROR 2061 Authentication requires secure connection auth_socket mysql_native_password のアカウント、パスワードポリシーなし、リモート root、匿名アカウント、t"},{"k":"scenario","v":"priv","l":"最小権限：ロールと DDL 権限のないアプリケーションアカウント","m":"権限と監査証跡 GRANT REVOKE ALL PRIVILEGES SUPER FILE least privilege 最小権限 CREATE ROLE ERROR 1142 command denied ERROR 3530 ERROR 1227 you need (at least one of) the SUPER privilege DEFAULT ROLE 権限レポート アプリケーションアカウントに CREATE/ALTER/DROP や *.* の権限がある、FILE/SUPER 権限を持つアカウントがある状態です。読み取り / 書き込み / DDL のロールと権限レポートを作成します。無停止で対応できます。"},{"k":"scenario","v":"audit","l":"監査：誰が何をしたか","m":"権限と監査証跡 監査 audit_log audit_log_filter 監査証跡 general_log Enterprise Audit Percona audit SIEM 個人情報保護法 (APPI) PCI audit_log_filter_set_filter ERROR 1126 MySQL Enterprise ライセンス 誰が何をしたか 監査担当者がセッションとクエリの記録を求めています。MySQL Community には組み込みの監査機能がありません。選択肢は Enterprise Audit、Percona Server の Audit Log Filter、または Community 向けの限定的な方法です。**ライセンス:** Enterprise Audit は MySQL Enterprise サブスクリプションでのみ提供されます。Percona の Au"},{"k":"scenario","v":"tde","l":"保存データを暗号化する（InnoDB テーブルスペース暗号化、keyring）","m":"データとバックアップ TDE encryption at rest ENCRYPTION='Y' keyring component_keyring_file ERROR 3185 Can't find master key from keyring binlog_encryption innodb_redo_log_encrypt ALTER INSTANCE ROTATE INNODB MASTER KEY mysqld.my keyring_component_status マスターキー ディスクやバックアップコピーの盗難に備えて、テーブル、redo、undo、binlog を暗号化します。keyring コンポーネントの導入に再起動が 1 回必要で、大きなテーブルでは ALTER に時間がかかります。Community でもライセンス不要です。暗号化 keyring / KMS k"},{"k":"scenario","v":"backup","l":"バックアップのセキュリティ（暗号化バックアップ、login-path、権限）","m":"データとバックアップ バックアップ暗号化 backup encryption mysqldump gpg xtrabackup --encrypt login-path mysql_config_editor .my.cnf パスワード xbcrypt --encrypt-key-file 暗号化されていないバックアップ unencrypted backup バックアップが暗号化されていない、または誰でも読めるディレクトリにある、スクリプトに平文パスワードがある状態です。mysqldump + GPG または XtraBackup --encrypt、バックアップ用アカウントと login-path で対処します。"},{"k":"scenario","v":"os","l":"オペレーティングシステム側（サービスアカウント、権限、コアダンプ、SELinux）","m":"サーバーとバージョン SELinux permissive secure_file_priv local_infile コアダンプ mysql アカウント .mysql_history ERROR 1290 secure-file-priv option ERROR 3948 Loading local data is disabled avc: denied データディレクトリや証明書ファイルが他ユーザーに開いている、secure_file_priv が空、local_infile が有効、SELinux が無効の状態です。一部の設定は再起動後に有効になります。"},{"k":"scenario","v":"patch","l":"パッチとバージョン：サポート対象のバージョンか","m":"サーバーとバージョン EOL end of life サポート終了 MySQL 8.0 EOL CPU Critical Patch Update CVE セキュリティパッチ パッチ適用計画 MySQL 8.0 end of life 8.4 LTS バージョン、サポート終了日（8.0 は 2026 年 4 月に終了）、未適用の更新を確認します。適用はアップグレードガイドで行います。読み取り専用です。"}]},{"id":"mssql-linux-install","file":"install/guides/mssql-linux-install.json","group":"SQL Server","engineId":"mssql","category":"install","title":"SQL Server Linux インストール (RHEL / Ubuntu、本番対応)","summary":"1 台の Linux サーバー (RHEL 系または Ubuntu) に Microsoft リポジトリから SQL Server 2022 または 2025 をインストールします。エディションの選択、sa パスワードの安全な受け渡し、mssql-tools18 (sqlcmd/bcp)、データ/ログ/tempdb/バックアップ用の個別ディレクトリ、メモリと CPU から算出したメモリ上限・max server memory・MAXDO","level":"初級","duration":"40–60 分","topology":"サーバー 1 台","tags":["sql server","mssql","linux","インストール","install","mssql-conf","sqlcmd","tempdb","maxdop","rhel","ubuntu","2022","2025"],"order":1,"steps":22,"scenarios":[]},{"id":"mssql-windows-install","file":"install/guides/mssql-windows-install.json","group":"SQL Server","engineId":"mssql","category":"install","title":"SQL Server 2022 の Windows へのインストール (無人インストール、本番対応)","summary":"1 台の Windows Server に SQL Server 2022 を ConfigurationFile.ini で無人 (unattended) インストールします。INI は選択内容から生成されます (機能、インスタンス、サービスアカウント/gMSA、照合順序、データ/ログ/tempdb/バックアップの各ディレクトリ、tempdb のファイル数、メモリ、MAXDOP、TCP)。インストール前にディスクのフォーマット、電源プ","level":"中級","duration":"45～75 分","topology":"Windows Server 1 台","tags":["sql server","mssql","windows","インストール","install","無人インストール","configurationfile.ini","setup.exe","gmsa","tempdb","maxdop","ifi","lock pages in memory","2022"],"order":2,"steps":18,"scenarios":[]},{"id":"mssql-ag-windows","file":"install/guides/mssql-ag-windows.json","group":"SQL Server","engineId":"mssql","category":"ha","title":"SQL Server Always On 可用性グループ (Windows, WSFC)","summary":"SQL Server 2022 をインストールした Windows サーバーで Always On 可用性グループを構築します。Windows Server フェールオーバー クラスター (WSFC) とクォーラム監視 (file share / cloud witness)、Always On の有効化、ミラーリング エンドポイントと権限、自動シード処理による AG、リスナー、同期/非同期レプリカ、読み取り可能なセカンダリ、フェールオ","level":"上級","duration":"90–150 分","topology":"Windows ノード 2–9 台 (WSFC) + 監視 (witness)","tags":["sql server","mssql","always on","可用性グループ","ag","wsfc","フェールオーバー クラスター","リスナー","クォーラム監視","自動シード処理","hadr","windows","高可用性"],"order":3,"steps":25,"scenarios":[]},{"id":"mssql-ag-linux","file":"install/guides/mssql-ag-linux.json","group":"SQL Server","engineId":"mssql","category":"ha","title":"SQL Server Always On 可用性グループ (Linux、Pacemaker)","summary":"SQL Server 2022 をインストールした 3 台の Linux サーバー (RHEL 9 または Ubuntu 22.04) で、Pacemaker が管理する Always On AG を構築します: mssql-server-ha、hadr.hadrenabled、証明書で認証するデータベースミラーリングエンドポイント、CLUSTER_TYPE = EXTERNAL の AG (同期レプリカ 3 つ、または同期 2 つ +","level":"上級","duration":"120〜180 分","topology":"Linux ノード 3 台: 同期レプリカ 3 つ、または同期 2 つ + configuration-only レプリカ","tags":["sql server","mssql","always on","可用性グループ","ag","linux","pacemaker","corosync","pcs","stonith","フェンシング","mssql-server-ha","ocf:mssql:ag","cluster_type external","configuration only","リスナー","仮想 ip","rhel","ubuntu","高可用性"],"order":4,"steps":30,"scenarios":[]},{"id":"mssql-cu-patch","file":"install/guides/mssql-cu-patch.json","group":"SQL Server","engineId":"mssql","category":"patch","title":"SQL Server 累積更新プログラム (CU) の適用","summary":"インストール済みの SQL Server 2022/2025 インスタンスに、同じメジャーバージョン内の累積更新プログラム (CU) を適用します: Linux では dnf/apt で、Windows では CU のセットアップファイルによるサイレント (/quiet) インストールで行います。単一サーバー、または Always On AG での rolling 適用 (先に secondary、failover、その後に旧 prim","level":"中級","duration":"30～90 分","topology":"サーバー 1 台、または AG (レプリカ 2 台以上)","tags":["sql server","mssql","cu","累積更新プログラム","パッチ","更新","rolling","可用性グループ","always on","yum","apt","kb"],"order":4,"steps":12,"scenarios":[]},{"id":"mssql-ag-ops","file":"install/guides/mssql-ag-ops.json","group":"SQL Server","engineId":"mssql","category":"ops","title":"SQL Server Always On AG の運用 (Windows と Linux)","summary":"インストール手順ではありません。構築済み の Always On 可用性グループ (AG) の日常運用と障害シナリオです: ヘルスチェック、遅延とログ増大の診断、計画的フェールオーバー、強制フェールオーバー (FORCE_FAILOVER_ALLOW_DATA_LOSS) とその後の作業、データ移動の中断/再開、同期/非同期モード、データベースの追加 (自動シード処理またはバックアップ/リストア)、レプリカの追加/削除、読み取り専用ルー","level":"上級","duration":"15–90 分 (シナリオによる)","topology":"レプリカ 2–9 台の AG (Windows WSFC または Linux Pacemaker)","tags":["sql server","mssql","always on","availability group","ag","failover","forced failover","force_failover_allow_data_loss","suspend","resume","automatic seeding","read-only routing","listener","pacemaker","pcs","wsfc","secondary lag","log_send_queue","redo_queue","required_synchronized_secondaries_to_commit"],"order":5,"steps":3,"scenarios":[{"k":"op","v":"health","l":"AG ヘルスチェック (ダッシュボードのクエリ)","m":"監視と診断 NOT SYNCHRONIZING NOT_HEALTHY DISCONNECTED RESOLVING PARTIALLY_HEALTHY AG の正常性 availability group health sys.dm_hadr dashboard レプリカの状態 Msg 35206 connection timeout AG dashboard Show Dashboard すべて正常かを確認します。レプリカ / データベースの状態、フェールオーバーの準備状況、クラスター、直近のロール変更。何も変更しません。"},{"k":"op","v":"lag","l":"セカンダリが遅れる / ログファイルが増大する (遅延の診断)","m":"監視と診断 AVAILABILITY_REPLICA log_reuse_wait log_send_queue redo_queue HADR_SYNC_COMMIT secondary lag secondary_lag_seconds Msg 9002 9002 transaction log is full 遅延 redo blocked ログ増大 send/redo キューが増えている、セカンダリのデータが古い、プライマリのログがいっぱいになりかけている (log_reuse_wait = AVAILABILITY_REPLICA)、またはコミットが遅い (HADR_SYNC_COMMIT) 場合。"},{"k":"op","v":"failover","l":"計画的フェールオーバー (switchover、データ損失なし)","m":"ロール変更 planned failover manual failover switchover ALTER AVAILABILITY GROUP FAILOVER pcs resource move Msg 41142 41142 Msg 19407 ロール変更 プライマリ移動 Failover Cluster Manager Move メンテナンス フェールオーバー メンテナンス、パッチ適用、テストのために、プライマリを同期コミットかつ SYNCHRONIZED のセカンダリに移します。数秒のダウンタイムがあり、データ損失はありません。"},{"k":"op","v":"forced","l":"プライマリ喪失: 強制フェールオーバー (FORCE_FAILOVER_ALLOW_DATA_LOSS)","m":"ロール変更 FORCE_FAILOVER_ALLOW_DATA_LOSS forced failover 強制フェールオーバー quorum lost クォーラム喪失 FixQuorum forcequorum disaster recovery DR Msg 41131 Msg 35250 サイト喪失 primary down Msg 47104 ForceQuorum Cluster is running in ForceQuorum state RESOLVING_NORMAL プライマリ障害 データ損失 プライマリ (またはサイト全体 / クラスターのクォーラム) が失われ、復旧を待てない場合です。データ損失を受け入れてセカンダリをプライマリにし、その後データを比較して他のレプリカを再開します。"},{"k":"op","v":"suspend","l":"データ移動を中断 / 再開する (SUSPEND / RESUME)","m":"メンテナンス SUSPENDED SET HADR SUSPEND SET HADR RESUME is_suspended suspend_reason data movement データ移動の中断 Msg 35264 35264 Msg 35265 SUSPEND_FROM_REDO SUSPEND_FROM_USER SUSPEND_FROM_PARTNER 停止中 データベース中断 セカンダリへのデータ送信を一時的に止める (ネットワークメンテナンス、一括処理)、または中断状態 (SUSPENDED) のまま止まっているデータベースを再開します。"},{"k":"op","v":"mode","l":"同期 / 非同期モードを変更する","m":"メンテナンス SYNCHRONOUS_COMMIT ASYNCHRONOUS_COMMIT availability mode REQUIRED_SYNCHRONIZED_SECONDARIES_TO_COMMIT required_synchronized_secondaries_to_commit 同期コミット 非同期コミット Msg 35211 35211 Msg 35212 35212 FAILOVER_MODE レプリカを SYNCHRONOUS_COMMIT ↔ ASYNCHRONOUS_COMMIT に切り替え (リモートサイト、低速ネットワーク、DR 訓練)、コミット保護 (REQUIRED_SYNCHRONIZED_SECONDARIES_TO_COMMIT) を設定します。"},{"k":"op","v":"adddb","l":"AG にデータベースを追加する (自動シード処理またはバックアップ/リストア)","m":"変更 ADD DATABASE automatic seeding SET HADR AVAILABILITY GROUP Msg 35250 Msg 1478 1478 seeding failed データベース追加 Msg 1475 1475 might contain bulk logged changes manual seeding 新規または既存のデータベースを AG に追加します。小〜中規模のデータベースは自動シード処理、大規模なデータベースや低速ネットワークではバックアップから行います。"},{"k":"op","v":"addrep","l":"レプリカ (ノード) を追加する","m":"変更 ADD REPLICA Add-ClusterNode pcs cluster node add 新しいレプリカ レプリカ追加 Msg 41158 41158 Failed to join local availability replica JOIN AG に新しいセカンダリを追加します。ノードをクラスターに参加させ、エンドポイントを準備し、ADD REPLICA + JOIN を行い、データベースはシード処理で取り込みます。"},{"k":"op","v":"removerep","l":"レプリカ (ノード) を削除する","m":"変更 REMOVE REPLICA Remove-ClusterNode pcs cluster node remove レプリカ削除 decommission Msg 35223 35223 ノード削除 恒久的に廃止する、または再構築するセカンダリを AG とクラスターから削除します。"},{"k":"op","v":"routing","l":"読み取り専用ルーティング (read-only routing)","m":"接続 read-only routing READ_ONLY_ROUTING_URL READ_ONLY_ROUTING_LIST ApplicationIntent=ReadOnly readable secondary 読み取り可能セカンダリ Msg 978 978 Msg 976 976 not accessible for queries Msg 10786 ApplicationIntent ApplicationIntent=ReadOnly の接続を、リスナー経由で読み取り可能セカンダリにルーティングします (レポート負荷をプライマリから外す)。"},{"k":"op","v":"listener","l":"リスナーを作成または変更する (IP、ポート)","m":"接続 listener ADD LISTENER MODIFY LISTENER MultiSubnetFailover RegisterAllProvidersIP Msg 19471 19471 Msg 41009 virtualip Msg 19456 19456 HostRecordTTL リスナー ポート DNS レコード リスナーがなければ作成し、ポートを変更し、または (Windows) 2 つ目のサブネット用に IP を追加します。"}]},{"id":"mssql-backup","file":"install/guides/mssql-backup.json","group":"SQL Server","engineId":"mssql","category":"backup","title":"SQL Server のバックアップ戦略、自動化と復元","summary":"インストール済みの SQL Server インスタンス (Linux または Windows、単一インスタンス、FCI または AG レプリカ) のバックアップを構成し、バックアップから復旧します。バックアップ: 復旧モデルの選択、週次の完全 + 日次の差分 + n 分ごとのログ バックアップ、COMPRESSION、CHECKSUM、証明書による暗号化、保持期間とスケジュール (SQL Server エージェントの T-SQL ジョブ","level":"中級","duration":"30～90 分","topology":"1 台のサーバー、フェールオーバー クラスター インスタンスまたは Always On AG レプリカ (別サーバーへの復元: 移行元 + 移行先)","tags":["sql server","mssql","backup","バックアップ","バックアップ取得","restore","復元","pitr","stopat","point in time","differential","transaction log","copy_only","compression","checksum","encryption","バックアップ暗号化","sql server agent","job","ola hallengren","maintenance solution","retention","verifyonly","headeronly","filelistonly","norecovery","standby","with move","task scheduler","cron","availability group","always on","backup preference","automated_backup_preference","fn_hadr_backup_is_preferred_replica","copy_only","sql agent","sysjobhistory","cron","task scheduler","page restore","suspect_pages","824","823","33111","18456","orphaned user","sp_help_revlogin","master restore","single user","msdb restore","model restore","stopatmark","tail-log","no_truncate","recovery_pending","suspect","log chain","lsn"],"order":15,"steps":11,"scenarios":[{"k":"mode","v":"strategy","l":"バックアップ戦略を構成する (スケジュール バックアップ + 保持期間)","m":"バックアップ バックアップ計画 backup strategy ログ ファイルが肥大化 LOG_BACKUP Msg 9002 transaction log is full sql agent job Msg 3013 3013 BACKUP DATABASE is terminating abnormally バックアップが取得されない バックアップ ジョブ 新しいサーバー、または定期バックアップのないデータベース: 完全 / 差分 / ログのジョブ、保持期間、監視を構成します。"},{"k":"mode","v":"oneoff","l":"単発のバックアップを取得する (例: 変更前の COPY_ONLY)","m":"バックアップ copy_only 単発バックアップ 変更前バックアップ 手動バックアップ Msg 4214 4214 Msg 4208 4208 BACKUP LOG is not allowed while the recovery model is SIMPLE 変更、パッチ適用、アップグレードの前、またはテスト環境へのコピー用の単発バックアップです。COPY_ONLY はチェーンを壊しません。"},{"k":"mode","v":"verify","l":"バックアップを検証する (履歴、VERIFYONLY、テスト復元)","m":"リハーサルと確認 VERIFYONLY HEADERONLY FILELISTONLY テスト復元 バックアップ 破損 確認 Msg 3241 Msg 3183 Msg 3203 バックアップが実際に復元できることを証明します: バックアップ履歴、VERIFYONLY、HEADERONLY / FILELISTONLY、一時データベースへのテスト復元 + CHECKDB。"},{"k":"mode","v":"chain","l":"バックアップ チェーンは健全か (LSN の欠落、ファイルの欠落)","m":"リハーサルと確認 Msg 4305 4305 too recent to apply LSN log chain チェーン 切断 broken log chain Msg 3136 last_log_backup_lsn バックアップ チェーン 復元の前、または定期監査として: msdb の履歴からチェーンを再構成し、LSN の欠落、ディスク上に存在しないファイル、途中に割り込んだバックアップを検出します。何も変更しません。"},{"k":"mode","v":"restore","l":"データベースをバックアップから復元する (チェーン、STOPAT / STOPATMARK、MOVE / REPLACE、別サーバー)","m":"復元と特定時点への復旧 STOPAT STOPATMARK STOPBEFOREMARK point in time PITR 誤って削除 DELETE 取り消し WITH MOVE REPLACE tail-log Msg 3154 Msg 3159 Msg 5133 Msg 1834 Msg 3156 The tail of the log for the database Msg 3101 3101 Exclusive access could not be obtained Msg 4335 4335 RESTORE DATABASE データが削除された、または誤って更新された、データベースのコピーが必要、あるいは別サーバーへ移行する。インスタンスは稼働中です。完全 + 差分 + ログ チェーン、特定の時点またはマークされたトランザクション、別の名前 / ディレクトリ、tail-l"},{"k":"mode","v":"damaged","l":"データベースが開かない: データ ファイルの喪失または破損 (tail-log + 復元)","m":"喪失 / 破損 Msg 945 945 RECOVERY_PENDING recovery pending SUSPECT Msg 5120 5120 Msg 17204 Msg 17207 Msg 5181 FCB::Open failed Operating system error 2 mdf 削除 データ ファイル 喪失 database cannot be opened Msg 823 NO_TRUNCATE CONTINUE_AFTER_ERROR EMERGENCY データベースが RECOVERY_PENDING または SUSPECT で、.mdf/.ndf を読み取れないがインスタンスは稼働中: まず NO_TRUNCATE で tail-log バックアップを取得し、その後直前の時点まで復元します。作業が終わるまでデータベースは使用できません。"},{"k":"mode","v":"page","l":"一部のページが破損 (Msg 823 / 824): ページ復元","m":"喪失 / 破損 Msg 824 824 Msg 823 823 Msg 829 829 suspect_pages torn page incorrect checksum 破損ページ page corruption page restore CHECKDB found Msg 8928 Msg 8939 Msg 8976 repair_allow_data_loss クエリまたは CHECKDB が特定のページでエラーになる (msdb.dbo.suspect_pages): 破損したページだけをバックアップから復元します。Enterprise/Developer ではデータベースはオンラインのまま、Standard/Express では短時間オフラインになります。"},{"k":"mode","v":"master","l":"master データベースを復元する (シングル ユーザー モード)","m":"システム データベース master Msg 3108 3108 single user mode single-user シングル ユーザー モード -m Msg 3417 3417 Msg 17113 Msg 18461 master 破損 force-setup REBUILDDATABASE master の破損、またはログイン / リンク サーバー / サーバー設定の喪失: インスタンスをシングル ユーザー モード (-m) で起動して master を復元すると、SQL Server は自動的に停止します。ダウンタイムが必要です。インスタンスがまったく起動しない場合は、先にシステム データベースを再構築します。"},{"k":"mode","v":"sysdb","l":"msdb または model データベースを復元する","m":"システム データベース msdb model Msg 3168 3168 ジョブ 消えた msdb suspect Msg 1807 msdb 破損 model 破損 ジョブ、バックアップ履歴、データベース メール (msdb)、または新規データベースのテンプレート (model) が破損 / 喪失: 同じビルドで取得したバックアップから REPLACE で復元します。エージェントは短時間停止します。"},{"k":"mode","v":"orphan","l":"復元後にユーザーが接続できない (orphaned user、ログインのマッピング)","m":"移行とアクセス Msg 18456 18456 Login failed for user orphaned user orphan 孤立ユーザー sp_help_revlogin sp_change_users_login Msg 15023 15023 Msg 916 Msg 4060 ログイン マッピング SID データベースを別サーバーへ移行または復元し、アプリケーションが 'Login failed' になる: ログインを SID とパスワード ハッシュごと移行元から転送し、残りのユーザーをログインにマッピングします。データベースはオンラインのままです。"},{"k":"mode","v":"enc","l":"暗号化されたバックアップを復元できない (証明書がない、Msg 33111)","m":"移行とアクセス Msg 33111 33111 Cannot find server certificate with thumbprint 暗号化バックアップ 復元 encrypted backup バックアップ 証明書 certificate TDE Msg 15581 15581 master key バックアップ (または TDE データベースのバックアップ) が証明書で暗号化されており、このサーバーに証明書がない: 拇印 (thumbprint) を特定し、証明書を秘密キーとともに読み込み、バックアップを検証します。既存のデータベースには影響しません。"}]},{"id":"mssql-bcp-export","file":"install/guides/mssql-bcp-export.json","group":"SQL Server","engineId":"mssql","category":"backup","title":"SQL Server テーブル単位のエクスポート/インポート (bcp, sqlpackage)","summary":"バックアップではなく論理的なデータ移動です。bcp でテーブルをエクスポートして別のデータベースに読み込む (ネイティブ形式または文字形式、フォーマット ファイル、バッチ、TABLOCK、ID 列、UTF-8)、クエリ結果を CSV/テキスト ファイルに出力する (queryout)、sqlpackage でスキーマ + データを移動する (.bacpac の Export/Import、例: Azure SQL Database への","level":"中級","duration":"20–60 分","topology":"サーバー 1 台 (コマンドは SQL Server 本体または管理サーバーで実行)","tags":["sql server","mssql","bcp","一括コピー","エクスポート","インポート","queryout","フォーマット ファイル","ネイティブ","csv","utf-8","sqlpackage","bacpac","dacpac","extract","publish","azure sql","データ移行","マイグレーション","テーブル コピー"],"order":16,"steps":8,"scenarios":[{"k":"op","v":"table","l":"テーブルを移動: bcp out → bcp in","m":"データ移行 bcp bcp out bcp in 一括コピー テーブル コピー テーブル移動 Unexpected EOF encountered in BCP data-file Unable to open BCP host data-file 1 つ以上のテーブルを別の SQL Server データベースにコピーします。ターゲットにテーブルが事前に存在している必要があります。"},{"k":"op","v":"query","l":"クエリ結果をファイルに出力: bcp queryout (CSV/テキスト)","m":"エクスポート queryout csv csv エクスポート クエリ結果 ファイル出力 export to file クエリの結果を、他のシステム (Excel、ETL、レポート) に渡す CSV/テキスト ファイルに書き出します。"},{"k":"op","v":"bacpac","l":"スキーマ + データ: sqlpackage Export / Import (.bacpac)","m":"データ移行 bacpac sqlpackage SqlPackage Export SqlPackage Import Azure SQL Database 移行 SQL71564 SQL71501 スキーマとデータを 1 つのファイルで移動します。特に Azure SQL Database への移行や、小～中規模のデータベース向けです。"},{"k":"op","v":"dacpac","l":"スキーマのみ: sqlpackage Extract / Script / Publish (.dacpac)","m":"スキーマ dacpac Extract Publish スキーマ比較 schema compare BlockOnPossibleDataLoss The schema update is terminating because data loss might occur スキーマのみを抽出する、ターゲットと比較して変更スクリプトを生成する、または空のスキーマを新しい環境に展開します。"}]},{"id":"mssql-security","file":"install/guides/mssql-security.json","group":"SQL Server","engineId":"mssql","category":"security","title":"SQL Server のセキュリティ強化 (Linux と Windows: 評価、ネットワーク、TLS、認証、権限、audit、TDE)","summary":"インストールガイドではありません。稼働中の SQL Server 2019 / 2022 / 2025 インスタンス (Linux または Windows) のセキュリティ上の問題を見つけて塞ぎます。まず読み取り専用の セキュリティ評価 が問題を重要度順に一覧表示し、各検出事項がどのカードに対応するかを示します。その後、領域ごとに個別に、またはすべてを順番に対処します: 待ち受けアドレスと firewall、Force Encrypti","level":"中級","duration":"5 分 (評価) ～ 3 時間 (完全なセキュリティ強化)","topology":"単一の SQL Server インスタンス (Linux または Windows) + アプリケーションサーバー。Always On AG は注記を参照","tags":["sql server","mssql","セキュリティ","security","hardening","セキュリティ強化","cis benchmark","stig","force encryption","tls","証明書","sa","check_policy","xp_cmdshell","trustworthy","server audit","audit","tde","transparent data encryption","backup encryption","mssql-conf","windows","linux"],"order":40,"steps":2,"scenarios":[{"k":"scenario","v":"scan","l":"セキュリティ評価: どこに問題があるか (読み取り専用)","m":"はじめに セキュリティ評価 security audit hardening check CIS STIG セキュリティホール 脆弱性 vulnerability ペネトレーションテストの指摘 SQL Vulnerability Assessment 評価クエリ セキュリティスキャン security scan 重大 最初に実行するスキャンです: sa、パスワードポリシー、空のパスワード、sysadmin のメンバー、public/guest の権限、xp_cmdshell、暗号化されていない接続、audit、TDE と証明書のバックアップ、ポートと firewall。何も変更しません。"},{"k":"scenario","v":"all","l":"完全なセキュリティ強化 (すべてを順番に)","m":"はじめに hardening セキュリティ強化 完全なセキュリティ対策 full hardening CIS benchmark の適用 STIG 新規インストール直後、または一度もセキュリティ強化していないインスタンス: すべての領域を安全な順序で適用します。SQL Server は 1～2 回再起動されます (メンテナンスウィンドウが必要です)。"},{"k":"scenario","v":"net","l":"ネットワークと接続: 誰がどこから接続できるか (待ち受け、firewall、Browser)","m":"ネットワークと認証 1433 1434 SQL Browser firewall ListenOnAllIPs network.ipaddress Error 53 Error 40 TCP/IP Error 26 Error locating Server/Instance Specified Login timeout expired A network-related or instance-specific error 外部からのアクセス アクセス制限 SQL Server がすべてのインターフェイスで待ち受け、1433 が全体に公開され、SQL Browser が不要に動作しています。待ち受けアドレスを変更すると再起動が必要です。"},{"k":"scenario","v":"tls","l":"接続を暗号化する (Force Encryption、証明書、クライアント側の検証)","m":"ネットワークと認証 Force Encryption TrustServerCertificate Encrypt=Mandatory certificate chain was issued by an authority that is not trusted SSL Provider error 0x80090325 tlscert 証明書の有効期限 TDS 8.0 strict The target principal name is incorrect certificate verify failed Encrypt=Strict Force Strict Encryption Unable to load user-specified certificate 証明書チェーン certificate chain 接続が暗号化されていないか、自己署名の一時証明書で暗号化されており"},{"k":"scenario","v":"auth","l":"認証とパスワード (sa、CHECK_POLICY、Windows 認証)","m":"ネットワークと認証 sa CHECK_POLICY CHECK_EXPIRATION mixed mode Login failed for user Error 18456 Error 18486 account is locked out パスワードポリシー password policy PWDCOMPARE Error 18452 Login is from an untrusted domain Error 18470 The account is disabled Msg 15118 Msg 33062 sa_disabled Windows Authentication sa が有効、SQL ログインにパスワードポリシーがない、空/脆弱なパスワード。個人用 DBA アカウントの用意と sa の無効化。ダウンタイムはありません (Windows 認証のみへの切り替えだけは再起動"},{"k":"scenario","v":"priv","l":"最小権限と攻撃対象領域 (ロール、public、guest、xp_cmdshell)","m":"権限と証跡 db_owner sysadmin public guest xp_cmdshell TRUSTWORTHY CONTROL SERVER least privilege 最小権限 Msg 262 Msg 229 permission was denied Msg 15247 Msg 916 db_ddladmin EXECUTE AS 権限レポート アプリケーションユーザーが db_owner または sysadmin、public/guest に余分な権限、xp_cmdshell/TRUSTWORTHY が有効。ロール設計と権限レポート。ダウンタイムはありません。"},{"k":"scenario","v":"audit","l":"Audit: 誰が何をしたか (Server Audit、Database Audit Specification)","m":"権限と証跡 SQL Server Audit server audit audit specification fn_get_audit_file C2 audit login auditing 監査証跡 SIEM 個人情報保護法 (APPI) PCI sqlaudit Server Audit Specification Database Audit Specification Msg 33072 誰が何をしたか 監査担当者がログイン、権限、スキーマ変更の記録を求めています。ファイル (または Windows イベントログ) への Server Audit、集中管理システムへの転送と保持。ダウンタイムはありません。すべてのエディションでライセンス不要です (2016 SP1 以降)。"},{"k":"scenario","v":"tde","l":"ディスク上のデータを暗号化する (TDE)","m":"データとバックアップ TDE transparent data encryption database encryption key DEK service master key Msg 33111 Cannot find server certificate with thumbprint encryption at rest Msg 15208 ENCRYPTION_IN_PROGRESS percent_complete Msg 15581 証明書のバックアップ ディスク、データファイル、バックアップが別のサーバーで開かれることへの対策としての TDE: DMK、証明書、DEK。オンラインで実施できます。証明書のバックアップは必須です (失うとデータベースとそのバックアップを開けなくなります)。**ライセンス:** SQL Server 2019 以降の Standard と Ent"},{"k":"scenario","v":"backup","l":"バックアップのセキュリティ (暗号化バックアップ、証明書、権限)","m":"データとバックアップ backup encryption バックアップの暗号化 WITH ENCRYPTION BACKUP CERTIFICATE バックアップの権限 Msg 33111 Msg 15151 RESTORE VERIFYONLY key_algorithm Msg 15240 バックアップが暗号化されていない、バックアップディレクトリが全員に公開されている、スクリプトにパスワードが平文で書かれている。BACKUP … WITH ENCRYPTION、証明書のバックアップとディレクトリ権限。ダウンタイムはありません。バックアップの暗号化は Standard と Enterprise で利用でき、Express にはありません。"},{"k":"scenario","v":"os","l":"OS 側 (サービスアカウント、ファイル権限、SELinux)","m":"サーバーとバージョン service account サービスアカウント LocalSystem gMSA virtual account icacls SELinux mssql ユーザー NT Service\\MSSQLSERVER mssql-server-selinux unconfined_service_t Configuration Manager Log On サービスが LocalSystem または管理者アカウントで動作している、データ/バックアップディレクトリが全員に公開されている、SELinux が無効。サービスアカウントの変更には再起動が必要です。"},{"k":"scenario","v":"patch","l":"パッチとバージョン: サポート対象のバージョンで最新の CU か","m":"サーバーとバージョン CU cumulative update GDR EOL end of support サポート終了 CVE セキュリティパッチ ProductUpdateLevel ProductUpdateReference Latest updates パッチ適用スケジュール バージョン、CU レベル、サポート終了日 (2016 は 2026 年 7 月に終了)。適用には CU パッチのガイドへ案内します。読み取り専用です。"}]},{"id":"mongo-replset","file":"install/guides/mongo-replset.json","group":"MongoDB","engineId":"mongodb","category":"ha","title":"MongoDB レプリカセットの構築 (3 メンバー、keyfile と認可)","summary":"3 メンバーの MongoDB 8.0 (または 7.0) レプリカセットを一から構築します。公式リポジトリ、XFS のデータディレクトリ、RAM に応じた WiredTiger キャッシュ、keyfile によるメンバー間認証、認可、管理者ユーザーとアプリケーションユーザー、read/write concern、フェイルオーバーテスト、接続文字列までを扱い、最終的にメンバー 1 台の喪失を停止なしで乗り切れる、パスワードで保護されたレ","level":"中級","duration":"60～90 分","topology":"サーバー 3 台 (primary 1 + secondary 2)、データを保持するメンバーは奇数台","tags":["mongodb","mongo","レプリカセット","replset","rs.initiate","keyfile","フェイルオーバー","stepdown","write concern","wiredtiger","高可用性","ha","rhel","ubuntu"],"order":1,"steps":36,"scenarios":[]},{"id":"mongo-sharded","file":"install/guides/mongo-sharded.json","group":"MongoDB","engineId":"mongodb","category":"ha","title":"MongoDB シャードクラスタのインストール (config server + シャード + mongos)","summary":"データ量や書き込み負荷が 1 つのレプリカセットの限界を超えたときに構築するシャードクラスタです。3 メンバーの config server レプリカセット、2 つまたは 3 つのシャードレプリカセット、2 台の mongos ルーターを構成し、keyfile による内部認証、認可、sh.addShard、シャードキーの選定、コレクションのシャーディング、バランサー、データ分散の確認までを行います。最終的に、アプリケーションが mong","level":"上級","duration":"2～3 時間","topology":"config server 3 台 + シャードメンバー 2×3 台 + mongos 2 台 (最低 11 台。テスト用ならより少なくて可)","tags":["mongodb","シャーディング","シャードクラスタ","mongos","config server","シャードキー","addShard","バランサー","hashed","スケーリング","rhel","ubuntu"],"order":2,"steps":60,"scenarios":[]},{"id":"mongo-upgrade","file":"install/guides/mongo-upgrade.json","group":"MongoDB","engineId":"mongodb","category":"upgrade","title":"MongoDB rolling upgrade (7.0 → 8.0): replica set と sharded cluster","summary":"稼働中の MongoDB 7.0 replica set または sharded cluster を、サービスを止めずに (rolling) 8.0 へアップグレードします。事前チェック (バージョン、FCV、メンバーの状態、ドライバー互換性)、バックアップ、まず secondary、次に stepDown と旧 primary。sharded cluster では balancer の停止、config server、各 shard、","level":"上級","duration":"60〜120 分 (データサイズに依存しない。メンバーあたり数分)","topology":"Replica set (3 メンバー以上) または sharded cluster (config server + shard + mongos)","tags":["mongodb","upgrade","メジャーバージョンアップグレード","rolling upgrade","8.0","7.0","featureCompatibilityVersion","fcv","stepdown","replica set","sharded","balancer","config server","mongos","fcv","featureCompatibilityVersion","rolling upgrade"],"order":3,"steps":30,"scenarios":[]},{"id":"mongo-backup","file":"install/guides/mongo-backup.json","group":"MongoDB","engineId":"mongodb","category":"backup","title":"MongoDB のバックアップとリストア (mongodump、mongorestore、snapshot)","summary":"インストール済みの MongoDB にバックアップの運用を構成し、バックアップからの復旧をシナリオごとに説明します。バックアップ: mongodump による単一 collection、データベースまたはデプロイメント全体 (--archive --gzip。replica set では --oplog による一貫性のある時点、secondary からの読み取り)、認証情報ファイル、systemd timer/cron による保持期間付","level":"中級","duration":"45〜90 分","topology":"バックアップサーバーまたはメンバー 1 台 + replica set / 単一インスタンス / sharded cluster (mongos)","tags":["mongodb","mongo","バックアップ","backup","restore","リストア","mongodump","mongorestore","oplog","oplogReplay","nsFrom","nsTo","mongoexport","mongoimport","fsyncLock","lvm snapshot","systemd timer","cron","retention","balancer","activeWindow","config server","cron","systemd timer","flock","oplog","リストアシナリオ","point in time recovery","pitr","oplogLimit","nsInclude","dryRun","sharded restore","クローン","削除された collection","誤って削除"],"order":15,"steps":20,"scenarios":[{"k":"scenario","v":"setup","l":"バックアップを構成する: mongodump、スケジュール、テストリストア","m":"バックアップ mongodump バックアップ 構成 backup setup systemd timer cron retention mongorestore backup user backup.yaml Failed: can't create session oplog overflow mongodump was unable to capture all new oplog entries バックアップ取得 バックアップユーザー、認証情報ファイル、手動および定期の mongodump、別名でのテストリストア。任意で snapshot と mongoexport。初めて構成する場合はここから始めてください。"},{"k":"scenario","v":"r_dry","l":"バックアップは本当にリストアできるか (--dryRun と一時インスタンスでのリハーサル)","m":"リハーサルと確認 dryRun --dryRun restore test リストアのリハーサル バックアップの検証 backup verify gzip: invalid compressed data unexpected EOF archive is corrupt 破損したアーカイブ gzip -t バックアップから戻せるか 本番データには触れません: アーカイブの整合性、含まれる namespace と oplog を確認し、任意で一時的な mongod へのフルリストアとドキュメント数の照合を行います。"},{"k":"scenario","v":"r_full","l":"すべてのデータをバックアップからリストアする (フルリストア、--drop)","m":"リストア full restore フルリストア データベース全体のリストア --drop mongorestore --drop データ損失 data loss ransomware ランサムウェア 全データが削除された dropDatabase no oplog file to replay oplogReplay applyOps not authorized … applyOps admin.tempusers データの大部分が失われたか破損しており、デプロイメントをバックアップ取得時点に戻します。バックアップ以降の書き込みは失われ、リストア中はアプリケーションが停止します。"},{"k":"scenario","v":"r_ns","l":"単一のデータベースまたは collection を戻す (--nsInclude、別名で、またはその場で)","m":"リストア --nsInclude --nsFrom --nsTo 単一 collection single collection restore collection 削除 collection dropped drop collection 削除されたドキュメント deleted documents deleteMany namespace restore E11000 duplicate key error $merge orders_restored 単一データベースのリストア collection/データベースが削除または破損したが、残りは正常: その namespace だけをバックアップから戻します。他のデータには触れず、アプリケーションは稼働したままにできます。"},{"k":"scenario","v":"r_pitr","l":"特定の時点に戻す: バックアップ + oplog (誤った drop、誤った update/delete)","m":"特定時点への復旧 point in time PITR ポイントインタイムリカバリ --oplogReplay --oplogLimit oplog replay oplog.rs 誤って削除 accidental drop 誤った update wrong update drop 直前 Timestamp oplog の周回 rollback to time 特定の時刻に戻す 誤操作がバックアップの後に発生し、その時点までの書き込みも必要な場合: 最新のフルバックアップをリストアし、本番の oplog を誤操作の直前まで適用します (--oplogReplay --oplogLimit)。replica set のみ。"},{"k":"scenario","v":"r_other","l":"バックアップを別のクラスタ/サーバーにリストアする (クローン、テスト環境、移行)","m":"移行とクローン clone クローン 別サーバーへのリストア restore to another cluster migration サーバー移行 テスト環境 refresh nsExclude admin.system.users Invalid feature compatibility version cannot use --oplogReplay with excludes specified テスト環境へのコピー ソースのデプロイメントには触れません: バックアップを別の replica set またはインスタンスに展開します (テスト/レポート用コピー、サーバー移行、バージョンアップグレード)。ユーザーの移行は任意です。"},{"k":"scenario","v":"r_shard","l":"sharded cluster をリストアする: mongodump の制約と適切な方法","m":"移行とクローン sharded restore sharded cluster restore mongos restore shard key shardCollection config server restore balancer inconsistent 一貫性のないバックアップ PBM Percona Backup Ops Manager --oplog mode only supported on full dumps mongos 経由のバックアップ バックアップ対象の構成は sharded cluster: mongos 経由の論理リストア (shard key の再作成、balancer)、または協調して取得した snapshot によるクラスタ全体の物理的な再構築。"}]},{"id":"mongo-ops","file":"install/guides/mongo-ops.json","group":"MongoDB","engineId":"mongodb","category":"ops","title":"MongoDB の日常運用と障害シナリオ (replica set と sharded cluster)","summary":"インストール手順ではありません。構築済みの MongoDB replica set と sharded cluster を日常的に運用し、障害時に復旧するためのシナリオ別 runbook です。ヘルスチェック、メンバーの追加・削除、priority/hidden/delayed メンバー、arbiter からデータ保持メンバーへの置き換え、遅延したメンバーの再同期、過半数喪失時の force reconfig、計画的な stepDown","level":"上級","duration":"5 分 (確認) – 数時間 (initial sync、drain、reshard)","topology":"Replica set (3 メンバー以上) または sharded cluster (config server + shard replica set + mongos)","tags":["mongodb","mongo","replica set","sharded cluster","rs.status","rs.add","rs.remove","rs.reconfig","force reconfig","stepDown","priority","hidden","delayed","secondaryDelaySecs","arbiter","resync","initial sync","too stale","oplog","replSetResizeOplog","FCV","setFeatureCompatibilityVersion","addShard","removeShard","movePrimary","balancer","activeWindow","jumbo","chunk","reshardCollection","shard key","運用","障害"],"order":20,"steps":3,"scenarios":[{"k":"scenario","v":"health","l":"ヘルスチェック: メンバー、遅延、oplog ウィンドウ (sharded の場合は shard と balancer)","m":"監視と確認 rs.status rs.status() replication lag レプリケーション遅延 replLag printSecondaryReplicationInfo sh.status health ヘルスチェック NotYetInitialized RECOVERING STARTUP2 UNKNOWN (not reachable/healthy) DOWN ReplicaSetNoPrimary Server selection timed out lastHeartbeatMessage 読み取り専用: メンバーの状態、レプリケーション遅延、oplog ウィンドウ、構成。sharded cluster では shard 一覧、balancer、chunk の分布も確認します。何をすべきか分からない場合はここから始めてください。"},{"k":"scenario","v":"add","l":"replica set に新しいメンバーを追加する (initial sync)","m":"メンバー管理 rs.add メンバー追加 add member initial sync 新しい secondary newlyAdded STARTUP2 scale out rs.add() Quorum check failed Found two member configurations with same host field votes: 0 新しいサーバーを構築済み (同じバージョン、keyfile、replSetName) であることが前提です。priority 0 / votes 0 で追加し、initial sync が完了して SECONDARY になった後に投票権と priority を与えます。ダウンタイムはありません。"},{"k":"scenario","v":"remove","l":"replica set からメンバーを削除する","m":"メンバー管理 rs.remove メンバー削除 remove member decommission サーバー撤去 REMOVED Our replica set config is invalid or we are not a member of it rs.remove() サーバーを廃止する、または恒久的に失われた場合です。メンバーを構成から削除し、残りの投票数で過半数が維持されることを確認します。対象が primary の場合は先に stepDown します。"},{"k":"scenario","v":"member_cfg","l":"メンバーのロールを変更する: priority、hidden、delayed メンバー","m":"メンバー管理 priority hidden delayed secondaryDelaySecs slaveDelay hidden メンバー delayed メンバー votes rs.reconfig priority must be 0 when hidden=true only one voting member can be added or removed at a time rs.reconfig() メンバーが primary になる優先度を変更する、レポート/バックアップ用の hidden メンバーや誤削除対策の delayed メンバーにする、または通常のメンバーに戻します。"},{"k":"scenario","v":"arbiter","l":"arbiter をデータ保持メンバーに置き換える (PSA → PSS)","m":"メンバー管理 arbiter arbiterOnly PSA rs.addArb majority write concern cache pressure w: majority 待機 Rejecting reconfig where the new config has a PSA topology implicit default write concern majority commit point primary + secondary + arbiter 構成の replica set では、データメンバーが 1 台停止すると majority 書き込みと cache 負荷が問題になります。新しいデータメンバーを追加し、arbiter を削除します。"},{"k":"scenario","v":"resync","l":"遅延または破損したメンバーを再同期する (resync)","m":"障害と復旧 too stale too stale to catch up RS102 resync 再同期 initial sync RECOVERING WiredTiger error WT_PANIC データファイル破損 data corruption OplogStartMissing maintenance mode InitialSyncFailure fassert checksum mismatch メンバーが RECOVERING のまま止まり 'too stale to catch up' と出力している、またはデータファイルが破損している場合です。メンバーのデータディレクトリを空にし、initial sync で一から同期し直します。他のメンバーは稼働を続けます。"},{"k":"scenario","v":"force","l":"過半数喪失: 残存メンバーで強制再構成する (force reconfig)","m":"障害と復旧 force reconfig force: true no primary primary 不在 過半数喪失 majority lost NotWritablePrimary not master no replset config split brain DR site サイト喪失 ReplicaSetNoPrimary Server selection timed out rs.reconfig force メンバーの大半が恒久的に失われ (サイト/サーバー喪失)、残ったメンバーで primary を選出できない場合です。残存メンバーで rs.reconfig(cfg, {force: true}) を実行します。最後の手段であり、使い方を誤るとデータ損失と split brain の危険があります。"},{"k":"scenario","v":"stepdown","l":"計画的な primary 切り替え (rs.stepDown、特定メンバーの primary 化)","m":"メンテナンス stepDown rs.stepDown replSetStepDown primary 切り替え switchover 計画メンテナンス maintenance rs.freeze No electable secondaries caught up InterruptedDueToReplStateChange PrimarySteppedDown primary 変更 primary サーバーでメンテナンス/パッチ適用を行う場合です。primary を降格させ、追いついている secondary が primary になります。アプリケーションでは数秒間書き込みエラーが発生することがあります。"},{"k":"scenario","v":"oplog","l":"oplog サイズを変更する (replSetResizeOplog)","m":"メンテナンス oplog oplog window oplog ウィンドウ replSetResizeOplog oplogSizeMB oplogMinRetentionHours too stale oplog overflow rs.printReplicationInfo getReplicationInfo log length start to end oplog ウィンドウが短い場合です。メンテナンス後に secondary が 'too stale' になる、バックアップが oplog を取得しきれない、またはポイントインタイムリカバリに足りない、といった症状が出ます。各メンバーでダウンタイムなしに拡張します。"},{"k":"scenario","v":"fcv","l":"Feature Compatibility Version (FCV) を確認して完了させる","m":"メンテナンス FCV featureCompatibilityVersion setFeatureCompatibilityVersion Invalid feature compatibility version IncompatibleServerVersion アップグレード後 UPGRADE PROBLEM requires confirm: true getParameter featureCompatibilityVersion アップグレード後に FCV が旧バージョンのまま、またはメンバー間でバージョンが異なる場合です。全メンバーのバイナリバージョンと FCV を確認し、FCV を新バージョンに引き上げます。"},{"k":"scenario","v":"addshard","l":"cluster に shard を追加する (sh.addShard)","m":"Sharded cluster addShard sh.addShard shard 追加 add shard scale out 新しい shard shardAdded is not running with --shardsvr in use by another shard 容量が不足している場合です。新しい shard replica set (shardsvr) を構築済みで、それを cluster に追加します。balancer が chunk を段階的に移動します。"},{"k":"scenario","v":"rmshard","l":"shard を削除する (removeShard: drain と movePrimary)","m":"Sharded cluster removeShard remove shard shard 廃止 drain draining movePrimary dbsToMove jumboChunks moveCollection collectionsToMove ShardNotFound draining started successfully shard を廃止する場合です。chunk を他の shard へ退避 (drain) し、その shard が primary shard になっているデータベースを移動 (movePrimary) した後、cluster から削除します。"},{"k":"scenario","v":"balancer","l":"Balancer: 時間ウィンドウ、停止 / 開始、collection 単位の無効化","m":"Sharded cluster balancer activeWindow stopBalancer startBalancer sh.stopBalancer disableBalancing balancer ウィンドウ chunk migration moveChunk isBalancerRunning getBalancerState Balancer timed out ピーク時間帯に chunk の移動が負荷になる、メンテナンス/バックアップのために移動を止める必要がある、または特定の collection だけバランシングさせたくない場合です。"},{"k":"scenario","v":"chunks","l":"分布の偏りまたは jumbo chunk (診断と対処)","m":"Sharded cluster jumbo jumbo chunk chunk too big ChunkTooBig 偏り imbalance hot shard balancerCollectionStatus clearJumboFlag moveChunk failed getShardDistribution low cardinality splitFind Cannot split on the boundary jumboChunks 特定の shard だけが他より大きく偏っている、balancer が移動しない、'jumbo' フラグ付きの chunk がある、または moveChunk が失敗する場合です。分布、jumbo chunk、balancer のエラーを調べます。"},{"k":"scenario","v":"reshard","l":"shard key を変更する (reshardCollection)","m":"Sharded cluster reshardCollection reshard shard key 変更 change shard key refineCollectionShardKey abortReshardCollection commitReshardCollection forceRedistribution ReshardCollectionInProgress ReshardCollectionAborted unshardCollection 現在の shard key が hot shard、jumbo chunk、scatter-gather クエリを生んでいる場合です。collection をオンラインのまま新しい shard key で再分散します (5.0+)。最後に書き込みが約 2 秒ブロックされます。"},{"k":"mcfg","v":"priority","l":"priority を変更する (primary になる優先度)","m":"メンバーが primary になる優先度を変更します (例: メインデータセンターのメンバーを優先する、DR メンバーを 0 にする)。選出が発生することがあり、短時間の書き込み中断が起こる可能性があります。"},{"k":"mcfg","v":"hidden","l":"hidden メンバー: アプリケーションからは見えない、バックアップ/レポート用","m":"メンバーはアプリケーションから見えなくなり (読み取りはルーティングされません)、レポート、分析、バックアップ用に確保されます。priority は 0 になり、primary にはなれません。"},{"k":"mcfg","v":"delayed","l":"delayed メンバー: 誤削除対策","m":"メンバーは指定した時間だけ遅れて oplog を適用します。誤って削除したデータはその間このメンバーに残ります。hidden、priority 0、votes 0 になります。"},{"k":"mcfg","v":"normal","l":"通常に戻す (priority 1、可視、遅延なし、投票あり)","m":"以前のロールを元に戻します: priority 1、可視、遅延なし、投票あり。"},{"k":"bal_op","v":"window","l":"時間ウィンドウを定義する (activeWindow)","m":"移動を特定の時間帯 (例: 夜間) のみに限定し、日中の負荷を避けます。"},{"k":"bal_op","v":"unwindow","l":"時間ウィンドウを削除する (常時稼働)","m":"時間ウィンドウを削除します。balancer は必要に応じて時間帯を問わず移動を行います (例: 新しい shard 追加後に素早くバランスさせる場合)。"},{"k":"bal_op","v":"stop","l":"balancer を停止する (メンテナンス/バックアップ)","m":"バックアップ、アップグレード、メンテナンスの前に行います。実行中の移動は完了し、新しい移動は開始されません。作業後は必ず再開してください。"},{"k":"bal_op","v":"start","l":"balancer を開始する","m":"停止している balancer を有効にします。バランシングは中断したところから再開します。"},{"k":"bal_op","v":"coll_off","l":"特定の collection のバランシングを無効にする","m":"1 つの collection の chunk だけを移動対象外にします (意図的な配置、問題のある collection)。他の collection は引き続きバランシングされます。"},{"k":"bal_op","v":"coll_on","l":"特定の collection のバランシングを有効にする","m":"collection に対して無効化したバランシングを再度有効にします。"}]},{"id":"mongo-security","file":"install/guides/mongo-security.json","group":"MongoDB","engineId":"mongodb","category":"security","title":"MongoDB セキュリティ強化 (認可、TLS、ロール、監査)","summary":"稼働中の MongoDB (スタンドアロン、レプリカセット、シャードクラスタ) をダウンタイムなしで強化するためのシナリオ別 runbook です。読み取り専用のセキュリティ監査、keyFile + transitionToAuth によるローリングでの認可有効化、最小権限のカスタムロールとユーザー、SCRAM-SHA-256、bindIp とファイアウォール、allowTLS → preferTLS → requireTLS への移行","level":"上級","duration":"10 分 (監査) – 2 時間 (全面的な強化)","topology":"スタンドアロン、3 メンバー以上のレプリカセット、またはシャードクラスタ","tags":["mongodb セキュリティ","mongodb security","hardening","セキュリティ強化","CIS","authorization","keyFile","transitionToAuth","TLS","requireTLS","x.509","SCRAM-SHA-256","custom role","least privilege","bindIp","audit log","auditLog","encryption at rest","LUKS","Percona"],"order":20,"steps":8,"scenarios":[{"k":"op","v":"audit","l":"セキュリティ状態の監査 (読み取り専用)","m":"監査 セキュリティ監査 security audit security checklist CIS MongoDB hardening セキュリティ強化 Access control is not enabled for the database auth 無効 bindIp 0.0.0.0 exposed mongodb インターネットに公開された mongodb ransom ランサムウェア getCmdLineOpts security checklist MongoDB 監査レポート 何も変更しません。認証なしのアクセス、待ち受けアドレス、TLS、認証メカニズム、高権限ユーザー、監査ログ、保存時の暗号化の状態を OK / WARN / RISK で報告します。どこから始めればよいかわからない場合はこれを選んでください。"},{"k":"op","v":"all","l":"全面的な強化 (すべてを順番に実施)","m":"監査 全面的な強化 full hardening CIS benchmark セキュリティプロジェクト ペネトレーションテスト 指摘事項 監査 指摘事項 監査 → 内部認証 + 認可 (transitionToAuth でダウンタイムなし) → 最小権限ユーザー → SCRAM-SHA-256 → bindIp/ファイアウォール → TLS (allowTLS → preferTLS → requireTLS) → 監査ログ (Enterprise/Percona) → 最終監査。レプリカセットではローリングで実施し、リスクのあるステップごとに確認を求めます。"},{"k":"op","v":"auth","l":"認可が無効: authorization を有効にする (keyFile、ダウンタイムなし)","m":"認証と認可 Access control is not enabled for the database Read and write access to data and configuration is unrestricted authorization disabled authorization: enabled auth 無効 no authentication transitionToAuth keyFile internal authentication メンバー間認証 認証なしのアクセス permissions on /etc/mongod.keyfile are too open Authentication failed __system localhost exception ユーザー名とパスワードなしで誰でも接続できる状態です。レプリカセットとシャードクラスタでは"},{"k":"op","v":"users","l":"最小権限のユーザーとカスタムロール (アプリケーション、バックアップ、監視)","m":"認証と認可 least privilege 最小権限 custom role createRole root ユーザー アプリケーションが root で接続 not authorized on Unauthorized command find requires authentication requires authentication readWrite clusterMonitor backup ロール createUser grantRolesToUser monitor_user backup_user アプリケーションが root または共用の管理者アカウントで接続している状態です。アプリケーションに自分のデータベースで必要な操作だけを許可するカスタムロールと、バックアップ用・監視用の個別ユーザーを作成します。cron/アプリケーション側でのパスワードの安全な保管方法も示します"},{"k":"op","v":"scram","l":"SCRAM-SHA-1 を無効化し SCRAM-SHA-256 のみにする","m":"認証と認可 SCRAM-SHA-1 SCRAM-SHA-256 authenticationMechanisms Received authentication for mechanism SCRAM-SHA-1 which is not enabled Unable to use SCRAM-SHA-256 based authentication for user without any SCRAM-SHA-256 credentials registered MD5 mechanism 古いユーザーの認証情報が SHA-1 で保存されているか、監査で SCRAM-SHA-1 が有効と検出された状態です。ユーザーを SHA-256 に移行し、その後ローリング再起動で `authenticationMechanisms` を絞り込みます。"},{"k":"op","v":"bind","l":"ネットワークアクセスを制限する (bindIp 0.0.0.0、ファイアウォール)","m":"ネットワークと暗号化 bindIp 0.0.0.0 bindIpAll bind_ip_all 0.0.0.0:27017 ポート 27017 開放 shodan インターネットに公開 ファイアウォール javascriptEnabled noscripting net.bindIp ufw allow 27017 firewall-cmd 27017 mongod がすべてのインターフェース (0.0.0.0、`bindIpAll`) で待ち受けているか、ポートが誰にでも開いている状態です。bindIp を localhost + サーバーの内部 IP に絞り、ファイアウォールではメンバーとアプリケーションネットワークのみを許可します。ローリングで実施し、ダウンタイムはありません。"},{"k":"op","v":"tls","l":"接続を暗号化する: TLS (allowTLS → preferTLS → requireTLS)","m":"ネットワークと暗号化 TLS SSL net.tls.mode requireTLS preferTLS allowTLS 暗号化されていない接続 cleartext no SSL certificate provided by peer SSL peer certificate validation failed certificate verify failed x.509 x509 clusterAuthMode Hostname/IP does not match certificate's altnames self-signed certificate in certificate chain rotateCertificates allowConnectionsWithoutCertificates アプリケーションとメンバー間、およびメンバー同士の通信が暗号化されていない状"},{"k":"op","v":"auditlog","l":"監査ログを有効にする (Enterprise / Percona)","m":"監査証跡とデータ保護 audit log auditLog 監査証跡 誰が削除したか who dropped Unrecognized option: auditLog unrecognised option '--auditDestination' 個人情報保護法 (APPI) PCI DSS ログ記録 誰がいつログインしたか、ユーザー/ロールの変更、drop 操作を記録する必要があります。MongoDB Enterprise と Percona Server for MongoDB では `auditLog` で有効化します。Community にはこの機能がありません (代替手段を示します)。"},{"k":"op","v":"ear","l":"保存時の暗号化 (ディスク上のデータを暗号化する)","m":"監査証跡とデータ保護 encryption at rest ディスク暗号化 enableEncryption encryptionKeyFile KMIP Vault LUKS dm-crypt データ暗号化 Unrecognized option: security.enableEncryption Unable to retrieve key Unable to use encryption at rest cryptsetup luksFormat ディスクやバックアップが盗まれてもデータを読めないようにします。Enterprise/Percona では、メンバーを 1 台ずつ初期同期 (initial sync) で再構築して WiredTiger 暗号化を有効にします。Community ではデータディスクを LUKS で暗号化します。"}]},{"id":"redis-sentinel","file":"install/guides/redis-sentinel.json","group":"Redis","engineId":"redis","category":"ha","title":"Redis Sentinel による高可用性構成 (master + replica + 3 Sentinel)","summary":"3 台のサーバーで Redis 7.2 / 8.2 または Valkey の高可用性構成をゼロから構築します。master 1 台、replica 2 台、各サーバーに Sentinel 1 つという構成です。RAM に応じた maxmemory、永続化 (RDB/AOF)、パスワード、カーネル設定、quorum とタイムアウト、計画的な failover テスト、Sentinel 対応のクライアント接続を順に設定します。最終的に、ma","level":"中級","duration":"45〜60 分","topology":"サーバー 3 台: 各サーバーに Redis (master 1 + replica 2) と Sentinel","tags":["redis","valkey","sentinel","レプリカ","レプリケーション","フェイルオーバー","クォーラム","高可用性","ha","キャッシュ","rhel","ubuntu"],"order":1,"steps":27,"scenarios":[]},{"id":"redis-cluster","file":"install/guides/redis-cluster.json","group":"Redis","engineId":"redis","category":"ha","title":"Redis Cluster の構築 (マスター 3 台 + レプリカ 3 台)","summary":"Redis Cluster をゼロから構築します (Redis 7.2 / 8.2 または Valkey)。16384 のハッシュスロットを 3 台 (またはそれ以上) のマスターに分配し、各マスターは別のサーバー上にレプリカを持ちます。サーバーごとに 1 インスタンス (6 サーバー) または 2 インスタンス (3 サーバー) の配置、インスタンスごとの systemd サービス、パスワード、クラスタの作成、確認、フェイルオーバーテ","level":"中級","duration":"45–60 分","topology":"6 インスタンス: 6 サーバー × 1 または 3 サーバー × 2","tags":["redis","valkey","クラスタ","redis cluster","シャーディング","ハッシュスロット","リシャード","フェイルオーバー","レプリカ","スケーリング","rhel","ubuntu"],"order":2,"steps":33,"scenarios":[]},{"id":"redis-backup","file":"install/guides/redis-backup.json","group":"Redis","engineId":"redis","category":"backup","title":"Redis のバックアップとリストア (RDB、AOF、replica、cluster)","summary":"インストール済みの Redis または Valkey (単一インスタンス、Sentinel 構成の master/replica、Redis Cluster) のバックアップ運用を構築し、バックアップからの復旧手順を説明します。RDB (save ルール、BGSAVE、LASTSAVE、dump.rdb のコピー) と AOF (BGREWRITEAOF、7.x のマルチファイル appendonlydir) のバックアップ、repli","level":"中級","duration":"30〜60 分","topology":"単一インスタンス、replica または Redis Cluster サーバー (Redis 7.2 / 8.x、Valkey)","tags":["redis","valkey","バックアップ","backup","restore","リストア","rdb","dump.rdb","bgsave","lastsave","aof","appendonly","bgrewriteaof","appendonlydir","redis cluster","systemd timer","cron","retention","cron","systemd timer","flock","REDISCLI_AUTH","sentinel"],"order":15,"steps":19,"scenarios":[]},{"id":"redis-ops","file":"install/guides/redis-ops.json","group":"Redis","engineId":"redis","category":"ops","title":"Redis / Valkey の日常運用と障害シナリオ (Cluster と Sentinel)","summary":"構築ガイドではありません: 構築済みの Redis Cluster または Sentinel 管理の master/replica 構成を日常的に運用し、障害時に復旧するためのシナリオ別 runbook です (Redis 7.2、Redis 8、Valkey)。Cluster: ヘルスチェック、ノードの追加/削除、rebalance/reshard、手動 failover (FORCE と TAKEOVER の違い)、障害ノードの交換","level":"上級","duration":"5 分 (確認) 〜 1 時間 (reshard)","topology":"Redis Cluster (master 3 台以上 + replica) または Sentinel (master 1 台 + replica + Sentinel 3 台)","tags":["redis","valkey","redis cluster","sentinel","redis-cli --cluster","cluster check","add-node","del-node","reshard","rebalance","CLUSTER FAILOVER","FORCE","TAKEOVER","CLUSTER FORGET","cluster fix","SENTINEL FAILOVER","SENTINEL RESET","quorum","CKQUORUM","INFO memory","MEMORY DOCTOR","eviction","maxmemory","bigkeys","memkeys","hotkeys","運用","障害"],"order":20,"steps":3,"scenarios":[{"k":"scenario","v":"c_health","l":"Cluster のヘルスチェック (--cluster check、CLUSTER INFO / NODES)","m":"Redis Cluster: 監視 cluster_state:fail CLUSTERDOWN CLUSTERDOWN Hash slot not served --cluster check CLUSTER INFO CLUSTER NODES fail? pfail slots not covered Not all 16384 slots are covered [ERR] Nodes don't agree about configuration MOVED ASK CLUSTERDOWN The cluster is down cluster_slots_fail クラスタ 状態 cluster health cluster_state 参照のみ: すべての slot がカバーされているか、ノード間で構成が一致しているか、障害 (fail) ノードや replica のない m"},{"k":"scenario","v":"c_add","l":"クラスタにノードを追加する (master または replica)","m":"Redis Cluster: ノード管理 add-node --cluster add-node ノード追加 add node scale out --cluster-slave --cluster-replica cluster-master-id 新しい master 新しい replica Node is not empty. Either the node already knows other nodes New node added correctly 容量拡張 新しいインスタンス (cluster-enabled yes、空) の準備ができている場合: master としてクラスタに参加して slot を受け取るか、ある master の replica になります。停止はありません。"},{"k":"scenario","v":"c_remove","l":"クラスタからノードを削除する (slot を空にする + del-node)","m":"Redis Cluster: ノード管理 del-node --cluster del-node ノード削除 remove node scale in slot 退避 cluster-weight Node … is not empty is not empty! Reshard data away and try again CLUSTER RESET SOFT ノード撤去 master または replica を撤去する場合: master の slot を他の master に移動してから、ノードをクラスタから削除します。停止はありません。移動中は ASK リダイレクトが発生します。"},{"k":"scenario","v":"c_reshard","l":"slot を再配置する (rebalance / reshard)","m":"Redis Cluster: ノード管理 rebalance reshard --cluster rebalance --cluster reshard slot 配置 偏り imbalance use-empty-masters MIGRATE importing migrating BUSYKEY IOERR error or timeout reading to target instance has slots in importing state has slots in migrating state Calling MIGRATE No rebalancing needed slot 移動 master 間で slot やメモリが偏っている、新しい master に slot が割り当てられていない、または特定数の slot をある master から別の master へ移"},{"k":"scenario","v":"c_failover","l":"手動 failover: replica を master にする (CLUSTER FAILOVER、FORCE、TAKEOVER)","m":"Redis Cluster: 障害とメンテナンス CLUSTER FAILOVER failover FORCE TAKEOVER manual failover master メンテナンス replica 昇格 Manual failover timed out ERR Master is down or failed, please use CLUSTER FAILOVER FORCE ERR You should send CLUSTER FAILOVER to a replica master 切り替え master のサーバーでメンテナンスを行う場合 (計画的、データ損失なし)、または master に到達できず自動 failover が起きなかった場合 (FORCE / TAKEOVER、データ損失のリスクあり)。"},{"k":"scenario","v":"c_replace","l":"障害 master / ノードを交換する (FORGET、新しい replica、--cluster fix)","m":"Redis Cluster: 障害とメンテナンス CLUSTER FORGET --cluster fix ノード喪失 failed node fail noaddr slots not covered CLUSTERDOWN replace node 障害 master handshake ERR Can't forget my master! CLUSTERDOWN Hash slot not served サーバー喪失 ディスク障害 ノードのサーバーが完全に失われた場合: その replica が master になっていれば旧ノードを FORGET させ、代わりに新しい replica を追加します。replica がなければ slot の所有者がいなくなるため --cluster fix で埋めます (その slot のデータは失われます)。"},{"k":"scenario","v":"s_health","l":"Sentinel の状態: master、replica、Sentinel、quorum","m":"Sentinel SENTINEL MASTERS SENTINEL master get-master-addr-by-name CKQUORUM +sdown +odown -odown +switch-master NOQUORUM NOGOODSLAVE sentinel 状態 +tilt -failover-abort-not-elected s_down o_down master_link_status:down sentinel health 参照のみ: Sentinel が認識している master のアドレス、replica、他の Sentinel、CKQUORUM、直近の failover イベント。Sentinel 構成で何をすべきかわからない場合はここから始めてください。"},{"k":"scenario","v":"s_failover","l":"Sentinel による手動 failover (SENTINEL FAILOVER)","m":"Sentinel SENTINEL FAILOVER sentinel failover switch-master 計画 failover INPROG NOGOODSLAVE -failover-abort-no-good-slave NOGOODSLAVE No suitable replica to promote sentinel メンテナンス master のサーバーでメンテナンスを行う場合: Sentinel が最適な replica を master に昇格させ、他の replica とクライアントを新 master に向けます。停止は 1〜2 秒で、master が稼働中であればデータ損失はありません。"},{"k":"scenario","v":"s_replace","l":"Sentinel 構成でノードを追加 / 削除 / 交換する (SENTINEL RESET)","m":"Sentinel SENTINEL RESET sentinel reset replicaof 新しい replica 新しい sentinel sentinel 追加 sentinel 削除 古い replica が表示される num-other-sentinels known-replica known-sentinel 古い sentinel が表示される replica または Sentinel を完全に撤去した、または新規に追加した場合: 新しい replica は REPLICAOF で接続し、Sentinel に残る古い登録は SENTINEL RESET で消去します。"},{"k":"scenario","v":"s_quorum","l":"quorum と Sentinel の設定を変更する (SENTINEL SET)","m":"Sentinel SENTINEL SET quorum down-after-milliseconds failover-timeout parallel-syncs CKQUORUM NOQUORUM failover 遅い 不要な failover Sentinel の台数が変わった、または failover の発動が遅すぎる/早すぎる場合: quorum、down-after-milliseconds、failover-timeout、parallel-syncs をすべての Sentinel で変更します。"},{"k":"scenario","v":"memory","l":"メモリ逼迫: 使用量、フラグメンテーション、eviction の診断","m":"メモリとキー OOM command not allowed when used memory > 'maxmemory' OOM maxmemory used_memory evicted_keys eviction maxmemory-policy MEMORY DOCTOR mem_fragmentation_ratio fragmentation activedefrag client-output-buffer-limit メモリ不足 Out of memory: Killed process oom-killer used_memory_rss mem_clients_normal omem used_memory が maxmemory に近づいた、'OOM command not allowed' エラーが出る、eviction が増えている、RSS が想定より大きい、また"},{"k":"scenario","v":"bigkeys","l":"大きなキーとホットキーを見つける (--bigkeys、--memkeys、--hotkeys)","m":"メモリとキー --bigkeys --memkeys --hotkeys big key 大きなキー hot key ホットキー MEMORY USAGE UNLINK slowlog latency SCAN HGETALL KEYS * --keystats レイテンシ スパイク latency spike 特定のノードだけメモリや CPU が高い、レイテンシのスパイクがある、DEL に時間がかかる場合: 最も大きいキーと最もアクセスの多いキーを特定し、安全に削除します (UNLINK)。"},{"k":"add_role","v":"master","l":"master (slot を受け取る: 追加後に rebalance)","m":"空の master として参加し、その後 rebalance で slot を受け取ります。容量が増えます。新しい master 用に replica も追加してください。"},{"k":"add_role","v":"replica","l":"replica (master のコピー)","m":"master のコピーとなり、master に障害が起きたら引き継ぎます。master のメモリ量分のデータがネットワークを流れます (フル同期)。"},{"k":"rs_mode","v":"rebalance","l":"rebalance: slot を master 間で均等に配分する (空の master を含む)","m":"すべての master が均等に配分を受けます (slot のない新しい master を含む)。先にシミュレーションが表示されます。新しい master を追加した後の最も一般的な操作です。"},{"k":"rs_mode","v":"move","l":"reshard: 指定数の slot をある master から別の master へ移動する","m":"指定した数の slot をある master から別の master へ移動します: 負荷の高い/大きな master の負担を減らす、または master を段階的に空にするために使います。"},{"k":"fo_mode","v":"default","l":"計画 (デフォルト): master と同期してから引き継ぐ。データ損失なし","m":"master が稼働している必要があります。"},{"k":"fo_mode","v":"force","l":"FORCE: master に到達できない。同期を待たずに引き継ぐ","m":"master の直近の書き込みが失われる可能性があります。master の過半数による投票は引き続き必要です。"},{"k":"fo_mode","v":"takeover","l":"TAKEOVER: master の過半数も失われている。投票なしで引き継ぐ","m":"最後の手段: split brain と epoch 衝突のリスクがあります。"},{"k":"srep_op","v":"add_replica","l":"新しい replica を追加する","m":"新しいサーバーの Redis が現在の master に接続し、Sentinel が自動的に検出します。"},{"k":"srep_op","v":"rm_replica","l":"replica を完全に撤去する","m":"replica を停止し、すべての Sentinel からその登録を消去します。"},{"k":"srep_op","v":"add_sentinel","l":"新しい Sentinel を追加する","m":"新しいサーバーに Sentinel を追加します (Sentinel の総数は奇数を保つこと: 3 → 5)。"},{"k":"srep_op","v":"rm_sentinel","l":"Sentinel を完全に撤去する","m":"Sentinel を停止して他の Sentinel からその登録を消去し、その後 quorum を見直します。"}]},{"id":"redis-security","file":"install/guides/redis-security.json","group":"Redis","engineId":"redis","category":"security","title":"Redis / Valkey のセキュリティ強化 (ACL、TLS、危険なコマンド)","summary":"インストールや日常運用のガイドではありません。稼働中の Redis または Valkey (単一サーバー、replica + Sentinel、または Cluster) をダウンタイムなしで強化するための、シナリオ別の runbook です。読み取り専用のセキュリティ監査、ACL ユーザーと default ユーザーの無効化、requirepass/masterauth、bind と protected-mode、CONFIG/DEBU","level":"上級","duration":"5 分 (監査) 〜 90 分 (完全な強化)","topology":"単一サーバー、master + replica + Sentinel、または Redis Cluster","tags":["redis セキュリティ","redis security","valkey","hardening","セキュリティ強化","ACL","ACL SETUSER","aclfile","requirepass","masterauth","protected-mode","bind","rename-command","enable-protected-configs","TLS","tls-replication","sentinel パスワード","CIS"],"order":20,"steps":7,"scenarios":[{"k":"op","v":"audit","l":"セキュリティ状態の監査 (読み取り専用)","m":"監査 redis セキュリティ監査 redis security audit CIS Redis hardening セキュリティ強化 redis 公開状態 exposed redis unauthorized redis redis パスワードなし -NOAUTH crackit redis cryptominer kinsing NOAUTH Authentication required redis セキュリティチェック redis pentest 何も変更しません。パスワードなしのアクセス、default ユーザー、待ち受けアドレス、protected-mode、危険なコマンド、TLS、Sentinel のパスワード、ファイル権限を `OK` / `WARN` / `RISK` として報告します。どこから始めればよいかわからない場合はこれを選択してください。"},{"k":"op","v":"all","l":"完全な強化 (すべてを順に実施)","m":"監査 完全なセキュリティ強化 full hardening redis セキュリティプロジェクト ペネトレーションテストの指摘事項 監査 → ACL ユーザー (管理者、アプリケーション、レプリケーション、Sentinel) と default ユーザーの無効化 → bind/protected-mode/ファイアウォール → 危険なコマンドと protected config → TLS → ファイル権限 → 最終監査。replica/Sentinel ではローリングで適用し、リスクのある手順では確認を求めます。"},{"k":"op","v":"acl","l":"ACL ユーザーと default ユーザーの無効化 (Redis 6+)","m":"認証と権限 ACL ACL SETUSER aclfile default user default ユーザー NOPERM WRONGPASS invalid username-password pair -NOAUTH Authentication required user default on nopass masteruser least privilege 最小権限 NOPERM this user has no permissions to run the NOPERM this user has no permissions to access one of the keys used as arguments ACL LOG ユーザーごとのパスワード ACL SAVE 全員が単一のパスワードで (またはパスワードなしで) `default` ユーザーとして接続しています。"},{"k":"op","v":"auth","l":"パスワードなしの Redis: requirepass / masterauth (応急対応)","m":"認証と権限 requirepass masterauth auth-pass パスワードなし redis no password MASTER aborted replication with an error: NOAUTH Unable to AUTH to MASTER -NOAUTH ERR AUTH <password> called without any password configured for the default user Client sent AUTH, but no password is set パスワード設定 パスワードがまったく設定されておらず、ACL に移行する時間もない場合です。すべてのノードに共通のパスワード (`requirepass` + レプリケーション用の `masterauth`、Sentinel には `auth-pass`) を稼働"},{"k":"op","v":"net","l":"ネットワークアクセスを制限する (bind 0.0.0.0、protected-mode、ファイアウォール)","m":"ネットワークと暗号化 bind 0.0.0.0 protected-mode no DENIED Redis is running in protected mode 0.0.0.0:6379 ポート 6379 公開 shodan ファイアウォール DENIED Redis is running in protected mode because protected mode is enabled and no password is set for the default user *:6379 Could not create server TCP listening socket Redis がすべてのインターフェースで待ち受けているか、`protected-mode no` で動作しています。bind を localhost + 内部 IP に絞り、protected-mode を"},{"k":"op","v":"cmds","l":"危険なコマンドと CONFIG の悪用 (FLUSHALL、CONFIG、DEBUG、MODULE)","m":"ネットワークと暗号化 CONFIG SET dir dbfilename authorized_keys crontab FLUSHALL FLUSHDB DEBUG MODULE LOAD enable-protected-configs enable-debug-command enable-module-command rename-command @dangerous ERR CONFIG SET failed (possibly related to argument 'dir') - can't set protected config ERR DEBUG command not allowed CONFIG SET dbfilename rename-command CONFIG 悪意のあるモジュール SLAVEOF の悪用 `CONFIG SET dir/dbfilenam"},{"k":"op","v":"tls","l":"接続を暗号化する: TLS (クライアント、レプリケーション、Sentinel、cluster bus)","m":"ネットワークと暗号化 TLS SSL tls-port tls-replication tls-cluster tls-auth-clients 暗号化されていない接続 Error accepting a client connection: error:0A00010B:SSL routines::wrong version number SSL_connect certificate verify failed rediss:// Connection reset by peer tls-cert-file 暗号化された接続 encryption in transit 通信が暗号化されていません。既存ポートと並行して TLS ポートを稼働中に開き、レプリケーションと Sentinel を TLS に移行し、アプリケーションの切り替えが完了したら平文のポートを閉じます (`port 0`"},{"k":"op","v":"perms","l":"ファイル権限とサービス実行ユーザー","m":"痕跡とファイル redis.conf 権限 world readable chmod dump.rdb appendonly root で動作 running as root ファイル権限 Permission denied 640 User=redis redis root redis.conf (パスワードを含む)、ACL ファイル、RDB/AOF、ログファイルを他のユーザーが読み取れるか、Redis が root で動作しています。権限を 640/750 に絞り、所有者をサービスユーザーに変更します。"}]},{"id":"es-cluster","file":"install/guides/es-cluster.json","group":"Elasticsearch","engineId":"elasticsearch","category":"install","title":"Elasticsearch cluster の構築 (3+ ノード、TLS、Kibana)","summary":"3 ノード以上の Elasticsearch 8.x / 9.x cluster をゼロから構築します。Elastic リポジトリ、RAM に応じた heap、memory lock、vm.max_map_count、最初のノードでの自動セキュリティ設定 (TLS + elastic パスワード)、enrollment token による他ノードの参加、master/data ロールの共用または分離、Kibana のインストールと en","level":"中級","duration":"60～90 分","topology":"Elasticsearch ノード 3 台以上 (+ 任意で Kibana サーバー)","tags":["elasticsearch","elastic","kibana","cluster","クラスター","インストール","install","enrollment","tls","heap","snapshot","rhel","ubuntu"],"order":1,"steps":54,"scenarios":[]},{"id":"es-rolling-upgrade","file":"install/guides/es-rolling-upgrade.json","group":"Elasticsearch","engineId":"elasticsearch","category":"upgrade","title":"Elasticsearch rolling upgrade (8.x のマイナーアップグレードまたは 8.19 → 9.x)","summary":"インストールではありません。稼働中の Elasticsearch クラスタを、ノードを 1 台ずつアップグレードしてダウンタイムなしで新しいバージョンへ移行します (8.x 内のマイナーアップグレード、または 8.19 → 9.x のメジャーアップグレード)。事前チェック (バージョン、ヘルス、deprecation API、system feature migration)、アップグレード前の snapshot、shard alloc","level":"上級","duration":"ノードあたり 15〜30 分","topology":"3 ノード以上の既存クラスタ (+ Kibana)","tags":["elasticsearch","アップグレード","ローリングアップグレード","マイナー","メジャー","9.x","8.19","kibana","upgrade assistant","非推奨","スナップショット","ロールバック","ローリングアップグレード","ノードロール","master-eligible","deprecation api","versionlock"],"order":2,"steps":34,"scenarios":[{"k":"path","v":"minor","l":"同一メジャーバージョン内 (例: 8.18 → 8.19、9.1 → 9.2)","m":"同一メジャーバージョン内 (8.18 → 8.19、9.1 → 9.2): リポジトリは変わりませんが、deprecation チェックは実施します。中間のマイナーバージョンを飛ばすことはサポートされています。"},{"k":"path","v":"major","l":"メジャーバージョン: 8.19.x → 9.x","m":"移行元クラスタは事前に 8.19.x (最新パッチ) にアップグレードしておく必要があります。事前チェックには Upgrade Assistant / deprecation API と system feature migration の手順が含まれます。"}]},{"id":"es-snapshot","file":"install/guides/es-snapshot.json","group":"Elasticsearch","engineId":"elasticsearch","category":"backup","title":"Elasticsearch のスナップショットとリストア (fs / S3 リポジトリ、SLM)","summary":"インストール済みの Elasticsearch 8.x / 9.x クラスタにスナップショット (バックアップ) の仕組みを構築し、復旧手順を説明します。対象は、共有ファイルシステム (NFS + path.repo) または S3 (keystore) リポジトリ、rolling restart による有効化と検証、手動スナップショット (indices、include_global_state、feature_states)、SLM","level":"中級","duration":"45–90 分","topology":"Elasticsearch 8.x / 9.x クラスタ (1–N ノード) + 共有ディレクトリ (NFS) または S3 互換オブジェクトストレージ","tags":["elasticsearch","スナップショット","リストア","バックアップ","backup","復元","リポジトリ","path.repo","nfs","s3","keystore","slm","スナップショット ライフサイクル","保持期間","rename_pattern","feature_states","読み取り専用リポジトリ","移行","slm","スナップショット ライフサイクル","quartz cron","utc","netrc"],"order":15,"steps":33,"scenarios":[]},{"id":"es-ops","file":"install/guides/es-ops.json","group":"Elasticsearch","engineId":"elasticsearch","category":"ops","title":"Elasticsearch の日常運用と障害シナリオ (8.x / 9.x)","summary":"インストールではありません。インストール済みの Elasticsearch 8.x / 9.x クラスタを日常的に運用し、障害時に復旧するための、シナリオ別の runbook です。ヘルスと allocation explain、未割り当て shard の解消 (ディスク、filtering、retry_failed、replica、最後の手段としての stale/empty primary)、ディスク watermark、read_o","level":"上級","duration":"5 分 (確認) 〜 数時間 (reindex、ノードの退避)","topology":"Elasticsearch 8.x / 9.x クラスタ (1〜N ノード)、TLS と認証が有効","tags":["elasticsearch","elastic","cluster health","red","yellow","unassigned","allocation explain","reroute","retry_failed","allocate_stale_primary","watermark","flood stage","read_only_allow_delete","exclude","voting_config_exclusions","enrollment token","reindex","alias","ILM","rollover","shrink","split","snapshot restore","運用","障害対応"],"order":20,"steps":6,"scenarios":[{"k":"scenario","v":"health","l":"クラスタのヘルス: status、ノード、未割り当て shard、ディスク","m":"監視と診断 red yellow _cluster/health _cat/shards UNASSIGNED allocation explain _cluster/allocation/explain status red status yellow クラスタ ヘルス pending tasks master_not_discovered_exception NoNodeAvailableException circuit_breaking_exception heap クラスタ ヘルスチェック 読み取り専用: green/yellow/red、ノード一覧、未割り当て (UNASSIGNED) の shard とその原因 (allocation explain)、ディスク使用率と watermark、保留中のタスク。何をすべきかわからない場合はここから始めてください。"},{"k":"scenario","v":"unassigned","l":"未割り当て (UNASSIGNED) の shard を解消する (explain に基づく)","m":"監視と診断 UNASSIGNED unassigned shards NODE_LEFT ALLOCATION_FAILED max_retry shard has exceeded the maximum number of retries retry_failed no_valid_shard_copy cannot allocate because a previous copy of the primary shard existed allocate_stale_primary allocate_empty_primary the node is above the high watermark same_shard awareness filter NO_VALID_SHARD_COPY CLUSTER_RECOVERED REPLICA_ADDED cannot alloca"},{"k":"scenario","v":"watermark","l":"ディスク watermark の設定を確認 / 変更する","m":"ディスクとブロック watermark disk.watermark low disk watermark high disk watermark flood stage disk watermark ディスクフル disk full cluster.routing.allocation.disk cluster.routing.allocation.disk.watermark.high disk usage exceeded ディスク しきい値 ディスク使用率が原因で shard が移動している、または割り当てられない場合です。watermark のしきい値 (low / high / flood_stage) を一時的または恒久的に変更するか、デフォルトに戻します。"},{"k":"scenario","v":"readonly","l":"index が読み取り専用になった: read_only_allow_delete ブロックを解除する","m":"ディスクとブロック read_only_allow_delete FORBIDDEN/12/index read-only / allow delete (api) TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark cluster_block_exception index.blocks.read_only_allow_delete flood stage 読み取り専用 read-only blocked by: [FORBIDDEN/12/index read-only / allow delete (api)] index read-only 書き込み拒否 書き込みが 'FORBIDDEN/12/index read-only / allow delete (api)' または 'TOO_MANY_REQUES"},{"k":"scenario","v":"add_node","l":"クラスタにノードを追加する (enrollment token)","m":"ノード管理 ノード追加 add node enrollment token elasticsearch-create-enrollment-token elasticsearch-reconfigure-node scale out join cluster master not discovered master not discovered yet, this node has not previously joined a bootstrapped cluster 容量 増強 新規ノード 容量が必要な場合です。新しいサーバーに Elasticsearch をインストールし、enrollment token でクラスタに参加させます。shard は自動的にリバランスされます。ダウンタイムはありません。"},{"k":"scenario","v":"remove_node","l":"ノードを安全に削除する (exclude、退避、停止)","m":"ノード管理 ノード削除 remove node decommission cluster.routing.allocation.exclude._name exclude voting_config_exclusions relocating ノード 退避 voting configuration ノード 廃止 サーバー リプレース ノードを廃止する、またはハードウェアを交換する場合です。allocation exclude で shard を他のノードに移動し、ノードが空になったことを確認し、master-eligible であれば voting exclusion を設定してから停止します。"},{"k":"scenario","v":"reindex","l":"Reindex: mapping/設定の変更のために、新しい index と alias でダウンタイムなしに切り替える","m":"index 管理 _reindex reindex mapping 変更 mapper_parsing_exception illegal_argument_exception: mapper alias _aliases 無停止切り替え zero downtime task version_conflict_engine_exception cannot be changed from type mapper [ analyzer 変更 mapping のフィールド型、analyzer、または shard 数を変更する場合です。新しい index を作成し、_reindex でデータをコピーし、alias をアトミックに新しい index に切り替えます。"},{"k":"scenario","v":"ilm","l":"index lifecycle (ILM) と rollover を設定する / トラブルシューティングする","m":"index 管理 ILM index lifecycle rollover _rollover _ilm/explain is_write_index rollover_alias ilm policy index.lifecycle.name ERROR step illegal_argument_exception: index.lifecycle.rollover_alias rollover_alias does not point to index ILM ERROR index が削除されない ログ index 肥大化 ログ/時系列の index が肥大化する、または削除されない場合です。ILM ポリシー (rollover + delete)、index テンプレート、最初の index (write alias) を設定します。既存のポリシーが進まない理由は explain"},{"k":"scenario","v":"resize","l":"shard 数を修正する: _shrink (削減) / _split (増加)","m":"index 管理 _shrink _split shrink split shard 数 number_of_shards too many shards shard 過多 oversharding index.blocks.write must be read-only to resize index must have all shards allocated on the same node to shrink index number_of_routing_shards index の shard 数の選択が適切でなかった場合です。小さすぎる shard (oversharding) は _shrink で統合し、大きすぎる shard は _split で分割します。切り替えは alias で行います。"},{"k":"scenario","v":"snaprestore","l":"snapshot から単一 index を新しい名前でリストアする","m":"index 管理 snapshot restore _restore 単一 index リストア rename_pattern rename_replacement index 削除 deleted index index_not_found_exception cannot restore index because an open index with same name already exists snapshot_missing_exception 誤って削除 index 復旧 index が削除された、または破損した場合です。snapshot リポジトリからその index だけを、稼働中の index に触れずに新しい名前 (rename) でリストアし、検証後に alias で本番に切り替えます。"},{"k":"un_fix","v":"retry","l":"リトライ上限を超えた: 再試行する (_cluster/reroute?retry_failed)","m":"max_retry shard has exceeded the maximum number of retries ALLOCATION_FAILED explain: 'shard has exceeded the maximum number of retries'。先に根本のエラー (ディスク、mapping、メモリ) を解消してください。"},{"k":"un_fix","v":"replicas","l":"replica 数がノード数より多い: replica を減らす","m":"same_shard a copy of this shard is already allocated to this node explain: same_shard (同じノードにコピーは配置できません)。単一ノードのクラスタでは replica を 0 にします。"},{"k":"un_fix","v":"filter","l":"allocation filtering / exclude がブロックしている: フィルターを解除する","m":"filter node does not match index setting [index.routing.allocation node matches cluster setting [cluster.routing.allocation.exclude explain: filter decider ('node does not match index setting [index.routing.allocation…]' またはクラスタの exclude)。"},{"k":"un_fix","v":"disk","l":"ディスク watermark がブロックしている","m":"disk_threshold the node is above the low watermark the node is above the high watermark explain: disk_threshold decider。watermark のシナリオを案内します。"},{"k":"un_fix","v":"stale","l":"最後の手段: 古い (stale) コピーから primary を割り当てる","m":"no_valid_shard_copy all the copies of its data in the cluster are stale or corrupt allocate_stale_primary primary の最新のコピーが失われ、古いコピーしか残っていない場合です。そのコピーに含まれない直近の書き込みは失われます。"},{"k":"un_fix","v":"empty","l":"本当に最後の手段: 空の primary を割り当てる (shard のデータはすべて失われます)","m":"no_valid_shard_copy there are no copies of its data in the cluster allocate_empty_primary コピーが 1 つもなく、index を snapshot からリストアできない場合です。"},{"k":"wm_op","v":"show","l":"表示のみ (ディスク使用率と現在のしきい値)","m":"読み取り専用: ノードごとのディスクと現在のしきい値。"},{"k":"wm_op","v":"set","l":"しきい値を変更する","m":"しきい値を一時的に引き上げます (例: 大容量ディスクではパーセントの代わりに空き容量 `50gb`)。問題が解決したらデフォルトに戻してください。"},{"k":"wm_op","v":"reset","l":"デフォルトに戻す (85% / 90% / 95%)","m":"以前に変更したしきい値を削除し、デフォルト (85% / 90% / 95%) に戻します。"},{"k":"ilm_op","v":"setup","l":"新しいポリシー + テンプレート + 最初の index (write alias)","m":"ポリシー (rollover + 削除)、index テンプレート、最初の index (`-000001`、書き込み用 alias) を作成します。新しいログストリーム用です。"},{"k":"ilm_op","v":"debug","l":"既存の index が進まない理由 (explain、retry)","m":"index が rollover されない、または削除されない場合です。`_ilm/explain` で失敗している手順を確認し、原因を解消してから retry します。"},{"k":"ilm_op","v":"rollover","l":"手動で rollover する","m":"条件を待たずに新しい書き込み用 index を作成します (mapping 変更後や、肥大化した index の場合)。"},{"k":"rs_kind","v":"shrink","l":"_shrink: shard 数を減らす (ターゲットは現在の数の約数であること)","m":""},{"k":"rs_kind","v":"split","l":"_split: shard 数を増やす (ターゲットは現在の数の倍数であること)","m":""}]},{"id":"es-security","file":"install/guides/es-security.json","group":"Elasticsearch","engineId":"elasticsearch","category":"security","title":"Elasticsearch セキュリティ強化 (security、TLS、ロール、audit)","summary":"インストールや日常運用のガイドではありません。稼働中の Elasticsearch クラスタを強化するためのシナリオ別 runbook です。読み取り専用のセキュリティ監査、無効な security を transport TLS とともに有効化 (クラスタ全体の再起動)、HTTP TLS への rolling 移行、DBA/アプリケーション用ロール、有効期限付き API キー、緊急用 file realm ユーザー、elastic を","level":"上級","duration":"10 分 (監査) – 2 時間 (全面的な強化)","topology":"ノード 1～12 台の Elasticsearch クラスタ (+ Kibana)","tags":["elasticsearch セキュリティ","elasticsearch security","hardening","セキュリティ強化","xpack.security","TLS","elasticsearch-certutil","elasticsearch-users","API キー","role mapping","elastic superuser","anonymous","audit logging","IP filtering","kibana_system","service account token","CIS"],"order":20,"steps":4,"scenarios":[{"k":"op","v":"audit","l":"セキュリティ状態の監査 (読み取り専用)","m":"監査 elasticsearch セキュリティ監査 elasticsearch security audit CIS Elasticsearch hardening セキュリティ強化 公開された elasticsearch exposed elasticsearch xpack.security.enabled missing authentication credentials for REST request security_exception elasticsearch セキュリティチェック elasticsearch pentest RISK 何も変更しません。security が有効か、認証なしアクセス、HTTP/transport TLS、anonymous アクセス、ユーザーと elastic の使用状況、有効期限のない API キー、audit logging、IP フィ"},{"k":"op","v":"all","l":"全面的な強化 (すべてを順に)","m":"監査 全面的な強化 full hardening elastic セキュリティ対策 ペネトレーションテスト指摘事項 監査 → security + transport/HTTP TLS (無効な場合。クラスタ全体の再起動) → ユーザー/ロール/API キー、anonymous の無効化、elastic を日常業務から外す → ネットワークと IP フィルタリング → audit logging (ライセンスが許す場合) → スナップショットリポジトリへのアクセス → Kibana 接続 → 最終監査。"},{"k":"op","v":"enable","l":"Security が無効: セキュリティと transport TLS を有効化する","m":"認証と暗号化 xpack.security.enabled: false security disabled 認証なしアクセス Elasticsearch built-in security features are not enabled Transport SSL must be enabled if security is enabled invalid configuration for xpack.security.transport.ssl 7.x アップグレード セキュリティ Security is disabled xpack.security.transport.ssl 認証なし `xpack.security.enabled: false`、または 7.x からアップグレードされ、認証なしでアクセスされているクラスタ。証明書を生成し、transport (および必要に応"},{"k":"op","v":"httptls","l":"HTTP (REST) トラフィックを TLS に移行する","m":"認証と暗号化 http.ssl xpack.security.http.ssl.enabled received plaintext http traffic on an https channel plaintext http https 9200 elasticsearch-certutil http SSLHandshakeException curl: (52) Empty reply from server http:// 9200 パスワードが平文で流れる Security は有効ですが、9200 番ポートが平文 HTTP のためパスワードをネットワーク上で読み取れます。HTTP 証明書を配布し、ノードを 1 台ずつ再起動します。クライアントは `https://` に切り替えます。"},{"k":"op","v":"users","l":"ユーザー、ロール、API キー、elastic と anonymous アクセス","m":"認証と暗号化 elastic ユーザー elastic superuser superuser role mapping API キー api_key elasticsearch-users anonymous xpack.security.authc.anonymous action [indices:data/write/bulk[s]] is unauthorized is unauthorized for user unable to authenticate user action [indices:data/read/search] is unauthorized for user api キー 有効期限 有効期限なし api キー break-glass アプリケーションが `elastic` スーパーユーザーで接続している、anonymous アクセスが有効、または有効期限"},{"k":"op","v":"auditlog","l":"Audit logging を有効化する","m":"証跡とアクセス audit log xpack.security.audit.enabled audit logging _audit.json 監査証跡 誰が削除したか 個人情報保護法 (APPI) PCI DSS xpack.security.audit.logfile.events.include アクセスログ 誰がどのインデックスにアクセスしたか、失敗したログイン試行、認可拒否、セキュリティ設定の変更を記録する必要があります。`xpack.security.audit.enabled` (静的設定、rolling 再起動) — ライセンスが必要です (ステップ内でライセンスを確認します)。"},{"k":"op","v":"net","l":"ネットワークアクセスと IP フィルタリング","m":"証跡とアクセス network.host 0.0.0.0 0.0.0.0:9200 ポート 9200 公開 xpack.security.transport.filter xpack.security.http.filter ip filtering shodan firewall 0.0.0.0:9300 network.host: 0.0.0.0 _site_ グローバル IP 9200/9300 がすべてのインターフェースでリッスンしている、または誰でもアクセスできる場合。`network.host` を内部 IP に限定し、firewall と Elasticsearch の IP フィルタリングでノード、Kibana、アプリケーションネットワークだけを許可します。"},{"k":"op","v":"snapshot","l":"スナップショットリポジトリへのアクセスを保護する","m":"証跡とアクセス snapshot repo path.repo repository_exception s3.client access_key readonly repository スナップショット セキュリティ snapshot_operator Object Lock バックアップ セキュリティ スナップショットディレクトリを誰でも読める、リポジトリの管理権限が広すぎる、またはクラウドのアクセスキーが elasticsearch.yml に書かれている場合。ディレクトリのパーミッション、スナップショットオペレーター用ロール、keystore、2 つ目のクラスタでの読み取り専用リポジトリ登録を扱います。"},{"k":"op","v":"kibana","l":"Kibana の接続を保護する","m":"証跡とアクセス kibana_system elasticsearch.username: elastic kibana.yml パスワード service account token elasticsearch.serviceAccountToken xpack.encryptedSavedObjects.encryptionKey Kibana server is not ready yet unable to retrieve version information from Elasticsearch nodes value of \"elastic\" is forbidden serviceAccountToken kibana.keystore Kibana が `elastic` ユーザーまたは暗号化なしで接続しており、パスワードが kibana.yml に平文で書かれている場"}]},{"id":"mon-prometheus-grafana","file":"install/guides/mon-prometheus-grafana.json","group":"監視","engineId":null,"category":"monitoring","title":"Prometheus + Grafana によるデータベース監視","summary":"中央の監視サーバー (Prometheus、Alertmanager、Grafana) を構築し、監視対象サーバーに node_exporter と選択したデータベースの exporter (PostgreSQL、MySQL、Oracle、SQL Server、MongoDB、Redis、Elasticsearch) を追加します。最小権限の監視ユーザー、systemd サービス、基本的なアラートルール、メール/Webhook 通知、デ","level":"中級","duration":"60～120 分","topology":"監視サーバー 1 台 + 監視対象サーバー","tags":["prometheus","grafana","alertmanager","node_exporter","postgres_exporter","mysqld_exporter","oracledb_exporter","sql_exporter","mongodb_exporter","redis_exporter","elasticsearch_exporter","データベース監視","モニタリング","アラート","ダッシュボード"],"order":1,"steps":44,"scenarios":[]},{"id":"ora19-install","file":"install/guides/ora19-install.json","group":"Oracle","engineId":"oracle","category":"install","title":"Oracle Database 19c シングルインスタンスのインストール (EE / SE2)","summary":"1 台のサーバの Oracle Linux / RHEL 7.9、8、9 に Oracle Database 19c を新規にインストールします: OS の準備 (preinstall RPM または手動)、OFA ディレクトリ、Release Update を含むサイレントモードでのソフトウェアインストール、リスナー、CDB + PDB (AL32UTF8、RAM に応じた SGA/PGA、REDO、FRA、ARCHIVELOG)、H","level":"中級","duration":"90〜150 分","topology":"サーバ 1 台","tags":["oracle","19c","インストール","install","runInstaller","dbca","netca","サイレント","release update","applyRU","opatch","cdb","pdb","hugepages","rman","oracle linux","rhel","asm","ol7","マルチパス","oracle restart"],"order":1,"steps":38,"scenarios":[]},{"id":"ora23-install","file":"install/guides/ora23-install.json","group":"Oracle","engineId":"oracle","category":"install","title":"Oracle AI Database 26ai / 23ai のインストール (Linux)","summary":"1 台のサーバーに Oracle AI Database 26ai (23ai の後継で、バージョン番号 23.26.x のリリース) をインストールします。3 つの公式な方法から 1 つを選びます: 本番向けのゴールドイメージ ZIP による OFA インストール (runInstaller -setupDBHome + dbca。ファイルシステム、または事前にインストールした 26ai Oracle Restart の ASM)、手","level":"中級","duration":"45〜120 分","topology":"サーバー 1 台","tags":["oracle","26ai","23ai","ai database","インストール","install","rpm","free","gold image","setupDBHome","dbca","cdb","pdb","oracle linux","rhel","asm","oracle restart"],"order":2,"steps":30,"scenarios":[]},{"id":"ora-storage-prep","file":"install/guides/ora-storage-prep.json","group":"Oracle","engineId":"oracle","category":"install","title":"Oracle 用ストレージの準備: マルチパス、永続的なディスク名、ASM ディスク","summary":"Oracle Grid Infrastructure、Oracle Restart、またはデータベースのインストールの 前に 1 回だけ 実施します。SAN の LUN を WWID で識別し、必要に応じて DM-Multipath のエイリアスを設定し、ASM ディスクに udev ルールまたは ASMLib ラベル（AFD を選んだ場合はインストーラがラベル付けできる形）で永続的な名前と grid:asmadmin の権限を与えます","level":"中級","duration":"30～90 分","topology":"サーバー 1 台、または RAC で 2～8 ノード + SAN/iSCSI/VM ディスク","tags":["oracle","asm","multipath","device-mapper-multipath","dm-multipath","multipath.conf","wwid","udev","udev ルール","asmlib","oracleasm","afd","asm filter driver","lvm","xfs","fstab","san","lun","ストレージ","storage","ディスク","rac","oracle restart"],"order":3,"steps":10,"scenarios":[]},{"id":"ora-grid-asm","file":"install/guides/ora-grid-asm.json","group":"Oracle","engineId":"oracle","category":"install","title":"Oracle Restart: Grid Infrastructure 19c + ASM（単一サーバー）","summary":"単一サーバーへの Oracle Restart（Grid Infrastructure 19c スタンドアロン、HA_CONFIG）と ASM のインストール手順です。grid ユーザーと ASM グループ、永続的なディスク名（udev、ASMLib または ASM Filter Driver。シングルパスまたはマルチパスのディスク）、RU を同時適用する gridSetup.sh -silent、DATA と FRA のディスク・グル","level":"上級","duration":"90–150 分","topology":"サーバー 1 台 + 非共有 ASM ディスク","tags":["oracle","19c","grid infrastructure","oracle restart","asm","gridSetup","HA_CONFIG","udev","asmlib","oracleasm","afd","asm filter driver","srvctl","asmcmd","インストール","マルチパス","ol7"],"order":3,"steps":30,"scenarios":[]},{"id":"ora19-patch-ru","file":"install/guides/ora19-patch-ru.json","group":"Oracle","engineId":"oracle","category":"patch","title":"Oracle Database 19c Release Update (RU) の適用","summary":"シングル インスタンスまたは Oracle Restart (Grid Infrastructure + ASM) の 19c データベースに四半期ごとの Release Update を適用します: OPatch の更新、競合と空き領域の事前チェック、ORACLE_HOME のバックアップと保証付きリストア ポイント、opatch apply (Oracle Restart では opatchauto)、任意で OJVM RU、dat","level":"中級","duration":"60–120 分 (停止時間: in-place 30–60 分、out-of-place 10–20 分)","topology":"サーバー 1 台 (シングル インスタンスまたは Oracle Restart)。RAC はローリング パッチのガイド","tags":["oracle","19c","パッチ","release update","ru","opatch","opatchauto","datapatch","ojvm","out-of-place","ロールバック","リストア ポイント","oracle restart","rac","ローリング","standby-first","data guard","スタンバイ","1265700.1"],"order":10,"steps":25,"scenarios":[]},{"id":"ora19-rac","file":"install/guides/ora19-rac.json","group":"Oracle","engineId":"oracle","category":"ha","title":"Oracle RAC 19c のインストール (Grid Infrastructure + ASM + RAC データベース)","summary":"2 台以上のノードに Oracle Grid Infrastructure 19c (Flex ASM、SCAN) と Oracle RAC 19c データベースを新規にインストールします。ネットワークと DNS の設計、共有ディスクの準備 (udev または ASMLib、マルチパスまたはシングルパス)、ユーザーと SSH、cluvfy、インストール時に RU を適用するサイレントモードの gridSetup/runInstaller","level":"上級","duration":"4〜6 時間","topology":"2〜8 ノード + 共有ディスク (SAN/iSCSI) + DNS 上の SCAN","tags":["oracle","rac","19c","grid infrastructure","clusterware","asm","scan","gridsetup","dbca","srvctl","crsctl","クラスタ","高可用性","udev","asmlib","マルチパス","ol7","scan","ocr","投票ディスク"],"order":10,"steps":68,"scenarios":[]},{"id":"ora-rac-patch","file":"install/guides/ora-rac-patch.json","group":"Oracle","engineId":"oracle","category":"patch","title":"Oracle RAC 19c ローリング Release Update (opatchauto)","summary":"稼働中の 2～8 ノード構成 RAC 19c クラスタに、四半期ごとの GI Release Update を停止なし (rolling) で適用します。OPatch の更新、opatchauto analyze による競合チェック、OCR バックアップとフォールバック・ポイント、サービスを再配置しながらのノード単位の適用、datapatch の単一ノードでの完了、検証、必要に応じたロールバックまでを扱います。シングル・インスタンスおよ","level":"上級","duration":"ノードあたり 45～90 分","topology":"既存の 2～8 ノード構成 RAC 19c","tags":["oracle","rac","19c","パッチ","release update","ru","opatchauto","opatch","datapatch","ローリング","grid infrastructure","ロールバック","scan","サービス","standby-first","srvctl"],"order":11,"steps":38,"scenarios":[]},{"id":"ora-rac-ops","file":"install/guides/ora-rac-ops.json","group":"Oracle","engineId":"oracle","category":"ops","title":"Oracle RAC の日常運用と障害シナリオ","summary":"構築済みで稼働中の Oracle RAC (Grid Infrastructure 19c) クラスタの日常運用と障害対応: ヘルス・チェック、ノード・エビクションの診断、ノードのメンテナンス、クラスタ全体の計画停止と起動、ノードの追加と削除、サービス管理 (preferred/available、AC/TAC)、SCAN/VIP/ポート/インターコネクトの変更、OCR/OLR のバックアップとリストア、OCR と投票ファイルの移動。イ","level":"上級","duration":"15 分～3 時間 (シナリオによる)","topology":"既存の 2～8 ノード RAC (Grid Infrastructure 19c。23ai/26ai の違いは注記を参照)","tags":["oracle","rac","grid infrastructure","clusterware","crsctl","srvctl","olsnodes","cluvfy","addnode","ノード追加","ノード削除","delete node","ocr","olr","voting disk","votedisk","ocrconfig","ocrcheck","scan","vip","oifcfg","インターコネクト","エビクション","ocssd","misscount","サービス","relocate","application continuity","taf","fan","日常運用","障害"],"order":12,"steps":10,"scenarios":[{"k":"scenario","v":"health","l":"クラスタのヘルス・チェック (日次 / メンテナンス前)","m":"確認と診断 crsctl check cluster crsctl stat res -t cluvfy OFFLINE のリソース CRS-4535 CRS-4530 CRS-4639 health check ヘルス・チェック INTERMEDIATE CRS-4537 CRS-2765 CRS-2878 CRS-4700 CRS-4701 crsctl check crs クラスタの状態 cluster status リソース停止 resource offline orachk tfactl メンテナンス前チェック 何も変更しません。Clusterware スタック、リソース、OCR/投票ファイル、ASM、インターコネクト、時刻、最近のアラートを確認します。日次チェック、各メンテナンスやパッチの前、問題の報告を受けたときの最初の作業として選択します。"},{"k":"scenario","v":"eviction","l":"ノードがクラスタから排除された、または勝手に再起動した (エビクションの診断)","m":"確認と診断 CRS-1609 CRS-1610 CRS-1611 CRS-1612 CRS-1615 CRS-1625 CRS-1632 CRS-1656 CRS-8011 node eviction evicted node reboot split brain ocssd.trc misscount disktimeout ノード・エビクション CRS-1601 CRS-1606 CRS-1607 CRS-1608 CRS-1613 CRS-1614 CRS-8013 ORA-29740 ORA-29770 IPC Send timeout network heartbeat disk heartbeat ノード再起動 サーバーが勝手に再起動した rebootless restart instance eviction 読取り専用: ノードが予期せず再起動した場合や、クラスタから排除さ"},{"k":"scenario","v":"stopnode","l":"メンテナンスのためにノードを停止して再起動する","m":"起動 / 停止 crsctl stop crs crsctl start crs ノードのメンテナンス OS パッチ reboot CRS-4133 CRS-4123 drain_timeout srvctl stop instance CRS-2673 CRS-2677 CRS-2675 crsctl disable crs crsctl enable crs メンテナンス・モード maintenance kernel update カーネル更新 firmware ノードで OS パッチ、カーネル、ハードウェアのメンテナンスを行う場合に選択します。他のノードは稼働を続けます。そのノードのインスタンスのサービスは移動され、セッションはドレイン時間の経過後に終了します。"},{"k":"scenario","v":"stopall","l":"クラスタ全体を計画停止して起動する","m":"起動 / 停止 crsctl stop cluster -all crsctl start cluster -all 全停止 cluster shutdown 計画停止 srvctl stop database CRS-2677 CRS-4133 CRS-4123 crsctl stop crs crsctl start crs SAN メンテナンス データセンター・メンテナンス datacenter maintenance power off 全サーバー停止 SAN やデータセンターのメンテナンスなど、全ノードを同時に停止する必要がある場合に選択します。完全停止: 全ノードですべてのデータベース、ASM、Clusterware が停止します。"},{"k":"scenario","v":"addnode","l":"クラスタに新しいノードを追加する","m":"ノードの追加 / 削除 addnode.sh addNode gridSetup.sh -addNode ノード追加 add node cluvfy stage -pre nodeadd dbca -addInstance INS-06006 PRVG- PRVF- INS-13013 INS-40912 CLSRSC-184 PRVG-11050 PRVF-4664 PRVF-7617 cvuqdisk new node 新規サーバー追加 クラスタ拡張 新しいサーバーをクラスタに参加させる場合に選択します (容量増強、ハードウェア更改)。無停止: 事前チェック (cluvfy)、Grid home (addnode.sh)、DB home と新しいインスタンス (dbca -addInstance)。"},{"k":"scenario","v":"delnode","l":"クラスタからノードを削除する","m":"ノードの追加 / 削除 crsctl delete node deinstall -local dbca -deleteInstance ノード削除 delete node remove node cluvfy stage -post nodedel crsctl unpin css CRS-4658 CRS-4661 runInstaller -updateNodeList srvctl remove instance decommission サーバーをクラスタから外す 旧サーバーの撤去 サーバーをクラスタから恒久的に外す場合に選択します (返却、ハードウェア故障)。インスタンスを削除し、そのノードから DB home と Grid home を削除して、ノードをクラスタから削除します。他のノードはオープンのままです。"},{"k":"scenario","v":"service","l":"サービスを追加、変更、移動、削除する","m":"サービスとネットワーク srvctl add service srvctl modify service srvctl relocate service srvctl remove service ORA-12514 PRCD-1026 preferred available TAF Application Continuity TAC FAN サービス移動 PRKO-2017 PRCR-1090 ORA-12514: TNS:listener does not currently know of service srvctl start service srvctl status service failback サービスが戻らない drain_timeout サービス追加 create service アプリケーションが接続するサービスを定義する場合、配置 (preferred/ava"},{"k":"scenario","v":"net","l":"SCAN、VIP、リスナー・ポート、インターコネクトの変更","m":"サービスとネットワーク srvctl modify scan srvctl modify scan_listener srvctl modify nodeapps srvctl modify listener oifcfg setif oifcfg delif oifcfg getif IP アドレス変更 SCAN IP VIP 変更 インターコネクト private network ORA-12545 listener port PRCS-1034 PRKO-2310 PRCR-1079 oifcfg HAIP 169.254 ポート変更 SCAN 変更 VIP change remote_listener ASMNET1LSNR_ASM SCAN 名/IP、ノードの VIP、リスナー・ポート、プライベート・ネットワーク (インターコネクト) を変更する場合に選択します。インターコネクト"},{"k":"scenario","v":"ocr_backup","l":"OCR と OLR のバックアップを取得し、バックアップを確認する","m":"OCR、OLR、投票ファイル ocrconfig -manualbackup ocrconfig -showbackup ocrconfig -local -manualbackup OLR バックアップ OCR バックアップ OCR backup ocrcheck ocrdump PROT- ocrconfig -copy ocrconfig -showbackuploc OLR backup OCR バックアップの場所 OCR 手動バックアップ 停止なし: OCR の手動バックアップ、各ノードでの OLR バックアップ、バックアップのクラスタ・ディスク外へのコピー。パッチ、ノードの追加/削除、ネットワーク変更など、リスクのある作業の前に必ず選択します。"},{"k":"scenario","v":"ocr_restore","l":"OCR の破損または CRS ディスク・グループの喪失: バックアップからリストアする","m":"OCR、OLR、投票ファイル PROT-602 PROC-26 CRS-4535 CRS-4000 CRS-1606 ocrconfig -restore crsctl start crs -excl -nocrs OCR corruption OCR 破損 CRS ディスク・グループ喪失 投票ディスク喪失 ORA-15017 ORA-15063 PROT-35 PROT-19 ORA-15018 ORA-15033 ocrdump OCR restore CRSD が起動しない Logical corruption check failed `ocrcheck` が破損を示す場合、CRSD が起動しない場合 (PROT-/PROC- エラー)、または CRS ディスク・グループが完全に失われた場合に選択します。クラスタ全体が停止します。OCR を排他モードでバックアップからリストアし、デ"},{"k":"scenario","v":"olr_restore","l":"1 つのノードで Clusterware が起動しない: OLR の破損","m":"OCR、OLR、投票ファイル ocrcheck -local ocrconfig -local -restore OLR 破損 OLR corrupt ohasd が起動しない CRS-4124 CRS-4639 PROCL- CRS-4123 ohasd.trc olr.loc ocrconfig -local -showbackup Local registry integrity check failed OHASD が起動しない 1 ノードだけ起動しない 他のノードは稼働しているのに、1 つのノードだけで `crsctl start crs` が OHASD を起動できず、`ocrcheck -local` が OLR エラーを返す場合に選択します。影響はそのノードだけです。OLR をバックアップからリストアします。"},{"k":"scenario","v":"ocrvote_move","l":"OCR と投票ファイルを別のディスク・グループに移動する","m":"OCR、OLR、投票ファイル crsctl replace votedisk crsctl query css votedisk ocrconfig -add ocrconfig -delete 投票ディスク移動 votedisk OCR 移動 storage migration ORA-15274 ocrconfig -backuploc asmcmd spmove asmcmd pwmove CRS ディスク・グループ移動 投票ファイル移動 OCR move ストレージ入れ替え 無停止: ocrconfig -add/-delete と crsctl replace votedisk。ストレージ (SAN) の入れ替え時、CRS ディスク・グループの冗長性を上げる場合、OCR を 2 つ目のディスク・グループにも書き込む場合に選択します。"}]},{"id":"ora-asm-ops","file":"install/guides/ora-asm-ops.json","group":"Oracle","engineId":"oracle","category":"ops","title":"Oracle ASM の日常運用と障害シナリオ","summary":"構築済みの Oracle Restart または RAC における ASM ディスクグループの日常運用と障害時の対応です。容量チェック (usable_file_mb)、リバランスの監視、ディスクの追加/交換/削除、オフラインディスク、新規ディスクグループ、マウント/ディスマウント、ASM 構成のバックアップ、検出文字列を扱います。ASM のインストールは扱いません (インストール: Oracle Restart または RAC のガイ","level":"上級","duration":"10 分～数時間 (リバランスの所要時間による)","topology":"Oracle Restart (単一サーバー) または 2～8 ノードの RAC、Grid Infrastructure 19c (23ai/26ai との違いは注記を参照)","tags":["oracle","asm","disk group","diskgroup","add disk","drop disk","replace disk","rebalance","v$asm_operation","usable_file_mb","disk_repair_time","online disk","offline disk","failgroup","compatible.asm","asmcmd","spbackup","md_backup","asm_diskstring","dsset","udev","asmlib","afd","multipath","rac","oracle restart","日常運用","障害"],"order":13,"steps":4,"scenarios":[{"k":"op","v":"capacity","l":"容量とディスクグループの健全性チェック","m":"チェックと監視 usable_file_mb required_mirror_free_mb asmcmd lsdg ディスクグループ 満杯 ASM 使用率 free_mb 容量 ORA-15041 ORA-01653 ORA-17502 ORA-15041: diskgroup space exhausted diskgroup space exhausted disk group full ASM disk group full usable_file_mb マイナス negative usable_file_mb ASM 空き容量不足 asmcmd du 何も変更しません。ディスクグループがいっぱいか、残り容量はどれだけか (冗長性ごとの usable_file_mb の正しい読み方)、オフラインディスク、ディスクの偏り、互換性属性を確認します。容量の問題、アラート、定期チェックで最"},{"k":"op","v":"rebal","l":"リバランスを監視する、速くする、遅くする","m":"チェックと監視 v$asm_operation gv$asm_operation rebalance REBALANCE POWER asm_power_limit asmcmd lsop est_minutes resync compact リバランス 遅い rebalance slow リバランス 止まった rebalance hung ERRS ARB0 リバランス いつ終わる 実行中のリバランス/再同期の進捗と残り時間 (v$asm_operation、est_minutes)、および POWER の変更。データベースはオープンしたままで、I/O 負荷だけが変わります。"},{"k":"op","v":"add","l":"ディスクグループに新しいディスクを追加する","m":"ディスク操作 ADD DISK ALTER DISKGROUP ADD DISK ディスク追加 空き容量の確保 容量拡張 ORA-15041 ORA-15031 ORA-15033 ORA-15014 ORA-15410 ORA-15032 ORA-15075 ORA-17502 add disk 新規 LUN new LUN ディスクグループ 拡張 extend diskgroup ディスクグループの空き容量が減った、または拡張が必要な場合です。新しい LUN をすべてのノードで準備し (multipath/udev/ASMLib/AFD)、ADD DISK で追加し、リバランスを監視します。データベースはオープンしたままです。"},{"k":"op","v":"replace","l":"ディスクを新しいディスクと交換する (REPLACE DISK)","m":"ディスク操作 REPLACE DISK ディスク交換 replace disk ORA-15145 storage migration ディスク更新 ORA-15221 ORA-15033 replace failed disk 障害ディスク 交換 disk replacement ストレージ移行 storage migration ASM 障害が発生した (オフラインの) ディスク、または更新対象のディスクを 1 回の操作で新しいディスクに交換します。そのディスクのデータだけがコピーされます (12.1 以降、NORMAL/HIGH)。EXTERNAL では追加と削除を 1 つのコマンドで行います。データベースはオープンしたままです。"},{"k":"op","v":"drop","l":"ディスクグループからディスクを削除する","m":"ディスク操作 DROP DISK ディスク削除 UNDROP DISKS FORMER ORA-15041 ORA-15067 LUN 返却 drop disk DROPPING ディスク取り外し remove disk from diskgroup LUN を返す LUN を返却する、またはストレージから外す場合です。DROP DISK でデータを残りのディスクに移動します。リバランスが終わってディスクが FORMER になるまで、ディスクは取り外しません。データベースはオープンしたままです。"},{"k":"op","v":"failed","l":"ディスクがオフラインまたは障害 (NORMAL/HIGH 冗長性)","m":"ディスク操作 ONLINE DISK OFFLINE DISK disk_repair_time repair_timer mode_status OFFLINE ORA-15042 ORA-15040 ORA-15130 ORA-15063 missing disk disk offline fast mirror resync ORA-15080 ORA-15081 ORA-27061 ORA-27072 ORA-15066 WARNING: Write Failed WARNING: Read Failed remaining active paths: 0 ディスク オフラインになった SYNCING ディスク 読み取れない I/O error ASM NORMAL/HIGH のディスクグループでディスクが OFFLINE と表示される、またはアラートログに書き込み/読み取りエラー"},{"k":"op","v":"create","l":"新しいディスクグループを作成する","m":"ディスクグループ管理 CREATE DISKGROUP ディスクグループ作成 au_size compatible.asm compatible.rdbms failgroup ORA-15018 ORA-15221 ORA-15072 ORA-15031 ORA-15033 create diskgroup new disk group 新規ディスクグループ データ、FRA、アプリケーション用の新しいディスクグループを作成する場合です。冗長性、AU サイズ、compatible.asm/rdbms 属性、RAC ではすべてのノードでのマウントと Clusterware リソースを扱います。既存のディスクグループには影響しません。"},{"k":"op","v":"mount","l":"ディスクグループをマウントまたはディスマウントする","m":"ディスクグループ管理 srvctl start diskgroup srvctl stop diskgroup ALTER DISKGROUP MOUNT DISMOUNT ORA-15027 ORA-15017 ディスクグループ マウントできない v$asm_client ORA-15063 ORA-15040 ORA-15130 ORA-15032 ORA-15042 PRCR-1065 CRS-2674 MOUNT FORCE diskgroup dismounted ディスクグループ オープンできない insufficient number of disks ディスクグループを計画的に停止する (ディスマウント) 場合、または停止中/オープンできないディスクグループをオープンする (マウント) 場合です。すべてのノードで srvctl start/stop diskgroup を使"},{"k":"op","v":"spbackup","l":"ASM の spfile、パスワードファイル、メタデータのバックアップ","m":"構成 asmcmd spbackup asmcmd spget asmcmd pwget asmcmd pwcopy md_backup md_restore ASM spfile バックアップ orapwASM asmcmd spcopy GPnP profile profile.xml ASM password file backup ASM metadata backup ASM バックアップ 停止不要です。ASM の spfile、パスワードファイル、ディスクグループ構造 (md_backup)、RAC では GPnP プロファイルを ASM の外にバックアップし、ディスクグループを失っても ASM 構成を再構築できるようにします。構築後と、構造を変更するたびに実行してください。"},{"k":"op","v":"dstring","l":"ASM ディスク検出文字列 (asm_diskstring) を変更する","m":"構成 asm_diskstring asmcmd dsset asmcmd dsget discovery string 検出文字列 ORA-15014 kfod ORA-15020 discovered duplicate ASM disk afd_dsset asm_diskstring change ディスクが見つからない ASM がディスクを探すパスのパターンを変更する場合です (例: multipath への移行、新しい udev ディレクトリ、ASMLib/AFD)。まず kfod で試し、その後 asmcmd dsset を実行します。既存のすべてのディスク (OCR/投票ディスクを含む) が新しい文字列でも検出される必要があります。"}]},{"id":"ora-autoupgrade","file":"install/guides/ora-autoupgrade.json","group":"Oracle","engineId":"oracle","category":"upgrade","title":"19c → Oracle AI Database 26ai (23ai) へのアップグレード: AutoUpgrade","summary":"メジャーリリースのアップグレード (19c → 26ai) に使用します。同一リリース内の四半期 RU には「Oracle Database 19c Release Update (RU) の適用」ガイドを使用します。Oracle が推奨する AutoUpgrade ツールを使い、最新の autoupgrade.jar、構成ファイル、analyze → fixups → deploy、保証付きリストア・ポイントによる自動フォールバック・","level":"上級","duration":"2～4 時間 (停止時間: データベースのサイズとコンポーネントに応じて 30～90 分)","topology":"サーバー 1 台、Oracle Restart または RAC (26ai home は全ノードに必要)","tags":["oracle","アップグレード","autoupgrade","19c","26ai","23ai","非CDB","pdb","target_cdb","リストア・ポイント","restoration","タイムゾーン","compatible","ロールバック","rac","oracle restart","cluster_database","srvctl"],"order":20,"steps":25,"scenarios":[]},{"id":"ora-dataguard","file":"install/guides/ora-dataguard.json","group":"Oracle","engineId":"oracle","category":"ha","title":"Oracle Data Guard 19c physical standby (Broker 使用、シングル・インスタンス、Oracle Restart、RAC)","summary":"稼働中の 19c primary データベースに対して RMAN DUPLICATE … FROM ACTIVE DATABASE で physical standby を構築し、Data Guard Broker に追加します。最終的に、REDO をリアルタイムで受信・適用するスタンバイ、SUCCESS ステータスの broker 構成、テスト済みの switchover (任意で failover/reinstate のテストと F","level":"上級","duration":"2～4 時間 (データ量による)","topology":"primary (シングル・インスタンス / Oracle Restart / RAC 2～8 ノード) + physical standby (シングル・インスタンス / Oracle Restart / RAC) + 任意の observer","tags":["oracle","data guard","dataguard","スタンバイ","フィジカル・スタンバイ","dgmgrl","ブローカー","rman duplicate","switchover","failover","fast-start failover","オブザーバー","19c","災害対策","rac","oracle restart","srvctl","スタンバイREDOログ","apply インスタンス"],"order":20,"steps":43,"scenarios":[]},{"id":"ora-datapump","file":"install/guides/ora-datapump.json","group":"Oracle","engineId":"oracle","category":"backup","title":"Oracle Data Pump: エクスポート / インポート、データ移行、スキーマ・リフレッシュ、トランスポータブル","summary":"expdp/impdp による表、スキーマ、表領域または全体（FULL）単位のエクスポート、インポート、2つのデータベース間の移行（ダンプ・ファイル + scp + チェックサム、または NETWORK_LINK）、ダンプからの DDL 抽出（SQLFILE）。ディレクトリ、ユーザー、パラメータ・ファイルの準備、一貫性、パラレル化、リマップ、監視、中断したジョブのクリーンアップを含みます。RAC では SCAN + サービス接続、共有デ","level":"中級","duration":"30～90分（データ量による）","topology":"データベース1つ（シングル・インスタンス、Oracle Restart または RAC）。移行ではソース + ターゲット","tags":["oracle","data pump","datapump","expdp","impdp","エクスポート","インポート","ダンプ","parfile","remap_schema","network_link","sqlfile","table_exists_action","flashback_time","データ移行","migration","logical backup","論理バックアップ","rac","scan","cluster","acfs","cron","wallet","スケジュール","refresh","スキーマ・リフレッシュ","prod to test","drop user cascade","transportable tablespace","tts","xtts","full transportable","transportable=always","dbms_tts","transport_set_check","endian","rman convert","cross-platform","11g to 19c","non-cdb to pdb","encryption","encryption_password","compression","attach","kill_job","start_job","continue_client","orphan","dba_datapump_jobs","lob","securefile","data_options"],"order":20,"steps":16,"scenarios":[{"k":"op","v":"export","l":"エクスポート: データベースからダンプ・ファイルを作成する","m":"エクスポート / インポート expdp エクスポート ダンプ取得 論理バックアップ logical backup ORA-39001 ORA-39000 ORA-39070 ORA-31633 ORA-01555 ORA-39095 ORA-39094 ORA-00439 LRM-00123 UDE-00002 ORA-39127 表、スキーマ、表領域またはデータベース全体をダンプ・ファイルに書き出します（expdp）。データベースはオープンのままで、アプリケーションも稼働を続けます。論理コピーであり、RMAN バックアップの代わりにはなりません（Point-in-Time リカバリと完全リカバリには RMAN が必要です）。"},{"k":"op","v":"import","l":"インポート: ダンプ・ファイルをデータベースにロードする","m":"エクスポート / インポート impdp インポート ダンプのロード REMAP_SCHEMA REMAP_TABLESPACE TABLE_EXISTS_ACTION ORA-39002 ORA-39087 ORA-39142 ORA-39143 ORA-39083 ORA-12899 ORA-39171 ORA-39082 ORA-31684 ORA-31640 ORA-39059 ORA-01917 ORA-39151 ORA-39111 ORA-01653 ORA-30036 取得済みのダンプ・ファイルを impdp でロードします。スキーマ名、表領域名、表名はリマップできます。ターゲットはオープンのままですが、ロードするオブジェクトを使うアプリケーションは停止する必要があります。"},{"k":"op","v":"move","l":"移行: ソース・データベースからターゲットへデータを移す","m":"移行とリフレッシュ データ移行 migration NETWORK_LINK データベース・リンク scp チェックサム ORA-31679 ORA-02085 ORA-39183 エクスポート → ファイル・コピー → インポート、または NETWORK_LINK でダンプ・ファイルを使わず直接移行します。ターゲットにスキーマがまだない場合（初回ロード）はこのカードを選択します。ターゲットに同じスキーマがすでにあり、本番のものと置き換える場合は「スキーマ・リフレッシュ」カードを選択します。ソースはオープンのままです。"},{"k":"op","v":"sqlfile","l":"ダンプ・ファイルから DDL のみを抽出する (SQLFILE)","m":"エクスポート / インポート SQLFILE DDL 抽出 ダンプの内容 ダンプの中身 メタデータ DBMS_METADATA 何もロードされず、オブジェクトの CREATE 文が .sql ファイルに書き出されます。データベースは変更されません。"},{"k":"op","v":"refresh","l":"本番からテストへのスキーマ・リフレッシュ (refresh)","m":"移行とリフレッシュ refresh スキーマ・リフレッシュ テスト環境のリフレッシュ prod to test 本番からテストへ UAT リフレッシュ DROP USER CASCADE ORA-01940 ORA-02380 ORA-01917 ORA-31684 ORA-00031 TABLE_EXISTS_ACTION=REPLACE テスト/UAT にすでにあるスキーマを、本番の最新の状態で置き換えます。ターゲット・スキーマのバックアップ、セッションの切断、DROP USER … CASCADE または TABLE_EXISTS_ACTION=REPLACE、パスワード/プロファイルと権限の保持を行います。ソースはオープンのままですが、ターゲット・スキーマは作業中は使用できません。"},{"k":"op","v":"tts","l":"データファイルのコピーで表領域を移す (トランスポータブル表領域)","m":"トランスポータブル (データファイルのコピー) transportable tablespace TTS XTTS TRANSPORT_TABLESPACES TRANSPORT_DATAFILES DBMS_TTS TRANSPORT_SET_CHECK endian cross-platform RMAN CONVERT ORA-29335 ORA-29341 ORA-29342 ORA-29345 ORA-29349 ORA-19722 ORA-01647 大きな表領域（数百 GB 以上）は、行単位ではなくデータファイルをコピーして移します。同一または異なるプラットフォーム/エンディアン（RMAN CONVERT）に対応します。キャラクタ・セットは両側で同じである必要があります。ソースでは作業中、表領域が READ ONLY になります（書込みの停止）。"},{"k":"op","v":"fulltts","l":"データベース全体を移す: フル・トランスポータブル (11g/12c → 19c, 非CDB → PDB)","m":"トランスポータブル (データファイルのコピー) full transportable TRANSPORTABLE=ALWAYS FULL=Y VERSION=12 11g to 19c 11g から 19c へ non-CDB to PDB PDB への移行 migration upgrade by migration ORA-39123 ORA-01647 ORA-29349 ORA-39127 FULL=Y TRANSPORTABLE=ALWAYS により、ユーザー表領域はデータファイルとして、それ以外のすべて（ユーザー、PL/SQL、権限）はメタデータとして新しい PDB に移されます。11.2.0.3 以上のソースでは VERSION=12 を指定します。ソースでは作業中、すべてのユーザー表領域が READ ONLY になります。"},{"k":"op","v":"jobfix","l":"中断 / 停滞した Data Pump ジョブ: 監視、再開、終了","m":"監視と障害 ATTACH START_JOB CONTINUE_CLIENT KILL_JOB STOP_JOB dba_datapump_jobs orphan マスター表 NOT RUNNING IDLING 停滞 resumable ORA-39171 ORA-31626 ORA-31633 ORA-39002 ORA-31634 ORA-39097 ORA-39126 expdp/impdp ジョブが停滞している（resumable wait）、停止している、または中断した状態です。ATTACH で接続して再開する、KILL_JOB で終了する、あるいは孤立したマスター表をクリーンアップします。データベースはオープンのままです。"}]},{"id":"ora-dataguard-ops","file":"install/guides/ora-dataguard-ops.json","group":"Oracle","engineId":"oracle","category":"ops","title":"Oracle Data Guard の日常運用と障害シナリオ (19c / 23ai)","summary":"構築済みの Data Guard (physical standby) 構成の日常運用と障害リカバリの runbook です。構築には Data Guard 構築ガイドを使用します。何をすべきか確信がない場合は「ステータスとラグの確認」から始めてください。読み取り専用の診断で適切なシナリオに誘導されます (計画的 switchover、failover、旧 primary の reinstate、アーカイブ・ギャップ、RECOVER …","level":"上級","duration":"5 分 (確認) – 4 時間 (再構築)","topology":"Primary (シングル・インスタンス / Oracle Restart / RAC) + physical standby (シングル・インスタンス / Oracle Restart / RAC) + 任意で observer","tags":["oracle","data guard","dataguard","standby","physical standby","dgmgrl","broker","switchover","failover","reinstate","archive gap","fal","recover from service","roll forward","snapshot standby","active data guard","redo apply","mrp","apply lag","transport lag","protection mode","fast-start failover","fsfo","observer","standby_file_management","standby redo log","unnamed","rman","runbook","dr","rac","19c","23ai"],"order":21,"steps":5,"scenarios":[{"k":"scenario","v":"health","l":"ステータスとラグの確認 (すべて正常か)","m":"監視と確認 ORA-16809 ORA-16810 ORA-16853 ORA-16855 ORA-16857 ORA-16766 ORA-16825 apply lag transport lag 遅延 lag SHOW CONFIGURATION WARNING Data Guard ステータス ORA-16854 ORA-16856 ORA-16191 ORA-16198 ORA-03135 ORA-16714 ORA-16792 ORA-16047 スタンバイ 遅れ transport lag 大きい Data Guard ヘルスチェック health check 読み取り専用: 構成、transport/apply lag、アーカイブ・ギャップ、プロセスとアラート・ログを確認し、何も変更しません。何をすべきか確信がない場合はここから始めてください。最後のステップで出力に応じた適切"},{"k":"scenario","v":"switchover","l":"計画的 switchover (ロールを入れ替える)","m":"ロール変更 switchover ロール変更 role transition DR 訓練 ORA-16475 ORA-16470 ORA-16467 Ready for Switchover ORA-16541 ORA-16516 switchover_status TO STANDBY SESSIONS ACTIVE switchback ロールを元に戻す 計画メンテナンス サイト切替 primary とスタンバイは正常で、ロールを計画的に入れ替えたい場合です (メンテナンス、DR 訓練、ロールを元に戻す)。データ損失はなく、アプリケーションは数分間停止します。primary にアクセスできる限り、ロール変更には常にこちらを選んでください。"},{"k":"scenario","v":"failover","l":"primary 喪失: スタンバイへ failover","m":"障害とリカバリ failover primary クラッシュ primary down サイト喪失 disaster ORA-16472 ORA-01034 ORA-12541 FAILOVER TO ACTIVATE PHYSICAL STANDBY ORA-12514 ORA-12170 ORA-03113 ORA-16625 ORA-16778 primary 接続不可 データセンター喪失 FAILOVER TO IMMEDIATE 緊急時 primary にアクセスできず、復旧の見込みもない場合です (サーバー、ストレージ、サイトの喪失)。スタンバイが primary になります。元に戻せません。MaxPerformance では直前数秒のデータが失われる可能性があり、旧 primary は後で reinstate か再構築が必要です。primary にまだアクセスできる場合は s"},{"k":"scenario","v":"reinstate","l":"failover 後に旧 primary をスタンバイとして戻す (reinstate)","m":"障害とリカバリ reinstate ORA-16661 ORA-16795 ORA-38729 ORA-16653 needs to be reinstated 旧 primary flashback ORA-16649 split-brain 旧 primary がオープンしない FastStartFailoverAutoReinstate REINSTATE DATABASE standby_became_primary_scn failover が行われ、旧 primary サーバーが復旧した場合です。Flashback Database が有効であれば、再構築せずに新 primary のスタンバイにします。新 primary はオープンのままです。flashback が無効、またはフラッシュバックの期間が足りない場合は、診断ステップで再構築に誘導されます。"},{"k":"scenario","v":"gap","l":"アーカイブ・ギャップ (gap): スタンバイが欠落したアーカイブ・ログを待っている","m":"障害とリカバリ archive gap アーカイブ・ギャップ v$archive_gap FAL Fetching gap ORA-00308 ORA-16401 ORA-27037 ORA-16055 gap sequence waiting for log WAIT_FOR_GAP FAL[client] Media Recovery Waiting for thread アーカイブログ 欠落 missing archive log ORA-16089 `v$archive_gap` が行を返す、またはアラート・ログに FAL/gap メッセージがあり、apply がある順序番号で止まっています。データベースはオープンのままです。欠落したアーカイブ・ログがどこにもない場合は、フォームの選択でロールフォワードの手順に切り替えます。"},{"k":"scenario","v":"rollfwd","l":"スタンバイが大きく遅れている、またはアーカイブ・ログがない: ロールフォワード (RECOVER FROM SERVICE)","m":"障害とリカバリ roll forward ロールフォワード RECOVER STANDBY DATABASE FROM SERVICE nologging ORA-01578 ORA-26040 スタンバイ 遅延 resync 再同期 ORA-10567 BACKUP INCREMENTAL FROM SCN スタンバイ 数日遅れ NONLOGGED BLOCK incremental roll forward ギャップ分のアーカイブ・ログがどこにもない、NOLOGGING 操作でスタンバイが破損した、またはスタンバイが何日も遅れている場合です。スタンバイを再構築せずに primary から増分で同期します (18c 以降)。"},{"k":"scenario","v":"rebuild","l":"スタンバイを一から再構築する","m":"障害とリカバリ rebuild スタンバイ 再構築 re-create standby ORA-16795 DUPLICATE スタンバイ 喪失 制御ファイル 喪失 ORA-00205 ORA-01157 スタンバイ ファイル削除 DROP DATABASE スタンバイ ディスク障害 reinstate (flashback なし) もロールフォワードもできない、またはスタンバイのファイル/制御ファイルが失われた場合です。スタンバイを削除して DUPLICATE で作り直します。primary はオープンのままですが、再構築が終わるまで保護されません (他のスタンバイがない場合)。"},{"k":"scenario","v":"snapshot","l":"snapshot standby への変換 / 戻す (テスト用の書込み可能なコピー)","m":"テストと参照 snapshot standby CONVERT TO SNAPSHOT STANDBY テスト環境 read write standby ORA-16000 ORA-38784 ORA-16433 CONVERT TO PHYSICAL STANDBY SNAPSHOT STANDBY guaranteed restore point テスト用 スタンバイ オープン スタンバイを一時的に読取り/書込みでオープンしてテストし、その後変更を破棄して physical standby に戻したい場合です。primary に影響はなく REDO の受信も続きますが、snapshot standby の間このスタンバイは failover に使えません。"},{"k":"scenario","v":"apply","l":"Redo Apply の停止 / 開始、apply インスタンスの変更、read-only オープン","m":"日常運用 MRP redo apply APPLY-OFF APPLY-ON apply instance read only Active Data Guard ORA-16766 ORA-16136 ORA-01153 real-time query WAIT_FOR_LOG APPLYING_LOG READ ONLY WITH APPLY OPEN READ ONLY PreferredApplyInstance intended state apply 停止 MRP 動いていない メンテナンスのために MRP を停止または再開したい、RAC スタンバイで apply を別インスタンスに移したい、またはスタンバイをレポート用にオープンしたい場合です (Active Data Guard のライセンスに注意)。"},{"k":"scenario","v":"prot","l":"保護モード、Fast-Start Failover と observer","m":"日常運用 protection mode MaxAvailability MaxPerformance MaxProtection SYNC ASYNC FSFO fast-start failover observer ORA-16627 ORA-16651 ORA-16820 ORA-16819 ORA-16072 ORA-16647 NetTimeout LogXptMode FASTSYNC protection_level 保護モード MaxPerformance / MaxAvailability / MaxProtection を切り替えたい、FSFO を有効化/無効化したい、または observer を管理したい場合です。"},{"k":"scenario","v":"files","l":"データファイル、REDO ログ、スタンバイ REDO ログの追加 / UNNAMED ファイル","m":"日常運用 standby_file_management UNNAMED ORA-01111 ORA-01110 ORA-01157 ORA-01274 データファイル 追加 add datafile REDO ログ 追加 standby redo log SRL ORA-16789 db_file_name_convert ADD STANDBY LOGFILE ORA-01136 データファイル追加 スタンバイ primary にデータファイルまたは REDO ログを追加する、スタンバイに UNNAMED ファイルができた (ORA-01111/ORA-01274)、またはスタンバイ REDO ログが不足している場合です。"},{"k":"scenario","v":"backup","l":"スタンバイから RMAN バックアップを取得する","m":"日常運用 rman standby backup スタンバイからバックアップ archivelog deletion policy RMAN-08137 recovery catalog offload backup RMAN-06820 BACKED UP 1 TIMES CONFIGURE DB_UNIQUE_NAME スタンバイ バックアップ バックアップの負荷を primary から外すために RMAN バックアップをスタンバイで実行し、アーカイブ・ログ削除ポリシーをそれに合わせて設定したい場合です。"}]},{"id":"ora-backup-strategy","file":"install/guides/ora-backup-strategy.json","group":"Oracle","engineId":"oracle","category":"backup","title":"Oracle バックアップ戦略と自動化 (RMAN + Data Pump)","summary":"構築済みのデータベースに対し、恒久的で自動化されたバックアップ体制を構築します (障害発生時のリカバリは別のガイド「RMAN によるリストアとリカバリ」で扱います)。週次 level 0 + 日次 level 1 (または毎日フル)、頻繁なアーカイブログ・バックアップ、FRA または専用ディレクトリ、保存ポリシー (retention)、圧縮、暗号化、ブロック・チェンジ・トラッキング、並列度を扱います。加えて、wallet を使用したフ","level":"中級","duration":"60–120 分 (初回 level 0 の所要時間を除く)","topology":"サーバー 1 台 (シングル・インスタンスまたは Oracle Restart) または RAC (2–8 ノード)","tags":["oracle","rman","バックアップ","backup","戦略","level 0","level 1","増分バックアップ","archivelog","fra","保存ポリシー","ブロック・チェンジ・トラッキング","data pump","expdp","crontab","cron","systemd timer","dbms_scheduler","自動化","wallet","mkstore","rac","oracle restart","snapshot controlfile","asm","/etc/cron.d","ol7","リカバリ・カタログ","create catalog","register database","リストア訓練","restore drill","restore validate","preview"],"order":21,"steps":33,"scenarios":[]},{"id":"ora-rman-restore","file":"install/guides/ora-rman-restore.json","group":"Oracle","engineId":"oracle","category":"backup","title":"RMAN によるリストアとリカバリ","summary":"障害発生時に適切な RMAN リカバリを手順どおりに実施します。19 のシナリオ: データファイル、SYSTEM/UNDO、一時ファイル、破損ブロック、オンライン REDO ログ、制御ファイル、spfile の損失、全体リストア、別ディレクトリ/ASM および別サーバーへのリストア、ポイントインタイムリカバリ (CDB または PDB PITR)、Flashback Database、表領域 PITR、単一表のリカバリ (RECOVER","level":"上級","duration":"30 分~数時間 (データベースのサイズによる)","topology":"サーバー 1 台 (シングルインスタンスまたは Oracle Restart) または RAC。新規ホストのシナリオではソース + ターゲット","tags":["oracle","rman","リストア","リカバリ","データベース復旧","pitr","point in time","resetlogs","recover table","制御ファイル","spfile","autobackup","データファイル","preview","validate","dbid","新規サーバー","disaster recovery","rac","oracle restart","cluster_database","srvctl","asm","block corruption","破損ブロック","ORA-01578","redo log","ORA-00313","clear logfile","tempfile","tspitr","flashback database","restore point","dropped pdb","unplug","from service","data guard","restore archivelog","catalog start with","set newname","undo","system tablespace"],"order":22,"steps":10,"scenarios":[{"k":"scenario","v":"preview","l":"予行演習: RESTORE … PREVIEW / VALIDATE (何も変更しない)","m":"予行演習とバックアップ記録 RESTORE PREVIEW RESTORE VALIDATE リストア 予行演習 リストア テスト バックアップ 使えるか backup test restore drill リカバリ訓練 RMAN VALIDATE バックアップ 健全性 何も壊れていませんが、バックアップが本当にリカバリに足りるかをデータを書き込まずに確認したい場合です (データベースはオープンのまま)。月次のリストア訓練や、どのシナリオを選ぶべきか確信がないときの最初の手順でもあります。"},{"k":"scenario","v":"catalog","l":"バックアップを別ディレクトリへ移動した / RMAN がバックアップを見つけられない (CATALOG)","m":"予行演習とバックアップ記録 CATALOG START WITH RMAN-06023 RMAN-06025 RMAN-06026 ORA-19505 ORA-27037 EXPIRED バックアップ 移動 backup moved no backup found CROSSCHECK NFS 変更 バックアップが見つからない バックアップピースは存在するが RMAN が認識していない (移動した、NFS が変わった、別サーバーから持ってきた) ため、RMAN-06023/06025 が出ます。データベースはオープンのままです。"},{"k":"scenario","v":"arch","l":"アーカイブログのみリストアする (RESTORE ARCHIVELOG)","m":"予行演習とバックアップ記録 RESTORE ARCHIVELOG ORA-00308 アーカイブログ リストア archive log restore archive gap LogMiner SET ARCHIVELOG DESTINATION LogMiner、スタンバイのギャップ解消または手動リカバリのために、特定の順序番号範囲のアーカイブログがディスク上に必要な場合です。データベースはオープンのままで、どのファイルも上書きされません。"},{"k":"scenario","v":"datafile","l":"単一のデータファイルまたは表領域の損失/破損 (データベースはオープンのまま)","m":"損失 / 破損 ORA-01157 ORA-01110 ORA-01116 ORA-27041 ORA-00376 ORA-01113 データファイル 損失 データファイル 削除 missing datafile lost datafile 表領域 損失 ORA-27037 ORA-01135 ORA-01115 ORA-01114 データファイル 破損 データベースはオープンしており、1 つのデータファイルまたは表領域だけが読めません (ORA-01157/01110/01116)。それ以外はすべて動作しています。ファイルが SYSTEM/UNDO に属する場合は「SYSTEM または UNDO」、一時ファイルの場合は「一時ファイル」、ファイルは開けるが数ブロックが破損している場合 (ORA-01578) は「破損ブロック」のカードを選んでください。"},{"k":"scenario","v":"block","l":"破損ブロックがある (ORA-01578、ブロックメディアリカバリ)","m":"損失 / 破損 ORA-01578 ORA-26040 ORA-01110 破損ブロック block corruption corrupt block v$database_block_corruption RECOVER CORRUPTION LIST block media recovery nologging ORA-19566 Marked Corrupt Corrupt block relative dba DBVERIFY 問合せで ORA-01578/ORA-26040 が出る、バックアップが ORA-19566 で停止する、または VALIDATE で破損ブロックが見つかった場合です。ファイルの残りは健全です。データベースはオープンのままで、破損したブロックだけを修復します (Enterprise Edition。SE2 ではファイルをリストアします)。ファイル全体が開けな"},{"k":"scenario","v":"sysdf","l":"SYSTEM または UNDO のデータファイルを損失 (データベースがオープンしない)","m":"損失 / 破損 ORA-01157 ORA-01110 ORA-01116 ORA-01147 ORA-00376 ORA-01541 SYSTEM datafile UNDO datafile UNDO 表領域 損失 system tablespace lost データベースがオープンしない ORA-01113 system01.dbf undotbs 損失または破損したファイルが SYSTEM または UNDO 表領域に属しています。オフラインにできないため、データベース (PDB のファイルであればその PDB のみ) を停止し、MOUNT 状態でリストアします。データ損失はありません。他の表領域のファイルであれば、「単一のデータファイル」カードでデータベースを停止せずに対処できます。"},{"k":"scenario","v":"temp","l":"一時ファイルの損失または破損 (TEMP 表領域)","m":"損失 / 破損 ORA-01157 ORA-01187 ORA-25153 ORA-01116 ORA-01122 ORA-01110 tempfile temp tablespace 一時表領域 TEMP 損失 temp01.dbf dba_temp_files ソート/ハッシュ処理で ORA-01157/ORA-01187/ORA-25153 が出ており、ファイルが一時ファイルである場合です (エラーメッセージ中の番号が `db_files` の値より大きい。例: `data file 201`)。リストアは不要で、新しい一時ファイルを追加します。データベースはオープンのままです。"},{"k":"scenario","v":"redo","l":"オンライン REDO ログの損失または破損","m":"損失 / 破損 ORA-00313 ORA-00312 ORA-00327 ORA-00366 ORA-00367 ORA-00353 ORA-00354 ORA-00316 ORA-01624 REDO ログ 損失 online redo lost redo log CLEAR LOGFILE ORA-00314 ORA-00320 ORA-00321 ORA-00340 ORA-00350 ORA-00470 CLEAR UNARCHIVED アラートログに ORA-00313/00312 (オープンできない) または ORA-00327/00366/00367 (破損) が出ています。1 つのメンバーだけを損失した場合やグループが INACTIVE の場合、データベースはオープンのままです。CURRENT グループを損失した場合はリストア + RESETLOGS が必要で、直近のトラ"},{"k":"scenario","v":"controlfile","l":"制御ファイルのすべてのコピーを損失","m":"損失 / 破損 ORA-00205 ORA-00202 ORA-00210 ORA-27037 制御ファイル 損失 control file lost RESTORE CONTROLFILE autobackup ORA-00206 ORA-00214 ORA-00221 ORA-00227 制御ファイル 破損 インスタンスが MOUNT 段階で制御ファイルを見つけられない、または読めません (ORA-00205/00202/00210)。データファイルと REDO は健全です。コピーのいずれかが健全ならリストアは不要です (診断手順で分かります)。すべて損失した場合は autobackup からリストアして RESETLOGS でオープンします。オンライン REDO が健全なのでデータ損失はありません。"},{"k":"scenario","v":"spfile","l":"spfile 損失","m":"損失 / 破損 ORA-01078 LRM-00109 ORA-01565 spfile 損失 spfile lost parameter file RESTORE SPFILE CRS-5017 PRCR-1079 spfile 削除 spfile が削除または破損しました。インスタンスが起動しない (ORA-01078/LRM-00109)、または起動中だがファイルがない状態です。データファイルには触れず、データ損失はありません。インスタンスがまだ起動中であれば停止時間も発生しません。"},{"k":"scenario","v":"full","l":"全体リストア、同一サーバー (データファイルを損失。制御ファイルと REDO は健全)","m":"損失 / 破損 全データファイル 損失 all datafiles lost full restore RESTORE DATABASE ディスク障害 storage failure ディスク 喪失 LUN 喪失 データファイル 削除された データファイルのすべてまたは大半が失われ、制御ファイルとオンライン REDO ログは健全な場合です。データベースは停止しますが、データ損失はありません。ファイルがあった旧ディスク/ディレクトリがもう使えない場合は「別ディレクトリ」カード、制御ファイルも損失している場合はまず「制御ファイル」カード、サーバーが完全に失われた場合は「別サーバーへのリストア」カードを選んでください。"},{"k":"scenario","v":"relocate","l":"ディスク喪失: データベースを別ディレクトリ / ASM へリストアする (SET NEWNAME)","m":"損失 / 破損 SET NEWNAME SWITCH DATAFILE ALL 別ディレクトリへリストア ASM へリストア new location ディスク交換 マウントポイント 喪失 relocate ORA-15001 ORA-15040 disk group dismounted データファイルが置かれていたディスクまたはディスクグループが使用できません。制御ファイルと REDO は健全です。ファイルを新しいディレクトリまたは ASM ディスクグループへリストアします。データベースは停止しますが、データ損失はありません。"},{"k":"scenario","v":"pitr","l":"時点 / SCN へのリカバリ (PITR、RESETLOGS)","m":"ポイントインタイムリカバリと巻き戻し PITR point in time recovery 時点リカバリ SCN へリカバリ 誤った DELETE 誤った UPDATE TRUNCATE ユーザーエラー logical error UNTIL TIME データ 削除 DROP USER UNTIL SCN RESETLOGS 誤った DELETE/UPDATE/TRUNCATE や不具合のあるアプリケーションのリリースに対し、データベース (または PDB のみ) を過去の時点に戻します。その時点以降の変更はすべて失われます (RESETLOGS)。まず範囲の狭い方法を検討してください: 単一の表 →「単一の表をリカバリ」、単一の表領域 → TSPITR、フラッシュバックが有効 →「Flashback Database」(リストア不要で、はるかに高速)。"},{"k":"scenario","v":"flashback","l":"Flashback Database で巻き戻す (リストアポイント / SCN / 時刻)","m":"ポイントインタイムリカバリと巻き戻し FLASHBACK DATABASE FLASHBACK PLUGGABLE DATABASE restore point guaranteed restore point 巻き戻し アップグレード 切り戻し テスト後に戻す FLASHBACK_ON FLASHBACK TO RESTORE POINT フラッシュバックが有効、または保証付きリストアポイントがあり、どのファイルも損失していない場合、リストアせずに数分で巻き戻せます (Enterprise Edition)。RESETLOGS が必要です。有効かどうか: `SELECT flashback_on FROM v$database;` → YES、または `v$restore_point` に GUARANTEE_FLASHBACK_DATABASE = YES の行がある。"},{"k":"scenario","v":"tspitr","l":"表領域を過去の時点に戻す (TSPITR)","m":"ポイントインタイムリカバリと巻き戻し TSPITR tablespace point in time RECOVER TABLESPACE AUXILIARY DESTINATION DBMS_TTS 表領域 リカバリ ORA-29308 誤った操作が 1 つの表領域内のオブジェクトだけに影響し、データベースの残りは現在のままにしておく必要がある場合です (Enterprise Edition)。処理中その表領域はオフラインになり、中のオブジェクトはすべて目標時点に戻ります。影響を受けたのが 1、2 個の表だけなら、「単一の表をリカバリ」のほうが戻す範囲が小さくて済みます。"},{"k":"scenario","v":"table","l":"単一の表をリカバリする (RECOVER TABLE、12c 以降の Enterprise Edition)","m":"ポイントインタイムリカバリと巻き戻し RECOVER TABLE 表 削除 DROP TABLE 表 リカバリ table recovery ORA-00942 REMAP TABLE ORA-38305 FLASHBACK TABLE recyclebin PURGE 1 つの表が誤って削除または破損し、データベースの残りはそのままにしておく必要がある場合です (12c 以降の Enterprise Edition)。DROP されて PURGE されていなければ、まずごみ箱を確認してください: `FLASHBACK TABLE … TO BEFORE DROP` なら数秒で済みます (診断手順で表示されます)。"},{"k":"scenario","v":"pdbdrop","l":"削除された PDB を元に戻す (DROP PLUGGABLE DATABASE)","m":"ポイントインタイムリカバリと巻き戻し DROP PLUGGABLE DATABASE PDB 削除 dropped PDB RMAN-06813 ORA-65011 ORA-65179 KEEP DATAFILES PDB 復元 unplug DBMS_PDB.RECOVER PDB が `DROP PLUGGABLE DATABASE` で削除されました。ファイルが残っていれば XML で再度プラグインします。ファイルも削除されていればバックアップから戻します (21c 以降は 1 コマンド、19c は一時 CDB 経由)。CDB はオープンのままです。"},{"k":"scenario","v":"newhost","l":"別サーバーへのリストア (新規ホスト、制御ファイルの autobackup から)","m":"別サーバーとスタンバイ 新規サーバー 別サーバー サーバー喪失 disaster recovery DR new host データベース複製 clone テスト環境 サーバー焼失 server lost restore to another host サーバーが完全に失われた、またはコピー/テスト環境を構築する場合に、バックアップを別のサーバーへリストアします (シングルインスタンス、ファイルシステムのみ)。バックアップ済みの最後のアーカイブログまでリカバリし、それ以降は失われます。コピーは RESETLOGS でオープンします。"},{"k":"scenario","v":"fromsvc","l":"Data Guard: ファイルをスタンバイ/プライマリからネットワーク経由で取得する (FROM SERVICE)","m":"別サーバーとスタンバイ RESTORE FROM SERVICE FROM SERVICE RECOVER STANDBY DATABASE スタンバイからリストア Data Guard スタンバイ 遅延 archive gap standby controlfile ORA-01110 v$archive_gap apply lag Data Guard がある場合、プライマリで損失したデータファイルをスタンバイから、遅れているスタンバイや損失したスタンバイ制御ファイルをプライマリから、バックアップピースを使わずに取得できます (12c 以降)。"}]},{"id":"ora-goldengate","file":"install/guides/ora-goldengate.json","group":"Oracle","engineId":"oracle","category":"ha","title":"Oracle GoldenGate Microservices: Oracle → Oracle 一方向レプリケーション","summary":"GoldenGate 21c または 23ai/26ai Microservices を使って、PDB のスキーマを別のデータベースへ継続的に (数秒の遅延で) レプリケートします。最終的に、ソースでは Integrated Extract と Distribution Path が、ターゲットでは Parallel Replicat が稼働します。ターゲットのスキーマは一貫性のある SCN からの初期ロードで作成され、heartbea","level":"上級","duration":"3～5 時間","topology":"ソース DB サーバー (OGG ソース deployment) + ターゲット DB サーバー (OGG ターゲット deployment)。RAC では GoldenGate をノード 1 に (または XAG でクラスタリソースとして)","tags":["oracle","goldengate","ogg","microservices","レプリケーション","replication","cdc","integrated extract","parallel replicat","distribution path","adminclient","oggca","21c","23ai","26ai","rac","scan","xag","acfs","tranlogoptions"],"order":30,"steps":42,"scenarios":[]},{"id":"ora-goldengate-ops","file":"install/guides/ora-goldengate-ops.json","group":"Oracle","engineId":"oracle","category":"ops","title":"Oracle GoldenGate の日常運用と障害シナリオ (Microservices 21c / 23ai)","summary":"構築済みの GoldenGate Microservices レプリケーションの日常運用と障害リカバリの runbook です (構築には GoldenGate 構築ガイドを使用します)。何をすべきか確信がない場合は「ヘルスとラグの確認」から始めてください。読取り専用の診断で適切なシナリオに誘導されます — Extract と Replicat の ABEND (レポート、discard、OGG-xxxxx エラー)、データが入っている","level":"上級","duration":"5 分 (確認) – 2 時間 (アップグレード、表の追加)","topology":"ソース・サーバー (ソース deployment、Integrated Extract、Distribution Path) + ターゲット・サーバー (ターゲット deployment、Parallel Replicat)","tags":["oracle","goldengate","ogg","microservices","adminclient","runbook","abend","extract","replicat","lag","stats","info all","heartbeat","report","discard","reperror","handlecollisions","cdr","conflict","add trandata","schematrandata","aftercsn","atcsn","mapexclude","tableexclude","resync","purge trail","purgeoldextracts","trail","alter extract scn","etrollover","upgrade","patch","opatch","oggHome","data guard","switchover","failover","handledlfailover","OGG-00664","OGG-01004","OGG-01296","OGG-02912","21c","23ai","26ai"],"order":31,"steps":8,"scenarios":[{"k":"scenario","v":"health","l":"ヘルスとラグの確認 (すべて正常か)","m":"監視と確認 INFO ALL lag ラグ STATS heartbeat GG_LAG Service Manager ggserr.log OGG-01027 OGG-01738 Long Running Transaction STOPPED RUNNING Distribution Path DISTPATH Receiver INFO DISTPATH レプリケーション遅延 replication lag 読取り専用です。Service Manager とマイクロサービス、INFO ALL、ラグ、STATS、ハートビートのラグ、データベース側の capture の状態、ggserr.log を確認します。何も変更しません。何をすべきか確信がない場合はここから始めてください。"},{"k":"scenario","v":"ext_abend","l":"Extract ABENDED (エラーで停止)","m":"障害 (ABEND) Extract ABENDED ABEND OGG-00664 OGG-00446 OGG-02171 OGG-02912 OGG-02022 OGG-02091 OGG-01044 OGG-01668 ORA-01291 ORA-01017 ORA-28001 ORA-04031 ORA-01031 missing log archived log not found logmining OGG-00868 Extract STARTING Extract 停止 capture ABORTED ソースの Extract が ABENDED になっている、または再起動を繰り返しています。レポート・ファイルの OGG-xxxxx エラーから原因 (接続、アーカイブ・ログの欠落、ログ・マイニング、権限、ディスク) を特定して解消し、Extract を停止した位置から再開し"},{"k":"scenario","v":"rep_abend","l":"Replicat ABENDED (ターゲットに適用できない)","m":"障害 (ABEND) Replicat ABENDED OGG-01004 OGG-01296 OGG-01154 OGG-00869 OGG-01161 OGG-01169 OGG-01431 OGG-00199 OGG-00423 ORA-01403 ORA-00001 ORA-02291 ORA-00942 ORA-01653 no data found unique constraint discard REPERROR HANDLECOLLISIONS CDR conflict Replicat 停止 ORA-01400 ORA-12899 value too large ターゲットの Replicat がトランザクションを適用できませんでした。レポートと discard ファイルから表、操作、エラーを特定し、データを修正するか一時的な REPERROR でスキップして、Repl"},{"k":"scenario","v":"add_table","l":"データが入っている表をレプリケーションに追加する (初期ロード + AFTERCSN)","m":"表の管理 表の追加 add table ADD TRANDATA ADD SCHEMATRANDATA AFTERCSN ATCSN initial load 初期ロード flashback_scn MAPEXCLUDE 新しい表 既存のデータが入っている表を、稼働中のレプリケーションに停止なしで追加します: ADD TRANDATA、一貫性のある SCN での expdp/impdp、その SCN より後のこの表の変更だけを適用する別の Replicat (AFTERCSN)。ほかの表のレプリケーションは継続します。"},{"k":"scenario","v":"remove_table","l":"表をレプリケーションから除外する","m":"表の管理 表の除外 remove table TABLEEXCLUDE MAPEXCLUDE DELETE TRANDATA exclude 表は今後レプリケートされなくなります: Extract で TABLEEXCLUDE (または TABLE 行の削除)、Replicat で MAPEXCLUDE、必要に応じて DELETE TRANDATA。プロセスは短時間再起動されます。"},{"k":"scenario","v":"resync","l":"単一の表を再同期する (resync)","m":"表の管理 resync 再同期 out of sync データの差異 不整合 Veridata OGG-01004 ORA-01403 ORA-00001 row count 行数の不一致 ある表のターゲット側のデータがソースと食い違っています (手動変更、スキップしたエラー、不完全な初期ロード)。表をソースから一貫性のある SCN で再ロードし、一時的な Replicat がその SCN より後の変更を適用します。ほかの表には影響しません。"},{"k":"scenario","v":"purge","l":"trail ファイルがディスクを圧迫している: 削除 (Purge Trail)","m":"メンテナンス trail purge PURGEOLDEXTRACTS Purge Trail ディスクフル No space left on device trail の削除 var/lib/data trail ディレクトリがいっぱい ENOSPC trail ディレクトリが大きくなっている、またはディスクがいっぱいになりそうです。どのファイルが読まれているかを確認し、Purge Trail タスク (Classic の PURGEOLDEXTRACTS に相当) を USECHECKPOINTS 付きで定義します。緊急時は読込み済みのファイルを手動で削除します。"},{"k":"scenario","v":"reposition","l":"Extract を特定の SCN に再配置する","m":"メンテナンス reposition ALTER EXTRACT SCN BEGIN SCN ETROLLOVER SCN から開始 trail の消失 first_scn 巻き戻し Extract に最初から取り直させたい SCN があります (trail の消失、誤った開始位置、ターゲット側のロールバック)。ALTER EXTRACT … SCN と ETROLLOVER により新しい trail ファイルから開始します。同じデータがターゲットに 2 回届くことがあります。"},{"k":"scenario","v":"upgrade","l":"GoldenGate のバージョン・アップグレード / パッチ (Microservices)","m":"メンテナンス upgrade patch アップグレード OPatch out-of-place oggHome Service Manager upgrade bundle patch 21c 23ai 26ai release update GoldenGate patch Service Manager PATCH 新しい GoldenGate のリリースやパッチへの移行です: out-of-place (新しいホームをインストールし、Service Manager と deployment を REST で新しいホームに移す) または OPatch による in-place。Extract/Replicat は短時間停止します。切り戻しは古いホームに戻すことです。"},{"k":"scenario","v":"dg_role","l":"ソースでの Data Guard switchover/failover 後に Extract を継続させる","m":"ロール変更 Data Guard switchover failover role transition HANDLEDLFAILOVER ORA-01033 ORA-16000 ORA-01109 新しい primary スタンバイ FSFO ORA-12514 ロール変更 Extract 新しい primary FAILOVERTARGETDESTID ソース・データベースで switchover または failover が発生しました。Extract は新しい primary に接続してチェックポイントから続行する必要があります。接続 (資格証明の別名/サービス)、capture の状態、HANDLEDLFAILOVER、データ不整合の可能性を確認します。"}]},{"id":"ora-security","file":"install/guides/ora-security.json","group":"Oracle","engineId":"oracle","category":"security","title":"Oracle Database セキュリティ強化 (アセスメント、ネットワーク、TLS、認証、権限、Unified Auditing、TDE)","summary":"インストール・ガイドではありません。稼働中の Oracle 19c / 23ai (26ai) データベース (シングル・インスタンス、Oracle Restart または RAC、CDB/PDB) のセキュリティ上の不備を見つけて解消します。まず読み取り専用のセキュリティ・アセスメントが検出事項を重大度順に一覧表示し、各項目がどのカードにつながるかを示します。その後、各領域を個別に、またはすべてを順に対処します: リスナーと TCP.","level":"上級","duration":"5 分 (アセスメント) ～ 4 時間 (完全な強化)","topology":"シングル・インスタンス / Oracle Restart / RAC (2～8 ノード)、CDB + PDB、アプリケーション・サーバー (クライアント側の確認)","tags":["oracle","セキュリティ","security","hardening","セキュリティ強化","cis benchmark","stig","tcps","wallet","orapki","sqlnet.ora","ネイティブ・ネットワーク暗号化","TCP.VALIDNODE_CHECKING","ALLOWED_LOGON_VERSION_SERVER","プロファイル","ORA12C_STRONG_VERIFY_FUNCTION","unified auditing","AUDSYS","DBMS_AUDIT_MGMT","TDE","キーストア","ADMINISTER KEY MANAGEMENT","UTL_FILE","PUBLIC","デフォルト・パスワード"],"order":40,"steps":2,"scenarios":[{"k":"scenario","v":"scan","l":"セキュリティ・アセスメント: 不備はどこにあるか (読み取り専用)","m":"ここから開始 データベース・セキュリティ監査 security audit hardening check CIS STIG DBSAT セキュリティ・ホール 脆弱性 vulnerability ペネトレーション・テストの指摘 dba_users_with_defpwd 監査クエリー セキュリティ・アセスメント security scan 重大 最初に実行するスキャン: デフォルト・パスワードのアカウントとオープンなアカウント、古いパスワード・ベリファイア、プロファイル、DBA/ANY 権限、PUBLIC に付与された UTL_* PL/SQL パッケージ、監査、TDE、暗号化されていないセッション、リスナーとファイルの権限。何も変更しません。"},{"k":"scenario","v":"all","l":"完全な強化 (全領域を順に)","m":"ここから開始 hardening セキュリティ強化 全面的なセキュリティ対策 full hardening CIS benchmark の適用 STIG 新規インストール直後、または一度も強化していないデータベース: 全領域を安全な順序で適用します。リスナーとデータベースを 1～2 回再起動します (メンテナンス・ウィンドウが必要)。"},{"k":"scenario","v":"net","l":"ネットワークと接続: 誰がどこから接続できるか (リスナー、TCP.VALIDNODE_CHECKING、ファイアウォール)","m":"ネットワークと認証 TCP.VALIDNODE_CHECKING TCP.INVITED_NODES リスナー 1521 5500 ORA-12537 TNS-12537 ORA-12541 ADMIN_RESTRICTIONS ファイアウォール TNS-12546 ORA-12170 invited nodes listener.log 外部からのアクセス アクセス制限 リスナーがすべてのアドレスに開いている、invited nodes が未定義、1521/5500 が誰にでも開いている。リスナーを再起動します (既存のセッションには影響しません)。"},{"k":"scenario","v":"tls","l":"接続を暗号化する (TCPS wallet またはネイティブ・ネットワーク暗号化)","m":"ネットワークと認証 TCPS SSL TLS wallet orapki SQLNET.ENCRYPTION_SERVER ORA-28860 ORA-29024 ORA-28759 ORA-29106 ORA-12696 ORA-12660 SSL_SERVER_DN_MATCH 証明書の有効期限 ORA-29003 ORA-29002 TNS-12560 TLS 証明書チェーン certificate chain ネイティブ・ネットワーク暗号化 ネットワーク・トラフィックが暗号化されていない。TLS (TCPS、wallet、証明書、クライアント側の SSL_SERVER_DN_MATCH) または証明書不要のネイティブ暗号化 (SQLNET.ENCRYPTION_SERVER=REQUIRED)。どちらもライセンス不要です。リスナーを再起動しますが、既存のセッションには影響しません。"},{"k":"scenario","v":"auth","l":"認証とパスワード (12C ベリファイア、プロファイル、デフォルト・アカウント)","m":"ネットワークと認証 ALLOWED_LOGON_VERSION_SERVER ORA-28040 ORA-01017 ORA-28000 ORA-28001 ORA-28003 ORA-28007 password_versions 10G PROFILE ORA12C_STRONG_VERIFY_FUNCTION デフォルト・パスワード default password SCOTT ORA-65066 ORA-00988 password_versions 10G パスワード・プロファイル password policy FAILED_LOGIN_ATTEMPTS 10G/11G パスワード・ベリファイア、パスワード・プロファイルなし、デフォルト・パスワードのアカウントやサンプル・アカウントがオープン、個人用 DBA アカウント。停止時間なし。"},{"k":"scenario","v":"priv","l":"最小権限: ロール、PUBLIC、アプリケーション・アカウント","m":"権限と監査証跡 PUBLIC UTL_FILE UTL_TCP UTL_HTTP UTL_SMTP DBA role RESOURCE ANY privilege least privilege 最小権限 ORA-01031 ORA-00942 schema-only account PLS-00201 ORA-04021 GRANT ANY UNLIMITED TABLESPACE 権限レポート アプリケーション・アカウントに DBA/RESOURCE/ANY 権限、PUBLIC に付与された UTL_FILE/UTL_TCP/UTL_HTTP。スキーマ所有者、読取り/書込みロール、権限レポート。停止時間なし。"},{"k":"scenario","v":"audit","l":"監査: 誰が何をしたか (Unified Auditing、AUDSYS のクリーンアップ)","m":"権限と監査証跡 unified auditing AUDIT POLICY AUDSYS DBMS_AUDIT_MGMT UNIFIED_AUDIT_TRAIL ORA_LOGON_FAILURES ORA_SECURECONFIG UNIFIED_AUDIT_SYSTEMLOG SYSAUX 満杯 監査証跡 SIEM ORA-46267 unified audit policy 誰が何をしたか who changed 監査担当者がログオン、アカウント変更、スキーマ変更の記録を求めている。Unified Audit ポリシー、保存期間に従った AUDSYS のパージ、syslog / 集中サーバーへの記録の転送。Unified Auditing はライセンス不要です。"},{"k":"scenario","v":"tde","l":"保存データを暗号化する (TDE)","m":"データとバックアップ TDE transparent data encryption キーストア wallet ADMINISTER KEY MANAGEMENT WALLET_ROOT ORA-28365 ORA-28374 ORA-46665 ENCRYPT_NEW_TABLESPACES encryption at rest ORA-28367 ORA-46658 ORA-28353 Advanced Security master key TDE_CONFIGURATION データファイル、バックアップ、ディスクのコピーを読み取られることへの対策としての TDE: WALLET_ROOT、キーストア、マスター暗号化鍵、表領域の暗号化 (オンライン)。Advanced Security ライセンスが必要です。WALLET_ROOT のために 1 回再起動します。"},{"k":"scenario","v":"backup","l":"バックアップのセキュリティ (RMAN 暗号化、パスワードなしの自動化、権限)","m":"データとバックアップ RMAN encryption CONFIGURE ENCRYPTION ORA-19913 expdp ENCRYPTION secure external password store mkstore SEPS バックアップの権限 ORA-19914 Advanced Security ライセンス 暗号化されていないバックアップ unencrypted backup ENCRYPTION_PWD_PROMPT RMAN/Data Pump のバックアップが暗号化されていない、スクリプトに平文のパスワード、バックアップ・ディレクトリを誰でも読める。RMAN 暗号化、ENCRYPTION_PWD_PROMPT、wallet (SEPS)、ディレクトリの権限。RMAN と Data Pump の暗号化には Advanced Security ライセンスが必要です。"},{"k":"scenario","v":"os","l":"OS 側 (oracle アカウント、ファイル権限、コア・ダンプ、SELinux)","m":"サーバーとバージョン SELinux orapw oracle アカウント ファイル権限 コア・ダンプ ORACLE_HOME の権限 sudo avc: denied passwd -l oracle setuid 6751 limits.d oracle アカウントにパスワードがありログインできる、パスワード・ファイル / network admin / wallet の権限が緩い、SELinux が無効。コア・ダンプの制限は新しいセッション / 再起動後に有効になります。"},{"k":"scenario","v":"patch","l":"パッチとバージョン: 最新の RU を適用しているか","m":"サーバーとバージョン RU release update CPU Critical Patch Update opatch lspatches datapatch dba_registry_sqlpatch CVE サポート終了 opatch Doc ID 742060.1 パッチ適用スケジュール インストール済みの RU、datapatch の状態、サポート期間。適用には RU パッチ・ガイドを参照します。読み取り専用。"}]},{"id":"ora-oem","file":"install/guides/ora-oem.json","group":"Oracle","engineId":"oracle","category":"monitoring","title":"Oracle Enterprise Manager Cloud Control 13c Release 5 (13.5) のインストール","summary":"Oracle Enterprise Manager Cloud Control 13.5 をインストールします。既存の 19c データベースを Management Repository として準備し (ドキュメント記載のパラメータ、オプティマイザ設定のリセット)、OMS サーバーにサイレントインストールを行い (OL9 ではソフトウェアのみ + RU + ConfigureGC)、Release Update を適用し、ターゲットサー","level":"上級","duration":"3～5 時間","topology":"OMS サーバー + リポジトリデータベースサーバー (+ 監視対象のターゲットサーバー)","tags":["oracle","enterprise manager","oem","em13c","13.5","cloud control","oms","エージェント","emctl","emcli","monitoring","監視","rac","クラスタ","discover_db","data guard","exportconfig"],"order":40,"steps":32,"scenarios":[]}]}}