{"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":"Sessões e atividade","categoryId":"sessions","order":1,"concepts":[{"id":"active-sessions","title":"Mostrar sessões ativas / consultas em execução","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 fornece as sessões ativas no momento. Para o texto SQL completo, faça join com v$sql pelo sql_id.","danger":"safe"},"postgres":{"command":"SELECT pid, usename, state, wait_event_type, query\nFROM pg_stat_activity\nWHERE state <> 'idle';","note":"state = 'active' mostra as que estão executando uma consulta naquele momento. Calcule as durações a partir de 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":"No MySQL 8 / MariaDB, performance_schema.processlist mantém menos locks.","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":"Para uma visão rápida: EXEC sp_who2 'active';","danger":"safe"},"mongodb":{"command":"db.currentOp({ \"active\": true })","note":"Para filtrar operações de longa duração: db.currentOp({ active: true, secs_running: { $gt: 5 } })","danger":"safe"},"redis":{"command":"CLIENT LIST\n# For a summary: INFO clients","note":"Como o Redis é single-threaded, são listados os clientes conectados em vez de 'consultas em execução'. Para comandos lentos, use SLOWLOG GET.","danger":"safe"}}},{"id":"blocking-sessions","title":"Encontrar sessões bloqueadoras / aguardando lock","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":"Uma sessão com blocking_session preenchido está bloqueada pelo SID indicado no valor de blocking_session.","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":"O array blocked_by fornece os PIDs que estão bloqueando este pid.","danger":"safe"},"mysql":{"command":"SELECT * FROM sys.innodb_lock_waits\\G\n-- MySQL 8: SELECT * FROM performance_schema.data_lock_waits;","note":"O schema sys apresenta de forma legível o trx_id / thread em espera e o bloqueador.","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":"Requisições com blocking_session_id <> 0 estão bloqueadas. É possível montar uma consulta recursiva para seguir a cadeia.","danger":"safe"},"mongodb":{"command":"db.currentOp({ \"waitingForLock\": true })","note":"O WiredTiger faz lock em nível de documento/coleção. Operações longas podem ser encerradas com 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":"O bloqueio geralmente vem de um único comando de longa duração (ex.: KEYS *, um SORT grande); o SLOWLOG os mostra.","danger":"safe"}}},{"id":"kill-session","title":"Encerrar (kill) uma sessão / consulta","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":"Obtenha os valores de sid e serial# em v$session. IMMEDIATE inicia o rollback imediatamente.","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":"Tente primeiro pg_cancel_backend; se não funcionar, use pg_terminate_backend.","danger":"danger"},"mysql":{"command":"-- Kill only the query:\nKILL QUERY <id>;\n-- Close the connection entirely:\nKILL CONNECTION <id>;","note":"O valor <id> é a coluna Id da processlist.","danger":"danger"},"mssql":{"command":"KILL <session_id>;\n-- To see rollback progress:\n-- KILL <session_id> WITH STATUSONLY;","note":"KILL faz rollback da transação aberta; em transações grandes, o rollback pode demorar bastante.","danger":"danger"},"mongodb":{"command":"db.killOp(<opid>)","note":"Pegue o valor de opid no campo opid da saída de db.currentOp().","danger":"danger"},"redis":{"command":"CLIENT KILL ID <client-id>\n# or by address: CLIENT KILL ADDR 10.0.0.5:6379","note":"Use CLIENT LIST para obter o client-id. Um único comando já em execução não pode ser interrompido (exceto um script Lua: SCRIPT KILL); é preciso esperar que termine. Para liberar um cliente aguardando um comando bloqueante como BLPOP/XREAD BLOCK sem derrubar a conexão, use CLIENT UNBLOCK <client-id> [TIMEOUT|ERROR]. CLIENT UNPAUSE apenas retoma clientes pausados com CLIENT PAUSE.","danger":"caution"}}},{"id":"connection-count","title":"Ver número de conexões e limite de conexões","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":"Os limites são os parâmetros processes/sessions. Para a utilização, consulte também a view resource_limit.","danger":"safe"},"postgres":{"command":"SELECT count(*) FROM pg_stat_activity WHERE backend_type = 'client backend';\nSHOW max_connections;","note":"Como pg_stat_activity também inclui processos em segundo plano, apenas as conexões de clientes (backend_type = 'client backend') são contadas. Os slots de superuser_reserved_connections são reservados para administradores.","danger":"safe"},"mysql":{"command":"SHOW STATUS LIKE 'Threads_connected';\nSHOW VARIABLES LIKE 'max_connections';","note":"O status Max_used_connections mostra o pico.","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 é o teto teórico; o limite prático depende da memória e das worker threads.","danger":"safe"},"mongodb":{"command":"db.serverStatus().connections","note":"Retorna os campos current, available e totalCreated. O limite é definido por net.maxIncomingConnections.","danger":"safe"},"redis":{"command":"INFO clients\nCONFIG GET maxclients","note":"connected_clients é a contagem atual; maxclients é o teto configurado (padrão 10000).","danger":"safe"}}}]},"rosetta/storage.json":{"category":"Espaço e armazenamento","categoryId":"storage","order":2,"concepts":[{"id":"database-size","title":"Mostrar o tamanho total do banco de dados","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":"Para considerar apenas os segmentos usados, some dba_segments. Adicione dba_temp_files para o TEMP.","danger":"safe"},"postgres":{"command":"SELECT pg_size_pretty(pg_database_size(current_database()));","note":"Para todos os bancos de dados: 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":"No InnoDB, esse valor é uma estimativa; para o tamanho exato dos arquivos, verifique o ibdata/os arquivos no nível do SO.","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":"A coluna size está em páginas de 8 KB; * 8 / 1024 converte para MB.","danger":"safe"},"mongodb":{"command":"db.stats(1024*1024)\n// returns the dataSize, storageSize, indexSize fields in MB","note":"storageSize é o tamanho comprimido em disco; dataSize é o tamanho lógico não comprimido.","danger":"safe"},"redis":{"command":"INFO memory\n# the used_memory_human line gives the total size in memory\nDBSIZE  # number of keys","note":"O Redis é baseado em memória; 'tamanho' significa uso de RAM. O tamanho do arquivo RDB/AOF é o estado persistido em disco.","danger":"safe"}}},{"id":"largest-tables","title":"Listar as maiores tabelas / coleções","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":"Remova o filtro segment_type para ver também os índices.","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 é a soma de tabela + índices + TOAST; use pg_relation_size apenas para a tabela.","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":"Para um schema específico, use 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 abrange todas as páginas reservadas (dados + índices).","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 é o tamanho comprimido em disco. O custo de stats() é baixo mesmo em coleções grandes.","danger":"safe"},"redis":{"command":"redis-cli --bigkeys\n# To rank by memory (bytes): redis-cli --memkeys","note":"Ambos varrem todo o keyspace com SCAN (não bloqueiam o servidor, mas adicionam carga); a diferença é a métrica: --bigkeys informa as maiores chaves por contagem de elementos/comprimento em cada tipo, --memkeys pelo consumo de memória via MEMORY USAGE. Para uma única chave, use MEMORY USAGE <key>.","danger":"caution"}}},{"id":"free-space","title":"Verificar espaço livre / taxa de uso","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":"Para arquivos com AUTOEXTEND ativado, o limite real é maxbytes; verifique dba_data_files.maxbytes para o MAXSIZE.","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":"O PostgreSQL depende do SO para o espaço livre em disco; o monitoramento do sistema operacional (df) é essencial para limites críticos.","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 é o espaço recuperável (fragmentado) dentro da tabela; o espaço livre em disco fica no nível do SO.","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 está em páginas; dividir por 128 resulta em MB (páginas de 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":"Com WiredTiger, fsTotalSize / fsUsedSize fornecem o tamanho total e usado do disco no nível do SO.","danger":"safe"},"redis":{"command":"INFO memory\nCONFIG GET maxmemory\n# Usage = used_memory / maxmemory","note":"Se maxmemory for 0, não há limite e, quando a RAM se esgota, o OOM killer do SO entra em ação. maxmemory-policy determina o comportamento de eviction.","danger":"safe"}}},{"id":"row-count","title":"Obter a contagem de linhas / documentos (rápido)","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 reflete a última execução de ANALYZE/DBMS_STATS; use COUNT(*) para um valor exato.","danger":"safe"},"postgres":{"command":"-- Estimated (instant):\nSELECT reltuples::bigint FROM pg_class WHERE relname = 'customer';\n-- Exact: SELECT count(*) FROM customer;","note":"reltuples é uma estimativa referente ao último ANALYZE/VACUUM; um COUNT completo é caro em tabelas grandes.","danger":"safe"},"mysql":{"command":"-- Estimated (InnoDB):\nSELECT table_rows FROM information_schema.tables\nWHERE table_name = 'customer';\n-- Exact: SELECT COUNT(*) FROM customer;","note":"No InnoDB, table_rows é uma estimativa e pode errar em até 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 (heap) ou 1 (clustered) fornece a contagem de linhas; muito mais rápido que uma varredura com COUNT(*).","danger":"safe"},"mongodb":{"command":"// Fast (from metadata):\ndb.customer.estimatedDocumentCount()\n// Exact (can count with a filter): db.customer.countDocuments({})","note":"estimatedDocumentCount lê metadados (instantâneo); countDocuments faz uma varredura real.","danger":"safe"},"redis":{"command":"DBSIZE\n# Specific pattern: count roughly with SCAN (do not use KEYS * in production)","note":"DBSIZE retorna em O(1) o número total de chaves no banco de dados selecionado.","danger":"safe"}}}]},"rosetta/performance.json":{"category":"Desempenho","categoryId":"performance","order":3,"concepts":[{"id":"top-slow-queries","title":"Encontrar as consultas mais lentas / mais caras","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":"Para análise histórica, use o AWR: dba_hist_sqlstat. Com o sql_id, DBMS_XPLAN.DISPLAY_CURSOR mostra o plano.","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":"Requer a extensão pg_stat_statements (shared_preload_libraries). Zere com 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":"Alternativa: o slow query log com slow_query_log = ON e 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":"Se o Query Store estiver habilitado, use sys.query_store_runtime_stats para uma análise histórica mais rica.","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":"O profiler adiciona overhead de escrita; desative-o com db.setProfilingLevel(0) após o diagnóstico.","danger":"caution"},"redis":{"command":"SLOWLOG GET 10\n# Set the threshold (microseconds): CONFIG SET slowlog-log-slower-than 10000","note":"slowlog-log-slower-than está em microssegundos (10000 = 10 ms). Limpe com SLOWLOG RESET.","danger":"safe"}}},{"id":"explain-plan","title":"Obter o plano de execução de uma consulta (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 fornece o plano estimado; para contagens reais de linhas, use DISPLAY_CURSOR + STATISTICS_LEVEL=ALL.","danger":"safe"},"postgres":{"command":"EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)\nSELECT * FROM customer WHERE city = 'Ankara';","note":"ANALYZE REALMENTE executa a consulta (cuidado com INSERT/UPDATE/DELETE; teste dentro de uma transação e faça 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+) executa a consulta; FORMAT=JSON fornece detalhes sem executá-la.","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":"No SSMS, 'Include Actual Execution Plan' (Ctrl+M) mostra o plano gráfico.","danger":"caution"},"mongodb":{"command":"db.customer.find({ city: \"Ankara\" }).explain(\"executionStats\")","note":"executionStats mostra o número real de documentos retornados e o uso de índices (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":"O desempenho depende da complexidade do comando e do tamanho da chave/estrutura de dados; meça com o SLOWLOG.","danger":"safe"}}},{"id":"unused-indexes","title":"Detectar índices não utilizados","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":"Se USED = NO, o índice não foi usado durante o período de monitoramento. Desative o monitoramento com NOMONITORING USAGE. A antiga v$object_usage mostra apenas os índices do usuário da sessão e está obsoleta desde o 12c. No 12.2+, o uso de índices é rastreado automaticamente em 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 significa que o índice não foi usado desde o último reset das estatísticas; não remova índices UNIQUE/PK.","danger":"safe"},"mysql":{"command":"SELECT * FROM sys.schema_unused_indexes;","note":"O performance_schema precisa estar habilitado e o servidor precisa estar em execução há algum tempo; constraints UNIQUE são excluídas.","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 é zerado quando o servidor reinicia; reserve uma janela de observação suficiente.","danger":"safe"},"mongodb":{"command":"db.customer.aggregate([{ $indexStats: {} }])\n// Indexes with low/0 accesses.ops are candidates","note":"accesses.ops conta os acessos desde o timestamp accesses.since; o índice _id não pode ser removido.","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":"Como o modelo de dados é chave-valor, não existe o conceito tradicional de índice.","danger":"safe"}}},{"id":"cache-hit-ratio","title":"Medir a taxa de acerto do cache","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":"Uma taxa baixa nem sempre é ruim; interprete-a no contexto da carga de trabalho, não isoladamente.","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":"Geralmente o alvo é 99%+. Se estiver baixa, revise shared_buffers e o cache do SO.","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 são leituras do disco, read_requests são o total de leituras. Se estiver baixa, aumente 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":"No SQL Server moderno, o Page Life Expectancy (PLE) é um indicador mais significativo de pressão de memória.","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":"Valores altos de 'pages read into cache' e de eviction indicam que o cache do WiredTiger é pequeno demais.","danger":"safe"},"redis":{"command":"INFO stats\n# keyspace_hits / (keyspace_hits + keyspace_misses) = hit ratio","note":"Uma taxa de acerto persistentemente baixa indica que as configurações de TTL/eviction ou o padrão de acesso precisam ser revisados.","danger":"safe"}}}]},"rosetta/backup.json":{"category":"Backup e recuperação","categoryId":"backup","order":4,"concepts":[{"id":"logical-dump","title":"Fazer um backup lógico (dump)","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":"Usa o Data Pump. O objeto DIRECTORY deve ser definido antes com CREATE DIRECTORY. Use o RMAN para backups físicos.","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 permite restores flexíveis (tabelas seletivas/paralelo). Use pg_dumpall para o cluster inteiro (incluindo roles).","danger":"safe"},"mysql":{"command":"mysqldump -u root -p --single-transaction \\\n  --routines --triggers --events mydb > db.sql","note":"--single-transaction fornece um backup consistente sem locks no InnoDB. Opções paralelas para grandes volumes: mydumper/myloader ou MySQL Shell util.dumpInstance()/dumpSchemas() (o mysqlpump foi descontinuado no 8.0.34 e removido no 8.4).","danger":"safe"},"mssql":{"command":"BACKUP DATABASE [MyDB]\nTO DISK = N'C:\\backup\\MyDB_full.bak'\nWITH COMPRESSION, CHECKSUM, INIT;","note":"INIT sobrescreve o arquivo existente; use NOINIT para anexar. Para backups de log, use BACKUP LOG (no recovery model FULL).","danger":"safe"},"mongodb":{"command":"mongodump --uri=\"mongodb://localhost:27017\" \\\n  --archive=db.archive.gz --gzip --db=mydb","note":"Em um cluster com sharding, faça-o pelo mongos com o balancer parado, para garantir consistência.","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 roda em segundo plano via fork; SAVE bloqueia o servidor (não use em produção). Com AOF habilitado, perde-se menos dados.","danger":"safe"}}},{"id":"restore-dump","title":"Restaurar a partir de backup","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":"Use REMAP_SCHEMA para carregar em outro schema e REMAP_TABLESPACE para outra 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 remove os objetos existentes. Use -j <n> para um restore paralelo.","danger":"danger"},"mysql":{"command":"mysql -u root -p target_db < db.sql","note":"O banco de dados de destino já deve existir (CREATE DATABASE). Para arquivos grandes, prefere-se o comando source.","danger":"danger"},"mssql":{"command":"RESTORE DATABASE [MyDB]\nFROM DISK = N'C:\\backup\\MyDB_full.bak'\nWITH REPLACE, RECOVERY;","note":"Para point-in-time, restaure o backup completo WITH NORECOVERY e depois aplique os backups de log com STOPAT.","danger":"danger"},"mongodb":{"command":"mongorestore --uri=\"mongodb://localhost:27017\" \\\n  --archive=db.archive.gz --gzip --drop","note":"--drop exclui as coleções de destino antes de restaurar. Use --nsInclude para um restore seletivo.","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":"Com AOF habilitado, o AOF é carregado em vez do RDB; para restaurar a partir do RDB, inicie com appendonly no ou reconstrua o AOF.","danger":"danger"}}},{"id":"last-backup-status","title":"Verificar status / horário do último backup","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":"O histórico do RMAN também pode ser visto com 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":"Backups lógicos (pg_dump) não são registrados dentro do banco; verifique os logs da ferramenta/job de backup.","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 mostra os arquivos de binlog disponíveis (a janela de PITR); o histórico de backups fica no log da ferramenta (Xtrabackup etc.).","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 registra todos os backups feitos pelo 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":"A janela do oplog determina até quando é possível fazer PITR a partir do replica set; o histórico de backups fica no log da ferramenta.","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 fornece o horário do último salvamento RDB bem-sucedido (Unix epoch); rdb_changes_since_last_save mostra quantas escritas ainda não estão no backup.","danger":"safe"}}}]},"rosetta/security.json":{"category":"Usuários e privilégios","categoryId":"security","order":5,"concepts":[{"id":"list-users","title":"Listar usuários / roles","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 mostra os estados LOCKED/EXPIRED. Para roles, use dba_roles.","danger":"safe"},"postgres":{"command":"SELECT rolname, rolsuper, rolcanlogin, rolvaliduntil\nFROM pg_roles\nORDER BY rolname;\n-- Shortcut (psql): \\du","note":"No PostgreSQL, um usuário é uma role com o atributo LOGIN; rolcanlogin faz a distinção.","danger":"safe"},"mysql":{"command":"SELECT user, host, account_locked, password_expired\nFROM mysql.user\nORDER BY user;","note":"No MySQL, uma identidade é um par usuário + host ('app'@'%' e 'app'@'localhost' são diferentes).","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":"Um login é de nível de servidor, um user é de nível de banco de dados; os dois são mapeados pelo 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":"Os usuários são definidos no banco de dados em que foram criados (authenticationDatabase).","danger":"safe"},"redis":{"command":"ACL LIST\n# Names only: ACL USERS\n# Your own identity: ACL WHOAMI","note":"O sistema de ACL do Redis 6+. Antes disso, havia um único usuário 'default' e o requirepass.","danger":"safe"}}},{"id":"create-user-grant","title":"Criar um usuário e conceder privilégios","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":"Sem CREATE SESSION o usuário não consegue se conectar. Para uma cota: 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":"Para tabelas criadas no futuro: 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":"'%' permite conexões de qualquer host; por segurança, especifique um IP/host determinado sempre que possível. CREATE USER/GRANT têm efeito imediato; FLUSH PRIVILEGES só é necessário se DML foi executado diretamente nas tabelas de grants.","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":"Um login vale para todo o servidor; um user é criado separadamente em cada banco de dados. Para uma role: 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":"O db em que o usuário é criado passa a ser seu auth db. Roles nativas: 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 = habilitado, >password adiciona uma senha, ~app:* é o padrão de chaves, +@read/+@write são categorias de comandos. Se não for persistido, perde-se no restart: ACL SAVE só funciona quando um aclfile está configurado e retorna erro caso contrário; nesse caso, use CONFIG REWRITE.","danger":"caution"}}},{"id":"show-privileges","title":"Mostrar os privilégios de um usuário","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":"O grantee é armazenado em maiúsculas. Para privilégios indiretos concedidos por roles, percorra também 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":"As associações a roles (herança) ficam em pg_auth_members; \\du/\\drg mostram apenas associações diretas; use pg_has_role('app', '<role>', 'MEMBER') para associação indireta.","danger":"safe"},"mysql":{"command":"SHOW GRANTS FOR 'app'@'%';","note":"Para roles (MySQL 8), primeiro execute SET ROLE ALL ou use 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":"Para permissões concedidas por roles, verifique também as associações em sys.database_role_members.","danger":"safe"},"mongodb":{"command":"db.getUser(\"app\", { showPrivileges: true, showCredentials: false })","note":"showPrivileges também lista os privilégios expandidos (efetivos) das roles.","danger":"safe"},"redis":{"command":"ACL GETUSER app","note":"Retorna os comandos permitidos, os padrões de chaves (~), os canais pub/sub (&) e os hashes de senha.","danger":"safe"}}},{"id":"change-password","title":"Alterar a senha de um usuário","aliases":["change password","reset password","change password","reset password","alter password"],"engines":{"oracle":{"command":"ALTER USER app IDENTIFIED BY \"New#Pass2\";","note":"Para desbloquear uma conta bloqueada: ALTER USER app ACCOUNT UNLOCK; Se a senha expirou, o mesmo comando a redefine.","danger":"caution"},"postgres":{"command":"ALTER ROLE app WITH PASSWORD 'New#Pass2';","note":"Para manter a senha fora dos logs, o meta-comando \\password app (psql) gera o hash da senha no lado do cliente.","danger":"caution"},"mysql":{"command":"ALTER USER 'app'@'%' IDENTIFIED BY 'New#Pass2';","note":"Certifique-se de escolher o host correto; 'app'@'localhost' é uma conta separada. ALTER USER tem efeito imediato; FLUSH PRIVILEGES não é necessário.","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 pode forçar a troca no primeiro login: WITH PASSWORD='...' MUST_CHANGE, CHECK_POLICY=ON.","danger":"caution"},"mongodb":{"command":"db.changeUserPassword(\"app\", \"New#Pass2\")","note":"Certifique-se de ter mudado para o auth database do usuário (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 remove todas as senhas existentes; > apenas adiciona uma. Para persistir, execute ACL SAVE se um aclfile for usado, ou CONFIG REWRITE se os usuários estiverem definidos no redis.conf (ACL SAVE retorna erro sem aclfile).","danger":"caution"}}}]},"rosetta/maintenance.json":{"category":"Manutenção e administração","categoryId":"maintenance","order":6,"concepts":[{"id":"update-statistics","title":"Atualizar estatísticas (para o otimizador)","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":"A tarefa AUTO geralmente as coleta à noite; colete manualmente quando houver um problema. Recomenda-se ESTIMATE_PERCENT=>AUTO_SAMPLE_SIZE.","danger":"safe"},"postgres":{"command":"ANALYZE customer;\n-- Both cleanup and analyze: VACUUM ANALYZE customer;","note":"O autovacuum faz isso automaticamente; um ANALYZE manual após uma carga de dados repentina gera planos precisos.","danger":"safe"},"mysql":{"command":"ANALYZE TABLE customer;","note":"Obtém um breve lock de leitura no InnoDB; em tabelas grandes, execute em períodos de baixa atividade.","danger":"safe"},"mssql":{"command":"UPDATE STATISTICS dbo.customer WITH FULLSCAN;\n-- Whole database: EXEC sp_updatestats;","note":"FULLSCAN é o mais preciso, mas o mais caro; em tabelas grandes, pode-se preferir a amostragem (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":"Em vez de estimativa de custo, o MongoDB executa testes reais (plan racing); estatísticas manuais não são necessárias.","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no query optimizer / statistics.","note":"A complexidade dos comandos é fixa; o desempenho depende da escolha da estrutura de dados.","danger":"safe"}}},{"id":"rebuild-index","title":"Reconstruir / reorganizar um índice","aliases":["rebuild index","reindex","refresh index","reorganize","index maintenance","defrag index"],"engines":{"oracle":{"command":"ALTER INDEX customer_city_idx REBUILD ONLINE;","note":"ONLINE reconstrói sem bloquear a tabela (Enterprise Edition). Para movê-lo para outra tablespace: ... 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+) reconstrói sem bloquear as escritas na tabela; mais lento, porém seguro.","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 permite escritas concorrentes; INPLACE pode não ser possível para todo ALTER.","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":"Limite comum: fragmentação de 5-30% REORGANIZE, >30% REBUILD. ONLINE é um recurso da Enterprise.","danger":"caution"},"mongodb":{"command":"db.customer.reIndex()","note":"Reconstrói todos os índices em primeiro plano e bloqueia a coleção. No 6.0+ só roda em standalone (não é permitido em membros de replica set); em um replica set, reconstrua um único índice com dropIndex + createIndex, nó por nó (rolling).","danger":"danger"},"redis":{"command":"# Not applicable (core). If RediSearch is used:\n# FT.ALTER / rebuilding is done per the module documentation.","note":"O modelo chave-valor não tem manutenção tradicional de índices.","danger":"safe"}}},{"id":"reclaim-space","title":"Recuperar espaço livre (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 reduz o high water mark (HWM). Para reduzir também os índices, use 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 obtém um AccessExclusiveLock e reescreve a tabela; não execute em horários de pico. Alternativa: pg_repack.","danger":"caution"},"mysql":{"command":"OPTIMIZE TABLE customer;","note":"No InnoDB, reconstrói a tabela e devolve o espaço data_free; demora bastante em tabelas grandes.","danger":"caution"},"mssql":{"command":"-- Generally NOT RECOMMENDED (causes fragmentation). If really needed:\nDBCC SHRINKFILE (N'MyDB_data', 1024);  -- target 1024 MB","note":"Reduzir um arquivo de dados causa fragmentação de índices; faça REBUILD dos índices depois. Para o log, faça um backup antes.","danger":"danger"},"mongodb":{"command":"db.runCommand({ compact: \"customer\" })","note":"No WiredTiger, tenta devolver o espaço livre ao sistema operacional (nem sempre é possível). No 4.4+ não bloqueia leituras/escritas, apenas certas operações DDL na mesma coleção; como gera IO intenso, executá-lo em um secondary e em uma janela de manutenção é mais seguro.","danger":"danger"},"redis":{"command":"MEMORY PURGE\n# Tries to return jemalloc fragmentation to the OS","note":"A configuração activedefrag yes faz desfragmentação automática online; MEMORY DOCTOR dá recomendações.","danger":"caution"}}},{"id":"version-uptime","title":"Mostrar versão e uptime","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 também fornece detalhes da instância, como status e 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 é útil para comparação numérica (ex.: 160002 = 16.2).","danger":"safe"},"mysql":{"command":"SELECT VERSION();\nSHOW GLOBAL STATUS LIKE 'Uptime';  -- seconds","note":"Uptime está em segundos; divida por 86400 para obter dias.","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') e ('Edition') fornecem detalhes de versão/edição.","danger":"safe"},"mongodb":{"command":"db.version()\ndb.serverStatus().uptime   // seconds","note":"serverStatus() também inclui informações de host, process e connections.","danger":"safe"},"redis":{"command":"INFO server\n# redis_version and uptime_in_seconds / uptime_in_days lines","note":"INFO server também fornece informações de os, run_id e tcp_port.","danger":"safe"}}},{"id":"show-config-param","title":"Ver um parâmetro de configuração","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":"Para alterá-lo: ALTER SYSTEM SET ... SCOPE=BOTH; (alguns apenas com SCOPE=SPFILE + restart).","danger":"safe"},"postgres":{"command":"SHOW shared_buffers;\n-- Details: SELECT name, setting, unit, context FROM pg_settings WHERE name = 'shared_buffers';","note":"A coluna context indica se a alteração exige restart ou reload (SELECT pg_reload_conf()).","danger":"safe"},"mysql":{"command":"SHOW VARIABLES LIKE 'innodb_buffer_pool_size';","note":"Atenção à distinção GLOBAL vs SESSION: SHOW GLOBAL VARIABLES mostra o valor de todo o servidor.","danger":"safe"},"mssql":{"command":"SELECT name, value, value_in_use, is_dynamic\nFROM sys.configurations\nWHERE name LIKE '%max server memory%';","note":"Para alterá-lo: sp_configure + RECONFIGURE; opções com is_dynamic=0 exigem restart.","danger":"safe"},"mongodb":{"command":"db.adminCommand({ getParameter: 1, cursorTimeoutMillis: 1 })\n// All startup options: db.adminCommand({ getCmdLineOpts: 1 })","note":"Use setParameter para os que podem ser alterados em tempo de execução; as configurações persistentes ficam no arquivo mongod.conf.","danger":"safe"},"redis":{"command":"CONFIG GET maxmemory\n# Wildcard: CONFIG GET max*","note":"Use CONFIG SET para alterar em tempo de execução; CONFIG REWRITE para persistir (grava no redis.conf).","danger":"safe"}}}]},"rosetta/schema.json":{"category":"Schema e objetos","categoryId":"schema","order":7,"concepts":[{"id":"list-tables","title":"Listar tabelas / coleções","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 retorna as tabelas do schema atual; all_tables, as que estão acessíveis.","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":"Apenas para o schema public: WHERE table_schema = 'public'.","danger":"safe"},"mysql":{"command":"SHOW TABLES;\n-- Another schema: SHOW TABLES FROM mydb;","note":"Para detalhes: 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":"Atalho: SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE';","danger":"safe"},"mongodb":{"command":"show collections\n// or: db.getCollectionNames()","note":"Para ver também as coleções do sistema: db.getCollectionInfos().","danger":"safe"},"redis":{"command":"SCAN 0 MATCH * COUNT 100\n# Continue with SCAN <cursor> ... using the returned cursor","note":"O Redis não tem 'tabelas'; as chaves é que são listadas. NUNCA use KEYS * em produção (bloqueia); SCAN é baseado em cursor.","danger":"caution"}}},{"id":"describe-table","title":"Mostrar as colunas / estrutura de uma tabela (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":"Os nomes das tabelas são armazenados em maiúsculas (se criados sem aspas).","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 também mostra índices, constraints e chaves estrangeiras.","danger":"safe"},"mysql":{"command":"DESCRIBE customer;\n-- or: SHOW COLUMNS FROM customer;","note":"Para a definição completa, use SHOW CREATE TABLE customer; (veja o conceito 'Gerar DDL' abaixo).","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 lista índices e constraints, além das colunas.","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":"O MongoDB não tem schema fixo; os campos podem variar de documento para documento. Se um validador $jsonSchema estiver definido, ele pode ser visto com db.getCollectionInfos.","danger":"safe"},"redis":{"command":"TYPE mykey        # string | list | set | hash | zset | stream\nOBJECT ENCODING mykey   # internal encoding","note":"Não há schema fixo; o tipo e o encoding de cada chave são consultados separadamente. Use HGETALL para os campos de um hash.","danger":"safe"}}},{"id":"list-indexes","title":"Listar os índices de uma tabela","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":"Faça join com user_indexes para obter o tipo/unicidade do índice.","danger":"safe"},"postgres":{"command":"SELECT indexname, indexdef\nFROM pg_indexes\nWHERE tablename = 'customer';","note":"indexdef fornece a instrução CREATE INDEX completa; \\d customer no psql também os lista.","danger":"safe"},"mysql":{"command":"SHOW INDEX FROM customer;","note":"As colunas Non_unique, Seq_in_index e Cardinality mostram a estrutura e a seletividade do índice.","danger":"safe"},"mssql":{"command":"EXEC sp_helpindex 'dbo.customer';\n-- Details: join sys.indexes + sys.index_columns","note":"sp_helpindex retorna nome, tipo e colunas do índice; use as views sys para colunas filtradas/incluídas.","danger":"safe"},"mongodb":{"command":"db.customer.getIndexes()","note":"Retorna as chaves de cada índice e opções como unicidade e 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":"O modelo chave-valor não tem índices secundários; eles só vêm com módulos como RediSearch/RedisJSON.","danger":"safe"}}},{"id":"create-index","title":"Criar um índice","aliases":["create index","add index","build index","new index","createindex"],"engines":{"oracle":{"command":"CREATE INDEX customer_city_idx ON customer(city) ONLINE;","note":"ONLINE o cria sem bloquear a tabela. Use CREATE UNIQUE INDEX para único; (a, b) para composto.","danger":"caution"},"postgres":{"command":"CREATE INDEX CONCURRENTLY customer_city_idx ON customer(city);","note":"CONCURRENTLY não bloqueia as escritas na tabela, mas não pode ser executado dentro de um bloco de transação e é mais lento.","danger":"caution"},"mysql":{"command":"CREATE INDEX customer_city_idx ON customer(city);\n-- Lock-free: ... ALGORITHM=INPLACE, LOCK=NONE;","note":"O InnoDB adiciona a maioria dos índices online; em tabelas grandes, permita escritas com LOCK=NONE.","danger":"caution"},"mssql":{"command":"CREATE NONCLUSTERED INDEX IX_customer_city\nON dbo.customer (city)\nWITH (ONLINE = ON);","note":"ONLINE é um recurso da Enterprise. Para colunas de cobertura, use 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 é ordem ascendente, -1 descendente. Em coleções grandes, criar primeiro em um secondary reduz a carga.","danger":"caution"},"redis":{"command":"# Not applicable (core). If RediSearch is present:\n# FT.CREATE idx ON HASH PREFIX 1 customer: SCHEMA city TAG","note":"Índices secundários só vêm com o módulo RediSearch; no Redis core, o acesso é por chave.","danger":"safe"}}},{"id":"show-ddl","title":"Gerar o DDL de um objeto (instrução 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":"Use 'INDEX' para índices, 'PACKAGE' para packages etc. Evite o truncamento de saídas longas com 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":"No psql, \\d customer mostra a estrutura de forma legível; para o DDL completo, use pg_dump --schema-only.","danger":"safe"},"mysql":{"command":"SHOW CREATE TABLE customer\\G","note":"Retorna o CREATE TABLE completo (colunas, índices, engine, charset) em um único comando.","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":"Para o corpo de uma procedure/view: 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":"Se options.validator ($jsonSchema) estiver definido, ele é a única 'definição de schema'; os índices são obtidos separadamente com getIndexes().","danger":"safe"},"redis":{"command":"# Not applicable: there is no schema/DDL concept.","note":"As estruturas de dados são definidas no código da aplicação; a persistência fica nos arquivos RDB/AOF.","danger":"safe"}}}]},"rosetta/replication.json":{"category":"Replicação e HA","categoryId":"replication","order":8,"concepts":[{"id":"replication-status","title":"Mostrar status e lag da replicação","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 e transport lag são as principais métricas de lag do Data Guard; execute isto no standby.","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 é o atraso de replay; sync_state = 'sync' indica uma réplica síncrona.","danger":"safe"},"mysql":{"command":"SHOW REPLICA STATUS\\G\n-- Before 8.0.22: SHOW SLAVE STATUS\\G","note":"Seconds_Behind_Source fornece o lag; Replica_IO_Running e Replica_SQL_Running devem estar 'Yes'. SHOW SLAVE STATUS é um alias no 8.0.22–8.3 e foi removido no 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":"Para Always On. Um redo_queue_size grande significa que a réplica secundária está ficando para trás.","danger":"safe"},"mongodb":{"command":"rs.printSecondaryReplicationInfo()\n// Detailed status: rs.status()","note":"Mostra quantos segundos cada secondary está atrás do primary; os valores de optimeDate são comparados.","danger":"safe"},"redis":{"command":"INFO replication\n# Check the role, connected_slaves, master_repl_offset,\n# and slaveN:...,offset=... lines","note":"A diferença entre master_repl_offset e o offset do slave fornece o lag; master_link_status deve estar 'up'.","danger":"safe"}}},{"id":"list-replicas","title":"Listar réplicas / nós do cluster","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":"A configuração do Data Guard também pode ser vista com DGMGRL> SHOW CONFIGURATION.","danger":"safe"},"postgres":{"command":"SELECT application_name, client_addr, state, sync_state\nFROM pg_stat_replication;","note":"Lista as réplicas conectadas apenas no PRIMARY; cada linha é um standby.","danger":"safe"},"mysql":{"command":"SHOW REPLICAS;\n-- Before 8.0.22: SHOW SLAVE HOSTS;","note":"Execute no servidor de origem; mostra as réplicas que têm report-host definido. SHOW SLAVE HOSTS é um alias no 8.0.22–8.3 e foi removido no 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 distingue PRIMARY/SECONDARY; synchronization_health_desc fornece a saúde geral.","danger":"safe"},"mongodb":{"command":"rs.status().members.map(m => ({ name: m.name, state: m.stateStr, health: m.health }))","note":"stateStr retorna PRIMARY/SECONDARY/ARBITER; health 1 significa saudável.","danger":"safe"},"redis":{"command":"INFO replication\n# If Sentinel is used:\n# SENTINEL replicas <master-name>","note":"As linhas slave0, slave1... fornecem ip/port/offset de cada réplica.","danger":"safe"}}},{"id":"promote-failover","title":"Promover uma réplica / fazer failover (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 é uma transição de papéis planejada; FAILOVER é realizado enquanto o primary está inacessível e traz risco de perda de dados.","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":"Antes de promover, certifique-se de que o antigo primary esteja realmente parado (risco de split-brain). Após a promoção, reintegrar o antigo primary como réplica do novo primary exige pg_rewind; para isso, wal_log_hints = on ou data checksums devem estar habilitados.","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":"Se RESET REPLICA ALL for executado antes de o relay log ser totalmente aplicado, as transações recebidas mas não aplicadas são perdidas. As réplicas geralmente rodam com read_only/super_read_only habilitado; escritas não são aceitas até que sejam desativados. Se a antiga origem ainda aceitar escritas, há risco de split-brain. A sintaxe é do 8.0.22+ (antes, STOP SLAVE / RESET SLAVE ALL; a forma antiga foi removida no 8.4). Para failover automático e seguro em produção, prefira InnoDB Cluster/Group Replication, Orchestrator ou 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":"Um failover planejado para uma réplica síncrona não tem perda de dados; FORCE é usado apenas em um cenário de desastre.","danger":"danger"},"mongodb":{"command":"// Trigger an election on the current primary:\nrs.stepDown(60)   // step down from primary for 60 s","note":"stepDown inicia uma nova eleição; para favorecer um nó específico, ajuste os valores de priority dos membros.","danger":"danger"},"redis":{"command":"# Make the replica an independent primary:\nREPLICAOF NO ONE\n# With Sentinel (recommended): SENTINEL FAILOVER <master-name>","note":"Se você usa Sentinel/Cluster, use SENTINEL FAILOVER em vez de um REPLICAOF manual; caso contrário, há risco de split-brain.","danger":"danger"}}},{"id":"open-transactions","title":"Encontrar transações abertas / de longa duração","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":"Um used_ublk alto significa que uma transação grande está consumindo muito undo; ela pode estar aguardando um commit/rollback.","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":"Transações longas no estado 'idle in transaction' bloqueiam o VACUUM e a limpeza de tuplas; monitore-as.","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":"Use trx_mysql_thread_id para correlacionar com a PROCESSLIST e faça KILL se necessário.","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":"Transações abertas longas impedem o truncamento do log e incham o arquivo de log.","danger":"safe"},"mongodb":{"command":"db.adminCommand({\n  currentOp: 1,\n  \"transaction\": { $exists: true }\n})","note":"Transações multidocumento longas são abortadas automaticamente após transactionLifetimeLimitSeconds (padrão 60 s).","danger":"safe"},"redis":{"command":"# Not applicable: MULTI/EXEC transactions are short and atomic; they do not stay open.","note":"As transações do Redis não mantêm locks; para comandos únicos de longa duração, verifique o SLOWLOG.","danger":"safe"}}}]},"rosetta/connect.json":{"category":"Conexão e CLI","categoryId":"connect","order":9,"concepts":[{"id":"connect-cli","title":"Conectar pela linha de comando (CLI / connection string)","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 é o formato 'Easy Connect'; como alternativa, use um alias TNS do tnsnames.ora.","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":"Para não digitar a senha na linha de comando, use um arquivo ~/.pgpass ou a variável de ambiente PGPASSWORD.","danger":"safe"},"mysql":{"command":"mysql -h host -P 3306 -u root -p mydb\n# Require TLS: --ssl-mode=REQUIRED","note":"Passe -p sozinho (a senha é solicitada); a forma 'mysql -pPassword' expõe a senha na lista de processos.","danger":"safe"},"mssql":{"command":"sqlcmd -S host,1433 -U sa -P password -d mydb\n# Windows authentication: sqlcmd -S host -E -d mydb","note":"No go-sqlcmd mais recente, as flags -C (confiar no certificado do servidor) e -N (criptografar) podem ser necessárias para TLS.","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 geralmente é o banco de dados em que o usuário está definido (na maioria das vezes, 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 passa a senha na linha de comando (exibe um aviso); para login seguro, use a variável de ambiente REDISCLI_AUTH.","danger":"safe"}}},{"id":"list-databases","title":"Listar bancos de dados / schemas","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":"No Oracle, um 'banco de dados' corresponde à instância; a separação é em nível de schema (usuário) ou de PDB dentro de um CDB.","danger":"safe"},"postgres":{"command":"SELECT datname FROM pg_database WHERE datistemplate = false;\n-- psql shortcut: \\l","note":"Para schemas: SELECT schema_name FROM information_schema.schemata;","danger":"safe"},"mysql":{"command":"SHOW DATABASES;","note":"No MySQL, 'database' e 'schema' são sinônimos.","danger":"safe"},"mssql":{"command":"SELECT name, state_desc FROM sys.databases ORDER BY name;","note":"state_desc mostra o estado do banco de dados, como ONLINE/OFFLINE/RESTORING.","danger":"safe"},"mongodb":{"command":"show dbs\n// or: db.adminCommand({ listDatabases: 1 })","note":"Bancos de dados vazios (sem dados gravados ainda) não aparecem na lista.","danger":"safe"},"redis":{"command":"INFO keyspace\n# db0:keys=..., db1:keys=... lines show the logical DBs in use","note":"O Redis tem DBs lógicos numerados (padrão 0-15); no modo Cluster, apenas o DB 0 é usado.","danger":"safe"}}},{"id":"switch-database","title":"Alterar o banco de dados / schema ativo","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 altera apenas a resolução de nomes de objetos, não os privilégios.","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":"No PostgreSQL, uma conexão fica vinculada a um único banco de dados; trocar de DB significa reconectar.","danger":"safe"},"mysql":{"command":"USE mydb;","note":"Altera o schema ativo sem derrubar a conexão.","danger":"safe"},"mssql":{"command":"USE mydb;","note":"Altera o contexto do batch; os comandos seguintes são executados neste banco de dados.","danger":"safe"},"mongodb":{"command":"use mydb","note":"Muda mesmo que o banco de dados não exista; ele é de fato criado quando o primeiro documento é gravado.","danger":"safe"},"redis":{"command":"SELECT 1\n# Switches to a logical DB index between 0 and 15","note":"No modo Cluster, SELECT aceita apenas 0; use prefixos de chave em vez de separação por DB lógico.","danger":"safe"}}}]},"rosetta/objects.json":{"category":"Gerenciamento de objetos","categoryId":"objects","order":10,"concepts":[{"id":"create-partition","title":"Criar / dividir / remover uma partição","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":"Suporta particionamento RANGE/LIST/HASH. DROP PARTITION exclui todas as linhas daquela partição; com UPDATE INDEXES, os índices globais permanecem válidos. O particionamento por intervalo (interval) pode adicionar partições automaticamente.","danger":"caution","priv":"ALTER na tabela","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":"O PostgreSQL core não tem SPLIT/MERGE PARTITION (até o PG17); para dividir, faça DETACH da partição, crie duas partições com os novos limites, mova os dados e faça ATTACH. DETACH ... CONCURRENTLY (PG14+) reduz a duração do lock.","danger":"caution","priv":"proprietário da tabela","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":"A coluna de particionamento deve fazer parte de toda PRIMARY KEY / chave UNIQUE. Para RANGE, a divisão/junção é feita com REORGANIZE PARTITION. DROP PARTITION também exclui as linhas (RANGE/LIST).","danger":"caution","priv":"ALTER, DROP na tabela","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":"Define-se uma partition function + scheme, e a tabela é criada sobre esse scheme com CREATE TABLE ... ON ps_date(created_at). O filegroup NEXT USED deve ser definido antes do SPLIT. Para remover dados, mova-os para uma tabela de staging com SWITCH PARTITION.","danger":"caution","priv":"ALTER na tabela, ALTER ANY DATASPACE","minver":"2016 SP1 (todas as edições)"},"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":"Não há particionamento no sentido clássico. A divisão horizontal é feita via chunks com sharding; para dados baseados em tempo, as time-series collections fazem bucketing automático.","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no table/partition concept; scaling is done with Redis Cluster hash slots (16384).","note":"O Redis Cluster distribui as chaves entre 16384 hash slots; trata-se de divisão em nível de aplicação, não de particionamento de tabela. Não há comando manual de partição.","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":"No Elasticsearch, a divisão é obtida dividindo um índice em shards e, para séries temporais, criando novos backing indices com ILM + data streams (rollover). Índices antigos podem ser excluídos com ILM.","danger":"safe"}}},{"id":"sequence","title":"Criar uma sequence / valor auto-incremento","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":"O método clássico é CREATE SEQUENCE + NEXTVAL/CURRVAL. Desde o 12c, colunas GENERATED AS IDENTITY também são suportadas. Um valor de CACHE melhora o desempenho, mas podem ocorrer lacunas.","danger":"safe","priv":"CREATE SEQUENCE","minver":"12c para IDENTITY"},"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 é padrão SQL e recomendado; serial é a forma abreviada legada. Acesse manualmente com nextval/currval. O valor pode ser redefinido com setval.","danger":"safe","priv":"CREATE no schema","minver":"PG10 para IDENTITY"},"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":"O MySQL não tem um objeto sequence independente (padrão); usa-se uma coluna AUTO_INCREMENT (uma por tabela, deve estar indexada). O MariaDB 10.3+ suporta CREATE SEQUENCE.","danger":"safe","priv":"CREATE, ALTER na tabela"},"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) fica vinculado a uma coluna da tabela. CREATE SEQUENCE (2012+) fornece um contador independente das tabelas, que pode ser compartilhado entre elas; os valores são obtidos com NEXT VALUE FOR.","danger":"safe","priv":"CREATE SEQUENCE / ALTER na tabela","minver":"2012 para SEQUENCE"},"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":"O _id padrão é um ObjectId (já único e aproximadamente crescente). Se for necessário um inteiro sequencial, gere-o de forma atômica com $inc em uma coleção counters separada.","danger":"safe"},"redis":{"command":"# Atomic counter\nINCR customer:id\n# or with a specific step\nINCRBY customer:id 10","note":"INCR/INCRBY são atômicos e ideais para gerar IDs únicos crescentes em ambientes distribuídos. Se a chave não existir, começa em 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":"Se você fizer POST sem um ID, o ES atribui um _id único aleatório (não crescente). _seq_no é um número de sequência interno que aumenta a cada escrita, mas serve para concorrência otimista, não como contador da aplicação.","danger":"safe"}}},{"id":"add-constraint","title":"Adicionar ou desabilitar uma constraint (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":"As constraints do Oracle podem ser desligadas temporariamente com DISABLE/ENABLE (útil em cargas em massa). ENABLE VALIDATE verifica as linhas existentes; NOVALIDATE não.","danger":"caution","priv":"ALTER na tabela, REFERENCES no destino"},"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":"O PostgreSQL não tem DISABLE de constraint. Para reduzir o lock em uma tabela grande, adicione a constraint com NOT VALID e faça VALIDATE depois. ALTER TABLE ... DISABLE TRIGGER ALL também desabilita os triggers internos da FK e exige superuser; os dados inseridos enquanto estão desligados nunca são validados, e reabilitar não verifica retroativamente (risco de perda silenciosa de integridade). Em vez disso, faça DROP da constraint, adicione-a novamente com NOT VALID e depois execute VALIDATE CONSTRAINT.","danger":"caution","priv":"proprietário da tabela, REFERENCES no destino"},"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":"Requer InnoDB. Em vez de desabilitar uma única constraint, usa-se SET FOREIGN_KEY_CHECKS=0 em nível de sessão. As constraints CHECK só são de fato aplicadas a partir do MySQL 8.0.16 (antes eram ignoradas).","danger":"caution","priv":"ALTER, REFERENCES na tabela","minver":"8.0.16 para CHECK"},"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":"No SQL Server, as constraints FK/CHECK são desabilitadas com NOCHECK CONSTRAINT. Se WITH CHECK CHECK CONSTRAINT não for usado ao reabilitar, a constraint fica 'not trusted' e o otimizador de consultas não pode usá-la.","danger":"caution","priv":"ALTER na tabela, REFERENCES no destino"},"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":"Não há chaves estrangeiras (são garantidas na camada da aplicação). O equivalente a UNIQUE é um índice único. Em vez de CHECK, use validação $jsonSchema; validationAction: 'warn' produz o efeito de desabilitá-la.","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":"Não existe o conceito de integridade relacional ou constraints. A unicidade é controlada no lado da aplicação com SET ... NX (grava apenas se não existir) ou verificando um SET/HASH separado.","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":"Relações e constraints não existem no engine. A verificação de tipos é feita pelo mapping. Para um efeito de UNIQUE, use a chave natural como _id (escritas no mesmo _id sobrescrevem) ou rejeite conflitos com op_type=create.","danger":"safe"}}},{"id":"create-view","title":"Criar / alterar uma view","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 tanto cria quanto altera. Para views atualizáveis sob certas condições, pode-se adicionar 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":"Com CREATE OR REPLACE, novas colunas só podem ser adicionadas no final; alterar o tipo/ordem de uma coluna exige DROP antes. Views simples são atualizáveis automaticamente.","danger":"safe","readonly":true,"priv":"CREATE no schema"},"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":"A definição é atualizada com CREATE OR REPLACE VIEW ou ALTER VIEW. O método de execução pode ser definido com ALGORITHM = MERGE/TEMPTABLE; WITH CHECK OPTION protege as views atualizáveis.","danger":"safe","readonly":true,"priv":"CREATE VIEW na tabela"},"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+) cria/altera em uma única instrução. Em versões mais antigas, use CREATE primeiro e depois ALTER VIEW. A instrução da view deve ser a primeira do batch.","danger":"safe","readonly":true,"priv":"CREATE VIEW","minver":"2016 SP1 para OR ALTER"},"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 cria uma view somente leitura sobre uma coleção de origem e um pipeline de agregação. Não é possível gravar em views; para alterar a definição, remova e recrie (ou use 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":"Não há suporte a views definidas sobre consultas. Para uma necessidade semelhante, mantenha chaves pré-calculadas ou crie um índice pesquisável com 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":"Não há view SQL clássica; um alias filtrado é o equivalente mais próximo e aplica o filtro às consultas automaticamente. Para seleção de colunas, use filtragem de _source na consulta.","danger":"safe","readonly":true}}},{"id":"materialized-view","title":"Criar e atualizar uma materialized view","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 requer um materialized view log; COMPLETE ('C') recalcula tudo, FAST ('F') é incremental. ON COMMIT/ON DEMAND determina quando ocorre o refresh.","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 recalcula tudo (não é incremental). CONCURRENTLY não bloqueia leituras, mas requer um índice único e é mais lento.","danger":"caution","priv":"proprietário da tabela","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":"Não há suporte nativo a materialized views. Mantém-se uma tabela de resumo, repopulada instantaneamente com triggers ou periodicamente com o EVENT SCHEDULER.","danger":"caution","priv":"CREATE, EVENT no schema"},"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":"O SQL Server usa indexed views: WITH SCHEMABINDING é obrigatório; depois que um índice clustered único é criado, os dados são armazenados fisicamente e mantidos automaticamente (não é necessário REFRESH separado). Com GROUP BY, COUNT_BIG(*) é obrigatório; se a coluna dentro de SUM aceitar nulos, escreva SUM(ISNULL(amount, 0)) (caso contrário, erro 8662). A view deve ser criada com QUOTED_IDENTIFIER e ANSI_NULLS ON. A correspondência automática de views pelo otimizador de consultas existe apenas nas edições Enterprise (e Developer); na Standard, referencie a view com o hint WITH (NOEXPAND).","danger":"caution","priv":"CREATE VIEW, ALTER no schema"},"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":"Obtém-se uma materialized view sob demanda gravando o resultado da agregação em uma coleção persistente com $out ou $merge. Para atualizar, execute o pipeline novamente (manualmente ou com um agendador).","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":"Não existe o conceito de materialized view; a abordagem mais próxima é manter valores pré-calculados em chaves (String/Hash/Sorted Set) e armazená-los em cache por tempo limitado com 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":"Um transform pivota o índice de origem e o materializa em um índice de destino de resumo. Este exemplo é um transform em batch: executa uma vez com _start e para. Para um transform contínuo que se atualiza automaticamente à medida que chegam novos dados, adicione \"sync\": { \"time\": { \"field\": \"<time_field>\", \"delay\": \"60s\" } } com um campo de tempo à configuração (não existe a configuração continuous: true).","danger":"caution"}}},{"id":"rename-object","title":"Renomear uma tabela / objeto","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 ou ALTER ... RENAME TO é usado para tabelas/views/sequences. Objetos dependentes (views, synonyms) podem ficar inválidos e precisar ser recompilados.","danger":"caution","priv":"ALTER no objeto"},"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 funciona para a maioria dos tipos de objeto. Referências de chaves estrangeiras e índices são preservadas automaticamente mesmo com a mudança de nome (baseadas em OID).","danger":"caution","priv":"proprietário da tabela"},"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 é atômico e pode mover várias tabelas em uma única instrução. Para renomear colunas, use RENAME COLUMN no 8.0+; antes disso, é preciso usar CHANGE e especificar também o tipo.","danger":"caution","priv":"ALTER, DROP no antigo; CREATE, INSERT no novo"},"mssql":{"command":"-- Table\nEXEC sp_rename 'dbo.old_name', 'new_name';\n-- Column\nEXEC sp_rename 'dbo.customer.name', 'full_name', 'COLUMN';","note":"O SQL Server não tem instrução RENAME TABLE; usa-se a procedure de sistema sp_rename. O prefixo de schema é informado no nome da tabela, mas não no novo nome. Views/procedures dependentes devem ser atualizadas manualmente.","danger":"caution","priv":"ALTER no objeto, 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 altera o nome da coleção. Para renomear um campo, use o operador $rename com updateMany. Coleções com sharding podem ser renomeadas no 5.0+; versões mais antigas não suportam.","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 renomeia a chave; se o destino já existir, é sobrescrito. RENAMENX funciona apenas se o destino não existir. Retorna erro se a chave de origem não existir.","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":"Não há comando para renomear índices. Faça reindex para o novo nome com _reindex e exclua o antigo. Recomenda-se operar atrás de um alias estável, para manter a aplicação independente dos nomes dos índices.","danger":"caution"}}}]},"rosetta/datamove.json":{"category":"Movimentação de dados","categoryId":"datamove","order":11,"concepts":[{"id":"bulk-import","title":"Carga de dados em massa (CSV / a partir de arquivo)","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":"A ferramenta mais comum é o SQL*Loader (com um control file). Para ler o arquivo como uma consulta, use uma external table. Para grandes volumes, o direct path load (DIRECT=TRUE) é rápido.","danger":"caution","priv":"INSERT na tabela, um objeto 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 lê um arquivo no servidor e exige privilégios; o \\copy do psql lê um arquivo do cliente e não precisa de privilégios extras. É a forma mais rápida de carregar CSV.","danger":"caution","priv":"INSERT na tabela (pg_read_server_files para COPY)"},"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 é a forma mais rápida de carga em massa. LOCAL lê um arquivo do cliente e deve estar habilitado tanto no servidor (local_infile=ON) quanto no cliente. secure_file_priv restringe o caminho no servidor.","danger":"caution","priv":"FILE (INSERT para LOCAL)"},"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 lê o arquivo de um caminho acessível à conta de serviço do SQL Server. bcp é uma ferramenta de linha de comando; -c é o modo caractere, -t o terminador de campo. Para máxima velocidade, busque minimal logging com 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 carrega CSV/TSV/JSON; --headerline trata a primeira linha como nomes de campos. Para atualizar documentos existentes, use --mode=upsert --upsertFields. Para grandes volumes, --numInsertionWorkers acelera o processo.","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":"Para carga em massa, use redis-cli --pipe (mass insert); é muito rápido porque transmite os comandos no formato do protocolo RESP por uma única conexão. Como alternativa, os comandos são agrupados com pipelining.","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":"A API _bulk recebe NDJSON (uma linha de ação + uma linha de dados por documento; o arquivo deve terminar com \\n). Para CSV, use Logstash, Filebeat ou elasticdump. Desativar o refresh_interval durante a carga acelera o processo.","danger":"caution","priv":"privilégio index / create index"}}},{"id":"bulk-export","title":"Exportar dados (CSV / para arquivo)","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":"Para CSV, use SET MARKUP CSV ON + SPOOL do SQL*Plus (12.2+). Para mover schemas/tabelas, o Data Pump (expdp) gera um .dmp binário que é importado em outro banco Oracle com impdp.","danger":"safe","readonly":true,"priv":"SELECT na tabela","minver":"12.2 para MARKUP CSV"},"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 grava o resultado de uma consulta em um arquivo (no lado do servidor, exige privilégios); o \\copy do psql grava em um arquivo do cliente. HEADER true adiciona uma linha de cabeçalho.","danger":"safe","readonly":true,"priv":"SELECT na tabela"},"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 cria o arquivo no servidor (exige o caminho de secure_file_priv e o privilégio FILE; não pode sobrescrever). Para saída no lado do cliente, redirecione com 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 grava dados em um arquivo: -c modo caractere, -t, terminador de campo, -n formato binário nativo. Use queryout para o resultado de uma consulta. 'Results to File' no SSMS também é uma opção.","danger":"safe","readonly":true,"priv":"SELECT na tabela"},"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 gera CSV/JSON; para CSV, as colunas devem ser informadas explicitamente com --fields. Use --query para filtrar. Para um backup binário completo, prefere-se o 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":"Não há exportação estruturada para CSV embutida. Use --scan (não bloqueante) para uma lista de chaves e um arquivo RDB para os dados completos: redis-cli --rdb baixa para um arquivo local um snapshot gerado em segundo plano no servidor; se quiser o arquivo no servidor, use BGSAVE. SAVE bloqueia a thread principal; não use em produção. Para obter também os valores, leia o resultado do scan em um loop.","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":"Não há exportação direta para CSV. Para obter todos os dados, use elasticdump ou pagine o _search com scroll/PIT (point-in-time). A conversão para CSV exige o output csv do Logstash ou uma ferramenta externa.","danger":"safe","readonly":true,"priv":"read no índice"}}},{"id":"copy-between","title":"Copiar dados entre tabelas / ambientes","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":"No mesmo banco de dados, use INSERT ... SELECT ou CREATE TABLE AS SELECT (CTAS). Para cópias entre ambientes, prefere-se um database link (@remote_db) ou o Data Pump. O hint APPEND acelera com direct-path.","danger":"caution","priv":"SELECT na origem, INSERT/CREATE no destino"},"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":"No mesmo DB, use INSERT ... SELECT / CTAS. Entre servidores, use um pipeline pg_dump | psql ou copie por uma foreign table com postgres_fdw.","danger":"caution","priv":"SELECT na origem, INSERT/CREATE no destino"},"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":"No mesmo DB, INSERT ... SELECT ou CREATE TABLE ... AS SELECT. Entre servidores diferentes, é comum encadear a saída do mysqldump para o cliente mysql. CTAS não copia índices nem constraints.","danger":"caution","priv":"SELECT na origem, INSERT/CREATE no destino"},"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":"No SQL Server, a cópia para uma nova tabela é feita com SELECT ... INTO (o equivalente ao CTAS). Entre servidores, use um linked server (nome de quatro partes), bcp out/in ou SSIS.","danger":"caution","priv":"SELECT na origem, INSERT / CREATE TABLE no destino"},"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 substitui totalmente a coleção de destino; $merge mescla com/insere em documentos existentes (no mesmo ou em outro DB). Para movimentações entre servidores, use mongodump | mongorestore ou mongoexport/mongoimport.","danger":"caution","priv":"find na origem, insert no destino"},"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 move a chave atomicamente para a instância de destino e a exclui da origem (com a opção COPY, não exclui). Para copiar na mesma instância, use o comando COPY (6.0+) ou 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 copia entre índices; pode ser filtrado com uma consulta e transformado com um script. Entre clusters, use o remote reindex (reindex.remote.whitelist deve estar definido no destino). Trabalhos grandes são paralelizados com slices.","danger":"caution","priv":"read na origem, write no destino"}}},{"id":"generate-insert","title":"Gerar dados como script de 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":"O Oracle não oferece um comando SQL que converta dados diretamente em um script de INSERT pronto. Para DDL, use DBMS_METADATA.GET_DDL; para INSERTs de linhas, use o SQLcl (SET SQLFORMAT INSERT) ou o assistente Export do SQL Developer.","danger":"safe","readonly":true,"priv":"SELECT na tabela"},"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 grava cada linha como um INSERT separado; --column-inserts adiciona também os nomes das colunas (robusto a diferenças de schema). O padrão (sem flag) gera o formato COPY, que carrega muito mais rápido.","danger":"safe","readonly":true,"priv":"SELECT na tabela"},"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 gera instruções INSERT por padrão; --no-create-info ignora o CREATE TABLE e gera apenas os dados. --skip-extended-insert faz de cada linha um INSERT separado (o padrão combina muitas linhas em uma única instrução).","danger":"safe","readonly":true,"priv":"SELECT na tabela"},"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":"O SQL Server não tem um comando T-SQL nativo para isso. A forma mais comum é escolher Data only no assistente 'Generate Scripts' do SSMS. Na linha de comando, a ferramenta mssql-scripter da Microsoft gera INSERTs com --data-only.","danger":"safe","readonly":true,"priv":"SELECT na tabela"},"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":"Não existe o conceito de INSERT SQL. Para um backup portátil, use mongodump (BSON, restaurado com mongorestore). Para um insertMany embutido no código, pode-se usar a saída de 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":"Não é gerado script de INSERT SQL. Use serialização DUMP + RESTORE por chave e um arquivo RDB (--rdb) para todos os dados. Se for necessária uma lista de comandos, itere com SCAN e monte os comandos SET/HSET adequados para cada tipo.","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":"Não é gerado INSERT SQL; no Elasticsearch, a unidade de carga é o NDJSON do _bulk. Para extrair os dados existentes em formato recarregável, use elasticdump (type=data); a saída de _search + PIT pode ser convertida em NDJSON com um script externo.","danger":"safe","readonly":true,"priv":"read no índice"}}}]},"rosetta/monitoring.json":{"category":"Monitoramento e diagnóstico","categoryId":"monitoring","order":12,"concepts":[{"id":"current-locks","title":"Listar os locks atuais","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":"Mostra os locks ativos e a sessão bloqueadora (blocking_session) via v$lock e v$locked_object.","danger":"safe","readonly":true,"priv":"SELECT em v$lock, v$session"},"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":"Faz join de pg_locks com pg_stat_activity; linhas com granted=false mostram locks em espera (bloqueados).","danger":"safe","readonly":true,"priv":"role pg_monitor (para ver todas as consultas)"},"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 lista os locks InnoDB atuais, e data_lock_waits lista as relações de espera.","danger":"safe","readonly":true,"priv":"SELECT em performance_schema","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 mostra as requisições de lock atuais; as com request_status = WAIT são requisições bloqueadas.","danger":"safe","readonly":true,"priv":"VIEW SERVER STATE"},"mongodb":{"command":"db.currentOp({ \"$or\": [ { \"waitingForLock\": true }, { \"locks\": { \"$exists\": true } } ] })","note":"db.currentOp mostra as operações aguardando um lock (waitingForLock) e as que mantêm locks; o MongoDB faz lock em nível de documento/coleção, não de linha.","danger":"safe","priv":"inprog / role 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":"Como o Redis é single-threaded, não há uma lista tradicional de locks.","danger":"safe"},"elasticsearch":{"command":"GET _cluster/pending_tasks","note":"O Elasticsearch não tem locks de linha; isto lista as tarefas de alteração do cluster enfileiradas no master (pending tasks).","danger":"safe","readonly":true}}},{"id":"long-operations","title":"Ver o progresso de operações de longa duração","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 mostra o progresso percentual e o tempo restante (time_remaining) de operações que rodam há mais de 6 segundos.","danger":"safe","readonly":true,"priv":"SELECT em v$session_longops"},"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":"As views pg_stat_progress_* informam o progresso das operações VACUUM, CREATE INDEX, CLUSTER, ANALYZE e 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":"Quando a instrumentação de stages está habilitada, events_stages_current mostra o progresso via work_completed/work_estimated (ex.: ALTER TABLE).","danger":"safe","readonly":true,"priv":"SELECT em performance_schema"},"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 fornece o percentual de operações como BACKUP, RESTORE, DBCC e rebuild de índices.","danger":"safe","readonly":true,"priv":"VIEW SERVER STATE"},"mongodb":{"command":"db.currentOp({ \"active\": true, \"secs_running\": { \"$gte\": 3 } })","note":"Na saída de db.currentOp, as operações de longa duração e, para criação de índices, o campo 'progress' (done/total) mostram o progresso.","danger":"safe","priv":"inprog / role clusterMonitor"},"redis":{"command":"INFO persistence\n# Keys: rdb_bgsave_in_progress, aof_rewrite_in_progress, rdb_last_bgsave_status, loading, loading_loaded_perc","note":"A seção INFO persistence informa se operações de save ou rewrite de RDB/AOF estão em andamento e o percentual de carregamento.","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 mostra o status de tarefas de longa duração (reindex, update_by_query); _cat/recovery mostra o progresso da recuperação de shards ativa.","danger":"safe","readonly":true}}},{"id":"session-trace","title":"Rastrear uma sessão / consulta (habilitar trace / profiling)","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 gera um arquivo de trace 10046 para a sessão; sempre desabilite ao terminar (o trace adiciona overhead e uso de disco).","danger":"caution","priv":"EXECUTE em DBMS_MONITOR"},"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 grava os planos das consultas, e log_min_duration_statement grava as consultas lentas/todas, no arquivo de log; o valor 0 registra todas as consultas, então atenção ao volume de log.","danger":"caution","priv":"SUPERUSER (para LOAD) ou SET em nível de sessão"},"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":"O rastreamento de consultas é feito com os events_statements do performance_schema; o método SET profiling é antigo (obsoleto), mas fornece uma medição rápida por sessão.","danger":"caution","priv":"SELECT/UPDATE em performance_schema"},"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) é o método moderno de rastreamento; crie a sessão, inicie-a com START e pare-a com STOP/DROP ao terminar.","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) registra todas as operações na coleção system.profile; em produção, prefere-se 1 (apenas lentas), pois o nível 2 adiciona overhead.","danger":"caution","priv":"dbAdmin / enableProfiler"},"redis":{"command":"MONITOR\n# Streams all commands arriving at the server in real time. Exit: Ctrl-C","note":"MONITOR mostra todos os comandos ao vivo, mas causa uma queda séria de desempenho; use-o por pouco tempo e com cuidado em produção. Alternativa: 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 fornece o detalhamento de tempo de consulta/agregação de uma única busca; para monitoramento contínuo, configure limites de slowlog.","danger":"safe","readonly":true}}},{"id":"top-wait-events","title":"Ver os principais wait events","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 fornece os wait events acumulados; v$active_session_history fornece a amostragem de sessões ativas dos últimos minutos (requer a licença Diagnostics Pack).","danger":"safe","readonly":true,"priv":"SELECT em v$system_event"},"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 mostra o estado de espera atual; amostrá-lo repetidamente (polling) revela os wait events mais frequentes.","danger":"safe","readonly":true,"priv":"role 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 fornece os tempos totais de espera por evento (em picossegundos); os instrumentos de wait devem estar habilitados.","danger":"safe","readonly":true,"priv":"SELECT em performance_schema"},"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 mostra os wait types acumulados desde o início da instância; pode ser zerado com 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":"O WiredTiger não tem wait events clássicos; o esgotamento de concurrentTransactions (tickets), globalLock.currentQueue e a pressão no cache indicam congestionamento.","danger":"safe","priv":"role clusterMonitor"},"redis":{"command":"CONFIG SET latency-monitor-threshold 100\nLATENCY LATEST\nLATENCY HISTORY command\n# For the slowest commands: SLOWLOG GET 10","note":"Depois que o limite do latency monitor é definido, LATENCY LATEST/HISTORY informa os eventos que causam mais latência.","danger":"safe"},"elasticsearch":{"command":"GET _nodes/hot_threads","note":"_nodes/hot_threads revela gargalos fornecendo stack traces das threads que mais consomem CPU.","danger":"safe","readonly":true}}},{"id":"os-resource","title":"Ver o uso de recursos do servidor de dentro do banco (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 fornece contadores de CPU/memória do SO; v$sysmetric fornece métricas do DB em tempo real (CPU, IOPS) do intervalo mais recente.","danger":"safe","readonly":true,"priv":"SELECT em v$osstat, v$sysmetric"},"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 fornece contadores de leitura/escrita/acerto de cache; o PostgreSQL não expõe o uso de CPU, então são necessárias ferramentas do sistema operacional.","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":"As views de resumo do schema sys (host_summary) fornecem um detalhamento de IO/latência; SHOW ENGINE INNODB STATUS mostra a atividade do buffer pool e de IO.","danger":"safe","readonly":true,"priv":"SELECT em sys, 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 fornece contadores de desempenho do DB; dm_os_ring_buffers fornece a proporção de CPU entre SQL e outros processos nos últimos ~256 minutos.","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() fornece métricas de memória, rede, opcounters e cache do WiredTiger; para CPU/IO detalhados do SO, use mongostat ou ferramentas do sistema operacional.","danger":"safe","priv":"role 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 informa o consumo de CPU do processo Redis, e INFO stats informa as operações por segundo e o tráfego de rede.","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 fornece percentual de CPU, memória e métricas de processo por nó; use a seção fs para disco.","danger":"safe","readonly":true}}}]},"rosetta/automation.json":{"category":"Automação e auditoria","categoryId":"automation","order":13,"concepts":[{"id":"schedule-job","title":"Criar um job agendado","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 define um job agendado; repeat_interval define a recorrência com uma expressão de calendário.","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":"A extensão pg_cron define jobs na sintaxe cron padrão com cron.schedule; se a extensão não estiver instalada, use o pgAgent ou o cron do sistema operacional.","danger":"caution","priv":"pg_cron instalado; geralmente superuser/proprietário da extensão"},"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 é executado pelo event scheduler; a variável global event_scheduler deve estar ON, caso contrário os eventos não disparam.","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":"Os jobs do SQL Server Agent são criados com procedures do msdb: o job, o step e o schedule são definidos e vinculados ao servidor. O serviço SQL Server Agent deve estar em execução.","danger":"caution","priv":"SQLAgentUserRole ou 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":"A edição Community não tem jobs agendados; é necessário um agendador externo ou um 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":"O Redis não executa jobs agendados; isso é feito com TTL/keyspace notifications e cron externo.","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":"O SLM (Snapshot Lifecycle Management) faz snapshots agendados; o ILM é usado para o ciclo de vida dos dados e o Watcher para automação avançada.","danger":"caution","priv":"privilégio de cluster manage_slm"}}},{"id":"list-jobs","title":"Listar jobs agendados / ver seu status","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 mostra os jobs definidos e seus estados; dba_scheduler_job_run_details mostra os resultados de sucesso/falha das execuções anteriores.","danger":"safe","readonly":true,"priv":"SELECT em dba_scheduler_jobs"},"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":"Com o pg_cron, cron.job lista os jobs definidos e cron.job_run_details fornece o status e a mensagem de retorno de cada execução.","danger":"safe","readonly":true,"priv":"pg_cron instalado; acesso ao schema 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 lista os eventos definidos, seu status (ENABLED/DISABLED) e o horário da última execução.","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 fornece os jobs do Agent definidos, e sysjobhistory fornece o histórico de execuções e o resultado (run_status).","danger":"safe","readonly":true,"priv":"SQLAgentReaderRole / acesso ao 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":"O MongoDB Community não tem tabela de jobs; os Atlas Triggers são gerenciados na interface do Atlas.","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no concept of scheduled jobs, so there are no jobs to list.","note":"O Redis não inclui agendador de jobs; não há jobs para listar.","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 lista as políticas de snapshot, _ilm/policy lista as políticas de ciclo de vida e _watcher/stats mostra o estado de execução do Watcher.","danger":"safe","readonly":true,"priv":"privilégio read_slm / read_ilm"}}},{"id":"enable-audit","title":"Habilitar auditoria / logging","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":"Com o Unified Auditing, uma política é criada e habilitada com AUDIT; os registros ficam na view unified_audit_trail.","danger":"caution","priv":"AUDIT SYSTEM / role 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":"O pgaudit fornece log de auditoria detalhado; configure-o com ALTER SYSTEM para valer em todo o servidor (um SET em nível de sessão audita apenas aquela sessão). Sem a extensão, o logging básico é habilitado com log_statement ('ddl','mod','all'). Atenção ao volume de log.","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":"O plugin audit_log (Enterprise, ou server_audit no MariaDB) mantém uma trilha de auditoria detalhada; o general_log registra todas as consultas, mas degrada o desempenho.","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":"Primeiro crie e habilite um destino SERVER AUDIT (arquivo/event log) e depois defina quais eventos rastrear com uma AUDIT SPECIFICATION de servidor ou de banco de dados.","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":"A auditoria está disponível apenas no Enterprise e no Atlas; é habilitada com a seção auditLog da configuração do mongod. Não existe na edição 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":"O ACL LOG registra automaticamente eventos de segurança (falhas de autenticação, comandos/chaves não autorizados); a auditoria completa de comandos não é nativa.","danger":"safe","priv":"permissão de ACL (admin por padrão)"},"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":"O log de auditoria é habilitado com xpack.security.audit.enabled; é definido no elasticsearch.yml e exige restart do nó (não é dinâmico). Requer licença comercial.","danger":"caution"}}},{"id":"current-config-diff","title":"Listar configurações fora do padrão","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":"As linhas de v$parameter com isdefault = 'FALSE' mostram os parâmetros que diferem do padrão (definidos explicitamente).","danger":"safe","readonly":true,"priv":"SELECT em v$parameter"},"postgres":{"command":"SELECT name, setting, unit, source\nFROM pg_settings\nWHERE source NOT IN ('default', 'override')\nORDER BY name;","note":"Se pg_settings.source for qualquer coisa diferente de 'default' e 'override', a configuração foi alterada por um arquivo de configuração, pela linha de comando ou pela sessão.","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 retorna todas as configurações; não mostra diretamente a diferença em relação ao padrão. A coluna VARIABLE_SOURCE de performance_schema.variables_info mostra as alterações diferentes do padrão compilado (arquivo, linha de comando, dinâmica).","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 retorna as configurações do servidor; se value e value_in_use forem diferentes, há uma alteração não aplicada com RECONFIGURE (ou aguardando restart). sys.configurations não armazena o valor padrão (minimum/maximum é apenas o intervalo permitido); para ver as diferenças em relação ao padrão, compare os valores com os padrões documentados.","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":"A seção 'parsed' do comando getCmdLineOpts lista apenas as configurações especificadas explicitamente (fora do padrão).","danger":"safe","priv":"privilégio 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 * retorna todas as configurações em execução; não há diff nativo em relação ao padrão, então compare a saída com os valores padrão do redis.conf da versão correspondente.","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 retorna as configurações de cluster fora do padrão (persistent/transient); com include_defaults=true, os padrões também são mostrados para comparação.","danger":"safe","readonly":true}}}]},"rosetta/lifecycle.json":{"category":"Instalação e upgrade","categoryId":"lifecycle","order":14,"concepts":[{"id":"check-version","title":"Mostrar a versão instalada e o nível de patch","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":"O banner de v$version fornece a versão. dba_registry_sqlpatch mostra se os Release Updates (RU) e patches one-off aplicados foram registrados na camada SQL, enquanto 'opatch lspatches' mostra os patches binários no home.","danger":"safe","readonly":true,"priv":"SELECT em v$version, dba_registry_sqlpatch"},"postgres":{"command":"SELECT version();\n-- Numeric version only:\nSHOW server_version;\nSELECT current_setting('server_version_num');","note":"version() retorna o texto completo, incluindo as informações de build. O PostgreSQL não tem um número de patch separado; a versão minor (ex.: 16.3) representa o nível de correções.","danger":"safe","readonly":true},"mysql":{"command":"SELECT VERSION();\n-- Detailed build information:\nSHOW VARIABLES LIKE 'version%';","note":"VERSION() retorna, por exemplo, '8.0.36'; o último componente é o nível de patch (release). A variável version_comment indica se o build é Community/Enterprise ou 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 fornece o Cumulative Update aplicado (ex.: CU12), e ProductUpdateReference fornece o número do KB relacionado. ProductLevel mostra 'RTM' ou, em versões mais antigas, 'SP'.","danger":"safe","readonly":true},"mongodb":{"command":"db.version()\n// Detailed build information:\ndb.serverBuildInfo()\n// or: db.adminCommand({ buildInfo: 1 })","note":"db.version() retorna a string de versão (ex.: '7.0.11'). No MongoDB, as correções são lançadas como uma nova versão de patch; não existe um conceito separado de 'nível de patch'.","danger":"safe"},"redis":{"command":"INFO server\n# redis-cli one-liner: redis-cli INFO server | grep redis_version","note":"O campo redis_version na saída de INFO server fornece a versão instalada. No Redis, as correções saem como uma nova versão de patch (ex.: 7.2.5); o campo redis_git_sha1 também mostra o identificador do build.","danger":"safe"},"elasticsearch":{"command":"GET /\n# curl: curl -s http://localhost:9200/","note":"O endpoint raiz retorna version.number (ex.: '8.14.1'), lucene_version e build_flavor. Para ver as versões de todos os nós: GET _cat/nodes?v&h=name,version","danger":"safe","readonly":true}}},{"id":"check-upgrade-readiness","title":"Verificação de compatibilidade/prontidão antes do upgrade","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":"O modo 'analyze' do AutoUpgrade gera um relatório pré-upgrade sem alterar dados; lista os avisos que precisam ser corrigidos e os itens que serão resolvidos automaticamente. Sempre execute-o antes do upgrade real.","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 verifica se o upgrade é viável sem alterar nenhum dado (informa extensões ausentes, tipos de dados incompatíveis etc.). --check também pode ser executado com o cluster antigo em funcionamento; o upgrade real é feito com os dois clusters parados.","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":"O util.checkForServerUpgrade() do MySQL Shell informa recursos removidos, conflitos com palavras reservadas e definições incompatíveis. A partir do 8.0, o próprio servidor faz o upgrade do dicionário na inicialização; um mysql_upgrade separado não é mais necessário.","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":"O Data Migration Assistant (DMA) substituiu o antigo Upgrade Advisor; informa recursos obsoletos, breaking changes e impedimentos por banco de dados. Execute-o antes do upgrade e resolva os achados.","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":"Antes de atualizar a versão do binário, o FCV deve ser igual à versão atual; caso contrário, o upgrade é bloqueado. O MongoDB não tem um 'scanner de obsolescência' automático; as notas de compatibilidade da release são revisadas manualmente.","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":"Os upgrades do Redis geralmente são compatíveis para frente; como não há um scanner oficial de prontidão, verifique manualmente nas release notes o formato dos arquivos RDB/AOF, as diretivas de configuração removidas e as mudanças de comandos.","danger":"safe"},"elasticsearch":{"command":"GET _migration/deprecations\n# For a specific component: GET <index>/_migration/deprecations","note":"A Deprecation Info API lista como 'critical' / 'warning' as configurações de cluster, nó, índice e ML que causarão problemas na passagem para a próxima versão major. O Kibana Upgrade Assistant exibe os mesmos dados visualmente.","danger":"safe","readonly":true}}},{"id":"apply-patch","title":"Aplicar um patch","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 atualiza os binários no Oracle Home; em seguida, o datapatch aplica as alterações de dicionário/SQL no banco aberto e as registra em dba_registry_sqlpatch. No RAC, patches rolling-installable podem ser aplicados nó por nó.","danger":"caution","priv":"SO: proprietário do 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":"Patches minor dentro da mesma série major (16.3 -> 16.4) não alteram o formato dos dados: basta atualizar o pacote e reiniciar o serviço; não é necessário pg_upgrade nem dump/restore.","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":"O MySQL 8.0+ faz o upgrade do data dictionary automaticamente na inicialização; não é necessária uma etapa separada de mysql_upgrade. Na replicação, aplique o patch primeiro nas réplicas e depois na origem.","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":"As atualizações CU (Cumulative Update) e GDR (General Distribution Release) são aplicadas com o instalador setup e exigem restart da instância. Em um grupo Always On, aplique o patch primeiro nas réplicas secundárias e faça failover para minimizar o downtime.","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":"Atualizações de patch dentro da mesma versão major (7.0.x) são feitas de forma rolling, primeiro nos secondaries. O primary recebe o patch depois de transferir o papel com rs.stepDown(), minimizando o downtime de escrita.","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":"Versões de patch (7.2.x) são aplicadas com rolling restart: primeiro as réplicas são atualizadas e ressincronizadas, depois uma réplica é promovida a master e o antigo master recebe o patch. O Sentinel/Cluster automatiza o failover.","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":"Upgrades de patch/minor são feitos com rolling upgrade: a alocação de shards é restringida, os nós são atualizados e reiniciados um de cada vez, depois a alocação é reabilitada e aguarda-se o cluster voltar a green.","danger":"caution"}}},{"id":"upgrade-major","title":"Upgrade de versão major","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":"O AutoUpgrade executa a análise, os pre-fixups, o upgrade e as etapas posteriores com um único comando; pode processar vários bancos em sequência para reduzir o downtime. O DBUA faz o mesmo com uma interface guiada. Um backup completo prévio é obrigatório.","danger":"danger","priv":"SYSDBA + SO: proprietário do novo 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 faz a migração de versão major (16 -> 17) in-place; o modo --link reduz o tempo criando hard links em vez de copiar arquivos, mas invalida o cluster antigo. As estatísticas devem ser coletadas novamente após a migração.","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":"A partir do MySQL 8.x, upgrades major in-place são suportados: um servidor iniciado com os novos binários converte automaticamente o data dictionary e as tabelas de sistema (a antiga etapa separada de mysql_upgrade foi removida). Faça o upgrade de uma versão major por vez.","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 atualiza a instância in-place para a nova versão major. O método mais seguro é uma instalação side-by-side, movendo depois os bancos com backup/restore e elevando o compatibility level em uma etapa separada.","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":"Um upgrade major no MongoDB tem duas fases: primeiro os binários de todos os nós são atualizados de forma rolling para a nova versão; depois, com o cluster estável, o FCV é elevado para a nova versão. Só é possível subir uma versão major por vez; o FCV é gerenciado separadamente para permitir downgrade.","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":"A migração de versão major do Redis (6.x -> 7.x) é feita configurando uma réplica na nova versão, deixando-a sincronizar e depois promovendo-a a master; assim, o downtime de escrita fica próximo de zero. Os arquivos RDB são compatíveis com versões posteriores.","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":"O Elasticsearch não permite pular versões major por nenhum método: tanto o rolling upgrade quanto o full-cluster restart só avançam para a próxima major (n -> n+1) e exigem que a origem esteja na última minor (ex.: 7.17). Índices criados duas majors antes (ex.: no 6.x) não podem ser abertos na nova versão; devem ser reconstruídos com _reindex antes da migração (o 8.x só consegue lê-los de forma limitada, como archive indices somente leitura). Faça um snapshot e resolva os avisos de obsolescência antes da migração.","danger":"danger"}}},{"id":"set-compatibility","title":"Definir compatibility level / versão de recursos","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":"O parâmetro COMPATIBLE determina quais recursos e formatos de arquivo de versão estão habilitados. Depois de elevado e com a instância reiniciada, NÃO PODE SER REVERTIDO (o downgrade fica bloqueado); por isso, eleve-o gradualmente até confirmar o sucesso do upgrade.","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":"O PostgreSQL não tem um conceito de 'compatibility level' como o SQL Server/Oracle; o comportamento da versão está ligado diretamente à versão do binário. A migração entre versões é feita com pg_dump/pg_restore ou 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":"O MySQL não tem compatibility level baseado em versão; o comportamento SQL depende principalmente da versão do binário e da configuração de sql_mode. Ajuste o sql_mode para preservar o comportamento de aplicações legadas.","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 determina a qual versão correspondem o comportamento do otimizador de consultas e os recursos da linguagem (150=2019, 160=2022). Após o upgrade da instância, os bancos podem permanecer no nível antigo; recomenda-se elevá-lo gradualmente e monitorar regressões de plano. Pode ser reduzido novamente.","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":"O FCV controla quando as alterações de formato de dados persistentes e os novos recursos de uma versão são habilitados. Eleve-o após o upgrade do binário, com o cluster estável; reduzi-lo só é possível se a mesma versão de binário ainda suportar o FCV inferior.","danger":"caution","priv":"role clusterManager / root"},"redis":{"command":"# Not applicable: Redis has no compatibility level / feature version concept.\n# Behavior depends directly on the running binary version.","note":"O Redis não tem compatibility level configurável; o conjunto de recursos depende inteiramente da versão em execução. A compatibilidade é preservada apenas no nível do formato de arquivo RDB/AOF, em direção para frente.","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":"O Elasticsearch não tem configuração de compatibility level; cada índice carrega o formato da versão major em que foi criado. Índices criados na versão major anterior podem ser lidos; os mais antigos devem ser movidos para a nova versão com _reindex.","danger":"safe"}}},{"id":"post-upgrade-tasks","title":"Tarefas pós-upgrade (recompile/analyze)","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 recompila packages/views/triggers que ficaram INVALID após o upgrade. Coletar em seguida as estatísticas do dicionário e dos fixed objects permite que o otimizador produza planos adequados na nova versão.","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":"O pg_upgrade (PG17 e anteriores) não transfere as estatísticas do planner; analyze-in-stages torna o sistema utilizável rapidamente, coletando primeiro estatísticas grosseiras e depois as completas. As extensões devem ser atualizadas com ALTER EXTENSION ... UPDATE, e os índices com REINDEX se a collation mudou.","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":"No MySQL 8.0.16 e posteriores, a função do mysql_upgrade passou para o servidor, então ele não é executado separadamente. Após o upgrade, atualizar as estatísticas com ANALYZE TABLE nas tabelas grandes/críticas preserva a qualidade dos planos.","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":"Após o upgrade, DBCC UPDATEUSAGE corrige contadores imprecisos de espaço/linhas herdados de versões antigas, e sp_updatestats atualiza as estatísticas. Ao elevar o compatibility level, monitore as regressões de plano que o novo Cardinality Estimator (CE) pode causar.","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":"Após um upgrade major, verifique se o FCV chegou à versão alvo. Reconstruir índices não é uma etapa rotineira do upgrade; se um índice for citado nas release notes ou gerar aviso no log, recrie-o com dropIndex + createIndex. No 6.0+, reIndex só funciona em standalone e não é permitido em membros de replica set.","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":"Após um upgrade do Redis, não há tarefa de compile/analyze de schema; o trabalho é verificar se a replicação foi restabelecida, se a persistência RDB/AOF está saudável e se a contagem de chaves foi preservada.","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":"Após o upgrade, verifique se o status do cluster está 'green' e se todos os shards estão alocados. Índices em formato anterior à versão major anterior não podem ser lidos na nova versão, então devem ser movidos para o formato atual com _reindex.","danger":"caution"}}}]},"rosetta/migration.json":{"category":"Migração e transferência","categoryId":"migration","order":15,"concepts":[{"id":"compare-schema","title":"Comparar dois schemas/ambientes (schema diff)","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":"O Oracle não tem um schema diff nativo de comando único. O método comum é gerar DDL determinístico dos dois ambientes com DBMS_METADATA.GET_DDL (com os atributos de STORAGE/segmento desligados) e fazer um diff de texto. Para comparação visual/automatizada, use o assistente Database Diff do SQL Developer ou o SQLcl.","danger":"safe","readonly":true,"priv":"SELECT_CATALOG_ROLE ou acesso de leitura ao schema"},"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":"A forma mais simples é gerar a saída de pg_dump --schema-only nos dois ambientes e compará-la com diff. apgdiff e migra são ferramentas que convertem a diferença diretamente em instruções ALTER executáveis. Adicione --no-owner --no-privileges para uma saída determinística.","danger":"safe","readonly":true,"priv":"SELECT / leitura do schema (acesso aos objetos para o 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":"A ferramenta mysqldbcompare do MySQL Utilities informa as diferenças de objetos/schema entre dois servidores (como instruções aplicáveis com difftype=sql). O método sem ferramenta é gerar a saída de mysqldump --no-data (apenas schema) ou SHOW CREATE TABLE nos dois ambientes e comparar com diff. O mysqldbcompare agora está obsoleto; para MariaDB/8.x, prefere-se Liquibase ou Skeema.","danger":"safe","readonly":true,"priv":"SELECT, SHOW VIEW nos dois schemas"},"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":"Para diferenças de schema, SqlPackage /Action:DeployReport retorna como relatório XML as alterações a serem aplicadas no destino; /Action:Script gera um script de diff executável. O 'Schema Compare' do Visual Studio / Azure Data Studio usa o mesmo engine. Para diferenças de dados em nível de linha, existe o utilitário de linha de comando tablediff.","danger":"safe","readonly":true,"priv":"VIEW DEFINITION (acesso de leitura ao destino para o 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":"O MongoDB é schemaless; não há DDL fixo. A comparação é feita de duas formas: compare as regras do validador $jsonSchema definidas na coleção (via getCollectionInfos) ou gere um schema inferido a partir dos dados com mongodb-schema / Compass e compare as distribuições de campos e tipos. Para índices, faça diff da saída de 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":"Não se aplica: o Redis não tem o conceito de schema (tabela/coluna/DDL), então um schema diff clássico não se aplica. Se for necessária uma comparação estrutural, apenas o padrão de nomes das chaves (namespace) pode ser listado com SCAN e comparado.","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":"No Elasticsearch, o equivalente a um schema é o mapping do índice. O método padrão é obter a saída de GET <index>/_mapping (e _settings, se necessário) dos dois clusters e comparar com diff. Como os campos do mapping são em grande parte imutáveis, uma diferença detectada pode exigir um novo índice + _reindex.","danger":"safe","readonly":true,"priv":"view_index_metadata / monitor"}}},{"id":"export-for-migration","title":"Exportação consistente para migração","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":"O Data Pump (expdp) é a ferramenta padrão de exportação lógica para migração. Para consistência de leitura, passe FLASHBACK_SCN=<scn> (ou FLASHBACK_TIME) para que todas as tabelas sejam exportadas de forma consistente em um único SCN; isso é crítico em um sistema em produção. PARALLEL acelera o processo, e %U gera vários arquivos.","danger":"caution","readonly":true,"priv":"DATAPUMP_EXP_FULL_DATABASE, objeto 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":"Para migração, prefere-se o formato pg_dump -Fc (custom) ou -Fd (directory); ambos permitem carga seletiva/paralela com pg_restore. Como o pg_dump roda dentro de uma única transação, sua saída é automaticamente um snapshot consistente. Objetos de todo o cluster, como roles e tablespaces, são exportados separadamente com pg_dumpall --globals-only.","danger":"safe","readonly":true,"priv":"SELECT (em todos os objetos a serem exportados)"},"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":"No InnoDB, --single-transaction fornece um único snapshot consistente e não bloqueia tabelas. --source-data=2 (antes --master-data=2) grava como comentário no início da saída a posição do binlog/GTID necessária para iniciar a replicação/CDC; isso é essencial para um cutover sem downtime. Para grandes volumes, o mydumper roda em paralelo.","danger":"safe","readonly":true,"priv":"SELECT, LOCK TABLES, RELOAD, REPLICATION CLIENT (para --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":"Ao migrar para o mesmo SQL Server ou um mais novo, BACKUP ... RESTORE é o caminho mais confiável (a integridade é verificada com CHECKSUM). Para migração independente de versão/plataforma ou para o Azure SQL, prefere-se exportar schema+dados em um único arquivo .bacpac com SqlPackage /Action:Export. O bcp é usado para tabelas individuais.","danger":"safe","readonly":true,"priv":"BACKUP DATABASE (db_backupoperator) ou acesso de leitura para o 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":"O mongodump é a exportação binária (BSON) padrão para migração. Em um replica set, a opção --oplog captura do oplog as alterações gravadas enquanto o dump está em execução, fornecendo um ponto no tempo consistente (em conjunto com mongorestore --oplogReplay); essa opção só vale para um dump completo. Para migração em nível de cluster de um cluster grande, mongosync/ferramentas live são mais adequados.","danger":"safe","readonly":true,"priv":"read (read no db local para o oplog / 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":"No Redis, a exportação consistente é o snapshot RDB. BGSAVE gera um dump.rdb consistente em segundo plano via fork, sem bloquear o processo principal (SAVE bloqueia e não deve ser usado). O caminho do arquivo é obtido com CONFIG GET dir e dbfilename; migre copiando esse dump.rdb para o diretório de dados do servidor de destino.","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":"No Elasticsearch, o método de exportação consistente para migração é o snapshot. Primeiro registra-se um repository (fs, S3, GCS etc.) e depois tira-se o snapshot; os snapshots são incrementais e capturam um estado consistente do momento em que são tirados. O elasticdump também pode ser usado para dados pequenos/um único índice, mas o snapshot é o padrão.","danger":"safe","readonly":true,"priv":"manage / create_snapshot"}}},{"id":"import-for-migration","title":"Importar no destino","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":"O impdp carrega no destino o arquivo .dmp gerado com expdp. REMAP_SCHEMA move a origem para outro schema e REMAP_TABLESPACE para outra tablespace; são muito usados na migração entre ambientes. O comportamento para tabelas existentes é definido com TABLE_EXISTS_ACTION, e a velocidade com PARALLEL.","danger":"caution","priv":"DATAPUMP_IMP_FULL_DATABASE, cota no tablespace de destino"},"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":"Com pg_restore -j, dumps em formato custom/directory são carregados em paralelo (vários processos); isso acelera significativamente a carga em bancos grandes. --clean --if-exists remove primeiro os objetos no destino, e --no-owner se adapta a uma estrutura de roles diferente. Dumps SQL simples são carregados com psql -f (sem paralelismo).","danger":"caution","priv":"privilégios de CREATE / proprietário no banco de destino"},"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":"Um dump SQL do mysqldump é carregado redirecionando-o para o cliente mysql (mysql shop < dump.sql). Para uma carga paralela e muito mais rápida, um diretório gerado com mydumper é restaurado com myloader --threads. Desabilitar FOREIGN_KEY_CHECKS e UNIQUE_CHECKS durante a carga melhora o desempenho.","danger":"caution","priv":"INSERT, CREATE (e DROP, para --overwrite/--clean)"},"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":"Um backup .bak é carregado com RESTORE DATABASE; ao mudar para um layout de disco diferente, WITH MOVE redireciona os arquivos de dados/log para novos caminhos. Para um destino independente de versão/Azure SQL, SqlPackage /Action:Import cria o arquivo .bacpac (schema + dados) como um novo banco.","danger":"caution","priv":"dbcreator/sysadmin para RESTORE; CREATE DATABASE para Import"},"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":"O mongorestore carrega no destino a saída BSON do mongodump. --oplogReplay reaplica as alterações do oplog de um backup feito com --oplog, levando o dump a um único ponto no tempo consistente. Os nomes de banco/coleção são alterados com --nsFrom/--nsTo, e os dados existentes podem ser apagados com --drop.","danger":"caution","priv":"readWrite (restore/clusterAdmin para oplogReplay)"},"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":"O Redis só carrega o RDB na inicialização. Por isso, o servidor de destino é parado, o dump.rdb migrado é colocado no diretório de dados (CONFIG GET dir) e o servidor é reiniciado; na inicialização, a memória é populada a partir do RDB. Para carregar sem parar o servidor, transmita as chaves em formato RESP com redis-cli --pipe.","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":"No cluster de destino, registre o mesmo snapshot repository da origem (os arquivos devem estar acessíveis) e depois restaure os índices com _snapshot/.../_restore. Os nomes dos índices podem ser alterados com rename_pattern/rename_replacement. Índices existentes não podem ser restaurados enquanto estiverem abertos; feche-os ou renomeie-os antes.","danger":"caution","priv":"manage (create_index, restore)"}}},{"id":"heterogeneous-migration","title":"Migrar para outro banco de dados (heterogêneo)","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":"Para migração heterogênea a partir do Oracle (especialmente para PostgreSQL), a ferramenta open source mais comum é o Ora2Pg: converte tabelas, constraints, PL/SQL e dados para o dialeto de destino; --estimate_cost estima o esforço de migração. Para migração online/com baixo downtime, usa-se AWS DMS ou Oracle GoldenGate (com CDC).","danger":"caution","readonly":true,"priv":"SELECT no schema de origem (acesso de leitura às views 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":"O pgloader é a ferramenta padrão para migrar para o PostgreSQL a partir de outros engines (MySQL, SQLite, MS SQL): com connection strings, cria o schema em um único comando, mapeia os tipos e copia os dados rapidamente; transformações/mapeamentos de tipos personalizados são definidos em um script .load. Se a origem for Oracle, prefere-se o Ora2Pg; para migração online, o AWS DMS.","danger":"caution","priv":"CREATE no destino; SELECT na origem"},"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":"Não há uma única ferramenta aberta dominante para migrar para o MySQL a partir de outros engines; a solução mais comum é o AWS DMS (gerenciado, com suporte a CDC) ou adaptar o dump da origem quanto a sintaxe/tipos e carregá-lo com o cliente mysql. MySQL e MariaDB são amplamente compatíveis; a saída do mysqldump geralmente migra diretamente.","danger":"caution","priv":"CREATE, INSERT no destino"},"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":"O pgloader (origem mssql://) é usado para migrar do SQL Server para o PostgreSQL; se você quiser manter o T-SQL sem alterar a aplicação, o Babelfish for Aurora PostgreSQL oferece uma camada de compatibilidade. A ferramenta SSMA da Microsoft automatiza a migração de outros engines (Oracle, MySQL, DB2) para o SQL Server. Para migração online, o AWS DMS.","danger":"caution","priv":"SELECT na origem; CREATE no destino"},"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":"A migração entre o MongoDB e engines SQL exige uma transformação do modelo linha<->documento (ETL); não há um comando único automático. De SQL para MongoDB, o MongoDB Relational Migrator mapeia tabelas para um schema de documentos; em casos simples, gere CSV/JSON a partir da origem e carregue com mongoimport. No sentido inverso, a saída do mongoexport é carregada na tabela relacional de destino com COPY/LOAD DATA.","danger":"caution","priv":"read na origem, write no destino"},"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":"Na migração heterogênea, o Redis geralmente é a camada de cache como destino/origem; para carregar dados no Redis a partir de fontes relacionais ou de arquivos, usa-se a ferramenta oficial RIOT do Redis (db-import mapeia um resultado SQL para estruturas HSET/SET). Para Redis para Redis ou para arquivo, existem os comandos 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":"A ferramenta mais comum para migrar de outros bancos para o Elasticsearch é o Logstash (input JDBC/file -> output elasticsearch); os connectors/Beats da própria Elastic também são usados. Ao passar de um cluster Elasticsearch antigo para um novo, o remote reindex (_reindex com origem 'remote') é comum; reindex.remote.whitelist deve estar definido no destino.","danger":"caution","priv":"write/create_index no destino"}}},{"id":"setup-cdc-replication","title":"Configurar replicação contínua / CDC (cutover sem downtime)","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":"No Oracle, a ferramenta padrão para CDC sem downtime/heterogêneo é o Oracle GoldenGate: o processo Extract captura as alterações dos redo logs e o Replicat as aplica no destino; o supplemental logging deve estar habilitado. Migração típica: a carga inicial é feita com Data Pump e, a partir daí, o GoldenGate transmite as alterações para o destino, permitindo um cutover com downtime próximo de zero.","danger":"caution","priv":"privilégios de administrador do GoldenGate, supplemental logging"},"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":"O PostgreSQL fornece CDC com a logical replication nativa: CREATE PUBLICATION na origem, CREATE SUBSCRIPTION no destino. Quando a subscription inicia, copia os dados existentes (initial copy) e depois transmite continuamente as alterações a partir do WAL; wal_level=logical é obrigatório. Para cenários grandes/complexos, prefere-se pglogical ou Debezium.","danger":"caution","priv":"role REPLICATION na origem; superuser no destino para CREATE SUBSCRIPTION (no PG16+, a role pg_create_subscription também é suficiente)","minver":"10 (logical replication)"},"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":"No MySQL, um cutover sem downtime é feito com replicação baseada em binlog. A carga inicial é feita com mysqldump --source-data e a posição do binlog/GTID é registrada; no destino, a replicação é iniciada a partir dessa posição com CHANGE REPLICATION SOURCE TO (sintaxe do 8.0.23+; antes CHANGE MASTER TO). START REPLICA aplica as alterações continuamente. Uma configuração baseada em GTID é mais segura.","danger":"caution","priv":"REPLICATION SLAVE (usuário repl), 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":"O SQL Server tem dois caminhos principais para replicação contínua: se você quer um fluxo direto para o destino, configure a Transactional Replication (publisher/subscriber); se vai mover as alterações com seu próprio ETL, habilite o Change Data Capture (sp_cdc_enable_db + sp_cdc_enable_table) e leia das tabelas _CT. Para destinos heterogêneos, o CDC é combinado com AWS DMS/Debezium.","danger":"caution","priv":"sysadmin (para habilitar o CDC); o SQL Server Agent deve estar em execução"},"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":"No MongoDB, usam-se Change Streams para CDC: db.collection.watch() transmite ao vivo, a partir do oplog, os eventos de insert/update/delete a serem aplicados no destino (é necessário um replica set). Para migração/replicação contínua completa de cluster para cluster, a ferramenta oficial Cluster-to-Cluster Sync do MongoDB, o mongosync (não é exclusivo do Atlas; também funciona com clusters autogerenciados), gerencia a carga inicial + a sincronização contínua.","danger":"caution","priv":"changeStream (read); clusterAdmin para o mongosync"},"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":"No Redis, um cutover sem downtime é feito com a replicação nativa: execute REPLICAOF <source host port> (antes SLAVEOF) no servidor de destino; o destino primeiro recebe o RDB completo e depois permanece sincronizado continuamente pelo fluxo de comandos. Verifique master_link_status:up com INFO replication e, concluído o cutover, torne o destino standalone com 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":"O recurso real de replicação contínua no Elasticsearch é o Cross-Cluster Replication (CCR): o cluster de destino segue o leader index na origem e puxa as alterações continuamente (requer licença comercial/Platinum). Sem licença, obtém-se uma sincronização quase contínua com remote reindex periódico (incremental, baseado em um campo de tempo/sequência).","danger":"caution","priv":"manage/read_ccr para CCR; whitelist para remote reindex"}}},{"id":"verify-migration","title":"Verificação pós-migração (contagem de linhas/checksum)","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":"A verificação mais rápida é comparar COUNT(*) por tabela nos dois lados. Para encontrar diferenças reais de conteúdo em nível de linha, use o package DBMS_COMPARISON: ele compara as tabelas de origem e destino linha a linha por um database link e pode informar/convergir as diferenças. Para checksums, pode-se obter um digest de colunas com ORA_HASH ou STANDARD_HASH.","danger":"safe","readonly":true,"priv":"SELECT nos dois lados; EXECUTE em DBMS_COMPARISON"},"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":"O primeiro passo é comparar count(*) em cada tabela. Para verificação de conteúdo, calcule o md5 da representação textual de cada linha, concatene-os em ordem e aplique o hash novamente; isso fornece um checksum independente de ordem entre os dois lados. Para grandes volumes, calcule o digest apenas sobre as colunas mutáveis/chave; ordenar pela PK é importante para a repetibilidade.","danger":"safe","readonly":true,"priv":"SELECT na tabela"},"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":"No MySQL, CHECKSUM TABLE fornece um único checksum do conteúdo da tabela; execute-o na origem e no destino e compare (engine/versão devem ser os mesmos). Use COUNT(*) para a contagem de linhas. Em produção e para consistência da replicação, o padrão do mercado é o pt-table-checksum do Percona Toolkit; ele compara chunk a chunk, online e com baixo impacto.","danger":"safe","readonly":true,"priv":"SELECT na tabela"},"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":"No SQL Server, a ferramenta oficial de linha de comando que encontra diferenças em nível de linha é o tablediff (informa quais linhas foram adicionadas/alteradas e, com o -f opcional, grava um script de correção). Para uma verificação geral rápida, CHECKSUM_AGG(BINARY_CHECKSUM(*)) fornece um único digest da tabela; compare os dois lados junto com COUNT_BIG(*) (independente da ordem das linhas).","danger":"safe","readonly":true,"priv":"SELECT nas duas tabelas"},"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":"A primeira verificação é comparar a contagem de documentos nos dois lados com countDocuments() (estimatedDocumentCount é rápido, mas depende de metadados; use countDocuments para uma contagem exata). Para verificação de conteúdo, o comando dbHash gera um digest md5 em nível de coleção/banco; compare os hashes dos dois ambientes. Verifique os índices separadamente com getIndexes().","danger":"safe","readonly":true,"priv":"read (acesso ao 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":"No Redis, a verificação básica é comparar a contagem total de chaves com DBSIZE; a distribuição por banco é mostrada por INFO keyspace. O Redis não tem checksum de tabela nativo; se for necessária verificação exata de conteúdo, obtenha a serialização DUMP por chave e compare os dois lados (lembre-se das diferenças de TTL). A ferramenta riot compare também pode ser usada.","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":"No Elasticsearch, a verificação básica é comparar a contagem de documentos nos dois clusters com GET <index>/_count (o docs.count de _cat/indices também fornece um resumo rápido). Baseie a comparação em _count: o docs.count de _cat/indices conta no nível do Lucene (incluindo subdocumentos nested; ex.: um documento com dois itens nested conta como 3), então pode diferir de _count. Para verificação de conteúdo, compare por amostragem de documentos sobre o mesmo conjunto de _ids ou por um campo de hash.","danger":"safe","readonly":true,"priv":"read / monitor no índice"}}}]},"rosetta/tuning.json":{"category":"Tuning de desempenho","categoryId":"tuning","order":16,"concepts":[{"id":"plan-baseline","title":"Fixar / forçar um plano de consulta (plan baseline / hint)","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":"O SQL Plan Management fixa o plano; é a proteção mais forte contra regressões. Hints /*+ ... */ também podem ser usados.","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":"Alternativa: direcionar em nível de sessão com configurações como enable_seqscan; para fixação persistente, use o pg_hint_plan.","danger":"caution"},"mysql":{"command":"SELECT /*+ INDEX(customer customer_city_idx) */ * FROM customer WHERE city='Ankara';","note":"Os optimizer hints são embutidos na consulta. Para reescrita persistente, use o plugin 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":"O Query Store deve estar habilitado. Como alternativa, OPTION (USE PLAN N'...') ou um plan guide.","danger":"caution","priv":"ALTER no banco de dados"},"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 força um índice específico; limpe um plano obsoleto com planCacheClear.","danger":"safe"},"redis":{"command":"# Not applicable: there is no query planner.","note":"O desempenho depende da estrutura de dados e da complexidade dos comandos.","danger":"safe"},"elasticsearch":{"command":"# There is no plan pinning; optimize the query/index and routing.\nGET <index>/_search { \"profile\": true, \"query\": {...} }","note":"Use profile para ver qual consulta é cara; direcione com shards/routing.","danger":"safe"}}},{"id":"gather-stats-advanced","title":"Coletar estatísticas com opções avançadas (histogramas etc.)","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 controla os histogramas e degree controla o paralelismo. Use LOCK_TABLE_STATS para bloquear as estatísticas.","danger":"safe"},"postgres":{"command":"ALTER TABLE customer ALTER COLUMN city SET STATISTICS 500;\nANALYZE customer;","note":"Alvo de amostragem por coluna; default_statistics_target define o padrão global.","danger":"safe"},"mysql":{"command":"ANALYZE TABLE customer UPDATE HISTOGRAM ON city WITH 32 BUCKETS;","note":"Suporte a histogramas no MySQL 8.0; útil em colunas que são filtradas, mas não são seletivas.","danger":"safe"},"mssql":{"command":"UPDATE STATISTICS dbo.customer WITH FULLSCAN;\n-- Filtered statistics: CREATE STATISTICS ... WHERE ...","note":"FULLSCAN é o mais preciso; use SAMPLE em tabelas grandes. AUTO_UPDATE_STATISTICS para atualizações automáticas.","danger":"safe"},"mongodb":{"command":"// There are no manual statistics; the planner measures at runtime.\ndb.customer.getPlanCache().clear()","note":"Além de limpar um plan cache obsoleto, não são necessárias estatísticas manuais.","danger":"safe"},"redis":{"command":"# Not applicable.","note":"Não há estatísticas/otimizador.","danger":"safe"},"elasticsearch":{"command":"# There is no statistics gathering; refresh searchability:\nPOST <index>/_refresh","note":"Field data e doc values são usados no momento da consulta; o force merge reduz os segmentos.","danger":"safe"}}},{"id":"perf-report","title":"Gerar um relatório de desempenho (AWR / ASH e equivalentes)","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 requerem a licença Diagnostics Pack. O Statspack é o equivalente sem licença.","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":"Para um equivalente do AWR, use a extensão pg_profile (snapshots periódicos) ou a análise de logs do 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":"O schema sys transforma o performance_schema em relatórios legíveis; o Enterprise Monitor é mais abrangente.","danger":"safe"},"mssql":{"command":"-- Query Store reports (SSMS) or:\nSELECT TOP 20 * FROM sys.query_store_runtime_stats ORDER BY avg_duration DESC;","note":"O Query Store mantém planos/desempenho ao longo do tempo; o sp_BlitzFirst (comunidade) fornece diagnóstico rápido.","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 mostram a carga instantânea; o profiler registra as operações lentas.","danger":"safe"},"redis":{"command":"INFO stats\nredis-cli --latency-history\nSLOWLOG GET 20","note":"--latency e --latency-history fornecem o perfil de latência; INFO fornece todos os contadores.","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 mostra as threads mais caras; _nodes/stats fornece métricas holísticas. O Monitoring (Kibana) é histórico.","danger":"safe"}}},{"id":"optimizer-params","title":"Ver/alterar configurações do otimizador / paralelismo","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":"Configurações como optimizer_index_cost_adj e parallel_degree_policy afetam a escolha do plano; altere-as com cuidado.","danger":"caution"},"postgres":{"command":"SHOW random_page_cost;\nSHOW max_parallel_workers_per_gather;\n-- Session: SET enable_seqscan = off;","note":"Em SSDs, recomenda-se random_page_cost ~1.1. As flags enable_* servem para diagnóstico, não como correção permanente.","danger":"caution"},"mysql":{"command":"SELECT @@optimizer_switch;\nSET SESSION optimizer_switch='index_merge=off';","note":"optimizer_switch liga/desliga otimizações individuais; teste em nível de sessão.","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 é ilimitado; geralmente 4-8 para OLTP. O padrão de 5 do 'cost threshold for parallelism' é baixo demais para a maioria.","danger":"caution"},"mongodb":{"command":"# There are no optimizer parameters; indexes and query shape are decisive.\ndb.customer.find({...}).explain('allPlansExecution')","note":"allPlansExecution mostra todos os planos avaliados pelo planner.","danger":"safe"},"redis":{"command":"# Not applicable.","note":"Não há planner; io-threads e a escolha da estrutura de dados determinam o desempenho.","danger":"safe"},"elasticsearch":{"command":"GET <index>/_settings?include_defaults=true\n# search limits such as search.max_buckets, index.max_result_window","note":"Não há otimizador; o número de shards, o routing e a estrutura da consulta determinam o desempenho.","danger":"safe"}}},{"id":"sql-monitor","title":"Monitorar SQL em execução/recente em tempo real","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":"O Real-Time SQL Monitoring mostra ao vivo as consultas longas/paralelas (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":"Com o auto_explain, os planos das consultas lentas podem ser registrados automaticamente no log.","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 mostra as instruções em execução no momento.","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":"O 'Live Query Statistics' no SSMS mostra o progresso do plano ao vivo.","danger":"safe"},"mongodb":{"command":"db.currentOp({ active: true, secs_running: { $gt: 1 } })","note":"Mostra ao vivo as operações de longa duração; elas podem ser encerradas com killOp.","danger":"safe"},"redis":{"command":"MONITOR","note":"Transmite TODOS os comandos ao vivo — afeta o desempenho em produção, use apenas por pouco tempo. Prefira o SLOWLOG.","danger":"caution"},"elasticsearch":{"command":"GET _tasks?detailed=true&group_by=parents","note":"Mostra ao vivo as tarefas em execução; uma tarefa longa é cancelada com POST _tasks/<id>/_cancel.","danger":"safe"}}}]},"rosetta/tuning-adv.json":{"category":"Tuning avançado","categoryId":"tuning-adv","order":17,"concepts":[{"id":"parallel-query","title":"Executar uma consulta paralela / definir o grau de paralelismo","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":"O hint PARALLEL aplica uma varredura paralela à tabela; degree=DOP. Um DOP excessivo esgota os recursos do servidor; escolha-o com cuidado. parallel_degree_policy=AUTO o gerencia automaticamente.","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":"Se Gather/Parallel Seq Scan aparecer no plano, o paralelismo está em vigor. max_parallel_workers e min_parallel_table_scan_size também influenciam.","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":"O MySQL não oferece execução paralela geral de consultas; innodb_parallel_read_threads só paraleliza varreduras do clustered index (ex.: COUNT(*)). JOINs complexos são single-threaded.","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 limita o número de threads paralelas; MAXDOP 1 desabilita o paralelismo. Quando o 'cost threshold for parallelism' é ultrapassado, o plano passa a ser paralelo.","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":"Em um cluster com sharding, a consulta é executada em cada shard em paralelo; em um único nó, os estágios de agregação são majoritariamente sequenciais. allowDiskUse permite operações que excedem o limite de memória.","danger":"safe"},"redis":{"command":"# Not applicable: there is no concept of query parallelism.","note":"A execução de comandos é single-threaded; escale com Cluster (sharding) ou use io-threads para paralelismo de I/O de rede.","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":"Uma busca é executada simultaneamente em todos os shards relevantes; o número de primary shards define o nível básico de paralelismo. slices dividem operações grandes de scroll/reindex.","danger":"safe"}}},{"id":"bind-variables","title":"Gerenciar bind variables / parameter sniffing","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":"Bind variables reduzem os hard parses. O Adaptive Cursor Sharing atenua problemas de sniffing mantendo vários planos para valores de bind com distribuição assimétrica. Use cursor_sharing=FORCE com cuidado.","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 escolhe entre planos genéricos e personalizados; force_custom_plan gera um plano específico para os parâmetros a cada execução (uma solução para problemas semelhantes a sniffing).","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":"Prepared statements evitam SQL injection e reduzem o custo de parsing. O MySQL também suporta parametrização no nível do driver.","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) gera um plano específico para os parâmetros a cada execução (caro em CPU). OPTIMIZE FOR fixa o plano em um valor específico/típico; OPTIMIZE FOR UNKNOWN usa a seletividade média.","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":"Consultas com o mesmo formato (mesmos campos/operadores) compartilham o plano em cache; valores literais diferentes não geram um novo plano. Se a distribuição dos valores for muito assimétrica, redefina com planCacheClear.","danger":"safe"},"redis":{"command":"# Not applicable: there is no query planner or parameter sniffing.","note":"Os comandos são executados diretamente; o design das chaves, e não a parametrização, determina o desempenho.","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":"Um search template (Mustache) parametriza o corpo da consulta; a aplicação chama um template fixo com valores diferentes, melhorando a consistência das consultas e o uso do cache.","danger":"safe"}}},{"id":"partition-pruning","title":"Verificar o partition pruning","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 mostram que apenas as partições relevantes são lidas (o ideal é um número em vez de KEY). Aplicar uma função/conversão implícita à chave de partição impede o pruning.","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":"Com enable_partition_pruning ativado, apenas as partições correspondentes aparecem no plano; as demais aparecem como 'never executed'. Valores constantes são podados no momento do plano; parâmetros, no momento da execução.","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":"No MySQL 5.7+, a coluna 'partitions' da saída do EXPLAIN simples lista as partições a serem varridas (a sintaxe EXPLAIN PARTITIONS foi removida no 8.0); apenas a(s) partição(ões) relevante(s) deve(m) aparecer. Se todas as partições forem listadas, o pruning não está ocorrendo.","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":"A função $PARTITION retorna o número da partição de um valor. Se o número de partições acessadas no plano de execução real estiver próximo de 1, o pruning está em vigor; se todas as partições forem varridas, o predicado não corresponde.","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":"Se a consulta contiver a shard key, o mongos a direciona apenas ao shard relevante (targeted); caso contrário, ela é enviada a todos os shards (scatter-gather). Verifique os shards acessados na saída do explain.","danger":"safe"},"redis":{"command":"# Not applicable: there is no table/partition concept.","note":"Os dados são distribuídos pelos hash slots do Cluster; em vez de pruning de consultas, o acesso por chave é direto.","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":"O custom routing restringe a consulta a um único shard (semelhante ao pruning). Para dados de séries temporais, um nome de índice com padrão de data (sale-2026-01) garante que apenas os índices relevantes sejam pesquisados; use um padrão restrito em vez de um curinga.","danger":"safe"}}},{"id":"result-cache","title":"Usar um cache de resultados / de consultas","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":"O Server Result Cache mantém o resultado na SGA; é invalidado automaticamente quando as tabelas subjacentes mudam. RESULT_CACHE_MODE=FORCE o aplica a todas as consultas elegíveis; MANUAL, apenas via hint. Pouco benefício em tabelas que mudam com frequência.","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":"O PostgreSQL não oferece cache de resultados de consultas; use uma materialized view (REFRESH manual/agendado) ou um cache em nível de aplicação (Redis). Observação: o nó Memoize fornece cache em nível de linha dentro de um nested loop, não cache de resultados de consultas.","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":"O antigo query_cache_type foi totalmente removido no MySQL 8.0 (devido a problemas de escalabilidade). Em vez disso, use o InnoDB buffer pool, tabelas de resumo ou um cache externo (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":"O SQL Server não mantém cache de resultados (mantém um plan cache). Para agregações repetidas, uma indexed view é mantida automaticamente; a correspondência automática nos planos existe apenas nas edições Enterprise (e Developer), enquanto na Standard a view deve ser consultada com o hint WITH (NOEXPAND); além disso, o buffer pool mantém em memória as páginas lidas com frequência.","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":"O MongoDB não oferece cache de resultados; o WiredTiger mantém em memória os dados acessados com frequência. Para agregações caras, use uma coleção de resumo pré-calculada via $merge/$out ou um cache de aplicação (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":"O padrão cache-aside comum: se a chave existir, retorne-a rapidamente com GET; caso contrário, calcule a partir da origem e grave com SET usando EX (TTL). O Redis geralmente serve como cache de resultados para outros bancos de dados.","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":"O shard request cache armazena em cache os resultados por shard de requisições size:0 (apenas agregação); é invalidado quando o índice faz refresh. Consultas com size>0 (que retornam hits) não são armazenadas em cache por padrão.","danger":"safe"}}}]},"rosetta/advanced-features.json":{"category":"Recursos avançados","categoryId":"advanced-features","order":18,"concepts":[{"id":"full-text-search","title":"Busca full-text","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":"O Oracle Text (antes interMedia) fornece busca full-text sensível ao idioma por meio de um índice CONTEXT. O operador CONTAINS suporta operadores de busca como AND/OR/NEAR. O índice é mantido com CTX_DDL.SYNC_INDEX ou SYNC automático.","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":"A busca full-text nativa do PostgreSQL compara tsvector (documento) com tsquery (consulta) usando o operador @@. Um índice GIN acelera buscas em textos grandes. A configuração de idioma ('english') faz stemming e tratamento de stop words.","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":"Um índice FULLTEXT do MySQL é consultado com a sintaxe MATCH ... AGAINST. IN NATURAL LANGUAGE MODE retorna um score de relevância; IN BOOLEAN MODE dá controle refinado com os operadores +/-/*. O InnoDB suporta busca full-text a partir do 5.6.","since":"MySQL 5.6","xnote":"A busca full-text no InnoDB chegou no MySQL 5.6; antes disso, existia apenas no 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":"O Full-Text Search do SQL Server precisa primeiro de um Full-Text Catalog e depois de um Full-Text Index na tabela (um KEY INDEX único é obrigatório). CONTAINS suporta busca exata/por proximidade e operadores lógicos; FREETEXT suporta busca por significado (linguística). O componente Full-Text Search deve estar instalado.","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":"Um índice text do MongoDB fornece busca full-text pelo operador $text; uma coleção pode ter apenas um índice text. O meta campo textScore fornece a relevância. Para buscas mais avançadas, usa-se o Atlas Search ($search, baseado em 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":"O Redis core não oferece busca full-text; o módulo RediSearch (incluído no Redis Stack) fornece indexação com FT.CREATE e busca com FT.SEARCH. Stemming, busca fuzzy, filtragem e ordenação são suportados. Sem o módulo instalado, o recurso não está disponível.","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":"O Elasticsearch é fundamentalmente um mecanismo de busca full-text construído sobre o Lucene; os campos text são analisados no momento da indexação (tokenização, stemming). A consulta match retorna resultados ordenados pelo score de relevância (_score). Podem ser atribuídos analyzers específicos de idioma (ex.: 'english').","danger":"safe"}}},{"id":"json-query","title":"Consultar dados 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":"O Oracle (12c+) consulta dados JSON com expressões de caminho SQL/JSON. JSON_VALUE retorna um único valor escalar, JSON_QUERY um fragmento de objeto/array, e JSON_TABLE converte JSON em uma estrutura relacional de linhas e colunas. O 21c+ suporta um tipo de dado JSON nativo.","since":"Oracle 12c","xnote":"As consultas SQL/JSON chegaram no Oracle 12c; o tipo de dado JSON nativo, no 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":"O tipo jsonb do PostgreSQL oferece operadores ricos: -> (objeto/elemento json), ->> (valor texto), #> (caminho), @> (contenção), ? (existência de chave). Um índice GIN acelera as consultas com @> e ?. Consultas de caminho SQL/JSON também são possíveis com jsonb_path_query.","since":"PostgreSQL 9.4","xnote":"O tipo json chegou no PostgreSQL 9.2; o tipo jsonb, no 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":"O MySQL (5.7+) consulta o tipo JSON nativo com JSON_EXTRACT(); o operador -> é uma abreviação de JSON_EXTRACT, e ->> de JSON_UNQUOTE(JSON_EXTRACT()). Buscas em campos JSON podem ser aceleradas com uma generated column + índice.","since":"MySQL 5.7","xnote":"O tipo de dado JSON nativo chegou no 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":"O SQL Server (2016+) armazena JSON em uma coluna NVARCHAR. JSON_VALUE retorna um valor escalar, JSON_QUERY um objeto/array, e OPENJSON converte JSON em formato tabular. ISJSON() faz a validação. Buscas em caminhos JSON podem ser aceleradas com uma computed column + índice.","since":"SQL Server 2016","xnote":"As funções JSON (JSON_VALUE/OPENJSON) chegaram no 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":"O MongoDB armazena todos os dados como documentos (BSON, semelhante a JSON); consultá-los é nativo. A notação de ponto alcança campos aninhados e elementos de arrays. Transformações complexas são feitas com o Aggregation Pipeline, e os índices permitem buscas rápidas em campos aninhados.","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":"O Redis core não tem tipo JSON; o módulo RedisJSON (Redis Stack) fornece leituras e escritas baseadas em JSONPath com JSON.SET/JSON.GET. Junto com o RediSearch, documentos JSON podem ser indexados e consultados. Sem o módulo, o JSON é armazenado como string e interpretado na aplicação.","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":"O Elasticsearch armazena e indexa documentos nativamente como JSON. Para preservar os limites dos elementos em arrays de objetos aninhados, use o tipo de campo 'nested' e uma consulta nested; caso contrário, arrays do tipo object são achatados (risco de correspondência cruzada). A distinção object vs. nested é crítica para a correção.","danger":"safe"}}},{"id":"spatial-geo","title":"Consulta geográfica / espacial","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":"O Oracle Spatial armazena dados geográficos no tipo SDO_GEOMETRY; são necessários uma entrada em USER_SDO_GEOM_METADATA e um índice espacial. Operadores como SDO_WITHIN_DISTANCE, SDO_RELATE e SDO_NN respondem a consultas de distância/interseção/vizinho mais próximo. O SRID 4326 é o sistema WGS84 (latitude/longitude).","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":"O PostGIS transforma o PostgreSQL em um banco de dados espacial completo. Fornece os tipos geometry (plano) e geography (esférico) e centenas de funções ST_, como ST_Distance/ST_DWithin/ST_Intersects/ST_Contains. Um índice GiST/SP-GiST acelera as consultas espaciais.","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":"O MySQL (5.7+) suporta tipos de dados espaciais compatíveis com OGC (POINT, POLYGON etc.) e funções ST_. Um índice SPATIAL (R-tree) só pode ser criado em InnoDB/MyISAM e em colunas NOT NULL; para que o otimizador o use, a coluna deve ser definida com um atributo SRID (SRID 4326). Com SRID 4326, ST_Distance retorna a distância geodésica em metros. Com POINT(x, y) + ST_SRID, x é a longitude e y é a latitude; para entrada WKT (ST_GeomFromText) com SRID 4326, a ordem é latitude-longitude.","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":"O SQL Server oferece dois tipos espaciais: geography (esférico, latitude/longitude) e geometry (plano). Métodos como STDistance, STIntersects e STContains respondem às consultas. Um índice espacial (baseado em grade) melhora o desempenho. Atenção à ordem dos argumentos de 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":"O MongoDB armazena dados geográficos no formato GeoJSON e executa consultas esféricas com um índice 2dsphere. Os operadores $near (ordenado por distância), $geoWithin (dentro de uma área) e $geoIntersects são suportados. As coordenadas ficam na ordem [longitude, latitude]; $maxDistance está em metros.","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":"O Redis armazena localizações geográficas em um sorted set com GEOADD (longitude latitude member). GEOSEARCH (Redis 6.2+, substituindo o antigo GEORADIUS) retorna os membros dentro de um raio ou retângulo, ordenados por distância. GEODIST fornece a distância entre dois pontos. É um recurso core; não é necessário módulo.","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":"O Elasticsearch suporta os tipos de campo geo_point (ponto) e geo_shape (polígono/linha). A filtragem é feita com as consultas geo_distance (raio), geo_bounding_box (retângulo) e geo_polygon; a ordenação com geo_distance, e a agregação com geohash_grid/geotile_grid. As coordenadas são informadas como lat/lon ou como um array [lon, lat].","danger":"safe"}}},{"id":"window-functions-adv","title":"Funções de janela (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":"O Oracle foi pioneiro nas funções analíticas (de janela); ROW_NUMBER, RANK, DENSE_RANK, LAG, LEAD, SUM/AVG OVER, NTILE e FIRST_VALUE são totalmente suportadas. Dentro de OVER, PARTITION BY define os grupos, ORDER BY a ordenação, e o frame (ROWS/RANGE BETWEEN) a janela deslizante.","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":"O PostgreSQL suporta totalmente funções de janela com sintaxe SQL padrão. Estão disponíveis ROW_NUMBER/RANK/DENSE_RANK, LAG/LEAD, agregações com OVER, NTILE e FIRST_VALUE/LAST_VALUE. Definições de janela repetidas podem ser nomeadas e compartilhadas com a cláusula 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":"O MySQL adicionou funções de janela na versão 8.0 (o MariaDB 10.2+ também as suporta). Estão disponíveis ROW_NUMBER, RANK, DENSE_RANK, LAG, LEAD, NTILE e agregações com OVER. Versões anteriores ao 8.0 não têm essas funções; elas eram emuladas com variáveis de usuário.","since":"MySQL 8.0","xnote":"Antes do MySQL 8.0 não havia funções de janela; eram emuladas com variáveis de usuário.","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":"O SQL Server suporta funções de janela desde 2005 (ROW_NUMBER/RANK) e 2012 (LAG/LEAD, framing, agregações com OVER). PARTITION BY, ORDER BY e o frame ROWS/RANGE estão totalmente disponíveis. OFFSET/FETCH ou ROW_NUMBER são comuns para paginação.","since":"SQL Server 2005","xnote":"As funções de ranking chegaram em 2005; LAG/LEAD e framing, em 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":"O estágio de agregação $setWindowFields, introduzido no MongoDB 5.0, fornece funções de janela: $documentNumber (ROW_NUMBER), $rank/$denseRank, $shift (LAG/LEAD), funções de agregação e janelas deslizantes (window: { documents/range }). partitionBy e sortBy correspondem a PARTITION BY/ORDER BY no SQL.","since":"MongoDB 5.0","xnote":"O estágio $setWindowFields chegou no MongoDB 5.0.","danger":"safe"},"redis":{"command":"# Not applicable: there are no SQL-like window functions.","note":"O Redis é um armazenamento chave-valor; não tem funções analíticas de janela. Para resultados ordenados, pode-se usar um Sorted Set (acesso semelhante a ranking com ZADD/ZRANGE); porém, operações de janela relacionais como PARTITION BY/LAG são feitas na camada da aplicação.","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":"O Elasticsearch não oferece funções de janela clássicas (ROW_NUMBER/RANK/LAG). Agrupamento e ordenação são feitos com o framework de agregação: uma terms aggregation se aproxima de PARTITION BY, top_hits dos registros principais, e derivative/serial_diff (pipeline aggregations) de diferenças sucessivas semelhantes a LAG.","danger":"safe"}}},{"id":"columnstore-analytics","title":"Armazenamento colunar / analytics","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":"O Oracle Database In-Memory (12.1.0.2+) acelera consultas analíticas mantendo as tabelas em memória em formato colunar (In-Memory Column Store, IM), preservando o formato de linha em disco (dual format). INMEMORY é uma opção licenciada separadamente. O parâmetro inmemory_size dimensiona a área IM.","since":"Oracle 12.1.0.2","xnote":"O column store do Database In-Memory chegou no Oracle 12.1.0.2 (licença separada).","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":"O PostgreSQL core oferece apenas armazenamento baseado em linhas (heap). Para armazenamento colunar, usam-se o access method 'columnar' do Citus (USING columnar), o Hydra ou a antiga extensão cstore_fdw; elas fornecem compressão e velocidade de varredura para cargas de analytics/data warehouse.","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":"O MySQL padrão (InnoDB) é baseado em linhas e não tem columnstore nativo. Para aceleração analítica, usa-se o MySQL HeatWave (um acelerador colunar em memória na Oracle Cloud); soluções on-premises normalmente usam engines colunares externos como ClickHouse ou 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":"Os columnstore indexes do SQL Server (nonclustered somente leitura no 2012; clustered atualizável no 2014; nonclustered atualizável no 2016) armazenam os dados por coluna com alta compressão; com batch mode, aceleram bastante consultas analíticas com muita agregação/varredura. O clustered é adequado para data warehouses; o nonclustered, para HTAP.","since":"SQL Server 2012","xnote":"O columnstore index chegou em 2012 (somente leitura), o clustered columnstore atualizável em 2014 e o nonclustered columnstore atualizável em 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":"O MongoDB armazena documentos como BSON, semelhante a linhas; não há armazenamento colunar (columnstore) nativo. Para cargas analíticas, usam-se Analytics Nodes dedicados em um replica set do Atlas, o Atlas Data Federation ou a exportação dos dados para um sistema colunar (ex.: Parquet).","danger":"safe"},"redis":{"command":"-- Not applicable: there is no concept of columnar storage.","note":"O Redis é um armazenamento chave-valor em memória; não há distinção entre armazenamento por linha/coluna. Agregações analíticas são feitas com estruturas especiais como Sorted Set, HyperLogLog (contagem aproximada) ou RedisTimeSeries; não é adequado para OLAP em larga escala.","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":"Para ordenações e agregações, o Elasticsearch mantém os campos em uma estrutura colunar em disco chamada doc_values (habilitada por padrão em campos numeric/keyword/date). Esse layout colunar acelera consultas analíticas/de agregação; é desabilitado por padrão em campos text.","danger":"safe"}}},{"id":"in-memory","title":"Tabelas em memória / aceleração","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":"O Oracle Database In-Memory acelera analytics mantendo em memória, em formato colunar, as tabelas consultadas com frequência (licença separada). Para OLTP, o Buffer Cache e o KEEP pool também mantêm em memória os blocos acessados com frequência. A solução in-memory preserva a durabilidade pelo formato de linha em disco.","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":"O PostgreSQL não oferece um engine dedicado de tabelas em memória; uma tabela UNLOGGED pula a gravação no WAL para acelerar as escritas (o conteúdo é perdido em um crash; não é durável). Tabelas TEMP duram a sessão e ficam em memória sempre que possível via temp_buffers. Os dados quentes ficam em cache no 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":"O storage engine MEMORY (antes HEAP) do MySQL mantém os dados da tabela inteiramente na RAM; é muito rápido, mas os dados são perdidos quando o servidor reinicia (a estrutura permanece). Não suporta BLOB/TEXT e usa tamanho de linha fixo. Para dados quentes duráveis, prefere-se o InnoDB buffer pool.","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":"O In-Memory OLTP (Hekaton) do SQL Server fornece OLTP altamente concorrente com tabelas memory-optimized (MEMORY_OPTIMIZED=ON) e estruturas latch-free. DURABILITY=SCHEMA_AND_DATA mantém os dados duráveis; SCHEMA_ONLY preserva apenas o schema. Requer um filegroup memory-optimized.","since":"SQL Server 2014","xnote":"O In-Memory OLTP (Hekaton) chegou no 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":"O MongoDB não tem um tipo separado de tabela em memória (o antigo In-Memory Storage Engine era exclusivo do Enterprise e foi descontinuado). O engine padrão WiredTiger melhora a velocidade de leitura mantendo em seu cache de memória os dados e índices acessados com frequência; o cache de arquivos do SO também contribui.","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":"O Redis mantém todos os dados na RAM; por design, essa é a fonte de sua velocidade. A persistência é fornecida por RDB (snapshots) e/ou AOF (log de comandos). O limite maxmemory e a política de eviction (LRU/LFU/random) determinam o comportamento quando a memória fica cheia.","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":"O Elasticsearch armazena os dados em disco (segmentos Lucene); não oferece um engine dedicado de tabelas em memória. Para velocidade, depende do cache de arquivos do SO (page cache), dos doc_values e de uma arquitetura hot-warm-cold. RAM suficiente e configurações de heap adequadas são críticas para o desempenho.","danger":"safe"}}},{"id":"time-series","title":"Dados de séries temporais","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":"No Oracle, dados de séries temporais geralmente são gerenciados com particionamento RANGE (INTERVAL); novas partições são criadas automaticamente e as antigas são removidas facilmente (o partition pruning acelera as consultas). Também se usam compressão (ILM/ADO) e materialized views para agregação.","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":"O PostgreSQL pode armazenar séries temporais com particionamento nativo (PARTITION BY RANGE); a extensão TimescaleDB adiciona hypertables com chunking automático por tempo, compressão, políticas de retenção e continuous aggregates. É uma solução comum para grandes cargas de IoT/métricas.","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":"O MySQL não oferece um engine dedicado a séries temporais; o particionamento RANGE (com TO_DAYS/UNIX_TIMESTAMP) permite remover rapidamente dados antigos e fazer partition pruning. Para séries temporais de alto volume, geralmente se preferem soluções externas (TimescaleDB, InfluxDB) ou tabelas de resumo.","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":"O SQL Server gerencia séries temporais particionando com partition function/scheme; isso fornece pruning e arquivamento rápido para dados que abrangem grandes intervalos de datas. Além disso, as system-versioned temporal tables (SYSTEM_VERSIONING) mantêm automaticamente o histórico de alterações das linhas e permitem consultas point-in-time (FOR SYSTEM_TIME).","since":"SQL Server 2016","xnote":"As system-versioned temporal tables chegaram no 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":"As time-series collections, introduzidas no MongoDB 5.0, armazenam automaticamente os dados em formato comprimido, semelhante a colunar (em buckets), por tempo e meta field; reduzem o uso de disco e de índices e aceleram as consultas por intervalo. timeField é obrigatório; metaField (origem/tag) e granularity determinam o desempenho.","since":"MongoDB 5.0","xnote":"As time-series collections chegaram no 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":"O Redis core não tem tipo de série temporal; o módulo RedisTimeSeries (Redis Stack) fornece ingestão de amostras em alta velocidade com TS.CREATE/TS.ADD, retenção automática (RETENTION), downsampling (TS.CREATERULE) e consultas por intervalo baseadas em labels com TS.RANGE/TS.MRANGE. Sem o módulo, é emulado com um 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":"O Elasticsearch gerencia dados de séries temporais com data streams; novos backing indexes são criados automaticamente ao longo do tempo (rollover), e o ILM move os dados antigos pelas camadas hot/warm/cold e os exclui. O TSDS (index.mode: time_series) fornece otimizações de armazenamento específicas para dados de métricas; são obrigatórios pelo menos um campo time_series_dimension, um index.routing_path apontando para ele e um campo @timestamp (caso contrário, o template é rejeitado).","danger":"safe"}}},{"id":"vector-search","title":"Busca vetorial (IA/embeddings)","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":"O Oracle Database 23ai oferece um tipo de dado VECTOR nativo e o recurso AI Vector Search. A função VECTOR_DISTANCE calcula a similaridade com as métricas COSINE/EUCLIDEAN/DOT; índices vetoriais HNSW e IVF são suportados para busca aproximada. Os embeddings são gerados dentro do banco ou com modelos externos.","since":"Oracle 23ai","xnote":"O tipo VECTOR nativo e o AI Vector Search chegaram no 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":"A extensão pgvector adiciona ao PostgreSQL um tipo vector e operadores de similaridade: <-> (L2/euclidiana), <=> (cosseno), <#> (produto interno). Índices HNSW ou IVFFlat aceleram a busca aproximada de vizinhos mais próximos (ANN). Muito usada em aplicações de RAG e busca semântica.","xnote":"O PostgreSQL core não tem tipo vector; a extensão pgvector é necessária.","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":"O MySQL 9.0 adicionou o tipo de dado VECTOR nativo e as funções STRING_TO_VECTOR/VECTOR_TO_STRING e VECTOR_DIM (também no Community). A função DISTANCE() e a busca vetorial aproximada em escala estão disponíveis apenas no MySQL HeatWave na Oracle Cloud; no Community/Enterprise, calcule as distâncias na aplicação ou em um vector store externo. Versões on-premises mais antigas exigem um vector store externo.","since":"MySQL 9.0","xnote":"O tipo de dado VECTOR nativo chegou no 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":"O SQL Server 2025 (e o Azure SQL) oferecem um tipo de dado vector nativo e a função VECTOR_DISTANCE (cosine/euclidean/dot); índices vetoriais baseados em DiskANN para busca aproximada de vizinhos mais próximos estão em desenvolvimento. Os embeddings são gerados com modelos externos, como o Azure OpenAI, e armazenados.","since":"SQL Server 2025","xnote":"O tipo de dado vector nativo chegou no 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":"O MongoDB Atlas Vector Search consulta embeddings com o estágio de agregação $vectorSearch; internamente, faz busca aproximada de vizinhos mais próximos baseada em HNSW. O índice vetorial é definido como um índice do Atlas Search. Esse recurso é específico do serviço gerenciado Atlas (não está disponível na edição Community on-premises).","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":"O Redis fornece busca vetorial pelo módulo RediSearch (Redis Stack); o tipo de campo VECTOR suporta índices FLAT (exato) ou HNSW (aproximado) e as métricas COSINE/L2/IP. Os vizinhos mais próximos são obtidos com a sintaxe KNN dentro de FT.SEARCH. Usado para busca semântica de baixa latência e 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":"O Elasticsearch suporta consultas aproximadas de vizinhos mais próximos (HNSW) com o tipo de campo dense_vector e a busca knn nativa; a similaridade pode ser cosine/dot_product/l2_norm. A relevância pode ser melhorada combinando a busca vetorial com uma consulta de texto clássica (busca híbrida / RRF).","since":"Elasticsearch 8.0","xnote":"A busca kNN nativa com dense_vector chegou no Elasticsearch 8.x.","danger":"safe"}}},{"id":"cdc-change-tracking","title":"Rastreamento de alterações (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":"O Oracle faz rastreamento de alterações baseado no redo log. O LogMiner traduz redo/archived logs em SQL para inspecionar DML passado; os arquivos de log a analisar são adicionados com DBMS_LOGMNR.ADD_LOGFILE. Para resultados significativos, pelo menos o supplemental logging mínimo deve estar habilitado (ALTER DATABASE ADD SUPPLEMENTAL LOG DATA). Para CDC contínuo de baixa latência e replicação heterogênea, o Oracle GoldenGate (um produto separado) é o padrão; os antigos recursos Streams/Change Data Capture estão obsoletos.","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":"O logical decoding do PostgreSQL transforma os registros do WAL em um fluxo legível de alterações por meio de um output plugin (wal2json, pgoutput, test_decoding); o replication slot garante que as alterações não sejam perdidas. wal_level deve ser logical. O Debezium usa esse mecanismo para fornecer CDC corporativo.","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":"No MySQL, a fonte de CDC é o binary log. Com binlog_format=ROW, toda alteração de linha é registrada. Ferramentas como Debezium ou Maxwell leem o binlog como uma réplica e produzem um fluxo de eventos para o Kafka. Habilitar o GTID facilita o rastreamento confiável de posição.","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":"O SQL Server oferece dois mecanismos: o Change Data Capture (CDC) grava todo o DML (com valores antigos/novos) do transaction log em change tables e requer o SQL Server Agent. O Change Tracking apenas rastreia de forma leve quais linhas mudaram (net changes) e não mantém histórico completo dos dados.","since":"SQL Server 2008","xnote":"CDC e Change Tracking chegaram no 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":"Os Change Streams do MongoDB, construídos sobre o oplog, entregam eventos de insert, update e delete em nível de coleção/banco/cluster como um fluxo em tempo real. Requer um replica set ou um cluster com sharding. Com um resumeToken, um fluxo pode ser retomado de onde parou após uma interrupção; é a base das integrações de CDC.","since":"MongoDB 3.6","xnote":"Os Change Streams chegaram no 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":"As keyspace notifications do Redis publicam eventos sobre chaves (SET, DEL, EXPIRE etc.) por canais Pub/Sub; são habilitadas com a configuração notify-keyspace-events (K=keyspace, E=keyevent, A=todos os eventos). Para um fluxo de alterações confiável e durável, prefere-se o 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":"O Elasticsearch não oferece um fluxo de change data capture (CDC); não publica nativamente quando um documento mudou. A abordagem comum é adicionar um campo updated_ts a cada documento e executar consultas incrementais por timestamp (range + sort). Geralmente, o CDC do banco de origem é que alimenta o Elasticsearch.","danger":"safe"}}}]},"rosetta/sql-syntax.json":{"category":"Sintaxe SQL e palavras-chave","categoryId":"sql-syntax","order":19,"concepts":[{"id":"with-cte","title":"WITH (Common Table Expression / 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 define um conjunto de resultados temporário nomeado (CTE) dentro de uma consulta; em vez de escrever uma subconsulta repetidamente, você a define uma vez e a referencia pelo nome. Divide consultas complexas em partes legíveis. Suportado desde o 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":"Uma CTE divide consultas complexas em blocos nomeados. Antes do PostgreSQL 12, uma CTE era uma barreira de otimização (sempre materializada); a partir do 12, pode ser incorporada (inlined), e o comportamento antigo pode ser forçado com 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":"Uma CTE define um conjunto de resultados temporário nomeado dentro de uma consulta e melhora a legibilidade. Suportada a partir do MySQL 8.0 (e MariaDB 10.2); versões mais antigas exigem uma derived table (uma subconsulta no FROM).","since":"MySQL 8.0","xnote":"Antes do MySQL 8.0 não havia CTEs; o mesmo era feito com uma derived table (uma subconsulta no 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":"Uma CTE é um conjunto de resultados temporário nomeado. No SQL Server, a instrução imediatamente anterior a uma CTE deve terminar com ponto e vírgula; por isso, WITH costuma ser escrito como ';WITH'. Vale pela duração de uma única instrução (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":"O MongoDB não tem SQL/CTE; os estágios do aggregation pipeline fazem o mesmo trabalho. Cada estágio recebe como entrada a saída do estágio anterior, permitindo um processamento passo a passo semelhante a cadeias de CTEs. $facet ou $lookup também podem ser usados para resultados intermediários.","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no concept of SQL or CTEs.","note":"O Redis é um armazenamento de dados chave-valor sem linguagem de consulta. Você combina resultados intermediários no lado do cliente ou usa um script Lua (EVAL) para lógica no lado do servidor.","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":"O Elasticsearch SQL (a API _sql) não suporta a sintaxe WITH/CTE; agrupamento e filtragem são escritos em um único SELECT. Na abordagem nativa, o mesmo é feito com uma agregação 'terms' e uma pipeline aggregation 'bucket_selector'.","danger":"safe"}}},{"id":"recursive-cte","title":"CTE recursiva (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":"Usada para percorrer dados hierárquicos (árvore): organogramas, listas de materiais e similares. A forma clássica do Oracle é CONNECT BY / PRIOR e a pseudocoluna LEVEL; START WITH define a linha raiz. Desde o 11gR2, a CTE recursiva padrão também é suportada.","since":"Oracle 11gR2","xnote":"CONNECT BY é o método clássico; o WITH recursivo padrão (sem a palavra-chave RECURSIVE) chegou com o 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 combina uma consulta âncora e uma parte recursiva com UNION ALL; a parte recursiva é executada repetidamente até o resultado ficar vazio. Ideal para hierarquias e travessia de grafos. Proteja-se contra loops infinitos com UNION (em vez de ALL) ou proteção contra ciclos.","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":"O MySQL 8.0 (e o MariaDB 10.2+) suportam a sintaxe WITH RECURSIVE em conformidade com o padrão. A profundidade da recursão é limitada pela variável de sistema cte_max_recursion_depth (padrão 1000). Versões mais antigas exigiam escrever um loop em uma stored procedure.","since":"MySQL 8.0","xnote":"Antes do MySQL 8.0 (MariaDB 10.2) não havia consultas recursivas; escrevia-se um loop em uma stored procedure.","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":"No SQL Server, a palavra-chave RECURSIVE não é escrita para uma CTE recursiva; uma CTE com UNION ALL que referencia a si mesma é tratada automaticamente como recursiva. O limite padrão de recursão é 100; altere-o com OPTION (MAXRECURSION n) (0 = ilimitado, use com cuidado).","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":"O MongoDB não tem CTE recursiva; o estágio de agregação $graphLookup é usado para travessia hierárquica. connectFromField/connectToField definem os campos de ligação e maxDepth define o limite de profundidade. Resolve relações de árvore e grafo em uma única consulta.","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no recursive queries.","note":"O Redis não oferece linguagem de consulta. A travessia de hierarquias/grafos é feita no código da aplicação ou no lado do servidor com um script Lua; no Redis core, o percurso da árvore é escrito no lado do cliente. (O suporte ao módulo RedisGraph, usado anteriormente, terminou em 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":"O Elasticsearch não oferece consulta recursiva (não há equivalente de WITH RECURSIVE / CONNECT BY). Relações hierárquicas são modeladas com o tipo de campo 'join' (parent/child) ou armazenando o caminho da árvore (materialized path) em um campo; a travessia em vários níveis geralmente é feita na aplicação.","danger":"safe"}}},{"id":"joins","title":"Tipos de 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":"Um JOIN combina duas tabelas de acordo com a condição informada. INNER retorna apenas as correspondências; LEFT/RIGHT retornam todas as linhas de um lado (NULL onde não há correspondência); FULL retorna as linhas dos dois lados; CROSS retorna todas as combinações. Além dos JOINs ANSI padrão, o Oracle também suporta a antiga sintaxe de outer join (+).","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":"O PostgreSQL suporta totalmente todos os tipos de JOIN padrão (INNER, LEFT/RIGHT/FULL OUTER, CROSS). USING(my_column) é uma abreviação para colunas com nomes comuns, enquanto NATURAL JOIN une automaticamente por todas as colunas de mesmo nome (use com cuidado).","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":"O MySQL/MariaDB suportam INNER, LEFT, RIGHT e CROSS JOIN, mas não oferecem FULL OUTER JOIN diretamente; ele é emulado combinando os resultados de LEFT e RIGHT com UNION. O antigo join com vírgula gera um produto cartesiano e deve ser restringido com 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":"O SQL Server suporta todos os tipos de JOIN padrão. Os antigos operadores de outer join *= / =* foram removidos; deve-se usar a sintaxe ANSI JOIN. APPLY (CROSS/OUTER APPLY) é uma forma adicional de join para subconsultas correlacionadas linha a linha.","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":"O MongoDB não tem JOIN clássico; o estágio de agregação $lookup obtém os documentos correspondentes de outra coleção como um array (semelhante a um left outer join). Para um resultado semelhante a INNER, filtre depois os arrays vazios com $match e expanda o array em linhas com $unwind.","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no tables or JOINs.","note":"O Redis não oferece joins relacionais; os dados geralmente são desnormalizados, ou as relações são montadas no lado do cliente lendo várias chaves. O RediSearch (FT.AGGREGATE) pode ser usado para consultas limitadas semelhantes a join; o suporte ao módulo RedisGraph terminou em 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":"Devido à sua arquitetura distribuída, o Elasticsearch não oferece JOINs arbitrários entre tabelas. Para relações limitadas, existem o tipo de campo 'nested' dentro de um único índice e o tipo de campo 'join' (parent/child) no mesmo shard. A solução mais comum é desnormalizar os dados no momento da indexação.","danger":"safe"}}},{"id":"window-functions","title":"Funções de janela (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":"As funções de janela calculam sobre uma 'janela' para cada linha sem agrupar as linhas (sem reduzir o número de linhas). PARTITION BY divide a janela, ORDER BY a ordena. O Oracle foi pioneiro nessas funções analíticas e oferece um conjunto rico, incluindo ROW_NUMBER, RANK, DENSE_RANK, LAG/LEAD e 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":"O PostgreSQL suporta todas as funções de janela padrão e permite nomear uma definição de janela repetida com WINDOW ... AS. Com as definições de frame ROWS/RANGE/GROUPS, é possível calcular totais acumulados, médias móveis e similares.","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":"O MySQL 8.0 (e o MariaDB 10.2+) suportam funções de janela; antes disso, eram emuladas com variáveis de usuário ou subconsultas. Estão disponíveis ROW_NUMBER, RANK, DENSE_RANK, NTILE, LAG/LEAD, FIRST_VALUE/LAST_VALUE e a forma OVER das funções de agregação.","since":"MySQL 8.0","xnote":"Antes do MySQL 8.0 não havia funções de janela; eram emuladas com variáveis/self-joins.","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":"O SQL Server suporta funções de janela de ranking desde 2005, e agregações com frame e funções como LAG/LEAD desde 2012. ROW_NUMBER é muito usado para paginação (com OFFSET/FETCH) e para encontrar as N primeiras linhas por grupo.","since":"SQL Server 2005","xnote":"As funções de janela de ranking chegaram em 2005; frames e LAG/LEAD, em 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":"O estágio $setWindowFields do MongoDB 5.0+ é o equivalente às funções de janela do SQL: a janela é definida com partitionBy e sortBy, produzindo saídas como $rank/$denseRank/$documentNumber, $shift (LAG/LEAD) e totais acumulados. Em versões mais antigas, isso era resolvido com $group + código.","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no window functions.","note":"O Redis não oferece funções analíticas de janela. Para resultados ordenados e ranking, use a estrutura Sorted Set (ZSET): atribua scores com ZADD, leia o ranking com ZRANK/ZREVRANK e intervalos com ZRANGE. Análises complexas são feitas na aplicação.","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":"O Elasticsearch não tem funções de janela diretas. Para os N primeiros registros por grupo, use uma sub-agregação 'top_hits'; para cálculos móveis/acumulados, use pipeline aggregations como 'derivative', 'cumulative_sum' e 'moving_fn'. Ordenação e particionamento são feitos com uma terms aggregation.","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 agrupa as linhas pelas colunas informadas e aplica funções de agregação; HAVING filtra o resultado agrupado (WHERE filtra as linhas antes do agrupamento). ROLLUP gera subtotais hierárquicos + um total geral, CUBE todas as combinações, e GROUPING SETS os agrupamentos selecionados. O Oracle suporta os três.","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":"O PostgreSQL 9.5+ suporta ROLLUP, CUBE e GROUPING SETS em conformidade com o padrão. A função GROUPING() indica se uma coluna está em uma linha de total (NULL). HAVING filtra após a agregação; WHERE, antes.","since":"PostgreSQL 9.5","xnote":"ROLLUP, CUBE e GROUPING SETS chegaram com o 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":"O MySQL/MariaDB geram subtotais/totais gerais com a sintaxe GROUP BY ... WITH ROLLUP; CUBE e GROUPING SETS não são suportados. Aliases do SELECT podem ser usados no HAVING (isso geralmente não funciona no Oracle/SQL Server). Nas linhas de ROLLUP, a coluna agrupada aparece como 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":"Junto com o GROUP BY, o SQL Server suporta ROLLUP(), CUBE() e GROUPING SETS (2008+) com sintaxe moderna; a antiga forma WITH ROLLUP/WITH CUBE está obsoleta. GROUPING() e GROUPING_ID() ajudam a distinguir as linhas de total.","since":"SQL Server 2008","xnote":"A sintaxe moderna de GROUPING SETS chegou com o 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":"No MongoDB, $group é o equivalente ao GROUP BY do SQL; _id define a chave de agrupamento e os acumuladores ($sum, $avg, $max) definem as agregações. A filtragem após o agrupamento é feita com $match (o equivalente ao HAVING). Totais em vários níveis, como ROLLUP/CUBE, são obtidos executando vários pipelines com $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":"O Redis core não oferece agrupamento; o comando FT.AGGREGATE do módulo RediSearch faz agregação semelhante ao SQL com GROUPBY e REDUCE (COUNT, SUM, AVG). A etapa FILTER filtra o resultado agrupado como um HAVING. Sem o módulo, a agregação é feita na aplicação.","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":"No Elasticsearch, o agrupamento é feito com a bucket aggregation 'terms' e as agregações com metric aggregations (sum, avg, cardinality). Para filtragem semelhante a HAVING, use a pipeline aggregation 'bucket_selector'. Subtotais em vários níveis são montados com agregações aninhadas.","danger":"safe"}}},{"id":"case-expr","title":"Expressão CASE (valor condicional)","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 mapeia uma expressão para valores diferentes conforme as condições; tem uma forma simples (CASE my_column WHEN value) e uma forma pesquisada (CASE WHEN condition). O DECODE do Oracle faz algo semelhante, mas compara apenas por igualdade e trata NULLs como iguais; prefira CASE pela portabilidade.","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":"O PostgreSQL suporta totalmente a expressão CASE padrão, utilizável em qualquer lugar que produza um valor (SELECT, WHERE, ORDER BY, GROUP BY). Não tem DECODE no estilo Oracle; use CASE ou, para condições curtas, 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":"O MySQL/MariaDB suportam a expressão CASE padrão; há também a função IF(condition, if_true, if_false) para uma condição rápida de dois ramos (semelhante ao IIF do SQL Server). CASE pode ser usado em qualquer contexto de expressão.","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":"O SQL Server suporta o CASE padrão; desde 2012 existem o atalho IIF() para condições de dois ramos e CHOOSE() para múltiplas correspondências. Na verdade, o IIF é traduzido para CASE. CASE também pode ser usado em ORDER BY e em computed columns.","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":"Na agregação do MongoDB, os equivalentes ao CASE são os operadores $switch (vários ramos) e $cond (if-then-else com três argumentos). São usados dentro de $project ou $addFields para criar campos derivados condicionais.","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no in-query conditional expression.","note":"O Redis não tem uma expressão de consulta como CASE. A lógica condicional é escrita no código da aplicação ou em um script Lua no lado do servidor (EVAL). É possível uma avaliação limitada de expressões com APPLY dentro do FT.AGGREGATE do RediSearch.","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":"No Elasticsearch, a lógica CASE dentro da consulta é escrita como um script Painless (runtime field, script_fields ou scripted metric). O fluxo if/else é definido na linguagem Painless. A agregação 'range' também pode gerar buckets semelhantes a CASE para categorização.","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":"Os operadores de conjunto combinam os conjuntos de resultados de duas consultas. UNION remove duplicatas (mais lento), UNION ALL mantém todas (mais rápido), INTERSECT retorna as linhas em comum, e o operador de diferença retorna as linhas encontradas apenas no primeiro conjunto. Para a diferença, o Oracle usa MINUS em vez do EXCEPT padrão (EXCEPT também existe desde o 21c).","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":"O PostgreSQL suporta totalmente UNION, UNION ALL, INTERSECT e EXCEPT padrão (EXCEPT, não MINUS, para a diferença). A forma ALL de cada operador (INTERSECT ALL, EXCEPT ALL) preserva a contagem de duplicatas. O número e os tipos das colunas devem ser compatíveis.","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":"Por muito tempo o MySQL suportou apenas UNION / UNION ALL; INTERSECT e EXCEPT só foram adicionados no MySQL 8.0.31 (MariaDB 10.3). Em versões mais antigas, use INNER JOIN/EXISTS para interseção e LEFT JOIN ... IS NULL ou NOT EXISTS para diferença.","since":"MySQL 8.0.31","xnote":"INTERSECT/EXCEPT chegaram com o MySQL 8.0.31 (MariaDB 10.3); antes disso, eram resolvidos com 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":"O SQL Server suporta UNION, UNION ALL, INTERSECT e EXCEPT padrão (2005+); o operador de diferença é EXCEPT (não MINUS). INTERSECT/EXCEPT comparam as linhas tratando valores NULL como iguais.","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":"O estágio $unionWith do MongoDB 4.4+ combina os resultados de duas coleções (como UNION ALL). Para remover duplicatas, deduplique depois com $group. INTERSECT/EXCEPT não têm equivalente direto; são modelados com $lookup ou operadores de conjunto ($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":"O Redis não tem SQL, mas o tipo de dado Set oferece operações de conjunto nativas: SUNION (união), SINTER (interseção), SDIFF (diferença) e suas variantes STORE, que salvam o resultado. Elas operam sobre membros de conjuntos já montados, não sobre resultados de consultas.","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":"O Elasticsearch não oferece UNION/INTERSECT/EXCEPT. Um efeito de união é obtido consultando vários índices separados por vírgula; para interseção e diferença, use as cláusulas must/should/must_not de uma bool query ou lógica de conjuntos no lado da aplicação.","danger":"safe"}}},{"id":"exists-in","title":"EXISTS / IN / NOT EXISTS (subconsulta)","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 verifica se uma subconsulta correlacionada retorna pelo menos uma linha (para na primeira correspondência, por isso é rápido). IN verifica se um valor está em uma lista/resultado de subconsulta. Atenção: se a subconsulta puder produzir NULL, NOT IN gera resultados inesperados; NOT EXISTS é mais seguro. O otimizador do Oracle frequentemente transforma ambos no mesmo plano.","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":"O PostgreSQL suporta totalmente EXISTS/IN/NOT EXISTS. Com NOT IN, se a subconsulta contiver NULL, o resultado inteiro pode ficar vazio; por isso, recomenda-se NOT EXISTS ou LEFT JOIN ... IS NULL. Na maioria dos casos, o planner trata IN e EXISTS de forma equivalente, como um semi-join.","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":"O MySQL/MariaDB suportam EXISTS/IN/NOT EXISTS. Antes do MySQL 5.6, subconsultas correlacionadas podiam ser lentas; o 5.6+ acelerou as subconsultas IN com otimizações de semi-join e materialização. A armadilha NOT IN + NULL também se aplica aqui.","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":"O SQL Server suporta EXISTS/IN/NOT EXISTS, e o otimizador geralmente os processa como semi/anti-joins. Se uma subconsulta NOT IN contiver NULL, o resultado pode ficar inesperadamente vazio; NOT EXISTS é a escolha segura. INTERSECT/EXCEPT também podem ser usados para lógica de pertinência semelhante.","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":"No MongoDB, a pertinência a uma lista de valores é feita com os operadores $in / $nin. O equivalente a um EXISTS de subconsulta é obter o array de documentos correspondentes com $lookup e filtrar se o array está vazio. Verificar a existência de um campo é um operador separado, { field: { $exists: true } } (presença de um campo, não uma relação entre linhas).","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":"O Redis não tem subconsultas. Para pertinência de valores, use SISMEMBER em um Set (semelhante a IN). O comando EXISTS não é uma subconsulta; ele retorna se a chave informada existe. Verificações de existência relacionais são feitas no lado da aplicação lendo várias chaves.","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":"No Elasticsearch, o equivalente a IN é a consulta 'terms' (corresponde a um entre vários valores), e NOT IN é terms dentro de bool must_not. A consulta 'exists' não corresponde ao EXISTS do SQL; ela verifica se um campo tem valor no documento. Um EXISTS correlacionado entre tabelas geralmente exige desnormalização.","danger":"safe"}}},{"id":"limit-paging","title":"Limitação de linhas / paginação (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":"Usado para limitar/paginar um conjunto de resultados. Desde o Oracle 12c, o padrão OFFSET n ROWS FETCH NEXT m ROWS ONLY é suportado. Antes disso, usava-se a pseudocoluna ROWNUM; como o ROWNUM é atribuído antes da ordenação, é obrigatório envolver uma subconsulta com ORDER BY.","since":"Oracle 12c","xnote":"Antes do Oracle 12c, a limitação de linhas era feita com 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":"O PostgreSQL suporta tanto LIMIT n OFFSET m quanto a forma padrão OFFSET ... FETCH. Valores grandes de OFFSET são lentos; para paginação profunda, a paginação baseada em chave (keyset / 'WHERE id > last_id') é mais eficiente. LIMIT sem ORDER BY não garante a ordem do resultado.","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":"O MySQL/MariaDB usam a palavra-chave LIMIT de duas formas: LIMIT row_count OFFSET offset ou LIMIT offset, row_count. O MySQL 8.0.19+ também aceita a sintaxe FETCH padrão. Recomenda-se a paginação keyset para o desempenho com OFFSET profundo.","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":"O SQL Server usa TOP n (com as variantes TOP (n) PERCENT / WITH TIES) para as N primeiras linhas e, desde 2012, OFFSET ... FETCH para paginação. ORDER BY é obrigatório para OFFSET/FETCH funcionar. O SQL Server não tem a palavra-chave LIMIT.","since":"SQL Server 2012","xnote":"A paginação com OFFSET/FETCH chegou com o 2012; antes, era feita com TOP ou ROW_NUMBER.","danger":"safe"},"mongodb":{"command":"// Paging with skip/limit\ndb.employee.find()\n  .sort({ salary: -1 })\n  .skip(20)\n  .limit(10)","note":"No MongoDB, limit() define o número de documentos retornados e skip() o número de documentos pulados; combinados com sort(), fornecem paginação. Valores grandes de skip são caros; para paginação profunda, prefere-se uma consulta por intervalo (keyset) baseada no último valor visto.","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":"O Redis não tem LIMIT do SQL, mas tem comandos de leitura por intervalo: ZRANGE/ZREVRANGE start stop (baseado em índice) ou ZRANGEBYSCORE ... LIMIT offset count para Sorted Sets; LRANGE para Lists. Esses comandos fornecem acesso semelhante a paginação.","danger":"safe"},"elasticsearch":{"command":"GET employee/_search\n{\n  \"from\": 20,\n  \"size\": 10,\n  \"sort\": [ { \"salary\": \"desc\" } ]\n}","note":"No Elasticsearch, 'size' define o número de hits retornados e 'from' o número de hits pulados (o equivalente a LIMIT/OFFSET). from+size pode ser no máximo index.max_result_window (padrão 10.000); para paginação profunda, use 'search_after' (keyset) ou um PIT (point-in-time).","danger":"safe"}}},{"id":"merge-upsert","title":"MERGE / UPSERT (atualizar se existir, senão inserir)","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":"O MERGE (upsert) compara uma origem com um destino, atualizando as linhas correspondentes e inserindo as não correspondentes; ideal para sincronização de dados em massa. O Oracle tem um suporte robusto a MERGE: também é possível escrever WHEN MATCHED ... DELETE e atualizações condicionais. Para uma origem de linha única, usa-se a tabela 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":"O upsert clássico do PostgreSQL é INSERT ... ON CONFLICT (coluna única) DO UPDATE / DO NOTHING; os novos valores da linha em conflito são acessados pelo alias EXCLUDED. Desde o PostgreSQL 15, a instrução MERGE padrão também é suportada. ON CONFLICT é atômico em uma única tabela e muito usado.","since":"PostgreSQL 15","xnote":"A instrução MERGE padrão chegou com o PostgreSQL 15; antes, os upserts eram feitos com INSERT ... ON CONFLICT (9.5).","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":"O MySQL/MariaDB usam INSERT ... ON DUPLICATE KEY UPDATE para upserts; se uma chave única ou primária entrar em conflito, a linha é atualizada. Os novos valores são acessados com VALUES(my_column) (ou o alias de linha 'new.my_column' no 8.0.19+). INSERT IGNORE pula a linha silenciosamente em caso de conflito. O MySQL não tem MERGE padrão.","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":"O SQL Server suporta a instrução MERGE desde 2008; ela oferece ramos extras, como WHEN NOT MATCHED BY SOURCE, para excluir linhas excedentes no destino. Uma instrução MERGE deve terminar com ponto e vírgula. Observação: devido a alguns bugs em casos extremos, pode ser preferível escrever instruções INSERT/UPDATE separadas para upserts simples.","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":"No MongoDB, o upsert é uma opção nativa: se { upsert: true } for adicionado a updateOne/updateMany/findOneAndUpdate, um documento correspondente é atualizado; caso contrário, um novo documento é criado. Para sincronização em massa, o estágio de agregação $merge (gravar/atualizar em uma coleção de destino) é mais próximo do MERGE do SQL.","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":"No Redis, os comandos de escrita são intrinsecamente upserts: SET/HSET atualizam a chave ou o campo se existir; caso contrário, o criam. Use a opção SET ... NX para gravar apenas se não existir, e XX apenas se existir. A distinção 'atualizar se existir, senão inserir' já é o comportamento padrão da maioria dos comandos.","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":"No Elasticsearch, uma chamada index (PUT) com o mesmo _id substitui totalmente o documento se ele existir; caso contrário, o cria (semelhante a upsert). Para atualizações parciais com inserção se não existir, use 'doc_as_upsert': true ou um bloco 'upsert' na API _update. Upserts com script também são possíveis.","danger":"caution"}}},{"id":"returning-output","title":"Retornar a linha modificada (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 retorna os valores das linhas alteradas por INSERT/UPDATE/DELETE (ex.: um ID gerado automaticamente) sem um SELECT separado. No Oracle, uma única linha é retornada com RETURNING ... INTO uma bind variable, e várias linhas com RETURNING ... BULK COLLECT INTO uma coleção.","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":"A cláusula RETURNING do PostgreSQL é muito flexível: retorna diretamente como conjunto de resultados qualquer coluna (incluindo expressões calculadas) das linhas afetadas por instruções INSERT, UPDATE, DELETE e MERGE. É a forma mais limpa de obter valores serial/identity gerados.","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":"O MySQL não suporta o RETURNING padrão; a chave auto-incremento gerada por um INSERT é obtida com LAST_INSERT_ID(), e os valores atualizados são lidos com um SELECT separado. O MariaDB oferece INSERT ... RETURNING desde o 10.5 e DELETE ... RETURNING desde o 10.0.","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":"O equivalente no SQL Server é a cláusula OUTPUT: ela acessa as pseudotabelas INSERTED (novos valores) e DELETED (valores antigos); ambas podem ser usadas em um UPDATE. Com OUTPUT ... INTO, os resultados podem ser gravados em uma tabela/variável de tabela. Ideal para copiar as alterações para uma tabela de auditoria.","since":"SQL Server 2005","xnote":"A cláusula OUTPUT chegou com o 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":"No MongoDB, os comandos findOneAndUpdate / findOneAndDelete / findOneAndReplace retornam o documento afetado em uma única operação atômica. returnDocument: 'before' fornece a versão anterior à alteração; 'after', a versão posterior. insertOne retorna o _id do documento inserido.","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":"O Redis não tem um RETURNING separado, mas muitos comandos de escrita retornam o resultado diretamente: INCR/INCRBY retornam o novo valor, SET ... GET o valor antigo (GETSET está obsoleto desde o 6.2), e LPOP/RPOP o elemento removido. Para leitura-escrita atômica, esse comportamento substitui o 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":"No Elasticsearch, as operações index/update retornam metadados do resultado (_id, _version, result). Para obter o corpo do documento atualizado, adicione '_source': true à requisição _update; o campo get da resposta contém o _source atual. Não é necessária uma chamada GET separada.","danger":"safe"}}},{"id":"lateral-apply","title":"LATERAL / CROSS APPLY (subconsulta linha a linha)","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 permite que uma subconsulta no FROM referencie colunas da tabela à sua esquerda, possibilitando joins correlacionados como 'as N primeiras linhas para cada linha'. O Oracle 12c suporta tanto a sintaxe ANSI LATERAL quanto CROSS/OUTER APPLY.","since":"Oracle 12c","xnote":"LATERAL e CROSS/OUTER APPLY chegaram com o 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":"No PostgreSQL, subconsultas que dependem da linha à esquerda são escritas com a palavra-chave LATERAL (JOIN LATERAL / CROSS JOIN LATERAL / LEFT JOIN LATERAL). Muito útil para 'top N por grupo' e para expandir linhas com funções que retornam conjuntos. Não há sintaxe CROSS APPLY; usa-se LATERAL.","since":"PostgreSQL 9.3","xnote":"LATERAL chegou com o 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":"Desde o MySQL 8.0.14, LATERAL derived tables são suportadas; a subconsulta pode referenciar colunas da tabela externa. Antes disso, e para CROSS APPLY, não havia equivalente; 'top N por grupo' era resolvido com funções de janela ou subconsultas correlacionadas. O MariaDB ainda não tem LATERAL.","since":"MySQL 8.0.14","xnote":"As LATERAL derived tables chegaram com o MySQL 8.0.14; o MariaDB não as tem.","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":"O equivalente a LATERAL no SQL Server é o operador APPLY: CROSS APPLY (como INNER JOIN LATERAL, descarta as não correspondências) e OUTER APPLY (como LEFT JOIN LATERAL, NULL para as não correspondências). Comum para chamar table-valued functions para cada linha e para consultas top-N-por-grupo.","since":"SQL Server 2005","xnote":"O operador CROSS/OUTER APPLY chegou com o 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":"No MongoDB, o equivalente a LATERAL/APPLY é a forma do $lookup com sub-pipeline e variáveis let: os campos do documento externo são passados ao sub-pipeline via let como $$variable, onde ocorrem a correspondência/ordenação/limitação. Isso resolve o padrão 'top N relacionados para cada documento'.","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no subqueries / LATERAL.","note":"O Redis não oferece subconsultas correlacionadas linha a linha. O padrão 'top N relacionados para cada item' é resolvido com um loop no lado da aplicação (ex.: um ZRANGE separado por chave) ou com um script Lua no lado do servidor.","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":"O Elasticsearch não tem LATERAL/APPLY; o padrão 'top N registros por grupo' é obtido com uma sub-agregação top_hits aninhada dentro de uma terms aggregation. Em vez de uma subconsulta correlacionada, trata-se de agrupamento mais amostragem dentro do grupo em um único índice.","danger":"safe"}}},{"id":"pivot","title":"PIVOT / UNPIVOT (linhas↔colunas)","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 transforma valores distintos das linhas em colunas (uma tabela cruzada), e UNPIVOT transforma colunas de volta em linhas; usados em tabelas de resumo/relatório. O Oracle oferece os operadores PIVOT/UNPIVOT nativos desde o 11g; a lista de colunas deve ser estática (colunas dinâmicas exigem PIVOT XML ou código).","since":"Oracle 11g","xnote":"Os operadores PIVOT/UNPIVOT nativos chegaram com o 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":"O PostgreSQL não tem operador PIVOT nativo. Há duas formas: a função crosstab() da extensão tablefunc ou a agregação condicional portável (SUM(...) FILTER (WHERE ...) ou com CASE). A cláusula FILTER é uma técnica de pivot elegante, específica do 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":"O MySQL/MariaDB não têm operador PIVOT/UNPIVOT; uma tabela cruzada é montada manualmente com GROUP BY mais um SUM(CASE WHEN ... THEN ... END) para cada coluna de destino. Se as colunas forem dinâmicas, a consulta é gerada como string com um prepared statement.","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":"O SQL Server suporta nativamente os operadores PIVOT e UNPIVOT desde 2005. A lista de colunas do PIVOT é informada como valores estáticos entre colchetes; para colunas dinâmicas, a consulta é montada com SQL dinâmico. Para resumos pequenos, a agregação condicional (CASE) é uma alternativa.","since":"SQL Server 2005","xnote":"Os operadores PIVOT/UNPIVOT chegaram com o 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":"O MongoDB não tem operador PIVOT; uma tabela cruzada é montada no estágio $group com $sum + $cond (agregação condicional) para cada coluna de destino. Para o sentido inverso (UNPIVOT), os campos são expandidos em linhas com $objectToArray e $unwind.","danger":"safe"},"redis":{"command":"# Not applicable: Redis has no pivot/cross tab.","note":"O Redis não tem o conceito de girar linhas e colunas. Resumos/tabelas cruzadas são calculados no lado da aplicação; resumos solicitados com frequência podem ser pré-calculados e armazenados em campos de Hash (um campo por coluna). O FT.AGGREGATE do RediSearch pode fazer agregação agrupada, mas não é um pivot real.","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":"O Elasticsearch não tem operador PIVOT; um resumo cruzado é montado com terms aggregations aninhadas (chave externa / chave interna), o resultado volta como buckets aninhados em vez de colunas e é transformado em tabela no cliente. Um job de transform pode gerar um índice de destino agrupado, semelhante a um pivot.","danger":"safe"}}},{"id":"coalesce-null","title":"Tratamento de 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":"Para tratar NULL (valor desconhecido): COALESCE retorna o primeiro valor não NULL da lista (padrão, vários argumentos). O NVL(a,b) do Oracle é o equivalente de dois argumentos; NVL2 retorna valores diferentes conforme o valor seja NULL ou não. NULLIF(a,b) retorna NULL se forem iguais. Sempre teste NULL com IS NULL / IS NOT NULL (= NULL não funciona).","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":"O PostgreSQL oferece COALESCE, NULLIF e IS NULL/IS NOT NULL padrão; use COALESCE em vez do NVL do Oracle. Use IS, e não =, em comparações com NULL; se dois NULLs precisarem ser tratados como iguais, o operador 'IS NOT DISTINCT FROM' resolve.","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":"O MySQL/MariaDB suportam COALESCE e NULLIF padrão; IFNULL(a,b) é um atalho de dois argumentos (semelhante ao NVL do Oracle). O operador <=> fornece igualdade segura para NULL (trata dois NULLs como iguais). NULL é testado com 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":"O SQL Server oferece o COALESCE padrão (vários argumentos, com promoção de tipo de dado) e o ISNULL(a,b) de dois argumentos; os dois diferem em detalhes sutis (COALESCE é padrão e mais flexível quanto à precedência de tipos). NULLIF e IS NULL também são suportados. ISNULL é o equivalente ao NVL do Oracle (os nomes são parecidos).","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":"Na agregação do MongoDB, o equivalente ao COALESCE é o operador $ifNull (vários argumentos, retorna o primeiro que não seja null/ausente). Em uma consulta, { field: null } corresponde tanto aos documentos cujo valor é null quanto aos que não têm o campo; explicite a distinção com { field: { $type: 'null' } } ou $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":"O Redis não tem NULL no sentido do SQL; o equivalente é uma chave ou um campo de Hash ausente, e os comandos retornam nil nesse caso. A lógica de valor padrão (como COALESCE) é aplicada no lado da aplicação com uma verificação de nil. A existência de um campo é verificada com 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":"No Elasticsearch, campos null ou ausentes são verificados com a consulta 'exists' (must_not exists = documentos sem o campo). Para um padrão semelhante a COALESCE, defina 'null_value' no mapping ou atribua um valor às entradas ausentes com o parâmetro 'missing' nas agregações. Valores padrão também podem ser gerados com runtime fields/scripts.","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":"A Task API retorna as tarefas em execução no momento (search, reindex, bulk). Para a carga de CPU momentânea, hot_threads mostra as threads mais ativas.","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":"Em vez de bloqueio, a lentidão geralmente vem de tarefas de longa duração (buscas grandes, reindex). Avalie a duração com o campo 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":"Pegue o valor de task_id na saída de GET _tasks. Apenas tarefas canceláveis (cancellable:true) podem ser interrompidas.","danger":"danger"},"connection-count":{"command":"GET _nodes/stats/http","note":"current_open fornece as conexões HTTP abertas no momento; total_opened, o total de conexões desde o início do nó. O limite superior de conexões HTTP é determinado pelos limites do sistema operacional/sockets, não por http.max_content_length.","danger":"safe"},"database-size":{"command":"GET _cluster/stats\n# For a simple summary: GET _cat/indices?v&h=index,store.size","note":"_cluster/stats fornece o uso total de disco de todo o cluster via indices.store.size_in_bytes. _cat/indices lista o tamanho por índice em formato legível.","danger":"safe"},"largest-tables":{"command":"GET _cat/indices?v&s=store.size:desc&h=index,docs.count,store.size","note":"No Elasticsearch, o equivalente a uma \"tabela\" é um índice. s=store.size:desc coloca os maiores índices no topo.","danger":"safe"},"free-space":{"command":"GET _cat/allocation?v","note":"As colunas disk.used, disk.avail e disk.percent fornecem o uso de disco por nó. Quando os limites de watermark (85%/90%/95%) são ultrapassados, a alocação de shards para.","danger":"safe"},"row-count":{"command":"GET <index>/_count\n# Shortcut: GET _cat/count/<index>?v","note":"_count retorna a contagem de documentos rapidamente. Para uma contagem filtrada, passe uma consulta no corpo: 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":"O Elasticsearch não tem uma tabela central de consultas lentas; o search slowlog grava nos arquivos de log do nó as consultas que excedem o limite. Leia os logs ali.","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 detalha o tempo de cada componente da consulta e de cada etapa de agregação. _validate/consulta?explain mostra o equivalente Lucene da consulta e por que ela foi rejeitada.","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":"Em vez de índices de campos não utilizados, identifique via _stats/search os índices com baixa contagem de buscas (search.query_total) ou que não são mais consultados, e feche-os/exclua-os.","danger":"safe"},"cache-hit-ratio":{"command":"GET _nodes/stats/indices/query_cache\n# Ratio = hit_count / (hit_count + miss_count)","note":"query_cache armazena em cache os resultados em filter context. Examine o request_cache separadamente com 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":"No Elasticsearch, o equivalente a um dump lógico é a snapshot API. wait_for_completion=true aguarda até a operação terminar; para snapshots grandes, deixe false e consulte o status separadamente.","danger":"safe"},"restore-dump":{"command":"POST _snapshot/<repo>/<snapshot_1>/_restore\n{\n  \"indices\": \"*\",\n  \"rename_pattern\": \"(.+)\",\n  \"rename_replacement\": \"restored_$1\"\n}","note":"Para restaurar um índice existente, feche-o antes (POST <index>/_close) ou restaure com um novo nome usando rename_pattern. Não é possível restaurar sobre um índice aberto.","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":"O campo state assume os valores SUCCESS / IN_PROGRESS / PARTIAL / FAILED. _status fornece o progresso detalhado por shard.","danger":"safe"},"list-users":{"command":"GET _security/user","note":"O X-Pack Security deve estar habilitado. Para um único usuário: GET _security/user/<user>. Os usuários nativos também aparecem na lista.","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":"A autorização é baseada em roles: primeiro defina a role com os privilégios de índice/cluster e depois atribua-a ao usuário. A senha deve ter pelo menos 6 caracteres.","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":"Veja as roles de um usuário com _security/user e os privilégios que uma role contém com _security/role. _has_privileges verifica se uma ação específica é permitida.","danger":"safe"},"change-password":{"command":"POST _security/user/<user>/_password\n{\n  \"password\": \"NewStrongPassword123\"\n}","note":"Para alterar sua própria senha, basta POST _security/user/_password (sem nome de usuário). Para o usuário nativo elastic, também se pode usar a ferramenta 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":"O Lucene é baseado em segmentos; não é necessária uma etapa separada de atualização de estatísticas. _refresh torna pesquisáveis imediatamente os documentos ainda não pesquisáveis (por padrão, isso acontece automaticamente a cada 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":"O reindex é usado para alterações de mapping ou para reconstruir um índice corrompido. Para uma troca transparente, aponte um alias para o novo índice.","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":"Documentos excluídos/atualizados permanecem nos segmentos como tombstones; o forcemerge recupera esse espaço. É caro em índices com escrita ativa; execute fora do horário de pico.","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":"O endpoint raiz GET / retorna a versão, a versão do Lucene e o nome do cluster. jvm.uptime_in_millis é o uptime do nó.","danger":"safe"},"show-config-param":{"command":"GET _cluster/settings?include_defaults=true&flat_settings=true","note":"include_defaults=true também mostra os valores padrão. As configurações persistent e transient são retornadas em seções separadas; para configurações em nível de nó, use GET _nodes/settings.","danger":"safe"},"list-tables":{"command":"GET _cat/indices?v","note":"No Elasticsearch, o equivalente a uma tabela relacional é um índice. Fornece um resumo com as colunas health, status, docs.count e store.size. A saída padrão lista os índices abertos e fechados, mas não os ocultos (ex.: backing indices .ds-, índices de sistema); adicione &expand_wildcards=all para incluí-los, ou &expand_wildcards=open para apenas os abertos.","danger":"safe"},"describe-table":{"command":"GET <index>/_mapping","note":"O mapping fornece os tipos de campo e as configurações de análise; é o equivalente ao DESCRIBE TABLE. Para um único campo: GET <index>/_mapping/field/<field>.","danger":"safe"},"list-indexes":{"command":"GET <index>/_mapping","note":"No ES, os campos são indexados por padrão; não há uma tabela separada de índices secundários. Campos com \"index\": false no mapping não são pesquisáveis. Para os índices (tabelas) de todo o cluster: 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":"Depois que um índice é criado, o número de primary shards não pode ser alterado no lugar (o número de réplicas é dinâmico); se necessário, gere um novo índice com as APIs _split / _shrink ou com _reindex. O tipo de um campo existente não pode ser alterado; novos campos podem ser adicionados.","danger":"caution"},"show-ddl":{"command":"GET <index>","note":"Uma única chamada retorna settings, mappings e aliases; juntos, esses três são o equivalente ao \"DDL\" do índice. Você pode reutilizar a mesma saída como corpo de um novo 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 resume a saúde dos shards como green/yellow/red; yellow = réplica não alocada. active_shards_percent fornece a taxa de conclusão.","danger":"safe"},"list-replicas":{"command":"GET _cat/shards?v&h=index,shard,prirep,state,node\n# For node roles: GET _cat/nodes?v","note":"A coluna prirep assume o valor p (primary) ou r (replica); mostra como os shards estão distribuídos entre os nós e seu estado (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":"Em caso de falha de um nó, o Elasticsearch reelege o master automaticamente e reatribui os primary shards. A tomada manual só é necessária para desvincular um follower index do CCR de seu leader e torná-lo gravável.","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":"Uma escrita em um único documento é atômica e versionada (concorrência otimista: if_seq_no / if_primary_term). Não existe o conceito de rastreamento de transações abertas.","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":"É baseado em REST; em vez de um cliente CLI separado, usa-se curl ou o Kibana Dev Tools. -k pula a verificação de certificados TLS autoassinados (use uma CA em produção).","danger":"safe"},"list-databases":{"command":"GET _cat/indices?v\n# For aliases (logical views): GET _aliases","note":"O Elasticsearch não tem uma camada separada de \"banco de dados\"; os conceitos mais próximos são os índices e os aliases que os agrupam. Para data streams: 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":"Não há um comando no estilo USE <db>; o índice/alias de destino é informado no caminho de cada requisição. Para pesquisar vários índices, separe-os com vírgulas: 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":"Uma linha inserida ou atualizada viola uma constraint UNIQUE ou PRIMARY KEY. Em outras palavras, o mesmo valor já existe.","cause":"Reinserção de uma linha com o mesmo valor de chave, entrada de dados duplicados em uma coluna que deve ser única, ou processamento do mesmo registro duas vezes durante replicação/reexecuções.","fix":"Encontre a coluna violada a partir do nome da constraint na mensagem de erro: SELECT column_name FROM all_cons_columns WHERE constraint_name = 'CONSTRAINT_NAME'. Use GROUP BY ... HAVING COUNT(*) > 1 para encontrar dados duplicados. Na aplicação, use UPDATE ou MERGE em vez de INSERT para registros existentes. Se o valor da sequence ficou para trás, avance-o com 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","severity":"caution","meaning":"O recurso (linha ou tabela) a ser bloqueado está bloqueado por outra sessão e não pôde ser adquirido imediatamente porque NOWAIT foi especificado ou o DDL_LOCK_TIMEOUT expirou.","cause":"Geralmente um DDL (ALTER TABLE, DROP, CREATE INDEX) tentado enquanto a tabela está bloqueada por outra transação; ou uma linha bloqueada encontrada com SELECT ... FOR UPDATE NOWAIT.","fix":"Encontre a sessão que mantém o lock: SELECT * FROM v$locked_object. Faça join de v$session e v$lock para identificar a sessão bloqueadora. Aguarde a transação terminar ou, se necessário, encerre-a com ALTER SYSTEM KILL SESSION. Para DDL, você pode definir um tempo de espera: ALTER SESSION SET DDL_LOCK_TIMEOUT = 60; Execute DDL em janelas de manutenção tranquilas.","tags":["lock","locked","ddl","nowait","busy","resource busy","timeout"]},{"code":"ORA-00060","title":"Deadlock detected while waiting for resource","severity":"danger","meaning":"Duas ou mais sessões estão em deadlock, cada uma aguardando um recurso mantido pela outra. O Oracle detecta o ciclo, escolhe uma vítima e faz rollback da instrução dessa sessão.","cause":"Locks de linha adquiridos em ordens diferentes, as mesmas linhas atualizadas de forma cruzada por transações diferentes, locks de tabela em atualizações da tabela pai causados por foreign keys sem índice, ou DML concorrente em um índice bitmap.","fix":"Examine o arquivo de trace do deadlock (grafo) referenciado no alert log para encontrar as instruções SQL e as linhas em conflito. Na aplicação, sempre acesse tabelas/linhas na mesma ordem. Indexe as colunas de foreign key (FKs sem índice são uma causa clássica de deadlock). Mantenha as transações curtas e revise a frequência de commit. Capture a transação em deadlock na aplicação e tente novamente.","tags":["deadlock","deadlock detected","lock","locking","tx","transaction"]},{"code":"ORA-01017","title":"Invalid username/password; logon denied","severity":"caution","meaning":"O logon foi negado porque o nome de usuário ou a senha fornecidos ao conectar ao banco de dados estão incorretos.","cause":"Senha errada, nome de usuário errado, a configuração de senha sensível a maiúsculas/minúsculas (SEC_CASE_SENSITIVE_LOGON) diferente do esperado, uma senha alterada, ou credenciais desatualizadas na connection string da aplicação.","fix":"Verifique o nome de usuário e a senha. Se necessário, redefina a senha como DBA: ALTER USER app_user IDENTIFIED BY new_password. Verifique se o usuário existe e não está bloqueado: SELECT username, account_status FROM dba_users. Com as versões de hash de senha do 12c+, clientes 11g podem ter problemas para conectar; revise a configuração 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":"Uma consulta de longa duração não conseguiu acessar os dados de undo antigos necessários para montar a imagem de leitura consistente referente ao seu momento de início, porque essas informações de undo foram sobrescritas.","cause":"Undo tablespace pequeno, UNDO_RETENTION curto, consultas de longa duração durante DML concorrente muito intenso, ou um loop que faz commit na mesma tabela dentro de uma consulta (fetch across commit).","fix":"Aumente o UNDO_RETENTION e amplie o undo tablespace; sempre que possível, deixe-o sob gerenciamento automático (AUTOEXTEND ativado). Divida consultas longas em partes menores ou execute-as fora do horário de pico. Considere RETENTION GUARANTEE: ALTER TABLESPACE undotbs1 RETENTION GUARANTEE. Corrija a lógica da aplicação que faz commit dentro de um loop.","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":"O Oracle não encontrou espaço livre suficiente no tablespace para estender um segmento temporário (temp). Geralmente ocorre durante ordenações, hash joins ou operações com global temporary tables.","cause":"O tablespace TEMP está cheio; operações grandes de ORDER BY, GROUP BY, DISTINCT, hash join ou criação de índice não cabem na memória PGA e transbordam para o disco; datafiles estão com AUTOEXTEND desativado, ou o espaço em disco se esgota.","fix":"Monitore o uso do TEMP: SELECT * FROM v$sort_usage / v$tempseg_usage. Adicione um arquivo ao tablespace TEMP ou amplie-o: ALTER TABLESPACE temp ADD TEMPFILE '...' SIZE 2G AUTOEXTEND ON. Se um tablespace permanente estiver cheio, adicione um datafile. Reduza as ordenações em disco otimizando a consulta (índice adequado, PGA_AGGREGATE_TARGET maior).","tags":["temp","tablespace","free space","space","sort","sorting","extend"]},{"code":"ORA-04031","title":"Unable to allocate N bytes of shared memory","severity":"danger","meaning":"O Oracle não conseguiu alocar memória contígua do tamanho solicitado em um pool de memória compartilhada (geralmente o shared pool ou o large pool). Um componente da SGA está sob pressão de memória.","cause":"Fragmentação do shared pool devido a muitas instruções SQL únicas sem bind variables (cheias de literais), SHARED_POOL_SIZE insuficiente, conexões concorrentes demais, pacotes PL/SQL grandes, ou dimensionamento incorreto de ASMM/AMM.","fix":"Verifique a qual pool a mensagem de erro se refere (shared pool, large pool etc.). Curto prazo: ALTER SYSTEM FLUSH SHARED_POOL (cuidado: em produção isso força o re-parse de todo o SQL, ou seja, uma tempestade temporária de hard parse, e não corrige a fragmentação de forma permanente). Correção permanente: imponha o uso de bind variables (incluindo CURSOR_SHARING), aumente SGA_TARGET / SHARED_POOL_SIZE / LARGE_POOL_SIZE. Fixe na memória os pacotes usados com frequência com DBMS_SHARED_POOL.KEEP. Examine a distribuição de memória com 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":"O nome de serviço (connect identifier / alias TNS) usado na conexão não pôde ser resolvido. O Oracle Net não consegue mapear o nome informado para as informações de servidor/serviço.","cause":"O alias não existe no tnsnames.ora, a variável de ambiente TNS_ADMIN aponta para o diretório errado, o nome do alias está grafado incorretamente, falta a configuração de nomenclatura EZConnect/LDAP, ou a ordem de NAMES.DIRECTORY_PATH no sqlnet.ora está errada.","fix":"Verifique se o alias usado está definido no tnsnames.ora. Teste a conexão: tnsping service_name. Certifique-se de que TNS_ADMIN aponta para a pasta correta. Como alternativa, tente o EZConnect: app_user/password@host:1521/service_name. Verifique a linha NAMES.DIRECTORY_PATH = (TNSNAMES, EZCONNECT) no sqlnet.ora.","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":"O listener está em execução, mas não reconhece o nome de serviço solicitado; ou seja, o serviço não está registrado no listener.","cause":"A instância do banco de dados não está totalmente aberta, o serviço ainda não se registrou no listener (LREG no 12c+, atraso no registro pelo PMON no 11g e anteriores), o SERVICE_NAME errado é usado, ou há confusão entre SID e nome de serviço.","fix":"Veja os serviços conhecidos pelo listener: lsnrctl status e lsnrctl services. Verifique se o banco de dados está OPEN. Force o registro do serviço: ALTER SYSTEM REGISTER no SQL. Verifique o parâmetro LOCAL_LISTENER e o uso correto de SERVICE_NAME. Em um pluggable database, certifique-se de que o PDB está OPEN.","tags":["tns","listener","service","service_name","connection","network","networking"]},{"code":"ORA-00942","title":"Table or view does not exist","severity":"caution","meaning":"A tabela ou view referenciada na consulta não existe ou não é visível para o usuário que a acessa.","cause":"O objeto realmente não existe, está em outro schema e nenhum prefixo de schema foi informado, o usuário não tem privilégios sobre o objeto (como SELECT), falta um sinônimo, ou o nome do objeto está grafado incorretamente.","fix":"Verifique se o objeto existe e quem é o dono: SELECT owner, object_type FROM all_objects WHERE object_name = 'TABLE_NAME'. Se estiver em outro schema, qualifique-o por completo como schema.table ou conceda GRANT SELECT ON app_schema.my_table TO app_user. Se necessário, crie um sinônimo público/privado: CREATE SYNONYM my_table FOR app_schema.my_table. Atenção a maiúsculas/minúsculas e identificadores entre aspas.","tags":["table","missing table","view","missing view","grant","privilege","synonym","alias"]},{"code":"ORA-01031","title":"Insufficient privileges","severity":"caution","meaning":"O usuário não tem o privilégio (de sistema ou de objeto) necessário para a operação que está tentando executar.","cause":"O privilégio de sistema ou de objeto necessário não foi concedido, o privilégio vem apenas por meio de uma role (roles não têm efeito dentro de blocos PL/SQL com definer rights), uma operação administrativa foi tentada sem SYSDBA/SYSOPER, ou falta um grant direto para procedures com definer rights.","fix":"Conceda o privilégio que falta, por exemplo: GRANT CREATE TABLE TO app_user ou GRANT SELECT ON app_schema.my_table TO app_user. Lembre-se de que, para objetos PL/SQL nomeados, os privilégios devem ser concedidos diretamente, não por meio de uma role. Para operações que exigem SYSDBA, conecte-se com as credenciais corretas. Verifique os privilégios atuais: 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":"O processo archiver (ARCH) não consegue arquivar os redo logs; geralmente o destino de arquivamento (FRA ou destino dos archive logs) está cheio. O banco de dados suspende novas transações.","cause":"A Flash Recovery Area (DB_RECOVERY_FILE_DEST) ou o destino dos archive logs está cheio, o espaço em disco se esgotou, os backups RMAN não estão excluindo os archive logs, ou o limite DB_RECOVERY_FILE_DEST_SIZE foi atingido.","fix":"Libere espaço: faça backup dos archive logs antigos com RMAN para um destino fora da FRA e exclua-os: RMAN> BACKUP ARCHIVELOG ALL FORMAT '/backup/arc_%U' DELETE INPUT (gravar o backup na FRA enquanto ela está cheia falha). Com Data Guard, não exclua archives ainda não enviados ao standby ou não aplicados nele; caso contrário, forma-se um gap no standby (CONFIGURE ARCHIVELOG DELETION POLICY TO APPLIED ON ALL STANDBY). Veja o uso da FRA: SELECT * FROM v$recovery_file_dest / v$flash_recovery_area_usage. Aumente temporariamente DB_RECOVERY_FILE_DEST_SIZE ou mova o destino para um disco maior. Verifique o espaço livre no nível do disco. Estabeleça uma política regular de limpeza de archives.","tags":["archive","archivelog","archiver","fra","disk","space","redo"]},{"code":"ORA-01000","title":"Maximum open cursors exceeded","severity":"caution","meaning":"Uma sessão abriu mais cursores do que o permitido pelo parâmetro OPEN_CURSORS. Nenhum cursor novo pode ser aberto.","cause":"A aplicação não fecha os objetos Statement/ResultSet que abre (vazamento de cursores), OPEN_CURSORS está definido baixo demais para a carga de trabalho, ou novos prepared statements são preparados continuamente em um loop e nunca fechados.","fix":"Monitore os cursores abertos: SELECT * FROM v$open_cursor WHERE sid = ...  e veja a contagem por sessão via v$sesstat. A correção real é fechar todo Statement/ResultSet em um bloco finally na aplicação (eliminando o vazamento de cursores). Como contorno, aumente OPEN_CURSORS: ALTER SYSTEM SET OPEN_CURSORS = 1000. Revise o tamanho do statement cache do JDBC.","tags":["cursor","open cursor","open_cursors","leak","cursor leak","jdbc"]},{"code":"ORA-00018","title":"Maximum number of sessions exceeded","severity":"danger","meaning":"O banco de dados atingiu o número máximo de sessões permitido pelo parâmetro SESSIONS; nenhuma sessão nova pode ser aberta.","cause":"SESSIONS/PROCESSES definidos abaixo da necessidade da carga de trabalho, uma configuração de pool de conexões superdimensionada, vazamento de conexões, ou acúmulo de sessões que nunca são fechadas.","fix":"Veja a contagem atual de sessões: SELECT COUNT(*) FROM v$session. Verifique os limites: SELECT * FROM v$resource_limit WHERE resource_name IN ('sessions','processes'). Aumente PROCESSES e, indiretamente, SESSIONS (via SPFILE, requer reinicialização): ALTER SYSTEM SET PROCESSES = 500 SCOPE=SPFILE. Revise os tamanhos do pool de conexões e vazamentos na aplicação.","tags":["session","session limit","sessions","processes","connection","connections","limit"]},{"code":"ORA-28000","title":"The account is locked","severity":"caution","meaning":"O logon falha porque a conta de usuário do banco de dados à qual se está conectando está bloqueada.","cause":"O limite FAILED_LOGIN_ATTEMPTS do profile foi excedido (senhas erradas repetidas), ou a conta foi bloqueada manualmente por um DBA (ALTER USER ... ACCOUNT LOCK). Um bloqueio por falha de login é liberado automaticamente após PASSWORD_LOCK_TIME. Observação: a expiração por PASSWORD_LIFE_TIME não bloqueia a conta; a conta passa para EXPIRED / EXPIRED(GRACE) e retorna ORA-28001/ORA-28002.","fix":"Verifique o status da conta: SELECT username, account_status, lock_date FROM dba_users WHERE username = 'APP_USER'. Desbloqueie-a: ALTER USER app_user ACCOUNT UNLOCK. Para evitar recorrência, encontre a origem das falhas de login e, se necessário, revise FAILED_LOGIN_ATTEMPTS no profile. Se a senha expirou, atribua uma nova senha.","tags":["account","user account","locked","account locked","auth","password","profile"]},{"code":"ORA-01578","title":"Oracle data block corrupted (file #, block #)","severity":"danger","meaning":"Um bloco de dados no datafile especificado está corrompido; o Oracle informa que o bloco falhou na verificação de consistência (checksum). Trata-se de corrupção física.","cause":"Falha de disco/hardware, erros na camada de armazenamento, problemas no sistema operacional ou na controladora, blocos parcialmente gravados após uma queda de energia, ou um backup/restore corrompido.","fix":"Confirme a corrupção e sua extensão: RMAN> VALIDATE DATABASE / VALIDATE CHECK LOGICAL DATAFILE n; execute também o DBVERIFY (dbv) e verifique v$database_block_corruption. Se houver backup, recupere no nível de bloco: RMAN> RECOVER DATAFILE n BLOCK m; ou, para todos os blocos listados, RMAN> RECOVER CORRUPTION LIST; (o comando BLOCKRECOVER, mais antigo, está obsoleto desde o 11g). Se for um bloco de índice, reconstrua o índice. Sempre verifique a saúde do hardware/disco; a causa raiz geralmente é o armazenamento.","tags":["corruption","block corruption","block","corrupt block","datafile","rman","disk"]},{"code":"ORA-01722","title":"Invalid number","severity":"safe","meaning":"Uma cadeia de caracteres que não pode ser convertida em número foi usada onde é exigido um contexto numérico. Uma conversão implícita ou explícita falhou.","cause":"Comparação de uma coluna numérica com texto (por exemplo, WHERE num_col = 'ABC'), inserção de um valor contendo letras em um campo numérico, formato inadequado para TO_NUMBER, ou incompatibilidade de separador decimal/de milhar (vírgula vs ponto).","fix":"Encontre a expressão com a conversão que falha; geralmente uma condição WHERE ou um valor de INSERT. Garanta a compatibilidade de tipos em comparações texto/número e use conversão explícita quando necessário: TO_NUMBER(my_column) ou TO_CHAR para o lado texto. Impeça a entrada de valores não numéricos em colunas numéricas na camada da aplicação. Atenção à configuração 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":"Uma transação distribuída excedeu DISTRIBUTED_LOCK_TIMEOUT enquanto aguardava um lock no banco de dados remoto. A transação expirou.","cause":"Uma transação executada por um database link aguarda uma linha bloqueada no lado remoto; transações longas na sessão remota, latência de rede, ou locks conflitantes mantidos nas duas pontas.","fix":"Encontre e resolva o lock e a sessão bloqueadora no banco de dados remoto (v$lock, v$session). Mantenha as transações distribuídas curtas e adquira os locks necessários o mais tarde possível. Se necessário, aumente DISTRIBUTED_LOCK_TIMEOUT para a carga de trabalho (SPFILE, requer reinicialização). Para transações distribuídas in-doubt, examine a view DBA_2PC_PENDING e resolva-as manualmente se necessário.","tags":["distributed","distributed transaction","dblink","lock","lock wait","timeout","2pc"]},{"code":"enq: TX - row lock contention","title":"Espera: sessão bloqueada em um lock de linha mantido por outra transação","severity":"caution","meaning":"Uma sessão está aguardando a liberação de um lock de linha mantido por outra transação. Este é o evento de espera de lock clássico no nível da aplicação.","cause":"Transações concorrentes tentando atualizar a mesma linha, transações deixadas sem commit por muito tempo, locking amplo causado por foreign keys sem índice, ou concentração em uma chave sequencial (hot block).","fix":"Encontre as sessões bloqueadoras e bloqueadas: SELECT * FROM v$session WHERE blocking_session IS NOT NULL; e correlacione com v$lock. Se transações longas forem a causa raiz, revise a estratégia de commit. Indexe as colunas de foreign key. Repense o design (sequence, hash) para hot rows. Encerre a sessão bloqueadora quando necessário.","tags":["wait","wait event","enq","row lock","row lock wait","tx","contention","lock"]},{"code":"log file sync","title":"Espera: sessão aguardando o LGWR gravar o redo em disco no commit","severity":"caution","meaning":"Quando uma sessão faz COMMIT, ela aguarda o LGWR gravar (flush) os registros de redo nos arquivos de redo log. Se essa espera for alta, há latência de commit.","cause":"Discos de redo log lentos (alta latência de I/O), uma aplicação que faz commit com frequência excessiva (commit linha a linha), pressão de CPU no processo LGWR, ou volume de redo muito alto.","fix":"Meça o tempo médio de espera com AWR/Statspack. Mova os arquivos de redo log para discos rápidos e de baixa latência (SSD). Reduza a frequência desnecessária de commits na aplicação e agrupe as operações em lote. Se necessário, avalie as opções COMMIT_LOGGING/COMMIT_WAIT (commit_write) frente aos requisitos de negócio; ATENÇÃO: NOWAIT/BATCH reduzem a durabilidade, e transações que aparentam estar commitadas podem ser perdidas em um crash. Use-as apenas no nível de sessão ou de instrução para trabalhos em que a perda é tolerável; não as habilite para todo o sistema. Examine a latência do LGWR e do armazenamento em conjunto.","tags":["wait","wait event","log file sync","commit","lgwr","redo","latency"]},{"code":"db file sequential read","title":"Espera: leitura física de bloco único, tipicamente um acesso por índice ou tabela","severity":"caution","meaning":"Uma sessão aguarda a leitura de um único bloco do disco. Geralmente visto em acesso por índice ou leituras de bloco único por ROWID; normalmente um evento esperado.","cause":"Blocos que não estão no buffer cache sendo lidos do disco, uso de índice pouco seletivo ou errado, buffer cache insuficiente, ou uma camada de armazenamento lenta.","fix":"Se estiver alto, encontre as instruções SQL que mais fazem leituras (AWR Top SQL, v$sql). Melhore as consultas com índices adequados e caminhos de acesso corretos, e reduza nested loops desnecessários. Avalie o tamanho do buffer cache (DB_CACHE_SIZE). Verifique a latência de I/O do armazenamento. Este evento costuma ser normal; se estiver anormalmente alto, concentre-se em tuning de SQL.","tags":["wait","wait event","db file sequential read","io","disk io","index","index access","single block"]},{"code":"db file scattered read","title":"Espera: leitura física multibloco, tipicamente um full table scan ou index fast full scan","severity":"caution","meaning":"Uma sessão aguarda a leitura de vários blocos (multibloco) do disco. Geralmente ocorre durante um full table scan ou index fast full scan.","cause":"Full table scans por falta de um índice adequado, plano errado por estatísticas desatualizadas, varreduras de tabelas muito grandes, ou o caminho de acesso escolhido recaindo em uma varredura de tabela.","fix":"Identifique as instruções SQL que fazem full scans e adicione os índices necessários ou garanta que o índice existente seja usado. Atualize as estatísticas: DBMS_STATS.GATHER_TABLE_STATS. Se uma varredura grande for realmente necessária, considere parallel query ou particionamento. Revise DB_FILE_MULTIBLOCK_READ_COUNT e o throughput do armazenamento.","tags":["wait","wait event","db file scattered read","full scan","full table scan","io","disk io","multiblock"]},{"code":"buffer busy waits","title":"Espera: contenção por um buffer que já está sendo lido ou modificado por outra sessão","severity":"caution","meaning":"Uma sessão está aguardando para acessar um bloco de buffer que outra sessão está lendo ou modificando ao mesmo tempo. Trata-se de contenção de bloco em memória.","cause":"Concentração em hot blocks, contenção na borda direita de índices com chaves monotonicamente crescentes, freelists insuficientes/segmentos não ASSM, ou DML concorrente intenso no mesmo bloco.","fix":"Descubra qual segmento e qual classe de bloco são afetados (v$session, v$segment_statistics, ASH). Para hot blocks de índice, considere um índice reverse key ou particionado por hash. Use ASSM (Automatic Segment Space Management). Sob alta concorrência, aumente INITRANS/PCTFREE. Distribua o padrão de acesso da aplicação.","tags":["wait","wait event","buffer busy","hot block","hot blocks","contention","block contention"]},{"code":"gc buffer busy","title":"Espera (RAC): contenção por um bloco de cache fusion sendo transferido entre instâncias","severity":"caution","meaning":"Em um ambiente RAC, uma sessão está aguardando para acessar um bloco global que está sendo transferido via cache fusion de/para outra instância ou está mantido ocupado por essa instância.","cause":"Os mesmos hot blocks compartilhados entre nós do RAC (hot block entre instâncias), latência/gargalo no interconnect, contenção entre nós em índices com chaves sequenciais, ou distribuição desbalanceada da carga de trabalho.","fix":"Encontre os segmentos afetados com v$segment_statistics e as views GV$. Verifique a saúde e a latência do interconnect (rede privada e rápida). Use reverse key ou particionamento por hash para índices quentes. Reduza a contenção entre nós nos mesmos blocos separando a carga de trabalho entre os nós por serviço.","tags":["wait","wait event","rac","gc buffer busy","cache fusion","interconnect","global"]},{"code":"library cache lock","title":"Espera: contenção em um handle de objeto do library cache (serialização de parse/DDL)","severity":"caution","meaning":"Uma sessão está aguardando um lock em um objeto do library cache (SQL, PL/SQL, definição de tabela). Geralmente causado pela serialização de operações de parse e DDL.","cause":"DDL (ALTER/CREATE) em objetos muito utilizados, objetos PL/SQL recompilados com frequência (invalidação), hard parsing excessivo, invalidação de objetos dependentes, ou tempestades intensas de conexões concorrentes.","fix":"Encontre a sessão bloqueadora e o objeto (v$session, ASH, diagnósticos de library cache lock se necessário). Evite executar DDL em objetos muito utilizados no horário de pico. Reduza cadeias de dependência e evite recompilações desnecessárias. Diminua o hard parsing usando bind variables. Suavize tempestades de conexões com um pool de conexões.","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":"A linha inserida ou atualizada viola uma constraint UNIQUE ou a PRIMARY KEY; o mesmo valor já existe na tabela.","cause":"Reinserção com a mesma chave única, entrada de dados duplicados em uma coluna única, o valor da sequence ficando para trás por causa de inserts manuais, ou duas requisições concorrentes inserindo a mesma chave.","fix":"O nome da constraint e o valor da chave no detalhe do erro mostram qual linha está em conflito. Para atualizar a linha existente, use INSERT ... ON CONFLICT (my_column) DO UPDATE ou DO NOTHING. Para encontrar duplicatas: SELECT my_column, COUNT(*) FROM my_table GROUP BY my_column HAVING COUNT(*) > 1. Se a sequence ficou para trás: 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":"Uma constraint FOREIGN KEY foi violada. A linha pai referenciada pela linha inserida/atualizada não existe, ou a linha pai que está sendo excluída ainda tem linhas filhas dependentes.","cause":"Um INSERT/UPDATE referenciando uma chave pai inexistente, uma tentativa de excluir/atualizar uma linha pai que ainda é referenciada, ou dados carregados na ordem errada (primeiro o filho, depois o pai).","fix":"Insira primeiro a linha pai, depois a linha filha. Se for necessário comportamento em cascata na exclusão, defina a constraint com ON DELETE CASCADE ou ON DELETE SET NULL. Em cargas em massa, carregue os dados na ordem pai-filho. Encontre as linhas que fazem referência: 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":"Houve uma tentativa de inserir NULL em uma coluna com constraint NOT NULL, ou de definir essa coluna como NULL.","cause":"Omissão de uma coluna obrigatória no INSERT, atribuição explícita de NULL, a coluna sem DEFAULT, ou um valor vazio/ausente vindo da aplicação.","fix":"Forneça um valor válido para a coluna ou defina um DEFAULT adequado para ela: ALTER TABLE my_table ALTER COLUMN my_column SET DEFAULT value. Se a coluna não precisa realmente ser obrigatória, remova a constraint: ALTER TABLE my_table ALTER COLUMN my_column DROP NOT NULL. Adicione validação de dados ausentes na camada da aplicação.","tags":["not null","null","constraint","constraint","required","23502","insert"]},{"code":"40P01","title":"deadlock_detected","severity":"danger","meaning":"Duas ou mais transações entraram em deadlock, cada uma aguardando locks mantidos pela outra. O PostgreSQL detecta o ciclo e cancela uma das transações.","cause":"Locks adquiridos em ordens diferentes, atualizações cruzadas das mesmas linhas, transações longas, ou locks conflitantes obtidos durante verificações de foreign key.","fix":"O detalhe do deadlock no log do servidor mostra as consultas em conflito. Acesse tabelas/linhas na mesma ordem em todas as transações. Mantenha as transações curtas. Capture a transação cancelada na aplicação e tente novamente. Faça join de pg_locks com pg_stat_activity para examinar os locks. Se necessário, torne a ordem dos locks explícita com SELECT ... FOR UPDATE.","tags":["deadlock","deadlock","lock","lock","40P01","tx","transaction"]},{"code":"40001","title":"serialization_failure","severity":"caution","meaning":"No nível de isolamento SERIALIZABLE ou REPEATABLE READ, a transação não pôde ser serializada porque entrou em conflito com alterações concorrentes, e foi cancelada. Este é um comportamento esperado que protege a consistência dos dados.","cause":"Transações que acessam os mesmos dados concorrentemente não podem ser organizadas em uma ordem serializável, conflitos de escrita sob alta concorrência, ou dependências perigosas detectadas pelo SSI (Serializable Snapshot Isolation).","fix":"Não é um bug, mas um sinal esperado: repita a transação como está. Adicione lógica de retry automático à aplicação. Para reduzir conflitos, encurte as transações e use um nível de isolamento mais baixo (READ COMMITTED) se ele não for realmente necessário. Projete para reduzir a contenção em hot rows.","tags":["serialization","serialization","isolation","isolation","retry","retry","40001","mvcc"]},{"code":"53300","title":"too_many_connections","severity":"danger","meaning":"O servidor atingiu o número máximo de conexões concorrentes permitido por max_connections; novas conexões não podem ser aceitas.","cause":"Ausência de pool de conexões ou um pool mal dimensionado, vazamentos de conexões, aplicações abrindo muitas conexões de curta duração, ou max_connections definido abaixo da carga de trabalho.","fix":"Identifique as origens das conexões: SELECT usename, state, COUNT(*) FROM pg_stat_activity GROUP BY 1,2. Encerre de forma direcionada as conexões de cliente ociosas há muito tempo (o encerramento em massa sem filtro afeta todas as aplicações e pools): 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(). A correção real é um pool de conexões como o PgBouncer. Aumentar max_connections custa memória; prefira pooling. As conexões reservadas para superusuários mantêm o acesso administrativo disponível.","tags":["connection","connection","max_connections","too many","53300","pool","pool","pgbouncer"]},{"code":"53100","title":"disk_full","severity":"danger","meaning":"O servidor não conseguiu gravar em um arquivo porque o disco está cheio. Não resta espaço no disco que contém o diretório de dados, o WAL ou os arquivos temporários.","cause":"Crescimento dos dados, acúmulo descontrolado de WAL (arquivamento ou um replication slot ficando para trás), arquivos temporários grandes (ordenações enormes), arquivos de log inchados, ou bloat de tabelas/índices.","fix":"Inspecione o uso do disco e remova arquivos desnecessários. Verifique o acúmulo de WAL: pg_stat_replication e pg_replication_slots (remova slots não utilizados; os atrasados retêm WAL). Não execute VACUUM FULL ou REINDEX com o disco cheio: como reescrevem a tabela, precisam de espaço extra igual ao tamanho da tabela e podem piorar a situação; o VACUUM simples também (quase) nunca devolve espaço ao sistema operacional. NUNCA exclua arquivos do diretório pg_wal manualmente. Primeiro libere espaço resolvendo as origens de WAL/slot, logs e temporários; revise a localização dos logs e dos arquivos temporários. Como correção permanente, aumente a capacidade de disco e configure monitoramento/alertas.","tags":["disk","space","space","full","full","wal","53100","vacuum"]},{"code":"57014","title":"query_canceled","severity":"safe","meaning":"A consulta foi cancelada. Geralmente causado pela expiração do statement_timeout ou por um cancelamento do usuário ou do cliente (pg_cancel_backend, cancelamento pelo driver).","cause":"statement_timeout excedido, um cancelamento com pg_cancel_backend, ou uma solicitação de cancelamento enviada pela aplicação/cliente. Situações semelhantes têm códigos diferentes: a expiração do lock_timeout retorna 55P03, idle_in_transaction_session_timeout 25P03 (FATAL), e um cancelamento causado por conflito de replicação em um hot standby 40001 (40P01 em alguns casos).","fix":"Se a consulta realmente demora, faça o tuning (EXPLAIN ANALYZE, índices, plano). Se o timeout estiver baixo demais, ajuste statement_timeout para a sessão/role em questão. Cancelamentos deliberados não exigem ação. Para cancelamentos causados por locks e conflitos no standby, consulte as entradas 55P03 e 40001.","tags":["cancel","cancel","timeout","timeout","statement_timeout","57014","standby"]},{"code":"42P01","title":"undefined_table","severity":"caution","meaning":"A tabela (ou view) referenciada na consulta não existe ou não é encontrada no search_path.","cause":"A tabela realmente não existe, está em outro schema que não está no search_path, erro de digitação/de maiúsculas e minúsculas no nome da tabela, incompatibilidade de maiúsculas/minúsculas com identificadores entre aspas, ou o objeto ainda não foi criado ou foi removido.","fix":"Verifique se a tabela existe e qual é seu schema: SELECT schemaname, tablename FROM pg_tables WHERE tablename = 'my_table'. Se estiver em outro schema, qualifique-a como schema.table ou defina o search_path: SET search_path TO app_schema, public. Lembre-se de que identificadores sem aspas são convertidos para minúsculas; se foram usadas aspas na criação, referencie-o da mesma forma.","tags":["table","table","undefined","42P01","search_path","schema","schema"]},{"code":"42703","title":"undefined_column","severity":"caution","meaning":"A coluna referenciada na consulta não existe na tabela ou no escopo atual.","cause":"Erro de digitação no nome da coluna, a coluna foi removida/renomeada, referência à tabela errada, incompatibilidade de maiúsculas/minúsculas com identificador entre aspas, ou qualificação ambígua/incorreta em uma consulta com várias tabelas.","fix":"Liste as colunas: \\d my_table ou SELECT column_name FROM information_schema.columns WHERE table_name = 'my_table'. Corrija o nome e a tabela, e qualifique as colunas nos JOINs como table.column. Se foram usadas aspas na criação, referencie-a com as mesmas maiúsculas/minúsculas.","tags":["column","column","undefined","42703","typo","typo","schema"]},{"code":"42501","title":"insufficient_privilege","severity":"caution","meaning":"A role não tem o privilégio necessário para a operação que está tentando executar.","cause":"O GRANT necessário na tabela/schema/banco de dados não foi concedido, falta USAGE no schema, o objeto pertence a outra role, ou políticas de row-level security (RLS) bloqueiam o acesso.","fix":"Conceda o privilégio que falta: GRANT SELECT, INSERT ON my_table TO app_role; para o schema GRANT USAGE ON SCHEMA app_schema TO app_role. Para concessões em massa, use GRANT ... ON ALL TABLES IN SCHEMA, e ALTER DEFAULT PRIVILEGES para objetos futuros. Veja os privilégios atuais: \\dp my_table. Se RLS estiver ativo, revise as políticas relevantes.","tags":["privilege","privilege","permission","grant","42501","permission","rls"]},{"code":"28P01","title":"invalid_password","severity":"caution","meaning":"A senha fornecida durante a autenticação está errada; o login foi rejeitado para a role.","cause":"Senha errada, senha alterada, credenciais desatualizadas na connection string da aplicação, ou incompatibilidade com o método de autenticação esperado no pg_hba.conf (scram-sha-256, md5).","fix":"Verifique a senha e redefina-a se necessário: ALTER ROLE app_role WITH PASSWORD 'new_password'. Certifique-se de que o método no pg_hba.conf é compatível com o cliente (clientes antigos podem ter problemas com scram-sha-256). Após as alterações, recarregue a configuração com SELECT pg_reload_conf().","tags":["auth","identity","password","password","28P01","scram","md5","hba"]},{"code":"08006","title":"connection_failure","severity":"danger","meaning":"A conexão entre cliente e servidor não pôde ser estabelecida ou caiu inesperadamente.","cause":"O servidor não está em execução ou está reiniciando, problemas de rede/firewall, host/porta errados, uma configuração de listen_addresses que bloqueia o acesso, uma conexão ociosa derrubada pela rede, ou um servidor sobrecarregado.","fix":"Verifique se o servidor está no ar e escutando no host/porta corretos (pg_isready host port). Verifique listen_addresses no postgresql.conf e as regras de acesso no pg_hba.conf. Verifique as configurações de rede/firewall e DNS. Revise as configurações de TCP keepalive e timeout no pool de conexões. Procure vestígios de crash/reinicialização no log do servidor.","tags":["connection","connection","network","network","08006","failure","disconnect"]},{"code":"55P03","title":"lock_not_available","severity":"caution","meaning":"O lock solicitado não pôde ser adquirido imediatamente. Geralmente acontece quando um lock é solicitado com NOWAIT enquanto outra sessão o mantém, ou quando o lock_timeout expira.","cause":"A linha/tabela estar bloqueada durante o uso de SELECT ... FOR UPDATE NOWAIT ou LOCK TABLE ... NOWAIT, ou a expiração do lock_timeout. Na maioria das vezes, uma transação longa está mantendo o lock.","fix":"Encontre a sessão bloqueadora: faça join de pg_locks e pg_stat_activity (relação de espera/bloqueio). Finalize a transação longa ou, se necessário, encerre-a com pg_terminate_backend(pid). Em vez de NOWAIT, aguarde com um lock_timeout razoável e adicione lógica de retry. Encurte as transações para reduzir o tempo de retenção dos locks.","tags":["lock","lock","nowait","lock_timeout","55P03","not available","busy"]},{"code":"54000","title":"program_limit_exceeded","severity":"caution","meaning":"Um limite de implementação/formato do PostgreSQL foi excedido; por exemplo, o tamanho máximo de uma linha ou campo, o tamanho da linha de índice, ou o limite do número de parâmetros/colunas em uma consulta.","cause":"Tentativa de armazenar um valor muito grande (por exemplo, um campo acima de 1 GB), um valor indexado que excede o limite de página do B-tree (cerca de 2704 bytes), ou uso de colunas ou parâmetros de consulta em excesso.","fix":"Identifique o limite excedido (a mensagem geralmente informa qual). Revise ou divida a estrutura para textos/dados muito grandes. Indexe colunas de texto longas com um índice hash ou um índice de expressão/parcial em vez de um B-tree. Reduza o número de parâmetros/colunas na consulta ou divida o lote.","tags":["limit","limit","program_limit","54000","index size","size","row size"]},{"code":"22001","title":"string_data_right_truncation","severity":"caution","meaning":"O valor seria truncado porque o comprimento do texto excede o comprimento definido da coluna de destino (por exemplo, VARCHAR(n)); o PostgreSQL o rejeita e gera um erro.","cause":"Inserção ou atualização de texto maior que n em uma coluna VARCHAR(n)/CHAR(n), dados maiores que o esperado vindos da aplicação, ou um comprimento de coluna definido estreito demais para a necessidade.","fix":"Encurte o valor para que caiba na coluna, ou aumente o comprimento da coluna: ALTER TABLE my_table ALTER COLUMN my_column TYPE VARCHAR(500). Se for necessário texto ilimitado, use o tipo TEXT. Valide o comprimento na aplicação. Se quiser truncamento deliberado, aplique LEFT(value, n) explicitamente.","tags":["truncation","truncation","varchar","string","text","22001","length","length"]},{"code":"25P02","title":"in_failed_sql_transaction","severity":"caution","meaning":"Já ocorreu um erro anteriormente na transação; nenhum outro comando pode ser executado nela. A transação está no estado abortado e apenas ROLLBACK é aceito.","cause":"Uma instrução anterior em um bloco de transação falhou (por exemplo, uma violação de constraint) e novos comandos continuam sendo enviados na mesma transação mesmo assim. A aplicação não captura o erro e prossegue com a transação.","fix":"Faça rollback da transação: ROLLBACK, e então inicie-a novamente. Se quiser isolar o erro de um bloco e continuar, use SAVEPOINT e retorne a esse ponto com ROLLBACK TO SAVEPOINT. Na aplicação, capture o erro de cada instrução e gerencie a transação adequadamente (torne explícita a decisão de commit/rollback).","tags":["transaction","transaction","aborted","aborted","25P02","rollback","savepoint"]},{"code":"53200","title":"out_of_memory","severity":"danger","meaning":"O servidor não conseguiu alocar a memória necessária para uma operação. Um processo backend ou o servidor inteiro está sob pressão de memória.","cause":"work_mem/maintenance_work_mem definidos altos demais e multiplicados pela alta concorrência, operações de hash/sort demais em uma única consulta, número excessivo de conexões, vazamento de memória, ou pressão do OOM killer do sistema operacional.","fix":"Verifique o contexto de memória no log do servidor e vestígios do OOM killer. Defina work_mem de forma sensata, levando em conta o número de consultas e a concorrência (ele é alocado separadamente para cada sort/hash). Limite o número de conexões com pooling. Revise as configurações de memória/overcommit do sistema operacional. Otimize as consultas pesadas para reduzir sua necessidade de memória.","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":"A autenticação falhou para o nome de usuário, a senha ou o host a partir do qual você está se conectando; o login foi rejeitado.","cause":"Senha errada, o usuário não tem privilégios a partir do host de onde se conecta (user@host), a conta não existe, incompatibilidade de plugin de autenticação (caching_sha2_password vs mysql_native_password) ou credenciais desatualizadas na connection string.","fix":"Verifique a correspondência entre usuário e host: SELECT user, host, plugin FROM mysql.user. Conceda privilégios para o host correto (por exemplo, 'app_user'@'%'). Redefina a senha: ALTER USER 'app_user'@'host' IDENTIFIED BY 'new_password'; (ALTER USER/GRANT têm efeito imediato; FLUSH PRIVILEGES só é necessário se as grant tables foram modificadas diretamente com DML). Se você vir 'using password: NO', o cliente não está enviando senha alguma. Para incompatibilidades de plugin, revise o plugin de autenticação: no MySQL 8.4 o plugin mysql_native_password vem desabilitado por padrão (carregado apenas com --mysql-native-password=ON); contas antigas que usam esse plugin e clientes antigos não conseguem conectar. Migre a conta com ALTER USER ... IDENTIFIED WITH caching_sha2_password BY '...'; e atualize o driver do cliente.","tags":["auth","authentication","access denied","access","password","password","1045","privilege"]},{"code":"1062","title":"Duplicate entry for key","severity":"caution","meaning":"A linha inserida ou atualizada viola um índice UNIQUE ou a PRIMARY KEY; o mesmo valor de chave já existe.","cause":"Um INSERT repetido com a mesma chave única, entrada de dados duplicados, um contador AUTO_INCREMENT que ficou para trás, ou linhas duplicadas existentes ao adicionar um índice único a uma tabela existente.","fix":"A mensagem de erro mostra o valor de chave em conflito e o nome do índice. Para atualizar a linha existente, considere INSERT ... ON DUPLICATE KEY UPDATE ou INSERT IGNORE / REPLACE. Encontre duplicatas: SELECT my_column, COUNT(*) FROM my_table GROUP BY my_column HAVING COUNT(*) > 1. Se não for possível adicionar um índice único, limpe as duplicatas primeiro.","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":"O InnoDB detectou um deadlock em que duas ou mais transações aguardam os locks umas das outras e quebrou o ciclo fazendo rollback de uma das transações.","cause":"Locks de linha adquiridos em ordens diferentes, atualizações cruzadas das mesmas linhas, faixas amplas de linhas sendo bloqueadas (gap locks) por falta de índices, ou conflitos durante verificações de foreign key.","fix":"Veja os detalhes do último deadlock: SHOW ENGINE INNODB STATUS (seção LATEST DETECTED DEADLOCK). Acesse linhas/tabelas na mesma ordem em todas as transações e mantenha as transações curtas. Reduza a faixa bloqueada adicionando índices adequados. Capture a transação que sofreu rollback na aplicação e tente novamente (lógica de retry).","tags":["deadlock","deadlock detected","lock","row lock","innodb","1213","tx","transaction"]},{"code":"1205","title":"Lock wait timeout exceeded; try restarting transaction","severity":"danger","meaning":"Uma transação aguardou um lock de linha necessário por innodb_lock_wait_timeout segundos, não conseguiu adquiri-lo e expirou.","cause":"Outra transação mantendo o lock por muito tempo sem commit ou rollback; transações abertas ociosas, atualizações em massa de longa duração ou hot rows disputadas.","fix":"Encontre a transação bloqueadora: faça join de performance_schema.data_lock_waits com data_locks (information_schema.innodb_lock_waits/innodb_trx em versões mais antigas). Faça commit/rollback da transação bloqueadora ou encerre-a com KILL <trx_mysql_thread_id> se necessário. Mantenha as transações curtas e não deixe transações ociosas (autocommit/lógica da aplicação). Se necessário, ajuste innodb_lock_wait_timeout à carga de trabalho.","tags":["lock","lock wait","timeout","timed out","innodb","1205","wait","waiting"]},{"code":"1040","title":"Too many connections","severity":"danger","meaning":"O servidor atingiu o número máximo de conexões concorrentes permitido por max_connections; novas conexões estão sendo rejeitadas.","cause":"Pool de conexões mal dimensionado, vazamentos de conexões, muitas conexões de curta duração, conexões dormindo por muito tempo (Sleep) ou um valor de max_connections baixo demais para a carga de trabalho.","fix":"Inspecione as conexões: SHOW PROCESSLIST ou SELECT * FROM performance_schema.processlist. Feche conexões dormentes desnecessárias com KILL. Aumente max_connections: SET GLOBAL max_connections = 500 (no my.cnf para persistir). A correção de raiz é usar um pool de conexões e fechar conexões ociosas com wait_timeout. Uma conexão administrativa extra de emergência é reservada para SUPER/CONNECTION_ADMIN.","tags":["connection","connections","too many","max_connections","1040","pool","connection pool"]},{"code":"1064","title":"You have an error in your SQL syntax","severity":"safe","meaning":"A instrução SQL tem um erro de sintaxe; o servidor não conseguiu analisá-la. A mensagem mostra o texto próximo ao erro.","cause":"Erro de digitação, vírgula ou parêntese faltando/sobrando, palavra reservada usada sem aspas como nome de coluna/tabela, sintaxe não suportada pela versão do MySQL, ou erros de aspas/escape.","fix":"A parte 'near ...' da mensagem mostra onde o erro começa; olhe imediatamente antes dela. Coloque palavras reservadas entre backticks: `order`, `group`. Balanceie parênteses e vírgulas. Verifique se você está usando sintaxe suportada pela sua versão. Se você gera SQL dinâmico, registre em log e inspecione a consulta completa resultante.","tags":["syntax","syntax error","1064","parse","parsing","reserved word","reserved keyword"]},{"code":"1146","title":"Table doesn't exist","severity":"caution","meaning":"A tabela referenciada na consulta não existe ou não é encontrada no banco de dados atual.","cause":"A tabela realmente não existe, o banco de dados errado está selecionado, erro de digitação no nome da tabela, sensibilidade a maiúsculas/minúsculas do nome da tabela no Linux (lower_case_table_names) ou um arquivo de tabela InnoDB (.ibd) ausente/corrompido (no 5.7 e anteriores também o arquivo de definição .frm; no 8.0 as definições ficam no data dictionary).","fix":"Verifique a tabela: SHOW TABLES; e selecione o banco de dados correto: USE mydb. Atenção à sensibilidade a maiúsculas/minúsculas (especialmente no Linux). Verifique o nome da tabela e o schema com SELECT ... FROM information_schema.tables. Se houver problema no arquivo InnoDB, pode ser necessário restore/reparo.","tags":["table","table missing","doesn't exist","not found","1146","schema","database"]},{"code":"1054","title":"Unknown column in field list","severity":"caution","meaning":"A coluna referenciada na consulta não existe na tabela ou no escopo atual.","cause":"Erro de digitação no nome da coluna, a coluna foi removida/renomeada, referência à tabela errada, qualificação ambígua/errada em um JOIN, ou um valor string escrito sem aspas e interpretado como coluna (WHERE name = value em vez de WHERE name = 'value').","fix":"Liste as colunas: SHOW COLUMNS FROM my_table ou DESCRIBE my_table. Corrija o nome da coluna e qualifique-a como my_table.my_column nos JOINs. Coloque literais string entre aspas simples; backticks são apenas para identificadores. Você pode verificar com 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","severity":"danger","meaning":"O cliente não conseguiu se conectar ao servidor MySQL local pelo socket Unix. Geralmente o servidor não está em execução ou o caminho do socket está errado.","cause":"O serviço MySQL/MariaDB não está em execução ou travou, o caminho do arquivo de socket (por exemplo, /var/run/mysqld/mysqld.sock) difere entre cliente e servidor, problemas de permissão, ou o servidor não foi iniciado.","fix":"Verifique o status do serviço e inicie-o (systemctl status mysql / start mysql). Verifique o caminho correto do socket: SHOW VARIABLES LIKE 'socket' e a configuração socket no my.cnf. Se o caminho for diferente, especifique-o explicitamente com --socket ou use TCP: mysql -h 127.0.0.1 -P 3306. Verifique os logs do servidor em busca de erros de inicialização/crash.","tags":["connection","connect","socket","unix socket","2002","server","local","localhost"]},{"code":"2003","title":"Can't connect to MySQL server (TCP/IP)","severity":"danger","meaning":"O cliente não conseguiu se conectar ao servidor MySQL via TCP/IP no host e na porta especificados.","cause":"O servidor não está em execução, host/porta errados, um firewall bloqueando a porta 3306, o servidor vinculado apenas ao localhost (bind-address = 127.0.0.1) ou skip-networking habilitado.","fix":"Verifique se o servidor está no ar e escutando na porta correta. Para acesso remoto, defina bind-address = 0.0.0.0 (ou o IP apropriado) no my.cnf e certifique-se de que skip-networking está desativado. Abra a porta 3306 no firewall. Verifique host/porta: mysql -h host -P 3306 -u app_user -p. Certifique-se de que o usuário tem privilégios a partir do host remoto.","tags":["connection","connect","tcp","port","2003","network","firewall","bind-address"]},{"code":"2006","title":"MySQL server has gone away","severity":"caution","meaning":"A conexão entre cliente e servidor foi perdida durante um comando. O servidor pode ter fechado a conexão ou rejeitado o pacote.","cause":"Uma conexão ociosa fechada porque wait_timeout/interactive_timeout expirou, uma consulta/dados maiores que max_allowed_packet, uma reinicialização ou crash do servidor, ou uma queda de rede.","fix":"Para problemas com conexões ociosas, use validação no pool de conexões e revise wait_timeout. Se você envia dados grandes, aumente max_allowed_packet (por exemplo, SET GLOBAL max_allowed_packet = 64*1024*1024, no my.cnf para persistir). Verifique os logs do servidor em busca de reinicializações/crashes e vestígios de OOM. Adicione lógica de reconexão na aplicação para conexões derrubadas.","tags":["connection","connection lost","gone away","disconnect","2006","timeout","max_allowed_packet"]},{"code":"1114","title":"The table is full","severity":"danger","meaning":"Não é possível gravar mais dados na tabela porque um limite de armazenamento ou o fim do espaço disponível foi atingido.","cause":"Disco cheio, limite max_heap_table_size atingido para tabelas MEMORY, tmp_table_size excedido para tabelas temporárias, um tablespace de tamanho fixo definido por innodb_data_file_path enchendo, ou limites de tamanho específicos do sistema de arquivos/da tabela.","fix":"Primeiro verifique e libere espaço em disco. Para tabelas MEMORY/temporárias, aumente max_heap_table_size e tmp_table_size. Para InnoDB, certifique-se de que innodb_data_file_path está com autoextend ou adicione espaço. Otimize consultas que despejam grandes resultados temporários em disco. Para uma correção permanente, aumente a capacidade de armazenamento.","tags":["table full","table is full","disk","space","1114","space","memory","innodb"]},{"code":"1215","title":"Cannot add foreign key constraint","severity":"caution","meaning":"A constraint de foreign key que está sendo definida não pode ser criada; o MySQL não consegue adicionar a constraint.","cause":"Incompatibilidade de tipo de dado/comprimento/sinal (signed-unsigned) ou de character set/collation entre a coluna filha e a referenciada, ausência de índice/PRIMARY KEY adequado na coluna referenciada, tabelas usando storage engines diferentes (uma é MyISAM) ou a tabela referenciada ainda não existe.","fix":"Certifique-se de que os tipos das colunas dos dois lados são EXATAMENTE iguais (por exemplo, ambos INT UNSIGNED). Verifique se a coluna referenciada é suportada por um índice (geralmente PRIMARY KEY ou UNIQUE). Certifique-se de que ambas as tabelas são InnoDB. Use o mesmo charset/collation para chaves string. Para detalhes: 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":"Você tentou excluir uma linha pai ou alterar sua chave, mas a constraint de foreign key não permite porque existem linhas filhas dependentes.","cause":"A linha pai referenciada ainda tem linhas filhas e a constraint usa RESTRICT/NO ACTION para ON DELETE/UPDATE.","fix":"Primeiro exclua as linhas filhas dependentes ou mova-as para outro pai, depois exclua a linha pai. Se quiser comportamento automático, redefina a constraint com ON DELETE CASCADE ou ON DELETE SET NULL. Encontre as linhas dependentes: 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":"Você está inserindo ou atualizando uma linha filha, mas o valor da chave pai para o qual ela aponta não existe na tabela referenciada; a constraint de foreign key a rejeita.","cause":"Um INSERT/UPDATE referenciando uma chave pai inexistente, dados carregados na ordem errada (primeiro o filho) ou uma linha pai excluída.","fix":"Insira primeiro a linha pai, depois a linha filha. Verifique se o valor referenciado existe: SELECT * FROM parent_table WHERE key_column = value. Preserve a ordem pai-filho em cargas em massa. Use SET FOREIGN_KEY_CHECKS=0 apenas em operações de manutenção controladas e volte para 1 ao terminar.","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":"Um valor incompatível com o tipo ou o character set da coluna foi inserido em uma coluna. Geralmente causado por incompatibilidade de codificação de caracteres ou de tipo.","cause":"Gravação de um emoji/caractere de 4 bytes (utf8mb4) em uma coluna latin1, entrada de texto não numérico em uma coluna numérica, charset de conexão errado, ou envio de um valor de tipo diferente do esperado.","fix":"Para problemas de caracteres, converta a coluna/tabela para utf8mb4: ALTER TABLE my_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci e defina o charset da conexão como utf8mb4. Valide os tipos na aplicação para campos numéricos. Lembre-se de que o servidor roda em SQL mode estrito (STRICT); a causa raiz é o tipo/a codificação dos dados.","tags":["charset","character","incorrect value","1366","utf8mb4","encoding","type","collation"]},{"code":"1044","title":"Access denied for user to database","severity":"caution","meaning":"Embora o usuário tenha se autenticado corretamente, ele não tem privilégios para operar no banco de dados especificado.","cause":"Nenhum GRANT no banco de dados para o usuário, nome de banco de dados errado, o privilégio definido para um host diferente (user@host) ou um banco de dados inexistente.","fix":"Veja os privilégios do usuário: SHOW GRANTS FOR 'app_user'@'host'. Conceda o privilégio necessário: GRANT ALL PRIVILEGES ON mydb.* TO 'app_user'@'host'; (GRANT tem efeito imediato, FLUSH PRIVILEGES não é necessário). Verifique a correspondência correta do host e o nome do banco de dados. Seguindo o princípio do menor privilégio, conceda apenas os direitos necessários.","tags":["access denied","access","database","database access","1044","grant","privilege","permission"]},{"code":"1264","title":"Out of range value for column","severity":"caution","meaning":"Um valor fora do intervalo permitido pelo tipo foi inserido em uma coluna numérica ou de data. Este erro é gerado no SQL mode estrito.","cause":"Ultrapassagem do limite de tipos como TINYINT/INT (por exemplo, 200 em TINYINT, ou um valor negativo em uma coluna UNSIGNED), overflow de data/número, ou envio de um valor maior que o esperado.","fix":"Amplie o tipo da coluna conforme necessário (por exemplo, INT em vez de TINYINT, BIGINT em vez de INT) ou corrija o sinal (SIGNED/UNSIGNED). Valide os intervalos de valores na aplicação. Mesmo que você queira o comportamento de truncamento silencioso (não recomendado), torne os dados compatíveis com o tipo em vez de remover STRICT do sql_mode.","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":"Duas ou mais transações aguardam, cada uma, locks mantidos pela outra (um deadlock). Para quebrar o ciclo, o SQL Server escolhe uma transação como vítima e faz rollback dela.","cause":"Transações bloqueando tabelas/linhas em ordens diferentes, transações de longa duração, varreduras amplas causadas por falta de índices, lock escalation e alta concorrência são as causas típicas.","fix":"Capture o erro 1205 na aplicação e repita a transação automaticamente. Acesse os objetos na mesma ordem em todas as transações e mantenha as transações curtas. Examine o grafo de deadlock: use Extended Events (a sessão system_health) ou o trace flag 1222 para detalhes. Adicione índices adequados para reduzir varreduras e locks. Se necessário, avalie o nível de isolamento 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","severity":"caution","meaning":"Você tentou inserir ou atualizar um valor que já existe em coluna(s) protegida(s) por uma constraint PRIMARY KEY ou UNIQUE. Chaves duplicadas não são aceitas.","cause":"Inserção do mesmo valor único uma segunda vez, um UPDATE colidindo com um valor existente, ausência de verificação de unicidade, ou duas requisições concorrentes produzindo a mesma linha.","fix":"Verifique se a linha existe antes de inserir, ou use MERGE / IF NOT EXISTS. Para inserts idempotentes, aplique o padrão \"INSERT ... WHERE NOT EXISTS\". Capture o erro e retorne uma mensagem significativa. Se você realmente precisa de dados duplicados, revise a constraint. Use IDENTITY ou SEQUENCE para evitar colisões ao gerar chaves.","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":"Um UNIQUE INDEX rejeitou uma linha por causa de um valor de chave duplicado. 2627 é gerado para constraints, 2601 para índices únicos.","cause":"Gravação de um valor existente novamente em coluna(s) protegida(s) por um UNIQUE INDEX, inserts concorrentes, ou uma colisão entre linhas cobertas por um filtered unique index.","fix":"Remova ou atualize o valor duplicado. Se duplicatas precisarem ser toleradas, considere a opção IGNORE_DUP_KEY = ON (duplicatas são ignoradas silenciosamente). Adicione uma verificação NOT EXISTS antes de inserir. Se houver um filtered index, verifique sua cláusula WHERE e a colisão.","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","severity":"caution","meaning":"A instrução violou uma constraint FOREIGN KEY ou CHECK. Ou ela referenciou uma linha pai que não existe, gravou um valor que quebra uma regra CHECK, ou tentou excluir uma linha pai que ainda é referenciada.","cause":"FK: a linha pai referenciada pela linha filha inserida não existe. DELETE/UPDATE: linhas filhas dependem da linha pai que está sendo excluída/alterada. CHECK: o valor da coluna não satisfaz a condição definida.","fix":"Insira primeiro a linha pai, depois a linha filha. Para exclusões, remova primeiro as linhas dependentes ou defina ON DELETE CASCADE onde for apropriado. Para uma violação de CHECK, faça o valor cumprir a regra. Identifique a constraint violada pelo nome da constraint no texto do erro.","tags":["foreign key","fk","check","constraint","constraint violation","referential","547"]},{"code":"18456","title":"Login failed for user","severity":"danger","meaning":"Uma tentativa de login foi rejeitada durante a autenticação. O nome de usuário/senha pode estar errado, a conta pode estar desabilitada, ou o usuário pode não ter acesso ao banco de dados.","cause":"Senha errada, login inexistente, conta desabilitada/bloqueada, uso de um login SQL enquanto apenas a autenticação do Windows está habilitada, ou falta de acesso ao banco de dados padrão. O código State no texto do erro identifica a causa real (State 5: o login não existe, State 7: login desabilitado e senha também errada, State 8: senha errada (o mais comum), State 18: a senha precisa ser alterada, State 38: o banco de dados especificado não pode ser aberto, State 58: login SQL tentado enquanto o servidor está no modo de autenticação somente Windows).","fix":"Encontre a causa raiz pelo valor State no error log do SQL Server (os detalhes não são enviados ao cliente por motivos de segurança). Verifique o nome de usuário/senha. Verifique se o servidor roda em 'SQL Server and Windows Authentication Mode' (modo misto); se você alterou isso, reinicie o serviço. Verifique o mapeamento de usuário do login e a permissão de acesso no banco de dados de destino.","tags":["login","session","authentication","authentication failed","password","18456","state"]},{"code":"8152","title":"String or binary data would be truncated","severity":"caution","meaning":"Você tentou gravar dados maiores que o comprimento definido de uma coluna. O SQL Server interrompe a instrução para evitar perda de dados (2628 é a versão mais nova do mesmo erro, que informa a coluna/o valor).","cause":"Por exemplo, gravar 15 caracteres em uma coluna VARCHAR(10), uma coluna de destino mais estreita que a origem, incompatibilidade de tipo de dado/comprimento, ou tamanho de campo insuficiente em ETL/transferências.","fix":"Amplie a coluna para comportar os dados (ALTER TABLE ... ALTER COLUMN) ou encurte os dados. No SQL Server 2019+, use o erro 2628, que mostra a tabela/coluna/valor que estourou; em versões mais antigas, verifique as colunas uma a uma com LEN() para encontrar a linha problemática. Em transferências, alinhe os comprimentos dos schemas de origem e destino.","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":"A versão aprimorada do 8152 (SQL Server 2019 e posteriores). Informa explicitamente qual tabela, qual coluna e qual valor seriam truncados.","cause":"Gravação de um valor texto/binário maior que o comprimento definido da coluna de destino. Geralmente uma incompatibilidade de schema ou dados de entrada com comprimento inesperado.","fix":"Veja o nome da tabela e da coluna no texto do erro; amplie a coluna ou encurte o valor de origem. No SQL Server 2019, o 2628 é gerado por padrão apenas no nível de compatibilidade 150+; em níveis inferiores, habilite-o com ALTER DATABASE SCOPED CONFIGURATION SET VERBOSE_TRUNCATION_WARNINGS = ON ou o trace flag 460. A partir do SQL Server 2016 SP2 CU6 e 2017 CU12, o trace flag 460 fornece a mesma mensagem detalhada. Alinhe os comprimentos dos campos com o destino na camada de transferência.","tags":["truncation","truncate","overflow","column","column name","length","2628","460"]},{"code":"1222","title":"Lock request time out period exceeded","severity":"caution","meaning":"O timeout de uma consulta expirou enquanto ela aguardava para adquirir um lock. A requisição foi cancelada porque outra transação manteve o recurso necessário bloqueado por tempo demais.","cause":"Ultrapassagem do tempo de espera definido com SET LOCK_TIMEOUT, transações bloqueadoras de longa duração, transações abertas sem commit, varreduras longas e conflitos de lock.","fix":"Encontre o bloqueador: examine sys.dm_exec_requests, sys.dm_tran_locks e a coluna blocking_session_id, ou use sp_who2 / sp_whoisactive. Encurte as transações longas e faça commit delas. Ajuste LOCK_TIMEOUT se necessário. Em sistemas com muita leitura, reduza os conflitos leitor-escritor com RCSI/snapshot isolation.","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":"O arquivo de transaction log do banco de dados está cheio e novas transações não podem ser registradas. O banco de dados rejeita gravações e pode se comportar como se fosse somente leitura.","cause":"Ausência de backups de log no recovery model FULL, uma transação aberta há muito tempo, lag de replicação/AlwaysOn, ou o log incapaz de crescer (autogrow desabilitado ou disco cheio). log_reuse_wait_desc mostra o motivo.","fix":"Verifique log_reuse_wait_desc em sys.databases. Se for LOG_BACKUP no modelo FULL, faça um backup de log (BACKUP LOG). Se for ACTIVE_TRANSACTION, encontre a transação aberta e faça commit/rollback dela (DBCC OPENTRAN). Libere espaço em disco ou corrija a configuração de autogrow do arquivo de log. Se o log realmente cresceu, reduza-o com DBCC SHRINKFILE após o backup. Se você não precisa da cadeia de log, revise o recovery model.","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":"O filegroup que contém o arquivo de dados está cheio e não é possível alocar espaço para novos dados. Inserts/updates falham.","cause":"O arquivo de dados não consegue crescer (autogrowth desabilitado ou MAXSIZE atingido), sem espaço livre em disco, o filegroup PRIMARY esgotado, ou um limite de tamanho de arquivo.","fix":"Libere espaço em disco ou adicione um novo disco/arquivo. Habilite o autogrowth no arquivo de dados ou amplie-o (ALTER DATABASE ... MODIFY FILE). Adicione um novo arquivo ao filegroup. Arquive e expurgue dados desnecessários/antigos. Para o tempdb, verifique os arquivos do tempdb e seu disco.","tags":["filegroup full","file full","allocate space","disk","autogrow","1105"]},{"code":"208","title":"Invalid object name","severity":"safe","meaning":"A tabela, view ou objeto referenciado na consulta não foi encontrado. O SQL Server não conseguiu resolver o nome especificado.","cause":"Nome de objeto grafado incorretamente, contexto de banco de dados/schema errado (um schema diferente de dbo), o objeto realmente não existe ou ainda não foi criado, ou falta o nome em duas partes (schema.table).","fix":"Escreva corretamente o nome do objeto e o schema; use o nome qualificado (por exemplo, dbo.Customers). Certifique-se de estar conectado ao banco de dados certo (USE). Verifique se o objeto existe: SELECT * FROM sys.objects WHERE name = 'YourObjectName'. Certifique-se de que as tabelas temporárias são criadas na mesma sessão.","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","severity":"caution","meaning":"O usuário não tem permissão para executar a operação solicitada (SELECT, INSERT, EXECUTE etc.) no objeto. O acesso foi negado por motivos de segurança.","cause":"A permissão necessária não foi concedida ao usuário/role, propriedade de schema errada (ownership chaining quebrado), um DENY explícito no objeto, ou o usuário não é membro de uma role suficiente.","fix":"Conceda a permissão necessária: GRANT SELECT ON dbo.MyTable TO UserName (ou GRANT EXECUTE ON dbo.MyProcedure TO ...). Adicione o usuário a uma role adequada (por exemplo, db_datareader). Remova qualquer DENY explícito. Organize as permissões segundo o princípio do menor privilégio. Audite as permissões existentes com 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":"A autenticação pode ter sucesso, mas a conexão é rejeitada porque o banco de dados solicitado não pode ser aberto. Geralmente visto junto com o 18456.","cause":"O banco de dados não existe, está OFFLINE/SINGLE_USER/RESTORING/SUSPECT, o login não tem mapeamento de usuário nesse banco de dados, ou o banco de dados padrão na connection string está inacessível.","fix":"Verifique se o banco de dados existe e está ONLINE: SELECT name, state_desc FROM sys.databases. Crie um usuário para o login no banco de dados e conceda permissões. Verifique o valor Initial Catalog/Database na connection string. Se o banco de dados estiver RESTORING/SUSPECT, siga as etapas de reparo/restore.","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":"O cliente alcançou o servidor, mas a conexão caiu durante o handshake. Geralmente causado pela configuração de Named Pipes/TCP, configurações de protocolo ou uma rejeição do lado do servidor. Relacionado ao 10054 (conexão fechada à força).","cause":"Protocolos Shared Memory/Named Pipes/TCP desabilitados, conexões remotas não permitidas, a conta incapaz de fazer login (veja 18456), um firewall/queda de rede, ou o servidor fechando a conexão à força (10054).","fix":"Habilite o TCP/IP e, se necessário, o Named Pipes no SQL Server Configuration Manager e reinicie o serviço. Verifique se as conexões remotas são permitidas. Abra a porta do SQL (padrão 1433) no firewall. Para problemas de autenticação, examine o código State do 18456 no error log. Verifique a estabilidade da rede e as configurações de TLS/criptografia.","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)","severity":"danger","meaning":"O SQL Server recebeu um erro de I/O no nível do sistema operacional ao ler ou gravar um arquivo de dados/log. Trata-se de um alerta sério de integridade que aponta para um problema no hardware de disco ou no subsistema de armazenamento.","cause":"Setores de disco defeituosos, uma controladora/driver com falha, problemas de storage/SAN, erros no sistema de arquivos, ou uma página que não pode ser lida de forma alguma (erro de I/O grave). Geralmente relacionado a hardware.","fix":"Faça um backup íntegro imediatamente (se possível). Examine o log de eventos do Windows e os logs do storage, e teste a saúde do hardware/disco. Execute DBCC CHECKDB para verificar a integridade. Verifique a tabela suspect_pages (msdb.dbo.suspect_pages). Se houver corrupção, restaure a partir de um backup íntegro ou faça um restore no nível de página. Substitua/repare o hardware.","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)","severity":"danger","meaning":"O SQL Server leu uma página, mas seu conteúdo é logicamente inconsistente (checksum incorreto, torn page ou ID de página errado). A página de dados está corrompida.","cause":"Erros no subsistema de armazenamento, queda súbita de energia/torn pages, problemas de controladora ou driver, corrupção silenciosa detectada pelo PAGE_VERIFY CHECKSUM. Assim como o 823, relacionado principalmente a hardware/armazenamento.","fix":"Execute DBCC CHECKDB para determinar a extensão da corrupção. Restaure a partir do último backup íntegro ou repare as páginas afetadas com um restore no nível de página. Examine msdb.dbo.suspect_pages. Certifique-se de que PAGE_VERIFY = CHECKSUM está habilitado. Inspecione o hardware/armazenamento. REPAIR_ALLOW_DATA_LOSS deve ser o último recurso e causa perda de dados.","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":"O SQL Server não conseguiu alocar, a partir do resource pool correspondente, a memória necessária para executar a consulta. A operação falhou por pressão de memória.","cause":"Memória do servidor insuficiente, configuração baixa de max server memory, consultas que consomem muita memória (grandes sorts/hashes), vazamento de memória, muitas requisições concorrentes, ou limites de pool do Resource Governor.","fix":"Revise a configuração max server memory e forneça RAM física suficiente. Otimize as consultas que consomem muita memória (índices adequados, menos sorts/hashes). Monitore a memória: sys.dm_os_memory_clerks, DBCC MEMORYSTATUS, contadores de memória do Perfmon. Ajuste os limites de pool do Resource Governor. Reduza a concorrência se necessário.","tags":["memory","memory pressure","insufficient memory","resource pool","701","oom"]},{"code":"845","title":"Time-out occurred while waiting for buffer latch","severity":"danger","meaning":"Ocorreu um timeout enquanto se aguardava um buffer latch em uma página de dados. O SQL Server não conseguiu adquirir em tempo razoável o lock interno de curta duração (latch) necessário para acessar uma página; geralmente um sinal de I/O intenso ou pressão de memória.","cause":"Um subsistema de disco lento/sobrecarregado, páginas lidas constantemente do disco por pressão de memória, problemas de hardware, paginação excessiva, ou um gargalo de armazenamento.","fix":"Meça a latência de I/O de disco (sys.dm_io_virtual_file_stats, latência de disco no Perfmon). Verifique o desempenho do armazenamento e a saúde do hardware. Revise se a memória é suficiente e a configuração max server memory. Examine os wait types (sys.dm_os_wait_stats, esperas PAGEIOLATCH). Elimine o gargalo de armazenamento; forneça discos mais rápidos/mais RAM se necessário.","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":"O dispositivo/arquivo de backup de destino não pôde ser aberto durante o backup ou restore. O SQL Server não conseguiu acessar o caminho especificado.","cause":"Caminho de pasta errado/inexistente, a conta de serviço do SQL Server sem permissão de gravação na pasta de destino, sem acesso a um compartilhamento de rede (UNC), disco cheio, ou o arquivo bloqueado por outro processo.","fix":"Verifique se o caminho do backup existe e está escrito corretamente. Conceda à conta de serviço do SQL Server permissão de gravação na pasta de destino. Para compartilhamentos UNC, verifique o acesso da conta de serviço. Certifique-se de que há espaço livre em disco suficiente. Para um caminho local, verifique se a letra da unidade é visível a partir do servidor (não uma unidade do cliente).","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","severity":"caution","meaning":"Um insert ou update tentou gravar, em campo(s) protegido(s) por um índice único, um valor que já existe na collection. O MongoDB rejeita a chave duplicada.","cause":"Colisão de _id, gravação do mesmo valor uma segunda vez em um campo com índice único, uma condição de corrida durante upsert, ou valores null colidindo em mais de um documento em um índice único (índice não sparse).","fix":"Verifique se o documento existe antes de gravar, ou use um upsert: db.collection.updateOne(filter, {$set:{...}}, {upsert:true}). Veja o nome do índice e o valor dup key na mensagem de erro. Se a unicidade não for realmente necessária, remova o índice; se os nulls forem o problema, use um índice partial/sparse. Na aplicação, capture o erro e tente novamente ou informe ao usuário.","tags":["duplicate key","duplicate key","unique index","unique","e11000","upsert","_id"]},{"code":"11000","title":"DuplicateKey (error code 11000)","severity":"caution","meaning":"O código numérico do erro de chave duplicada (retornado junto com o texto E11000). Uma operação de escrita violou uma constraint de índice único.","cause":"Gravação do mesmo campo único novamente, upserts concorrentes gerando a mesma chave, ou documentos duplicados em um bulk write.","fix":"Capture o código de erro 11000 no código da aplicação e implemente comportamento idempotente (atualizar se existir, inserir caso contrário). Em operações em massa, use ordered:false para permitir que os documentos que não são duplicados sejam gravados. Revise a regra de unicidade e a definição do índice.","tags":["duplicatekey","11000","duplicate","unique","unique","bulk write","write error"]},{"code":"13","title":"Unauthorized (error code 13)","severity":"caution","meaning":"O usuário autenticado não tem privilégio para a operação ou o recurso tentado. O usuário está logado, mas suas roles não cobrem essa ação.","cause":"A role necessária (por exemplo, readWrite, dbAdmin) não foi concedida ao usuário, a operação roda no banco de dados errado, ou os privilégios são insuficientes para um comando administrativo. Configuração de RBAC incompleta.","fix":"Verifique as roles do usuário: db.getUser(\"app_user\"). Conceda a role necessária: db.grantRolesToUser(\"app_user\", [{role:\"readWrite\", db:\"mydb\"}]). Certifique-se de que a operação roda no banco de dados correto. Atribua uma role built-in ou personalizada adequada seguindo o princípio do menor privilégio. Verifique o valor authSource na connection string.","tags":["unauthorized","unauthorized","authorization","role","role","rbac","13","permission"]},{"code":"18","title":"AuthenticationFailed (error code 18)","severity":"caution","meaning":"A autenticação falhou. O nome de usuário, a senha ou as credenciais fornecidos são inválidos; o usuário não conseguiu fazer login.","cause":"Nome de usuário/senha errados, banco de dados authSource errado, mecanismo de autenticação incompatível (SCRAM-SHA-1/SCRAM-SHA-256), ou o usuário não está definido no banco de dados especificado.","fix":"Verifique o nome de usuário e a senha. Especifique o authSource correto na connection string (o banco de dados em que o usuário foi criado, geralmente admin): ...?authSource=admin. Verifique se o mecanismo de autenticação é compatível com o servidor. Certifique-se de que o usuário foi criado no banco de dados correto. Faça URL-encode da senha se ela contiver caracteres especiais.","tags":["authentication failed","authentication","password","password","authsource","18","scram"]},{"code":"11600","title":"InterruptedAtShutdown (error code 11600)","severity":"danger","meaning":"A operação foi interrompida porque o servidor começou a ser desligado. A operação em andamento não pôde ser concluída porque o processo mongod estava parando.","cause":"Reinicialização/desligamento do mongod, desligamento durante um stepdown do primary do replica set, manutenção planejada, um crash, ou o processo encerrado pelo OOM killer.","fix":"Aguarde o servidor voltar e repita a operação. Na aplicação, capture erros transitórios e tente novamente de forma automática; habilite retryable writes. Para desligamentos inesperados, revise os logs do mongod e os logs do sistema (OOM, crash). Use um replica set para alta disponibilidade.","tags":["interrupted","shutdown","shutdown","downtime","11600","retry","replica set"]},{"code":"50","title":"MaxTimeMSExpired (error code 50)","severity":"caution","meaning":"O servidor cancelou a operação porque ela excedeu o limite de tempo definido com maxTimeMS. A consulta não foi concluída no tempo previsto.","cause":"Consultas de longa duração, varreduras de collection (COLLSCAN) causadas por falta de índices, grandes volumes de dados, operações pesadas de agregação ou alta carga no servidor.","fix":"Otimize a consulta: inspecione o plano com explain() e adicione um índice adequado. Se mais tempo for realmente necessário, aumente maxTimeMS. Simplifique agregações pesadas ou filtre cedo com $match. Divida os resultados com paginação. Verifique a carga do servidor e a capacidade de recursos.","tags":["maxtimems","timeout","timeout","50","slow query","slow query","index"]},{"code":"251","title":"NoSuchTransaction (error code 251)","severity":"caution","meaning":"A transação multidocumento referenciada não foi encontrada. A transação já terminou, expirou, ou foi usado um número de transação inválido.","cause":"A transação excedeu transactionLifetimeLimitSeconds e foi abortada automaticamente, a sessão terminou, um txnNumber errado/desatualizado, ou a continuação de uma transação que já havia sido abortada após um erro.","fix":"Reinicie a transação do início (com uma nova sessão). Mantenha as transações curtas; projete-as para terminar dentro do tempo de vida padrão (60 s). Para erros rotulados TransientTransactionError, repita a transação inteira com segurança. Se transações longas forem necessárias, revise a configuração transactionLifetimeLimitSeconds.","tags":["nosuchtransaction","transaction","transaction","251","session","abort","retry"]},{"code":"112","title":"WriteConflict (error code 112)","severity":"caution","meaning":"Um conflito de escrita que ocorre quando duas operações concorrentes tentam modificar o(s) mesmo(s) documento(s). Por causa do controle de concorrência otimista, o WiredTiger faz rollback de uma das operações.","cause":"Escritas altamente concorrentes nos mesmos documentos, atualizações conflitantes durante transações de longa duração, contenção intensa em um documento quente.","fix":"Repita a operação; o WriteConflict geralmente é transitório e se resolve com uma nova tentativa (ele é rotulado TransientTransactionError). Mantenha as transações curtas e reduza o número de documentos afetados. Revise o modelo de dados para reduzir a contenção no mesmo documento. Implemente retries com exponential backoff na aplicação.","tags":["writeconflict","write conflict","112","concurrency","concurrency","retry","wiredtiger"]},{"code":"133","title":"FailedToSatisfyReadPreference (error code 133)","severity":"danger","meaning":"Nenhum membro adequado do replica set foi encontrado para satisfazer a read preference especificada (por exemplo, primary, secondary). O driver não conseguiu selecionar um nó para encaminhar a requisição.","cause":"Membros do replica set inacessíveis/fora do ar, nenhum primary existe enquanto uma eleição está em andamento, uma partição de rede, nenhum membro atende aos critérios do tag set, ou a maioria (quorum) não pode ser alcançada.","fix":"Verifique o status do replica set: rs.status(). Verifique a saúde dos nós e a conectividade de rede. Aguarde a conclusão da eleição do primary e tente novamente. Revise sua configuração de read preference; se necessário, use uma preferência mais flexível (por exemplo, primaryPreferred). Se você usa tag sets, certifique-se de que existe um membro correspondente.","tags":["read preference","readpreference","133","replica set","election","secondary","primary"]},{"code":"6","title":"HostUnreachable (error code 6)","severity":"danger","meaning":"O driver/cliente não conseguiu alcançar o servidor MongoDB de destino (host). Nenhuma conexão pôde ser estabelecida no nível de rede.","cause":"O servidor está fora do ar, host/porta errados, bloqueio de firewall, problema de resolução de DNS, queda de rede, ou uma configuração de bindIp que exclui o cliente.","fix":"Verifique se o hostname e a porta estão corretos (padrão 27017). Verifique se o serviço mongod está em execução. Teste o firewall e o acesso de rede (ping/telnet). Certifique-se de que a configuração bindIp no mongod.conf permite o acesso do cliente. Verifique os registros DNS/SRV (para conexões mongodb+srv).","tags":["hostunreachable","host","connection","network","network","6","firewall","bindip"]},{"code":"89","title":"NetworkTimeout (error code 89)","severity":"danger","meaning":"Uma operação de rede durante a comunicação com o servidor não foi concluída no tempo previsto e expirou. A conexão foi estabelecida, mas a resposta não chegou a tempo.","cause":"Rede lenta ou instável, servidor sobrecarregado, uma operação de longa duração atrasando a resposta, valores de socket/connect timeout definidos baixos demais, ou congestionamento de rede.","fix":"Meça a latência e a estabilidade da rede. Verifique a carga e os recursos do servidor. Defina connectTimeoutMS e socketTimeoutMS no driver com valores realistas. Capture erros transitórios e tente novamente. Otimize consultas lentas para reduzir os tempos de resposta.","tags":["networktimeout","network timeout","89","timeout","socket","network","retry"]},{"code":"262","title":"ExceededTimeLimit (error code 262)","severity":"caution","meaning":"A operação excedeu o limite de tempo permitido no lado do servidor e foi encerrada. Exceder maxTimeMS ou limites de tempo internos pode causar este erro.","cause":"Uma consulta/comando de longa duração, execução lenta por falta de índice, agregação pesada, varredura de um grande conjunto de dados, ou alta carga no servidor.","fix":"Inspecione a consulta com explain() e adicione um índice adequado. Divida a operação em partes menores. Defina maxTimeMS de acordo com a necessidade real. Reduza os dados cedo no pipeline de agregação com $match/$project. Verifique se os recursos do servidor são suficientes.","tags":["exceededtimelimit","time limit","262","timeout","maxtimems","slow","index"]},{"code":"292","title":"QueryExceededMemoryLimitNoDiskUseAllowed (error code 292)","severity":"caution","meaning":"Uma consulta ou estágio de agregação excedeu o limite de memória permitido (padrão 100 MB) e falhou porque a gravação em disco não era permitida. Geralmente visto em estágios de sort ou group.","cause":"Ordenação em memória sobre grandes volumes de dados sem índice, estágios de agregação $group/$sort grandes, conjuntos de resultados intermediários muito grandes, a configuração allowDiskUse:false.","fix":"Permita o uso de disco (spill) na agregação com a opção allowDiskUse:true: db.collection.aggregate(pipeline, {allowDiskUse:true}). Reduza o uso de memória indexando os campos ordenados. Filtre o pipeline cedo com $match para reduzir os dados processados. Pagine os resultados se necessário. No MongoDB 6.0+, o uso de disco é habilitado por padrão na maioria dos casos.","tags":["memory limit","memory limit","292","allowdiskuse","sort","aggregation","group"]},{"code":"26","title":"NamespaceNotFound (error code 26)","severity":"safe","meaning":"O namespace referenciado (database.collection) não foi encontrado. A collection ou o índice especificado não existe.","cause":"Nome de collection grafado incorretamente, uma collection ainda não criada, o contexto de banco de dados errado, ou uma tentativa de operação de drop/índice em uma collection inexistente.","fix":"Verifique o nome da collection e o banco de dados: show collections. Lembre-se de que os nomes diferenciam maiúsculas de minúsculas. O MongoDB cria uma collection automaticamente na primeira gravação; se necessário, crie-a explicitamente com db.createCollection(). Para operações como drop, verifique antes se a collection existe.","tags":["namespacenotfound","namespace","collection missing","26","collection","not found","not found"]},{"code":"43","title":"CursorNotFound (error code 43)","severity":"caution","meaning":"O cursor do lado do servidor não existe mais. Quando o cliente solicita o próximo lote (getMore), o erro é retornado porque o cursor não é encontrado.","cause":"O cursor expirou (padrão de 10 minutos de inatividade), espera longa demais entre lotes, reinicialização do servidor, ou o cursor foi fechado explicitamente.","fix":"Processe os resultados do cursor mais rapidamente; não espere muito entre os lotes. Para operações de longa duração, use a opção noCursorTimeout com cuidado (mongosh: cursor.noCursorTimeout(); PyMongo: no_cursor_timeout=True) e sempre feche o cursor; um cursor dentro de uma sessão é fechado no timeout da sessão (localLogicalSessionTimeoutMinutes, padrão 30 min) mesmo com essa opção. Para grandes conjuntos de resultados, itere com um batchSize menor ou use paginação baseada em intervalo. Reinicie a operação e consulte novamente.","tags":["cursornotfound","cursor","cursor","43","getmore","timeout","batch","pagination"]},{"code":"211","title":"KeyNotFound (error code 211)","severity":"caution","meaning":"Uma chave/valor esperado não foi encontrado. Geralmente indica uma inconsistência relacionada ao gerenciamento interno de chaves, chaves de sessão ou à collection oplog/keys.","cause":"Chaves de assinatura ausentes/excluídas na collection admin.system.keys, problemas de sincronização de relógio no replica set/sharded cluster, problemas de keyfile/rotação de chaves, ou estado interno corrompido.","fix":"Verifique a sincronização de relógio (NTP) entre os membros do replica set. Verifique o conteúdo de admin.system.keys e a geração de chaves. Revise o status do cluster (rs.status(), sh.status()). Se persistir, analise os logs do mongod e revise a configuração de keyfile/identidade. Certifique-se de que o primary está funcionando corretamente para que as chaves possam ser regeneradas.","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":"Um comando foi executado contra uma chave que não é apropriada para o tipo de dado dessa chave. Por exemplo, aplicar um comando de list (LPUSH) ou hash (HSET) a uma chave que contém uma string.","cause":"A chave é de um tipo diferente do esperado, o mesmo nome de chave é usado com tipos de dados diferentes, confusão de tipos na lógica da aplicação, ou uma chave antiga/remanescente sendo sobrescrita.","fix":"Verifique o tipo da chave: TYPE mykey. Escolha o comando de acordo com o tipo real da chave. Diferencie os tipos na nomenclatura das chaves (por exemplo, um set para user:1:tags, uma string para user:1:name). Se necessário, exclua a chave antiga (DEL) e recrie-a com o tipo correto. Garanta a consistência de tipos na camada da aplicação.","tags":["wrongtype","wrong type","type","data type","key","key"]},{"code":"OOM","title":"OOM command not allowed when used memory > 'maxmemory'","severity":"danger","meaning":"A memória usada pelo Redis atingiu o limite maxmemory e os comandos de escrita são rejeitados porque a política de eviction não consegue liberar espaço para novos dados. A memória está cheia; não é possível gravar.","cause":"O limite maxmemory foi excedido, a política noeviction está selecionada (nenhuma chave é removida), dados sem TTL continuam crescendo, vazamento de memória, ou RAM insuficiente para o limite.","fix":"Inspecione o uso de memória: INFO memory e MEMORY USAGE. Escolha uma política de eviction adequada (por exemplo, allkeys-lru ou volatile-lru): CONFIG SET maxmemory-policy allkeys-lru. Defina TTLs nas chaves para que sejam limpas automaticamente. Aumente maxmemory/RAM. Encontre e reduza big keys (redis-cli --bigkeys). Expurgue dados desnecessários.","tags":["oom","out of memory","memory","maxmemory","eviction","memory","danger"]},{"code":"NOAUTH","title":"NOAUTH Authentication required","severity":"caution","meaning":"O Redis exige autenticação, mas o cliente tentou executar um comando antes de se autenticar. Ele precisa fazer login com AUTH primeiro.","cause":"Uma senha requirepass/ACL está definida no servidor, o cliente não envia o comando AUTH, a senha não está na connection string, ou o AUTH não é repetido após a conexão ser restabelecida.","fix":"Autentique-se antes de executar comandos: AUTH password (com ACLs, AUTH app_user password). Adicione a senha ao cliente/à connection string. Se você usa um pool de conexões, certifique-se de que o AUTH é executado em toda nova conexão. Armazene a senha com segurança (variável de ambiente/secrets manager).","tags":["noauth","authentication","authentication","auth","password","requirepass","acl"]},{"code":"WRONGPASS","title":"WRONGPASS invalid username-password pair or user is disabled","severity":"caution","meaning":"O par usuário/senha informado no comando AUTH é inválido, ou o usuário ACL está desabilitado. A autenticação foi rejeitada.","cause":"Senha errada, nome de usuário ACL errado, o usuário está desabilitado na ACL, o valor de requirepass mudou, ou um problema de escape/codificação na senha.","fix":"Informe o nome de usuário e a senha corretos. Inspecione o usuário ACL: ACL LIST e ACL GETUSER app_user. Se o usuário estiver desabilitado, habilite-o (ACL SETUSER app_user on ...). Verifique a senha definida com requirepass (CONFIG GET requirepass). Ao redefinir a senha, certifique-se de que todos os clientes sejam atualizados.","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":"Um comando de escrita foi enviado a um nó réplica (slave). As réplicas são somente leitura por padrão; gravações só podem ser feitas no master.","cause":"O cliente se conecta a uma réplica em vez do master, o antigo master virou réplica após um failover, roteamento para o nó errado no Sentinel/Cluster, ou um load balancer encaminhando gravações para uma réplica.","fix":"Encaminhe as requisições de escrita para o nó master. Se você usa Sentinel, consulte o master atual no Sentinel (SENTINEL get-master-addr-by-name). No Cluster, grave no master do shard correto. Configure a separação de leitura/escrita na biblioteca cliente. Após um failover, atualize as conexões para que apontem para o novo master.","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":"O link entre a réplica e o master está fora do ar e, como replica-serve-stale-data está definido como 'no', a réplica se recusa a responder às requisições com dados desatualizados.","cause":"O nó master travou ou está inacessível, queda/partição de rede, o link de replicação master-réplica caiu, ou o master não consegue responder sob carga pesada.","fix":"Verifique o status do nó master e a conectividade de rede. Inspecione o status da replicação: INFO replication. Coloque o master de volta no ar, ou deixe ocorrer um failover via Sentinel/Cluster. Se servir dados desatualizados for aceitável, considere replica-serve-stale-data yes (atenção ao risco de consistência). Use Sentinel/Cluster para alta disponibilidade.","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":"O Redis Cluster não está totalmente operacional. Alguns hash slots não são atendidos por nenhum nó, então o cluster rejeita as requisições.","cause":"Nós master acessíveis insuficientes, um ou mais slots não atribuídos/não cobertos, perda da maioria (quorum), crashes de nós, ou alguns slots inacessíveis enquanto cluster-require-full-coverage está como yes.","fix":"Verifique o estado do cluster: CLUSTER INFO e CLUSTER NODES. Coloque de volta no ar os masters que caíram, ou deixe as réplicas serem promovidas. Reatribua os slots não atribuídos (redis-cli --cluster fix ou CLUSTER ADDSLOTS). Verifique se todos os slots estão cobertos. Se a operação parcial for aceitável, considere 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":"O Redis está iniciando e carregando o dataset (RDB/AOF) do disco para a memória. A maioria dos comandos é temporariamente rejeitada até a conclusão do carregamento.","cause":"O servidor acabou de iniciar, um arquivo RDB/AOF grande está sendo carregado, uma réplica está fazendo full sync a partir do master, ou um processo de recuperação após uma reinicialização.","fix":"Aguarde o fim do carregamento; a duração depende do tamanho dos dados. Monitore o status: INFO persistence (aguarde enquanto loading:1; pronto quando 0). Na aplicação, capture esse erro transitório e tente novamente em intervalos curtos. Para reduzir o tempo de carregamento, revise a estratégia de dataset/persistência (RDB vs AOF). Forneça RAM suficiente e discos rápidos.","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":"Um script Lua ou function de longa duração está em execução e excedeu busy-reply-threshold (chamado lua-time-limit antes do Redis 7; padrão 5000 ms). Como o Redis é single-threaded, ele não consegue processar outros comandos durante esse tempo; apenas SCRIPT KILL (FUNCTION KILL para functions) ou SHUTDOWN NOSAVE são aceitos.","cause":"Um loop infinito ou um script/function Lua de execução muito longa, computação pesada, um script iterando sobre grandes volumes de dados, ou uma chamada EVAL mal escrita.","fix":"Se o script não modificou dados, interrompa-o: SCRIPT KILL. Se o script já realizou gravações, SCRIPT KILL não funciona; como último recurso para preservar a consistência dos dados, pode ser necessário SHUTDOWN NOSAVE (dados não salvos são perdidos; tenha cuidado). Escreva scripts curtos e determinísticos. Divida operações longas em partes. Revise a configuração busy-reply-threshold (antes 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","severity":"danger","meaning":"O Redis está configurado para gerar snapshots RDB, mas não consegue gravar em disco. Nesse estado, se stop-writes-on-bgsave-error estiver habilitado, o Redis rejeita todos os comandos de escrita.","cause":"Disco cheio, problemas de permissão no sistema de arquivos, um diretório sem permissão de escrita, erros no salvamento em segundo plano (BGSAVE), falha de fork por memória insuficiente, ou um problema no hardware de disco.","fix":"Libere espaço em disco e verifique a permissão de escrita no diretório do RDB (dir). Inspecione o último erro de BGSAVE: INFO persistence e os logs do Redis. Para permitir gravações temporariamente até o problema ser corrigido, pode-se definir stop-writes-on-bgsave-error no (atenção ao risco de durabilidade). Garanta memória suficiente para o fork e a configuração vm.overcommit_memory=1. Verifique a configuração de persistência (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":"No Redis Cluster, foi usado um comando multichave (por exemplo, MGET, MSET, SUNION), mas as chaves caem em hash slots diferentes. Operações multichave exigem que todas as chaves estejam no mesmo slot.","cause":"No modo cluster, comandos que acessam várias chaves de uma vez são chamados com chaves espalhadas por slots diferentes. As chaves são distribuídas para nós diferentes porque não usam hash tag.","fix":"Use uma hash tag para colocar chaves relacionadas no mesmo slot: fixe parte do nome da chave com chaves {} (por exemplo, {user1}:profile e {user1}:settings vão para o mesmo slot). Use comandos multichave apenas com chaves que compartilham a mesma hash tag. Como alternativa, divida as operações em comandos de chave única.","tags":["crossslot","cross slot","cluster","cluster","hash tag","slot","mget","mset"]},{"code":"MOVED","title":"MOVED slot ip:port (cluster redirect)","severity":"safe","meaning":"No Redis Cluster, o hash slot que contém a chave solicitada pertence a outro nó. O servidor redireciona o cliente permanentemente para o nó correto. Trata-se de um redirecionamento, não de um erro.","cause":"Um cliente que não é cluster-aware envia uma requisição ao nó errado, os slots foram redistribuídos entre os nós (resharding), ou o mapa de slots em cache no cliente está desatualizado.","fix":"Use uma biblioteca cliente cluster-aware; elas seguem a resposta MOVED automaticamente, redirecionam para o nó correto e atualizam o mapa de slots. Use a flag -c ao conectar com redis-cli. Certifique-se de que seu cliente atualiza periodicamente a topologia de slots (CLUSTER SLOTS/SHARDS).","tags":["moved","cluster","cluster","redirect","redirect","slot","resharding"]},{"code":"ASK","title":"ASK slot ip:port (cluster redirect)","severity":"safe","meaning":"No Redis Cluster, um slot está sendo migrado para outro nó, e a chave solicitada pode estar temporariamente no nó de destino. O servidor redireciona o cliente ao nó de destino apenas para esta requisição (redirecionamento temporário).","cause":"Acesso a uma chave que já foi transferida dentro de um slot em migração durante o resharding. Ao contrário do MOVED, não é permanente; vale apenas naquele momento.","fix":"Clientes cluster-aware tratam redirecionamentos ASK automaticamente: enviam o comando ASKING ao nó de destino e repetem a requisição, mas não atualizam o mapa de slots permanentemente. Use uma biblioteca cliente adequada, e a flag -c no redis-cli. Quando o resharding termina, os redirecionamentos passam a ser MOVED e permanentes.","tags":["ask","asking","cluster","cluster","migration","migration","redirect","redirect"]},{"code":"NOSCRIPT","title":"NOSCRIPT No matching script. Please use EVAL","severity":"caution","meaning":"O digest SHA1 do script Lua chamado com EVALSHA não foi encontrado no script cache do servidor. O Redis não conhece um script correspondente a esse hash.","cause":"O servidor foi reiniciado ou o script cache foi limpo com SCRIPT FLUSH, o script nunca foi carregado, ou o cache está vazio no novo nó após um failover.","fix":"Execute o script com o corpo completo via EVAL (o Redis o armazena em cache automaticamente), ou carregue-o primeiro com SCRIPT LOAD e use o SHA retornado no EVALSHA. Na aplicação, capture o erro NOSCRIPT e implemente uma lógica de fallback de EVALSHA para EVAL. Muitas bibliotecas cliente do Redis fazem isso automaticamente.","tags":["noscript","script","evalsha","eval","lua","sha","script load","cache"]},{"code":"EXECABORT","title":"EXECABORT Transaction discarded because of previous errors","severity":"caution","meaning":"Uma transação em um bloco MULTI/EXEC foi abortada por causa de erros ocorridos na fase de enfileiramento. O EXEC rejeita a transação sem executar nenhum comando.","cause":"Um comando entre MULTI e EXEC contém um erro de sintaxe, ou erros detectados durante o enfileiramento, como um nome de comando inexistente ou um número errado de argumentos. Esses erros invalidam a transação inteira.","fix":"Corrija a sintaxe e os argumentos dos comandos no bloco MULTI. Verifique as respostas ao enfileirar os comandos; se algum comando retornar um erro em vez de QUEUED, a transação é abortada no EXEC. Reconstrua a transação com comandos válidos. Observação: transações do Redis não fazem rollback; apenas erros de enfileiramento levam ao EXECABORT, e erros em tempo de execução não interrompem os demais comandos.","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]] (antes do 7.x: FORBIDDEN/12/index read-only / allow delete (api))","severity":"danger","meaning":"Como o uso de disco excedeu o flood stage watermark (padrão 95%; em discos grandes determinado por max_headroom), o Elasticsearch aplicou um bloqueio read_only_allow_delete nos índices que têm um shard no nó afetado, para evitar que o disco se encha por completo. Por causa desse bloqueio, gravações no índice (index/update/delete de documentos) não são possíveis; apenas a exclusão do próprio índice é permitida. O ES 8.x retorna este erro com HTTP 429.","cause":"O uso de disco em pelo menos um nó excedeu o limite cluster.routing.allocation.disk.watermark.flood_stage. Mesmo que o bloqueio seja removido manualmente, o Elasticsearch o reaplica enquanto o disco continuar cheio. Índices grandes sem rotação de logs, snapshots não limpos ou capacidade de disco insuficiente são causas típicas.","fix":"Primeiro libere espaço em disco: exclua índices antigos/desnecessários (DELETE /old-index), faça um snapshot e remova índices, ou aumente o disco. No 7.4+, o bloqueio é removido automaticamente quando o uso de disco cai abaixo do high watermark; para removê-lo imediatamente sem esperar, remova-o manualmente: PUT /_all/_settings {\"index.blocks.read_only_allow_delete\": null}. Para uma correção permanente, exclua/arquive dados antigos automaticamente com ILM (Index Lifecycle Management) e revise as configurações de watermark (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 (legado: FORBIDDEN/12/index read-only / allow delete (api))","severity":"danger","meaning":"O índice está somente leitura porque index.blocks.read_only_allow_delete é true; novos documentos não podem ser gravados nem atualizados, apenas o índice pode ser excluído. O Elasticsearch geralmente define isso automaticamente quando o flood stage watermark de disco é excedido; o ES 8.x retorna HTTP 429 para as requisições de escrita.","cause":"O bloqueio foi definido automaticamente porque o uso de disco excedeu o limite de flood stage, ou a configuração foi definida como true manualmente. Se o bloqueio for removido sem liberar espaço em disco, o Elasticsearch o reaplica.","fix":"Libere espaço em disco suficiente. No 7.4+, um bloqueio definido automaticamente se remove sozinho quando o uso de disco cai abaixo do high watermark; para um bloqueio definido manualmente, ou para removê-lo sem esperar, remova o bloqueio: PUT /_all/_settings {\"index.blocks.read_only_allow_delete\": null}. Para um único índice: PUT /index-name/_settings {\"index.blocks.read_only_allow_delete\": null}. Se continuar se repetindo, aumente a capacidade de disco, configure uma política de ILM e monitore qual nó está enchendo com _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":"O uso de disco de um nó excedeu o limite de high watermark (padrão 90%) ou de flood stage (padrão 95%). Quando o high watermark é excedido, o Elasticsearch tenta mover shards desse nó para outros nós; quando o flood stage é excedido, ele torna os índices somente leitura.","cause":"O disco está enchendo: índices de log/métricas em crescimento contínuo, índices antigos nunca excluídos, um repositório de snapshots não limpo, um disco subdimensionado, ou um único nó enchendo demais por distribuição desbalanceada de shards.","fix":"Inspecione o uso de disco: GET _cat/allocation?v. Exclua índices antigos ou faça snapshot e remova-os, e aumente o disco. Você pode elevar os limites temporariamente (com cuidado; no 8.x defina os três juntos por causa da validação de max_headroom): 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%\"}}. Depois de resolvido, volte aos padrões definindo as mesmas configurações como null (configurações transient estão obsoletas; não as use). Correção permanente: gerenciamento de ciclo de vida com ILM, limpeza regular de índices e planejamento de capacidade. Se os índices ficaram somente leitura por causa do flood stage, remova o bloqueio separadamente.","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":"Uma requisição foi rejeitada porque excederia o limite do circuit breaker de memória (heap). O Elasticsearch interrompe a requisição antecipadamente para evitar que o nó trave com um OutOfMemoryError. O breaker [parent] protege o uso total de memória; o breaker [fielddata] protege a memória de fielddata em campos text.","cause":"JVM heap insuficiente, agregações muito grandes/complexas, grandes conjuntos de resultados, grandes requisições bulk, fielddata carregado em campos text, ou muitas consultas pesadas concorrentes enchendo o heap. Geralmente é um sintoma de pressão no heap.","fix":"Reduza as consultas: diminua o tamanho das agregações, o tamanho dos lotes bulk e os campos retornados. Agregue no subcampo keyword (.keyword) em vez de fielddata em campos text. Aumente o JVM heap (~50% da RAM do servidor, no máximo ~31GB). Monitore a pressão no heap: GET _cat/nodes?v&h=name,heap.percent. Corrija a causa raiz (memória/consulta) em vez de elevar temporariamente os limites dos breakers. Verifique qual breaker disparou com 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":"Ao indexar um documento, o valor enviado para um campo não correspondeu ao tipo definido para esse campo no mapping e não pôde ser analisado. Por exemplo, texto enviado a um campo definido como integer, ou um formato de data inválido enviado a um campo definido como date.","cause":"Incompatibilidade de tipo de campo (uma string para um campo numérico, um formato malformado para um campo de data), uma data que não corresponde ao formato de data esperado, JSON malformado/incompleto, campos com tipo errado definidos dinamicamente, ou um valor escalar enviado onde se espera um objeto.","fix":"Verifique o nome do campo e o tipo esperado na mensagem de erro: GET /index-name/_mapping. Faça o valor no documento corresponder ao tipo do campo, ou redefina o mapping com o tipo correto. Para campos de data, faça o parâmetro format corresponder ao formato do documento. O tipo de um campo existente não pode ser alterado; se necessário, crie um novo índice e mova os dados com _reindex. Valide os dados na camada da aplicação.","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","severity":"caution","meaning":"Como o mapping do índice ou do objeto está definido como \"dynamic\": \"strict\", um documento contendo um novo campo não definido no mapping foi rejeitado. O modo strict impede que campos fora do schema sejam adicionados silenciosamente.","cause":"Um campo ausente do mapping foi enviado no documento (erro de digitação, campo novo, campo inesperado) enquanto o mapping está como dynamic:strict. Geralmente é uma proteção deliberada para manter o controle rígido do schema.","fix":"Corrija ou remova o campo extra/grafado incorretamente no documento. Se o campo for realmente necessário, adicione-o primeiro ao mapping: PUT /index-name/_mapping {\"properties\": {\"new_field\": {\"type\": \"...\"}}}. Se quiser que novos campos sejam adicionados automaticamente, defina dynamic como \"true\", ou como \"false\" se eles devem ser armazenados mas não indexados. Use o modo strict deliberadamente para preservar a disciplina do schema.","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","severity":"caution","meaning":"Foi tentada uma agregação, ordenação ou script em um campo text analisado. Essas operações vêm desabilitadas por padrão em campos text porque exigem fielddata, que é caro em memória.","cause":"Uma agregação/ordenação foi aplicada diretamente a um campo text. No Elasticsearch, text é usado para busca full-text e keyword para agregação/ordenação por valor exato; misturar os dois produz este erro.","fix":"Use o subcampo keyword do campo para agregação/ordenação (por exemplo, \"my_field.keyword\"). Se o campo for apenas text, adicione um subcampo keyword ao mapping (multi-field) e execute _reindex. Habilitar fielddata em um campo text (fielddata=true) é possível, mas não recomendado devido ao alto consumo de memória e ao risco de circuit breaker; use apenas quando for inevitável.","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":"Uma requisição de busca falhou em um ou em todos os shards necessários. É um erro genérico de busca que encapsula a causa subjacente real; a seção \"caused by\" informa o problema real (erro de parse, breaker, tipo de campo inadequado, shard inacessível etc.).","cause":"Sintaxe de consulta inválida, agregação no tipo de campo errado, too_many_clauses, disparo de circuit breaker, um shard não atribuído/inacessível, timeout de consulta ou crash de nó. A causa raiz está na exceção interna da resposta.","fix":"Encontre a exceção real nos detalhes \"caused by\" / \"failed_shards\" da resposta e corrija de acordo (corrija a consulta, use um campo keyword, configurações de breaker/heap, alocação de shards). Verifique a saúde do cluster: GET _cluster/health e GET _cat/shards?v. Se resultados parciais forem permitidos e alguns shards falharam, revise o comportamento de 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":"Uma consulta excedeu o número máximo permitido de cláusulas Lucene. No ES 8.x esse limite não é fixo; ele é calculado automaticamente a partir do tamanho do heap do nó e do número de threads de busca (pode cair para 1024 em nós com heap pequeno), e a mensagem de erro mostra o valor atual. Consultas bool muito grandes e consultas que se expandem para muitos termos o disparam.","cause":"Consultas bool geradas programaticamente com milhares de cláusulas should/must; consultas wildcard/prefix/fuzzy/query_string que se expandem para muitos termos; estruturas bool profundamente aninhadas. Observação: a consulta terms (uma lista de valores em um único campo) não está sujeita a esse limite; seu teto é index.max_terms_count (padrão 65,536).","fix":"Simplifique a consulta: converta muitas cláusulas term em um único campo em uma consulta terms (ou um terms lookup para listas grandes). Use tipos de consulta mais específicos ou campos index_prefixes/keyword em vez de wildcard/prefix. No ES 8.x a configuração indices.query.bool.max_clause_count está obsoleta e é ignorada; a forma de elevar o limite é aumentar o heap do nó. Revise a lógica de geração das consultas.","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":"Uma requisição de update/delete de documento foi rejeitada pelo controle de concorrência otimista. A versão do documento (ou _seq_no/_primary_term) não corresponde à da requisição; ou seja, outra pessoa modificou o documento depois que você o leu. Retorna HTTP 409.","cause":"Atualizações concorrentes no mesmo documento, uma gravação tentada com version/seq_no desatualizado, uma tentativa de criar (op_type=create) um documento que já existe, ou uma condição de corrida durante _bulk.","fix":"Leia o documento novamente e repita a requisição com o _seq_no e o _primary_term (ou version) atuais (loop read-modify-write). Para retries automáticos, use o parâmetro retry_on_conflict na requisição _update; em _update_by_query/_delete_by_query passe conflicts=proceed para pular os documentos em conflito e continuar. Se a intenção for apenas criar, o conflito é normal; capture o 409 na aplicação e trate-o adequadamente (repetir ou pular).","tags":["version-conflict","409","concurrency","optimistic","seq-no","caution"]},{"code":"document_missing_exception","title":"document_missing_exception: [_doc][id]: document missing","severity":"caution","meaning":"O documento a ser atualizado (_update) não foi encontrado no índice. Um update exige um documento existente; se o documento não existir, ocorre esta exceção.","cause":"O documento foi excluído anteriormente, nunca foi criado, o _id errado foi usado, a requisição foi para o índice errado, ou um documento gravado com routing personalizado foi acessado sem routing. (GET e _update são em tempo real; o atraso de refresh não causa este erro.)","fix":"Verifique se o _id e o índice de destino estão corretos: GET /index-name/_doc/id. Se quiser o comportamento atualizar-se-existir/criar-se-não-existir, use upsert (ou doc_as_upsert:true) na requisição _update. Crie o documento diretamente com index (PUT). Na aplicação, capture esta exceção e recorra à lógica de 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":"O índice (ou alias) solicitado não existe. A operação foi rejeitada com HTTP 404 porque nenhum índice com o nome informado foi encontrado.","cause":"O índice nunca foi criado, foi excluído, o nome do índice/alias tem um erro de digitação, o cliente está conectado ao ambiente (cluster) errado, ou houve tentativa de gravar em um índice inexistente enquanto action.auto_create_index está desabilitado.","fix":"Liste os índices existentes: GET _cat/indices?v. Verifique o nome e o alias: GET _alias. Crie o índice: PUT /index-name (com os mappings/settings necessários), ou configure a criação automática com um index template. Se a criação automática for desejada, verifique a configuração action.auto_create_index. Verifique se você não está conectado ao cluster errado.","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":"O índice (ou recurso) a ser criado já existe. A requisição de criação foi rejeitada porque existe um índice com o mesmo nome. Em versões mais antigas também aparece como index_already_exists_exception.","cause":"Tentativa de criar o mesmo índice duas vezes, scripts de setup não idempotentes, requisições de criação concorrentes, ou uma tentativa de recriar o mesmo nome com configurações diferentes.","fix":"Se o índice já existe, não é necessário criá-lo; continue. Se ele precisar ser recriado, exclua-o primeiro (DELETE /index-name) e depois crie-o (cuidado: perda de dados). Torne os scripts de setup idempotentes: verifique primeiro a existência com GET _cat/indices. Evite conflitos usando index templates ou ILM/rollover para o gerenciamento de schema.","tags":["already-exists","resource-already-exists","index","create","idempotent","safe"]},{"code":"cluster_health_red","title":"cluster health status: RED / shards não atribuídos","severity":"danger","meaning":"Cluster health RED significa que pelo menos um primary shard não está atribuído e está indisponível. É um estado crítico em que alguns dados não podem ser lidos/gravados, com risco de perda parcial de dados. (YELLOW significa que apenas as réplicas não estão atribuídas; os primaries estão intactos.)","cause":"Um nó travou/saiu e os primary shards nele ficaram sem cópia, a alocação está bloqueada pelo disk watermark, um shard corrompido, um erro durante o restore de snapshot, ou configurações de alocação impedindo a atribuição de shards.","fix":"Veja por que os shards não estão atribuídos: GET _cluster/allocation/explain ou GET _cat/shards?v&h=index,shard,prirep,state,unassigned.reason. Traga de volta os nós que travaram; se for um problema de disco, libere espaço (watermark). Se a alocação foi bloqueada temporariamente, dispare a realocação: POST _cluster/reroute?retry_failed=true. Se um primary foi totalmente perdido, restaure a partir de um snapshot. No estado RED, concentre-se primeiro em recuperar os primaries.","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":"Não foi encontrada nenhuma cópia ativa de shard capaz de atender a uma requisição. A requisição não pode ser atendida porque o shard correspondente não está atribuído, está em recuperação, ou o nó que o hospeda está inacessível.","cause":"Crash de nó/partição de rede, shards não atribuídos, uma recuperação de shard em andamento, um bloqueio de alocação devido ao disk watermark, ou o cluster no estado RED/YELLOW.","fix":"Inspecione o estado do cluster e dos shards: GET _cluster/health e GET _cat/shards?v. Veja por que os shards não estão atribuídos: GET _cluster/allocation/explain. Traga de volta os nós que travaram, corrija o problema de disco e aguarde a recuperação terminar: GET _cat/recovery?v&active_only=true. Se necessário, repita a alocação com 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":"Uma operação foi rejeitada porque a capacidade da fila do thread pool correspondente (search, write/bulk etc.) está cheia. Sob sobrecarga, o Elasticsearch se protege recusando requisições (backpressure) e retorna HTTP 429 (Too Many Requests).","cause":"Volume muito alto de requisições concorrentes, requisições bulk muito grandes ou muito frequentes, carga pesada de agregação/busca, recursos de nó/CPU insuficientes, ou uma fila de thread pool pequena demais para a carga de trabalho.","fix":"Repita no lado do cliente com exponential backoff; o 429 normalmente é transitório. Reduza o tamanho dos lotes bulk e a taxa de envio, e diminua a concorrência. Monitore as operações rejeitadas: GET _cat/thread_pool?v&h=node_name,name,active,queue,rejected. Para carga sustentada, adicione nós/recursos (escalabilidade horizontal). Aumentar o tamanho da fila é o último recurso; a causa raiz é capacidade.","tags":["rejected-execution","429","thread-pool","queue","bulk","backpressure","danger"]},{"code":"master_not_discovered_exception","title":"master_not_discovered_exception / MasterNotDiscoveredException","severity":"danger","meaning":"O cluster não conseguiu eleger/encontrar um nó master ativo. Sem master, alocação de shards, alterações de mapping e atualizações do cluster state não podem ocorrer; o cluster fica incapaz de processar operações.","cause":"A maioria (quorum) dos nós master-eligible está inacessível, uma partição de rede (prevenção de split brain), configuração incorreta de discovery.seed_hosts / cluster.initial_master_nodes, ausência de bootstrap em uma nova instalação, ou poucos nós master-eligible.","fix":"Verifique se os nós master-eligible estão em execução e conseguem se ver: GET _cat/nodes?v e GET _cluster/state. Verifique as configurações discovery.seed_hosts e cluster.initial_master_nodes (no primeiro setup). Verifique a rede/firewall e a conectividade entre nós (transport 9300). Mantenha nós master-eligible suficientes (de preferência 3) em execução. Inspecione os logs em busca de mensagens de eleição do master.","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":"A autenticação (401 Unauthorized) ou a autorização (403 Forbidden) falhou. 401 indica credenciais ausentes/incorretas; 403 indica que o usuário está autenticado, mas não tem a role/o privilégio necessário para esta ação/este índice.","cause":"Nome de usuário/senha ou API key errados, header Authorization ausente, token expirado/inválido, o usuário sem o privilégio de índice ou de cluster correspondente, ou atribuição de role ausente/incorreta.","fix":"Para 401: envie as credenciais/API key corretas e verifique o header Authorization. Para 403: inspecione as roles e os privilégios do usuário (GET _security/user/app_user, GET _security/role/app_role) e adicione os privilégios de índice/cluster necessários. Siga o princípio do menor privilégio. Se você usa uma API key, verifique sua expiração e permissões.","tags":["security","401","403","authentication","authorization","security","danger"]},{"code":"validation_exception","title":"validation_exception / illegal_argument_exception: Validation Failed: ...","severity":"caution","meaning":"Os parâmetros ou as configurações de uma requisição falharam na validação. O Elasticsearch rejeitou a requisição com valores inválidos ou inconsistentes sem executá-la (por exemplo, número de shards inválido, combinação de configurações incompatível, campo obrigatório ausente).","cause":"Uma configuração de índice inválida (por exemplo, number_of_shards negativo/zero), uma tentativa de atualizar uma configuração não modificável em um índice existente, uma combinação de parâmetros incompatível, um campo obrigatório ausente, ou um valor fora do intervalo.","fix":"Leia o detalhe da validação na mensagem de erro; ele informa claramente qual parâmetro é inválido e por quê. Coloque o valor em um intervalo/formato válido. Especifique as configurações não modificáveis (static) ao criar um novo índice, não em um índice existente (_reindex se necessário). Forneça os campos obrigatórios que a API espera. Verifique os valores válidos documentados da configuração.","tags":["validation","validation","settings","illegal-argument","invalid","caution"]},{"code":"task_cancelled_exception","title":"task_cancelled_exception: Task was cancelled / TaskCancelledException","severity":"caution","meaning":"Uma tarefa em execução (search, _reindex, _update_by_query etc.) foi cancelada. O cancelamento pode ocorrer por uma solicitação do usuário a _tasks/_cancel, pelo cliente fechando a conexão HTTP (timeout/abort do cliente; o Elasticsearch cancela automaticamente a busca associada), ou pelo cancelamento de uma tarefa pai ou de uma async search expirada.","cause":"O usuário cancelou a tarefa com POST _tasks/<task_id>/_cancel (X-Opaque-Id apenas identifica e ajuda a encontrar a tarefa; não a cancela), um timeout do cliente derrubou a conexão, consultas caras de longa duração, ou o gerenciamento adaptativo de recursos interrompeu uma tarefa pesada.","fix":"Se a tarefa foi cancelada inesperadamente, revise as configurações de timeout e de conexão do cliente; otimize a consulta pesada (menos dados, filtros mais específicos). Para operações longas, execute _reindex/_update_by_query de forma assíncrona (wait_for_completion=false) e monitore com GET _tasks. Veja as tarefas ativas: GET _tasks?detailed=true. Se necessário, divida as consultas caras ou use 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","severity":"danger","meaning":"Ocorreu um erro durante o SQL recursivo que o Oracle executa internamente em segundo plano. É um erro envoltório (externo) que oculta o erro real; a causa real está no segundo código de erro listado logo abaixo dele.","cause":"Acesso ao data dictionary, um trigger de DDL com falha, tablespace SYSTEM cheio, espaço temporário insuficiente, um objeto do data dictionary corrompido, ou um trigger de LOGON com falha executado no login da sessão.","fix":"Leia a segunda linha que segue o ORA-00604 na pilha de erros; essa é a causa real, e corrija-a. Por exemplo, se você vir ORA-01653, estenda o tablespace. Se houver suspeita de um trigger de DDL/LOGON, desabilite-o temporariamente: ALTER TRIGGER trigger_name DISABLE; Verifique o uso dos tablespaces SYSTEM e TEMP com 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":"Um número que excede os limites de precisão e escala definidos foi gravado em uma coluna NUMBER. Por exemplo, um valor com parte inteira de 3 dígitos não cabe em uma coluna NUMBER(4,2).","cause":"A definição NUMBER(p,s) da coluna é estreita demais para os dados; o resultado de um cálculo é maior que o esperado; a escala decimal reduz os dígitos restantes para a parte inteira (NUMBER(5,3) permite apenas 2 dígitos inteiros).","fix":"Amplie a capacidade da coluna para corresponder ao intervalo real dos dados: ALTER TABLE my_table MODIFY (my_column NUMBER(12,2)); Arredonde o valor na aplicação, ou ajuste-o à escala com ROUND/TRUNC. Para encontrar a linha que estoura, restrinja sua consulta durante os testes, e adicione validação de entrada.","tags":["number","precision","precision","scale","scale","overflow","numeric"]},{"code":"ORA-01400","title":"cannot insert NULL into (column)","severity":"caution","meaning":"Um valor NULL foi inserido ou definido em uma coluna com constraint NOT NULL. Um campo obrigatório não pode ficar vazio.","cause":"Nenhum valor fornecido para uma coluna obrigatória em um INSERT, um UPDATE definindo a coluna como NULL, nenhum DEFAULT definido para a coluna, ou um valor vazio vindo de uma subconsulta/da aplicação.","fix":"Forneça um valor válido para a coluna indicada na mensagem de erro. Defina um padrão adequado para a coluna: ALTER TABLE my_table MODIFY (my_column DEFAULT 0); (DEFAULT só se aplica quando a coluna é totalmente omitida do INSERT; para valores NULL enviados explicitamente, use o DEFAULT ON NULL do 12c+: ALTER TABLE my_table MODIFY (my_column DEFAULT ON NULL 0);) Se a regra não for realmente obrigatória, remova a constraint: ALTER TABLE my_table MODIFY (my_column NULL); Valide os valores vazios na aplicação antes de enviá-los.","tags":["not null","null","empty","insert","constraint","constraint","mandatory"]},{"code":"ORA-02291","title":"integrity constraint violated - parent key not found","severity":"danger","meaning":"Uma constraint de foreign key foi violada. Não foi encontrada nenhuma linha pai correspondente ao valor inserido na tabela filha; ou seja, o registro referenciado não existe.","cause":"Um INSERT/UPDATE referenciando um registro pai inexistente, a linha da tabela pai ainda não inserida, a ordem de carga errada (filho antes do pai), ou a correspondência falhando por diferenças de maiúsculas/minúsculas ou de espaços em branco.","fix":"Insira primeiro o registro correspondente na tabela pai, depois na tabela filha. Verifique se a referência existe: SELECT * FROM parent_table WHERE key_col = value; Em cargas em massa, processe as tabelas na ordem correta (primeiro o pai). Para encontrar a linha que viola, compare o valor na tabela filha com a tabela pai usando NOT IN / um anti-join.","tags":["fk","foreign key","foreign key","constraint","constraint","parent","reference"]},{"code":"ORA-02292","title":"integrity constraint violated - child record found","severity":"danger","meaning":"Uma linha pai foi excluída ou teve sua chave alterada, mas a constraint de foreign key não permitiu porque existem registros filhos dependentes.","cause":"Tentativa de DELETE de uma linha pai que tem registros na tabela filha; a FK está definida sem ON DELETE CASCADE; os registros dependentes não foram limpos antes.","fix":"Primeiro exclua os registros filhos dependentes ou mova-os para outro registro pai, depois exclua a linha pai. Se a regra de negócio permitir, recrie a foreign key com 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; Para encontrar as linhas dependentes, consulte a tabela filha pela chave pai.","tags":["fk","foreign key","foreign key","child","child record","delete","cascade"]},{"code":"ORA-00979","title":"not a GROUP BY expression","severity":"caution","meaning":"Uma coluna não agregada foi usada na lista do SELECT junto com uma função de agregação (SUM, COUNT etc.), mas a coluna não foi adicionada à cláusula GROUP BY. O Oracle não sabe como agrupar essa coluna.","cause":"Uma coluna presente no SELECT, mas não no GROUP BY; expressões fora das funções de agregação ausentes da lista do GROUP BY; inconsistência no HAVING ou nas expressões do select.","fix":"Adicione todas as colunas não agregadas à lista do GROUP BY: SELECT department, COUNT(*) FROM employee GROUP BY department; Como alternativa, envolva também essa coluna em uma função de agregação (MAX, MIN), ou redesenhe o agrupamento com uma função analítica (OVER()).","tags":["group by","grouping","aggregate","aggregation","sum","count","query"]},{"code":"ORA-00918","title":"column ambiguously defined","severity":"caution","meaning":"Existe uma coluna com o mesmo nome em mais de uma tabela da consulta e, como ela é usada sem prefixo de tabela/alias, o Oracle não consegue determinar a qual tabela ela pertence.","cause":"Ambas as tabelas do join têm uma coluna com o mesmo nome (por exemplo, ID nas duas); a coluna é usada sem qualificação (sem prefixo) no SELECT, WHERE ou ORDER BY.","fix":"Qualifique toda coluna ambígua com o nome ou o alias da tabela: SELECT a.id, b.id FROM tableA a JOIN tableB b ON a.id = b.a_id; Dê aliases curtos às tabelas e prefixe todas as colunas para melhorar a legibilidade e a clareza.","tags":["ambiguous","ambiguous column","column","column","join","alias","query"]},{"code":"ORA-06550","title":"line/column PLS-... PL/SQL compilation error","severity":"caution","meaning":"Foi encontrado um erro de sintaxe ou semântico ao compilar um bloco PL/SQL, uma procedure ou um bloco anônimo. O código falhou na fase de compilação antes de poder ser executado.","cause":"Erros de digitação, referência a uma variável ou objeto não declarado, uma chamada com número/tipo errado de parâmetros, um ponto e vírgula faltando, uma chamada a uma procedure/package inexistente, ou um privilégio ausente.","fix":"Vá até o número de linha e coluna na mensagem de erro; leia o subcódigo PLS-XXXX. Para ver todos os erros de compilação: SHOW ERRORS; ou SELECT * FROM user_errors WHERE name = 'OBJECT_NAME'; Verifique os nomes dos objetos, as assinaturas de parâmetros e os GRANTs necessários, e então recompile.","tags":["plsql","compilation","compile","pls","syntax","procedure","code"]},{"code":"ORA-04068","title":"existing state of packages has been discarded","severity":"caution","meaning":"Enquanto uma sessão em execução usava o estado de um package, o package foi recompilado, e esse estado foi invalidado. A instância do package mantida pela sessão não é mais válida.","cause":"O body ou a specification de um package foi recompilado com ALTER/CREATE OR REPLACE enquanto sessões dependentes dele estavam ativas; geralmente ocorre durante o deploy da aplicação em um sistema em produção. Visto junto com ORA-04061/04065.","fix":"Executar a chamada novamente (retry) geralmente resolve; na segunda tentativa o package é carregado em sua nova forma. Capture o ORA-04068 na aplicação e tente novamente de forma automática. Aplique as alterações de packages em janelas de manutenção, quando a atividade dos usuários for baixa. Um design de package stateless reduz esse problema.","tags":["package","package","state","package state","recompile","compile","retry"]},{"code":"ORA-01427","title":"single-row subquery returns more than one row","severity":"caution","meaning":"Uma subconsulta da qual se esperava uma única linha retornou mais de uma linha. Por exemplo, a subconsulta do lado direito de uma comparação de igualdade (=) produziu vários valores.","cause":"Uma subconsulta retornando várias linhas onde se espera = ou uma atribuição; uma condição WHERE insuficientemente restrita; uma correspondência não única na correlação; uma subconsulta escalar na lista do SELECT retornando várias linhas.","fix":"Restrinja a subconsulta para que ela retorne uma única linha (WHERE adicional, chave única). Se vários valores forem realmente esperados, use IN em vez de =: WHERE id IN (SELECT id FROM ...). Ou adicione uma agregação à subconsulta (MAX, MIN), ou reduza-a a uma linha com ROWNUM = 1. Primeiro execute a subconsulta isoladamente e verifique quantas linhas ela retorna.","tags":["subquery","subquery","single row","single row","in","scalar","query"]},{"code":"ORA-12899","title":"value too large for column","severity":"caution","meaning":"Um valor maior que o comprimento máximo definido foi gravado em uma coluna de caracteres/dados. Por exemplo, um texto de 15 caracteres não cabe em uma coluna VARCHAR2(10).","cause":"A largura da coluna é insuficiente para os dados; em um character set multibyte (UTF8) o número de caracteres excede o limite em bytes (semântica BYTE); um character set diferente durante a migração de dados; o resultado de uma concatenação ficando mais longo.","fix":"Amplie a coluna: ALTER TABLE my_table MODIFY (my_column VARCHAR2(100)); Para conteúdo multibyte, use a semântica CHAR: my_column VARCHAR2(100 CHAR). Se valores longos precisarem ser encurtados, trunque-os com SUBSTR. A mensagem de erro informa o comprimento real e o permitido; encontre o registro que estoura com 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":"Em uma instrução MERGE (ou um join atualizável), o lado de origem produziu mais de uma linha correspondente para a mesma linha de destino. O Oracle interrompeu a operação porque não consegue decidir com qual valor de origem atualizar.","cause":"A origem do MERGE ... USING contém correspondências duplicadas para a condição ON; a consulta de origem não é única na chave de destino; várias linhas de origem mapeiam para a mesma linha de destino.","fix":"Torne a consulta de origem única na chave de destino. Encontre as correspondências duplicadas: SELECT key_col, COUNT(*) FROM (source_query) GROUP BY key_col HAVING COUNT(*) > 1; Elimine as duplicatas da origem com DISTINCT ou uma função de agregação/analítica (ROW_NUMBER), e então execute o MERGE novamente. Certifique-se de que a condição ON é seletiva o suficiente.","tags":["merge","merge","duplicate","duplicate rows","source","source","stable"]},{"code":"ORA-08103","title":"object no longer exists","severity":"danger","meaning":"Um objeto (tabela, índice, segmento LOB) acessado por uma consulta em execução não existe mais, ou sua estrutura física mudou. Geralmente ocorreu um DDL/TRUNCATE sob o objeto enquanto a consulta estava em andamento.","cause":"O mesmo objeto sofreu TRUNCATE/DROP/SHRINK enquanto a consulta estava aberta; uma movimentação (MOVE) ou manutenção de partições; um índice/segmento corrompido; a estrutura subjacente desaparecendo enquanto um segmento LOB é acessado; um conflito com DDL concorrente.","fix":"Verifique se o objeto ainda existe e é válido: SELECT status FROM user_objects WHERE object_name = 'NAME'; Reconstrua o índice/objeto correspondente (REBUILD) ou execute a consulta novamente. Evite TRUNCATE/DROP em objetos enquanto consultas de longa duração os utilizam. Se houver suspeita de corrupção, verifique com ANALYZE ... VALIDATE STRUCTURE.","tags":["object","object","truncate","drop","ddl","corruption","segment"]},{"code":"ORA-01843","title":"not a valid month","severity":"caution","meaning":"Ao converter texto em DATE, a parte do mês não pôde ser interpretada como um mês válido. Geralmente o formato de data não corresponde ao formato dos dados.","cause":"Nenhuma máscara de formato passada ao TO_DATE e o NLS_DATE_FORMAT da sessão não corresponde aos dados; dia e mês trocados (confusão DD/MM vs MM/DD); uma diferença de idioma/locale (nos nomes dos meses); texto de data corrompido ou inesperado.","fix":"Sempre passe um formato explícito nas chamadas TO_DATE: TO_DATE('2026-07-04', 'YYYY-MM-DD'). Para textos com nomes de meses, especifique o idioma: TO_DATE(str, 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE=ENGLISH'). Defina o formato da sessão se necessário: ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD'. Valide os textos de data inválidos antes de carregar.","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":"O valor da partition key na linha inserida não mapeia para nenhuma partição definida na tabela. Não existe nenhuma partição range ou list que cubra o valor.","cause":"No particionamento RANGE, uma data/valor acima do maior intervalo foi inserido e não há partição MAXVALUE; no particionamento LIST, um valor novo que não está definido; a nova partição não foi criada com antecedência na virada de mês/ano.","fix":"Adicione a partição que falta: ALTER TABLE my_table ADD PARTITION p_2026_08 VALUES LESS THAN (TO_DATE('2026-09-01','YYYY-MM-DD')); Para RANGE, adicione uma partição MAXVALUE como rede de segurança. Defina uma partição DEFAULT para LIST para capturar valores inesperados. Use particionamento automático (INTERVAL partitioning) para que novas partições sejam criadas automaticamente.","tags":["partition","partition","partition key","range","list","maxvalue","insert"]},{"code":"ORA-01536","title":"space quota exceeded for tablespace","severity":"danger","meaning":"A cota de espaço do usuário no tablespace especificado se esgotou. Mesmo que o tablespace tenha espaço livre, não é possível alocar novo espaço porque o limite concedido ao usuário foi excedido.","cause":"O usuário tem uma cota limitada (não UNLIMITED); a cota se encheu com o crescimento dos dados; uma carga excessiva em uma tabela/índice; gravação no tablespace errado; segmentos crescendo mais rápido que o esperado.","fix":"Aumente a cota do usuário: ALTER USER app_user QUOTA UNLIMITED ON tablespace_name; ou defina um valor específico: QUOTA 500M ON users. Veja o uso atual: SELECT * FROM dba_ts_quotas WHERE username = 'APP_USER'. Arquive/expurgue segmentos desnecessariamente grandes ou mova objetos para um tablespace adequado.","tags":["quota","quota","tablespace","space","space","user","user"]},{"code":"direct path read","title":"Espera: sessão lendo blocos diretamente para a PGA, contornando o buffer cache","severity":"caution","meaning":"A sessão passa tempo neste evento de espera ao ler blocos diretamente para a memória PGA em vez de pelo buffer cache do banco de dados. Geralmente está associado a grandes full table scans e consultas paralelas.","cause":"Muitos blocos lidos do disco por causa de full scans de tabelas grandes, consultas paralelas, operações de sort/hash despejando no tablespace temporário, a decisão de serial direct path read para full scans seriais, e consultas que não conseguem usar um índice.","fix":"Identifique o SQL que faz full scans pesados com AWR/ASH e adicione índices adequados. Reduza varreduras desnecessárias de tabelas grandes por meio de tuning de consultas. Investigue a latência do armazenamento (I/O) e migre para discos mais rápidos se necessário. Revise o grau de paralelismo. Para operações que despejam no TEMP, avalie o tamanho de PGA_AGGREGATE_TARGET.","tags":["wait","wait","direct path read","full scan","full table scan","io","pga"]},{"code":"latch: cache buffers chains","title":"Espera: contenção no latch cache buffers chains","severity":"danger","meaning":"Há contenção no latch cache buffers chains (CBC), que protege os blocos no buffer cache. Esta espera aumenta quando muitas sessões tentam acessar os mesmos blocos acessados com frequência (hot blocks).","cause":"Hot blocks lidos com frequência; SQL ineficiente gerando muitas leituras lógicas; acesso repetido aos mesmos blocos raiz de índice em nested loop joins; acesso concorrente intenso distribuído de forma desigual; tabelas pequenas, mas muito lidas.","fix":"Encontre o SQL que gera mais leituras lógicas (V$SQL, ASH) e reduza o acesso ao buffer melhorando os índices/o plano de acesso. Identifique os hot blocks (X$BH / views relacionadas). Considere converter nested loops desnecessários em hash joins. Para tabelas de referência pequenas e muito lidas, distribua o padrão de acesso ou faça cache delas.","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":"A função (ou operador) chamada na consulta não foi encontrada com este nome e estes tipos de argumentos. O PostgreSQL resolve funções tanto pelo nome quanto pelos tipos de argumentos; se a assinatura não corresponder, este erro é gerado.","cause":"Nome de função grafado incorretamente; tipos de argumentos que não correspondem à assinatura definida (por exemplo, um número em vez de texto); falta de um cast explícito; o schema da função fora do search_path; a extensão necessária não instalada.","fix":"Verifique se a função existe e confira sua assinatura: \\df function_name. Faça cast explícito dos argumentos: SELECT fn(value::text). Adicione o prefixo de schema ou defina o search_path. Se uma extensão for necessária, instale-a: CREATE EXTENSION extension_name; Para erros de operador, faça os tipos dos dois lados corresponderem.","tags":["function","function not found","undefined","operator","cast","type conversion","42883"]},{"code":"42804","title":"datatype_mismatch","severity":"caution","meaning":"O tipo de dado esperado e o tipo de dado fornecido não correspondem. Por exemplo, atribuir um valor do tipo errado a uma coluna, ramos de CASE retornando tipos diferentes, ou ramos de UNION cujos tipos não se alinham.","cause":"Uma atribuição incompatível com o tipo da coluna; ramos de CASE/COALESCE produzindo tipos diferentes; colunas correspondentes em um UNION com tipos diferentes; um valor retornado (RETURN) que não corresponde ao tipo de retorno da função; um valor não booleano onde se espera um booleano.","fix":"Faça cast da expressão para o tipo correto: value::integer ou CAST(value AS numeric). Faça todos os ramos do CASE retornarem o mesmo tipo. Em um UNION, alinhe os tipos das colunas correspondentes dos dois lados. Certifique-se de que a condição WHERE resulta em um booleano.","tags":["type","data type","mismatch","type mismatch","cast","union","42804"]},{"code":"22P02","title":"invalid_text_representation","severity":"caution","meaning":"Um valor de texto não era uma representação válida para o tipo de dado de destino durante a conversão. Por exemplo, tentar converter o texto 'abc' em integer gera este erro.","cause":"Texto não numérico enviado a uma coluna/parâmetro numérico; uma string vazia ('') convertida em número/data; texto inválido para um UUID ou enum; JSON malformado; dados de entrada fora do formato esperado.","fix":"Verifique se o valor convertido é realmente válido. Valide a entrada na aplicação antes da conversão de tipo. Converta strings vazias em NULL: NULLIF(value, ''). Para uma conversão segura no PostgreSQL 16+, teste o valor antes com pg_input_is_valid('abc', 'integer') e use pg_input_error_info() para os detalhes do erro; em versões mais antigas, considere uma verificação de validação (regex). Restrinja a busca para descobrir qual linha está com problema.","tags":["cast","type conversion","invalid text","invalid input","integer","uuid","22P02"]},{"code":"22003","title":"numeric_value_out_of_range","severity":"caution","meaning":"Um valor numérico está fora do intervalo permitido pelo tipo de destino. Por exemplo, gravar um valor maior que 2 bilhões em uma coluna integer, ou um número grande demais para uma coluna numeric(5,2).","cause":"Ultrapassagem dos limites de smallint/integer/bigint; ultrapassagem da precisão/escala de numeric(p,s); overflow aritmético; uma soma/produto excedendo a capacidade do tipo; uma sequence atingindo o limite superior do seu tipo.","fix":"Altere a coluna/o parâmetro para um tipo mais amplo (bigint em vez de integer, aumente a precisão do numeric): ALTER TABLE my_table ALTER COLUMN my_column TYPE bigint; Arredonde (ROUND) ou valide o valor de acordo com a regra de negócio. Se um cálculo intermediário estourar, calcule a expressão como numeric. Para overflow de sequence, amplie o tipo.","tags":["numeric","number","out of range","overflow","numeric overflow","integer","22003"]},{"code":"23514","title":"check_violation","severity":"caution","meaning":"Uma constraint CHECK foi violada. A linha inserida ou atualizada não satisfaz uma condição lógica definida na tabela (por exemplo, price > 0).","cause":"Dados que violam uma regra de negócio (preço negativo, código de status inválido, violação de intervalo de datas); ausência de validação no lado da aplicação; uma constraint rígida demais para os dados; registros que quebram a regra durante uma carga em massa.","fix":"Use o nome da constraint na mensagem de erro para descobrir qual condição foi violada; veja a definição: \\d table_name. Consulte as linhas que violam invertendo a condição. Corrija os dados ou, se a regra realmente mudou, atualize a constraint: 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":"Uma expressão aritmética tentou uma divisão (ou módulo) por zero. O PostgreSQL não permite divisão por zero e aborta a consulta.","cause":"A coluna/expressão divisora avaliando como 0; um denominador zero em um cálculo de razão/percentual; divisão por um COUNT ou SUM igual a zero; valores zero inesperados em dados não filtrados.","fix":"Use NULLIF para retornar NULL quando o denominador for zero: numerator / NULLIF(denominator, 0). Se desejar, transforme o resultado em um valor padrão com COALESCE: COALESCE(numerator / NULLIF(denominator,0), 0). Ou use CASE WHEN denominator = 0 THEN NULL ELSE numerator/denominator END. Filtre os casos com zero nos dados antecipadamente.","tags":["division","divide","zero","divide by zero","nullif","arithmetic","22012"]},{"code":"42601","title":"syntax_error","severity":"caution","meaning":"Foi encontrado um erro de sintaxe na instrução SQL. O PostgreSQL não conseguiu analisar a consulta e informa a localização aproximada (position) do erro.","cause":"Vírgula ou parêntese faltando/sobrando; uma palavra-chave reservada (como user, order) usada como nome de coluna sem aspas; ponto e vírgula faltando; um comando grafado incorretamente; um literal string não terminado; uso de sintaxe específica de versão.","fix":"Use o valor 'position' na mensagem de erro para localizar o problema; inspecione a parte imediatamente anterior. Coloque palavras reservadas entre aspas duplas: \"order\". Verifique se parênteses e aspas estão balanceados. Teste uma consulta complexa dividindo-a em partes. Consulte a documentação da sua versão para a sintaxe correta.","tags":["syntax","syntax error","parse","parser","keyword","position","42601"]},{"code":"42P07","title":"duplicate_table","severity":"caution","meaning":"A tabela (ou objeto similar) que está sendo criada já existe. O CREATE falhou porque existe um objeto com o mesmo nome.","cause":"Recriação de uma tabela existente com CREATE TABLE; execução do script duas vezes; reaplicação de migrations; conflito de nome com uma view/sequence/índice de mesmo nome.","fix":"Use IF NOT EXISTS para pular a criação quando o objeto já existir: CREATE TABLE IF NOT EXISTS my_table (...). Se você realmente quiser recriá-la, remova-a primeiro: DROP TABLE IF EXISTS my_table; Torne as migrations seguras para reexecução (idempotentes). Verifique o objeto existente com \\dt.","tags":["duplicate","duplicate object","table","relation","create","already exists","42P07"]},{"code":"42701","title":"duplicate_column","severity":"caution","meaning":"O mesmo nome de coluna foi usado mais de uma vez em uma definição de tabela ou operação ALTER, ou uma coluna já existente foi adicionada novamente.","cause":"Escrever o mesmo nome de coluna duas vezes no CREATE TABLE; adicionar uma coluna já existente com ALTER TABLE ADD COLUMN; um erro de copiar e colar; uma migration executada novamente.","fix":"Remova ou renomeie o nome de coluna duplicado na definição da tabela. Verifique antes para não adicionar novamente uma coluna existente: \\d table_name. Onde a versão suportar, adicione com segurança: ALTER TABLE my_table ADD COLUMN IF NOT EXISTS my_column type; Certifique-se de que as migrations são idempotentes.","tags":["duplicate","duplicate column","column","column exists","alter","add column","42701"]},{"code":"3D000","title":"invalid_catalog_name","severity":"danger","meaning":"O banco de dados ao qual você está tentando se conectar ou acessar não existe. Nenhum banco de dados com o nome informado foi encontrado.","cause":"Nome de banco de dados grafado incorretamente na connection string; o banco de dados ainda não criado ou removido; sensibilidade a maiúsculas/minúsculas; conexão ao servidor errado; um nome errado na configuração de ambiente (env).","fix":"Liste os bancos de dados existentes: psql -l ou SELECT datname FROM pg_database. Corrija o nome do banco de dados na connection string. Crie-o se necessário: CREATE DATABASE database_name; Verifique se você está se conectando ao servidor/à porta corretos. Verifique o nome do BD na configuração da aplicação.","tags":["database","database not found","catalog","does not exist","missing","connection","3D000"]},{"code":"3F000","title":"invalid_schema_name","severity":"caution","meaning":"O schema referenciado não existe ou não é encontrado no search_path. Não existe nenhum schema com o nome informado.","cause":"Nome de schema grafado incorretamente; o schema nunca criado; search_path sem incluir o schema; uma diferença de maiúsculas/minúsculas; prefixo errado ao acessar um objeto com prefixo de schema.","fix":"Liste os schemas existentes: \\dn ou SELECT schema_name FROM information_schema.schemata. Corrija o nome do schema. Crie-o se necessário: CREATE SCHEMA schema_name; Defina o search_path: SET search_path TO schema_name, public; Acesse os objetos com o prefixo de schema correto.","tags":["schema","schema not found","search_path","does not exist","missing","invalid","3F000"]},{"code":"0A000","title":"feature_not_supported","severity":"caution","meaning":"O recurso que você está tentando usar não é suportado neste contexto ou nesta versão do PostgreSQL. Mesmo que a operação solicitada possa ser válida, ela não pode ser aplicada na situação atual.","cause":"Sintaxe/recurso ainda não disponível na versão; um ALTER não suportado para um tipo específico de coluna/tabela; uma operação não suportada por um foreign data wrapper (FDW); restrições em combinações de replicação lógica/constraints; conversões não permitidas para certos tipos de dados.","fix":"Leia a mensagem de erro completa; ela geralmente informa claramente o que não é suportado. Use uma abordagem alternativa (por exemplo, nova coluna + cópia + renomeação em vez de alterar o tipo da coluna diretamente). Se o recurso chegou em uma versão mais nova, considere fazer upgrade. Se você atingir limites de FDW/extensão, consulte a documentação.","tags":["not supported","unsupported","feature","unsupported feature","version","upgrade","0A000"]},{"code":"57P03","title":"cannot_connect_now","severity":"danger","meaning":"O servidor não pode aceitar conexões agora; geralmente o banco de dados ainda está iniciando ou realizando recovery. As conexões podem ser abertas assim que o sistema estiver pronto.","cause":"O PostgreSQL acabou de ser iniciado e ainda está na fase de startup/recovery; crash recovery; durante um restore a partir de backup; um standby ainda não pronto para aceitar consultas; um desligamento em andamento.","fix":"Aguarde um pouco e reconecte; o servidor aceita conexões assim que o startup termina. Monitore o progresso do recovery no log do servidor. Se demorar, pode haver um grande replay de WAL ou um problema de recovery. Adicione lógica de retry à aplicação.","tags":["connection","connection refused","starting up","startup","recovery","crash recovery","57P03"]},{"code":"2BP01","title":"dependent_objects_still_exist","severity":"caution","meaning":"A remoção foi bloqueada porque outros objetos dependem do objeto que está sendo removido. O DROP falha enquanto existirem objetos dependentes.","cause":"Tentativa de remover uma tabela enquanto views/foreign keys/funções dependem dela; objetos dependentes de um tipo ou schema; DROP sem CASCADE; uma coluna/sequence referenciada por outros objetos.","fix":"Remova primeiro os objetos dependentes ou faça o drop com CASCADE: DROP TABLE my_table CASCADE; (lembre-se de que o CASCADE também remove os objetos dependentes; tenha cuidado). Para ver as dependências, leia o detalhe do erro (linha DETAIL) ou inspecione pg_depend/os catálogos correspondentes. Planeje corretamente a ordem de remoção.","tags":["dependency","dependent objects","cascade","drop","objects","object","2BP01"]},{"code":"55006","title":"object_in_use","severity":"danger","meaning":"A operação não pode ser executada no objeto de destino (geralmente um banco de dados) porque ele está sendo usado por outras sessões. Por exemplo, um banco de dados com conexões ativas não pode ser removido.","cause":"Conexões abertas com o banco de dados durante o DROP DATABASE; uma operação que exige lock exclusivo em um objeto em uso; outra sessão mantendo o objeto.","fix":"Encontre e encerre as conexões abertas com o banco de dados de destino: SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'db_name' AND pid <> pg_backend_pid(); Bloqueie novas conexões (se necessário). No PostgreSQL 13+, remova-o fechando as conexões à força: 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":"Um valor de texto não estava em um formato válido ao ser convertido para um tipo de data/hora (date, time, timestamp). O valor não corresponde ao formato de data-hora esperado.","cause":"Texto de data em formato inesperado (confusão na ordem dia/mês/ano); valores de dia/hora inválidos; conversão de uma string vazia ('') em data; componentes ausentes ou extras; incompatibilidade de locale/formato; uma máscara de formato errada para to_timestamp/to_date.","fix":"Converta o texto de data com o formato correto: to_date('2026-07-04', 'YYYY-MM-DD') ou to_timestamp(str, 'YYYY-MM-DD HH24:MI:SS'). Prefira o formato ISO 8601 (YYYY-MM-DD). Transforme valores vazios em NULL com NULLIF(value,''). Valide os dados de entrada antes de carregar; restrinja a busca para encontrar a linha com problema.","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":"Existe uma coluna com o mesmo nome em mais de uma tabela da consulta e, como ela é usada sem prefixo de tabela/alias, o MySQL não consegue saber a qual tabela ela pertence.","cause":"Ambas as tabelas do join têm uma coluna com o mesmo nome (por exemplo, id nas duas); a coluna escrita sem qualificação (sem prefixo) no SELECT, WHERE, ON, GROUP BY ou ORDER BY.","fix":"Qualifique toda coluna ambígua com o nome ou o alias da tabela: SELECT a.id, b.id FROM a JOIN b ON a.id = b.a_id; Dê aliases curtos às tabelas e prefixe todas as colunas em conflito. Reduza a ambiguidade em joins por colunas comuns com 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":"O número de colunas na instrução INSERT não corresponde ao número de valores na lista VALUES. Cada coluna deve receber exatamente um valor.","cause":"A lista de colunas e a lista de valores de um INSERT com comprimentos diferentes; em um INSERT sem lista de colunas, os valores não correspondendo ao número de colunas da tabela; uma vírgula faltando/sobrando; a estrutura da tabela mudou, mas o script não foi atualizado.","fix":"Iguale o número de colunas e o número de valores. Sempre use uma lista de colunas explícita: INSERT INTO my_table (a, b, c) VALUES (1, 2, 3); Verifique a estrutura da tabela: DESCRIBE my_table; Faça os valores corresponderem um a um com as colunas e corrija vírgulas extras/faltantes.","tags":["column count","column count mismatch","insert","values","mismatch","value count","1136"]},{"code":"1048","title":"Column 'x' cannot be null","severity":"caution","meaning":"Houve uma tentativa de inserir NULL em uma coluna definida como NOT NULL, ou de definir essa coluna como NULL. Um campo obrigatório não pode ficar vazio.","cause":"Nenhum valor informado para uma coluna obrigatória no INSERT; um UPDATE definindo a coluna como NULL; nenhum DEFAULT para a coluna; um valor vazio vindo da aplicação/de uma subconsulta; o SQL mode estrito não preenchendo silenciosamente o valor vazio.","fix":"Forneça um valor válido para a coluna obrigatória. Defina um padrão adequado para a coluna: ALTER TABLE my_table MODIFY my_column INT NOT NULL DEFAULT 0; Se a regra for desnecessária, permita NULL: ALTER TABLE my_table MODIFY my_column INT NULL; Valide os valores vazios na aplicação antes de enviá-los.","tags":["not null","null","empty value","insert","cannot be null","mandatory","1048"]},{"code":"1292","title":"Incorrect datetime value / truncated incorrect value","severity":"caution","meaning":"Um valor era inválido ou malformado ao ser convertido para o tipo da coluna de destino (especialmente data/hora ou numérico). No modo estrito, o MySQL o rejeita como erro.","cause":"Datas ou valores inválidos como '0000-00-00'; formato de data errado; texto não numérico em uma coluna numérica; SQL mode estrito (STRICT_TRANS_TABLES) ativo; problemas de conversão causados por um character set/collation diferente.","fix":"Coloque o valor em um formato válido para o tipo da coluna ('YYYY-MM-DD' para datas). Use NULL em vez de datas vazias/inválidas. Se necessário, informe um formato explícito com STR_TO_DATE: STR_TO_DATE(str, '%Y-%m-%d'). Se for necessária tolerância temporária, revise o sql_mode, mas de preferência corrija os dados. Restrinja a busca para encontrar a linha problemática.","tags":["datetime","date","truncated","incorrect value","strict mode","format","1292"]},{"code":"1406","title":"Data too long for column","severity":"caution","meaning":"Foi gravado um valor maior que o comprimento máximo definido da coluna. Por exemplo, uma string de 20 caracteres não cabe em uma coluna VARCHAR(10).","cause":"Largura da coluna pequena demais para os dados; caracteres em um character set multibyte (utf8mb4) ocupando mais espaço que o esperado; o resultado de uma concatenação ficando mais longo; SQL mode estrito ativo (caso contrário, o valor é truncado silenciosamente).","fix":"Amplie a coluna: ALTER TABLE my_table MODIFY my_column VARCHAR(255); Para conteúdo muito longo, considere o tipo TEXT. Se o valor precisar ser encurtado, corte-o na aplicação ou com SUBSTRING. Encontre a linha que estoura: SELECT * FROM my_table WHERE CHAR_LENGTH(my_column) > 10; Adicione validação de entrada.","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":"O índice (ou chave) que está sendo criado excedeu o comprimento máximo permitido em bytes. Especialmente com character sets multibyte, índices VARCHAR atingem esse limite rapidamente.","cause":"Um índice em uma coluna VARCHAR larga com utf8mb4 (4 bytes por caractere); um row format antigo do InnoDB (REDUNDANT/COMPACT; no 5.7 e anteriores também innodb_large_prefix desabilitado); o comprimento total de um índice composto de várias colunas excedendo o limite; uma primary key grande.","fix":"Reduza o comprimento da coluna indexada ou use um prefix index: CREATE INDEX idx ON my_table (my_column(191)); Passe para o limite de 3072 bytes com o row format DYNAMIC/COMPRESSED (DYNAMIC é o padrão no MySQL 8.0; innodb_large_prefix foi removido no 8.0 e só é necessário no 5.7 e anteriores). Se necessário, revise o character set/comprimento da coluna.","tags":["index","index length","key too long","key","prefix","utf8mb4","1071"]},{"code":"1050","title":"Table already exists","severity":"caution","meaning":"A tabela que está sendo criada já existe. O CREATE TABLE falhou porque existe uma tabela com o mesmo nome.","cause":"Recriação de uma tabela existente; um script executado duas vezes; migrations aplicadas novamente; outro objeto (uma view) usando o mesmo nome.","fix":"Use IF NOT EXISTS para criar a tabela somente se ela não existir: CREATE TABLE IF NOT EXISTS my_table (...); Se você realmente quiser recriá-la, remova-a primeiro: DROP TABLE IF EXISTS my_table; Liste as tabelas existentes: SHOW TABLES; Torne as migrations seguras para reexecução (idempotentes).","tags":["table exists","table already exists","duplicate","duplicate table","create table","1050"]},{"code":"1051","title":"Unknown table 'x'","severity":"caution","meaning":"A tabela referenciada não existe. Nenhuma tabela com o nome informado foi encontrada durante um drop, alter ou consulta.","cause":"Nome de tabela grafado incorretamente; a tabela nunca criada ou já removida; o banco de dados (schema) errado selecionado; sensibilidade a maiúsculas/minúsculas (nomes de tabelas diferenciam maiúsculas de minúsculas no Linux); DROP TABLE em uma tabela inexistente.","fix":"Liste as tabelas existentes: SHOW TABLES; e selecione o banco de dados certo: USE mydb; Corrija o nome da tabela e suas maiúsculas/minúsculas. Para evitar o erro no drop: DROP TABLE IF EXISTS my_table; Se ela estiver em outro schema, qualifique-a como 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","severity":"caution","meaning":"A coluna, o índice ou a foreign key que está sendo removida com ALTER TABLE não existe. Não é possível remover um objeto inexistente.","cause":"Informar um nome de objeto inexistente em DROP COLUMN/INDEX/FOREIGN KEY; um nome grafado incorretamente; o objeto já removido; confusão entre o nome da foreign key e o nome do índice; uma migration executada uma segunda vez.","fix":"Verifique o nome real do objeto: SHOW CREATE TABLE my_table; ou SHOW INDEX FROM my_table; Remova-o usando o nome correto. Para uma foreign key, use o nome do seu símbolo: ALTER TABLE my_table DROP FOREIGN KEY fk_name; O MySQL não tem a sintaxe DROP COLUMN IF EXISTS (apenas o MariaDB tem); em migrations idempotentes, verifique primeiro se a coluna existe via 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","severity":"caution","meaning":"Em uma instrução UPDATE ou DELETE, a própria tabela que está sendo atualizada/excluída não pode ser usada diretamente como origem em uma subconsulta (no FROM). O MySQL não permite que a mesma tabela seja destino e origem dessa forma.","cause":"Uma subconsulta lendo diretamente a mesma tabela de destino, como em UPDATE my_table ... WHERE id IN (SELECT ... FROM my_table ...); uma subconsulta referenciando a mesma tabela em um DELETE.","fix":"Envolva a subconsulta em uma derived table e dê a ela um novo alias para que o MySQL a trate como uma cópia separada: UPDATE my_table SET c = 1 WHERE id IN (SELECT id FROM (SELECT id FROM my_table WHERE condition) AS t); Como alternativa, escreva-a como um self-join: 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":"A stored procedure ou função chamada não foi encontrada no banco de dados especificado. Nenhuma rotina com esse nome está definida.","cause":"Nome de procedure grafado incorretamente; a procedure no banco de dados errado ou nunca criada; o schema errado selecionado com USE; falta do privilégio EXECUTE para chamar a procedure; sensibilidade a maiúsculas/minúsculas.","fix":"Verifique se a procedure existe e em qual schema: SHOW PROCEDURE STATUS WHERE Db = 'mydb'; Selecione o banco de dados certo: USE mydb; ou chame-a com o nome totalmente qualificado: CALL mydb.my_procedure(...); Conceda os privilégios necessários: 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":"O usuário não tem o privilégio necessário para a operação tentada. A operação exige um direito além das permissões concedidas à conta.","cause":"Um privilégio administrativo ausente, como SUPER, PROCESS, RELOAD ou CREATE USER; a permissão necessária para ler uma view/tabela global não concedida; uma operação específica (SET GLOBAL, acesso ao binlog) que exige privilégios elevados.","fix":"Veja os privilégios atuais: SHOW GRANTS FOR CURRENT_USER(); Conceda a permissão necessária com uma conta privilegiada: GRANT PROCESS ON *.* TO 'app_user'@'host'; (GRANT tem efeito imediato; FLUSH PRIVILEGES não é necessário). Sempre que possível, use dynamic privileges (por exemplo, SYSTEM_VARIABLES_ADMIN) em vez de SUPER. Siga o princípio do menor privilégio.","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":"A tabela não pode ser removida porque a foreign key de outra tabela a referencia. Enquanto a referência existir, o DROP fica bloqueado.","cause":"Tentativa de remover uma tabela pai enquanto ainda existem tabelas filhas ligadas a ela por uma FK; desrespeito à ordem de dependência; não remover as foreign keys antes.","fix":"Primeiro remova a foreign key que faz a referência: ALTER TABLE child_table DROP FOREIGN KEY fk_name; e então remova a tabela. Encontre as tabelas/constraints dependentes: SELECT * FROM information_schema.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_NAME = 'my_table'; Em operações em massa, SET FOREIGN_KEY_CHECKS = 0; pode ser usado temporariamente, mas tenha cuidado e volte para 1 em seguida.","tags":["foreign key","fk","drop table","referenced","reference","constraint","3730"]},{"code":"2013","title":"Lost connection to MySQL server during query","severity":"danger","meaning":"A conexão entre o cliente e o servidor MySQL caiu enquanto a consulta estava em execução. Ela foi cortada antes que o servidor pudesse responder ou retornar resultados.","cause":"Uma consulta de longa duração excedendo net_read_timeout/net_write_timeout; o servidor encerrando a consulta/conexão por falta de memória (OOM); uma queda de rede; ultrapassagem de max_allowed_packet; o servidor travando ou reiniciando; um conjunto de resultados muito grande.","fix":"Verifique a estabilidade da rede e o error log do servidor; veja se houve OOM ou crash. Aumente os timeouts: SET GLOBAL net_read_timeout = 120; Divida consultas grandes em lotes. Aumente max_allowed_packet. Adicione lógica de retry de conexão na aplicação. Otimize as consultas longas.","tags":["lost connection","connection dropped","timeout","network","network outage","oom","2013"]},{"code":"1153","title":"Got a packet bigger than 'max_allowed_packet' bytes","severity":"danger","meaning":"O cliente ou o servidor tentou enviar um pacote de dados maior que o tamanho máximo de pacote permitido (max_allowed_packet). Geralmente acontece com valores BLOB/TEXT grandes ou INSERTs em massa muito grandes.","cause":"Inserção de dados BLOB/TEXT muito grandes; um único INSERT enorme ou um INSERT em massa com várias linhas; uma consulta que retorna um resultado grande; um valor pequeno de max_allowed_packet; importação de linhas grandes com mysqldump.","fix":"Aumente max_allowed_packet (no servidor e no cliente): SET GLOBAL max_allowed_packet = 67108864; (64MB) e reconecte. Para torná-lo permanente, adicione max_allowed_packet = 64M na seção [mysqld] do my.cnf. Divida operações em massa grandes em lotes menores. Avalie se você realmente precisa armazenar valores muito grandes.","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":"Específico do MariaDB (ER_STATEMENT_TIMEOUT): a consulta foi interrompida porque excedeu o tempo máximo de execução definido por max_statement_time. O MySQL não tem este código; o equivalente no MySQL é o erro 3024 (ER_QUERY_TIMEOUT, max_execution_time).","cause":"No MariaDB, ultrapassagem do limite max_statement_time da sessão/global ou de um limite definido com SET STATEMENT max_statement_time=N FOR ...; um plano ineficiente, um índice ausente, uma varredura de grande volume de dados ou esperas por lock.","fix":"Analise a consulta com EXPLAIN e acelere-a adicionando índices e melhorando o plano. Se a consulta realmente precisar rodar por muito tempo, eleve o limite no MariaDB: SET SESSION max_statement_time = 60; (segundos) ou SET STATEMENT max_statement_time = 60 FOR SELECT ...; Se você usa MySQL, consulte a entrada 3024 (max_execution_time, milissegundos; hint MAX_EXECUTION_TIME). Divida as operações grandes.","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":"Ocorreu um erro de divisão por zero porque o divisor de uma expressão aritmética é zero. O SQL Server não consegue concluir a divisão e interrompe a consulta.","cause":"Uma coluna ou expressão usada como divisor avaliando como 0, um denominador zero em cálculos de média/razão, divisão sem NULLIF, ou valores zero inesperados nos dados.","fix":"Proteja o denominador com NULLIF (por exemplo, value / NULLIF(denominator, 0)); o resultado passa a ser NULL e um valor padrão pode ser fornecido com ISNULL/COALESCE. Use CASE WHEN denominator = 0 THEN NULL ELSE value/denominator END. Filtre os valores zero com WHERE antes de dividir. Se necessário, avalie o comportamento de 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":"Um valor não pôde ser convertido para o tipo de dado de destino. Por exemplo, uma conversão implícita/explícita falhou por conteúdo inadequado ao converter um valor string em int ou date.","cause":"Conversão de texto não numérico em int/decimal, um formato de data inválido, conversão implícita de tipo em comparações de colunas, tipos incompatíveis em uma condição WHERE ou JOIN, ou dados de entrada malformados.","fix":"Use as variantes de conversão segura: TRY_CAST ou TRY_CONVERT (retornam NULL em caso de falha). Identifique as linhas com problema com ISNUMERIC/TRY_CONVERT. Alinhe os tipos das colunas e elimine a conversão implícita. Valide a entrada e use um formato explícito para datas (por exemplo, um estilo do CONVERT).","tags":["conversion","type conversion","cast","convert","data type","245"]},{"code":"515","title":"Cannot insert the value NULL into column","severity":"caution","meaning":"Houve uma tentativa de inserir ou atualizar um valor NULL em uma coluna definida como NOT NULL. A operação foi rejeitada porque a coluna não permite nulos.","cause":"Uma coluna obrigatória omitida da instrução INSERT, campos ausentes/vazios nos dados de origem, uma coluna NOT NULL sem valor padrão, ou NULL enviado pela aplicação.","fix":"Forneça um valor válido para as colunas obrigatórias. Adicione constraints DEFAULT às colunas adequadas. Valide os dados de origem quanto a campos ausentes e atribua valores padrão com ISNULL/COALESCE. Se a coluna não precisar realmente ser obrigatória, revise o schema para permitir NULL.","tags":["null","not null","insert","constraint","constraint violation","515"]},{"code":"8115","title":"Arithmetic overflow error converting expression to data type","severity":"caution","meaning":"O valor produzido por uma operação aritmética ou conversão excedeu o intervalo que o tipo de dado de destino suporta. Ocorreu um overflow porque o número é grande demais.","cause":"Uma soma/produto (SUM) excedendo o intervalo de int, um valor grande atribuído a uma coluna com tipo pequeno, precisão/escala decimal insuficiente, ou um valor IDENTITY atingindo o limite do tipo.","fix":"Use um tipo mais amplo para cálculos intermediários (por exemplo, SUM com CAST(my_column AS bigint)). Aumente a precisão/escala decimal. Amplie o tipo da coluna para comportar os dados. Converta as expressões com risco de overflow antes de calcular e restrinja os intervalos de entrada.","tags":["overflow","arithmetic overflow","arithmetic","math","int","bigint","8115"]},{"code":"512","title":"Subquery returned more than 1 value","severity":"caution","meaning":"Uma subconsulta usada em um contexto que espera um único valor (=, <, >, comparação ou atribuição) retornou mais de uma linha. O SQL Server esperava um único valor escalar, mas encontrou vários valores.","cause":"Uma subconsulta que se supunha retornar um único valor para a comparação retorna várias linhas, uma condição de correspondência não única, um filtro ausente, ou uma consulta correlacionada construída incorretamente.","fix":"Reduza a subconsulta a uma única linha (por exemplo, TOP 1, MAX/MIN, ou um GROUP BY adequado). Se vários valores forem esperados, use IN ou EXISTS em vez de =. Reescreva com um JOIN. Investigue por que a subconsulta retorna várias linhas e corrija as condições de filtro/chave.","tags":["subquery","scalar subquery","more than one","512","in","exists"]},{"code":"207","title":"Invalid column name","severity":"caution","meaning":"O nome de coluna referenciado na consulta não foi encontrado na tabela/view. Não existe nenhuma coluna com esse nome, ou ela está fora do escopo.","cause":"Um erro de grafia/de maiúsculas e minúsculas, o alias de tabela errado, uma coluna ainda não adicionada ou renomeada, o contexto de schema/tabela errado, ou a omissão de colchetes em vez de aspas.","fix":"Verifique o nome da coluna e a tabela (consulte sys.columns ou o Object Explorer). Use o alias e o schema corretos. Para colunas recém-adicionadas, certifique-se de que o objeto está atualizado; recompile a stored procedure se necessário. Use colchetes para nomes que contenham espaços/caracteres especiais.","tags":["column","column name","invalid column","invalid column name","alias","207"]},{"code":"156","title":"Incorrect syntax near the keyword","severity":"caution","meaning":"Há um erro de sintaxe próximo a uma palavra-chave. O SQL Server não conseguiu analisar a instrução porque uma palavra reservada é usada em uma posição inesperada.","cause":"Uso de uma palavra reservada (por exemplo, ORDER, USER, TABLE) como nome de coluna/objeto sem colchetes, uma vírgula/parêntese faltando, cláusulas na ordem errada, ou uma cláusula mal posicionada (WHERE, GROUP BY).","fix":"Inspecione a área ao redor da palavra-chave apontada pelo erro. Se você usa palavras reservadas como nomes de objetos, coloque-as entre colchetes (por exemplo, [User]). Corrija vírgulas, parênteses e a ordem das cláusulas. Teste a sintaxe dividindo a consulta em partes.","tags":["syntax","syntax error","keyword","reserved word","156"]},{"code":"2812","title":"Could not find stored procedure","severity":"caution","meaning":"A stored procedure chamada com EXEC não foi encontrada no escopo atual de banco de dados/schema. Não existe nenhuma procedure com esse nome.","cause":"Erro de digitação no nome da procedure, prefixo de schema ausente ou errado (por exemplo, dbo. omitido), a procedure em outro banco de dados, ainda não criada, ou não visível por causa de permissões.","fix":"Verifique o nome da procedure e o schema; use o nome totalmente qualificado na chamada (por exemplo, EXEC dbo.ProcedureName). Certifique-se de estar no banco de dados correto (USE DatabaseName). Verifique se a procedure existe (sys.procedures / OBJECT_ID). Conceda a permissão EXECUTE necessária e verifique se o script de deploy foi executado.","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":"O processador de consultas esgotou seus recursos internos em uma consulta complexa demais e não conseguiu produzir um plano de execução. A consulta não pode ser otimizada por ser grande/complexa demais.","cause":"Consultas com listas IN muito longas ou muitas cláusulas OR/UNION, um número excessivo de JOINs, consultas enormes geradas automaticamente, consultas com parâmetros demais, ou árvores de expressões excessivamente profundas.","fix":"Simplifique a consulta: mova listas IN longas para uma tabela temporária/table-valued parameter, reduza as condições OR com UNION ALL ou uma reescrita, e divida a consulta complexa em partes. Reduza o número de JOINs. Divida em lotes as consultas geradas automaticamente. Revise os índices e o design da consulta quando necessário.","tags":["query processor","internal resources","plan","complex query","8623","danger"]},{"code":"4104","title":"The multi-part identifier could not be bound","severity":"caution","meaning":"Um identificador de várias partes separado por pontos (por exemplo, table.column ou alias.column) não pôde ser resolvido. O SQL Server não conseguiu associar esse nome a uma tabela/coluna da consulta.","cause":"Um alias de tabela errado ou não definido, uma referência a uma tabela que não está no FROM/JOIN, uma coluna atribuída à tabela errada, uso do nome real da tabela depois de definir um alias, ou um erro de digitação.","fix":"Verifique se os aliases usados estão definidos na cláusula FROM/JOIN. Qualifique a coluna com a tabela/o alias correto. Se você definiu um alias para uma tabela, use o alias em todos os lugares (não o nome real). Adicione a tabela que falta ao JOIN e verifique os nomes.","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":"Já existe no banco de dados um objeto com o mesmo nome do que está sendo criado (tabela, view, procedure etc.). A instrução CREATE falhou por conflito de nomes.","cause":"Execução do mesmo script CREATE uma segunda vez, não remover o objeto existente antes, uma suposição de schema diferente, scripts de deploy/migration não idempotentes, ou um conflito de nomenclatura.","fix":"Verifique antes se o objeto existe: crie condicionalmente com IF OBJECT_ID('dbo.Name') IS NULL, ou use CREATE OR ALTER (para procedures/views/funções). Se necessário, faça DROP do objeto existente e recrie-o. Escreva scripts de migration idempotentes. Verifique se você está trabalhando no schema/banco de dados correto.","tags":["already exists","object exists","create","object","duplicate object","2714"]},{"code":"601","title":"Could not continue scan with NOLOCK due to data movement","severity":"caution","meaning":"Durante uma varredura com NOLOCK (READ UNCOMMITTED), a varredura não pôde continuar por causa de movimentação concorrente de dados (page splits/movimentações de páginas). A leitura sem lock encontrou um estado inconsistente.","cause":"Páginas varridas sendo realocadas por updates/deletes/page splits concorrentes durante a leitura com o hint NOLOCK ou o nível de isolamento READ UNCOMMITTED.","fix":"Execute a consulta novamente (geralmente é transitório). Evite o hint NOLOCK sempre que possível; use o isolamento READ COMMITTED SNAPSHOT (RCSI) para leituras sem bloqueio e ainda assim consistentes. Em tabelas com muita escrita, prefira snapshot isolation a dirty reads.","tags":["nolock","scan","data movement","601","isolation","read uncommitted"]},{"code":"50000","title":"Erro personalizado gerado com RAISERROR","severity":"caution","meaning":"É o número padrão (50000) para erros personalizados (definidos pelo usuário) gerados com RAISERROR sem especificar um ID de mensagem. A lógica da aplicação/procedure gerou um erro deliberadamente.","cause":"Um erro personalizado gerado com RAISERROR ou THROW em uma stored procedure ou script diante de uma violação de regra de negócio, uma falha de validação, controle de fluxo deliberado, ou mensagens de exceção personalizadas.","fix":"Leia o texto da mensagem do RAISERROR/THROW para entender a violação real da regra de negócio. Capture este erro no lado da aplicação com TRY...CATCH e obtenha detalhes com ERROR_MESSAGE()/ERROR_NUMBER(). Defina mensagens com sp_addmessage para dar números significativos aos seus erros personalizados. Corrija a condição que dispara o erro na lógica de negócio.","tags":["raiserror","custom error","user-defined error","throw","50000","try catch"]},{"code":"3902","title":"The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION","severity":"caution","meaning":"Um COMMIT TRANSACTION foi executado, mas não há um BEGIN TRANSACTION aberto correspondente. Nenhuma transação para commit foi encontrada porque a contagem de transações (@@TRANCOUNT) é zero.","cause":"Uso desbalanceado de BEGIN/COMMIT/ROLLBACK, a transação já desfeita (rollback) após um erro, gerenciamento incorreto das contagens de transações aninhadas, ou chamada de COMMIT novamente após ROLLBACK em um bloco CATCH.","fix":"Balanceie o número de instruções BEGIN e COMMIT. Verifique @@TRANCOUNT antes do commit (IF @@TRANCOUNT > 0 COMMIT). Em TRY...CATCH, em caso de erro faça ROLLBACK com base em XACT_STATE()/@@TRANCOUNT e evite um COMMIT desnecessário. Revise a lógica de transações aninhadas.","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":"O documento inserido ou atualizado foi rejeitado porque não satisfaz as regras de validação JSON Schema (validator) definidas na collection.","cause":"O documento não está em conformidade com o schema: um campo obrigatório ausente, um tipo BSON errado, um valor fora do intervalo/padrão permitido, campos adicionais proibidos, ou uma violação de regra enquanto validationAction é 'error'.","fix":"Inspecione os detalhes do erro (errInfo) para ver qual regra foi violada. Faça o documento se adequar ao schema: adicione os campos obrigatórios e corrija os tipos. Revise o validator da collection com collMod. validationLevel/validationAction podem ser relaxados temporariamente, mas manter as regras é preferível para a qualidade dos dados.","tags":["validation","validation","schema","schema","121","document"]},{"code":"40","title":"ConflictingUpdateOperators","severity":"caution","meaning":"Um update aplicou mais de um operador de atualização conflitante ao mesmo campo (path). O MongoDB não consegue modificar o mesmo path duas vezes em uma única operação.","cause":"Operadores conflitantes direcionados ao mesmo campo em um documento de update (por exemplo, $set e $inc juntos, ou modificar um path pai e um filho ao mesmo tempo), um update mal construído, ou um conflito de path aninhado.","fix":"Junte os operadores conflitantes no mesmo campo em um único operador, ou divida o update em operações separadas. Não modifique um path pai e um filho (por exemplo, a e a.b) ao mesmo tempo. Revise o documento de update e certifique-se de que cada campo é modificado apenas uma vez.","tags":["update","update","operator","conflict","conflict","40"]},{"code":"66","title":"ImmutableField (cannot update _id)","severity":"caution","meaning":"Houve uma tentativa de atualizar um campo imutável, tipicamente o campo _id do documento. O _id não pode ser alterado depois que o documento é criado.","cause":"Um update tentando alterar o campo _id, atualização de um campo da shard key de forma não permitida, ou definição de um novo valor para um campo tratado como imutável.","fix":"Não atualize o valor de _id; se for necessário um _id diferente, insira o documento com o novo _id e exclua o antigo (insert + delete). Siga as regras do MongoDB para atualizações de shard key. Remova os campos imutáveis do documento de update e defina apenas campos modificáveis.","tags":["immutable","_id","immutable","update","shard key","66"]},{"code":"2","title":"BadValue","severity":"caution","meaning":"Um valor inválido ou inesperado foi passado a um comando ou consulta. O MongoDB não conseguiu interpretar o argumento como um valor aceitável.","cause":"Um argumento de operador inválido, um número fora do intervalo, um valor de opção não suportado, uma especificação de sort malformada, uma expressão de consulta malformada, ou uma combinação inadequada de parâmetros.","fix":"Corrija o argumento com base na indicação de campo/valor na mensagem de erro. Valide as opções de comandos e consultas com a documentação. Verifique o formato das expressões de sort/projection/aggregate. Coloque os intervalos e tipos de valores dentro da faixa válida.","tags":["badvalue","invalid value","argument","2","query"]},{"code":"14","title":"TypeMismatch","severity":"caution","meaning":"O tipo do valor fornecido não corresponde ao tipo BSON esperado. Era esperado um tipo de dado diferente para um campo ou argumento.","cause":"Texto fornecido onde se espera um número, uma string usada em vez de uma data, um valor único enviado onde se espera um array, um argumento do tipo errado passado a um operador de agregação/consulta, ou inconsistência de tipos no schema.","fix":"Forneça o tipo BSON correto para o campo/argumento. Converta os tipos na camada da aplicação antes de salvar os dados (por exemplo, grave números como valores Number reais). Verifique os tipos esperados pelos operadores de consulta e de agregação. Garanta a consistência de tipos com um schema validator.","tags":["typemismatch","type mismatch","bson","type","14"]},{"code":"10334","title":"BSONObjectTooLarge","severity":"danger","meaning":"Um documento BSON excedeu o tamanho máximo permitido (16 MB). O MongoDB não consegue armazenar nem retornar um único documento acima desse limite.","cause":"Ultrapassagem do limite de 16 MB por acrescentar continuamente dados/elementos de array a um documento, arrays embutidos muito grandes, documentos enormes produzidos por uma agregação, ou grandes dados binários armazenados diretamente no documento.","fix":"Revise o modelo de dados: divida arrays grandes em collections separadas e use um modelo de referências. Use GridFS para arquivos binários grandes. Limite arrays sem limite (por exemplo, o padrão capped/bucket). Mantenha o tamanho dos documentos sob controle nos estágios de agregação.","tags":["bson","16mb","too large","large document","gridfs","10334","danger"]},{"code":"46","title":"LockBusy","severity":"caution","meaning":"O lock ou recurso solicitado não pôde ser adquirido imediatamente porque estava sendo mantido por outra operação, e a operação foi rejeitada em vez de aguardar. Esperas por lock que terminam em timeout têm um código separado (24 LockTimeout).","cause":"Operações administrativas/DDL concorrentes na mesma collection ou banco de dados (por exemplo, dois index builds ao mesmo tempo, collMod, drop ou rename), um conflito com uma operação de manutenção em andamento, ou uma operação interna que não pode esperar nem brevemente por um lock encontrando um recurso ocupado.","fix":"Encontre a operação conflitante: use db.currentOp() para inspecionar operações de DDL ou de manutenção em execução no mesmo namespace. Repita o comando após a operação conflitante terminar. Serialize as operações administrativas/DDL e não as execute em paralelo na mesma collection. Se persistir, investigue nos logs do mongod a operação que mantém o recurso.","tags":["lock","lock","lockbusy","busy","ddl","46"]},{"code":"96","title":"OperationFailed","severity":"danger","meaning":"Uma falha genérica de operação; ocorreu um erro inesperado durante a execução do comando e a operação não pôde ser concluída. É o erro genérico usado quando não existe um código mais específico.","cause":"Um erro interno do lado do servidor, esgotamento de recursos, um estado inconsistente, uma falha de subsistema (armazenamento, replicação), ou diversas condições de falha específicas de determinado comando.","fix":"Determine a causa raiz examinando o texto completo da mensagem de erro e os logs do servidor (mongod.log). Repita a operação; a condição pode ser transitória. Verifique os recursos (disco, memória) e a saúde do replica set. Se o problema se repetir, revise o comando e seus dados de entrada.","tags":["operationfailed","operation failed","generic error","96","danger"]},{"code":"72","title":"InvalidOptions","severity":"caution","meaning":"Opções inválidas ou mutuamente incompatíveis foram passadas a um comando. A combinação de opções especificada não é suportada para este comando.","cause":"Um nome de opção não suportado, opções mutuamente exclusivas usadas juntas, uma opção não válida para a versão em execução, uma combinação inválida de write concern/read concern, ou um conflito de opções de índice/collation.","fix":"Verifique na documentação as opções aceitas pelo comando e remova as incompatíveis. Certifique-se de que sua versão suporta a opção. Revise as configurações de write/read concern e collation. Use apenas combinações de opções válidas.","tags":["invalidoptions","invalid option","options","72","command"]},{"code":"9","title":"FailedToParse","severity":"caution","meaning":"O servidor não conseguiu analisar o comando, a consulta ou a expressão enviada. A estrutura é sintaticamente inválida ou não está no formato esperado.","cause":"Uma estrutura JSON/BSON malformada, campos ausentes ou extras, uso incorreto de operadores, sintaxe inválida de pipeline de agregação, ou um documento de comando que não corresponde ao formato esperado.","fix":"Corrija a estrutura do comando/consulta/pipeline de acordo com a documentação. Valide a estrutura JSON (colchetes/vírgulas faltando, nomes de campos errados). Verifique a sintaxe dos estágios de agregação. Certifique-se de que os operadores são usados corretamente e os argumentos são fornecidos no formato esperado.","tags":["failedtoparse","parse","parsing","syntax","9","query"]},{"code":"134","title":"ReadConcernMajorityNotAvailableYet","severity":"caution","meaning":"Foi solicitada uma leitura com read concern majority, mas ainda não há um snapshot confirmado pela maioria disponível. O servidor não consegue fornecer esse nível de consistência no momento.","cause":"O replica set acabou de iniciar ou está instável, as gravações majority ainda não foram confirmadas, lag de replicação, membros acessíveis insuficientes, ou o cluster ainda está na fase de inicialização.","fix":"Aguarde um pouco e tente novamente; a leitura tem sucesso assim que o snapshot majority estiver disponível. Verifique a saúde do replica set e o lag de replicação (rs.status()). Certifique-se de que há membros suficientes no ar. Se não for necessário, considere um read concern mais baixo (por exemplo, local).","tags":["readconcern","majority","majority","replica","134","consistency"]},{"code":"202","title":"NetworkInterfaceExceededTimeLimit","severity":"danger","meaning":"Uma requisição de rede (por exemplo, comunicação entre membros ou uma conexão de cliente) excedeu seu limite de tempo. A operação não pôde ser concluída por causa de um timeout de rede.","cause":"Latência/queda de rede, um membro de destino lento ou inacessível, carga excessiva, valores de timeout mal configurados, problemas de DNS/conexão, ou membros geograficamente distantes.","fix":"Verifique a conectividade e a latência da rede; confirme a acessibilidade entre os membros. Inspecione a saúde e a carga do membro de destino. Configure os timeouts (connect/socket timeout) para o seu ambiente. Adicione lógica de retry. Se persistir, revise a configuração de infraestrutura/rede.","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":"O usuário ACL autenticado não está autorizado para o comando que quer executar ou para a chave que acessa. O Redis rejeita a operação de acordo com as regras da ACL.","cause":"O usuário ACL não tem a permissão de comando/categoria, o padrão de chave não está na sua lista de permissões, aplica-se uma restrição de canal (pub/sub), ou o usuário recebeu privilégios de escopo restrito.","fix":"Inspecione as permissões do usuário: ACL GETUSER app_user. Adicione os comandos/categorias e padrões de chave necessários (por exemplo, ACL SETUSER app_user +get +set ~app:*). Seguindo o menor privilégio, conceda apenas as permissões necessárias. Verifique se você está conectado com o usuário certo.","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":"Um comando que espera um inteiro (por exemplo, INCR, EXPIRE, count do LPOP) recebeu um valor não numérico ou fora do intervalo. O Redis não conseguiu interpretar o valor como inteiro.","cause":"A chave alvo do INCR/DECR contendo um valor texto (não inteiro), um argumento informado como texto em vez de número, um número grande/pequeno demais para o intervalo, ou um valor negativo onde não é permitido.","fix":"Verifique o valor da chave: GET mykey e TYPE mykey. Para operações numéricas, certifique-se de que a chave contém um valor inteiro. Verifique se os argumentos são inteiros válidos dentro do intervalo correto. Se necessário, redefina o valor (SET mykey 0) ou recrie-a com o tipo correto.","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","severity":"caution","meaning":"Um comando que espera um número decimal (float) (por exemplo, INCRBYFLOAT, um score do ZADD) recebeu um valor que não é um número de ponto flutuante válido. O Redis não conseguiu interpretar o valor como float.","cause":"A chave alvo do INCRBYFLOAT sem um float válido, um argumento não numérico, o separador decimal errado (é necessário ponto, não vírgula) ou um número malformado.","fix":"Verifique o valor da chave com GET e certifique-se de que contém um float válido. Use ponto como separador decimal (por exemplo, 3.14). Verifique se o argumento é numérico e está formatado corretamente. Se necessário, redefina o valor para um float válido.","tags":["err","float","decimal","incrbyfloat","zadd","value"]},{"code":"ERR increment or decrement would overflow","title":"ERR increment or decrement would overflow","severity":"caution","meaning":"Um INCR/DECR (ou INCRBY/DECRBY) foi rejeitado porque o resultado estouraria o intervalo de inteiro com sinal de 64 bits. O valor excederia o limite superior ou inferior.","cause":"O valor da chave muito próximo do limite de int64 (cerca de 9,2 quintilhões), de modo que o incremento/decremento estoura, um argumento de INCRBY muito grande, ou um contador crescendo sem controle.","fix":"Projete os valores dos contadores para permanecerem dentro dos limites de int64. Para contagens grandes, aplique escalonamento ou reinicializações periódicas. Mantenha o incremento (o argumento do INCRBY) em um intervalo razoável. Se forem necessários valores muito grandes, use outra estratégia de contagem na camada da aplicação.","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":"O número de clientes conectados atingiu o limite maxclients e novas conexões não podem ser aceitas. O Redis recusa novas conexões de clientes.","cause":"Vazamento de conexões (conexões nunca fechadas), um valor de maxclients insuficiente, um pool de conexões mal configurado, um pico repentino de clientes, ou um limite baixo de file descriptors no sistema operacional.","fix":"Inspecione as conexões atuais: CLIENT LIST e INFO clients. Corrija vazamentos de conexões; dimensione corretamente o pool de clientes e reutilize conexões. Se necessário, eleve maxclients (CONFIG SET maxclients) e o limite ulimit (file descriptors) do SO. Defina um timeout para conexões ociosas.","tags":["err","maxclients","connection","client","limit","danger"]},{"code":"BUSYKEY","title":"BUSYKEY Target key name already exists","severity":"caution","meaning":"O RESTORE (ou um comando similar) falhou porque a chave de destino já existe. Por padrão, o Redis não sobrescreve uma chave existente.","cause":"O nome da chave sendo restaurada com RESTORE já existe no banco de dados, dados anteriores não foram limpos, ou várias tentativas de restore na mesma chave.","fix":"Se você quiser sobrescrever a chave existente, adicione a opção REPLACE ao RESTORE. Como alternativa, exclua antes a chave de destino (DEL mykey) ou use outro nome de chave. Verifique a existência antecipadamente com EXISTS mykey.","tags":["busykey","restore","already exists","target key","replace","key"]},{"code":"ERR no such key","title":"ERR no such key","severity":"caution","meaning":"A chave sobre a qual operar não foi encontrada no banco de dados. Comandos que exigem uma chave existente, como RENAME, DUMP e MOVE, não funcionam em uma chave inexistente.","cause":"A chave nunca foi criada, expirou e foi removida por causa do TTL, nome/grafia da chave errados, o índice de banco de dados (SELECT) errado, ou a chave já foi excluída com DEL.","fix":"Verifique se a chave existe: EXISTS mykey. Certifique-se de usar o nome de chave correto e o banco de dados correto (SELECT db). O RENAME exige que a chave de origem exista. Revise a lógica para chaves que expiram via TTL. Recrie a chave se necessário.","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","severity":"caution","meaning":"Os dados serializados (saída do DUMP) passados ao RESTORE são inválidos; a versão é incompatível ou a verificação do checksum falhou. O Redis não consegue restaurar os dados com segurança.","cause":"Os dados do DUMP corrompidos/modificados, transferência entre versões diferentes e incompatíveis do Redis, corrupção durante codificação/decodificação (por exemplo, tratamento incorreto de bytes), ou um payload ausente/truncado.","fix":"Certifique-se de que os dados do DUMP sejam transportados intactos (binary-safe); transfira-os como bytes brutos e não por meio de uma codificação de texto. Verifique se as versões do Redis de origem e destino são compatíveis. Faça um novo DUMP e transfira-o novamente. Para migração, considere o comando MIGRATE em vez do RESTORE.","tags":["err","dump","restore","checksum","checksum mismatch","version"]},{"code":"NOREPLICAS","title":"NOREPLICAS Not enough good replicas to write","severity":"danger","meaning":"Por causa da configuração min-replicas-to-write, as gravações são rejeitadas porque não há réplicas saudáveis suficientes. O Redis bloqueia as gravações por segurança dos dados.","cause":"Réplicas conectadas/atualizadas insuficientes, crashes de réplicas, lag de replicação excedendo o limite min-replicas-max-lag, problemas de rede, ou réplicas ausentes após um failover.","fix":"Verifique o status das réplicas: INFO replication. Coloque de volta no ar as réplicas que caíram e reduza o lag de replicação. Corrija a conectividade de rede. Revise as configurações min-replicas-to-write / min-replicas-max-lag para o seu ambiente (o equilíbrio entre durabilidade e disponibilidade). Forneça réplicas suficientes.","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":"Um comando de cluster (CLUSTER ...) foi executado, mas esta instância do Redis não foi iniciada em modo cluster. O comando foi rejeitado porque o suporte a cluster está desabilitado.","cause":"cluster-enabled yes não definido, a instância rodando em modo standalone, comandos de cluster enviados a um servidor standalone, ou conexão ao servidor errado.","fix":"Se você quiser usar os recursos de cluster, inicie a instância em modo cluster: defina cluster-enabled yes na configuração, reinicie e forme o cluster a partir dos nós. Se você permanecer no modo standalone, não use comandos de cluster. Verifique se você está conectado ao servidor (cluster) correto.","tags":["err","cluster","cluster mode","disabled","standalone","config"]},{"code":"ERR unknown subcommand","title":"ERR unknown subcommand or wrong number of arguments","severity":"caution","meaning":"Um comando contêiner (por exemplo, CONFIG, CLIENT, ACL, XINFO) recebeu um subcomando inválido, ou o subcomando recebeu o número errado de argumentos. O Redis não reconheceu o subcomando.","cause":"Erro de digitação no nome do subcomando, um subcomando inexistente na versão do Redis em uso, número de argumentos errado/faltando, ou sintaxe de subcomando incorreta.","fix":"Use o nome de subcomando e os argumentos corretos; consulte o subcomando HELP do comando (por exemplo, CONFIG HELP, CLIENT HELP). Verifique se sua versão do Redis suporta esse subcomando. Corrija o número de argumentos e a sintaxe de acordo com a documentação.","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)","severity":"caution","meaning":"O cliente tentou se autenticar com AUTH, mas nenhuma senha (requirepass) ou senha de ACL está definida no servidor. O AUTH foi rejeitado porque não há credencial a verificar. O Redis 6+ retorna \"ERR AUTH <password> called without any password configured for the default user. Are you sure your configuration is correct?\" nesse caso; \"Client sent AUTH, but no password is set\" é a mensagem anterior ao Redis 6.","cause":"requirepass vazio no servidor, o cliente enviando AUTH desnecessariamente, uma senha definida na connection string enquanto o servidor não tem nenhuma, ou uma incompatibilidade de configuração.","fix":"Se o servidor não exige senha, remova o comando AUTH/a configuração de senha do cliente. Se você quiser proteção por senha, defina requirepass no servidor (CONFIG SET requirepass password) ou defina uma senha para o usuário ACL. Torne consistentes as configurações do cliente e do servidor.","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":"A requisição falhou na validação antes da execução. Um campo obrigatório está ausente ou há campos inválidos, então o Elasticsearch rejeita a operação.","cause":"Parâmetros obrigatórios ausentes (por exemplo, nenhum nome de índice especificado), um body vazio, uma combinação inválida de campos, ou informações obrigatórias não fornecidas em uma requisição bulk/index.","fix":"Revise a lista de campos ausentes/inválidos na mensagem de erro e forneça os campos obrigatórios. Complete o body da requisição e os parâmetros de acordo com a documentação da API. Em requisições bulk, verifique se cada linha de ação tem metadados e body corretos.","tags":["validation","validation error","request","request error","action"]},{"code":"index_closed_exception","title":"index_closed_exception","severity":"caution","meaning":"O índice de destino está fechado. Um índice fechado não atende requisições de leitura/escrita, então a operação não pôde ser executada.","cause":"O índice foi fechado anteriormente com a close API, fechado durante operações de manutenção/ILM, ou desativado para economizar recursos.","fix":"Reabra o índice: POST /index_name/_open. Após abrir, aguarde a alocação dos shards (green/yellow). Investigue por que o índice foi fechado (política de ILM, ação manual). Revise a estratégia de manter fechados os índices raramente acessados.","tags":["index closed","closed index","open","index","closed"]},{"code":"unavailable_shards_exception","title":"unavailable_shards_exception","severity":"danger","meaning":"Um ou mais shards necessários para a operação não estão disponíveis, então a requisição (geralmente uma escrita) não pôde ser concluída. Não foram encontradas cópias ativas de shard suficientes.","cause":"Shards não atribuídos por crash/saída de um nó, ultrapassagem do disk watermark, réplicas ausentes, uma condição wait_for_active_shards não atendida, ou cluster health red.","fix":"Verifique a saúde do cluster e dos shards: GET _cluster/health e GET _cat/shards?v. Investigue por que os shards não estão atribuídos: GET _cluster/allocation/explain. Coloque de volta no ar os nós que caíram, libere espaço em disco (watermark) e revise as configurações de réplicas. Se necessário, defina wait_for_active_shards adequadamente.","tags":["shard","unavailable","inaccessible","cluster","allocation","danger"]},{"code":"query_shard_exception","title":"query_shard_exception","severity":"caution","meaning":"Uma consulta falhou ao ser executada em um shard específico. Geralmente ocorre porque a consulta é incompatível com o mapping ou tem uma estrutura inválida.","cause":"Consulta a um campo inexistente ou de tipo errado, tentativa de agregação/ordenação em um campo text (fielddata desabilitado), sintaxe de consulta inválida, análise errada, ou um tipo de campo incompatível.","fix":"Revise o campo/motivo nos detalhes do erro. Verifique o mapping do campo consultado: GET /index/_mapping. Para ordenação/agregação, use o subcampo keyword (field.keyword) em vez de text. Corrija a sintaxe da consulta e certifique-se de que os tipos de campo são compatíveis com a consulta.","tags":["query","query error","shard","mapping","fielddata","query shard"]},{"code":"script_exception","title":"script_exception","severity":"caution","meaning":"Ocorreu um erro ao compilar ou executar um script (geralmente Painless). O script está escrito incorretamente ou lançou uma exceção em tempo de execução.","cause":"Erro de sintaxe Painless, acesso a valor null, incompatibilidade de tipos, uso de um campo/variável inexistente, ultrapassagem do limite de compilação de scripts, ou uma chamada de API não permitida.","fix":"Revise os detalhes de compilação/execução na mensagem de erro. Corrija a sintaxe do script e o acesso aos campos; adicione verificações de null (por exemplo, doc['field'].size() > 0). Torne parametrizados (stored/params) os scripts usados com frequência para não exceder o limite de compilação. Use nomes e tipos de campos corretos.","tags":["script","painless","compilation","runtime","script exception"]},{"code":"number_format_exception","title":"number_format_exception","severity":"caution","meaning":"Um valor que deveria ser numérico não pôde ser convertido em número. Foi fornecida uma string inválida/não numérica onde um campo ou parâmetro espera um número.","cause":"Texto não numérico enviado a um campo numérico (integer/long/double), tentativa de converter uma string vazia em número, formato decimal errado, ou dados de entrada incompatíveis com o mapping.","fix":"Envie valores numéricos válidos ao campo. Valide/transforme os dados de origem antes da indexação. Use null para valores vazios ou omita o campo. Revise a configuração coerce e o tipo do campo no mapping. Use ponto como separador decimal.","tags":["number format","number","conversion","numeric","format"]},{"code":"connect_transport_exception","title":"connect_transport_exception","severity":"danger","meaning":"Não foi possível conectar a um nó pela camada de transport (9300). A comunicação entre nós ou entre cliente e cluster não pôde ser estabelecida, então a operação não pôde ser executada.","cause":"Nó de destino fora do ar/inacessível, problemas de rede/firewall, endereço/porta de transport errados, incompatibilidade de configuração TLS, problema de DNS, ou incompatibilidade de nome/versão do cluster.","fix":"Verifique se o nó de destino está em execução e se a porta de transport (padrão 9300) está acessível pela rede. Verifique as regras de firewall/rede e a configuração de discovery. Certifique-se de que as configurações de TLS/certificados são consistentes em todos os nós. Revise os logs dos nós e verifique a compatibilidade de cluster.name/versão.","tags":["transport","connection","connect","network","node","danger"]},{"code":"repository_missing_exception","title":"repository_missing_exception","severity":"caution","meaning":"O repositório de snapshots referenciado em uma operação de snapshot/restore não foi encontrado. Nenhum repositório está registrado com o nome informado.","cause":"O repositório nunca foi registrado, erro de digitação no nome, o repositório foi excluído, está definido em outro cluster, ou não foi registrado novamente após o cluster state ser redefinido.","fix":"Liste os repositórios registrados: GET _snapshot/_all. Registre novamente o repositório com o nome e as configurações corretos: PUT _snapshot/repo_name (com type e settings). Certifique-se de que o nome do repositório está escrito corretamente. Verifique se o acesso ao repositório compartilhado (fs/s3 etc.) funciona em todos os nós.","tags":["repository","snapshot repository","snapshot","missing","backup","restore"]},{"code":"concurrent_snapshot_execution_exception","title":"concurrent_snapshot_execution_exception","severity":"caution","meaning":"Uma nova requisição de snapshot/restore foi rejeitada porque uma operação de snapshot conflitante está em execução ao mesmo tempo. Outra operação de snapshot ainda está em andamento no repositório ou no índice.","cause":"Um snapshot anterior ainda em andamento, um conflito de snapshot/restore concorrente afetando o mesmo índice, uma política de SLM (snapshot lifecycle) colidindo com um snapshot manual, ou disparos em intervalos curtos.","fix":"Verifique os snapshots em execução: GET _snapshot/repo/_current e GET _snapshot/_status. Aguarde a operação atual terminar, ou cancele-a se necessário: DELETE _snapshot/repo/snapshot_name. Agende os snapshots para que não se sobreponham. Coordene as operações manuais com o SLM.","tags":["snapshot","concurrent","conflict","simultaneous","slm","backup"]},{"code":"invalid_index_name_exception","title":"invalid_index_name_exception","severity":"caution","meaning":"O nome de índice informado não segue as regras de nomenclatura do Elasticsearch. O nome contém caracteres inválidos ou viola regras de formato.","cause":"Letras maiúsculas, caracteres não permitidos (\\ / * ? \" < > | espaço , #), um nome que começa com _, - ou +, um nome longo demais (mais de 255 bytes), ou nomes reservados como . / ... (Nomes que começam com ponto não são proibidos, mas são reservados para índices ocultos/de sistema e geram um aviso.)","fix":"Torne o nome do índice compatível: use apenas minúsculas; evite os caracteres proibidos; não comece o nome com _, - ou +, e não use nomes que começam com ponto, exceto para índices de sistema/ocultos. Mantenha o nome abaixo de 255 bytes. Aplique essas regras na aplicação ao gerar nomes de índices.","tags":["index name","index naming","invalid","invalid name","naming"]},{"code":"resource_not_found_exception","title":"resource_not_found_exception","severity":"caution","meaning":"O recurso solicitado (documento, índice, tarefa, pipeline, modelo etc.) não foi encontrado. Não existe nenhum recurso para o ID/nome informado.","cause":"Um ID de documento inexistente, um índice/pipeline excluído ou nunca criado, um nome grafado incorretamente, uma tarefa ainda não concluída ou já limpa, ou uma requisição enviada ao cluster errado.","fix":"Verifique o nome/ID do recurso e se ele existe (por exemplo, GET /index/_doc/id, GET _ingest/pipeline/name). Certifique-se de que você está enviando a requisição ao índice e ao cluster corretos. Revise a ordem das operações de exclusão/criação. Para tarefas, verifique o status com a API _tasks.","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":"Uma atualização do cluster state (por exemplo, criação de índice, alteração de mapping) não foi concluída no tempo previsto e expirou. O nó master não conseguiu processar a atualização a tempo.","cause":"Nó master sob carga pesada, um cluster state muito grande/complexo, alterações frequentes e intensas de mapping/template, um master lento, ou problemas na eleição do master.","fix":"Verifique a carga e a saúde do nó master: GET _cluster/health, GET _cat/master, e GET _cluster/pending_tasks para as tarefas pendentes. Reduza o cluster state (diminua índices/mappings/templates desnecessários, evite a explosão de dynamic mapping). Execute operações pesadas do tipo DDL em lotes em períodos de baixo tráfego. Aumente os recursos do master se necessário.","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":"O nome do objeto que você está tentando criar (tabela, índice, view, sequence, sinônimo etc.) já é usado por outro objeto no mesmo schema. No Oracle, os nomes de objetos são únicos dentro de um schema, e até tipos diferentes como tabelas, views e sequences compartilham o mesmo namespace.","cause":"O nome escolhido na instrução CREATE conflita com um objeto existente. Uma armadilha comum: tentar criar uma sequence ou view com o mesmo nome de uma tabela; ou um nome de índice criado automaticamente (por exemplo, o índice da primary key) colidindo com o nome que você especificou.","fix":"Escolha outro nome ou remova o objeto conflitante. Para descobrir qual objeto usa o nome: SELECT object_type, object_name FROM user_objects WHERE object_name = 'YOUR_NAME'; Se você realmente quiser substituí-lo, faça DROP do objeto antigo (faça backup dos dados antes). CREATE OR REPLACE está disponível para views, sinônimos, types e objetos PL/SQL (procedure, function, package, trigger); não existe para tabelas, índices e sequences.","tags":["ddl","create","name","conflict","duplicate","object"]},{"code":"ORA-02449","title":"unique/primary keys in table referenced by foreign keys","severity":"caution","meaning":"A primary key ou unique key da tabela que você quer remover é referenciada por foreign keys em outras tabelas. O Oracle não permite remover a tabela sem antes remover essas dependências.","cause":"Você executou DROP TABLE sem CASCADE CONSTRAINTS enquanto outras tabelas referenciam esta tabela por FKs. Garantindo a integridade referencial, o Oracle impede foreign keys órfãs.","fix":"Para removê-la junto com as foreign keys dependentes: DROP TABLE table_name CASCADE CONSTRAINTS; Isso também remove as constraints FK relacionadas nas outras tabelas (não exclui os dados dessas tabelas). Para ver quais constraints dependem dela: 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":"O usuário não tem cota no tablespace em que está tentando gravar. No Oracle, um usuário precisa ter cota no tablespace para alocar espaço para um objeto.","cause":"Não foi concedida ao usuário uma cota no tablespace; tipicamente um usuário novo sem o privilégio de sistema UNLIMITED TABLESPACE tenta criar uma tabela/índice ou inserir dados em seu tablespace padrão. Aparece durante INSERT, CREATE TABLE ou crescimento de índice.","fix":"Como DBA, conceda uma cota ao usuário: ALTER USER app_user QUOTA UNLIMITED ON tablespace_name; ou um limite específico: ALTER USER app_user QUOTA 500M ON users; Como alternativa (use com cuidado), pode-se conceder GRANT UNLIMITED TABLESPACE TO app_user;, mas isso dá direitos ilimitados em todos os tablespaces e geralmente não é recomendado.","tags":["tablespace","quota","tablespace quota","privilege","privilege","insert"]},{"code":"ORA-01110","title":"data file N: 'path'","severity":"danger","meaning":"Mensagem complementar (secundária) que indica um problema no datafile com o número e o caminho informados. Ela nunca aparece sozinha; é precedida por outro erro ORA que relata o problema real, e esta linha apenas informa qual datafile foi afetado.","cause":"Geralmente acompanha um erro principal, como datafile offline (ORA-00376), necessidade de media recovery (ORA-01113), corrupção de bloco (ORA-01578) ou arquivo ilegível. Falha de disco, exclusão acidental, arquivo movido ou restauração incompleta a partir do backup podem causá-la.","fix":"Leia o erro ORA real que precede esta linha e resolva-o. Verifique o arquivo afetado: SELECT file#, name, status FROM v$datafile; Se for necessária recuperação: RECOVER DATAFILE 'path'; depois ALTER DATABASE DATAFILE 'path' ONLINE; Se o arquivo foi perdido fisicamente, restaure-o e recupere-o com 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","severity":"danger","meaning":"O Oracle não consegue arquivar um online redo log e, por isso, não pode reutilizar esse grupo de log. Quando o arquivamento trava em modo ARCHIVELOG, o banco pode parar de aceitar novas transações e ficar travado.","cause":"Normalmente o destino dos archive logs ou a Fast Recovery Area (FRA) está cheio; o espaço em disco acabou; o destino de arquivamento está inacessível; ou há um problema de permissão/montagem. Costuma aparecer junto com ORA-19809 (limit exceeded for recovery files) ou ORA-00312.","fix":"Libere espaço no destino de arquivamento/FRA: faça backup dos logs arquivados antigos com RMAN para um destino fora da FRA e exclua-os (DELETE ARCHIVELOG ALL COMPLETED BEFORE ...; com Data Guard, não exclua logs arquivados ainda não enviados/aplicados no standby), ou aumente db_recovery_file_dest_size. Verifique o status do destino: ARCHIVE LOG LIST; e SELECT dest_name, status, error FROM v$archive_dest WHERE status != 'INACTIVE'; Depois de corrigido o problema, o arquivamento continua de onde parou.","tags":["archivelog","archive","redo","fra","recovery area","archiver stuck"]},{"code":"ORA-19809","title":"limit exceeded for recovery files","severity":"danger","meaning":"O espaço alocado para a Fast Recovery Area (FRA) (db_recovery_file_dest_size) está cheio. Sem espaço para logs arquivados, flashback logs e backups, o Oracle não consegue criar novos arquivos de recuperação e o banco pode travar.","cause":"Os logs arquivados se acumularam na FRA por não terem sido copiados e removidos regularmente; o uso de flashback logs cresceu; ou o tamanho alocado é pequeno demais para a carga real. Aparece junto com erros de arquivamento como ORA-16038.","fix":"Analise o uso da FRA: SELECT * FROM v$recovery_file_dest; e SELECT * FROM v$flash_recovery_area_usage; Exclua logs arquivados desnecessários com RMAN: DELETE ARCHIVELOG ALL BACKED UP 1 TIMES TO DISK; (com Data Guard, verifique antes se foram aplicados no standby; recomenda-se CONFIGURE ARCHIVELOG DELETION POLICY TO APPLIED ON ALL STANDBY) ou, como solução permanente, aumente o tamanho: ALTER SYSTEM SET db_recovery_file_dest_size = 50G SCOPE=BOTH; Configure um job RMAN que faça backup dos logs arquivados regularmente.","tags":["fra","recovery area","db_recovery_file_dest_size","archivelog","space","rman"]},{"code":"ORA-00376","title":"file N cannot be read at this time","severity":"danger","meaning":"O datafile com o número informado não pode ser lido no momento porque está offline ou inacessível. Consultas e operações que acessam dados no tablespace afetado falham com este erro.","cause":"O datafile foi colocado offline automaticamente após um erro ou manualmente; está aguardando media recovery; o disco ficou inacessível; ou um arquivo que não pode ser recuperado em modo NOARCHIVELOG foi deixado offline. Geralmente vem acompanhado de uma linha ORA-01110 que identifica o arquivo.","fix":"Veja o status dos arquivos: SELECT file#, name, status FROM v$datafile WHERE status != 'ONLINE'; Recupere e coloque online: RECOVER DATAFILE N; depois ALTER DATABASE DATAFILE N ONLINE; Se houver corrupção/perda física, restaure e recupere com RMAN: RESTORE DATAFILE N; RECOVER DATAFILE N; Corrija também o problema subjacente de disco/hardware.","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 (o listener não encontrou um handler disponível para o tipo de servidor solicitado)","severity":"danger","meaning":"O listener não encontrou um processo servidor (handler) adequado para o tipo de conexão solicitado (dedicado ou compartilhado). O cliente consegue alcançar o listener, mas a conexão não pode ser repassada a um processo servidor.","cause":"A instância não está registrada no listener ou o registro está quebrado; o limite de PROCESSES/SESSIONS foi atingido e nenhum novo processo dedicado pode ser criado; não há dispatchers ou eles são insuficientes em uma configuração de shared server; ou a instância acabou de iniciar e ainda não se registrou no listener.","fix":"Verifique os serviços que o listener enxerga: lsnrctl services (quantidade e estado dos handlers). Registre novamente a instância no listener: ALTER SYSTEM REGISTER; Verifique o limite de PROCESSES: SELECT resource_name, current_utilization, max_utilization, limit_value FROM v$resource_limit WHERE resource_name IN ('processes','sessions'); Se necessário, aumente-o com ALTER SYSTEM SET processes=... SCOPE=SPFILE; e reinicie a instância.","tags":["listener","tns","connection","handler","processes","dispatcher"]},{"code":"ORA-28001","title":"the password has expired","severity":"caution","meaning":"A senha do usuário do banco com o qual você está se conectando expirou porque o PASSWORD_LIFE_TIME do seu profile se esgotou. Nenhuma sessão pode ser aberta até que a senha seja alterada.","cause":"O tempo de vida da senha definido no profile do usuário terminou e o período de carência (grace period) também se esgotou. No Oracle 11g e posteriores, as senhas no profile DEFAULT expiram a cada 180 dias; isso causa indisponibilidades inesperadas, especialmente em contas de serviço de aplicações de longa duração.","fix":"Altere a senha: ALTER USER app_user IDENTIFIED BY new_password; Para evitar problemas recorrentes com contas de aplicação, use um profile sem expiração de senha: CREATE PROFILE app_profile LIMIT PASSWORD_LIFE_TIME UNLIMITED; depois ALTER USER app_user PROFILE app_profile; Também é útil um monitoramento que avise antes da expiração. Verifique o status em ACCOUNT_STATUS na DBA_USERS.","tags":["password","password expired","expired","profile","account","login"]},{"code":"ORA-38029","title":"object statistics are locked","severity":"caution","meaning":"A coleta/exclusão de estatísticas foi rejeitada porque as estatísticas do otimizador de uma tabela (ou schema) estão bloqueadas. Estatísticas bloqueadas ficam protegidas contra recálculo com DBMS_STATS.","cause":"DBMS_STATS.LOCK_TABLE_STATS ou LOCK_SCHEMA_STATS foi chamado anteriormente (por exemplo, para manter as estatísticas fixas), ou uma importação do Data Pump (especialmente CONTENT=METADATA_ONLY) deixou as estatísticas bloqueadas sem intenção. Executar GATHER_TABLE_STATS enquanto estão bloqueadas gera este erro.","fix":"Desbloqueie as estatísticas: EXEC DBMS_STATS.UNLOCK_TABLE_STATS('APP_SCHEMA','MY_TABLE'); ou no nível de schema DBMS_STATS.UNLOCK_SCHEMA_STATS('APP_SCHEMA'); Se não quiser remover o bloqueio mas ainda precisar coletar, use FORCE=>TRUE: EXEC DBMS_STATS.GATHER_TABLE_STATS('APP_SCHEMA','MY_TABLE', force=>TRUE); Para ver o status do bloqueio: 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":"O comando é mais complexo do que o PostgreSQL consegue processar; geralmente expressões muito aninhadas ou muitos operadores aninhados fazem a árvore de expressões ultrapassar o limite de pilha do parser/planner. Pertence à Class 54 (program_limit_exceeded).","cause":"Parênteses/subconsultas aninhadas em excesso ou cadeias de OR/AND; listas WHERE ... IN (...) enormes geradas automaticamente; ou árvores de expressões muito grandes originadas de views recursivas. O limite max_stack_depth é atingido.","fix":"Simplifique a consulta: mova listas IN longas para uma tabela temporária ou um conjunto VALUES e faça JOIN com ela; divida expressões aninhadas; revise consultas enormes geradas por ORM. Se for realmente necessário e o limite de pilha do sistema operacional permitir, aumente max_stack_depth com cuidado (por exemplo, SET max_stack_depth = '4MB';), mas mantenha-o abaixo do ulimit do sistema operacional.","tags":["program_limit","complex","stack","nested","query","max_stack_depth"]},{"code":"58030","title":"io_error","severity":"danger","meaning":"O PostgreSQL encontrou um erro de entrada/saída (I/O) no nível do sistema operacional ao ler ou gravar um arquivo. Isso indica um problema físico ou de sistema de arquivos no acesso aos arquivos do banco. Pertence à Class 58 (system_error).","cause":"Falha de disco ou setores defeituosos; disco cheio; erros no sistema de arquivos; indisponibilidade de armazenamento em rede (NFS/SAN); problemas de permissão; ou limites de descritores de arquivo/inodes do sistema operacional esgotados.","fix":"Verifique a saúde do disco e o espaço livre (df -h, dmesg, dados SMART). Verifique nos logs do PostgreSQL qual arquivo foi afetado. Corrija os erros do sistema de arquivos; substitua o hardware se necessário. Se houver suspeita de corrupção de dados, planeje uma restauração a partir do último backup íntegro e mantenha os checksums habilitados daqui em diante (initdb --data-checksums).","tags":["system_error","io","disk","hardware","file","corruption"]},{"code":"22004","title":"null_value_not_allowed","severity":"caution","meaning":"Um NULL foi passado onde NULL não é aceito. Isso difere de uma restrição NOT NULL de coluna (23502); geralmente decorre de passar NULL a um parâmetro ou operação que não aceita NULL no contexto de uma função ou procedure. Pertence à Class 22 (data_exception).","cause":"Atribuir NULL a uma variável PL/pgSQL declarada como NOT NULL; passar uma string de consulta NULL para EXECUTE; ou passar NULL a argumentos de funções nativas que não o aceitam. Observação: uma função marcada como STRICT não gera erro com entrada NULL — ela retorna NULL sem ser executada.","fix":"Encontre a linha com falha (CONTEXT) e proteja o valor que chega a ela com uma verificação de NULL, ou forneça um padrão com COALESCE: COALESCE(value, default_value). Em PL/pgSQL, valide os valores antes de atribuí-los a variáveis NOT NULL; em SQL dinâmico, garanta que a string passada para EXECUTE não seja NULL. Impeça que campos obrigatórios sejam enviados como NULL na camada de aplicação.","tags":["data_exception","null","function","strict","parameter","coalesce"]},{"code":"42P18","title":"indeterminate_datatype","severity":"caution","meaning":"O PostgreSQL não conseguiu inferir pelo contexto o tipo de dado de uma expressão ou parâmetro. Ocorre com mais frequência quando um placeholder sem tipo (como $1) ou um NULL isolado é usado sem nenhuma indicação de tipo ao redor.","cause":"Parâmetros sem tipo em prepared statements; comparações em que os dois lados são indeterminados, como \"WHERE $1 = $2\"; ou uso de NULL/literais de array sem contexto. O planner não consegue decidir qual tipo usar.","fix":"Adicione um cast explícito à expressão indeterminada: $1::text, $1::integer, NULL::date etc. Por exemplo: SELECT $1::int + 1; Especifique os tipos dos parâmetros do driver/ORM. Em comparações de colunas, garanta que pelo menos um dos lados tenha tipo conhecido.","tags":["syntax","type","indeterminate","cast","parameter","prepared"]},{"code":"42P02","title":"undefined_parameter","severity":"caution","meaning":"A consulta referencia um parâmetro que não existe. O PostgreSQL informa que o parâmetro posicional referenciado (por exemplo, $2) não está definido. Pertence à Class 42 (syntax_error_or_access_rule_violation).","cause":"Referenciar mais parâmetros do que os fornecidos em um comando preparado com PREPARE (por exemplo, enviar dois parâmetros e usar $3); numeração de parâmetros com lacunas; ou índices $N errados em SQL concatenado dinamicamente.","fix":"Garanta que os números dos parâmetros correspondam à quantidade de valores fornecidos; verifique se começam em $1 e seguem sem lacunas. Defina completamente os tipos dos parâmetros no comando PREPARE: PREPARE p(int, text) AS SELECT ... WHERE a=$1 AND b=$2; Se usar ORM/driver, compare a quantidade de parâmetros vinculados com os placeholders da consulta.","tags":["syntax","parameter","prepared","undefined","placeholder","sql"]},{"code":"2F003","title":"prohibited_sql_statement_attempted","severity":"caution","meaning":"Houve a tentativa de executar, dentro de uma função/rotina SQL, um comando proibido naquele contexto. Pertence à Class 2F (sql_routine_exception). Por exemplo, uma função que deveria ser somente leitura tentando modificar dados.","cause":"O PostgreSQL em si raramente gera este código; geralmente ele vem de código de extensões ou de linguagens procedurais. Observação: uma função marcada como IMMUTABLE/STABLE que executa INSERT/UPDATE/DELETE não gera 2F003; ela gera '... is not allowed in a non-volatile function' com o código 0A000 (feature_not_supported).","fix":"Leia na mensagem de erro qual comando foi proibido e consulte a documentação da rotina/extensão envolvida. Se receber o erro de função não volátil (0A000), defina a função que modifica dados como VOLATILE (é o padrão): CREATE FUNCTION ... LANGUAGE plpgsql VOLATILE. Remova chamadas que modificam dados de locais que precisam ser somente leitura (expressões de índice, verificações de constraint).","tags":["sql_routine","function","volatile","prohibited","immutable","side effect"]},{"code":"40003","title":"statement_completion_unknown","severity":"danger","meaning":"O resultado da transação é desconhecido; a conexão com o servidor caiu antes de ficar claro se a transação foi concluída (especialmente durante o COMMIT). O cliente não tem como saber com certeza se as alterações são duráveis. Pertence à Class 40 (transaction_rollback).","cause":"A rede caiu, o servidor travou ou ocorreu um failover depois que o COMMIT foi enviado, mas antes de a resposta chegar. A transação pode ter sido concluída no servidor ou pode ter sofrido rollback.","fix":"Não repita a transação às cegas; primeiro verifique se ela foi de fato aplicada (por exemplo, consultando a linha esperada). Projete transações idempotentes; use chaves de negócio únicas/chaves de idempotência. Implemente uma lógica robusta de reconexão e validação no pool de conexões.","tags":["transaction","commit","unknown","connection","idempotent","failover"]},{"code":"08003","title":"connection_does_not_exist","severity":"danger","meaning":"Houve a tentativa de executar uma operação em uma conexão de banco que não existe (já fechada). A aplicação tentou enviar uma consulta usando um handle de conexão inválido. Pertence à Class 08 (connection_exception).","cause":"Timeout de conexão, fechamento pelo servidor, queda de rede ou uma conexão obtida do pool que na verdade está morta; ou reutilização de uma conexão que recebeu close() no código da aplicação.","fix":"Habilite verificações de disponibilidade no pool de conexões (validation query / keepalive); configure opções que removam conexões mortas do pool (por exemplo, connectionTestQuery/maxLifetime no HikariCP). Na aplicação, garanta que a conexão esteja aberta antes de usá-la e reconecte automaticamente quando ela cair. Revise os valores de TCP keepalive e idle_in_transaction_session_timeout.","tags":["connection","connection","closed","pool","pool","timeout"]},{"code":"25006","title":"read_only_sql_transaction","severity":"caution","meaning":"Houve a tentativa de executar um comando que modifica dados (INSERT/UPDATE/DELETE/DDL) dentro de uma transação somente leitura. A transação está configurada apenas para leituras. Pertence à Class 25 (invalid_transaction_state).","cause":"SET TRANSACTION READ ONLY ou a configuração default_transaction_read_only=on; ou, mais comumente, uma tentativa de escrita em uma réplica de leitura (hot standby / streaming replica). Servidores standby são somente leitura por definição.","fix":"Direcione as escritas para o servidor primário; verifique o roteamento de conexões que separa leituras e escritas. Se foi configurado por engano: SET TRANSACTION READ WRITE; ou, no servidor inteiro, default_transaction_read_only=off. Garanta que a aplicação envie o tráfego de leitura e escrita para o nó correto.","tags":["transaction","read only","read only","replica","standby","primary"]},{"code":"21000","title":"cardinality_violation","severity":"caution","meaning":"Mais de uma linha foi retornada onde se esperava uma única linha. Uma subconsulta escalar retornou várias linhas, ou MERGE/ON CONFLICT DO UPDATE tentou afetar a mesma linha de destino uma segunda vez. Pertence à Class 21.","cause":"Uma subconsulta usada na lista do SELECT ou na forma WHERE = (subconsulta) retornando várias linhas; a mesma chave de conflito proposta mais de uma vez em um único INSERT ... ON CONFLICT DO UPDATE ('cannot affect row a second time'); ou várias linhas de origem correspondendo a uma linha de destino no MERGE. UPDATE ... FROM não gera erro com múltiplas correspondências; a linha de destino é atualizada a partir de apenas uma das linhas de origem, de forma imprevisível.","fix":"Garanta que a subconsulta retorne uma única linha: adicione LIMIT 1, use uma agregação (MAX/MIN) ou forneça uma condição que torne a correspondência única. Nos padrões MERGE e ON CONFLICT, elimine duplicatas no lado da origem com DISTINCT ON/agregação; faça o mesmo com UPDATE ... FROM para evitar resultados silenciosamente errados. Para encontrar correspondências múltiplas inesperadas, execute a subconsulta isoladamente e verifique a contagem de linhas.","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 (a conexão foi encerrada)","severity":"danger","meaning":"Específico do MariaDB: a conexão/thread em execução foi encerrada pelo servidor, a consulta em andamento foi interrompida e a conexão do cliente caiu. Este código não existe no MySQL; lá, a mesma situação aparece como 1317 (ER_QUERY_INTERRUPTED) quando a consulta é interrompida e como 2013 (Lost connection) no lado do cliente quando a conexão cai.","cause":"Um administrador ou ferramenta de monitoramento enviando um comando KILL; o servidor entrando em shutdown; limites de conexões ociosas do MariaDB, como idle_transaction_timeout/wait_timeout; ou o servidor derrubando a conexão sob pressão de recursos. Também ocorre durante manutenções em ambientes de nuvem/proxy.","fix":"Investigue por que a consulta foi encerrada: SHOW PROCESSLIST e o slow query log para consultas longas; agendas de manutenção/reinicialização do servidor; políticas de encerramento de conexões. Capture este erro na aplicação e repita a operação com segurança (se for idempotente). Otimize e divida consultas longas; use reconexão automática no pool de conexões.","tags":["connection","connection killed","kill","thread","shutdown","retry"]},{"code":"1290","title":"ER_OPTION_PREVENTS_STATEMENT: running with the --read-only option (em execução com a opção --read-only)","severity":"caution","meaning":"O servidor MySQL rejeitou um comando que modifica dados (INSERT/UPDATE/DELETE/DDL) porque está em execução com a opção --read-only ou --super-read-only. Com read_only, usuários com CONNECTION_ADMIN/SUPER ainda podem escrever; com super_read_only habilitado, nem eles podem, e a mensagem diz '--super-read-only option'.","cause":"read_only=ON ou super_read_only=ON; na maioria das vezes, uma tentativa acidental de escrita em uma réplica. Réplicas e secundários do Group Replication são mantidos somente leitura para garantir a consistência dos dados; a automação de failover coloca o antigo primário em super_read_only. Escrever no nó errado durante um failover/switchover também causa o erro.","fix":"Direcione as escritas para o servidor primário (source). Se este servidor realmente deve se tornar o novo primário: SET GLOBAL read_only = OFF; (desligar read_only desliga automaticamente também super_read_only; ligar super_read_only também liga read_only). Não altere manualmente em nós gerenciados pela sua ferramenta de HA (Orchestrator/Group Replication/InnoDB Cluster). Para verificar o estado: 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 (em execução no modo somente leitura)","severity":"caution","meaning":"O InnoDB está em execução no modo somente leitura (innodb_read_only=ON) ou o diretório de dados/mídia é somente leitura; escritas e DDL em tabelas InnoDB são rejeitadas. Observação: uma tentativa de escrita com read_only/super_read_only habilitado retorna 1290 (ER_OPTION_PREVENTS_STATEMENT), e não este código.","cause":"O servidor foi iniciado com innodb_read_only=ON (por exemplo, mídia somente leitura, diretório de dados compartilhado, cópia para análise); nesse modo, alterações como INSERT/UPDATE/DELETE e CREATE/DROP/ALTER TABLE não podem ser feitas em tabelas InnoDB.","fix":"Se forem necessárias escritas, inicie o servidor sem innodb_read_only: remova a linha innodb_read_only=ON do my.cnf e reinicie (esta variável não é dinâmica e exige reinicialização). Para verificar o estado: SELECT @@innodb_read_only; Verifique se o diretório de dados e o sistema de arquivos permitem escrita. Se estiver escrevendo em uma réplica/secundário de HA (1290), direcione as escritas para o primário.","tags":["innodb_read_only","read only","read-only mode","innodb","1836"]},{"code":"3819","title":"ER_CHECK_CONSTRAINT_VIOLATED: Check constraint is violated (a constraint CHECK foi violada)","severity":"caution","meaning":"A linha que você está inserindo ou atualizando viola uma constraint CHECK definida na tabela. No MySQL 8.0.16 e posteriores, as constraints CHECK são de fato aplicadas (versões anteriores as ignoravam).","cause":"O valor da coluna não satisfaz a condição da expressão CHECK (por exemplo, informar um preço negativo quando existe CHECK (price >= 0)). Após atualizar versões antigas do MySQL para 8.0.16+, pode surgir inesperadamente porque constraints antes ignoradas passam a ser aplicadas.","fix":"Garanta que o valor satisfaça a condição da constraint; adicione validação no lado da aplicação. Para ver a definição da constraint: SHOW CREATE TABLE my_table; Se a constraint for realmente desnecessária: ALTER TABLE my_table DROP CHECK constraint_name; ou, temporariamente, ALTER TABLE my_table ALTER CHECK constraint_name NOT ENFORCED; Corrija também a origem dos dados inválidos.","tags":["check","constraint","check constraint","validation","8.0","violation"]},{"code":"1118","title":"ER_TOO_BIG_ROWSIZE: Row size too large","severity":"caution","meaning":"O tamanho de linha da tabela que você está definindo excede o tamanho máximo de linha permitido pelo storage engine. O tamanho máximo de linha para colunas que não são BLOB/TEXT é 65535 bytes; o InnoDB tem limites adicionais que dependem do tamanho de página.","cause":"Definir muitas colunas largas (especialmente VARCHAR/CHAR longos); cada caractere ocupando até 4 bytes em conjuntos de caracteres multibyte como utf8mb4; ou colunas grandes armazenadas inline no formato de linha COMPACT/REDUNDANT do InnoDB.","fix":"Converta algumas colunas grandes para TEXT/BLOB (que podem ser armazenadas fora da página); reduza colunas desnecessárias ou muito largas, ou divida a tabela em duas. No InnoDB, usar ROW_FORMAT=DYNAMIC ou COMPRESSED ajuda ao mover colunas grandes para fora da página: ALTER TABLE my_table ROW_FORMAT=DYNAMIC; Considere também o 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 (coluna BLOB/TEXT usada em uma chave sem comprimento de chave)","severity":"caution","meaning":"Você usou uma coluna BLOB ou TEXT em uma definição de índice/chave sem especificar um comprimento de prefixo. Esses tipos não podem ser indexados por completo; apenas os primeiros N caracteres/bytes podem ser indexados.","cause":"Definir um INDEX/UNIQUE/PRIMARY KEY em uma coluna TEXT/BLOB sem comprimento em CREATE TABLE ou CREATE INDEX. O MySQL exige um comprimento de prefixo porque não consegue indexar por completo esses valores potencialmente muito grandes.","fix":"Especifique um comprimento de prefixo no índice, como INDEX (description(255)). Exemplo: ALTER TABLE my_table ADD INDEX idx_description (description(191)); (191 é comumente usado com utf8mb4 por causa do limite de prefixo de chave do InnoDB). Se for necessária busca de texto completo, considere um índice FULLTEXT. Para campos que devem ser curtos e únicos, converter a coluna para VARCHAR pode ser mais adequado.","tags":["index","key","blob","text","prefix","prefix length"]},{"code":"1592","title":"ER_BINLOG_UNSAFE_STATEMENT: Unsafe statement written to the binary log (comando inseguro gravado no binary log)","severity":"caution","meaning":"Com o formato de binlog baseado em STATEMENT, foi executado um comando com resultado não determinístico (que poderia produzir um resultado diferente na réplica). O MySQL emite um aviso ao gravá-lo no binlog porque há risco de inconsistência de dados entre source e réplica.","cause":"Com binlog_format=STATEMENT: funções não determinísticas como UUID(), SYSDATE() ou USER() (NOW() é replicado com segurança em STATEMENT), UPDATE/DELETE com LIMIT mas sem ORDER BY, INSERTs combinados com AUTO_INCREMENT ou determinadas funções definidas pelo usuário/do sistema. Esses comandos podem não produzir o mesmo resultado em todos os servidores.","fix":"Mude o formato do binlog para baseado em linhas (recomendado; ROW é o padrão desde o MySQL 5.7.7): binlog_format=ROW no my.cnf ou SET PERSIST binlog_format = ROW; (a variável binlog_format está obsoleta desde a 8.0.34; a alteração vale para novas sessões). O formato ROW replica com segurança comandos não determinísticos. Se precisar continuar em STATEMENT, substitua funções/expressões não determinísticas por valores constantes e adicione um ORDER BY determinístico às DMLs com LIMIT.","tags":["binlog","replication","unsafe","statement","row","nondeterministic"]},{"code":"3140","title":"ER_INVALID_JSON_TEXT: Invalid JSON text","severity":"caution","meaning":"Um texto JSON inválido (sintaticamente quebrado) foi passado para uma coluna JSON ou função JSON. O MySQL rejeita a operação porque não consegue interpretar o valor como JSON.","cause":"Aspas/colchetes não fechados, vírgula sobrando no final, aspas simples, erros em caracteres de escape ou texto puro enviado a uma coluna JSON. Ocorre quando texto malformado é passado a funções como JSON_SET, JSON_INSERT ou a uma coluna do tipo JSON.","fix":"Corrija o texto JSON para uma sintaxe válida: use aspas duplas, remova vírgulas sobrando no final, verifique os escapes. Teste se o texto é válido: SELECT JSON_VALID('{...}'); (retorna 1 se for válido). Use uma biblioteca confiável para serializar JSON na camada de aplicação e valide-o antes de enviá-lo ao servidor.","tags":["json","invalid","syntax","json_valid","parse","data"]},{"code":"1526","title":"ER_NO_PARTITION_FOR_GIVEN_VALUE: Table has no partition for value (a tabela não tem nenhuma partição para o valor)","severity":"caution","meaning":"O valor da chave de particionamento da linha que você está inserindo não se encaixa em nenhuma partição definida. No particionamento RANGE ou LIST, a inserção falha porque nenhuma partição cobre o valor recebido.","cause":"No particionamento RANGE, inserir um valor além do limite mais alto sem uma partição MAXVALUE definida (por exemplo, uma data futura); no particionamento LIST, a chegada de um valor não listado. Comum em tabelas particionadas por tempo quando a partição do novo período não é adicionada a tempo.","fix":"Adicione uma partição que cubra o valor. Uma nova partição superior para RANGE: ALTER TABLE my_table ADD PARTITION (PARTITION p2026 VALUES LESS THAN (2027)); Para uma partição que capture todo o restante, defina MAXVALUE para RANGE e os valores relevantes para LIST. Em tabelas baseadas em tempo, configure um job de manutenção (event/scheduler) que adicione partições automaticamente.","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 (não foi possível alocar uma nova página por falta de espaço em disco no filegroup)","severity":"danger","meaning":"O SQL Server tentou alocar uma nova página para um objeto, mas o filegroup não tem espaço em disco suficiente. Os arquivos de dados não conseguem crescer nem encontrar uma página livre, por isso a escrita falha.","cause":"O disco que contém o arquivo de dados está cheio; o autogrow está desabilitado no arquivo ou o MAXSIZE foi atingido; ou todos os arquivos do filegroup chegaram ao limite de tamanho. Comum durante INSERTs grandes/criação de índices.","fix":"Libere espaço no disco ou adicione espaço ao filegroup. Aumente o arquivo ou habilite o autogrow: ALTER DATABASE db MODIFY FILE (NAME = logical_name, SIZE = 20GB, MAXSIZE = UNLIMITED, FILEGROWTH = 512MB); Como alternativa, adicione um novo arquivo ao filegroup (em outro disco). Para ver o uso dos arquivos, consulte sys.database_files e o espaço livre com DBCC SQLPERF.","tags":["disk","filegroup","file group","autogrow","space","allocation"]},{"code":"3729","title":"Cannot DROP because it is being referenced by object (não é possível remover porque outro objeto o referencia)","severity":"caution","meaning":"O objeto que você quer remover (tabela, tipo, função etc.) é referenciado por outro objeto, e essa dependência impede o DROP. Objetos com schema binding, em particular, são protegidos dessa forma.","cause":"Tentar remover uma tabela/objeto do qual depende uma view ou função criada WITH SCHEMABINDING; remover uma tabela referenciada por uma foreign key; ou remover um tipo definido pelo usuário enquanto uma tabela/parâmetro ainda o utiliza.","fix":"Remova primeiro os objetos que fazem a referência ou elimine a dependência. Para encontrar dependências: SELECT referencing_schema_name, referencing_entity_name FROM sys.dm_sql_referencing_entities('app_schema.object', 'OBJECT'); Para views com schema binding, primeiro remova o SCHEMABINDING com ALTER VIEW ou remova a view e, em seguida, remova a tabela.","tags":["drop","reference","schemabinding","view","dependencies","dependency"]},{"code":"3961","title":"Snapshot isolation transaction failed because the object was modified by a DDL statement (a transação snapshot falhou porque um comando DDL modificou o objeto)","severity":"caution","meaning":"Uma transação em execução com snapshot isolation falhou porque um objeto que ela acessava foi alterado por um comando DDL (mudança de schema) em outra transação concorrente. Os metadados não são versionados, por isso a transação snapshot não pode continuar.","cause":"Enquanto uma transação iniciada com isolamento SNAPSHOT (SET TRANSACTION ISOLATION LEVEL SNAPSHOT) está em execução, outra sessão executa DDL como ALTER TABLE/CREATE INDEX em uma tabela que ela acessa. Transações snapshot enxergam versões de linhas, mas não versões de schema. Este erro não ocorre com READ COMMITTED SNAPSHOT (RCSI); o RCSI obtém um novo snapshot para cada comando.","fix":"Repita a transação; geralmente ela é bem-sucedida depois que o DDL termina. Como solução permanente, faça as mudanças de schema (DDL) em janelas de manutenção sem carga snapshot pesada. Capture este erro na aplicação e implemente uma lógica de nova tentativa automática. Encurte transações snapshot de longa duração.","tags":["snapshot","isolation level","ddl","concurrency","retry","isolation"]},{"code":"1785","title":"Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths (a constraint FOREIGN KEY pode causar ciclos ou vários caminhos em cascata)","severity":"caution","meaning":"A foreign key que você está adicionando pode criar um ciclo ou vários caminhos de exclusão/atualização em cascata até a mesma tabela em operações em cascata (ON DELETE/UPDATE CASCADE). O SQL Server a rejeita para evitar um comportamento ambíguo em cascata.","cause":"Uma FK com ação em cascata criando uma referência circular entre tabelas (A->B->A) ou vários caminhos em cascata até uma tabela. O SQL Server não permite isso para evitar uma ordem ambígua de cascata e loops infinitos.","fix":"Defina a foreign key como ON DELETE NO ACTION / ON UPDATE NO ACTION (remova a cascata): ALTER TABLE child ADD CONSTRAINT fk ... FOREIGN KEY (...) REFERENCES parent(...) ON DELETE NO ACTION; Implemente a exclusão em cascata necessária com uma trigger INSTEAD OF DELETE: a trigger exclui primeiro as linhas filhas e depois a linha pai (por exemplo, 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;). Uma trigger AFTER DELETE não funciona; a verificação da FK é executada antes da trigger, por isso a exclusão é rejeitada com o erro 547. Revise as dependências circulares no modelo de dados.","tags":["foreign key","fk","cascade","circular reference","cycle","constraint"]},{"code":"9421","title":"XML parsing: illegal xml character","severity":"caution","meaning":"O SQL Server encontrou um caractere não permitido (inválido) ao interpretar um texto como XML. A conversão para o tipo XML ou a atribuição a uma coluna/variável XML falhou por causa desse caractere.","cause":"Caracteres de controle proibidos no XML 1.0 (por exemplo, alguns caracteres no intervalo 0x00-0x1F), codificação errada (incompatibilidade de encoding) ou dados corrompidos/não sanitizados vindos de outra origem. Geralmente ocorre durante CAST(... AS XML) ou um INSERT em uma coluna XML.","fix":"Remova os caracteres inválidos do texto antes de convertê-lo para XML. Torne a codificação de origem (UTF-8/UTF-16) compatível com a de destino; declare a codificação correta na declaração XML. Remova caracteres de controle com REPLACE/NCHAR, ou gere e valide o XML com uma biblioteca padrão na camada de aplicação. Se precisar armazenar o texto bruto, considere 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 (o objeto/principal não foi encontrado porque não existe ou você não tem permissão)","severity":"caution","meaning":"O objeto ou principal de segurança (usuário, role, login) referenciado não existe ou você não tem permissão para acessá-lo/agir sobre ele. Por motivos de segurança, o SQL Server combina os dois casos em uma única mensagem.","cause":"Usar um nome de usuário, role, schema ou objeto inexistente em um comando como GRANT/ALTER/DROP; executar no contexto de banco errado (o objeto está em outro banco); ou não ter o privilégio para a operação. Erros de digitação, maiúsculas/minúsculas e prefixos de schema são causas frequentes.","fix":"Verifique se o nome do objeto/principal está escrito corretamente e se você está no banco certo. Para usuários: SELECT name, type_desc FROM sys.database_principals; para objetos, consulte sys.objects. Garanta que a conta em execução tenha as permissões necessárias (por exemplo, ALTER ANY USER, CONTROL). Use o prefixo de schema correto (como dbo.object).","tags":["permission","principal","privilege","not found","grant","security"]},{"code":"4834","title":"You do not have permission to use the bulk load statement (você não tem permissão para usar o comando de carga em massa)","severity":"caution","meaning":"Você não tem a permissão necessária para executar uma carga em massa com BULK INSERT (ou OPENROWSET BULK). A carga em massa acessa diretamente o sistema de arquivos e os recursos do servidor, por isso exige um privilégio separado.","cause":"O login não tem a permissão ADMINISTER BULK OPERATIONS no nível do servidor ou não é membro da role de servidor bulkadmin (o Azure SQL Database exige, em vez disso, ADMINISTER DATABASE BULK OPERATIONS no nível do banco). Também são necessárias a permissão INSERT na tabela de destino e acesso de leitura ao arquivo de origem para a conta de serviço do SQL Server.","fix":"Conceda a permissão necessária: GRANT ADMINISTER BULK OPERATIONS TO login_name; (nível de servidor) ou adicione o usuário à role apropriada. O Azure SQL DB usa ADMINISTER DATABASE BULK OPERATIONS. Garanta também que a conta de serviço do SQL Server tenha permissão de leitura no arquivo/compartilhamento de destino. Seguindo o princípio do menor privilégio, conceda-a apenas às contas que precisam dela.","tags":["bulk insert","privilege","permission","bulk load","bulkadmin","file"]},{"code":"10928","title":"Resource limit for the database has been reached (Azure SQL) (o limite de recursos do banco foi atingido)","severity":"danger","meaning":"No Azure SQL Database, o banco atingiu um limite de recursos (como requisições/workers simultâneos ou sessões) e a nova requisição foi rejeitada. Isso indica que o teto da camada de serviço selecionada (DTU ou vCore) foi atingido.","cause":"Ultrapassar o máximo de requisições simultâneas (workers) ou sessões permitido pela camada selecionada; um pico repentino de carga; consultas ineficientes/longas consumindo worker threads; ou um pool de conexões superdimensionado.","fix":"Reduza a concorrência: otimize as consultas para encurtar sua duração, feche transações abertas desnecessárias, mantenha o tamanho do pool de conexões razoável. Para carga constante, aumente a camada de serviço (mais DTU/vCore). Monitore o uso de recursos com sys.dm_db_resource_stats. Para erros que permitem nova tentativa, implemente retry com backoff exponencial na aplicação.","tags":["azure","limit","resource","dtu","vcore","concurrency"]},{"code":"40544","title":"The database has reached its size quota (Azure SQL) (o banco atingiu sua cota de tamanho)","severity":"danger","meaning":"O Azure SQL Database atingiu a cota máxima de tamanho de dados definida para a camada de serviço. O banco não pode crescer mais, por isso novas escritas falham.","cause":"Dados crescendo até o limite da camada; índices/log grandes consumindo espaço; ou um MAXSIZE pequeno permitido pela camada selecionada (por exemplo, Basic/Standard série S). Dados históricos não arquivados também enchem a cota rapidamente.","fix":"Libere espaço: exclua/arquive dados desnecessários, remova índices não utilizados, compacte tabelas (data compression). Como solução permanente, aumente o MAXSIZE ou mude para uma camada de serviço superior: ALTER DATABASE db MODIFY (MAXSIZE = 250 GB); Monitore o uso de tamanho com sys.database_files e DMVs relacionadas. Planeje o dimensionamento com antecedência com base na tendência de crescimento.","tags":["azure","size","quota","maxsize","size quota","scaling"]},{"code":"40613","title":"Database is not currently available (Azure SQL) (o banco não está disponível no momento)","severity":"danger","meaning":"No Azure SQL, o banco de destino não está acessível no momento. Geralmente é transitório; aparece brevemente enquanto a plataforma move, reconfigura ou recupera o banco.","cause":"Escalonamento/failover automático, aplicação de patches, balanceamento de carga ou realocação de recursos no lado do Azure; raramente, um evento de plataforma mais longo. As conexões são rejeitadas até que o banco volte a ficar online.","fix":"Aguarde um pouco e tente novamente; este é um erro transitório. Implemente retry automático com backoff exponencial na aplicação; os SDKs/bibliotecas de retry do Azure reconhecem este código de erro como transitório. Se o problema persistir, verifique o Azure Service Health e incidentes regionais. Para alta disponibilidade, considere geo-replicação/um failover group.","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":"A role referenciada não está definida no MongoDB. Um nome de role inexistente foi usado ao conceder uma role a um usuário, atualizar uma role ou consultar os privilégios de uma role.","cause":"Um nome de role digitado errado ou nunca criado em grantRolesToUser/createUser; procurar a role no banco errado (roles são vinculadas a um banco específico); ou uma role personalizada (não nativa) que ainda não foi definida com createRole.","fix":"Verifique o nome da role e o banco ao qual ela pertence. Liste as roles existentes: db.getRoles({showBuiltinRoles: false}) ou a consulta administrativa correspondente em todos os bancos. Se a role personalizada não existir, crie-a primeiro: db.createRole({role:'reader', privileges:[...], roles:[]}). Especifique o db correto ao conceder: 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 (operação não suportada dentro de uma transação multidocumento)","severity":"caution","meaning":"Houve a tentativa de executar, dentro de uma transação multidocumento, uma operação não suportada nesse contexto. Alguns comandos (notadamente certas operações de DDL e de metadados) não podem ser executados dentro de uma transação.","cause":"Operações não suportadas dentro da transação, como criar coleções/índices (dependendo da versão); certos comandos do tipo count/list; ou comandos administrativos não válidos em uma sessão de transação. Versões antigas do MongoDB não suportam DDL dentro de transações (parte disso chegou com a 4.4+).","fix":"Mova a operação não suportada para fora da transação (por exemplo, crie as coleções/índices necessários antes de a transação começar). Verifique sua versão do MongoDB; a 4.4+ suporta parte do DDL dentro de transações. Execute a operação em uma sessão separada no driver. Limite a transação às operações CRUD suportadas.","tags":["transaction","multi-document transaction","ddl","unsupported","session","crud"]},{"code":"20 IllegalOperation","title":"Illegal operation","severity":"caution","meaning":"A operação solicitada é inválida/proibida para o estado atual do servidor ou para o tipo do objeto de destino. O MongoDB retorna este erro genérico quando rejeita uma ação logicamente não permitida.","cause":"Tentar uma operação exclusiva de coleções em uma view; uma renomeação inválida entre dois bancos; uma alteração proibida em coleções do sistema; ou uma ação administrativa não permitida pela configuração do replica set/sharding. Varia conforme o contexto.","fix":"Leia os detalhes da mensagem de erro; geralmente ela informa explicitamente qual operação foi proibida e por quê. Adapte a operação ao tipo do objeto de destino (por exemplo, trabalhe na coleção subjacente em vez da view). Para operações de renomeação/movimentação, revise as restrições do MongoDB (como renameCollection dentro do mesmo banco). Verifique o estado do cluster (replica set/sharding).","tags":["illegal","invalid","operation","view","rename","system"]},{"code":"48 NamespaceExists","title":"Namespace (collection) already exists","severity":"safe","meaning":"A coleção (namespace) que você está tentando criar já existe. O MongoDB informa que ela está presente, portanto não é necessário criar uma nova coleção com o mesmo nome e as mesmas opções.","cause":"Tentar recriar uma coleção existente com createCollection (possivelmente com opções diferentes); scripts de schema/setup executados mais de uma vez; ou tentar redefinir um nome existente como capped collection ou com opções especiais.","fix":"Geralmente pode ser ignorado com segurança; significa que a coleção já existe. Torne seus scripts de setup idempotentes: verifique a existência antes de criar (db.getCollectionNames().includes('name')). Para alterar as opções, é preciso remover e recriar a coleção (faça backup dos dados antes): db.my_collection.drop() e depois createCollection.","tags":["namespace","collection","collection exists","createcollection","already exists","idempotent"]},{"code":"11601 Interrupted","title":"Operation was interrupted","severity":"caution","meaning":"A operação em execução foi interrompida. O MongoDB a encerrou antes da conclusão por causa de uma intervenção externa ou de uma mudança no estado do servidor.","cause":"Um administrador/ferramenta encerrando a operação com db.killOp(); o servidor entrando em shutdown; uma troca de primário no replica set (stepdown/failover). (Ultrapassar maxTimeMS retorna 50 MaxTimeMSExpired, e não este erro.) Consultas longas podem ser interrompidas dessa forma.","fix":"Investigue por que a operação foi interrompida: histórico de currentOp/killOp, eventos de failover, manutenção do servidor. Se a operação for idempotente, repita-a com segurança. Otimize e encurte consultas longas; adicione índices adequados. Use lógica de retry para erros transitórios no driver; garanta a reconexão automática em failovers do replica set.","tags":["interrupted","interruption","killop","failover","stepdown","retry"]},{"code":"85 IndexOptionsConflict","title":"Index already exists with different options / different name (o índice já existe com outras opções / outro nome)","severity":"caution","meaning":"O índice que você está criando entra em conflito com um existente: um índice com o mesmo nome tem opções diferentes, ou um índice equivalente com a mesma chave e as mesmas opções já existe com outro nome. O MongoDB não permite recriar o mesmo índice com uma definição conflitante.","cause":"Criar um índice com o mesmo nome e a mesma chave, mas com opções diferentes (por exemplo, expireAfterSeconds, partialFilterExpression, collation); ou redefinir o equivalente de um índice existente com um nome diferente ('Index already exists with a different name'). A causa típica são definições de índice que divergem com o tempo em scripts da aplicação/de migração. O mesmo nome com uma chave diferente gera, em vez disso, 86 IndexKeySpecsConflict.","fix":"Veja o índice existente: db.my_collection.getIndexes(). Se realmente quiser alterar as opções, remova o índice antigo e crie o novo: db.my_collection.dropIndex('index_name') e depois createIndex(...). Caso contrário, faça a definição corresponder exatamente ao índice existente ou dê outro nome ao novo índice. Torne os scripts de migração idempotentes.","tags":["index","indexes","options","conflict","unique","createindex"]},{"code":"67 CannotCreateIndex","title":"Cannot create index","severity":"caution","meaning":"A criação do índice falhou por causa de uma restrição ou limite. O MongoDB não conseguiu criar o índice solicitado devido aos dados existentes ou à configuração.","cause":"Ultrapassar o número máximo de índices permitido por coleção (64); uma chave grande demais; ou combinações de opções incompatíveis (por exemplo, um tipo de campo inadequado para um índice TTL). Observação: criar um índice único quando os dados existentes contêm duplicatas gera E11000 DuplicateKey, e não este código.","fix":"Se atingir o limite de quantidade de índices, remova os índices não utilizados (analise o uso com $indexStats). Verifique a compatibilidade de tamanho/tipo da chave e a combinação de opções. Em coleções grandes, crie o índice em períodos de baixa carga (desde a 4.2, a criação de índices não bloqueia as escritas por muito tempo; a opção background é ignorada).","tags":["index","indexes","unique","duplicate","limit","ttl"]},{"code":"27 IndexNotFound","title":"Index not found","severity":"safe","meaning":"O índice referenciado não foi encontrado na coleção. Geralmente ocorre ao tentar remover ou renomear um índice inexistente.","cause":"Informar um nome de índice ou uma especificação de chave errados em um comando como dropIndex/hideIndex; o índice ter sido removido anteriormente; ou o nome de índice gerado automaticamente ser diferente do esperado (o MongoDB gera nomes como field_1_field2_-1).","fix":"Liste os índices existentes e seus nomes exatos: db.my_collection.getIndexes(). Repita a operação com o nome ou o documento de chave correto: db.my_collection.dropIndex({field: 1}) ou db.my_collection.dropIndex('field_1'). Escreva os scripts de remoção de modo que não falhem quando o índice não existir (com verificação de existência).","tags":["index","indexes","dropindex","not found","getindexes","name"]},{"code":"79 UnknownReplWriteConcern","title":"Unknown replica set write concern","severity":"caution","meaning":"O write concern especificado não é reconhecido. O valor w usado na operação (um nome de write concern personalizado/com tag ou um valor numérico) não está definido na configuração do replica set.","cause":"Usar um nome de write concern personalizado não definido em getLastErrorModes (por exemplo, um erro de digitação em vez de 'majority' ou um nome de tag personalizado). A configuração e a requisição não correspondem. Observação: solicitar um w numérico acima do número de membros votantes é outro erro (100 UnsatisfiableWriteConcern).","fix":"Garanta que o nome do write concern usado esteja definido nas configurações do replica set. Veja a configuração atual: rs.conf() (settings.getLastErrorModes). Se usar um modo personalizado, defina-o primeiro ou mude para valores padrão ('majority' ou um w numérico válido). Revise a configuração de writeConcern no driver/na string de conexão da aplicação.","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","severity":"caution","meaning":"Você tentou executar o comando DEBUG, mas o servidor não o permite. DEBUG é um comando de diagnóstico de baixo nível e perigoso; por motivos de segurança, ele vem desabilitado ou restrito por padrão nas versões mais recentes do Redis.","cause":"No Redis 7+, os subcomandos DEBUG não são executados sem a configuração enable-debug-command; serviços Redis gerenciados em nuvem geralmente desabilitam o comando por completo; ou o comando é negado por uma ACL. Scripts de teste/diagnóstico (por exemplo, DEBUG SLEEP, DEBUG OBJECT) costumam encontrar este erro.","fix":"Evite DEBUG em produção. Se for realmente necessário em um ambiente local/de teste, habilite-o na configuração: enable-debug-command yes (ou 'local') no redis.conf. Em serviços de nuvem, geralmente o comando não pode ser habilitado; use comandos seguros como MEMORY USAGE, OBJECT ENCODING e INFO para obter informações equivalentes. Se houver uma restrição de ACL, revise as permissões.","tags":["debug","command","prohibited","security","acl","config"]},{"code":"ERR Can't save in background: fork failed","title":"Background save failed: fork failed","severity":"danger","meaning":"O Redis não conseguiu criar um processo filho (fork) para um snapshot RDB em segundo plano ou uma reescrita do AOF. Como a persistência não pode ser executada, os dados não podem ser gravados em disco.","cause":"O sistema operacional não consegue alocar memória suficiente para o fork; geralmente o overcommit_memory está desabilitado e o sistema recusa quando o Redis tenta reservar aproximadamente uma cópia da memória que utiliza. Memória física/virtual insuficiente ou limites de quantidade de processos também podem causá-lo.","fix":"Habilite o overcommit de memória no Linux: sysctl vm.overcommit_memory=1 (adicione ao /etc/sysctl.conf para torná-lo permanente). Adicione memória ao servidor ou reduza o uso de memória do Redis (maxmemory). Disponibilize espaço de swap suficiente. Verifique os limites de processos/descritores de arquivo (ulimit). Se a persistência for crítica, não vá para produção sem essas configurações.","tags":["fork","rdb","aof","persistence","overcommit","memory"]},{"code":"NOPROTO unsupported protocol version","title":"Unsupported RESP protocol version","severity":"caution","meaning":"O cliente solicitou uma versão do protocolo RESP que o servidor não suporta. Geralmente é retornado quando o RESP3 (versão 3) é solicitado com o comando HELLO e o servidor suporta apenas RESP2.","cause":"HELLO 3 foi enviado, mas o servidor executa uma versão antiga do Redis (anterior à 6.0) ou não suporta RESP3; a biblioteca cliente solicita RESP3 por padrão, mas o servidor é antigo. Incompatibilidade de versões.","fix":"Configure seu cliente para usar RESP2 ou solicite uma versão válida com HELLO (HELLO 2). Atualize o servidor para uma versão que suporte RESP3 (Redis 6+). Revise a configuração de versão do protocolo da sua biblioteca cliente; a maioria das bibliotecas consegue voltar automaticamente para RESP2. Verifique a versão do servidor: 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) (opção ou número de argumentos desconhecidos para CONFIG SET)","severity":"caution","meaning":"O parâmetro de configuração que você tentou alterar com CONFIG SET não é reconhecido nesta versão do Redis, ou o número de argumentos está errado. No Redis 7, a mensagem completa é \"ERR Unknown option or number of arguments for CONFIG SET - '<name>'\"; versões mais antigas retornam \"ERR Unsupported CONFIG parameter\". CONFIG GET não gera erro para um parâmetro desconhecido; ele retorna uma lista vazia.","cause":"Um nome de parâmetro digitado errado; usar um parâmetro de outra versão do Redis (parâmetros podem ser adicionados e removidos entre versões); ou o serviço gerenciado em nuvem não permitir a alteração de certos parâmetros. Executar scripts antigos em versões mais novas/mais antigas é a causa típica.","fix":"Verifique o nome de parâmetro válido. Liste as configurações atuais com um padrão, como CONFIG GET 'maxmemory*'. Consulte a lista de parâmetros na documentação da sua versão do Redis; veja a versão com INFO server. Se houver restrição em um serviço de nuvem, use o conjunto de parâmetros permitido pelo provedor. Atualize seus scripts para a versão de destino.","tags":["config","parameter","unsupported","version","config set","config get"]},{"code":"ERR MULTI calls can not be nested","title":"MULTI calls can not be nested","severity":"caution","meaning":"MULTI foi enviado novamente enquanto um bloco MULTI (transação) já estava aberto. O Redis não suporta blocos de transação aninhados; apenas um MULTI pode estar ativo por vez.","cause":"A lógica da aplicação inicia um novo MULTI sem fechar o anterior com EXEC/DISCARD; reutilizar a mesma conexão de um pool de conexões sem redefinir corretamente o estado da transação; ou um wrapper de biblioteca chamando MULTI duas vezes sem perceber.","fix":"Feche cada bloco MULTI com um único EXEC (ou DISCARD para cancelar) e abra um novo bloco somente depois de concluir o anterior. Separe claramente o início/fim da transação no fluxo do código. Garanta que nenhuma transação fique aberta antes de devolver uma conexão ao pool. Se for necessária lógica aninhada, considere fazer a operação atômica com um script 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 (o script Lua tentou acessar uma variável global inexistente)","severity":"caution","meaning":"Um script Lua executado com EVAL/EVALSHA tentou acessar uma variável global não definida. Para proteger o ambiente de scripts, o Redis restringe a criação/leitura de variáveis globais e retorna esse acesso como erro.","cause":"Usar acidentalmente uma variável global em vez de local no script (esquecer a palavra-chave local); acessar um nome não definido por erro de digitação; ou tentar manter estado em uma variável global. O ambiente Lua isolado (sandbox) do Redis não permite isso.","fix":"Declare todas as variáveis do script com local: local x = ... Corrija erros de digitação; garanta que toda variável esteja definida antes do uso. Os scripts devem ser stateless; para estado persistente, use chaves do Redis (KEYS/redis.call), e não variáveis globais do Lua. Mantenha o script curto e determinístico.","tags":["lua","eval","script","global","variable","local"]},{"code":"ERR unknown command","title":"Unknown command","severity":"caution","meaning":"O Redis não reconhece o comando enviado. O nome do comando pode estar errado, não estar disponível nesta versão ou estar desabilitado/renomeado.","cause":"Um nome de comando digitado errado; o comando foi adicionado em uma versão mais recente do Redis (não existe no servidor antigo); chamar um comando que exige um módulo (por exemplo, RedisJSON, RediSearch) sem o módulo carregado; ou o comando foi desabilitado com rename-command/ACL. Às vezes, uma divisão errada dos argumentos pelo cliente também faz o nome do comando parecer corrompido.","fix":"Verifique o nome e a sintaxe do comando (COMMAND DOCS command ou a documentação). Verifique a versão do servidor: INFO server. Para um comando de módulo, verifique se o módulo está carregado: MODULE LIST. Se o comando foi ocultado com rename-command, revise a configuração. Garanta que sua biblioteca cliente codifique o comando corretamente.","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) (requisição com várias chaves durante o rehashing do slot)","severity":"caution","meaning":"No Redis Cluster, enquanto um hash slot estava sendo movido entre nós (rehashing/resharding), foi feita uma requisição com várias chaves pertencentes ao mesmo slot, e algumas das chaves já haviam sido movidas enquanto outras não. O servidor pede que você repita a operação em instantes.","cause":"Executar um comando com várias chaves (MGET, MSET, Lua com várias chaves, transação) enquanto uma migração de slot está em andamento. No slot em migração, algumas chaves estão no nó de origem e outras no nó de destino, por isso o comando não pode ser executado de forma atômica.","fix":"Capture este erro no cliente e tente novamente após uma breve espera (TRYAGAIN é transitório; desaparece quando o resharding termina). Para operações com várias chaves, garanta que todas as chaves estejam no mesmo slot com uma hash tag, como {app_user123}.profile, {app_user123}.settings. Faça o rebalanceamento do cluster (resharding) em períodos de baixo tráfego.","tags":["cluster","slot","rehash","resharding","tryagain","hash tag"]},{"code":"ERR DISCARD without MULTI","title":"DISCARD without MULTI","severity":"caution","meaning":"DISCARD foi enviado sem nenhum bloco MULTI aberto. DISCARD é usado apenas para cancelar uma transação em andamento; ele retorna este erro quando não há nada a cancelar.","cause":"Chamar DISCARD sem MULTI, ou novamente depois que a transação já foi fechada com EXEC/DISCARD; uma chamada incondicional de DISCARD no código de tratamento de erros; ou o estado da conexão diferente do esperado (MULTI não está aberto na conexão obtida do pool).","fix":"Chame DISCARD somente quando um MULTI estiver de fato aberto; acompanhe o estado da transação no código. Nos tratadores de erro, verifique se há uma transação aberta antes de chamar DISCARD. Use o wrapper de transação da sua biblioteca para que ele gerencie o estado automaticamente. Garanta um estado limpo no pool de conexões.","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) (contexto de busca não encontrado para o id; o scroll expirou)","severity":"caution","meaning":"O contexto de busca usado por uma consulta scroll não existe mais no servidor. Geralmente ocorre ao continuar com um scroll_id armazenado depois que o contexto de scroll expirou ou foi limpo.","cause":"O keep-alive especificado para o scroll expirou (pausa longa demais entre as requisições); o contexto foi limpo manualmente (clear scroll); ou o contexto foi perdido quando um nó reiniciou. Os contextos de scroll ficam na memória do nó, por isso seu tempo de vida é limitado.","fix":"Passe um keep-alive suficiente em toda requisição de scroll (por exemplo, scroll=5m) e reduza o intervalo entre as páginas. No Elasticsearch moderno, use search_after + Point in Time (PIT) em vez de scroll para paginação profunda; é mais escalável e o método recomendado. Libere os contextos ao terminar (clear scroll) para não desperdiçar memória.","tags":["scroll","search_after","pit","context","timeout","pagination"]},{"code":"aliases_not_found_exception","title":"Aliases missing","severity":"safe","meaning":"O alias sobre o qual você está tentando operar não existe. Geralmente é retornado ao remover um alias inexistente ou executar uma ação sobre ele.","cause":"O nome do alias está digitado errado; o alias foi excluído anteriormente; ou uma ação remove na API _aliases cita um alias que nunca foi associado. Também ocorre quando nenhum alias corresponde a um padrão curinga.","fix":"Liste os aliases existentes: GET _alias, ou para um índice específico GET my-index/_alias. Repita a operação com o nome correto. Escreva os scripts de exclusão de modo que não falhem quando o alias não existir; trate as ações de forma condicional nas operações em lote do _aliases. Para reapontar aliases de forma atômica, use add e remove em uma única requisição _aliases.","tags":["alias","alias name","not found","aliases","index","routing"]},{"code":"snapshot_missing_exception","title":"Snapshot is missing","severity":"caution","meaning":"O snapshot referenciado não foi encontrado no repositório especificado. Indica que um nome de snapshot inexistente foi usado em uma requisição de restauração, exclusão ou status.","cause":"O nome do snapshot está digitado errado; o snapshot foi excluído anteriormente; o repositório errado foi consultado; ou o backup nunca foi concluído. Um resultado semelhante ocorre quando a definição do repositório foi alterada ou está inacessível.","fix":"Liste os snapshots do repositório: GET _snapshot/repo_name/_all (ou para um nome específico GET _snapshot/repo_name/snapshot_name). Tente novamente com o repositório e o nome de snapshot corretos. Verifique a definição do repositório: GET _snapshot/repo_name. Verifique se sua política de backup (SLM) é executada com sucesso e gera snapshots.","tags":["snapshot","backup","repository","repo","restore","not found"]},{"code":"index_template_missing_exception","title":"Index template is missing","severity":"safe","meaning":"O index template referenciado não foi encontrado. Um nome de template inexistente foi usado ao obter, excluir ou executar uma operação baseada em template.","cause":"O nome do template está digitado errado; o template foi excluído anteriormente; a API de templates legados foi confundida com a API de composable index templates; ou o template nunca foi criado. Também ocorre quando um script de setup não foi concluído.","fix":"Liste os templates existentes. Para composable templates: GET _index_template ou GET _index_template/name. Para templates legados: GET _template. Tente novamente com a API e o nome corretos. Se o template não existir, crie-o: PUT _index_template/name {...}. Torne os scripts de exclusão/atualização idempotentes para que não falhem quando o template não existir.","tags":["index template","template","composable","legacy","not found","mapping"]},{"code":"settings_exception","title":"Invalid settings","severity":"caution","meaning":"A operação foi rejeitada porque a configuração informada é inválida. Ao aplicar configurações de índice ou de cluster, há um problema com o nome da configuração, seu valor ou a possibilidade de alterá-la naquele contexto.","cause":"Um nome de configuração desconhecido/digitado errado; um valor de tipo errado ou fora do intervalo permitido; tentar alterar em um índice ativo uma configuração estática que só pode ser definida na criação do índice (por exemplo, number_of_shards); ou usar uma configuração removida/renomeada.","fix":"Valide o nome e o valor da configuração com base na documentação. Atualize configurações dinâmicas no índice ativo: PUT my-index/_settings {\"index.number_of_replicas\": 2}. Configurações estáticas (por exemplo, number_of_shards) são definidas apenas na criação; alterá-las exige um reindex. Veja as configurações atuais: GET my-index/_settings.","tags":["settings","setting","invalid","static","dynamic","reindex"]},{"code":"shard_not_found_exception","title":"Shard not found","severity":"danger","meaning":"O shard de destino não foi encontrado. O Elasticsearch não conseguiu concluir a requisição porque não conseguiu alcançar o shard correspondente do índice especificado.","cause":"O shard ainda não foi alocado (unassigned) ou está em recovery; o shard está temporariamente ausente porque um nó saiu do cluster; ou uma requisição de baixo nível roteada diretamente a um shard carrega informações de roteamento que não são mais válidas. Ocorre quando a saúde do cluster está degradada.","fix":"Verifique a saúde do cluster e dos shards: GET _cluster/health e GET _cat/shards?v. Veja por que os shards não estão alocados: GET _cluster/allocation/explain. Se um nó foi perdido, traga-o de volta; revise as configurações de disco/alocação (watermark). Se houver recovery em andamento, aguarde a conclusão. Mantenha uma quantidade adequada de réplicas para que os dados continuem disponíveis quando um único nó for perdido.","tags":["shard","shard","unassigned","unassigned shard","recovery","cluster health"]},{"code":"not_x_content_exception","title":"Compressor detection error / body is not valid content (erro na detecção do compressor / o corpo não é um conteúdo válido)","severity":"caution","meaning":"O Elasticsearch não conseguiu reconhecer o corpo da requisição como conteúdo estruturado válido (XContent, como JSON). Os dados enviados não estão no formato esperado ou estão corrompidos.","cause":"O corpo da requisição é um JSON inválido; o cabeçalho Content-Type está errado ou ausente (application/json não enviado); o corpo foi enviado acidentalmente compactado/binário; ou foi enviado JSON simples para endpoints como _bulk, que esperam JSON delimitado por quebras de linha (NDJSON). Erros de escape/codificação também o causam.","fix":"Verifique se o corpo da requisição é um JSON válido e envie o cabeçalho Content-Type: application/json. Para o endpoint _bulk, use NDJSON, em que cada linha é um objeto JSON separado e a última linha termina com uma quebra de linha (Content-Type: application/x-ndjson). Garanta que sua biblioteca cliente serialize o corpo corretamente. Se usar compactação, envie o cabeçalho Content-Encoding adequado.","tags":["json","xcontent","content-type","bulk","ndjson","request body"]},{"code":"document_source_missing_exception","title":"Document source is missing","severity":"caution","meaning":"A operação precisa do campo _source do documento, mas ele não está armazenado. Uma operação que exige _source (por exemplo, atualização parcial, obtenção do source) foi tentada em um índice com o source desabilitado.","cause":"O mapping do índice define _source: {enabled: false}; como o JSON original do documento não é armazenado, atualizações parciais, reindex e consultas que retornam _source não funcionam. Configurações que desabilitam o source para economizar espaço causam esse problema.","fix":"Operações que precisam de _source exigem que o source esteja habilitado no mapping. Ao criar um novo índice, deixe _source habilitado (ele vem habilitado por padrão). Se _source estiver desabilitado em um índice existente, reindexe o documento completo em vez de atualizá-lo (sobrescreva com a API index). Para economizar espaço, considere a filtragem de _source (includes/excludes) ou o synthetic _source em vez de desabilitar o source por completo.","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 não é suportado neste sistema)","severity":"danger","meaning":"A instância não consegue iniciar porque o gerenciamento automático de memória solicitado via MEMORY_TARGET / MEMORY_MAX_TARGET não é suportado pela configuração de memória compartilhada do sistema operacional. No Linux, geralmente isso ocorre porque /dev/shm é menor que o alvo de memória solicitado.","cause":"MEMORY_TARGET está definido com valor maior que /dev/shm (montado como tmpfs); ou MEMORY_TARGET (AMM) é usado com HugePages habilitado; o AMM não é compatível com HugePages, ao passo que o ASMM (SGA_TARGET) é. O Automatic Memory Management do Oracle funciona criando arquivos em /dev/shm e, se esse espaço for insuficiente, a instância não inicia.","fix":"Torne /dev/shm maior que MEMORY_TARGET: remonte o tmpfs (mount -o remount,size=8G /dev/shm) e torne a alteração persistente em /etc/fstab. Como alternativa, use configurações separadas em vez do AMM: defina MEMORY_TARGET e MEMORY_MAX_TARGET como 0 e defina SGA_TARGET e PGA_AGGREGATE_TARGET. Se usar HugePages, desabilite o AMM e prefira o ASMM (SGA_TARGET).","tags":["memory_target","memory","amm","dev/shm","hugepages","startup"]},{"code":"ORA-27102","title":"out of memory","severity":"danger","meaning":"Durante a inicialização, a instância Oracle não conseguiu alocar o segmento de memória compartilhada (SGA) que solicitou ao sistema operacional. Geralmente aparece junto com ORA-27102 e um código de erro OSD/Linux de nível mais baixo (por exemplo, Linux-x86_64 Error: 28: No space left on device).","cause":"A memória solicitada para a SGA excede os limites de memória compartilhada do kernel (shmmax, shmall); o servidor não tem RAM física/swap suficiente; ou a configuração de HugePages está ausente/insuficiente e uma SGA grande não pode ser alocada. Comum após aumentar SGA_MAX_SIZE.","fix":"Aumente os parâmetros de memória compartilhada do kernel: defina kernel.shmmax e kernel.shmall em /etc/sysctl.conf para cobrir a SGA e execute sysctl -p. Se usar HugePages, calcule e defina vm.nr_hugepages com base na SGA. Verifique o total de RAM e swap no servidor; se necessário, reduza 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 (memória do processo esgotada ao tentar alocar N bytes)","severity":"danger","meaning":"Um processo servidor não conseguiu alocar espaço em sua PGA (Program Global Area), ou seja, na memória privada do processo. Diferentemente da memória compartilhada da SGA, trata-se do esgotamento da memória própria de uma única sessão/processo.","cause":"Operações de sort/hash muito grandes, coleções PL/SQL superdimensionadas, variáveis acumulando em loops sem controle ou limites de memória de processo do sistema operacional (ulimit -v/-d, vm.max_map_count, espaço de endereçamento) esgotaram a memória do processo. Em instâncias de 32 bits, o limite do espaço de endereçamento também pode causá-lo.","fix":"Descubra o que está consumindo memória examinando a categoria de alocação na segunda linha do erro (por exemplo, 'pga heap', 'koh-kghu sessi'). Revise PGA_AGGREGATE_LIMIT / PGA_AGGREGATE_TARGET. Verifique os limites do sistema operacional (ulimit -a; memlock, as, stack para o usuário oracle). Otimize a consulta/o PL/SQL e reduza o tamanho dos lotes de processamento em massa. Se necessário, contate o Oracle Support com o arquivo de trace.","tags":["pga","process memory","memory","ulimit","sort","plsql"]},{"code":"ORA-12537","title":"TNS:connection closed","severity":"danger","meaning":"A conexão TNS entre cliente e servidor terminou porque o canal de comunicação foi fechado inesperadamente. A sessão cai enquanto a conexão está sendo estabelecida ou logo em seguida.","cause":"O listener repassou o cliente a um processo servidor, mas o processo não pôde ser criado ou terminou imediatamente: crash da instância, limite de PROCESSES atingido, falta de recursos do sistema operacional, firewall/camada intermediária cortando a conexão ou uma regra TCP.VALIDNODE_CHECKING/TCP.INVITED_NODES no sqlnet.ora rejeitando o cliente. Às vezes, um firewall entre cliente e servidor derruba a conexão ociosa.","fix":"Examine o listener.log e o sqlnet.log. Verifique os limites de PROCESSES/SESSIONS: SELECT * FROM v$resource_limit WHERE resource_name IN ('processes','sessions'); Verifique se as listas TCP.INVITED_NODES/TCP.EXCLUDED_NODES no sqlnet.ora do lado do servidor não rejeitam o IP do cliente (uma incompatibilidade de versão de logon gera ORA-28040, e não este erro). Aumente o timeout de ociosidade no firewall ou envie keepalives com SQLNET.EXPIRE_TIME. Verifique no alert.log se há registros de crash da instância.","tags":["tns","connection","listener","processes","firewall","sqlnet"]},{"code":"ORA-03135","title":"connection lost contact","severity":"danger","meaning":"Uma sessão estabelecida anteriormente e em funcionamento perdeu o contato com o servidor. Uma consulta longa ou uma conexão ociosa foi cortada porque os dois lados não conseguiam mais se comunicar.","cause":"O processo servidor terminou inesperadamente (ORA-00600/07445, kill, limite de recursos); um profile com RESOURCE_LIMIT encerrou a sessão; uma conexão ociosa foi derrubada por um firewall/load balancer; ou houve queda de rede/perda de pacotes. Ocorre tipicamente com consultas que ficam muito tempo sem responder ou com conexões ociosas.","fix":"Procure no alert.log e nos arquivos de trace relacionados o motivo da morte do processo (ORA-00600/ORA-07445?). No lado da rede, aumente o timeout de ociosidade do firewall e habilite a detecção de conexões mortas com SQLNET.EXPIRE_TIME no sqlnet.ora. Verifique os limites CONNECT_TIME/IDLE_TIME no profile do usuário. Examine a pressão de recursos no servidor (memória, CPU, PROCESSES).","tags":["connection","sqlnet","idle","firewall","dead connection","network"]},{"code":"ORA-01033","title":"ORACLE initialization or shutdown in progress (inicialização ou shutdown do ORACLE em andamento)","severity":"danger","meaning":"A instância de banco à qual você está se conectando está no meio da inicialização (mount/open) ou do shutdown. Conexões normais de usuários não são aceitas nesse estado intermediário.","cause":"A instância está presa em NOMOUNT/MOUNT (por exemplo, aguardando media recovery), um SHUTDOWN está em andamento ou o banco travou antes de chegar a OPEN devido a um erro. Conectar-se a uma instância recém-iniciada antes de a inicialização terminar também retorna este erro.","fix":"Conecte-se como SYSDBA e verifique o estado: sqlplus / as sysdba; depois SELECT status FROM v$instance; e SELECT open_mode FROM v$database; Tente abrir a instância: ALTER DATABASE OPEN; Se for necessária recuperação, execute RECOVER DATABASE; e depois abra-a. Encontre no alert.log o erro subjacente que impede a abertura (datafile ausente/corrompido, redo). Se o shutdown estiver travado, tente SHUTDOWN ABORT seguido de STARTUP.","tags":["startup","shutdown","mount","open","recovery","instance"]},{"code":"ORA-00600","title":"internal error code, arguments: [...]","severity":"danger","meaning":"Uma verificação interna de consistência no kernel do Oracle falhou. É um erro interno genérico que indica que o código do kernel encontrou uma condição inesperada; os argumentos entre colchetes identificam qual caminho de código foi acionado.","cause":"Pode ser causado por corrupção de bloco/dados, um bug não corrigido do software Oracle, níveis de patch inconsistentes, problemas de memória/hardware ou casos-limite inesperados. O primeiro argumento (por exemplo, [ktbdchk1]) indica a qual camada o problema está relacionado e é fundamental para a análise do suporte.","fix":"Este erro quase sempre deve ser tratado com o Oracle Support. Preserve o arquivo de trace gerado e a entrada do alert.log; pesquise o primeiro argumento no My Oracle Support com o ORA-600 Troubleshooter e a 'ORA-600 Lookup Tool'. Aplique o patch/PSU/RU apropriado. Se houver suspeita de corrupção, verifique a integridade dos blocos com DBVERIFY/RMAN VALIDATE. Em ambientes críticos, não faça experimentos em produção sem abrir uma SR.","tags":["internal","ora-600","kernel","bug","trace","support"]},{"code":"ORA-07445","title":"exception encountered: core dump","severity":"danger","meaning":"Um processo servidor Oracle travou inesperadamente após receber uma exceção do sistema operacional (por exemplo, SIGSEGV segmentation fault, access violation) e gerou um core dump. Diferentemente do ORA-00600, o erro é causado por um sinal do sistema operacional.","cause":"Geralmente um bug do software Oracle, corrupção de memória, blocos de dados/índice corrompidos, bibliotecas incompatíveis ou falha de hardware/memória. O nome da função e o tipo de sinal (por exemplo, SIGSEGV) na mensagem identificam o caminho de código que travou.","fix":"Preserve os arquivos de trace e de incidente gerados e o alert.log, e pesquise no My Oracle Support pelo nome da função + sinal; geralmente é necessário um patch. Execute testes de hardware/memória e alinhe os níveis de patch do sistema operacional e do Oracle. Se houver suspeita de corrupção, execute RMAN VALIDATE / DBVERIFY. Se o erro se repetir, abra uma SR e envie o core dump ao Support.","tags":["ora-7445","core dump","sigsegv","kernel","bug","trace"]},{"code":"ORA-01102","title":"cannot mount database in EXCLUSIVE mode","severity":"danger","meaning":"O banco não pode ser montado em modo EXCLUSIVE porque outra instância (ou arquivos remanescentes de uma instância antiga) ainda parece manter um lock sobre ele. A instância para no estágio MOUNT.","cause":"A instância anterior não foi encerrada corretamente e restaram arquivos de lock (lk<SID> em $ORACLE_HOME/dbs, ou memória compartilhada/semáforos remanescentes); outra instância já está associada ao mesmo banco; ou uma segunda instância foi iniciada em uma instalação não RAC. Processos/memória compartilhada remanescentes de uma instância anterior ou um arquivo lk<SID> obsoleto são as causas mais comuns.","fix":"Verifique se nenhuma outra instância está de fato em execução: ps -ef | grep pmon e ipcs -m (segmentos de memória compartilhada). Se houver remanescentes, faça ABORT da instância e limpe; se necessário, remova segmentos/semáforos remanescentes com ipcrm. Exclua o arquivo de lock lk<SID> em $ORACLE_HOME/dbs (somente se a instância estiver definitivamente parada). Depois, tente STARTUP MOUNT. No RAC, verifique CLUSTER_DATABASE e o status dos nós.","tags":["mount","exclusive","lock","startup","pmon","instance"]},{"code":"ORA-29913","title":"error in executing ODCIEXTTABLEOPEN callout (erro ao executar o callout ODCIEXTTABLEOPEN)","severity":"caution","meaning":"Ocorreu um erro ao ler/interpretar o arquivo de origem durante o acesso a uma external table. O Oracle falhou na rotina do access driver (ORACLE_LOADER / ORACLE_DATAPUMP) que chama para obter os dados da external table.","cause":"Geralmente o arquivo não está no caminho apontado pelo objeto DIRECTORY, o usuário do sistema operacional do Oracle não tem permissão de leitura no arquivo/diretório, não há permissão de escrita para os arquivos de log/bad, ou os access parameters (delimitador de campo, formato de registro) estão errados. Costuma vir acompanhado de suberros como ORA-29400 e KUP-04xxx.","fix":"Leia os suberros (KUP-xxxx) para determinar a causa raiz. Verifique o caminho do DIRECTORY e se o arquivo existe: SELECT directory_name, directory_path FROM all_directories; Conceda ao usuário do sistema operacional do Oracle permissão de leitura no arquivo e no diretório, e permissão de escrita no diretório de log/bad. Ajuste a seção ACCESS PARAMETERS da definição da external table ao formato do arquivo de origem. Se necessário, verifique os grants READ/WRITE no DIRECTORY.","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":"O cliente não conseguiu estabelecer uma conexão com o servidor PostgreSQL. A conexão falhou no nível de rede/endereço, antes de se tornar uma sessão.","cause":"Host/porta errados; um endereço em que o servidor não está escutando (conexão remota com listen_addresses = 'localhost'); o servidor está fora do ar/inacessível; um firewall bloqueia a porta (padrão 5432); ou falha na resolução de DNS. Um pool de conexões mal configurado também pode causá-lo.","fix":"Verifique se o servidor está no ar e escutando no endereço correto: confira listen_addresses = '*' (ou o IP correspondente) e a configuração de porta no postgresql.conf e reinicie o servidor (listen_addresses e port exigem reinicialização; um reload não basta). Teste o acesso a partir do cliente: psql -h host -p 5432 -U app_user. Libere 5432/tcp no firewall. Revise os valores de host/porta/DNS e a string de conexão.","tags":["connection","connection","network","listen_addresses","port","firewall"]},{"code":"08004","title":"sqlserver_rejected_establishment_of_sqlconnection","severity":"danger","meaning":"O servidor foi alcançado, mas recusou estabelecer a conexão. Há acesso de rede, mas o servidor não aceitou esta conexão por política.","cause":"O servidor PostgreSQL raramente produz este código; ele é reportado principalmente pelo driver do cliente ou pelo pool de conexões. Os códigos reais do servidor para rejeições semelhantes são outros: uma rejeição do pg_hba.conf ('no pg_hba.conf entry for host', o método reject) retorna 28000 (invalid_authorization_specification), o esgotamento de max_connections retorna 53300 (too_many_connections) e uma conexão recusada durante a inicialização/o shutdown retorna 57P03.","fix":"Leia no log do servidor o SQLSTATE real e o motivo da rejeição. Para uma rejeição do pg_hba (28000), adicione uma linha correspondente ao IP do cliente, ao usuário e ao banco (por exemplo, host all all 10.0.0.0/24 scram-sha-256) e recarregue com SELECT pg_reload_conf();. Para saturação de conexões (53300), compare as conexões de clientes com max_connections usando SELECT count(*) FROM pg_stat_activity WHERE backend_type = 'client backend';","tags":["connection","pg_hba","rejected","authentication","max_connections","reject"]},{"code":"57P01","title":"admin_shutdown","severity":"danger","meaning":"Sua conexão ativa foi encerrada por causa de um comando de administrador. O cliente recebe este erro quando o servidor está sendo desligado ou a sessão é encerrada manualmente ('terminating connection due to administrator command').","cause":"Um DBA encerrou a sessão com pg_terminate_backend(); o servidor está sendo desligado em modo fast/immediate (o smart shutdown não encerra sessões, ele espera que terminem); ou as conexões existentes foram derrubadas por uma mudança de configuração/manutenção planejada. Em alguns cenários de failover, o antigo primário também corta as conexões dessa forma.","fix":"Geralmente não é um erro permanente; a aplicação deve se reconectar (retry). Se for inesperado, investigue no log do servidor o motivo do shutdown/encerramento. Para manutenções planejadas, implemente reconexão automática e health checks do pool de conexões na aplicação. O log do servidor não mostra quem encerrou uma sessão; para rastrear chamadas de pg_terminate_backend, mantenha uma trilha de auditoria com log_statement (ou pgaudit).","tags":["shutdown","terminate","connection","maintenance","failover","retry"]},{"code":"53400","title":"configuration_limit_exceeded","severity":"danger","meaning":"A operação falhou porque um limite de configuração foi excedido. O servidor rejeitou a requisição por causa de um limite definido (por exemplo, temp_file_limit, o número de replication slots ou de WAL senders).","cause":"Exemplos típicos: o uso de arquivos temporários de uma consulta excedendo temp_file_limit ('temporary file size exceeds temp_file_limit'); todos os replication slots em uso ('all replication slots are in use', max_replication_slots); exceder o limite de max_wal_senders. Observação: o esgotamento de max_prepared_transactions retorna 53200, e prepared transactions desabilitadas (valor 0) retornam 55000.","fix":"A mensagem de erro informa qual limite foi excedido. Para temp_file_limit, otimize a consulta (use EXPLAIN ANALYZE para encontrar etapas de sort/hash que transbordam para o disco), aumente work_mem no nível da sessão se necessário ou eleve o limite de forma deliberada. Se os slots estiverem esgotados, limpe os slots não utilizados depois de verificar seus donos: SELECT slot_name, slot_type, active FROM pg_replication_slots; ou aumente max_replication_slots / max_wal_senders e reinicie o servidor.","tags":["limit","temp_file_limit","replication slot","max_wal_senders","configuration","resource"]},{"code":"XX001","title":"data_corrupted","severity":"danger","meaning":"O PostgreSQL detectou corrupção de dados em uma página de tabela/heap. A consulta não pode ser concluída com segurança porque o conteúdo do bloco lido é inconsistente ('invalid page in block').","cause":"Falha de disco/armazenamento, corrupção do sistema de arquivos, garantias de fsync não respeitadas durante uma queda repentina de energia, hardware defeituoso (RAM/controladora) ou, raramente, um bug de software. Com checksums habilitados, a corrupção é detectada mais cedo.","fix":"Primeiro verifique o hardware/armazenamento e, se possível, planeje voltar imediatamente para um backup físico (PITR). Se houver um backup íntegro, restaure-o. Para recuperação, COM RISCO PARA OS DADOS e apenas como último recurso, você pode zerar as páginas danificadas com zero_damaged_pages = on e exportar os dados legíveis (isso causa perda de dados). Habilite data_checksums (em um cluster existente com PG12+, pg_checksums --enable com o servidor parado), execute testes de RAM e faça backups PITR regulares.","tags":["corruption","corruption","checksum","page","hardware","pitr"]},{"code":"XX002","title":"index_corrupted","severity":"danger","meaning":"Foi detectada corrupção em uma estrutura de índice. Como os dados para os quais o índice aponta são inconsistentes com as linhas reais do heap, consultas que usam o índice podem retornar resultados errados ou falhar.","cause":"Falha de hardware/armazenamento, ordenação da B-tree quebrada por uma mudança de collation (regra de ordenação) após um upgrade da glibc/ICU do sistema operacional, ou uma queda repentina. Atualizações de collation do sistema operacional, em particular, causam corrupção silenciosa em índices de texto.","fix":"Reconstrua o índice corrompido: REINDEX INDEX idx_name; ou REINDEX TABLE my_table; Em tabelas grandes, use REINDEX INDEX CONCURRENTLY para reduzir o bloqueio. Se a causa for a collation, reconstrua todos os índices de texto afetados e verifique-os com a extensão amcheck (bt_index_check). Se a causa raiz for o hardware, substitua o armazenamento.","tags":["index","index","corruption","reindex","collation","amcheck"]},{"code":"25001","title":"active_sql_transaction","severity":"caution","meaning":"Um comando que só pode ser executado fora de uma transação, ou no início dela, foi chamado com uma transação ativa. Alguns comandos não são executados dentro de um bloco de transação.","cause":"Configurações como SET TRANSACTION ISOLATION LEVEL devem ser emitidas antes da primeira consulta do bloco ('SET TRANSACTION ISOLATION LEVEL must be called before any query'). Da mesma forma, alguns comandos são rejeitados dentro de um BEGIN/transação aberto. Geralmente decorre de a aplicação desabilitar o autocommit e iniciar uma transação silenciosamente.","fix":"Emita as configurações de nível de transação logo no início da transação, antes de qualquer consulta: BEGIN; SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; ... Verifique se a biblioteca cliente abre uma transação implícita (configuração de autocommit). Para comandos que não podem ser executados dentro de um bloco de transação, feche primeiro a transação atual com COMMIT/ROLLBACK.","tags":["transaction","transaction","isolation","set transaction","autocommit","begin"]},{"code":"42P16","title":"invalid_table_definition","severity":"caution","meaning":"O comando DDL foi rejeitado porque a definição da tabela é inválida. A estrutura de tabela/colunas solicitada viola as regras do PostgreSQL.","cause":"Situações como definir mais de uma chave primária ('multiple primary keys for table are not allowed'), definições conflitantes com herança, restrições de colunas generated/identity ou uma alteração para uma estrutura que o ALTER TABLE não consegue produzir. Comum em scripts de migração gerados automaticamente.","fix":"Leia o motivo específico na mensagem de erro. Defina apenas uma PRIMARY KEY; se for necessária uma chave de várias colunas, use uma chave composta na forma PRIMARY KEY (a, b). Revise as regras de colunas identity/generated. Verifique a definição atual da tabela com \\d my_table e corrija o script de migração.","tags":["ddl","table","primary key","definition","alter table","migration"]},{"code":"P0001","title":"raise_exception","severity":"caution","meaning":"Uma função ou trigger PL/pgSQL gerou um erro deliberadamente com RAISE EXCEPTION. Este erro não é produzido pelo motor do banco, mas por código de regra de negócio escrito por você (ou por uma biblioteca).","cause":"Quando a lógica de negócio reprova uma validação, o desenvolvedor chamou RAISE EXCEPTION 'message' USING ERRCODE = ...;. Por exemplo, uma trigger gera um erro personalizado para bloquear uma atualização não permitida ou impor uma regra de consistência.","fix":"A mensagem de erro e os eventuais campos HINT/DETAIL explicam o que a função rejeitou; satisfaça a regra de negócio de acordo. Para encontrar a origem, inspecione o código da função/trigger correspondente (os comandos RAISE). Se for necessário um SQLSTATE específico, atribua um código significativo com RAISE ... USING ERRCODE em vez do genérico P0001, para que a aplicação consiga diferenciá-lo.","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'","severity":"caution","meaning":"O banco de dados (schema) ao qual você está tentando se conectar ou que está tentando usar não existe no servidor. O comando USE ou o nome do banco padrão na string de conexão aponta para um schema inexistente.","cause":"O banco nunca foi criado, seu nome está digitado errado (a diferenciação de maiúsculas/minúsculas pode variar conforme o sistema operacional), ele foi removido ou a aplicação está se conectando ao ambiente errado (dev/prod). Schemas não migrados na mudança para um novo servidor são outra causa comum.","fix":"Liste os bancos existentes: SHOW DATABASES; Garanta que o nome esteja escrito corretamente e que as maiúsculas/minúsculas correspondam (a configuração lower_case_table_names importa). Se não existir, crie-o: CREATE DATABASE database_name CHARACTER SET utf8mb4; ou restaure-o a partir do backup. Verifique o ambiente de destino na configuração de conexão da aplicação.","tags":["database","database","schema","use","name","connection"]},{"code":"1364","title":"Field 'name' doesn't have a default value (o campo não tem valor padrão)","severity":"caution","meaning":"Uma linha foi inserida sem valor para uma coluna definida como NOT NULL sem DEFAULT. No modo SQL estrito, o MySQL gera um erro porque não consegue preencher automaticamente a coluna obrigatória ausente.","cause":"Uma coluna obrigatória (NOT NULL, sem DEFAULT) foi omitida do INSERT, e STRICT_TRANS_TABLES/STRICT_ALL_TABLES está habilitado no sql_mode. Uma aplicação escrita para o modo antigo e permissivo encontra este erro ao ser migrada para um servidor com modo estrito habilitado.","fix":"Adicione ao INSERT um valor para a coluna ausente ou defina um DEFAULT adequado na coluna: ALTER TABLE my_table MODIFY my_column ... NOT NULL DEFAULT 'value'; Se a coluna for realmente opcional, permita NULL. O sql_mode pode ser flexibilizado como solução temporária/de compatibilidade, mas manter o modo estrito é recomendado para a qualidade dos dados.","tags":["insert","not null","default","strict mode","sql_mode","column"]},{"code":"1206","title":"The total number of locks exceeds the lock table size (o número total de locks excede o tamanho da tabela de locks)","severity":"danger","meaning":"O InnoDB esgotou a memória alocada para os locks que mantém (as estruturas de lock dentro do buffer pool). Ocorre quando uma única transação acumula locks de linha/gap demais, e a transação sofre rollback.","cause":"Transações únicas muito grandes: UPDATE/DELETE de milhões de linhas de uma vez, uma cláusula WHERE sem índice que bloqueia a tabela inteira ou um innodb_buffer_pool_size pequeno demais para a carga. Grandes jobs em lote são o gatilho clássico.","fix":"Divida DMLs grandes em lotes pequenos (por exemplo, exclua/atualize 10.000 linhas por vez com LIMIT em um loop e faça COMMIT após cada lote). Indexe as colunas do WHERE para reduzir o número de linhas bloqueadas. Como solução permanente, aumente innodb_buffer_pool_size (as estruturas de lock são alocadas a partir dele). Evite transações desnecessariamente longas.","tags":["innodb","lock","lock","buffer pool","batch","memory"]},{"code":"1236","title":"Got fatal error 1236 from master when reading data from binary log (erro fatal 1236 do master ao ler o binary log)","severity":"danger","meaning":"Um servidor réplica (slave) recebeu um erro fatal ao ler dados do binary log do source (master), e a replicação parou. A réplica não encontra a posição que espera no binlog do source.","cause":"Os arquivos de binary log necessários foram excluídos no source (binlog_expire_logs_seconds — expire_logs_days antes da 8.0, removido na 8.4 — ou PURGE BINARY LOGS); uma lacuna/divergência de GTID; uma posição de binlog corrompida após um crash do source; ou a réplica ficou tão atrasada que solicita um log que não existe mais. 'Could not find first log file name in binary log index file' é a submensagem típica.","fix":"Inspecione o status da replicação: SHOW REPLICA STATUS\\G (8.0.22+; SHOW SLAVE STATUS em versões antigas, a sintaxe antiga foi removida na 8.4). Liste os binlogs disponíveis no source: SHOW BINARY LOGS; Se o log ausente foi removido (purge), é preciso reconstruir a réplica a partir de um novo backup/posição GTID (mysqldump --source-data — --master-data antes da 8.0.26, alias obsoleto na 8.0.26+ — ou o plugin CLONE). Aumente a retenção de binlogs no source conforme a carga; se usar GTIDs, verifique as lacunas de GTID.","tags":["replication","replication","binlog","master","gtid","slave"]},{"code":"1129","title":"Host 'host' is blocked because of many connection errors (host bloqueado por excesso de erros de conexão)","severity":"danger","meaning":"O MySQL bloqueou um host cliente depois que os erros de conexão consecutivos vindos dele ultrapassaram o limite (max_connect_errors). O host entrou na lista de bloqueio por causa dos handshakes que haviam falhado até então.","cause":"Um load balancer/ferramenta de monitoramento envia handshakes incompletos ou malformados para a porta TCP; problemas de rede cortam as conexões no meio; ou um cliente mal configurado fica tentando conexões que falham. Quando o contador de erros atinge max_connect_errors, o host é bloqueado.","fix":"Remova o bloqueio imediatamente: em SQL, TRUNCATE TABLE performance_schema.host_cache; (8.0.23+; FLUSH HOSTS tornou-se obsoleto na 8.0.23 e foi removido na 8.4) ou pela linha de comando, mysqladmin flush-hosts. Para ver os hosts bloqueados: SELECT host, ip, sum_connect_errors FROM performance_schema.host_cache; Corrija a causa raiz: configure a ferramenta de health check/monitoramento para fazer um handshake MySQL completo e verifique a estabilidade da rede. Em ambientes saudáveis, você pode aumentar max_connect_errors para ampliar a tolerância, mas o que importa é resolver os erros de conexão reais.","tags":["connection","host blocked","max_connect_errors","flush hosts","handshake","network"]},{"code":"1194","title":"Table 'name' is marked as crashed and should be repaired (tabela marcada como corrompida; deve ser reparada)","severity":"danger","meaning":"Uma tabela, geralmente armazenada com o engine MyISAM (também Aria no MariaDB), está marcada como corrompida/crashed e não pode ser usada até ser reparada. Consultas que acessam a tabela falham com este erro.","cause":"A tabela MyISAM não foi fechada corretamente durante um crash repentino do servidor/queda de energia, o disco encheu, houve falha de hardware ou o processo mysqld foi encerrado à força. Como o MyISAM não oferece transações nem segurança contra crash, isso acontece com muito mais frequência do que no InnoDB.","fix":"Repare a tabela: REPAIR TABLE table_name; ou offline com myisamchk -r. Sempre faça backup dos arquivos de dados antes de reparar. Como solução permanente, mova as tabelas para InnoDB: ALTER TABLE my_table ENGINE=InnoDB; o que as torna seguras contra crash. Verifique a saúde do disco e a configuração myisam_recover_options.","tags":["myisam","crashed","repair","corruption","corruption","innodb"]},{"code":"1615","title":"Prepared statement needs to be re-prepared (o prepared statement precisa ser preparado novamente)","severity":"caution","meaning":"A execução de um prepared statement do lado do servidor foi rejeitada porque ele se tornou inválido após a alteração dos metadados dos quais depende (definição de tabela/view). O comando precisa ser preparado novamente.","cause":"DDL (ALTER TABLE) na tabela subjacente depois que o comando foi preparado, a tabela sendo recriada, o cache de metadados enchendo e descartando a entrada, ou limites de table_definition_cache/table_open_cache pequenos demais. Comum em sistemas com muito DDL e em alguns cenários de ORM/pool.","fix":"A maioria das bibliotecas cliente captura isso e prepara o comando novamente de forma automática; na aplicação, capture este erro e repita prepare + execute. Se ocorrer com frequência, aumente table_definition_cache e table_open_cache. Evite DDL desnecessário durante o tráfego da aplicação.","tags":["prepared statement","re-prepare","ddl","metadata","cache","retry"]},{"code":"1553","title":"Cannot drop index needed in a foreign key constraint (não é possível remover um índice exigido por uma constraint de foreign key)","severity":"caution","meaning":"Você está tentando remover um índice exigido por uma constraint de foreign key. O InnoDB não permite remover o índice do qual uma FK depende.","cause":"No InnoDB, toda foreign key exige um índice na(s) coluna(s) que fazem a referência. Remover esse índice com DROP INDEX é rejeitado porque deixaria a constraint de FK sem suporte. Geralmente surge ao reorganizar uma tabela (limpeza de índices).","fix":"Primeiro remova a constraint de foreign key e depois remova o índice: ALTER TABLE my_table DROP FOREIGN KEY fk_name; e depois DROP INDEX idx_name ON my_table; Se necessário, recrie a FK de modo que ela dependa de outro índice adequado. Para listar as FKs existentes: 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 (o carregamento de dados locais está desabilitado; deve ser habilitado no cliente e no servidor)","severity":"caution","meaning":"Você tentou carregar dados de um arquivo do lado do cliente com LOAD DATA LOCAL INFILE, mas o recurso está desabilitado no lado do cliente e/ou do servidor. Por motivos de segurança, LOCAL vem desabilitado por padrão no MySQL 8.","cause":"A variável de sistema local_infile está OFF no servidor e/ou o driver do cliente não habilitou LOCAL INFILE. O recurso é restrito por padrão porque pode permitir que um servidor malicioso leia arquivos do cliente.","fix":"Se for realmente necessário, habilite-o nos dois lados: no servidor, SET GLOBAL local_infile = 1; no cliente, habilite a flag LOCAL INFILE do driver (por exemplo, a opção de conexão allowLoadLocalInfile / --local-infile=1). Do ponto de vista de segurança, a abordagem preferida é colocar o arquivo no servidor e usar LOAD DATA INFILE sem LOCAL, ou usar ferramentas de INSERT em massa/importação. Desabilite local_infile novamente ao terminar.","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 (definição de tabela incorreta; só pode haver uma coluna automática e ela deve ser definida como chave)","severity":"caution","meaning":"A definição da tabela é inválida porque as regras de AUTO_INCREMENT foram violadas: uma tabela pode ter apenas uma coluna auto-incremento, e essa coluna deve fazer parte de uma chave (PRIMARY KEY ou UNIQUE/índice).","cause":"Definir mais de uma coluna AUTO_INCREMENT ou deixar a coluna AUTO_INCREMENT fora de todas as chaves (índices). Ocorre durante CREATE TABLE ou ALTER TABLE.","fix":"Mantenha uma única coluna AUTO_INCREMENT e torne-a parte de uma chave: CREATE TABLE t (id INT AUTO_INCREMENT PRIMARY KEY, ...); Para corrigir uma tabela existente, primeiro adicione a coluna a uma chave: ALTER TABLE t ADD PRIMARY KEY (id); depois defina o AUTO_INCREMENT. Se precisar de mais de uma coluna automática, reveja o design; o MySQL não suporta isso.","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'","severity":"caution","meaning":"O parser do Transact-SQL encontrou uma sintaxe inválida perto do token especificado e não conseguiu compilar o comando. A consulta é rejeitada antes de ser executada.","cause":"Um erro de digitação, uma vírgula/parêntese faltando, uma palavra reservada (por exemplo, USER, ORDER) usada sem colchetes, um literal de string não terminado ou uma sintaxe incompatível copiada de outro dialeto SQL. Erros de concatenação em SQL dinâmico também são um gatilho frequente.","fix":"Inspecione com cuidado a região em torno do token informado; o erro muitas vezes está na linha anterior. Coloque palavras reservadas entre colchetes ([Order]) e verifique se parênteses e vírgulas estão balanceados. Se você monta SQL dinâmico, use PRINT @sql para ver o texto gerado e execute-o. Verifique se a sintaxe é suportada pela versão/nível de compatibilidade.","tags":["syntax","syntax error","parse","tsql","dynamic sql","keyword"]},{"code":"8114","title":"Error converting data type X to Y","severity":"caution","meaning":"Um valor não pôde ser convertido de um tipo de dado para outro porque os tipos são incompatíveis. Diferentemente do erro 245, geralmente trata-se de uma conversão de tipo que falhou no nível de parâmetro/expressão (por exemplo, varchar para numeric).","cause":"Enviar texto não numérico ou malformado para uma coluna/parâmetro numérico; estouro de escala/precisão; tentar converter uma string vazia ('') para numeric; ou passar um argumento de tipo errado em uma consulta parametrizada. Comum com conversões implícitas geradas por ORMs.","fix":"Verifique se os valores convertidos cabem no tipo de destino. Use TRY_CONVERT / TRY_CAST para conversão segura; eles retornam NULL em caso de falha, então você pode filtrar essas linhas com WHERE. Faça os tipos dos parâmetros corresponderem aos tipos das colunas. Varra os dados com ISNUMERIC/TRY_CAST para encontrar as linhas problemáticas e limpe as strings vazias.","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 (a instância do SQL Server Database Engine não consegue obter um recurso LOCK)","severity":"danger","meaning":"O SQL Server não conseguiu alocar a memória de que o lock manager precisa e não pode criar mais locks. A operação falha porque o pool de memória de locks está esgotado.","cause":"Locks de granularidade fina (linha/página) demais mantidos ao mesmo tempo: DML grande, sem índice ou em massa; lock escalation impedido; pressão geral de memória no servidor; ou transações abertas de longa duração. Às vezes, a pressão externa de memória é o gatilho.","fix":"Divida operações grandes em lotes menores para reduzir o número de locks simultâneos. Use índices adequados para reduzir o número de linhas varridas/bloqueadas. Revise configurações que desabilitam o lock escalation: trace flags 1211/1224 e ALTER TABLE ... SET (LOCK_ESCALATION = DISABLE); verifique com SELECT name, lock_escalation_desc FROM sys.tables; e DBCC TRACESTATUS(-1); Verifique a memória do servidor e a configuração max server memory, e alivie a pressão de memória.","tags":["lock","lock memory","memory","lock escalation","batch","resource"]},{"code":"3906","title":"Failed to update database because the database is read-only (não foi possível atualizar o banco porque ele é somente leitura)","severity":"caution","meaning":"Você tentou modificar dados (INSERT/UPDATE/DELETE/DDL) em um banco marcado como somente leitura. O SQL Server rejeitou a escrita.","cause":"O banco foi configurado como READ_ONLY; a conexão foi para uma réplica secundária de um Availability Group (destinada a leituras); o banco permaneceu somente leitura após um snapshot ou restore; ou o sistema de arquivos é somente leitura. Uma aplicação direcionada por engano a uma réplica secundária é a causa típica.","fix":"Se ele realmente precisar aceitar escritas: ALTER DATABASE mydb SET READ_WRITE; Em um Availability Group, direcione a aplicação para a réplica primária (verifique o roteamento de conexões ReadWrite / ApplicationIntent). Não é possível escrever em um snapshot somente leitura; use o banco de origem como destino. Verifique também as permissões de arquivos e o sistema de arquivos.","tags":["read only","read-only database","availability group","replica","read_write","write"]},{"code":"15023","title":"User already exists in the current database (o usuário já existe no banco atual)","severity":"caution","meaning":"Ao adicionar um novo usuário ao banco, verificou-se que um usuário com o mesmo nome já existe nesse banco. Também ocorre ao mapear um login para um usuário existente (orphaned users).","cause":"Normalmente, quando um banco é restaurado a partir de backup em outro servidor, os SIDs dos logins não correspondem aos usuários do banco (orphaned users). Tentar adicionar o mesmo nome novamente com CREATE USER ou configurar manualmente o mapeamento login-usuário gera este erro.","fix":"Remapeie o usuário órfão para o login existente: ALTER USER app_user WITH LOGIN = login_name; (recomendado em vez do legado sp_change_users_login). Se o usuário for realmente redundante: DROP USER app_user; Para encontrar órfãos: 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 (falha no login; o login vem de um domínio não confiável e não pode ser usado com autenticação do Windows)","severity":"danger","meaning":"Uma tentativa de login com autenticação do Windows foi rejeitada porque veio de um domínio não confiável (ou foi usada autenticação do Windows onde é exigida autenticação SQL). O servidor não confia nessa identidade.","cause":"O cliente está se conectando com uma identidade Windows de um domínio/grupo de trabalho em que o SQL Server não confia; as máquinas estão em domínios diferentes/não confiáveis; a configuração de Kerberos/SPN está errada; ou a string de conexão usa Integrated Security quando se espera autenticação SQL. Uma tentativa de login SQL com o modo misto desabilitado apresenta sintoma semelhante.","fix":"Se for necessária autenticação SQL, mude o servidor para Mixed Mode e use usuário/senha na string de conexão (Integrated Security=false). Se for necessária autenticação do Windows, verifique a relação de confiança entre domínios e a configuração de DNS/SPN do Kerberos. Garanta que cliente e servidor estejam no mesmo domínio ou em um domínio confiável. Restrinja a causa com o valor de 'state' no error log.","tags":["login","authentication","windows","domain","kerberos","mixed mode"]},{"code":"605","title":"Attempt to fetch logical page belongs to a different allocation unit (a página lógica solicitada pertence a outra allocation unit)","severity":"danger","meaning":"Ao ler uma página, o SQL Server encontrou uma página pertencente a outro objeto, e não ao objeto/allocation unit esperado. É um forte indício de corrupção física/lógica grave do banco.","cause":"Encadeamento de páginas quebrado causado por falha de armazenamento/disco, bug de controladora ou driver, corrupção do cache de escrita durante uma queda repentina de energia ou dano ao sistema de arquivos. Um '605 transitório' pode ocasionalmente decorrer de problemas temporários de I/O, mas os persistentes são corrupção real.","fix":"Execute imediatamente DBCC CHECKDB ('mydb') WITH NO_INFOMSGS, ALL_ERRORMSGS para determinar a extensão do dano. Se possível, restaure a partir de um backup comprovadamente íntegro (prefira um PITR que minimize a perda de dados). Teste o armazenamento/hardware e verifique a configuração PAGE_VERIFY CHECKSUM. As opções de REPAIR podem causar perda de dados, portanto use-as apenas como último recurso e depois de fazer um backup; em ambientes críticos, acione o suporte da 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 (ALTER TABLE ALTER COLUMN falhou porque um ou mais objetos acessam esta coluna)","severity":"caution","meaning":"Você tentou alterar o tipo/propriedade de uma coluna, mas objetos que dependem dela (índice, constraint, coluna computada, estatísticas, view com schema binding etc.) impediram a alteração. A coluna não pode ser alterada até que as dependências sejam removidas.","cause":"A coluna é usada em um índice, em uma constraint PRIMARY KEY/UNIQUE/CHECK/DEFAULT, na expressão de uma coluna computada, em uma view/função definida WITH SCHEMABINDING ou em um objeto de estatísticas. Uma alteração de tipo/tamanho invalidaria esses objetos, por isso o ALTER é rejeitado.","fix":"Primeiro encontre os objetos dependentes e remova-os ou desabilite-os temporariamente, altere a coluna e depois recrie-os. Consulte sys.sql_expression_dependencies e sys.indexes/sys.default_constraints para ver as dependências. Ordem típica: DROP CONSTRAINT/INDEX -> ALTER COLUMN -> CREATE novamente. Para views com schema binding, remova temporariamente o SCHEMABINDING e adicione-o de volta.","tags":["alter column","dependency","index","constraint","schemabinding","ddl"]},{"code":"7202","title":"Could not find server 'name' in sys.servers (o servidor não foi encontrado em sys.servers)","severity":"caution","meaning":"O nome de servidor referenciado na consulta via linked server ou nome de quatro partes (server.database.schema.object) não foi encontrado entre os linked servers configurados. O SQL Server não conseguiu resolver o nome.","cause":"O linked server nunca foi definido; o nome está digitado errado; um linked server que existe em outro ambiente (dev/prod) está ausente em produção; ou OPENQUERY/o nome de quatro partes aponta para o nome de servidor errado. Comum quando scripts são movidos entre servidores.","fix":"Liste os linked servers definidos: SELECT name FROM sys.servers; ou EXEC sp_linkedservers. Adicione-o se necessário: EXEC sp_addlinkedserver @server='SERVER', ...; e configure o mapeamento de logins com sp_addlinkedsrvlogin. Verifique se o nome de quatro partes na consulta usa o nome correto do linked server; se você acessa apenas um objeto local, remova o prefixo do servidor.","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 (o serviço está ocupado; repita a requisição após 10 segundos)","severity":"danger","meaning":"No Azure SQL Database, o serviço rejeitou temporariamente a requisição devido à pressão de recursos (engine throttling). O sistema está ocupado e espera-se que o cliente tente novamente em breve.","cause":"Um recurso como CPU, conexões, taxa de escrita do log de transações ou número de workers atingindo o limite da camada de serviço selecionada (DTU/vCore); um pico repentino de carga; ou consultas longas/ineficientes consumindo o recurso. O 'reason code' que acompanha o erro mostra qual recurso está sendo limitado.","fix":"Implemente lógica de retry com backoff exponencial na aplicação; esse é o comportamento esperado para erros transitórios. Analise o uso de recursos: sys.dm_db_resource_stats e as métricas do portal do Azure. Otimize consultas/índices e reduza a concorrência desnecessária. Se a saturação for persistente, aumente a camada de serviço (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":"Uma escrita (ou outra operação que exige o primário) foi enviada a um membro do replica set que não é o primário no momento. Apenas o primário aceita escritas, por isso a operação foi rejeitada.","cause":"A aplicação está escrevendo em um secundário; durante um failover (eleição), o antigo primário se tornou secundário e o cliente continua conectado a ele; ou a preferência de leitura/escrita e as informações de topologia do driver estão desatualizadas. A ausência do parâmetro replicaSet na string de conexão é a causa típica.","fix":"Configure o driver com todos os membros do replica set e o nome do replica set (replicaSet=... e todos os hosts na string de conexão), para que o driver descubra o primário automaticamente e redirecione em caso de failover. Use a preferência de leitura/escrita padrão, que direciona as escritas para o primário. Como este é um erro transitório, habilite retryable writes na aplicação. Verifique qual membro é PRIMARY com rs.status().","tags":["replica set","primary","failover","write","election","retryable"]},{"code":"91 ShutdownInProgress","title":"The server is in the process of shutting down (o servidor está sendo desligado)","severity":"danger","meaning":"A operação não pôde ser concluída porque o servidor (mongod/mongos) está sendo desligado. Um nó em processo de desligamento rejeita novas requisições e encerra as operações em andamento.","cause":"Uma reinicialização/manutenção planejada, um shutdown que antecede um stepdown do primário em um replica set, um sinal de término enviado pelo contêiner/orquestrador ou o processo sendo parado por esgotamento de recursos. É esperado durante rolling upgrades.","fix":"Geralmente é transitório; use lógica de retry na aplicação e uma conexão de replica set para que as requisições sejam direcionadas a outro membro saudável. Se for inesperado, verifique nos logs do mongod o motivo do shutdown (sinal, OOM killer, recursos). Durante manutenções rolling, faça o stepdown do primário de forma limpa antes de desligá-lo (rs.stepDown()).","tags":["shutdown","shutting down","maintenance","stepdown","replica set","retry"]},{"code":"189 PrimarySteppedDown","title":"Primary stepped down while operation was in progress (o primário fez stepdown durante a operação)","severity":"danger","meaning":"O primário fez stepdown enquanto a operação estava em execução e não aceita mais escritas. Por isso, o comando em andamento foi abortado.","cause":"Uma eleição foi disparada no replica set: o primário sofreu stepdown manual para manutenção, perdeu contato com a maioria, houve uma mudança de prioridade ou ocorreu uma partição de rede. Operações em andamento no momento do failover recebem este erro.","fix":"Normalmente é um erro passível de nova tentativa; com retryable writes/reads habilitados no driver, a operação pode ser direcionada automaticamente ao novo primário. Capture este erro na aplicação e tente novamente. Se acontecer com frequência, investigue a saúde do replica set: verifique os estados dos membros, a latência de rede e o atraso do oplog com rs.status(), e reduza eleições desnecessárias (configurações de heartbeat/timeout).","tags":["stepdown","election","failover","primary","replica set","retry"]},{"code":"24 LockTimeout","title":"Operation exceeded time limit waiting for a lock (a operação excedeu o limite de tempo aguardando um lock)","severity":"caution","meaning":"Uma operação excedeu seu limite de tempo enquanto aguardava um lock necessário (por exemplo, no nível de banco/coleção) e foi abortada. O lock não pôde ser obtido a tempo.","cause":"Uma operação longa ou um comando DDL (por exemplo, operações administrativas conflitantes em uma coleção) mantém o lock necessário; escritas concorrentes intensas; ou uma operação limitada por maxTimeMS expira enquanto aguarda um lock. Ocorre com operações conflitantes de índice/coleção.","fix":"Encontre a operação que mantém o lock: inspecione as operações ativas e em espera com db.currentOp(); encerre-a com db.killOp() se necessário. Mova comandos administrativos conflitantes (criação de índices, collMod, compact) para horários fora de pico. Mantenha as operações curtas e evite transações desnecessariamente longas. Se necessário, ajuste maxTimeMS à carga de trabalho.","tags":["lock","lock wait","timeout","currentop","ddl","concurrency"]},{"code":"7 HostNotFound","title":"Could not find host","severity":"danger","meaning":"O MongoDB não conseguiu resolver/encontrar um nome de host ao qual tentou se conectar. O driver ou um membro do replica set não consegue alcançar o host especificado, por isso a conexão não pode ser estabelecida.","cause":"Falha na resolução de DNS, um nome de host errado/desatualizado na string de conexão, nomes de host dos membros do replica set (rs.conf) que o cliente não consegue resolver, ou um problema de rede/acesso. Em ambientes de contêineres, nomes de host internos que não podem ser resolvidos de fora são a causa típica.","fix":"Verifique se o nome do host está correto e pode ser resolvido (teste o DNS com ping/nslookup). Atualize os hosts na string de conexão. Garanta que os nomes dos membros do replica set possam ser resolvidos tanto pelos clientes quanto pelos membros; se necessário, atualize os nomes de host em rs.conf() para FQDNs/IPs acessíveis. Se usar SRV (mongodb+srv), verifique os registros DNS SRV.","tags":["host","dns","connection","replica set","network","srv"]},{"code":"175 QueryPlanKilled","title":"Query plan killed during execution","severity":"caution","meaning":"O plano de uma consulta em execução se tornou inválido porque os dados/a coleção subjacente mudaram, e ele foi encerrado. A consulta foi abortada porque não podia continuar com segurança.","cause":"Enquanto a consulta estava em execução (especialmente com um cursor aberto), a coleção foi removida, um índice que ela usava foi removido ou ocorreu uma renomeação/reconfiguração. Alterações subjacentes durante chamadas getMore longas são o gatilho típico.","fix":"Reinicie a consulta/o cursor (retry). Garanta que nenhum DDL destrutivo (drop, dropIndex, rename) seja executado na coleção ou no índice enquanto houver consultas em execução; agende essas manutenções fora do tráfego de consultas. Encurte leituras longas e garanta que os índices necessários sejam permanentes.","tags":["query","cursor","getmore","drop","index","plan"]},{"code":"11602 InterruptedDueToReplStateChange","title":"Operation interrupted due to a replication state change (operação interrompida por uma mudança de estado da replicação)","severity":"danger","meaning":"A operação foi interrompida porque o estado do replica set mudou (por exemplo, o primário mudou). O comando em andamento foi encerrado porque não podia ser concluído com segurança na nova topologia.","cause":"Operações em andamento são interrompidas durante uma eleição, um stepdown do primário, mudanças de papel dos membros ou uma mudança de configuração. Tem a mesma raiz que o 189 PrimarySteppedDown e geralmente aparece no momento do failover.","fix":"Este é um erro passível de nova tentativa; com retryable writes/reads habilitados no driver, a operação pode ser repetida no novo primário. Capture este erro na aplicação e tente novamente. Se ocorrer com frequência, investigue a causa das eleições: instabilidade de rede, timeouts de heartbeat, sobrecarga ou atraso do oplog. Monitore a saúde do replica set com rs.status().","tags":["replica set","election","failover","interrupted","retry","state change"]},{"code":"136 CappedPositionLost","title":"Capped collection position lost","severity":"caution","meaning":"Um cursor que lê uma capped collection (de tamanho fixo), normalmente um tailable cursor, perdeu sua posição. O documento em que ele estava posicionado não existe mais porque a coleção o sobrescreveu de forma cíclica.","cause":"Quando uma capped collection fica cheia, os documentos mais antigos são removidos e sobrescritos automaticamente; um tailable cursor que acompanha uma coleção gravada mais rápido do que ele consegue consumir fica para trás e sua posição é sobrescrita. Ocorre em consumidores que acompanham estruturas capped, como o oplog.","fix":"Reposicione o cursor (abra um novo tailable cursor) e reinicie o acompanhamento; capture este erro na aplicação e atualize a leitura. Se a causa raiz for um consumidor que não acompanha a taxa de escrita: aumente o tamanho da capped collection/do oplog ou acelere o consumidor. Para acompanhar alterações de forma confiável, use change streams em vez de tailable cursors sempre que possível.","tags":["capped","tailable cursor","oplog","cursor","position","change stream"]},{"code":"28 PathNotViable","title":"Cannot use the part of the path to traverse the element (não é possível usar essa parte do caminho para percorrer o elemento)","severity":"caution","meaning":"Uma atualização tentou percorrer um caminho de campo com pontos (por exemplo, a.b.c), mas parte do caminho encontrou um tipo que não pode conter subcampos (um valor escalar ou um elemento de tipo errado). Por isso, o caminho não pôde ser percorrido.","cause":"Escrever em um caminho aninhado como a.b.c quando o campo 'a' do documento é um escalar (por exemplo, número/string) e não um objeto/array; ou incompatibilidades de tipo, como encontrar um objeto onde se espera um índice de array. Comum em documentos com schema inconsistente (ao atualizar caminhos profundos com $set).","fix":"Antes de atualizar, garanta que o caminho seja do tipo esperado (objeto/array). Corrija os documentos incompatíveis ou torne a atualização condicional à estrutura do documento. Se necessário, primeiro converta o campo para o tipo correto (por exemplo, substitua o valor escalar por um objeto) e depois grave o campo aninhado. Considere a validação de schema para manter a consistência do schema.","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":"Você tentou criar um consumer group em um stream com XGROUP CREATE, mas já existe um grupo com o mesmo nome nesse stream. O Redis não sobrescreve o grupo existente.","cause":"A aplicação tenta criar o grupo incondicionalmente na inicialização e o grupo é remanescente de uma execução anterior; ou várias instâncias tentam criar o mesmo grupo em paralelo. Típico de lógica de inicialização não idempotente.","fix":"Torne a criação do grupo idempotente: capture e ignore o erro (um grupo existente não é problema). Use XGROUP CREATE stream group $ MKSTREAM para criar o stream automaticamente se ele ainda não existir. Execute XINFO GROUPS stream para ver os grupos existentes. Se realmente quiser redefini-lo, primeiro exclua-o com 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":"Você executou um comando de consumo de stream (XREADGROUP, XACK, XCLAIM etc.), mas a chave (stream) ou o consumer group especificado não existe. O grupo/stream sobre o qual operar não foi encontrado.","cause":"O grupo nunca foi criado (XGROUP CREATE foi pulado); a chave do stream foi excluída ou nunca foi gravada; o nome do grupo/da chave está digitado errado; ou o grupo foi removido com XGROUP DESTROY. Comum quando os consumidores iniciam antes de o grupo ser criado.","fix":"Primeiro garanta que o stream e o grupo existam: XINFO STREAM stream e XINFO GROUPS stream. Se o grupo não existir, crie-o: XGROUP CREATE stream group $ MKSTREAM (também cria o stream, se necessário). Adicione na inicialização da aplicação uma etapa que crie o grupo (ignorando BUSYGROUP). Verifique se os nomes da chave e do grupo estão escritos corretamente.","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":"Você enviou SCRIPT KILL ou FUNCTION KILL, mas nenhum script/função Lua está em execução (e passível de encerramento) no momento. O comando foi rejeitado porque não há nada para encerrar.","cause":"O script já havia terminado quando você tentou pará-lo; SCRIPT KILL foi enviado ao nó errado (enquanto o script é executado em outra instância); ou a condição BUSY se resolveu sozinha antes do SCRIPT KILL. Geralmente é uma questão de timing.","fix":"Se nenhum script estiver de fato travado, não há nada a fazer; esta é uma resposta segura/informativa. Se você receber um erro BUSY (um script excedeu busy-reply-threshold, chamado lua-time-limit antes do Redis 7), tente SCRIPT KILL (FUNCTION KILL para funções) no nó correto onde o script está em execução. Se o script já modificou dados, SCRIPT KILL não funciona; como último recurso, pode ser necessário SHUTDOWN NOSAVE. Divida scripts longos em partes e respeite o limite de tempo.","tags":["lua","script kill","notbusy","busy","script","function"]},{"code":"DENIED Redis is running in protected mode","title":"Redis is running in protected mode","severity":"danger","meaning":"O Redis está em execução no protected mode e rejeitou uma conexão sem senha vinda de fora (de um endereço que não é loopback). Por segurança, o acesso remoto não autenticado é bloqueado.","cause":"O Redis, vinculado a todas as interfaces (ou com uma configuração de bind permissiva), recebeu uma conexão de um cliente externo sem senha (requirepass) configurada. O protected-mode vem ativado por padrão e, nessa situação, bloqueia requisições que não são de loopback. Indica um Redis sem proteção exposto acidentalmente à internet.","fix":"A correção adequada é protegê-lo: defina uma senha forte com requirepass (ou usuários ACL) e escute apenas em interfaces confiáveis com bind. Se for necessário acesso remoto, proteja-o com senha/TLS e restrinja a porta 6379 com um firewall. protected-mode no pode ser definido temporariamente apenas em uma rede fechada/segura, mas NUNCA é recomendado para instalações expostas à internet.","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 (comando não permitido no contexto de assinatura)","severity":"caution","meaning":"Depois que a conexão entrou no modo de assinatura do Pub/Sub, você tentou executar um comando comum (por exemplo, GET/SET) que não é permitido nesse modo. Uma conexão em modo de assinatura aceita apenas um conjunto limitado de comandos. Em versões antigas, a mensagem era \"ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / PING / QUIT allowed in this context\".","cause":"Enviar comandos de dados por uma conexão que passou para o modo de assinatura com SUBSCRIBE/PSUBSCRIBE/SSUBSCRIBE. No protocolo RESP2, uma conexão com assinatura permite apenas (P|S)SUBSCRIBE, (P|S)UNSUBSCRIBE, PING, QUIT e RESET. Compartilhar uma única conexão para pub/sub e trabalho comum é o erro típico.","fix":"Use uma conexão dedicada para Pub/Sub e abra outra para comandos comuns (a maioria das bibliotecas cliente faz isso automaticamente). Envie UNSUBSCRIBE/PUNSUBSCRIBE para sair do modo de assinatura; os comandos comuns voltam a funcionar. No protocolo RESP3 (HELLO 3), outros comandos também são permitidos em uma conexão com assinatura; mude para RESP3 se o seu driver suportar.","tags":["pubsub","subscribe","context","resp","connection","hello"]},{"code":"ERR SELECT is not allowed in cluster mode","title":"SELECT is not allowed in cluster mode","severity":"caution","meaning":"No modo Redis Cluster, você tentou mudar para outro banco lógico (índice de DB) com SELECT. O modo cluster suporta apenas o banco 0; não é possível usar vários DBs.","cause":"Uma aplicação que alterna entre os DBs 0-15 com SELECT no Redis standalone continua enviando o mesmo comando após migrar para o Redis Cluster. Como a arquitetura de cluster distribui os dados por slot, o conceito de múltiplos DBs não é suportado.","fix":"Remova as chamadas de SELECT no modo cluster; apenas o DB 0 é usado. Se precisar de separação lógica, use prefixos de chave (namespaces) (por exemplo, app1:key). Se certas chaves precisarem ser processadas juntas, use uma hash tag ({user123}) para que fiquem no mesmo slot. Torne a configuração da aplicação compatível com cluster.","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":"Um comando Redis foi enviado com menos ou mais argumentos do que o esperado. O comando foi rejeitado sem ser processado porque sua sintaxe não foi atendida.","cause":"Parâmetros faltando/sobrando (por exemplo, apenas SET key em vez de SET key value); variáveis passadas vazias/indefinidas; o comando chamado com a ordem de argumentos errada; ou expansão (spread) defeituosa de arrays/argumentos na biblioteca cliente. Comum com comandos montados dinamicamente.","fix":"Verifique a assinatura correta do comando (por exemplo, SET key value [options]); consulte a referência oficial de comandos. No código cliente, verifique se os argumentos (especialmente os vindos de arrays) não estão vazios/ausentes. Se você monta comandos a partir de entrada do usuário, valide antes a quantidade de argumentos. Teste o comando manualmente no redis-cli para confirmar o número esperado de argumentos.","tags":["syntax","arguments","argument","command","syntax","cli"]},{"code":"ERR Background save already in progress","title":"Background save already in progress","severity":"caution","meaning":"Você tentou iniciar um novo salvamento em segundo plano (BGSAVE) ou uma reescrita do AOF, mas já há um salvamento em segundo plano em andamento. O Redis não permite um segundo processo de salvamento ao mesmo tempo.","cause":"Um novo BGSAVE/BGREWRITEAOF disparado antes de o anterior terminar; scripts de monitoramento ou a aplicação chamando BGSAVE repetidamente enquanto o fork/salvamento demora em um conjunto de dados grande. Um disco lento ou um arquivo RDB grande prolonga o processo.","fix":"Aguarde o término do salvamento em execução; verifique o status com os campos rdb_bgsave_in_progress e aof_rewrite_in_progress em INFO persistence e o timestamp de LASTSAVE. Torne a lógica da aplicação/automação condicional para que não dispare um novo BGSAVE antes de o salvamento anterior terminar. Se os salvamentos demorarem demais, investigue a velocidade do disco e o tamanho do 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 (o offset de bit não é um inteiro ou está fora do intervalo)","severity":"caution","meaning":"O offset de bit informado a uma operação de bits como SETBIT/GETBIT/BITCOUNT é inválido: não é um inteiro ou está fora do intervalo permitido. O Redis não consegue executar uma operação de bits nesse offset.","cause":"Passar um valor não numérico como offset; usar um offset negativo; ou informar um offset muito grande que excede o limite superior permitido (uma string de bits pode ter até 512 MB, ou seja, cerca de 2^32 bits). Surge de erros de cálculo em estruturas de contadores/flags baseadas em bitmap.","fix":"Garanta que o offset seja um inteiro não negativo dentro do intervalo permitido (0 a ~2^32-1; strings têm no máximo 512 MB). Valide os cálculos de offset (por exemplo, os derivados de IDs de usuário) contra overflow/valores negativos. Se forem necessários offsets muito grandes, projete os dados para serem divididos em várias chaves (sharding).","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":"Um nó não está conectado no momento a outro nó com o qual precisa se comunicar. A requisição não pôde ser encaminhada ao nó de destino porque a conexão interna do cluster (camada de transporte) foi perdida.","cause":"Queda de rede ou perda de pacotes, o nó de destino travando/reiniciando, bloqueio por firewall/porta (porta de transporte padrão 9300), o nó deixando de responder temporariamente por pausas de GC, ou um problema de DNS/resolução de host. Pode aparecer de forma transitória durante rolling restarts.","fix":"Inspecione a saúde do cluster e dos nós: use GET _cluster/health e GET _cat/nodes?v para ver qual nó está ausente. Verifique o acesso de rede entre os nós e as regras de firewall para a porta de transporte (9300). Verifique nos logs do nó afetado se há crashes, pausas de GC ou OOM. Revise a estabilidade da rede e a configuração de discovery/seed hosts.","tags":["transport","node","connection","network","9300","cluster"]},{"code":"receive_timeout_transport_exception","title":"Request timed out waiting for a response from another node (timeout aguardando a resposta de outro nó)","severity":"danger","meaning":"Um nó enviou uma requisição a outro nó, mas a resposta não chegou dentro do tempo configurado e a requisição expirou (timeout). A chamada entre nós (transport) não pôde ser concluída.","cause":"O nó de destino sob carga pesada, pausas longas de GC, disco lento/pressão de CPU, latência de rede/perda de pacotes, ou o nó de destino ocupado demais para responder. Comum durante consultas pesadas, grandes operações em lote e rebalanceamento de shards.","fix":"Inspecione o uso de recursos nos nós afetados: verifique o heap da JVM, o GC e a saturação dos thread pools com GET _nodes/stats. Verifique as tarefas rejeitadas/enfileiradas com GET _cat/thread_pool?v. Meça a latência de rede. Reduza a carga (consultas/lotes bulk menores) e revise o heap e os recursos de hardware. Se persistir, adicione nós para distribuir a carga.","tags":["transport","timeout","gc","load","network","thread pool"]},{"code":"routing_missing_exception","title":"Routing value is required for this document (este documento exige um valor de routing)","severity":"caution","meaning":"É necessário um valor de routing para acessar/indexar o documento, mas ele não foi informado. Sem o routing, o Elasticsearch não conseguiu determinar a qual shard o documento pertence.","cause":"O mapping do índice define _routing required=true; é usada uma relação parent-join (parent/child) e os documentos filhos exigem routing; ou o parâmetro routing foi omitido de uma requisição index/get/update/delete. Ler documentos gravados com routing personalizado sem informar o routing é a causa típica.","fix":"Especifique o valor de routing explicitamente na requisição (por exemplo, ?routing=value nas chamadas index/get/update/delete). Com parent-join, passe o id do pai como routing para os documentos filhos. Use, nas leituras/atualizações/exclusões, o mesmo routing usado quando o documento foi gravado. Revise o requisito de _routing (required) no mapping.","tags":["routing","shard","parent-child","join","mapping","index"]},{"code":"too_many_buckets_exception","title":"Trying to create too many buckets","severity":"caution","meaning":"Uma consulta de agregação tentou produzir mais buckets do que o limite superior permitido (search.max_buckets, padrão 65.536). A consulta foi rejeitada para proteger a memória.","cause":"Agregações como terms/date_histogram executadas em campos de alta cardinalidade com um size muito grande ou um intervalo muito fino; agregações aninhadas multiplicando a quantidade de buckets. O limite é aplicado porque a criação excessiva de buckets pode esgotar a memória do nó.","fix":"Reduza o número de buckets produzidos: diminua o size das agregações terms, amplie o intervalo do date_histogram, remova agregações aninhadas desnecessárias. Se forem necessários muitos resultados, pagine-os com uma agregação composite. Aumentar o limite deve ser o último recurso e traz risco de memória: search.max_buckets pode ser alterado com PUT _cluster/settings, mas faça isso com cuidado.","tags":["aggregation","bucket","max_buckets","terms","composite","memory"]},{"code":"shard_lock_obtain_failed_exception","title":"Obtaining shard lock timed out","severity":"danger","meaning":"O Elasticsearch não conseguiu obter dentro do timeout o lock do diretório local (shard lock) necessário para operar em um shard. O shard não pôde ser iniciado nem realocado.","cause":"Uma cópia anterior do mesmo shard (após fechamento/realocação) ainda não liberou o lock; I/O lento/travado; problemas de disco; ou estado obsoleto do shard não limpo após uma reinicialização rápida do nó. Geralmente é transitório, mas, se persistir, o shard fica UNASSIGNED.","fix":"Verifique por que o shard não está alocado: GET _cluster/allocation/explain. Na maioria dos casos, o lock é liberado em pouco tempo e o cluster tenta novamente por conta própria; se necessário, dispare a realocação com POST _cluster/reroute?retry_failed=true. Se persistir, examine os logs do nó afetado em busca de erros de I/O/disco e verifique a saúde do disco. Uma reinicialização limpa do nó problemático pode liberar o lock.","tags":["shard","lock","unassigned","allocation","io","reroute"]},{"code":"parsing_exception","title":"Failed to parse the search request / query DSL (não foi possível interpretar a requisição de busca / o query DSL)","severity":"caution","meaning":"O corpo da consulta enviado (query DSL) não pôde ser interpretado. A consulta não pôde ser executada porque a estrutura JSON da requisição ou a sintaxe da consulta não corresponde ao formato que o Elasticsearch espera.","cause":"JSON inválido, chaves de consulta fora do lugar/desconhecidas, um tipo de consulta (por exemplo, bool, range) usado com a estrutura errada, um nome de campo removido/alterado entre versões, ou um colchete sobrando/faltando. Comum com consultas escritas à mão ou montadas dinamicamente.","fix":"Verifique o corpo da consulta usando a indicação de linha/posição na mensagem de erro; confirme que o JSON é válido. Compare a estrutura do query DSL com a referência oficial (posicionamento de bool/must/filter etc.). Atualize a sintaxe removida em upgrades de versão. Simplifique a consulta aos poucos para isolar a parte com defeito; use o consulta builder da biblioteca cliente sempre que possível.","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 (o documento contém pelo menos um termo enorme longo demais)","severity":"caution","meaning":"Em um documento sendo indexado, um termo (especialmente o valor de um campo keyword/não analisado) excedeu o comprimento máximo permitido em bytes (32766 bytes). O Lucene não consegue indexar um termo tão longo.","cause":"Um valor de texto muito longo gravado (por inteiro) em um campo keyword; por exemplo, o corpo inteiro de um documento, dados base64 ou uma URL/identificador longo colocado em um campo keyword. Como os campos keyword não são analisados, o valor é indexado como um único termo e excede o limite.","fix":"Use um campo text (analisado) para textos longos; keyword serve apenas para valores curtos que precisam de correspondência exata. Para limitar o valor, use ignore_above no mapping (valores mais longos que isso não são indexados, mas continuam armazenados). Se não for necessário, defina campos muito longos com index:false. Reavalie o design do campo (text vs keyword) com base no tipo de dado.","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":"O número total de campos no mapping de um índice excedeu o limite superior permitido (index.mapping.total_fields.limit, padrão 1000). A indexação falha porque não é possível adicionar novos campos.","cause":"Geralmente uma mapping explosion: com dynamic mapping habilitado, documentos JSON não estruturados/com chaves variáveis (por exemplo, objetos cujas chaves vêm de dados do usuário) adicionam cada novo campo ao mapping. Com o tempo, a quantidade de campos cresce rapidamente e atinge o limite.","fix":"Para corrigir a causa raiz, modele dados com chaves variáveis com um campo flattened ou como um array de pares chave-valor em vez de objetos; restrinja o dynamic mapping (dynamic: false ou strict). Se realmente precisar de mais campos, aumente o limite com cuidado: PUT idx/_settings {\"index.mapping.total_fields.limit\": 2000}. Monitore a mapping explosion verificando a quantidade de campos com 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) (falha de verificação: coluna ou índice desconhecido)","severity":"caution","meaning":"A consulta ES|QL (_query), SQL (_sql) ou EQL foi interpretada sintaticamente, mas falhou na verificação semântica: o índice, campo (coluna) ou função referenciado não foi encontrado, ou os tipos são incompatíveis. O texto do erro informa a posição de linha/coluna com problema (por exemplo, \"line 1:18: Unknown column [field]\"). Uma falha de verificação de repositório de snapshots não é este código; é repository_verification_exception.","cause":"Um nome de campo digitado errado ou ausente do mapping; um padrão de índice que não existe ou não corresponde a nenhum índice; uma operação não suportada em um campo text (por exemplo, agrupar pelo text em vez do seu subcampo keyword); uma comparação entre tipos incompatíveis ou uma função desconhecida.","fix":"Corrija a consulta usando a informação linha:coluna da mensagem de erro. Verifique os nomes e tipos dos campos: GET idx/_mapping (para SQL, DESCRIBE idx / SHOW COLUMNS). Verifique o padrão de índice com GET _cat/indices. Use o subcampo keyword (field.keyword) para agrupamento/ordenação; em incompatibilidades de tipo, aplique uma conversão explícita (ES|QL: TO_STRING, TO_INTEGER etc.).","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 (não é possível recuperar N bytes de espaço em disco do limite de M bytes)","severity":"danger","meaning":"O Oracle tentou abrir espaço na Fast Recovery Area (FRA) para um novo arquivo (log arquivado, backup, flashback log), mas não conseguiu recuperar o espaço necessário porque o limite lógico definido por DB_RECOVERY_FILE_DEST_SIZE foi atingido.","cause":"O tamanho da FRA (DB_RECOVERY_FILE_DEST_SIZE) é um limite superior independente do disco físico, e logs arquivados, backups RMAN ou flashback logs o preencheram. A causa raiz geralmente é a falta de backup e exclusão regulares dos logs arquivados, ou backups obsoletos não removidos.","fix":"Analise o uso da FRA: SELECT * FROM v$recovery_area_usage; e SELECT * FROM v$recovery_file_dest; Faça backup dos logs arquivados para um destino fora da FRA e exclua-os (RMAN: BACKUP ARCHIVELOG ALL FORMAT '/backup/arc_%U' DELETE INPUT;) ou remova os backups que não são mais necessários (RMAN: DELETE OBSOLETE;). Com Data Guard, não exclua logs arquivados ainda não aplicados no standby. Como solução permanente, aumente DB_RECOVERY_FILE_DEST_SIZE se houver espaço em disco. Se o Flashback Database não for necessário, considere desabilitá-lo.","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' (enqueue mantido por tempo demais)","severity":"danger","meaning":"Um enqueue de recurso crítico (por exemplo, CF - control file enqueue) foi mantido por um processo por muito mais tempo do que o permitido, e o Oracle encerrou esse processo para evitar que o sistema travasse. Aparece no alert.log junto com uma entrada 'killing enqueue blocker'.","cause":"Um processo de background ou de usuário manteve um enqueue importante além do tempo permitido por causa de um gargalo de I/O, forte pressão de CPU ou uma paralisação do sistema operacional (swapping, discos lentos); para o enqueue do control file (CF), esse tempo é definido por _controlfile_enqueue_timeout (padrão 900 s). Parâmetros ocultos (com underscore) só devem ser alterados sob orientação do Oracle Support. Geralmente causado por latência de armazenamento ou processos lentos como LGWR/CKPT.","fix":"Analise o alert.log e o arquivo de trace do processo encerrado para determinar qual enqueue (geralmente o do control file) e qual processo de background é responsável. A causa real costuma ser a latência de armazenamento/I/O: verifique os tempos de resposta do disco, o multipath e a saúde da controladora. Reduza a pressão de CPU/memória e o uso de swap. Se o erro se repetir, compartilhe a análise do trace com o Oracle Support.","tags":["enqueue","control file","i-o","storage","hang","background process"]},{"code":"ORA-04021","title":"timeout occurred while waiting to lock object (timeout ao aguardar o lock de um objeto)","severity":"caution","meaning":"Ocorreu um timeout ao aguardar a obtenção de um library cache lock/pin em um objeto (package, procedure, type etc.). Geralmente ocorre ao tentar compilar ou alterar um objeto PL/SQL enquanto ele está sendo executado ou bloqueado por outra sessão.","cause":"O objeto a ser alterado/compilado está em execução ativa em outra sessão ou está bloqueado por outro DDL, por isso o library cache lock exclusivo não pode ser obtido. Uma chamada de procedure de longa duração ou uma sessão travada pode estar mantendo o lock.","fix":"Encontre a sessão que bloqueia o objeto: SELECT * FROM dba_kgllock WHERE kgllkhdl IN (SELECT p1raw FROM v$session WHERE event LIKE 'library cache%'); ou identifique a sessão que usa o objeto com v$access e v$session. Repita o DDL/a compilação em uma janela de manutenção com pouca carga. Se necessário, encerre a sessão com segurança. Parar a aplicação brevemente facilita a obtenção do lock.","tags":["library cache","lock","plsql","ddl","compile","timeout"]},{"code":"ORA-04061","title":"existing state of package/procedure has been invalidated (o estado existente do package/procedure foi invalidado)","severity":"caution","meaning":"O estado existente de um objeto PL/SQL chamado (package, procedure, function) foi invalidado porque um objeto do qual ele depende foi alterado. É uma variante da condição de perda de estado acompanhada de ORA-04068; o estado do package mantido pela sessão não é mais válido.","cause":"Enquanto uma sessão usava um package, foi aplicado DDL a esse package ou às suas dependências (mudança na estrutura de tabela, recompilação, mudança de grants). Como resultado, o estado existente do package na sessão foi invalidado. Ocorre em ambientes com deploys frequentes quando são feitas mudanças de schema com a aplicação em execução.","fix":"A mesma chamada geralmente é bem-sucedida na segunda tentativa (já que o estado foi redefinido); capture este erro na aplicação e repita com segurança. Faça as mudanças de schema com pouco tráfego da aplicação/em uma janela de manutenção. Compile os objetos inválidos em massa: EXEC DBMS_UTILITY.COMPILE_SCHEMA('APP_SCHEMA'); Designs que minimizam o estado de package (variáveis globais) reduzem esse efeito.","tags":["plsql","package","invalidate","ddl","state","recompile"]},{"code":"ORA-01466","title":"unable to read data - table definition has changed (não é possível ler os dados; a definição da tabela mudou)","severity":"caution","meaning":"Uma consulta que lia dados de um ponto no passado (Flashback Query, AS OF ou leitura consistente) falhou porque a definição da tabela (DDL) mudou entre o momento passado consultado e agora. O Oracle não consegue ler com segurança os dados daquele momento com a definição atual.","cause":"Um DDL (adição/remoção de coluna, mudança de tipo) foi aplicado à tabela após o timestamp visado pela consulta Flashback/AS OF. Além disso, diferenças de relógio entre cliente e servidor ou consultas a um passado muito recente (alguns segundos) podem gerar este erro devido à resolução de SCN/tempo.","fix":"Execute a consulta flashback para um momento/SCN anterior à mudança de DDL da tabela. Sempre que possível, use um SCN exato em vez de um timestamp (AS OF SCN). Para consultas a um passado muito recente, volte alguns segundos. Se for necessário acesso histórico permanente, considere um design de tabela de versionamento ou de arquivo em vez de DDL.","tags":["flashback","as of","ddl","consistent read","scn","query"]},{"code":"ORA-08176","title":"consistent read failure; rollback data not available (falha de leitura consistente; dados de rollback indisponíveis)","severity":"danger","meaning":"Ao montar uma imagem de leitura consistente, uma consulta encontrou blocos modificados por uma operação que não gera undo; como não existem dados de undo/rollback para esses blocos, a imagem consistente não pôde ser montada. Diferentemente do ORA-01555, o undo nunca foi gerado, em vez de ter sido sobrescrito. (O erro de isolamento serializable é um código separado: ORA-08177.)","cause":"Uma operação que não gera undo é executada no mesmo objeto enquanto a consulta está em andamento: cargas direct-path (INSERT /*+ APPEND */, SQL*Loader DIRECT=TRUE), CREATE INDEX / rebuild de índice ou discrete transactions.","fix":"Execute a consulta novamente depois que a carga direct-path ou a operação de índice terminar (retry). Não agende relatórios longos e jobs de carga direct-path / manutenção de índices no mesmo objeto na mesma janela de tempo. Se o erro se repetir, identifique o job conflitante com o alert log e o ASH e separe os agendamentos.","tags":["undo","consistent read","direct path","append","create index","retry"]},{"code":"ORA-00020","title":"maximum number of processes (N) exceeded (número máximo de processos (N) excedido)","severity":"danger","meaning":"O número de processos da instância atingiu o limite superior definido pelo parâmetro de inicialização PROCESSES, e nenhuma nova conexão/processo pode ser criado. Novas sessões não conseguem se conectar; até um administrador pode não conseguir.","cause":"Um pool de conexões da aplicação superdimensionado, conexões que nunca são fechadas (vazamentos), mais usuários simultâneos do que o esperado ou um parâmetro PROCESSES baixo demais levam à ultrapassagem do limite. Às vezes, jobs em background travados ou processos de consultas paralelas também consomem processos.","fix":"Você pode se conectar com sqlplus -prelim / as sysdba, mas essa conexão não executa SQL (não é possível consultar v$session); ela só serve para oradebug (por exemplo, hanganalyze) e SHUTDOWN ABORT. Para liberar slots, encerre com cuidado, no nível do sistema operacional, processos servidores ociosos da aplicação (ps -ef | grep 'LOCAL=NO'); depois, com uma conexão SYSDBA normal, encontre as sessões vazadas via v$session/v$process e feche-as com ALTER SYSTEM KILL SESSION. Como solução permanente, aumente PROCESSES e reinicie a instância (se SESSIONS estiver definido explicitamente no spfile, ele não é recalculado; atualize-o também). No lado da aplicação, corrija o máximo do pool de conexões e a limpeza de conexões ociosas.","tags":["processes","process","connection","limit","pool","init parameter"]},{"code":"ORA-01113","title":"file N needs media recovery","severity":"danger","meaning":"Um datafile está sendo colocado online ou o banco está sendo aberto, mas o arquivo está inconsistente; é preciso aplicar media recovery antes de prosseguir. O arquivo está em um SCN mais antigo/inconsistente do que o esperado pelo control file.","cause":"O datafile foi restaurado a partir de um backup antigo, o redo não foi aplicado enquanto ele estava offline, ou o arquivo não está atualizado após um crash da instância/do armazenamento. Geralmente causado por pular a etapa de recover após um restore, ou por um arquivo que ficou offline por muito tempo.","fix":"Recupere o arquivo ou o banco: RECOVER DATAFILE N; ou RECOVER DATABASE; depois ALTER DATABASE DATAFILE N ONLINE; ou ALTER DATABASE OPEN; Garanta que os logs arquivados necessários estejam acessíveis. Com RMAN: após um RESTORE, se necessário, execute RECOVER DATAFILE N;. Acompanhe o alert.log para ver quais logs são solicitados.","tags":["media recovery","datafile","redo","restore","recover","scn"]},{"code":"ORA-02393","title":"exceeded call limit on CPU usage","severity":"caution","meaning":"O tempo de CPU permitido para uma única chamada (CPU_PER_CALL), definido no resource profile atribuído à sessão, foi excedido e o Oracle encerrou essa chamada. É uma proteção de limitação de recursos.","cause":"Há um limite CPU_PER_CALL definido no profile do usuário e RESOURCE_LIMIT=TRUE; uma única chamada SQL/PLSQL excedeu esse limite de CPU. Geralmente causado por uma consulta ineficiente/sem controle que consome muito mais CPU do que o esperado.","fix":"Otimize a consulta (índice adequado, plano correto, eliminação de full table scans desnecessários) para que o consumo de CPU fique abaixo do limite. Se a necessidade de negócio for legítima, aumente CPU_PER_CALL no profile do usuário adequado ou defina-o como UNLIMITED: ALTER PROFILE ... LIMIT CPU_PER_CALL ...; Considere gerenciar os recursos de forma mais flexível com o Database Resource Manager em vez de profiles.","tags":["profile","cpu_per_call","resource_limit","resource","query","optimization"]},{"code":"ORA-12801","title":"error signaled in parallel query server Pnnn (erro no servidor de parallel query Pnnn)","severity":"danger","meaning":"Em uma consulta executada em paralelo, um dos servidores de execução paralela (parallel query slaves) encontrou um erro, e esse erro foi repassado ao consulta coordinator. O ORA-12801 é um invólucro; o erro real está na segunda linha que o segue.","cause":"Um processo slave encontrou um erro real durante uma operação paralela: tablespace TEMP insuficiente (ORA-01652), esgotamento da memória PGA (ORA-04030), corrupção de dados, limites de processos paralelos ou outro erro SQL subjacente. O ORA-12801 apenas informa que o erro ocorreu em um contexto paralelo.","fix":"Concentre-se no código de erro real logo após o ORA-12801 e resolva-o (por exemplo, aumentar o TEMP, ajustar a PGA, reparar um bloco corrompido). Se necessário, isole o erro real executando a consulta de forma serial, removendo hints PARALLEL ou reduzindo o grau de paralelismo. Revise PARALLEL_MAX_SERVERS e o uso de recursos.","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":"Uma constraint EXCLUDE (de exclusão) foi violada. Esse tipo de constraint impede que duas linhas entrem em conflito segundo operadores específicos (por exemplo, sobreposição de intervalos &&); a linha inserida/atualizada foi rejeitada porque conflita com uma linha existente.","cause":"Normalmente há uma constraint EXCLUDE baseada em GiST definida (por exemplo, proibindo sobreposição de horários com tstzrange && em agendamentos/reservas de salas) e a nova linha tem um intervalo/valor que se sobrepõe a uma linha existente. Também pode ocorrer quando duas transações concorrentes inserem intervalos sobrepostos.","fix":"Verifique a sobreposição com uma consulta antes de inserir, ou capture o erro na aplicação e mostre ao usuário uma mensagem significativa. Consulte o intervalo/condição correspondente para encontrar a linha existente em conflito. Se a regra de negócio permitir sobreposições, flexibilize a constraint; caso contrário, corrija a entrada. Sob concorrência, repita a transação com segurança para serializá-la.","tags":["exclude","constraint violation","gist","range","overlap","constraint"]},{"code":"23001","title":"restrict_violation","severity":"danger","meaning":"O código restrict_violation do padrão SQL. Importante: o PostgreSQL informa a violação de uma foreign key definida com ON DELETE/ON UPDATE RESTRICT ou NO ACTION não com este código, mas com 23503 (foreign_key_violation); na prática, você não verá este código vindo do PostgreSQL em si.","cause":"Quando uma linha pai com linhas filhas dependentes é excluída ou tem sua chave alterada, o PostgreSQL retorna 23503. O 23001 geralmente aparece em código de aplicação portado de outro banco ou como erro personalizado de uma extensão. Diferentemente de NO ACTION, RESTRICT não pode adiar a verificação para o fim da transação e falha imediatamente.","fix":"Primeiro exclua/atualize as linhas filhas dependentes ou mova-as para outro pai; depois processe a linha pai. Se a regra de negócio permitir, considere redefinir a foreign key com ON DELETE CASCADE ou SET NULL. Em exclusões em massa, acerte a ordem de exclusão (primeiro o filho, depois o pai).","tags":["foreign key","restrict","fk","delete","reference","constraint"]},{"code":"42P17","title":"invalid_object_definition","severity":"danger","meaning":"A definição de um objeto (função, collation, trigger, rule etc.) é inválida. O PostgreSQL indica que a definição informada é internamente inconsistente ou inaceitável; o objeto não pode ser criado/alterado da forma como foi escrito.","cause":"Causas comuns: combinações contraditórias de atributos em uma função (por exemplo, marcada como IMMUTABLE mas com comportamento volátil), uma definição inválida de collation/conjunto de caracteres ou uma definição inadequada de trigger/rule. Opções inconsistentes em row-level security (RLS) e alguns DDLs também podem causá-lo.","fix":"Leia os detalhes do erro (DETAIL/HINT) para determinar qual parte da definição foi rejeitada. Alinhe os rótulos de volatilidade das funções ao comportamento real (VOLATILE/STABLE/IMMUTABLE). Verifique se o nome da collation existe em pg_collation. Corrija a definição de acordo com a sintaxe/as regras documentadas e execute-a novamente.","tags":["function","collation","definition","volatility","ddl","object"]},{"code":"42710","title":"duplicate_object","severity":"caution","meaning":"O objeto que está sendo criado (role, type, constraint, extensão, schema, nome de índice etc.) já existe. O PostgreSQL não permite um segundo objeto com o mesmo nome/definição.","cause":"Um comando como CREATE ROLE, CREATE TYPE, CREATE EXTENSION ou ADD CONSTRAINT foi executado quando já existia um objeto com o mesmo nome. Geralmente causado por um script executado duas vezes, migrações não idempotentes ou duas sessões concorrentes tentando criar o mesmo objeto.","fix":"Verifique se o objeto existe (pg_roles para roles, pg_type para types, pg_extension para extensões). Escreva migrações idempotentes: use CREATE ... IF NOT EXISTS quando disponível ou execute antes DROP ... IF EXISTS. Em um conflito de constraint, renomeie a constraint existente ou remova-a e recrie-a.","tags":["duplicate","role","type","extension","constraint","migration"]},{"code":"22008","title":"datetime_field_overflow","severity":"caution","meaning":"Ao calcular ou interpretar um valor de data/hora, um dos campos ficou fora do intervalo válido. Por exemplo, foi produzido um componente impossível, como mês 13 ou dia 32, ou um resultado além do intervalo de tempo suportado.","cause":"Uma data de entrada inválida (por exemplo, '2026-02-30'), um componente fora do intervalo ou uma soma de INTERVAL que excede o intervalo de datas suportado. Interpretar com o formato/locale errado ou inserir entrada de usuário não validada é a causa típica.","fix":"Valide as datas de entrada na aplicação antes de inserir e envie-as no formato correto (de preferência ISO 8601: YYYY-MM-DD). Ao interpretar com TO_DATE/TO_TIMESTAMP, faça a máscara de formato corresponder à entrada. Mantenha os resultados aritméticos dentro do intervalo de datas suportado; submeta valores suspeitos a verificações de limites.","tags":["date","time","overflow","interval","validation","format"]},{"code":"22026","title":"string_data_length_mismatch","severity":"caution","meaning":"O comprimento de uma string de bits não corresponde ao comprimento fixo exigido pela operação. No PostgreSQL, ocorre com mais frequência quando uma string de bits de outro comprimento é gravada em um tipo bit(n) de comprimento fixo, ou quando AND/OR/XOR bit a bit é aplicado a strings de bits de comprimentos diferentes.","cause":"Gravar uma string de bits menor/maior que n em uma coluna bit(n) (por exemplo, B'101' em uma coluna bit(4): 'bit string length 3 does not match type bit(4)'), ou aplicar &, |, # a strings de bits de comprimentos diferentes ('cannot AND bit strings of different sizes'). Não é causado por texto ou codificação de caracteres; um valor longo demais para char(n)/varchar(n) gera, em vez disso, 22001.","fix":"Ajuste o valor ao comprimento de destino: use um cast explícito (B'101'::bit(4) completa com zeros à direita e trunca o excesso) ou defina a coluna como bit varying(n) se o comprimento puder variar. Converta os operandos para o mesmo comprimento antes de operações bit a bit; verifique o comprimento com length().","tags":["bit","length","bit string","varbit","conversion","validation"]},{"code":"2201B","title":"invalid_regular_expression","severity":"caution","meaning":"O padrão informado a uma operação de expressão regular (~, ~*, SIMILAR TO, regexp_matches, substring etc.) é inválido. O PostgreSQL não conseguiu compilar o padrão porque sua sintaxe está errada.","cause":"Um padrão regex com parênteses desbalanceados, classes de caracteres inválidas, sequências de escape incorretas ou uma construção não suportada. Uma causa comum é usar a entrada do usuário diretamente como padrão sem escapar seus caracteres especiais.","fix":"Corrija o padrão regex de acordo com a sintaxe POSIX/ARE; verifique parênteses, colchetes e sequências de escape. Se você está procurando a entrada do usuário como texto literal e não como padrão: o PostgreSQL não tem uma função nativa regexp_quote, então escape os caracteres especiais prefixando-os com uma barra invertida via regexp_replace, ou evite regex por completo e use strpos()/position() ou LIKE ... ESCAPE. Valide o padrão testando-o em uma ferramenta separada.","tags":["regex","regular expression","pattern","similar to","escape","syntax"]},{"code":"44000","title":"with_check_option_violation","severity":"danger","meaning":"Um INSERT/UPDATE por meio de uma view definida WITH CHECK OPTION foi rejeitado porque a linha resultante não satisfaz mais a condição WHERE da view. A view impede a gravação de linhas que ficariam fora do seu próprio filtro.","cause":"Uma view atualizável está definida WITH CHECK OPTION e a escrita move a linha para fora da condição que define a view (por exemplo, definir uma linha como 'inactive' enquanto a view filtra status='active'). Uma verificação semelhante pode ser disparada em políticas de row-level security (RLS).","fix":"Garanta que os valores gravados satisfaçam a condição WHERE da view, ou execute a operação diretamente na tabela base em vez da view (se os privilégios permitirem). Se a regra de negócio permitir que a linha saia do filtro, redefina a view sem WITH CHECK OPTION. Para RLS, revise a expressão WITH CHECK da política.","tags":["view","check option","updatable view","rls","insert","update"]},{"code":"40002","title":"transaction_integrity_constraint_violation","severity":"danger","meaning":"O código do padrão SQL para a violação, no COMMIT, de uma constraint de integridade verificada no fim da transação. Importante: na prática, o PostgreSQL não produz este código; ele retorna as violações de constraints adiadas (DEFERRED) no COMMIT com o próprio código da constraint: 23503 para foreign keys, 23505 para unicidade.","cause":"Uma foreign key ou constraint unique definida como DEFERRABLE INITIALLY DEFERRED foi temporariamente violada em etapas intermediárias da transação e não foi corrigida até o COMMIT; no PostgreSQL, isso é informado como 23503/23505. Por exemplo, inserir linhas que se referenciam mutuamente na ordem errada sem corrigi-las causa isso.","fix":"Corrija a lógica da transação para que todas as constraints adiadas sejam satisfeitas antes do COMMIT (adicione as referências ausentes, resolva os conflitos). Se necessário, verifique a constraint mais cedo dentro da transação com SET CONSTRAINTS ... IMMEDIATE para detectar antes a etapa problemática. Reordene os inserts/updates em casos de referências mútuas.","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) (expressão que não está no GROUP BY)","severity":"caution","meaning":"Uma coluna que não está no GROUP BY nem envolvida por uma função de agregação foi usada na lista do SELECT ou em HAVING/ORDER BY. Como o modo SQL ONLY_FULL_GROUP_BY está habilitado, o MySQL rejeita essa expressão não determinística.","cause":"A consulta seleciona diretamente uma coluna além das colunas agrupadas, mas essa coluna pode não ter um único valor por grupo. ONLY_FULL_GROUP_BY vem habilitado por padrão no MySQL 5.7+; consultas que dependem do antigo comportamento permissivo do GROUP BY geram este erro.","fix":"Adicione a coluna à lista do GROUP BY ou envolva-a em uma função de agregação (MAX(), MIN(), ANY_VALUE()). Se você sabe que o valor é realmente único dentro do grupo, ANY_VALUE() suprime a ambiguidade de forma deliberada. Desabilitar o modo (remover ONLY_FULL_GROUP_BY do sql_mode) em vez de corrigir a consulta traz de volta o risco de resultados errados; evite isso.","tags":["group by","only_full_group_by","sql_mode","any_value","aggregate","query"]},{"code":"1267","title":"Illegal mix of collations","severity":"caution","meaning":"Em uma operação de comparação ou combinação (JOIN, WHERE, UNION, CONCAT), duas strings com collations diferentes foram combinadas e o MySQL não conseguiu determinar quais regras de collation aplicar.","cause":"Geralmente, comparar colunas com conjuntos de caracteres/collations diferentes (por exemplo, utf8mb4_general_ci vs. utf8mb4_unicode_ci, ou latin1 vs. utf8mb4), ou uma divergência entre uma coluna e a collation da conexão. Comum quando tabelas/bancos foram criados com padrões diferentes.","fix":"Leve os dois lados da comparação para a mesma collation: especifique uma collation explícita com COLLATE (por exemplo, col1 = col2 COLLATE utf8mb4_unicode_ci) ou use CONVERT(... USING ...). Como solução permanente, converta as colunas/tabelas afetadas para um único conjunto de caracteres e collation consistentes. Alinhe também a collation da conexão (collation_connection).","tags":["collation","collation mismatch","character set","join","utf8mb4","convert"]},{"code":"1030","title":"Got error N from storage engine","severity":"danger","meaning":"O storage engine (InnoDB/MyISAM) não conseguiu concluir uma operação e retornou um código de erro de baixo nível. É um relato genérico de um problema de disco, sistema de arquivos ou interno do engine, abaixo da camada SQL. O subcódigo entre parênteses/na mensagem mostra a causa real.","cause":"Causas comuns: disco/espaço temporário cheio (por exemplo, errno 28 - No space left on device), problemas de permissão de arquivos, arquivos de tabela corrompidos, problemas de tablespace do InnoDB ou erros de I/O no nível do sistema operacional. Consultas de sort/group que produzem tabelas temporárias grandes também podem causá-lo.","fix":"Decodifique o subcódigo de erro (no Linux, perror N mostra seu significado, por exemplo, perror 28). Verifique o uso de disco e o espaço do tmpdir; libere espaço. Verifique a propriedade/as permissões dos arquivos. Para InnoDB, revise os detalhes no error log; se houver suspeita de corrupção, execute CHECK TABLE e recupere se necessário. Otimize consultas que produzem resultados temporários enormes.","tags":["storage engine","innodb","disk","errno","tmpdir","i-o"]},{"code":"1197","title":"Multi-statement transaction required more than 'max_binlog_cache_size' (a transação com vários comandos exigiu mais que 'max_binlog_cache_size')","severity":"danger","meaning":"Os dados de binlog gerados por uma única transação excederam o limite de memória/cache definido por max_binlog_cache_size. A transação não coube no binary log, por isso falhou e sofreu rollback.","cause":"Uma transação muito grande (um único INSERT/UPDATE/DELETE de milhões de linhas ou uma carga em massa enorme) encheu o cache do binlog. Com o binary logging habilitado (replicação/recuperação point-in-time), transações grandes podem facilmente exceder esse limite.","fix":"Divida a transação grande em lotes menores; faça COMMIT após cada lote. Se transações realmente grandes forem inevitáveis, aumente max_binlog_cache_size (e binlog_cache_size, se necessário). Em cargas ETL/em massa, uma carga em blocos com COMMITs intermediários evita tanto este erro quanto locks mantidos por muito tempo.","tags":["binlog","max_binlog_cache_size","transaction","batch","replication","bulk"]},{"code":"1785","title":"Statement violates GTID consistency","severity":"danger","meaning":"Com a replicação baseada em GTID (Global Transaction Identifier) habilitada, o comando executado viola as regras de consistência de GTID. O modo GTID não permite certos tipos de comando que não podem ser atribuídos com segurança a um único GTID.","cause":"O 1785 (ER_GTID_UNSAFE_NON_TRANSACTIONAL_TABLE) ocorre especificamente quando tabelas não transacionais (por exemplo, MyISAM) são atualizadas na mesma transação que tabelas transacionais (InnoDB), ou em uma transação com vários comandos sem autocommit. Em versões mais antigas, CREATE TABLE ... SELECT (antes da 8.0.21; permitido na 8.0.21+ para engines com suporte a DDL atômico) e CREATE/DROP TEMPORARY TABLE dentro de uma transação (antes da 8.0.13; permitido na 8.0.13+ quando binlog_format é ROW/MIXED) também violam a consistência de GTID (esses casos são informados com códigos de erro separados). Eles são rejeitados quando enforce_gtid_consistency=ON.","fix":"Não misture tabelas de engines não transacionais com tabelas transacionais na mesma transação; atualize tabelas MyISAM com comandos únicos em autocommit ou mova todas as tabelas para InnoDB: ALTER TABLE my_table ENGINE=InnoDB; Em versões mais antigas (antes da 8.0.21), divida CREATE TABLE ... SELECT em duas etapas (CREATE TABLE e depois INSERT ... SELECT); antes da 8.0.13, crie e remova tabelas temporárias fora de uma transação explícita.","tags":["gtid","replication","consistency","temporary table","myisam","innodb"]},{"code":"3024","title":"Query execution was interrupted, maximum statement execution time exceeded (execução da consulta interrompida; tempo máximo de execução excedido)","severity":"caution","meaning":"Uma consulta SELECT foi interrompida pelo MySQL porque excedeu o tempo máximo de execução definido para ela (max_execution_time / hint MAX_EXECUTION_TIME). É uma proteção de timeout que impede que consultas longas prendam recursos.","cause":"A consulta foi executada por mais tempo do que o valor de max_execution_time da sessão/global ou o hint de otimizador MAX_EXECUTION_TIME(N) no SELECT. Geralmente causado por um plano ineficiente, índice ausente, uma varredura grande ou lentidão sob forte concorrência. (Aplica-se apenas a SELECTs somente leitura.)","fix":"Analise a consulta com EXPLAIN e otimize-a (índices adequados, predicados mais seletivos, menos full table scans). Se a consulta realmente precisar ser executada por muito tempo, aumente o hint MAX_EXECUTION_TIME desse SELECT ou o max_execution_time da sessão. Execute consultas analíticas pesadas offline/em uma réplica.","tags":["timeout","max_execution_time","query","explain","index","select"]},{"code":"1298","title":"Unknown or incorrect time zone","severity":"caution","meaning":"O nome de fuso horário especificado não foi reconhecido pelo MySQL. Uma chamada CONVERT_TZ(), a configuração time_zone ou uma operação que se refere a um fuso horário nomeado (por exemplo, 'Europe/Istanbul') falhou porque esse fuso horário não está definido no servidor.","cause":"Para que o MySQL use fusos horários nomeados, as tabelas de fuso horário do schema mysql (time_zone, time_zone_name etc.) precisam estar carregadas. Se essas tabelas estiverem vazias, apenas offsets numéricos ('+03:00') funcionam; os fusos nomeados são desconhecidos e este erro é gerado.","fix":"Carregue as tabelas de fuso horário. No Linux, importe os dados zoneinfo do sistema com mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql; depois reinicie o servidor ou execute FLUSH TABLES. Se não for possível carregar fusos nomeados, use um offset numérico ('+03:00'). Verifique a grafia do nome (maiúsculas/minúsculas, '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) (a função não tem DETERMINISTIC, NO SQL nem READS SQL DATA)","severity":"caution","meaning":"Uma stored function estava sendo criada, mas o binary logging está habilitado e a função não foi declarada com nenhuma das características de determinismo/acesso a dados. O MySQL rejeita uma função assim porque ela é ambígua do ponto de vista da segurança da replicação.","cause":"A função foi definida sem as características DETERMINISTIC, NO SQL ou READS SQL DATA com log_bin ON e log_bin_trust_function_creators=OFF. Sem essas características, o MySQL não pode ter certeza de que a função produz o mesmo resultado na réplica.","fix":"Declare o comportamento da função com as características corretas: adicione DETERMINISTIC se ela for realmente determinística, NO SQL se não acessar dados, READS SQL DATA se apenas ler dados. Se tiver certeza de que as funções são seguras, você pode definir log_bin_trust_function_creators=1 como política central; no entanto, declarar a característica corretamente é a abordagem mais segura. Garanta que a característica corresponda ao comportamento real da função.","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 ... (não é possível atribuir esse valor à variável)","severity":"caution","meaning":"O valor atribuído a uma variável de sistema/sessão (com SET) é inválido. O valor foi rejeitado porque está fora do conjunto permitido, é de tipo errado ou está em formato inadequado.","cause":"Exemplos comuns: atribuir um nome de modo inválido/digitado errado ao sql_mode, informar uma opção não definida a uma variável enum ou atribuir NULL a uma variável que não aceita NULL. Valores numéricos na unidade/no intervalo errado também podem causá-lo.","fix":"Verifique os valores válidos e o tipo que a variável aceita; para variáveis do tipo ENUM/SET (por exemplo, sql_mode, que é um SET), escreva os nomes de valores/modos exatamente e separe vários valores com vírgulas. Consulte o intervalo de valores válidos na documentação. Para listas como sql_mode, leia o valor atual (SELECT @@sql_mode) e adicione/remova itens com segurança a partir dele.","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 (timeout aguardando recursos de memória para executar a consulta)","severity":"danger","meaning":"Uma consulta sofreu timeout enquanto aguardava no resource semaphore o memory grant de que precisa para ser executada. Como a pressão de memória impediu a alocação de um grant, a operação foi cancelada.","cause":"Consultas concorrentes com uso intenso de memória (sorts grandes, hash joins, hash aggregates) consumiram todo o pool de memória para consultas; novas consultas entraram na fila do semáforo e sofreram timeout. Estimativas de memory grant superdimensionadas (estatísticas desatualizadas, planos ruins) ou memória insuficiente no servidor são a causa raiz.","fix":"Identifique as consultas que aguardam ou mantêm memória com sys.dm_exec_query_memory_grants e as DMVs do resource semaphore. Atualize as estatísticas e corrija planos que causam memory grants inflados (índices adequados, melhores estimativas). Reduza a concorrência de consultas com uso intenso de memória; se necessário, limite os memory grants com o Resource Governor. Revise a configuração de memória do servidor (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 (não foi possível executar a operação porque o memory grant solicitado não estava disponível)","severity":"danger","meaning":"O memory grant exigido pela consulta não estava disponível e a operação não pôde ser executada. Diferentemente do 8645, não se trata de uma espera, mas de uma falha direta em fornecer o grande bloco de memória solicitado; geralmente indica pressão de memória severa.","cause":"A memória disponível para consultas no servidor não consegue atender ao grant solicitado por um único operador (por exemplo, um sort/hash muito grande). Estimativas de memória excessivamente altas, um max server memory baixo, pressão externa de memória ou um limite baixo do Resource Governor, REQUEST_MAX_MEMORY_GRANT_PERCENT (workload group) ou MAX_MEMORY_PERCENT (resource pool), podem ser a causa.","fix":"Otimize as consultas que inflam os memory grants (atualize as estatísticas, indexe adequadamente, divida a consulta). Monitore a memória total e disponível; verifique a configuração max server memory e a pressão de memória de aplicações externas. Se o Resource Governor estiver em uso, revise as configurações REQUEST_MAX_MEMORY_GRANT_PERCENT do workload group e MAX_MEMORY_PERCENT do pool. Mova jobs em lote com uso intenso de memória para horários fora de pico.","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 falhou porque não foi possível obter um lock no banco)","severity":"danger","meaning":"Uma operação ALTER DATABASE (por exemplo, mudar para o modo single-user, alterar um arquivo, definir uma opção) não conseguiu obter o lock necessário no banco porque outras conexões/sessões ativas o estão usando.","cause":"A operação foi tentada com o banco em uso; o lock exclusivo necessário para SET SINGLE_USER, RESTRICTED_USER ou alterações de opções semelhantes não pôde ser obtido por causa de conexões ativas de usuários. Comum durante deploys/manutenções frequentes com conexões da aplicação abertas.","fix":"Identifique as outras sessões conectadas ao banco (sys.dm_exec_sessions, sp_who2) e feche-as com segurança. Para manutenção, mude o modo fazendo rollback das transações abertas com a opção ROLLBACK: ALTER DATABASE [db] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; Execute a operação quando o tráfego da aplicação estiver baixo ou em uma janela de manutenção. Lembre-se de voltar para MULTI_USER ao terminar.","tags":["alter database","lock","single_user","connection","maintenance","rollback"]},{"code":"3702","title":"Cannot drop database because it is currently in use (não é possível remover o banco porque ele está em uso)","severity":"caution","meaning":"Houve uma tentativa de remover ou renomear um banco, mas ela foi rejeitada porque o banco ainda está em uso por conexões ativas. O SQL Server não consegue remover um banco que está em uso.","cause":"Outras sessões (um pool de aplicação, uma aba aberta do SSMS, jobs em background) estão conectadas ao banco que está sendo removido. Até a sua própria sessão ter esse banco como contexto (USE) pode causá-lo. Conexões abertas de ferramentas de monitoramento/backup também são uma causa comum.","fix":"Mude para outro banco antes de remover (USE master;). Encontre e feche as sessões conectadas ou, primeiro, coloque o banco em modo single-user: ALTER DATABASE [db] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; e depois execute DROP DATABASE [db]; Pare os pools de conexões da aplicação e garanta que as ferramentas de monitoramento não estejam abrindo conexões.","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 (o principal é dono de um schema no banco e não pode ser removido)","severity":"caution","meaning":"Houve uma tentativa de remover um usuário/role do banco (database principal), mas ele não pôde ser removido porque o principal é dono de um ou mais schemas no banco. Ele não pode ser removido até que os schemas de sua propriedade sejam transferidos para outro principal.","cause":"O usuário que está sendo removido é o OWNER de pelo menos um schema (por exemplo, um schema criado com seu próprio nome por padrão ou atribuído via AUTHORIZATION). O SQL Server bloqueia a remoção para evitar schemas órfãos.","fix":"Encontre os schemas de propriedade do usuário: SELECT name FROM sys.schemas WHERE principal_id = USER_ID('app_user'); Transfira a propriedade desses schemas para outro principal (por exemplo, dbo): ALTER AUTHORIZATION ON SCHEMA::[app_schema] TO dbo; Se o schema não for mais necessário (e estiver vazio), use DROP SCHEMA. Depois que a propriedade for transferida, execute DROP USER novamente.","tags":["schema","principal","user","owner","alter authorization","drop user"]},{"code":"1934","title":"INSERT/UPDATE failed because the following SET options have incorrect settings (INSERT/UPDATE falhou porque estas opções SET têm valores incorretos)","severity":"danger","meaning":"Uma operação DML (INSERT/UPDATE/DELETE) falhou porque opções SET obrigatórias estavam configuradas incorretamente. Ocorre tipicamente quando as configurações SET obrigatórias para indexed views, índices em colunas computadas, filtered indexes ou índices espaciais/XML não são atendidas.","cause":"A tabela/view afetada tem um objeto que exige opções SET específicas (notadamente QUOTED_IDENTIFIER e ANSI_NULLS ON, NUMERIC_ROUNDABORT OFF etc.), mas as opções SET atuais da sessão não atendem a esse requisito. Drivers de cliente antigos ou scripts que definem explicitamente opções SET erradas causam o erro.","fix":"Defina as opções necessárias na conexão/sessão: 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; Garanta que o driver da aplicação envie essas opções corretamente ao se conectar. A mensagem de erro cita as opções incorretas; corrija-as.","tags":["set options","indexed view","computed column","quoted_identifier","ansi_nulls","dml"]},{"code":"468","title":"Cannot resolve the collation conflict","severity":"caution","meaning":"Em uma operação (JOIN, UNION, comparação no WHERE ou igualdade), duas expressões de string com collations diferentes se encontraram e o SQL Server não conseguiu decidir qual collation aplicar. A operação foi cancelada devido à ambiguidade.","cause":"As colunas comparadas são definidas com collations diferentes; ocorre com mais frequência quando a collation do banco difere da collation do servidor/tempdb, ou quando são unidas tabelas de bancos com collations diferentes. Unir tabelas temporárias (collation do tempdb) a tabelas permanentes é um gatilho clássico.","fix":"Especifique uma collation explícita na comparação: ... WHERE a.col = b.col COLLATE DATABASE_DEFAULT (ou um nome de collation concreto). Use COLLATE DATABASE_DEFAULT ao criar colunas de tabelas temporárias. Como solução permanente, alinhe as colunas/bancos afetados a uma única collation consistente. Se as divergências com o tempdb forem frequentes, DATABASE_DEFAULT é a correção mais prática.","tags":["collation","collation","join","tempdb","database_default","conflict"]},{"code":"4864","title":"Bulk load data conversion error (type mismatch or invalid character) (erro de conversão de dados na carga em massa (tipo incompatível ou caractere inválido))","severity":"caution","meaning":"Durante uma carga em massa (BULK INSERT, bcp ou OPENROWSET(BULK...)), um campo do arquivo de origem não pôde ser convertido para o tipo de dado da coluna de destino. Os dados da linha/coluna informada não correspondem ao tipo esperado.","cause":"Um valor do arquivo de dados de origem não se encaixa no tipo da coluna de destino: texto em uma coluna numérica, formato de data errado, separador decimal/de milhar inesperado, codificação de caracteres errada (UTF-8/UTF-16) ou colunas deslocadas por terminadores de campo/linha errados. Não pular a linha de cabeçalho também é uma causa comum.","fix":"Vá até a linha e a coluna informadas pelo erro e inspecione os dados de origem. Faça os terminadores de campo (FIELDTERMINATOR) e de linha (ROWTERMINATOR) corresponderem ao arquivo; use FIRSTROW=2 para pular a linha de cabeçalho. Defina CODEPAGE ou DATAFILETYPE para a página de código/codificação correta. Torne os formatos de data/número compatíveis com o tipo de destino. Usar um format file torna o mapeamento confiável.","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 (o principal de servidor não consegue acessar o banco no contexto de segurança atual)","severity":"caution","meaning":"Um login tentou acessar um banco específico, mas não tem acesso a ele no contexto de segurança atual. O login consegue se conectar ao servidor, mas não tem um usuário/permissão correspondente no banco de destino.","cause":"O login não tem um usuário mapeado no banco (órfão ou nunca criado), o acesso ao banco está restrito ou a conta guest está desabilitada. Um caso comum é o Object Explorer do SSMS tentando ler metadados de um banco ao qual o login não tem acesso.","fix":"Crie um usuário para o login no banco de destino e conceda as permissões necessárias: USE [db]; CREATE USER [login] FOR LOGIN [login]; e atribua as roles/permissões adequadas. Se existir um usuário órfão, mapeie-o com ALTER USER ... WITH LOGIN = ... Se o acesso for realmente necessário, adicione-o à role de banco adequada; caso contrário, o erro é o comportamento esperado (sem acesso a esse banco).","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":"Uma eleição de primário está em andamento no replica set. Até que a eleição termine, o primário fica indefinido, por isso escritas (e algumas leituras) temporariamente não são aceitas.","cause":"O cluster está elegendo um novo primário depois que o primário atual caiu, de uma partição de rede, de um step-down para manutenção ou da reinicialização de um nó. Uma eleição geralmente leva alguns segundos; operações que chegam nesse intervalo encontram esta condição.","fix":"É transitório; habilite o recurso de retry do driver (retryable writes/reads) para que a operação seja repetida automaticamente quando a eleição terminar. Se as eleições forem frequentes ou longas, investigue a causa raiz: estabilidade da rede, saúde dos nós, configuração de votos e configurações de timeout de eleição (settings.electionTimeoutMillis). Inspecione o estado do cluster com rs.status().","tags":["replica set","election","primary","retry","step-down","high availability"]},{"code":"225 TransactionTooOld","title":"TransactionTooOld","severity":"caution","meaning":"Um comando foi executado dentro de uma transação multidocumento, mas seu número de transação é mais antigo que o último número de transação que o servidor viu para essa sessão. Ou seja, uma transação mais nova foi iniciada, então esta antiga não é mais válida.","cause":"Uma nova transação foi iniciada na mesma sessão antes de a antiga terminar, ou os números de transação avançaram fora de ordem devido à concorrência. Geralmente acontece quando um objeto de sessão é compartilhado incorretamente ou várias threads usam a mesma sessão.","fix":"Gerencie corretamente o ciclo de vida da sessão para cada transação lógica; não compartilhe uma sessão simultaneamente entre várias threads. Execute as transações com a API withTransaction/callback recomendada pelo driver (ela cuida dos retries e do gerenciamento dos números). Feche a transação anterior com commit/abort antes de iniciar uma nova.","tags":["transaction","session","session misuse","concurrency","withtransaction","multi-document transaction"]},{"code":"246 SnapshotUnavailable","title":"SnapshotUnavailable","severity":"caution","meaning":"Uma leitura com o read concern de snapshot solicitado (readConcern: snapshot) não pôde ser executada porque o servidor não consegue fornecer um snapshot consistente para aquele momento. Geralmente está relacionado a um timestamp de leitura que não avançou o suficiente ou ficou para trás.","cause":"readConcern 'snapshot' é usado (principalmente em transações multidocumento), mas uma visão consistente para o timestamp atLeast/at solicitado ainda não está disponível; por exemplo, uma coleção/índice recém-criado, uma mudança no catálogo ou lag de replicação. Nesse caso, o servidor rejeita a leitura.","fix":"Geralmente é transitório; repita a operação após um breve intervalo (o mecanismo de retry para erros transitórios de transação do driver cobre isso). Se você executou DDL recentemente (criação de coleção/índice), inicie a transação depois dele. Verifique o lag de replicação e a saúde dos nós. Se uma leitura snapshot não for realmente necessária, escolha um readConcern mais adequado.","tags":["snapshot","readconcern","transaction","timestamp","retry","replication"]},{"code":"257 TransactionTooLarge","title":"TransactionTooLarge","severity":"danger","meaning":"Uma transação multidocumento excedeu os limites permitidos de tamanho/quantidade de operações. A transação foi rejeitada porque as alterações acumuladas nela (entrada de oplog ou uso de memória) ultrapassaram o limite superior.","cause":"Modificar/inserir um grande número de documentos em uma única transação elevou demais o total de dados produzidos pela transação (por exemplo, o volume de alterações que precisa ser mantido no cache do WiredTiger, ou limites do servidor como transactionLimitBytes). Desde a 4.2, uma transação pode ser dividida em várias entradas de oplog, então o limite de 16 MB por entrada de oplog sozinho não é decisivo. Usar transações para migração de dados em massa/ETL atinge esse limite com facilidade.","fix":"Divida a transação em partes menores; faça commit de cada lote em uma transação separada. Transações multidocumento foram projetadas para ser curtas e pequenas; prefira fazer grandes atualizações em massa sem transações (de forma idempotente, bloco a bloco) ou dividi-las com bulk write. Evite modificar milhares de documentos em uma única transação.","tags":["transaction","size","oplog","batch","bulk","bulk write"]},{"code":"276 IndexBuildAborted","title":"IndexBuildAborted","severity":"danger","meaning":"Uma criação de índice em andamento foi abortada/interrompida antes da conclusão. O índice de destino não foi criado com sucesso.","cause":"A criação do índice pode ter sido abortada por falta de disco/memória no nó, um abort explícito via dropIndexes, um step-down do primário/mudança de estado da réplica, uma violação de unicidade (documentos conflitantes durante a criação de um índice único) ou a reinicialização de um nó.","fix":"Encontre nos logs do mongod o motivo do abort (espaço em disco, memória, conflito de unicidade etc.) e resolva-o. Se estiver criando um índice único, limpe antes os documentos conflitantes. Disponibilize disco/memória suficientes e garanta que o estado da réplica esteja estável. Depois de corrigir o problema, recrie o índice com createIndex; em coleções grandes, escolha um período de baixa carga.","tags":["index","index build","aborted","unique","disk","replica set"]},{"code":"86 IndexKeySpecsConflict","title":"IndexKeySpecsConflict","severity":"caution","meaning":"O índice que está sendo criado tem a mesma especificação de chave (mesmos campos/ordem) de um índice existente, mas opções ou nome diferentes. O MongoDB não permite duas definições de índice conflitantes com a mesma chave.","cause":"Houve uma tentativa de criar um segundo índice no(s) mesmo(s) campo(s) com outro nome ou opções diferentes (por exemplo, collation, partialFilterExpression ou configuração unique diferentes). Geralmente acontece quando uma definição de índice é alterada em uma migração/no código e executada novamente.","fix":"Inspecione os índices existentes: db.collection.getIndexes() Encontre o índice conflitante com a mesma chave. Para passar às opções desejadas, primeiro remova o índice antigo (dropIndex) e depois recrie-o com a nova definição. Se apenas o nome for diferente, continue usando o índice existente; não crie uma segunda definição desnecessária.","tags":["index","getindexes","collation","unique","conflict","createindex"]},{"code":"166 CommandNotSupportedOnView","title":"CommandNotSupportedOnView","severity":"caution","meaning":"O comando não é suportado em uma view. As views do MongoDB são somente leitura e aceitam apenas certas operações de leitura; escritas ou comandos não suportados são rejeitados.","cause":"Operações de escrita como insert/update/delete, ou certos comandos não suportados em views (por exemplo, algumas operações text/geo, criação direta de índices), foram tentadas em uma view. Ocorre quando a aplicação tenta escrever em uma view pensando que é uma coleção.","fix":"Faça as escritas na coleção subjacente (de origem) na qual a view se baseia; views servem apenas para leitura. Verifique se o comando é suportado em views e use operações de leitura/agregação suportadas. Se precisar de uma estrutura gravável, projete uma coleção materializada ($merge/$out) em vez de uma view.","tags":["view","read-only view","read only","aggregation","write","collection"]},{"code":"168 InvalidPipelineOperator","title":"InvalidPipelineOperator","severity":"caution","meaning":"Um operador/estágio não reconhecido ou inválido foi usado em um pipeline de agregação. O MongoDB não conseguiu resolver o nome do operador especificado e rejeitou o pipeline.","cause":"Um nome de operador digitado errado (por exemplo, '$groups' em vez de '$group'), um operador novo não disponível na versão do MongoDB em uso ou uma expressão usada no contexto errado. A falta do prefixo $ ou um operador usado em uma posição inválida também causa o erro.","fix":"Verifique a grafia dos nomes de operadores/estágios e o prefixo $. Garanta que o operador seja suportado pela versão do MongoDB do servidor (operadores novos não existem em versões antigas). Compare o pipeline com a sintaxe documentada; use a expressão dentro do estágio correto (por exemplo, $expr, $project). Isole o estágio e teste-o com uma amostra pequena.","tags":["aggregation","pipeline","operator","syntax","version","expr"]},{"code":"118 NamespaceNotSharded","title":"NamespaceNotSharded","severity":"caution","meaning":"Uma operação que só faz sentido em coleções shardadas foi executada em uma coleção/namespace que ainda não está shardada. O comando não pôde ser aplicado porque a coleção de destino não está shardada.","cause":"moveChunk, split ou certos comandos administrativos baseados em shard key foram chamados em uma coleção sem sharding habilitado. Geralmente acontece porque a coleção não foi shardada com shardCollection ou o namespace errado foi usado como destino.","fix":"Verifique o status de sharding da coleção: sh.status() ou config.collections. Se a operação realmente exigir sharding, primeiro habilite o sharding no banco (sh.enableSharding) e sharde a coleção (sh.shardCollection com uma shard key adequada). Caso contrário, esses comandos administrativos não são necessários em coleções não shardadas; verifique se você está usando o namespace correto.","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 (erro de protocolo: comprimento multibulk inválido)","severity":"danger","meaning":"O servidor Redis não conseguiu interpretar o fluxo de bytes do cliente de acordo com o RESP (Redis Serialization Protocol). Como a quantidade de elementos declarada por um comando multibulk era inválida, a conexão foi fechada com um erro de protocolo.","cause":"Geralmente causado por um cliente que não é Redis (por exemplo, uma requisição HTTP, uma aplicação conectada à porta errada) enviando dados brutos para a porta do Redis, uma biblioteca cliente quebrada/incompleta, enquadramento defeituoso em um pipeline ou requisições enormes que excedem os limites do protocolo (proto-max-bulk-len).","fix":"Verifique se apenas um cliente Redis real se conecta à porta do Redis (sem tráfego HTTP/de outros protocolos indevido). Atualize a biblioteca cliente e evite a geração personalizada/manual de comandos que quebre o enquadramento do RESP. Se você envia valores muito grandes, revise o limite proto-max-bulk-len e o tamanho das requisições. Garanta que nenhum proxy intermediário na rede corrompa os dados.","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 excede o número de argumentos)","severity":"caution","meaning":"Ao executar um script Lua (EVAL/EVALSHA/FCALL), o número de chaves especificado (numkeys) é maior que o número de argumentos realmente passados ao comando. O Redis rejeita o comando porque não consegue dividir os arrays KEYS e ARGV.","cause":"A sintaxe do EVAL é 'EVAL script numkeys key [key ...] arg [arg ...]'. O valor de numkeys foi calculado errado (definido alto demais) ou as chaves esperadas nunca foram adicionadas ao comando. Um erro de programação comum.","fix":"Torne numkeys exatamente igual ao número de chaves realmente passadas ao comando. Use o wrapper de EVAL da sua biblioteca cliente (que geralmente recebe KEYS e ARGV como listas separadas) para que numkeys seja calculado automaticamente. Ao chamar o script, separe corretamente as chaves em KEYS e os demais parâmetros em ARGV.","tags":["lua","eval","evalsha","numkeys","keys","script"]},{"code":"ERR WATCH inside MULTI is not allowed","title":"WATCH inside MULTI is not allowed","severity":"caution","meaning":"WATCH foi enviado dentro de um bloco MULTI aberto. Para optimistic locking, o WATCH deve colocar as chaves sob observação ANTES de a transação começar; se chamado depois do MULTI, ele é rejeitado. O erro não aborta a transação; apenas o WATCH falha e nada fica sob observação.","cause":"WATCH e MULTI escritos em ordem inversa no código (primeiro MULTI, depois WATCH); chamar WATCH dentro do wrapper de pipeline/transação da biblioteca cliente; ou usar uma conexão do pool que ficou em estado MULTI. Nesse caso, o EXEC é executado mesmo que as chaves que deveriam estar sob observação tenham mudado; a proteção contra conflitos esperada não entra em ação.","fix":"Ordem correta: WATCH key -> (ler os valores) -> MULTI -> comandos -> EXEC. Se o EXEC retornar nil, uma chave observada mudou; repita a operação desde o início. Use a API de WATCH/transação da biblioteca cliente (por exemplo, helpers de watch + pipeline). Observação: comandos de pub/sub como SUBSCRIBE não são rejeitados dentro do MULTI; eles são enfileirados e a conexão passa para o modo de assinatura após o EXEC; isso também não é recomendado, use uma conexão dedicada para 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 não pode ser usado em instâncias réplica)","severity":"caution","meaning":"WAIT foi executado em uma instância réplica (replica/slave). O WAIT, que espera uma escrita chegar a um determinado número de réplicas, só faz sentido no primário (master); ele não pode ser usado em uma réplica.","cause":"A aplicação enviou WAIT por engano em uma conexão com uma réplica. Geralmente isso acontece porque a conexão é direcionada a uma réplica de leitura, ou porque o cliente continua conectado a uma réplica após uma mudança de papel (failover).","fix":"Envie WAIT somente ao nó primário. Garanta que a configuração do cliente/proxy direcione as escritas e as chamadas de WAIT para o master. Detecte mudanças de papel após um failover e redirecione as conexões para o novo primário (você pode verificar o papel com o comando ROLE).","tags":["wait","replica","master","write","failover","replication"]},{"code":"ERR Background append only file rewriting already in progress","title":"AOF rewrite already in progress","severity":"caution","meaning":"Houve uma tentativa de iniciar uma reescrita do AOF (Append Only File) (BGREWRITEAOF), mas uma reescrita do AOF já está em andamento. Duas reescritas do AOF não podem ser executadas ao mesmo tempo.","cause":"Uma nova requisição de reescrita chegou enquanto um BGREWRITEAOF anterior (manual ou automático, pelo gatilho auto-aof-rewrite-percentage) ainda estava em execução. Em conjuntos de dados grandes, uma reescrita do AOF pode demorar bastante e levar a esse conflito.","fix":"Aguarde a reescrita em execução terminar; acompanhe o campo aof_rewrite_in_progress na saída de INFO persistence. Se a operação estiver legitimamente em execução, não envie outra requisição. Se os conflitos forem frequentes, revise os limites da reescrita automática (auto-aof-rewrite-percentage/min-size) e o desempenho de I/O do disco.","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","severity":"danger","meaning":"Um comando MIGRATE (geralmente ao mover slots/chaves no Redis Cluster) encontrou um erro de I/O ou timeout ao se conectar à instância de destino ou ler sua resposta. A migração da chave não pôde ser concluída com segurança.","cause":"Latência/queda de rede entre os nós de origem e destino, o nó de destino sobrecarregado ou sem resposta, um timeout de MIGRATE curto demais ou uma chave grande que não pode ser transferida no tempo informado. Comum durante o rebalanceamento do cluster (resharding).","fix":"Verifique a conectividade e a latência de rede entre os nós de origem e destino. Especifique um timeout maior para o MIGRATE (especialmente para chaves grandes). Verifique a saúde/carga e o estado de memória do nó de destino. Ao mover chaves grandes durante o resharding, escolha horários de baixa carga; repita a migração se necessário.","tags":["migrate","cluster","resharding","timeout","network","i-o"]},{"code":"ERR Error compiling script (new function)","title":"Error compiling Lua script","severity":"caution","meaning":"O script Lua enviado com EVAL não pôde ser compilado pelo interpretador Lua embutido do Redis. Ele foi rejeitado antes do início da execução porque contém um erro de sintaxe.","cause":"Erros de sintaxe no script Lua: parênteses/aspas não fechados, palavras-chave digitadas errado, um 'end' faltando, operadores inválidos ou uma construção Lua não suportada. Concatenação/escape incorretos do script no lado do cliente também podem causá-lo.","fix":"Corrija a sintaxe Lua usando as informações de linha/caractere da mensagem de erro (verifique a correspondência de parênteses, aspas e 'end'). Valide o script compilando-o em um ambiente Lua separado. Garanta que o cliente monte o script corretamente (sem erros de escape/concatenação). Pré-carregue scripts validados com SCRIPT LOAD e chame-os com EVALSHA.","tags":["lua","eval","compilation","syntax","script load","script"]},{"code":"ERR FAILOVER requires connected replicas.","title":"FAILOVER requires connected replicas","severity":"caution","meaning":"FAILOVER foi executado para iniciar um failover coordenado (graceful), mas foi rejeitado porque não há uma réplica adequada conectada ao primário disponível para assumir. O failover não pode acontecer sem um destino para o qual passar o papel.","cause":"O primário não tem réplicas conectadas no momento (as réplicas estão fora do ar, desconectadas da rede ou fora de sincronia), ou a réplica de destino especificada não é elegível/não está conectada. Quando o FAILOVER manual (Redis 6.2+) é chamado, a topologia de replicação não atende à condição exigida. Observação: o FAILOVER funciona apenas com replicação standalone (master/replica); no Redis Cluster, usa-se CLUSTER FAILOVER na réplica.","fix":"Garanta que exista pelo menos uma réplica saudável, conectada e atualizada (verifique connected_slaves e o status de sincronização com INFO replication). Corrija problemas de rede/acesso nas réplicas para que se conectem ao primário. Para fazer failover para um destino específico, use FAILOVER TO host port e verifique se essa réplica é elegível.","tags":["failover","replica","master","replication","info replication","high availability"]},{"code":"ERR invalid expire time in 'set' command","title":"invalid expire time in SET","severity":"caution","meaning":"Um tempo de expiração inválido foi informado ao SET (com as opções EX/PX/EXAT/PXAT). O Redis rejeitou o comando porque não aceita um tempo de vida sem sentido, como zero ou um valor negativo.","cause":"Enviar 0 ou um valor negativo com EX/PX, ou a aplicação calcular errado a expiração e produzir um número inválido. Comandos como SETEX/GETEX retornam este erro de forma semelhante para durações não positivas. Alguns bugs de clientes vêm da confusão entre segundos e milissegundos.","fix":"Sempre envie a expiração como um inteiro estritamente positivo; EX espera segundos, PX milissegundos. Valide o cálculo da duração na aplicação (ele não deve produzir resultados negativos/zero) e não confunda as unidades (segundos vs. milissegundos). Para excluir uma chave imediatamente, use DEL/UNLINK em vez de definir uma expiração. Para tempo absoluto, passe um Unix timestamp futuro válido para EXAT/PXAT.","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) (o endereço já está em uso)","severity":"danger","meaning":"Ao iniciar, um nó do Elasticsearch não conseguiu vincular um socket para escutar na porta de transporte (comunicação entre nós) ou HTTP. Geralmente vem com o suberro 'Address already in use', e o nó não consegue iniciar.","cause":"A porta solicitada (padrão: transporte 9300, HTTP 9200) já está sendo usada por outro processo; na maioria das vezes, uma instância anterior do mesmo nó não foi encerrada corretamente, outra instância/serviço do ES no mesmo host entra em conflito, ou network.host/a porta estão mal configurados. Restrições de permissão/acesso também podem impedir o bind.","fix":"Descubra quem ocupa a porta (Linux: ss -ltnp | grep 9300 ou lsof -i:9300) e encerre o processo conflitante, ou atribua outra porta ao nó (transport.port / http.port). Verifique se o processo anterior do ES realmente terminou. Garanta que network.host e as configurações de intervalo de portas estejam corretos e permitam o bind. Depois, reinicie o nó.","tags":["transport","port","9300","bind","network.host","startup"]},{"code":"translog_corrupted_exception","title":"translog_corrupted_exception","severity":"danger","meaning":"O log de transações (translog) de um shard não pôde ser lido porque está corrompido. Durante o recovery, o Elasticsearch detectou que o translog falhou na verificação de integridade, e o shard não conseguiu iniciar.","cause":"Os arquivos de translog geralmente são corrompidos por uma queda repentina de energia, disco cheio, erro no sistema de arquivos, falha de hardware/disco ou operações externas no diretório de dados (cópia, intervenção manual). Escritas parcialmente concluídas durante um desligamento forçado (kill -9) também podem causá-lo.","fix":"Primeiro tente recuperar os dados de uma réplica ou de um snapshot; se existir uma cópia íntegra, reconstruir o shard corrompido a partir dela é o caminho mais seguro. Se não houver outra cópia e você aceitar a perda de dados, pare o nó e limpe o translog/dados corrompidos com bin/elasticsearch-shard remove-corrupted-data --index <index> --shard-id <n> (isso perde permanentemente os dados ainda não confirmados; a antiga ferramenta elasticsearch-translog foi removida na 7.0). A ferramenta exibe o comando POST _cluster/reroute (allocate_stale_primary, accept_data_loss: true) necessário para alocar o shard após a reinicialização do nó. Faça backup do diretório de dados antes da operação. Verifique a saúde do disco e o espaço livre.","tags":["translog","shard","recovery","corruption","snapshot","disk"]},{"code":"recovery_engine_exception","title":"recovery_engine_exception","severity":"danger","meaning":"Ocorreu um erro no nível do engine durante o recovery de um shard, e o shard não pôde ser aberto com sucesso. O recovery é a etapa executada durante a reinicialização de um nó, a alocação de réplicas ou a restauração de um snapshot.","cause":"Um problema subjacente durante o recovery: segmentos Lucene ou translog corrompidos, espaço em disco insuficiente, permissões de arquivos, interrupção de rede entre os nós de origem e destino, ou problemas de versão/compatibilidade. Geralmente envolve um suberro mais específico (corrupção, I/O).","fix":"Inspecione o erro subjacente (caused_by) para identificar o problema real (corrupção, disco, rede etc.). Verifique o espaço em disco e as permissões de arquivos. Se a alocação de réplicas falhar, veja o motivo com _cluster/allocation/explain e dispare a realocação se necessário. Se houver corrupção, recupere a partir de uma réplica/snapshot íntegro. Se for relacionado à rede, verifique a conectividade entre os nós e as configurações de recovery.","tags":["recovery","shard","engine","allocation","corruption","disk"]},{"code":"snapshot_in_progress_exception","title":"snapshot_in_progress_exception","severity":"caution","meaning":"A operação solicitada foi rejeitada porque conflita com um snapshot em andamento. Por exemplo, uma tentativa de excluir/fechar um índice ou modificar o repositório enquanto um snapshot está sendo feito é bloqueada.","cause":"Enquanto um snapshot ainda estava em execução, houve uma tentativa de excluir/fechar índices incluídos nesse snapshot, remover/modificar o repositório ou iniciar outra operação de snapshot/restore conflitante. O Elasticsearch não permite essas operações conflitantes, para preservar a consistência.","fix":"Aguarde o término do snapshot em execução: acompanhe o progresso com GET _snapshot/_status. Se a operação realmente precisar ser cancelada, interrompa-a excluindo o snapshot: DELETE _snapshot/repo/snapshot_name (isso aborta o snapshot em execução). Depois que o snapshot terminar ou for cancelado, execute novamente sua operação original (exclusão de índice, mudança no repositório).","tags":["snapshot","repository","restore","index deletion","conflict","backup"]},{"code":"repository_verification_exception","title":"repository_verification_exception","severity":"danger","meaning":"Enquanto um repositório de snapshots estava sendo registrado ou verificado, a checagem de que todos os nós conseguem acessar o repositório falhou. Como a verificação do repositório não passou, as operações de snapshot/restore não podem ser executadas de forma confiável.","cause":"Um repositório em sistema de arquivos compartilhado (fs) não está montado/acessível no mesmo caminho em todos os nós, path.repo está ausente da configuração, as permissões de arquivos são insuficientes, ou armazenamentos em nuvem/de objetos (S3, GCS, Azure) têm credenciais/acesso de rede incorretos. Alguns nós não conseguirem gravar no repositório é a causa típica.","fix":"Para um repositório fs compartilhado, garanta que path.repo esteja definido no elasticsearch.yml de todos os nós e que o mesmo caminho esteja montado com leitura/escrita em todos eles. Corrija as permissões de arquivos (usuário elasticsearch). Para repositórios em nuvem, verifique as credenciais (keystore), o nome do bucket e as permissões de rede/acesso. Verifique novamente o repositório com 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":"Ocorreu um erro na fase de reduce de uma busca. O nó coordenador encontrou um problema ao mesclar (reduce) resultados parciais/agregações de diferentes shards e não conseguiu produzir o resultado final.","cause":"Geralmente um limite de memória/recursos é excedido ao mesclar os resultados (por exemplo, agregações muito grandes, um circuit breaker disparando), uma estrutura de agregação incompatível/inválida, ou um resultado parcial retornado por um shard não pode ser mesclado. Comum com agregações de cardinalidade muito alta.","fix":"Leia o detalhe em caused_by para identificar a causa raiz. Alivie agregações pesadas: reduza o size em agregações terms de alta cardinalidade, pagine com uma agregação composite e reduza subagregações desnecessárias. Monitore a pressão de memória e divida a consulta em partes menores se necessário. Se um circuit breaker disparar, reduza o custo da consulta.","tags":["search","reduce","aggregation","coordinating node","memory","cardinality"]},{"code":"aggregation_execution_exception","title":"aggregation_execution_exception","severity":"caution","meaning":"Ocorreu um erro durante a execução de uma agregação. Embora a definição da agregação tenha sido interpretada, surgiu um problema em tempo de execução ao processar os campos/valores de destino.","cause":"A agregação é incompatível com o tipo do campo (por exemplo, agregar um campo text sem fielddata), valores inválidos durante a ordenação/o cálculo, uma pipeline aggregation que referencia um caminho inexistente (bucket path) ou combinações de tipos de campo não suportadas. Erros em tempo de execução em agregações baseadas em script também a causam.","fix":"Inspecione o nome do campo/da agregação no detalhe do erro. Garanta que os campos agregados sejam de um tipo adequado (keyword/numérico em vez de text; use campos com doc_values habilitado, se necessário). Em pipeline aggregations, verifique se buckets_path corresponde aos nomes reais dos buckets. Adicione verificações de null/tipo nas agregações com script. Corrija o mapping com os tipos de campo adequados.","tags":["aggregation","execution","fielddata","keyword","pipeline","mapping"]},{"code":"failed_node_exception","title":"failed_node_exception","severity":"danger","meaning":"Durante uma operação em todo o cluster (por exemplo, busca, estatísticas, comando de gerenciamento), um nó específico do cluster não conseguiu processar ou responder à requisição. O nó coordenador encapsula a falha desse nó nesta exceção.","cause":"O nó travou, saiu da rede, não conseguiu responder por sobrecarga/pausas de GC, problemas de disco/recursos, ou houve um erro de shard nesse nó. Também pode aparecer de forma transitória durante a reconfiguração do cluster (nós saindo/entrando).","fix":"Use caused_by para determinar em qual nó e por que a falha ocorreu. Verifique a saúde dos nós: GET _cat/nodes, GET _nodes/stats (CPU, memória, GC, disco). Se o nó estiver sob pressão de recursos, revise a carga/as configurações de heap; verifique a conectividade de rede. Se o nó saiu do cluster, aguarde que ele volte e que a alocação de shards se recupere (GET _cluster/health).","tags":["node","cluster","network","gc","shard","resources"]},{"code":"elasticsearch_parse_exception","title":"elasticsearch_parse_exception","severity":"caution","meaning":"O Elasticsearch encontrou um erro genérico de interpretação ao processar o corpo da requisição (consulta JSON, configurações ou configuração). A requisição não corresponde estruturalmente ao formato esperado.","cause":"JSON malformado/inválido (vírgula faltando, colchete não fechado), campos fora do lugar, tipos de valor inesperados (por exemplo, texto onde se espera um número) ou uma expressão de tempo/intervalo inválida. O aninhamento incorreto de uma consulta DSL também produz esta exceção.","fix":"Passe o corpo da requisição por um validador de JSON; verifique colchetes, aspas e vírgulas. Confira na documentação do DSL do Elasticsearch se os campos estão no lugar certo e são do tipo certo. Use a indicação de posição/campo na mensagem de erro para corrigir a parte problemática. Se usar uma biblioteca cliente, garanta que a serialização produza JSON válido.","tags":["parse","json","dsl","query","parsing","request"]}]},"health/oracle.json":{"engineId":"oracle","engine":"Oracle","order":1,"checks":[{"id":"version-uptime","group":"Geral","title":"Versão e uptime","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":"O status da instância deve ser OPEN. Se o startup_time for inesperadamente recente (inicialização recente), pode ter ocorrido um restart não planejado; investigue. A coluna version_full é do 18c+; no 12c e anteriores, use a coluna version.","severity":"safe"},{"id":"alertlog-errors","group":"Geral","title":"Erros críticos recentes no alert log (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":"Nenhum erro ORA- deve ser retornado para as últimas 24 horas. Entradas como ORA-00600, ORA-07445 e ORA-01578 (corrupção de bloco) exigem ação imediata.","severity":"danger"},{"id":"invalid-objects","group":"Geral","title":"Objetos 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":"O ideal é não haver objetos INVALID. Se houver, recompile com EXEC DBMS_UTILITY.COMPILE_SCHEMA ou utlrp.sql; objetos inválidos sob SYS/SYSTEM têm prioridade.","severity":"caution"},{"id":"tablespace-usage","group":"Capacidade","title":"Uso de tablespaces","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 acima de 85% é o limite de alerta; acima de 90%, crítico. Tablespaces com autoextend desligado têm maior risco de encher; adicione um datafile ou habilite o autoextend.","severity":"danger"},{"id":"largest-segments","group":"Capacidade","title":"Maiores segmentos (tabelas/índices)","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":"Mostra os segmentos que mais consomem espaço. Um crescimento inesperado pode indicar necessidade de arquivamento/expurgo ou de particionamento.","severity":"safe"},{"id":"undo-temp-usage","group":"Capacidade","title":"Uso das tablespaces UNDO e 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":"Se o uso do TEMP bate constantemente no teto, há operações grandes de sort/hash. Se o espaço de UNDO ativo não consegue atender à retenção, há risco de ORA-01555 (snapshot too old).","severity":"caution"},{"id":"sessions-vs-limit","group":"Capacidade","title":"Número de sessões vs limite","command":"SELECT resource_name, current_utilization, max_utilization, limit_value FROM v$resource_limit WHERE resource_name IN ('sessions','processes','transactions');","expect":"Se current_utilization se aproximar de limit_value (especialmente acima de 85%), novas conexões podem ser recusadas. max_utilization mostra o pico histórico; revise o parâmetro processes.","severity":"caution"},{"id":"fra-usage","group":"Capacidade","title":"Uso da Flash Recovery Area (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":"Quando a FRA chega a 85%, um alerta é gravado no alert log; em 100%, a gravação de archive logs para e o banco trava (archiver hung, ORA-00257). Limpe backups/archives do RMAN ou aumente db_recovery_file_dest_size.","severity":"danger"},{"id":"buffer-cache-hit","group":"Desempenho","title":"Taxa de acerto do buffer cache","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":"Em sistemas OLTP, normalmente espera-se acima de 90%. Valores persistentemente baixos podem indicar SGA/buffer cache subdimensionado ou indexação ruim; interprete junto com os wait events, não isoladamente.","severity":"safe"},{"id":"top-sql","group":"Desempenho","title":"Instruções SQL mais caras (elapsed time)","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":"Consultas com o maior elapsed time total. As com sec_per_exec alto ou executions muito alto são candidatas a tuning; analise-as com AWR/SQL Tuning Advisor.","severity":"safe"},{"id":"long-active-sessions","group":"Desempenho","title":"Sessões ativas de longa duração","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":"Sessões ativas com last_call_et (segundos) muito alto podem estar travadas ou executando uma consulta pesada. A coluna event mostra o recurso aguardado.","severity":"caution"},{"id":"blocking-sessions","group":"Desempenho","title":"Sessões bloqueadoras e em espera (locks)","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":"Nenhuma linha deve ser retornada. Sessões bloqueadoras causam latência na aplicação/deadlocks; se blocker_sid mantiver um lock por muito tempo (seconds_in_wait alto), avalie com a equipe da aplicação e, se necessário, execute ALTER SYSTEM KILL SESSION.","severity":"danger"},{"id":"rman-last-backup","group":"Backup e recuperação","title":"Status do último backup RMAN bem-sucedido","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":"O backup mais recente deve ter status = COMPLETED e um start_time recente o suficiente para sua política de RPO (ex.: nas últimas 24 horas). Entradas FAILED ou 'COMPLETED WITH WARNINGS' devem ser investigadas.","severity":"danger"},{"id":"archivelog-mode","group":"Backup e recuperação","title":"Modo archivelog e status do archiver","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":"Um banco de produção deve ter log_mode = ARCHIVELOG (caso contrário, a recuperação point-in-time não é possível). Se nenhum archive foi gerado nas últimas 24 horas, o archiver pode estar travado.","severity":"danger"},{"id":"locked-expired-accounts","group":"Segurança","title":"Contas bloqueadas ou expiradas","command":"SELECT username, account_status, lock_date, expiry_date, profile FROM dba_users WHERE account_status != 'OPEN' ORDER BY username;","expect":"Contas críticas de aplicação LOCKED/EXPIRED causam indisponibilidades inesperadas. Contas padrão (SCOTT, HR etc.) bloqueadas/desabilitadas é algo bom. EXPIRED(GRACE) indica uma expiração de senha próxima.","severity":"caution"},{"id":"privileged-users","group":"Segurança","title":"Usuários com privilégios elevados (role 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":"A role DBA deve ser concedida apenas a contas necessárias e conhecidas. Grantees inesperados ou com admin_option = YES são um risco de escalonamento de privilégios; revise-os segundo o princípio do menor privilégio. Para contas com privilégios SYSDBA/SYSOPER, verifique também: SELECT username, sysdba, sysoper FROM v$pwfile_users;","severity":"caution"},{"id":"default-password-users","group":"Segurança","title":"Contas abertas com senhas padrão não alteradas","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":"Contas com has_default_password = YES devem ter a senha alterada imediatamente ou ser bloqueadas (ALTER USER ... ACCOUNT LOCK). Para a política de validade de senhas, verifique também PASSWORD_LIFE_TIME em DBA_PROFILES.","severity":"caution"},{"id":"dataguard-lag","group":"Replicação","title":"Lag do standby do Data Guard","command":"SELECT name, value, unit, time_computed FROM v$dataguard_stats WHERE name IN ('apply lag','transport lag');","expect":"apply lag e transport lag devem estar o mais próximo possível de 0. Lag na ordem de minutos/horas indica problema de rede ou do MRP (Managed Recovery Process); o alvo de failover está em risco.","severity":"danger"},{"id":"dataguard-mrp","group":"Replicação","title":"Status do processo de apply do standby (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":"Em um physical standby, o processo MRP0 deve aparecer com action APPLYING_LOG ou WAIT_FOR_LOG. Se não houver MRP, o apply parou; se não houver RFS, os logs não estão chegando do primary. v$dataguard_process é do 12.2+; no 12.1 e anteriores, use a (agora obsoleta) v$managed_standby (colunas process, status).","severity":"danger"}]},"health/postgres.json":{"engineId":"postgres","engine":"PostgreSQL","order":2,"checks":[{"id":"version-uptime","group":"Geral","title":"Versão e uptime","command":"SELECT version() AS pg_version, pg_postmaster_start_time() AS started_at, date_trunc('second', now() - pg_postmaster_start_time()) AS uptime;","expect":"Mostra a versão e o horário de início. Se o uptime for inesperadamente curto (início recente), pode ter ocorrido um restart não planejado ou um crash; verifique os logs.","severity":"safe"},{"id":"recent-errors","group":"Geral","title":"Estatísticas de checkpoint","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":"Se o número de checkpoints solicitados (num_requested / checkpoints_req) for alto em relação aos programados (num_timed / checkpoints_timed), o WAL está enchendo rápido demais; aumente max_wal_size. No PG17, os contadores passaram de pg_stat_bgwriter para pg_stat_checkpointer.","severity":"caution"},{"id":"table-bloat","group":"Geral","title":"Tabelas inchadas e proporção de dead tuples","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":"Tabelas com dead_pct alto (ex.: acima de 20%) estão inchadas (bloat); isso afeta o desempenho do VACUUM e o uso de disco. Se last_autovacuum for muito antigo, revise as configurações do autovacuum ou execute um VACUUM (ANALYZE) manual.","severity":"caution"},{"id":"database-size","group":"Capacidade","title":"Tamanhos dos bancos de dados","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":"Mostra os tamanhos dos bancos de dados. Avalie um crescimento inesperado junto com a capacidade de disco (df -h); o PostgreSQL interrompe as operações de escrita quando o disco fica cheio.","severity":"danger"},{"id":"largest-tables","group":"Capacidade","title":"Maiores tabelas (incluindo índices)","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":"Mostra as tabelas que ocupam mais espaço. Se index_toast_size for muito maior que o tamanho da tabela, pode haver índices em excesso/não utilizados; considere arquivamento ou particionamento.","severity":"safe"},{"id":"temp-files","group":"Capacidade","title":"Uso de arquivos temporários","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":"Valores altos de temp_files/temp_bytes indicam que work_mem é insuficiente e que operações de sort/hash estão indo para o disco. Considere aumentar work_mem ou otimizar as consultas.","severity":"caution"},{"id":"connections-vs-limit","group":"Capacidade","title":"Número de conexões vs. 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":"Apenas as conexões de clientes são contadas (o filtro backend_type = 'client backend' é necessário porque pg_stat_activity também inclui processos em segundo plano). Acima de 80% de pct_used, novas conexões correm risco de ser rejeitadas (especialmente quando superuser_reserved_connections é atingido). Recomenda-se um pooler de conexões (PgBouncer).","severity":"caution"},{"id":"wal-directory-size","group":"Capacidade","title":"Tamanho do diretório de WAL e retenção por replication slots","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":"Replication slots inativos (active = false) fazem o WAL se acumular e o diretório pg_wal encher. Se retained_wal for grande, verifique a quem pertence o slot (slot_type, database, plugin): active = false também pode indicar um standby temporariamente desconectado ou um slot de subscriber lógico/CDC (ex.: Debezium). Se realmente não for usado, remova-o com pg_drop_replication_slot; um standby que dependia do slot removido deve ser reconstruído, e o lado do subscriber/CDC deve ser ressincronizado. Para proteção permanente, defina um limite superior com max_slot_wal_keep_size (PG13+).","severity":"danger"},{"id":"cache-hit-ratio","group":"Desempenho","title":"Taxa de acerto do buffer cache","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":"Para cargas OLTP, o alvo normalmente é acima de 99%. Um valor consistentemente baixo pode indicar que shared_buffers é pequeno demais ou que o working set não cabe na memória.","severity":"safe"},{"id":"top-queries","group":"Desempenho","title":"Consultas mais caras (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 deve estar em shared_preload_libraries (exige restart) e instalado no banco (CREATE EXTENSION pg_stat_statements). Os nomes total_exec_time/mean_exec_time são do PG13+; o PG12 usa total_time/mean_time. As consultas que consomem mais tempo total são candidatas a tuning; execute EXPLAIN ANALYZE nas que têm mean_ms alto.","severity":"safe"},{"id":"long-running-queries","group":"Desempenho","title":"Consultas ativas de longa duração","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":"Consultas ativas rodando há mais de 1 minuto podem estar travadas ou ser pesadas. wait_event mostra o que está sendo aguardado. Esta consulta lista apenas consultas ativas; verifique separadamente as sessões 'idle in transaction' (que impedem o VACUUM de remover dead tuples) com state = 'idle in transaction' e xact_start.","severity":"caution"},{"id":"blocking-locks","group":"Desempenho","title":"Sessões bloqueadoras e locks em espera","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":"Nenhuma linha deve ser retornada. Sessões bloqueadoras (blocking_pid) causam atrasos e timeouts na aplicação; investigue uma transação que bloqueia há muito tempo e, se necessário, encerre-a com pg_terminate_backend.","severity":"danger"},{"id":"archiver-status","group":"Backup e recuperação","title":"Saúde do arquivamento de 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 deve ser 0 e last_failed_time deve ser anterior a last_archived_time. Se since_last_archive for muito grande, o arquivamento parou (falha no archive_command); a cadeia de backup para PITR está quebrada.","severity":"danger"},{"id":"last-basebackup","group":"Backup e recuperação","title":"Atualidade do último backup e do archive de 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":"Verifique o horário do último base backup na ferramenta de backup (logs dos jobs do pgBackRest / Barman / pg_basebackup); ele deve ser recente o suficiente para sua política de RPO. Para PITR, o archive de WAL também deve ser contínuo: se since_last_archive for grande ou failed_count estiver aumentando, a cadeia de archives pode estar quebrada.","severity":"danger"},{"id":"locked-expired-roles","group":"Segurança","title":"Roles de login expiradas ou prestes a expirar","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":"Roles de aplicação cujo rolvaliduntil já passou ficam impedidas de fazer login, causando indisponibilidade. Planeje a renovação com antecedência para senhas que expiram nos próximos 7 dias.","severity":"caution"},{"id":"superuser-roles","group":"Segurança","title":"Roles com privilégios elevados (SUPERUSER / privilégios de criação)","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 deve existir apenas em contas necessárias e conhecidas. Roles com rolbypassrls = true ignoram a row-level security (RLS); privilégios elevados inesperados devem ser revogados segundo o princípio do menor privilégio.","severity":"caution"},{"id":"hba-trust-auth","group":"Segurança","title":"Regras de autenticação fraca (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 permite acesso sem senha e é perigoso em produção; 'password' envia a senha em texto claro. Substitua-os por scram-sha-256. (Requer PG 10+.)","severity":"danger"},{"id":"replication-lag","group":"Replicação","title":"Lag da streaming replication (lado do primary)","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":"Execute no primary. state deve ser streaming e replay_lag (bytes/tempo) deve ser pequeno. Se o standby não aparecer, a conexão caiu; se sync_state = async, a replicação síncrona não está funcionando como esperado.","severity":"danger"},{"id":"replica-lag-standby","group":"Replicação","title":"Lag da replicação (lado do standby)","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":"Execute no servidor standby. in_recovery deve ser true. Se replication_delay estiver na faixa de minutos/horas, pode haver apply lag; porém, esse valor também cresce quando não há escritas no primary (falso alarme), então interprete-o junto com a diferença de LSN; se a distância entre receive_lsn e replay_lsn for grande, o replay do WAL não está acompanhando.","severity":"danger"}]},"health/mysql.json":{"engineId":"mysql","engine":"MySQL","order":3,"checks":[{"id":"version-uptime","group":"Geral","title":"Versão e uptime","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":"Mostra a versão e o uptime em segundos. Se uptime_seconds for inesperadamente pequeno, pode ter ocorrido um restart não planejado ou um crash; verifique o error log.","severity":"safe"},{"id":"error-log-status","group":"Geral","title":"Entradas recentes do error log (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":"Mostra os erros e avisos recentes (requer MySQL 8.0+). Investigue as entradas com prio = 'Error' (especialmente erros de InnoDB, lock e disco). Em versões mais antigas, verifique o arquivo log_error do servidor.","severity":"danger"},{"id":"crashed-tables","group":"Geral","title":"Tabelas corrompidas / tabelas a verificar","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":"Lista o engine e o horário da última atualização de cada tabela. Tabelas MyISAM podem corromper; em caso de dúvida, verifique a integridade com CHECK TABLE ... ou mysqlcheck. Recomenda-se InnoDB para dados críticos.","severity":"caution"},{"id":"schema-sizes","group":"Capacidade","title":"Tamanhos dos schemas (bancos de dados)","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":"Mostra os tamanhos dos schemas e o espaço recuperável data_free. Avalie junto com a capacidade de disco; se free_mb for alto, o espaço pode ser recuperado com OPTIMIZE TABLE.","severity":"danger"},{"id":"largest-tables","group":"Capacidade","title":"Maiores tabelas (incluindo data_free / fragmentação)","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":"Mostra as maiores tabelas. Tabelas com data_free_mb alto estão fragmentadas; o espaço pode ser recuperado com OPTIMIZE TABLE. Considere particionamento para tabelas muito grandes.","severity":"safe"},{"id":"innodb-tablespace","group":"Capacidade","title":"Uso do tablespace InnoDB e do espaço temporário","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":"Mostra o quanto os datafiles do InnoDB estão cheios. Se innodb_file_per_table estiver desligado, o ibdata1 cresce continuamente e nunca diminui. Para crescimento excessivo do tablespace temporário, verifique também a saída de SHOW ENGINE INNODB STATUS.","severity":"caution"},{"id":"connections-vs-limit","group":"Capacidade","title":"Número de conexões e limite de 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":"Se max_used se aproximar de max_connections (acima de 85%), há risco de erros 'Too many connections'. Um aborted_connects alto aponta para problemas de autenticação/rede; use um pool de conexões.","severity":"caution"},{"id":"binlog-size","group":"Capacidade","title":"Arquivos de binary log e tamanho total","command":"SHOW BINARY LOGS;","expect":"Lista os arquivos de binlog e seus tamanhos. Se o tamanho total estiver pressionando o espaço em disco, revise binlog_expire_logs_seconds (expire_logs_days antes do 8.0; essa variável ficou obsoleta no 8.0 e foi removida no 8.4); se houver replicação, não faça purge antes que as réplicas os tenham lido.","severity":"caution"},{"id":"buffer-pool-hit","group":"Desempenho","title":"Taxa de acerto do InnoDB buffer pool","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":"Normalmente o alvo de hit_ratio_pct é acima de 99%. Se permanecer baixo, innodb_buffer_pool_size é insuficiente; considere aumentá-lo até ~70-80% da RAM em um servidor dedicado (menos em um servidor compartilhado).","severity":"safe"},{"id":"top-queries","group":"Desempenho","title":"Consultas mais caras (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":"O schema sys e o performance_schema devem estar habilitados. As consultas que consomem mais total_latency são candidatas a tuning. Se rows_examined_avg for muito maior que rows_sent_avg, falta um índice; analise com EXPLAIN.","severity":"safe"},{"id":"long-running-queries","group":"Desempenho","title":"Consultas ativas de longa duração","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":"Consultas rodando há mais de 60 segundos podem estar travadas ou ser pesadas. A coluna state mostra o que está sendo aguardado. Sessões longas no estado 'Sleep' também esgotam o pool de conexões; use KILL <id> se necessário.","severity":"caution"},{"id":"blocking-locks","group":"Desempenho","title":"Sessões bloqueadoras e locks em espera","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":"Não deve retornar linhas. Uma transação bloqueadora (blocking_thread) causa latência na aplicação e erros de lock wait timeout. Investigue uma transação que bloqueia há muito tempo e encerre-a com KILL se necessário. (Sintaxe do MySQL 8.0.)","severity":"danger"},{"id":"binlog-enabled","group":"Backup e recuperação","title":"Configurações de binary log e recuperação","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 deve estar ON para recuperação point-in-time. Para durabilidade, recomendam-se sync_binlog = 1 e innodb_flush_log_at_trx_commit = 1 (caso contrário, transações podem ser perdidas em um crash). binlog_format = ROW é o mais seguro para replicação.","severity":"danger"},{"id":"last-backup-note","group":"Backup e recuperação","title":"Horário do último backup (binlog / indicador da ferramenta)","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":"O MySQL não rastreia o status de backup por conta própria; verifique o horário do último backup bem-sucedido nos logs das ferramentas mysqldump / dump do MySQL Shell / Percona XtraBackup (o mysqlpump foi descontinuado no 8.0.34 e removido no 8.4). O backup deve ser tão recente quanto sua política de RPO exige (ex.: nas últimas 24 horas).","severity":"danger"},{"id":"locked-expired-accounts","group":"Segurança","title":"Contas bloqueadas ou com senhas expiradas","command":"SELECT user, host, account_locked, password_expired, password_lifetime FROM mysql.user ORDER BY user, host;","expect":"Contas críticas de aplicação com account_locked = 'Y' ou password_expired = 'Y' causam indisponibilidades. Se password_lifetime for NULL e a expiração global estiver desligada, a senha nunca expira; isso pode ser uma lacuna de política.","severity":"caution"},{"id":"anonymous-nopassword-users","group":"Segurança","title":"Usuários anônimos e usuários sem senha","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":"Não deve retornar linhas. Usuários anônimos (user = '') e contas sem senha são uma falha de segurança grave; remova-os com mysql_secure_installation ou atribua senhas fortes.","severity":"danger"},{"id":"super-privilege-users","group":"Segurança","title":"Usuários com privilégios elevados (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":"Privilégios como SUPER, FILE e GRANT OPTION devem existir apenas em contas necessárias e conhecidas. Grantees inesperados são um risco de escalonamento de privilégios; dê atenção especial a contas com privilégios elevados definidas com % (qualquer host).","severity":"caution"},{"id":"replica-status","group":"Replicação","title":"Status e lag da réplica (standby)","command":"SHOW REPLICA STATUS;","expect":"Execute na réplica (MySQL 8.0.22+). Replica_IO_Running e Replica_SQL_Running devem estar ambos 'Yes'. Seconds_Behind_Source deve ser pequeno; se for NULL, a replicação parou. Verifique o campo Last_Error. (SHOW SLAVE STATUS em versões mais antigas.)","severity":"danger"},{"id":"replication-threads","group":"Replicação","title":"Status da conexão de replicação e do applier (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 e sql_state devem estar 'ON'. Se io_error/sql_error estiver preenchido, a replicação falhou e parou; em configurações multi-source, cada channel_name deve estar saudável individualmente.","severity":"danger"}]},"health/mssql.json":{"engineId":"mssql","engine":"SQL Server","order":4,"checks":[{"id":"version-uptime","group":"Geral","title":"Versão e uptime","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":"Verifique a versão e o nível de patch. Se o uptime for muito curto (menos de algumas horas), pode ter ocorrido um restart inesperado; revise o error log do SQL Server.","severity":"safe"},{"id":"database-states","group":"Geral","title":"Bancos de dados em estado problemático (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":"Todos os bancos de produção devem estar ONLINE. SUSPECT, RECOVERY_PENDING ou EMERGENCY exige ação imediata; inicie a recuperação e revise o error log.","severity":"danger"},{"id":"recent-errors","group":"Geral","title":"Erros significativos recentes (ring buffer de memória/erros)","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":"Revise os registros recentes de exceções/erros. Erros 823/824/825 (consistência de I/O) recorrentes apontam para corrupção de disco. Para detalhes, leia também o error log no servidor com xp_readerrorlog.","severity":"caution"},{"id":"data-log-file-usage","group":"Capacidade","title":"Uso dos arquivos de dados e de log","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":"Execute em cada banco. Se o espaço usado estiver muito próximo do alocado (85%+) e o autogrowth tiver limite, planeje o crescimento ou adicione disco. Se o arquivo de log estiver constantemente cheio, revise as configurações de backup/recovery model.","severity":"caution"},{"id":"largest-tables","group":"Capacidade","title":"Maiores tabelas (tamanho e número de linhas)","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":"Identifique as tabelas que mais consomem espaço. Um crescimento inesperado pode indicar necessidade de arquivamento, manutenção de índices ou particionamento.","severity":"safe"},{"id":"tempdb-usage","group":"Capacidade","title":"Uso de espaço do 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":"Se o tempdb estiver prestes a ficar sem espaço livre (unallocated baixo), as consultas podem falhar. Se o version store continuar crescendo, há transações abertas de longa duração; investigue com sys.dm_tran_active_snapshot_database_transactions.","severity":"caution"},{"id":"connection-count","group":"Capacidade","title":"Número e distribuição de conexões","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":"Acompanhe o número de conexões por aplicação/banco. Um número anormalmente alto de conexões de uma única aplicação pode indicar vazamento no pool de conexões. Não se aproxime do limite de max worker threads.","severity":"safe"},{"id":"vlf-count","group":"Capacidade","title":"Número de VLFs do arquivo de log (fragmentação)","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":"Um número alto de VLFs (mais de algumas centenas, ex.: 500+) significa que o arquivo de log cresceu em incrementos muito pequenos; isso torna mais lentos a recuperação e o desempenho do backup. Reduza o log e faça-o crescer novamente em um único passo grande.","severity":"caution"},{"id":"buffer-cache-ple","group":"Desempenho","title":"Buffer Cache Hit Ratio e 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":"O buffer cache hit ratio deve idealmente ser 99%+ (hit_ratio_raw / hit_ratio_base). Se o Page Life Expectancy for consistentemente baixo (regra prática: abaixo de 300 s por 4 GB por nó NUMA), há pressão de memória; é necessário mais RAM ou otimização de consultas.","severity":"caution"},{"id":"expensive-queries","group":"Desempenho","title":"Consultas mais caras (CPU e leituras)","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":"Identifique as consultas mais caras por CPU e leituras lógicas. Consultas com muitas leituras são sinal de índices ausentes; revise seus planos de execução e adicione índices ou reescreva as consultas.","severity":"safe"},{"id":"blocking-sessions","group":"Desempenho","title":"Sessões bloqueadoras","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":"Uma sessão bloqueadora (blocking_session_id <> 0) significa que as consultas estão fazendo umas às outras esperar. Bloqueios prolongados causam timeouts na aplicação; encontre o head blocker e considere encerrar a transação longa.","severity":"danger"},{"id":"wait-stats","group":"Desempenho","title":"Principais estatísticas de espera (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":"Interprete os wait types dominantes: PAGEIOLATCH = gargalo de I/O de disco, CXPACKET/CXCONSUMER = paralelismo, LCK_M = bloqueio, WRITELOG = disco de log, RESOURCE_SEMAPHORE = memória. Um percentual alto de signal wait indica pressão de CPU.","severity":"safe"},{"id":"last-backup","group":"Backup e recuperação","title":"Horários dos últimos backups (full / differential / log)","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":"Todo banco de produção deve ter um backup full recente. Se last_full_backup for NULL ou muito antigo (além do RPO), o job de backup está falhando. No recovery model FULL, sem backups de log, o arquivo de log continua crescendo.","severity":"danger"},{"id":"recovery-model","group":"Backup e recuperação","title":"Consistência do recovery model","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":"Bancos críticos devem usar FULL para recuperação point-in-time. log_reuse_wait_desc = LOG_BACKUP significa que há um backup de log pendente; ACTIVE_TRANSACTION aponta para uma transação de longa duração.","severity":"caution"},{"id":"sysadmin-members","group":"Segurança","title":"Membros da role 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":"A associação à sysadmin deve ser minimizada. Logins inesperados (especialmente contas de aplicação ou usuários individuais) são um risco de escalonamento de privilégios; aplique o princípio do menor privilégio.","severity":"danger"},{"id":"sa-and-password-policy","group":"Segurança","title":"Conta sa e logins com política de senha desabilitada","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":"A conta sa deve estar desabilitada ou renomeada. Logins SQL com is_policy_checked = 0 trazem risco de senha fraca/antiga; habilite a política de senha (CHECK_POLICY).","severity":"caution"},{"id":"alwayson-sync","group":"Replicação","title":"Estado de sincronização e filas do 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 deve ser SYNCHRONIZED (síncrono) ou SYNCHRONIZING (assíncrono), e synchronization_health deve ser HEALTHY. Se log_send_queue ou redo_queue estiver crescendo, a réplica está ficando para trás; o risco de perda de dados/RTO no failover aumenta.","severity":"caution"}]},"health/mongodb.json":{"engineId":"mongodb","engine":"MongoDB","order":5,"checks":[{"id":"version-uptime","group":"Geral","title":"Versão e uptime","command":"db.serverStatus().version; db.serverStatus().uptime","expect":"Verifique se a versão é suportada e tem os patches aplicados. uptime está em segundos; se for muito pequeno (alguns milhares de segundos), ocorreu um restart inesperado; revise os logs do mongod.","severity":"safe"},{"id":"replset-status","group":"Geral","title":"Estados dos membros do replica set (health)","command":"rs.status().members.forEach(function(m) { print(m.name + \" | \" + m.stateStr + \" | health=\" + m.health); })","expect":"Todo membro deve ter health=1 e deve haver exatamente um PRIMARY. health=0 ou os estados (not reachable/healthy), DOWN e RECOVERING indicam uma falha. Se houver mais de um PRIMARY ou nenhum, há um problema de eleição.","severity":"danger"},{"id":"dbstats-sizes","group":"Capacidade","title":"Tamanhos dos bancos (data / storage / index)","command":"db.stats(1024*1024)","expect":"Monitore dataSize, storageSize e indexSize (MB). Se storageSize for muito maior que dataSize, pode haver fragmentação. Manter o indexSize dentro da RAM (cache do WiredTiger) é crítico para o desempenho.","severity":"safe"},{"id":"disk-space","group":"Capacidade","title":"Uso de espaço em disco (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":"Se a proporção entre fsUsedSize e fsTotalSize ultrapassar 85%, o disco está prestes a encher; o MongoDB interrompe as escritas quando o disco fica cheio. Planeje adicionar disco ou arquivar dados.","severity":"caution"},{"id":"largest-collections","group":"Capacidade","title":"Maiores coleções","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":"Identifique as coleções que mais usam espaço. Um crescimento inesperado pode indicar necessidade de arquivamento, de um índice TTL ou de sharding. Revise as coleções cujo tamanho de índices excede o tamanho dos dados.","severity":"safe"},{"id":"connections","group":"Capacidade","title":"Número de conexões (current / available)","command":"db.serverStatus().connections","expect":"Se current se aproximar de available, o limite de conexões está prestes a ser atingido e novas conexões serão rejeitadas. Verifique as configurações do pool de conexões da aplicação e possíveis vazamentos.","severity":"caution"},{"id":"wiredtiger-cache","group":"Desempenho","title":"Uso do cache do WiredTiger e 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":"A eviction é acionada quando a memória usada ultrapassa 80% do cache máximo; acima de 95%, as threads da aplicação são forçadas a fazer eviction e o desempenho cai. Uma proporção alta de páginas sujas (dirty) indica pressão de escrita.","severity":"caution"},{"id":"slow-queries-profiler","group":"Desempenho","title":"Consultas lentas (profiler) e 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":"Esta verificação é somente leitura: primeiro mostra o status do profiler (was: 0 desligado, 1 apenas operações lentas, 2 todas) e depois lista as operações lentas registradas. Se o profiler estiver desligado (was: 0), system.profile fica vazio; para diagnóstico, habilite-o em uma etapa separada com db.setProfilingLevel(1, {slowms: 100}) e desabilite com db.setProfilingLevel(0) ao terminar. Consultas que mostram COLLSCAN em planSummary fazem varredura completa da coleção e estão sem índice. Otimize as consultas com valores altos de millis por meio de indexação. O profiler adiciona overhead; use-o com cuidado em produção.","severity":"caution"},{"id":"long-running-ops","group":"Desempenho","title":"Operações de longa duração (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":"Operações ativas com valores altos de secs_running podem causar bloqueios. Encerre-as com db.killOp(opid) quando necessário. Operações com waitingForLock=true estão aguardando um lock; investigue a operação raiz.","severity":"danger"},{"id":"oplog-window","group":"Backup e recuperação","title":"Janela do oplog (histórico de replicação)","command":"rs.printReplicationInfo()","expect":"A janela do oplog (tamanho configurado do oplog e duração do log em horas) deve ser longa o suficiente. Se a janela for curta (algumas horas), um secondary lento pode cair em uma ressincronização completa (initial sync). As estratégias de backup e de recuperação point-in-time dependem do oplog.","severity":"caution"},{"id":"backup-note","group":"Backup e recuperação","title":"Status do backup e nota do último backup","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":"O MongoDB não tem backup agendado nativo; usam-se mongodump, snapshots do sistema de arquivos, Ops Manager ou PBM. Verifique na ferramenta externa o horário do último backup bem-sucedido e o teste de restore. Em um replica set, a janela do oplog (oplogWindowHours) limita até onde o PITR baseado em oplog pode voltar; ela não deve ser menor que o intervalo de backup. Verifique se as metas de RPO/RTO são atendidas.","severity":"danger"},{"id":"users-roles","group":"Segurança","title":"Lista de usuários e roles","command":"db.getSiblingDB('admin').system.users.find({}, {user: 1, db: 1, roles: 1, _id: 0}).forEach(printjson)","expect":"Revise os usuários definidos e suas roles. Contas inesperadas ou roles amplas demais (root, __system, dbOwner) são um risco de escalonamento de privilégios. Aplique o princípio do menor privilégio.","severity":"caution"},{"id":"auth-enabled","group":"Segurança","title":"A autenticação (authorization) está habilitada?","command":"db.getSiblingDB('admin').runCommand({getCmdLineOpts: 1}).parsed.security","expect":"security.authorization deve estar 'enabled'. Se estiver desabilitada (ou não houver bloco security), o banco fica aberto a acesso sem autenticação; isso é uma falha de segurança grave, habilite imediatamente.","severity":"danger"},{"id":"secondary-lag","group":"Replicação","title":"Lag de replicação dos secondaries","command":"rs.printSecondaryReplicationInfo()","expect":"O valor de 'replication lag' de cada secondary deve ser baixo (alguns segundos). Se o lag for grande (minutos), o secondary não consegue acompanhar a carga ou há um problema de rede/disco; o risco de perda de dados e de inconsistência de leitura no failover aumenta.","severity":"caution"},{"id":"member-health","group":"Replicação","title":"Saúde dos membros e estado da eleição","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":"Todos os membros devem estar saudáveis (health=1) e no estado esperado (PRIMARY/SECONDARY). Uma mensagem de erro em lastHeartbeatMessage indica uma partição de rede ou um membro inacessível. A perda da maioria interrompe as escritas.","severity":"caution"}]},"health/redis.json":{"engineId":"redis","engine":"Redis","order":6,"checks":[{"id":"server-version-uptime","group":"Geral","title":"Versão e uptime","command":"redis-cli INFO server | grep -E \"redis_version|uptime_in_days|redis_mode|os\"","expect":"redis_version deve ser uma release suportada e com patches. Se uptime_in_days for muito pequeno, ocorreu um restart inesperado; redis_mode (standalone/sentinel/cluster) confirma a configuração.","severity":"safe"},{"id":"persistence-status","group":"Geral","title":"Status da persistência (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 e aof_last_write_status devem ser 'ok'. Um valor 'err' indica problema de disco/permissão ou disco cheio e traz risco de perda de dados. loading:1 significa que o servidor ainda está carregando dados.","severity":"danger"},{"id":"memory-usage","group":"Capacidade","title":"Uso de memória (used_memory / maxmemory)","command":"redis-cli INFO memory | grep -E \"used_memory_human|used_memory:|maxmemory_human|maxmemory:|maxmemory_policy\"","expect":"Se used_memory se aproximar de maxmemory (85%+), há risco de eviction ou OOM. Se maxmemory=0, não há limite, e o Redis pode consumir toda a RAM e derrubar o sistema; sempre defina um limite e uma maxmemory_policy adequada.","severity":"caution"},{"id":"memory-fragmentation","group":"Capacidade","title":"Taxa de fragmentação de memória","command":"redis-cli INFO memory | grep -E \"mem_fragmentation_ratio|mem_allocator\"","expect":"O ideal é mem_fragmentation_ratio entre 1.0 e 1.5. Acima de 1.5 indica fragmentação alta (memória desperdiçada). Abaixo de 1.0 indica que o Redis está indo para swap em disco (problema sério de desempenho); verifique a RAM do sistema.","severity":"caution"},{"id":"evicted-keys","group":"Capacidade","title":"Chaves removidas por eviction (evicted_keys)","command":"redis-cli INFO stats | grep -E \"evicted_keys|expired_keys|keyspace_misses\"","expect":"Se evicted_keys continuar aumentando, o Redis atingiu o limite de memória e está descartando dados; isso pode causar perda de dados indesejada. Considere adicionar memória, usar TTLs ou revisar a maxmemory_policy.","severity":"caution"},{"id":"dbsize-keyspace","group":"Capacidade","title":"Número de chaves e distribuição do keyspace","command":"redis-cli DBSIZE; redis-cli INFO keyspace","expect":"Monitore o número total de chaves (DBSIZE) e a distribuição por banco (INFO keyspace: keys, expires, avg_ttl). Um keyspace crescendo sem TTLs (expires baixo) causa crescimento descontrolado da memória. Saltos repentinos no número de chaves podem ser sinal de comportamento anormal.","severity":"safe"},{"id":"hit-ratio","group":"Desempenho","title":"Taxa de acerto do cache (keyspace hits/misses)","command":"redis-cli INFO stats | grep -E \"keyspace_hits|keyspace_misses\"","expect":"Hit ratio = hits / (hits + misses). Para uso como cache, a taxa deve ser alta (80%+). Uma taxa baixa indica cache ineficiente, TTLs incorretos ou um padrão de cache miss; certifique-se de que os dados solicitados com frequência estejam em cache.","severity":"safe"},{"id":"slowlog","group":"Desempenho","title":"Log de comandos lentos (SLOWLOG)","command":"redis-cli SLOWLOG GET 10","expect":"Examine os comandos lentos (limite padrão de 10ms). Comandos O(N) (KEYS, SMEMBERS, HGETALL grandes, SORT) bloqueiam o Redis single-threaded e atrasam todas as requisições. Substitua-os por alternativas como SCAN.","severity":"caution"},{"id":"clients","group":"Desempenho","title":"Clientes conectados e bloqueados (clients)","command":"redis-cli INFO clients | grep -E \"connected_clients|blocked_clients|maxclients|client_recent_max_input_buffer\"","expect":"Se connected_clients se aproximar de maxclients, novas conexões são rejeitadas. Um número alto de blocked_clients (aguardando BLPOP/BRPOP) pode ser intencional, mas um aumento inesperado é sinal de congestionamento. Verifique vazamentos de conexão.","severity":"safe"},{"id":"ops-per-sec","group":"Desempenho","title":"Throughput instantâneo (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 mostra a carga de trabalho atual. Quedas/picos repentinos são sinal de anomalias. Se rejected_connections > 0, o limite de maxclients foi atingido. Por ser single-threaded, um número muito alto de ops pode criar um gargalo de CPU.","severity":"safe"},{"id":"rdb-last-save","group":"Backup e recuperação","title":"Último save RDB e alterações pendentes","command":"redis-cli INFO persistence | grep -E \"rdb_last_save_time|rdb_changes_since_last_save|rdb_last_bgsave_status\"; redis-cli LASTSAVE","expect":"Se rdb_changes_since_last_save for muito alto, muitos dados se acumularam desde o último snapshot; essas alterações são perdidas em um crash. Se rdb_last_save_time (LASTSAVE, Unix time) for muito antigo, revise o intervalo de save ou a frequência de backup.","severity":"caution"},{"id":"aof-rewrite","group":"Backup e recuperação","title":"Status do rewrite do 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":"Em cenários que exigem durabilidade, aof_enabled=1 deve estar definido. aof_last_bgrewrite_status deve ser 'ok'; 'err' indica um problema de disco/persistência. Se aof_current_size for muito maior que base_size, é necessário um rewrite.","severity":"caution"},{"id":"acl-auth","group":"Segurança","title":"Configuração de ACL / autenticação (requirepass)","command":"redis-cli ACL LIST; redis-cli ACL GETUSER default","expect":"Deve haver pelo menos um usuário protegido por senha. Se as flags na saída de ACL GETUSER default mostrarem 'on' e 'nopass' (requirepass também é a senha desse usuário), o Redis está aberto a acesso sem autenticação; isso é uma falha de segurança grave. As senhas são mostradas apenas como hashes; não use CONFIG GET requirepass para esta verificação, pois ele exibe a senha em texto claro. Defina usuários com menor privilégio por meio de ACLs.","severity":"danger"},{"id":"dangerous-commands","group":"Segurança","title":"Comandos perigosos e 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 deve ser 'yes' e bind deve estar limitado a interfaces seguras. Comandos perigosos como FLUSHALL, FLUSHDB, CONFIG, KEYS e DEBUG devem ser desabilitados em produção com rename-command ou restringidos com ACLs.","severity":"caution"},{"id":"replication-status","group":"Replicação","title":"Status da replicação (role, master link)","command":"redis-cli INFO replication","expect":"Verifique role (master/slave), connected_slaves e o status de cada réplica. Em uma réplica, master_link_status deve ser 'up'; 'down' significa que o link está quebrado. Se master_last_io_seconds_ago for alto (lag), o risco de perda de dados e de inconsistência aumenta.","severity":"danger"}]},"health/elasticsearch.json":{"engineId":"elasticsearch","engine":"Elasticsearch","order":7,"checks":[{"id":"cluster-health","group":"Geral","title":"Saúde do cluster (green / yellow / red)","command":"GET _cluster/health","expect":"status deve ser 'green': todos os shards primários e réplicas estão alocados. 'yellow' significa que os primários estão intactos, mas algumas réplicas não estão alocadas (risco de redundância); 'red' significa que pelo menos um shard primário foi perdido/não está alocado (parte dos dados está indisponível, ação imediata necessária). unassigned_shards deve ser 0.","severity":"danger"},{"id":"cluster-version","group":"Geral","title":"Versão e informações do cluster","command":"GET /","expect":"version.number deve ser uma versão suportada e com os patches de segurança aplicados. Versões antigas/EOL (end-of-life) trazem riscos de segurança e estabilidade. Verifique também se todos os nós rodam a mesma versão com GET _cat/nodes?v&h=name,version (uma mistura temporária durante um rolling upgrade é normal).","severity":"safe"},{"id":"pending-tasks","group":"Geral","title":"Tarefas pendentes do cluster","command":"GET _cluster/pending_tasks","expect":"A lista deve estar vazia ou ser muito curta. Tarefas que continuam se acumulando e aguardam por muito tempo (time_in_queue alto) indicam que o nó master está sobrecarregado ou que as atualizações do cluster state estão travadas; isso degrada o tempo de resposta de todo o cluster.","severity":"caution"},{"id":"disk-allocation-watermark","group":"Capacidade","title":"Alocação de disco e status de watermark","command":"GET _cat/allocation?v","expect":"disk.percent de cada nó deve estar abaixo do high watermark (padrão 90%). Acima de 85% é um alerta, 90% (high) aciona a realocação de shards, e 95% (flood_stage) torna os índices somente leitura. Verifique se a coluna shards está equilibrada entre os nós; uma distribuição desigual faz um único nó encher antes.","severity":"danger"},{"id":"largest-indices","group":"Capacidade","title":"Maiores índices (store size)","command":"GET _cat/indices?v&s=store.size:desc","expect":"Acompanhe os índices que mais consomem espaço e seus valores de doc.count. O crescimento descontrolado de índices de logs/métricas é a principal causa de discos cheios; defina políticas de rollover e exclusão para eles com ILM (Index Lifecycle Management). Dê atenção extra a índices com status 'close' ou com health yellow/red.","severity":"caution"},{"id":"jvm-heap-usage","group":"Capacidade","title":"Uso de JVM heap e RAM (por nó)","command":"GET _cat/nodes?v&h=name,heap.percent,ram.percent,cpu,load_1m","expect":"heap.percent deve ficar consistentemente abaixo de 75%; valores sustentados de 85%+ significam pressão de memória, pausas frequentes de GC e risco de circuit breaker. O JVM heap deve ser ~50% da RAM do servidor e no máximo ~31GB (limite de compressed oops). Para heap alto que não diminui, otimize as consultas ou adicione nós.","severity":"caution"},{"id":"shard-count-limits","group":"Capacidade","title":"Número de shards e limite de shards por nó","command":"GET _cluster/health?level=shards","expect":"active_shards e o número de shards por nó devem ser razoáveis. O limite superior padrão é cluster.max_shards_per_node = 1000 (por nó de dados); aproximar-se desse limite e ter milhares de shards pequenos no total (oversharding) cria pressão no master e desperdiça memória. A antiga regra \"~20 shards por GB de heap\" não se aplica ao 8.3+; a orientação atual é de 10-50GB por shard e planejamento de heap com base no número de campos (mappings) por nó. initializing_shards / relocating_shards não devem permanecer altos por muito tempo. Se houver shards demais, use shards maiores/em menor número ou rollover.","severity":"caution"},{"id":"http-connections","group":"Capacidade","title":"Número de conexões HTTP","command":"GET _nodes/stats/http","expect":"http.current_open deve estar dentro de limites razoáveis. Se http.total_opened crescer muito rápido, os clientes não estão usando pool de conexões e abrem uma nova conexão por requisição (ineficiente). Um current_open anormalmente alto aponta para vazamento de conexões ou possível esgotamento de recursos.","severity":"safe"},{"id":"thread-pool-rejections","group":"Desempenho","title":"Rejeições no thread pool e saturação de filas","command":"GET _cat/thread_pool?v&h=node_name,name,active,queue,rejected","expect":"A coluna rejected deve ser 0. Um valor de rejected crescente nos pools write/bulk e search mostra que o cluster está sobrecarregado e retornando HTTP 429 (es_rejected_execution_exception). Uma fila constantemente cheia é sinal de congestionamento. Aplique backoff no cliente, reduza o tamanho do batch ou adicione capacidade.","severity":"danger"},{"id":"query-cache-hit","group":"Desempenho","title":"Taxa de acerto do query cache","command":"GET _nodes/stats/indices/query_cache","expect":"A proporção hit_count / (hit_count + miss_count) deve ser alta para consultas de filtro repetidas. Uma taxa de acerto baixa com muitas evictions indica que o tamanho do cache é insuficiente ou que as consultas variam demais para serem armazenadas em cache. Usar filtros estáveis (filter context) aumenta a taxa de acerto.","severity":"safe"},{"id":"slowlog-config","group":"Desempenho","title":"Configurações do log de consultas lentas (slowlog)","command":"GET /_all/_settings?filter_path=**.search.slowlog,**.indexing.slowlog","expect":"Os limites de slowlog de busca e de indexação devem ser definidos nos índices importantes (ex.: index.search.slowlog.threshold.query.warn: 10s). Com o slowlog desabilitado, diagnosticar consultas lentas fica mais difícil. Habilite os limites e monitore os logs para identificar consultas caras (agregações amplas, wildcards, paginação profunda).","severity":"safe"},{"id":"hot-threads","group":"Desempenho","title":"Hot threads","command":"GET _nodes/hot_threads","expect":"Mostra as threads que mais consomem CPU. Usado em situações de CPU alta/lentidão para determinar qual operação (agregação pesada, merge, GC, script) é o gargalo. Se a mesma consulta/merge cara continuar aparecendo, otimize essa consulta ou a estratégia de indexação.","severity":"safe"},{"id":"fielddata-memory","group":"Desempenho","title":"Uso de memória de fielddata","command":"GET _cat/fielddata?v","expect":"O uso de memória de fielddata deve ser mantido baixo. Agregar/ordenar em campos text carrega fielddata na memória e aumenta o risco de erros de circuit breaker (Data too large) e OOM. Para campos com fielddata alto, passe a usar um subcampo keyword (doc_values).","severity":"caution"},{"id":"snapshot-status","group":"Backup e recuperação","title":"Snapshot repositories e status do snapshot mais recente","command":"GET _snapshot/_all","expect":"Deve haver pelo menos um snapshot repository definido. Depois de confirmar que os repositories existem, verifique o status dos snapshots mais recentes (junto com a verificação verify abaixo). Se não houver repository, o cluster não tem backup e os dados podem ser perdidos permanentemente em um estado RED. Configure o SLM (Snapshot Lifecycle Management) para snapshots automáticos regulares.","severity":"danger"},{"id":"snapshot-latest-state","group":"Backup e recuperação","title":"Status de sucesso dos snapshots mais recentes","command":"GET _snapshot/<repo>/_all?verbose=false","expect":"O state dos snapshots mais recentes deve ser 'SUCCESS'. 'PARTIAL' significa que alguns shards não puderam ser copiados, 'FAILED' significa que o backup falhou; ambos significam perda de dados no restore. A data do snapshot mais recente (end_time) não deve ser muito antiga (faça backups em uma frequência que atenda à sua meta de RPO).","severity":"danger"},{"id":"snapshot-repo-verify","group":"Backup e recuperação","title":"Verificação do snapshot repository","command":"POST _snapshot/<repo>/_verify","expect":"A verificação confirma que todos os nós conseguem acessar o repository (sistema de arquivos compartilhado, S3, HDFS etc.) e lista na resposta os nós que têm acesso. Se retornar erro, alguns nós não conseguem gravar no repositório de backup; nesse caso, os snapshots ficarão incompletos/falharão. Corrija o acesso ao repository e as credenciais.","severity":"caution"},{"id":"security-enabled","group":"Segurança","title":"A segurança (X-Pack security) está habilitada?","command":"GET _xpack/usage","expect":"security.enabled e security.available devem ser true. Com a segurança desabilitada, o cluster fica acessível sem autenticação; um cluster assim exposto à internet ou a uma rede não confiável é uma vulnerabilidade grave (vazamento/exclusão de dados). Autenticação, acesso baseado em roles e TLS devem estar habilitados.","severity":"danger"},{"id":"users-roles","group":"Segurança","title":"Usuários e roles","command":"GET _security/user","expect":"Revise os usuários definidos e as atribuições de roles. Certifique-se de que as contas nativas (elastic, kibana_system etc.) estejam protegidas com senhas fortes. Seguindo o princípio do menor privilégio, defina usuários separados com roles limitadas para cada aplicação; evite o uso desnecessariamente amplo da role superuser. Use GET _security/role para as roles.","severity":"caution"},{"id":"tls-transport-http","group":"Segurança","title":"Status de TLS / HTTPS (transport e HTTP)","command":"GET _nodes/settings?filter_path=**.xpack.security.transport.ssl.enabled,**.xpack.security.http.ssl.enabled","expect":"xpack.security.transport.ssl.enabled deve ser true (criptografia entre nós, obrigatória). O ideal é que http.ssl.enabled também seja true (HTTPS do cliente para o cluster). Com o TLS desabilitado, credenciais e dados trafegam pela rede em texto claro. Verifique também a validade dos certificados e o modo de verificação (verification_mode: certificate/full).","severity":"danger"},{"id":"unassigned-shards","group":"Replicação","title":"Shards não alocados e seus motivos","command":"GET _cat/shards?v&h=index,shard,prirep,state,unassigned.reason","expect":"Todos os shards devem ter state 'STARTED'. Shards no estado UNASSIGNED e seu unassigned.reason (NODE_LEFT, ALLOCATION_FAILED, DISK_THRESHOLD etc.) devem ser investigados. Um primário não alocado significa health RED; uma réplica não alocada, YELLOW. Use GET _cluster/allocation/explain para a causa raiz.","severity":"danger"},{"id":"recovery-active","group":"Replicação","title":"Recuperações de shards em andamento","command":"GET _cat/recovery?v&active_only=true","expect":"Normalmente não deve haver recuperação ativa (lista vazia). Uma recuperação temporária após adicionar/remover um nó ou após um failover é normal, mas recuperações que ficam travadas por muito tempo sem progresso (%progress não aumenta) apontam para um gargalo de rede/disco. Se o rebalanceamento (relocation) afetar a carga de trabalho, revise as configurações de throttling de recuperação (indices.recovery.max_bytes_per_sec).","severity":"caution"},{"id":"replica-count","group":"Replicação","title":"Número de réplicas por índice","command":"GET _cat/indices?v&h=index,health,pri,rep,docs.count","expect":"Em índices de produção, rep (number_of_replicas) deve ser pelo menos 1; em um índice com 0 réplicas, perder um nó significa perda permanente de dados. Porém, em um cluster com vários nós, o número de réplicas não deve exceder (número de nós de dados - 1); caso contrário, as réplicas extras não podem ser alocadas e o health fica YELLOW. Investigue os índices cuja coluna health não esteja green.","severity":"danger"}]},"recipes/oracle.json":{"engineId":"oracle","engine":"Oracle","order":1,"recipes":[{"id":"redo-switch","task":"Redo log switch (trocar o arquivo de log atual)","category":"Redo e archive","command":"ALTER SYSTEM SWITCH LOGFILE;","what":"Fecha o grupo de redo log atual e passa para o próximo; em modo archivelog, aciona o arquivamento.","when":"Para gerar um archive manualmente, forçar um log switch ou para testes.","caution":"Switches frequentes degradam o desempenho; se os arquivos de log forem pequenos demais, revise seu dimensionamento.","tags":["redo","switch","logfile","archive","archive","alter system"]},{"id":"redo-add-group","task":"Adicionar um novo grupo de redo log","category":"Redo e archive","command":"ALTER DATABASE ADD LOGFILE GROUP 4\n  ('/u01/oradata/ORCL/redo04a.log',\n   '/u02/oradata/ORCL/redo04b.log') SIZE 512M;","what":"Cria um novo grupo de redo log com o tamanho e os membros especificados (vários membros = espelhamento).","when":"Quando o throughput de redo for insuficiente ou quando você quiser aumentar o número de grupos.","caution":"Certifique-se de que o número do grupo não colida com grupos existentes; verifique com V$LOG.","tags":["redo","logfile","group","add","add","alter database"]},{"id":"redo-resize","task":"Redimensionar um grupo de redo log (drop + add)","category":"Redo e archive","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":"Um redo log não pode ser redimensionado diretamente; isso é feito removendo o grupo e adicionando-o novamente com o novo tamanho.","when":"Quando os arquivos de redo forem pequenos/grandes demais, para ajustar a frequência de checkpoints.","caution":"Apenas um grupo INACTIVE ou UNUSED pode ser removido; não remova o grupo CURRENT/ACTIVE. Pelo menos dois grupos devem sempre permanecer. REUSE reutiliza o arquivo existente.","tags":["redo","resize","size","drop","add","logfile","reuse"]},{"id":"enable-archivelog","task":"Colocar o banco de dados em modo ARCHIVELOG","category":"Redo e archive","command":"SHUTDOWN IMMEDIATE;\nSTARTUP MOUNT;\nALTER DATABASE ARCHIVELOG;\nALTER DATABASE OPEN;\n-- Verify:\nARCHIVE LOG LIST;","what":"Coloca o banco em modo archive log; os redo logs preenchidos são arquivados, o que possibilita hot backups e recuperação point-in-time.","when":"Para a estratégia de backup e recuperação de um banco de produção (obrigatório antes de RMAN, Data Guard).","caution":"Exige restart da instância; planeje o downtime. Certifique-se de que o destino de archive (FRA ou LOG_ARCHIVE_DEST) tenha espaço suficiente; se encher, o DB para. No RAC: pare todas as instâncias com srvctl stop database -d DB, abra uma única instância com STARTUP MOUNT, mude para ARCHIVELOG, desligue-a e inicie com srvctl start database -d DB (o 11gR2+ não exige cluster_database=false).","tags":["archivelog","archive","mode","mount","recovery","recovery"]},{"id":"fra-full-fix","task":"Corrigir FRA / destino de archive cheio","category":"Redo e archive","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":"Quando a Fast Recovery Area ou o destino de archive enche, o banco trava (ORA-00257). Corrige-se aumentando o espaço ou limpando archives.","when":"Erro do archiver ORA-00257, quando o DB para de aceitar novas transações.","caution":"Excluir archives que ainda não têm backup destrói a capacidade de recuperação. Faça primeiro um backup com RMAN e depois exclua. Não exclua com rm pelo SO; isso exige um CROSSCHECK do RMAN. Enquanto a FRA estiver cheia, faça backup dos archives para um destino fora da FRA (FORMAT '/backup/arc_%U'). Com Data Guard, não exclua archives ainda não enviados/aplicados no standby; caso contrário, forma-se um gap no standby. Use CONFIGURE ARCHIVELOG DELETION POLICY TO APPLIED ON ALL STANDBY.","tags":["fra","recovery area","ora-00257","archiver","archive","full","cleanup"]},{"id":"redo-status","task":"Ver o status dos redo logs","category":"Redo e archive","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":"Mostra o status dos grupos de redo log (CURRENT/ACTIVE/INACTIVE), seus tamanhos, arquivos membros e status de arquivamento.","when":"Ao revisar a configuração de redo ou para ver qual grupo está ativo antes de um redimensionamento.","caution":"Apenas consulta; sem risco.","tags":["redo","status","status","v$log","v$logfile","logfile"]},{"id":"asm-add-disk","task":"Adicionar discos a um diskgroup 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":"Adiciona novos discos ao diskgroup DATA e inicia um rebalance automático; a capacidade aumenta.","when":"Quando um diskgroup ASM começa a encher ou ao expandir o armazenamento.","caution":"Requer o privilégio SYSASM. Os tamanhos dos discos devem ser semelhantes. O rebalance gera carga de I/O; use um POWER baixo em horários de pico.","tags":["asm","diskgroup","add disk","add disk","rebalance","alter diskgroup"]},{"id":"asm-drop-disk","task":"Remover um disco de um diskgroup 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":"Remove o disco do diskgroup; seus extents são movidos para os discos restantes (rebalance). Ao concluir, o HDR_STATUS do disco passa a FORMER.","when":"Ao substituir um disco com falha, reduzir a capacidade ou migrar o armazenamento.","caution":"NÃO remova o disco fisicamente ANTES de o rebalance terminar; caso contrário, os dados são perdidos. Certifique-se de que os discos restantes tenham espaço livre suficiente.","tags":["asm","drop disk","remove disk","rebalance","v$asm_operation","alter diskgroup"]},{"id":"asm-rebalance-power","task":"Definir o POWER do rebalance do ASM","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":"Define o paralelismo/velocidade de um rebalance em andamento. Um POWER maior significa mais rapidez, mas mais I/O.","when":"Para acelerar um rebalance lento demais ou para desacelerar/parar um que esteja afetando a produção.","caution":"POWER 0 suspende o rebalance (a remoção de um disco não será concluída). Um valor alto afeta o I/O de produção.","tags":["asm","rebalance","power","power","diskgroup","tuning"]},{"id":"asm-diskgroup-space","task":"Ver o espaço livre dos diskgroups 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":"Mostra o espaço total, livre e utilizável (após a redundância) de cada diskgroup.","when":"Para planejamento de capacidade, quando o espaço estiver acabando, antes de decidir adicionar discos.","caution":"usable_file_mb considera a redundância; com redundância NORMAL/HIGH, essa coluna é o espaço realmente utilizável. Apenas consulta; sem risco.","tags":["asm","diskgroup","space","space","free","v$asm_diskgroup","capacity"]},{"id":"asm-monitor-rebalance","task":"Monitorar um rebalance do 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":"Mostra o progresso, o power e o tempo restante estimado das operações de rebalance/resync em andamento.","when":"Para acompanhar se o rebalance terminou após adicionar/remover discos.","caution":"Resultado vazio = nenhuma operação ativa (concluída). Apenas consulta; sem risco.","tags":["asm","rebalance","monitor","monitor","v$asm_operation","progress"]},{"id":"add-tablespace","task":"Adicionar uma nova tablespace","category":"Armazenamento","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":"Cria uma nova tablespace permanente na qual segmentos de tabelas/índices podem ser colocados.","when":"Ao alocar armazenamento separado para uma nova aplicação/schema.","caution":"Especifique MAXSIZE; caso contrário, o disco pode encher. No ASM, o nome do arquivo é gerado automaticamente.","tags":["tablespace","create","create","datafile","storage","storage","autoextend"]},{"id":"add-datafile","task":"Adicionar um datafile a um tablespace existente","category":"Armazenamento","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":"Aumenta a capacidade de um tablespace existente adicionando um novo datafile.","when":"Quando o tablespace está cheio e um único arquivo se aproxima do limite de smallfile (32G/64G).","caution":"Um tablespace smallfile tem um limite de blocos por arquivo; adicione um novo arquivo se necessário. Especifique MAXSIZE.","tags":["datafile","add","add","tablespace","alter tablespace","storage"]},{"id":"resize-datafile","task":"Redimensionar um datafile / definir autoextend","category":"Armazenamento","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":"Define um datafile com tamanho fixo ou configura seu comportamento de crescimento automático.","when":"Para recuperar espaço (shrink), pré-alocar espaço ou interromper um crescimento descontrolado.","caution":"A redução com RESIZE não pode ficar abaixo dos blocos usados no final do arquivo (ORA-03297). Mova os segmentos antes.","tags":["datafile","resize","size","autoextend","maxsize","alter database"]},{"id":"move-datafile-online","task":"Mover um datafile online","category":"Armazenamento","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":"Move um datafile para um novo local com o banco aberto (12c+); altera o armazenamento sem downtime.","when":"Ao trocar o disco/ponto de montagem, migrar para ASM ou mover para um armazenamento mais rápido.","caution":"Requer 12c ou posterior e Enterprise Edition. A movimentação gera I/O extra. Se você não usar KEEP, o arquivo antigo é excluído.","since":"Oracle 12c","note":"A movimentação online de datafiles (ALTER DATABASE MOVE DATAFILE) chegou com o Oracle 12c (12.1); antes disso, mover um datafile significava colocar o tablespace/datafile OFFLINE, copiá-lo no nível do SO e remapeá-lo com ALTER DATABASE RENAME FILE.","tags":["datafile","move","move","online","alter database move datafile","asm"]},{"id":"temp-tablespace","task":"Adicionar uma temp tablespace / alterar a padrão","category":"Armazenamento","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":"Fornece espaço temporário para operações de sort/hash/global temporary tables; você pode mudar a padrão para a nova tablespace.","when":"Para ORA-01652 (unable to extend temp segment), um gargalo no temp ou redimensionamento do temp.","caution":"Depois de alterar a padrão, não faça DROP do temp antigo imediatamente se estiver em uso; remova-o quando as sessões tiverem se esvaziado.","tags":["temp","tablespace","tempfile","ora-01652","default temporary","storage"]},{"id":"tablespace-space","task":"Consulta de espaço livre das tablespaces","category":"Armazenamento","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":"Mostra o espaço total e livre e o percentual de uso de cada tablespace (com base no espaço alocado atualmente, sem considerar o potencial de autoextend).","when":"Monitoramento de espaço, para descobrir qual tablespace precisa ser estendida.","caution":"Esta consulta se baseia no tamanho atual dos datafiles; eles podem crescer mais com autoextend. Para temp, use DBA_TEMP_FREE_SPACE. Apenas consulta; sem risco.","tags":["tablespace","space","space","free","dba_free_space","usage","storage"]},{"id":"alter-parameter","task":"Alterar um parâmetro (com SCOPE)","category":"Memória e parâmetros","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":"Altera um parâmetro de inicialização na instância em execução e/ou no spfile. SCOPE determina o comportamento.","when":"Para tuning, ajustes de capacidade e correções de erros que exigem alteração de parâmetro.","caution":"Parâmetros estáticos (processes, sga_max_size...) aceitam apenas SCOPE=SPFILE e exigem restart. Um valor errado pode impedir a instância de iniciar; para parâmetros críticos, faça antes um backup em pfile.","tags":["parameter","parameter","alter system","scope","spfile","tuning"]},{"id":"flush-pool","task":"Flush do shared pool / buffer cache","category":"Memória e parâmetros","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":"O flush do shared pool remove da memória todo o SQL/PL-SQL e as informações de dicionário em cache; o flush do buffer cache remove todos os blocos de dados.","when":"Para testar problemas de plano, após uma grande operação pontual ou para iniciar um benchmark consistente.","caution":"Cuidado EM PRODUÇÃO! Após um flush, todo SQL é analisado novamente (tempestade de hard parses) e os blocos são lidos do disco; segue-se uma queda temporária séria de desempenho.","tags":["flush","shared pool","buffer cache","memory","alter system","cache"]},{"id":"spfile-pfile","task":"Criar um pfile a partir do spfile e vice-versa","category":"Memória e parâmetros","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":"Converte entre o spfile binário e o pfile em texto; o pfile pode ser editado manualmente.","when":"Backup antes de uma alteração de parâmetro, reparo de um spfile corrompido, correção manual de um parâmetro estático.","caution":"Após CREATE SPFILE FROM PFILE, as alterações só têm efeito após um restart. Verifique o caminho antes de sobrescrever um spfile existente.","tags":["spfile","pfile","create pfile","create spfile","parameter","backup"]},{"id":"sga-pga-target","task":"Alterar os targets de SGA / PGA","category":"Memória e parâmetros","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":"Define os targets de memória SGA e PGA; o Oracle gerencia os componentes automaticamente (ASMM/AMM).","when":"Quando RAM é adicionada ao servidor, em um gargalo de memória ou pressão de memória.","caution":"sga_target não pode exceder sga_max_size. sga_max_size é estático e exige restart. Deixe RAM para o sistema operacional e outras instâncias; alocação excessiva causa swapping/OOM.","tags":["sga","pga","memory","memory","target","sga_target","pga_aggregate_target"]},{"id":"kill-session","task":"Encerrar uma sessão (kill session)","category":"Sessões e processos","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":"Encerra a sessão com o SID,SERIAL# informado; sua transação aberta sofre rollback.","when":"Para interromper uma sessão que mantém locks, executa uma consulta descontrolada ou vaza conexões.","caution":"Se houver uma transação aberta, o rollback pode demorar (termina rápido se pouco trabalho foi feito). Verifique antes com uma consulta para não encerrar o SID errado. O rollback de DML grande gera carga de I/O.","tags":["kill session","kill session","v$session","alter system","sid","serial"]},{"id":"long-running-queries","task":"Ver consultas / sessões de longa duração","category":"Sessões e processos","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":"Lista as sessões ativas rodando há mais de 60 segundos e o progresso de operações em batch de longa duração.","when":"Em reclamações de lentidão, para descobrir qual consulta está ocupando o sistema.","caution":"last_call_et é o tempo desde a última chamada; também pode ser grande para uma sessão ociosa, por isso o filtro status='ACTIVE' é importante. Apenas consulta; sem risco.","tags":["long running","long query","v$session","v$sql","v$session_longops","active"]},{"id":"find-blocking","task":"Encontrar a sessão bloqueadora","category":"Sessões e processos","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":"Lista os pares de sessões bloqueadora e em espera com o tempo de espera e o event.","when":"Para encontrar o culpado em problemas de lock como \"aplicação travada / espera enq: TX\".","caution":"Confirme com o responsável de negócio antes de encerrar o bloqueador; pode ser uma operação crítica. Apenas consulta; sem risco.","tags":["blocking","lock","lock","blocker","waiter","v$session","blocking_session"]},{"id":"gather-stats","task":"Coletar estatísticas (DBMS_STATS)","category":"Manutenção","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":"Coleta estatísticas de tabelas/índices para o otimizador; garante que planos de execução corretos sejam gerados.","when":"Após grandes DML/cargas, quando os planos regridem, após um novo índice/tabela.","caution":"Mudanças de estatísticas podem alterar planos de execução; em sistemas críticos, teste/compare primeiro com o AWR. O paralelismo DEGREE consome CPU. GATHER_DATABASE_STATS é pesado em horários de pico.","tags":["dbms_stats","statistics","statistics","gather","optimizer","maintenance"]},{"id":"rebuild-index-online","task":"Reconstruir um índice online","category":"Manutenção","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":"Reconstrói o índice sem bloquear DML (ONLINE); elimina a fragmentação e pode mudar o tablespace.","when":"Bloat/fragmentação de índice, mover um índice para outro tablespace, reparar um índice UNUSABLE.","caution":"ONLINE usa espaço temporário e I/O extras. PARALLEL persiste; redefina com NOPARALLEL após o rebuild, senão as consultas rodam em paralelo sem intenção. ONLINE não é suportado para índices bitmap em todas as versões. O rebuild ONLINE está disponível apenas no Enterprise Edition.","tags":["index","rebuild","online","rebuild","alter index","fragmentation","maintenance"]},{"id":"rman-full-backup","task":"Backup completo rápido com RMAN","category":"Manutenção","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":"Faz um backup completo compactado de todo o banco de dados e dos archive logs em paralelo por dois canais, faz backup do controlfile e remove backups obsoletos.","when":"Backup completo diário/semanal, para criar um ponto de recuperação.","caution":"COMPRESSED consome CPU. DELETE OBSOLETE remove backups antigos conforme a política de retenção; configure a política (CONFIGURE RETENTION POLICY) corretamente. ARCHIVELOG exige que o banco esteja em modo ARCHIVELOG. Garanta espaço suficiente no destino do backup.","tags":["rman","backup","backup","full","compressed","archivelog","maintenance"]},{"id":"controlfile-trace","task":"Fazer um backup do controlfile em trace","category":"Manutenção","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":"Gera o script SQL (trace) que recria o controlfile e/ou uma cópia binária dele.","when":"Após mudanças estruturais (adição de datafiles/redo), na preparação para recuperação de desastres ou para recriar o controlfile se todas as cópias forem perdidas.","caution":"Atualize o arquivo de trace sempre que a estrutura mudar; um script antigo cria a estrutura errada. REUSE sobrescreve um arquivo existente. Não há risco para o sistema, mas guarde o arquivo gerado com segurança.","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":"Verificar o status do banco de dados, das instâncias e dos serviços RAC com srvctl","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":"Mostra o estado em execução do banco de dados, de cada instância e de seus serviços conforme vistos pelo Clusterware (CRS), além da configuração registrada; -verbose adiciona o modo de abertura da instância.","when":"Como primeira verificação antes e depois de qualquer intervenção no RAC; durante uma indisponibilidade, para ver qual nó/instância foi afetado.","caution":"Somente leitura. Execute a partir do Oracle home do banco de dados (usuário oracle); um srvctl de um Grid home de versão diferente pode retornar resultados enganosos ou erros.","since":"12c","note":"As opções longas -db/-instance/-service são do 12c+; as opções curtas do 11g (-d, -i, -s) ainda funcionam no 19c, mas estão obsoletas.","tags":["rac","srvctl","status","instance","service","cluster","config"],"untested":true},{"id":"rac-srvctl-start-stop","task":"Parar / iniciar um banco de dados RAC ou uma única instância com srvctl (rolling)","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":"Para/inicia o banco de dados ou a instância selecionada de forma controlada pelo Clusterware; com -failover os serviços da instância parada migram para instâncias disponíveis, e -drain_timeout aguarda o esvaziamento das sessões.","when":"Para reinícios rolling (nó a nó) durante patches, manutenção do SO ou mudanças de parâmetros; para um desligamento completo planejado.","caution":"No RAC use srvctl em vez de SHUTDOWN no SQL*Plus; caso contrário o Clusterware não conhece o TARGET do recurso e pode reiniciar a instância. stop database derruba todas as instâncias = indisponibilidade total. Se os serviços não tiverem instâncias available definidas, -failover não consegue mover as conexões.","since":"12c","note":"-drain_timeout e -failover são do 12.2+. Use -stopoption abort apenas em emergências; a próxima inicialização exige instance recovery.","tags":["rac","srvctl","stop","start","rolling","drain","shutdown"],"untested":true},{"id":"rac-service-add","task":"Adicionar um serviço RAC com instâncias preferred/available (incluindo 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":"Define um serviço para aplicações que normalmente roda nas instâncias preferred e migra para uma instância available quando elas falham; com -role PRIMARY ele inicia apenas no papel de primário sob Data Guard.","when":"Para conectar aplicações a um serviço em vez de a uma instância, particionar cargas de trabalho entre nós e permitir failover transparente (drain/failover) durante manutenções planejadas.","caution":"As aplicações devem conectar com esse nome de serviço (via SCAN), não com um SID ou nome de instância. -failovertype TRANSACTION (Application Continuity) exige suporte da aplicação/driver; na dúvida, comece com -failovertype SELECT (TAF) ou NONE. Não use serviços SYS$ nem o serviço padrão com o nome do db_unique_name para aplicações.","since":"12c","note":"-pdb é do 12c+, -drain_timeout e -stopoption são do 12.2+. Altere com srvctl modify service; uma mudança permanente de preferred exige -modifyconfig.","tags":["rac","service","srvctl","preferred","available","taf","application continuity"],"untested":true},{"id":"rac-service-relocate","task":"Realocar um serviço RAC para outra instância","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":"Move um serviço em execução de uma instância/nó para outro; novas conexões vão para a instância de destino e as sessões existentes são deixadas para encerrar sozinhas durante o drain_timeout.","when":"Para esvaziar um nó antes de manutenção, devolver um serviço à sua instância preferred após um failover ou rebalancear a carga.","caution":"A realocação é temporária: não altera a configuração do serviço (preferred/available); quando a instância reinicia, o serviço volta para sua instância preferred. -force encerra as sessões existentes; se a aplicação não conseguir reconectar, os usuários percebem uma indisponibilidade.","since":"12c","note":"-drain_timeout e -wait são do 12.2+. A consulta SQL também roda em instância única; a parte do srvctl exige RAC.","tags":["rac","service","relocate","move","srvctl","drain","gv$session"],"untested":true},{"id":"rac-crsctl-stat-res","task":"Verificar o status dos recursos do cluster (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":"Lista em formato tabular, por nó, com TARGET/STATE, todos os recursos gerenciados pelo Clusterware (banco de dados, instância, listener, SCAN, VIP, ASM, disk group, rede).","when":"Após a inicialização de um nó, após patches e em toda investigação de indisponibilidade; para encontrar recursos OFFLINE, INTERMEDIATE ou UNKNOWN.","caution":"Somente leitura. Não gerencie recursos ora.* diretamente com crsctl start/stop/modify; use srvctl para recursos de banco de dados (o método suportado).","note":"O nome do recurso contém o db_unique_name em minúsculas (ora.orcl.db). A saída de -init fica totalmente visível apenas como root/grid.","tags":["rac","grid","crsctl","resource","resource","clusterware","status"],"untested":true},{"id":"rac-crsctl-check-cluster","task":"Verificar a saúde da pilha do cluster, a lista de nós e a versão do 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":"Mostra que os daemons Cluster Ready Services, Cluster Synchronization Services e Event Manager estão rodando em todos os nós, os membros do cluster e a versão ativa/de software do Clusterware.","when":"Na verificação de saúde matinal, após uma node eviction ou reboot e após um patch/upgrade rolling para confirmar que todos os nós estão no mesmo nível.","caution":"Somente leitura. Se activeversion -f mostrar \"ROLLING PATCH\" ou um nível de patch diferente, uma operação rolling está incompleta; conclua-a (crsctl stop rollingpatch / rootcrs -postpatch) antes de fazer novas mudanças.","since":"12c","note":"activeversion -f e softwareversion -all são do 12c+.","tags":["rac","grid","crsctl","olsnodes","health","cluster","version"],"untested":true},{"id":"rac-ocr-backup","task":"Verificar a integridade do OCR e fazer um backup do 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":"Mostra a integridade, os locais e os backups do Oracle Cluster Registry (o repositório de configuração do cluster); -manualbackup faz um backup físico imediato do OCR.","when":"Logo antes de mudanças de configuração do cluster, como adicionar/remover nós, patch/upgrade do Grid, mudanças de voting disk ou de rede (oifcfg).","caution":"ocrconfig -restore deve rodar com o CRS parado em todos os nós e em modo exclusivo; restaurar o backup errado pode deixar o cluster incapaz de iniciar, então faça isso com o Oracle Support. Os backups automáticos podem ficar por padrão no disco local de um único nó; mova o local para um disk group compartilhado.","note":"Executado como usuário grid, o ocrcheck pula a verificação de corrupção lógica (\"Logical corruption check bypassed\"). Backups para um disk group são do 12c+.","tags":["rac","ocr","ocrcheck","ocrconfig","backup","backup","grid"],"untested":true},{"id":"rac-votedisk-query","task":"Verificar voting disks e timeouts do 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":"Mostra o estado dos voting disks (voting files) usados para a associação ao cluster e os timeouts de heartbeat de rede/disco; replace votedisk move todos os voting files para o disk group de destino.","when":"Durante mudanças de storage, redesenho de disk groups ou investigação de node eviction; para confirmar que a maioria (quorum) dos voting disks está acessível.","caution":"Um nó que não acessa mais da metade dos voting disks reinicia a si mesmo. O disk group de destino precisa de failure groups suficientes (normal redundancy: 3, high: 5; use um quorum failgroup se necessário). Não altere misscount/disktimeout sem aprovação do Oracle Support.","note":"Padrões: misscount 30 s, disktimeout 200 s (Linux).","tags":["rac","voting disk","votedisk","css","misscount","quorum","eviction"],"untested":true},{"id":"rac-cluvfy-checks","task":"Executar verificações pré/pós com o 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":"Valida conectividade de rede, sincronização de relógio, OCR, ASM, equivalência de usuários e pré-requisitos do SO em todos os nós; reporta problemas com correções sugeridas.","when":"Antes e depois da instalação do Grid, da adição de nós e de upgrades; como validação de base para problemas de cluster sem explicação.","caution":"Somente leitura, mas conecta a todos os nós via ssh; o usuário grid precisa de equivalência ssh. Não execute os scripts -fixup (root) sem revisá-los; eles alteram parâmetros do SO.","note":"Para uma varredura mais ampla de boas práticas use orachk/exachk do AHF. Baixar o cluvfy mais recente do My Oracle Support oferece mais verificações.","tags":["rac","cluvfy","check","verification","precheck","grid","orachk"],"untested":true},{"id":"rac-node-eviction-diag","task":"Diagnosticar a causa de uma node eviction / reboot inesperado de nó","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":"Segue em ordem a cadeia de node eviction: mensagens CRS-16xx no alert log do CRS, perdas de heartbeat no ocssd.trc, métricas do SO do CHM e os logs de todos os nós coletados com o TFA.","when":"Quando um nó reinicia inesperadamente ou é removido do cluster, para análise de causa raiz (RCA) e um SR no Oracle Support.","caution":"Colete logs de todos os nós cobrindo o horário do evento; os arquivos de trace rotacionam e evidências podem se perder. Verifique se os fusos horários são iguais entre os nós (CTSS/NTP). Não aplique \"correções\" como aumentar o misscount antes de coletar as evidências.","note":"Causas típicas: queda/perda de pacotes no interconnect privado, latência de I/O do voting disk, esgotamento de CPU/memória (OOM, swap), saltos de relógio. O caminho segue o layout ADR do 12c+; no 11g fica em $GRID_HOME/log/<host>/.","tags":["rac","eviction","reboot","ocssd","tfactl","oclumon","rca"],"untested":true},{"id":"rac-gv-cluster-waits","task":"Analisar wait events de todo o cluster (gc waits) por instância com GV$","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":"Usa as views GV$ para mostrar, em uma única consulta, as esperas da classe Cluster (gc cr/current block 2-way/3-way, gc buffer busy, gc cr request) e sua latência média em todas as instâncias.","when":"Quando usuários relatam lentidão no RAC, para saber se o problema vem do interconnect/global cache e em qual instância ele se concentra.","caution":"gv$active_session_history exige a licença do Diagnostics Pack. Se avg_ms passar de alguns ms, verifique primeiro o interconnect (MTU, perda de pacotes, netstat -s) e a CPU do LMS; gc buffer busy normalmente aponta para um hot block da aplicação (sequence, índice crescendo à direita).","note":"Também roda em instância única (retorna inst_id = 1).","tags":["rac","gv$","gc","wait","wait event","interconnect","global cache"]},{"id":"asm-asmcmd-lsdg-du","task":"Mostrar o uso de disk groups, discos e diretórios com 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":"Mostra pela linha de comando a redundância, o espaço total/livre e o Usable_file_MB dos disk groups, o estado dos discos e o espaço que um banco de dados ocupa no ASM.","when":"Para verificações de capacidade, identificar discos candidatos antes de adicionar discos e descobrir qual banco consome espaço quando dispara um alerta de \"disk group full\".","caution":"Somente leitura. Se o Usable_file_MB no lsdg for negativo, o disk group não consegue restaurar a redundância após perder um disco/failgroup; libere espaço ou adicione discos imediatamente. du retorna dois valores: Used_MB e Mirror_used_MB (uso espelhado).","note":"Para o equivalente em SQL veja as receitas asm-diskgroup-space e asm-disk-health.","tags":["asm","asmcmd","lsdg","lsdsk","du","space","disk group"],"untested":true},{"id":"asm-disk-health","task":"Verificar o estado dos discos ASM, os contadores de erro e os discos candidatos com SQL","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":"Lista o header_status de cada disco (MEMBER, CANDIDATE, PROVISIONED, FORMER), o estado de mount/mode, o failgroup e os contadores de erros de leitura/escrita; o número de discos offline por disk group e os clientes ASM.","when":"Antes de adicionar discos, para verificar se um novo LUN aparece como CANDIDATE/PROVISIONED; em uma falha de disco, para ver qual disco está OFFLINE e eventuais erros de I/O.","caution":"Somente leitura. v$asm_disk executa a descoberta de discos a cada chamada e é lento em sistemas com muitos discos; para monitoramento frequente use v$asm_disk_stat (sem descoberta, não mostra discos novos). Nunca adicione um disco com header_status MEMBER a outro disk group com FORCE; isso destrói os dados existentes.","note":"Não retorna linhas sem ASM; uma saída significativa exige uma instância ASM.","tags":["asm","v$asm_disk","disk","header_status","error","candidate","failgroup"]},{"id":"asm-diskgroup-attributes","task":"Ver e alterar atributos de disk groups 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":"Mostra e altera os níveis de compatibilidade do disk group (compatible.asm/rdbms), o tamanho da AU e por quanto tempo um disco com falha temporária é mantido antes de ser removido (disk_repair_time).","when":"Após um upgrade do Grid, para habilitar novos recursos do ASM (flex disk groups, limites de arquivo maiores) ou para estender o disk_repair_time durante uma manutenção planejada de storage.","caution":"compatible.asm e compatible.rdbms NÃO PODEM SER REDUZIDOS DEPOIS DE AUMENTADOS. Se compatible.rdbms for maior que o COMPATIBLE do banco mais antigo que usa esse disk group, esse banco não consegue montá-lo. Aumente primeiro compatible.asm, depois compatible.rdbms. au_size só pode ser definido na criação do disk group.","note":"Sem ASM a consulta não retorna linhas. O disk_repair_time padrão é 12h.","tags":["asm","attribute","compatible","disk_repair_time","disk group","au_size","v$asm_attribute"],"untested":true},{"id":"dg-show-configuration","task":"Mostrar a configuração do Data Guard broker e o status dos bancos (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":"Mostra o status geral da configuração do broker (SUCCESS/WARNING/ERROR), o modo de proteção, o papel de cada banco, o lag de transporte/aplicação e as inconsistências entre o broker e o spfile.","when":"Antes e depois de toda operação de Data Guard (switchover, failover, mudança de parâmetro); na verificação diária de saúde.","caution":"Somente leitura. Com o broker habilitado, não altere parâmetros do Data Guard como log_archive_dest_n ou log_archive_config via SQL; o broker os sobrescreve com seus próprios valores. Faça as mudanças com EDIT DATABASE ... SET PROPERTY e, no 19c+, use EDIT DATABASE ... SET PARAMETER para parâmetros de inicialização.","note":"StatusReport lista os erros ORA- por banco; é a forma mais rápida de achar a causa de um status WARNING. InconsistentProperties está obsoleto no 19c e sempre retorna vazio; use InconsistentLogXptProps para inconsistências de redo transport.","tags":["data guard","dgmgrl","broker","configuration","standby","status","lag"],"untested":true},{"id":"dg-readiness-sql","task":"Verificar o papel primary/standby e a prontidão para switchover com 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":"Mostra o papel do banco, o modo de abertura, o modo de proteção, o switchover_status (TO STANDBY / TO PRIMARY / SESSIONS ACTIVE / NOT ALLOWED), o estado de FORCE LOGGING e de flashback, além de erros e gaps dos destinos de redo.","when":"Como pré-verificação antes de switchover/failover, após criar um novo standby e para monitoramento básico onde o broker não é usado.","caution":"Somente leitura. Se FORCE_LOGGING=NO, operações NOLOGGING deixam blocos corrompidos no standby; ALTER DATABASE FORCE LOGGING deve estar habilitado em um primário Data Guard. Se FLASHBACK_ON=NO, o antigo primário não pode ser reinstaurado após um failover e precisa ser recriado.","note":"Também roda no primário; v$archive_gap só faz sentido em um physical standby.","tags":["data guard","v$database","switchover_status","force logging","gap","role","standby"]},{"id":"dg-lag-apply-rate","task":"Medir o lag de transporte/aplicação, a taxa de aplicação e os processos do Data Guard no standby","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":"Mostra quanto o standby está atrás do primário (transport lag = redo ainda não recebido, apply lag = redo ainda não aplicado), quando o acúmulo será aplicado, a taxa de aplicação e qual processo trabalha em qual sequence.","when":"Para monitoramento de RPO/RTO e, em um alerta de lag, para saber se o problema está na rede (transporte) ou em I/O/CPU do standby (aplicação).","caution":"Somente leitura. Se datum_time estiver antigo (muito atrás de time_computed), o standby não está recebendo dados do primário e o valor do lag não é confiável. Verifique se DelayMins está definido; um atraso intencional parece apply lag.","since":"12c","note":"v$dataguard_process é do 12.2+. Sem standby, v$dataguard_stats não retorna linhas.","tags":["data guard","lag","lag","apply","transport","v$dataguard_stats","rpo"]},{"id":"dg-validate-database","task":"Validar o standby com o broker antes de switchover/failover (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":"Verifica se o standby está pronto para uma troca de papel (\"Ready for Switchover / Failover: Yes\"), o número/tamanho dos standby redo logs, o estado de flashback e de aplicação, diferenças de spfile e os serviços estáticos de que o broker precisa para reiniciar instâncias.","when":"Como passo obrigatório antes de todo switchover planejado; após criar um novo standby e após mudanças de rede/listener.","caution":"Somente leitura. Se aparecer \"Ready for Switchover: No\" ou um aviso de standby redo log, não prossiga com o switchover. Um erro de static connect identifier significa que o broker não consegue iniciar a instância durante um switchover, o que obriga a uma intervenção manual.","since":"12c","note":"VALIDATE DATABASE é do 12.1+, a opção SPFILE é do 12.2+, NETWORK CONFIGURATION e STATIC CONNECT IDENTIFIER são do 18c+.","tags":["data guard","dgmgrl","validate","validate","switchover","standby redo log","broker"],"untested":true},{"id":"dg-switchover","task":"Executar um switchover planejado (DGMGRL, troca de papel sem perda de dados)","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":"Troca os papéis do primário e do standby de forma controlada: todo o redo do primário é enviado e aplicado no standby, o antigo primário reinicia como standby e o redo apply começa automaticamente.","when":"Para manutenção planejada no site primário (SO, hardware, rolling upgrade), simulações de DR ou mudanças de data center.","caution":"O primário fica brevemente indisponível; as conexões das aplicações devem ser roteadas para o novo primário por serviços definidos com -role PRIMARY e FAN/TAF/AC. Transações longas e apply lag alto alongam o switchover; leve o lag para perto de zero antes. No RAC o broker gerencia as instâncias sozinho; não intervenha com srvctl.","since":"12c","note":"No 12.1+ o broker executa todos os passos com um único comando; sem o broker, o 11g usava ALTER DATABASE COMMIT TO SWITCHOVER em SQL (12c+: ALTER DATABASE SWITCHOVER TO <db> VERIFY).","tags":["data guard","switchover","dgmgrl","role change","planned","standby","primary"],"untested":true},{"id":"dg-failover","task":"Executar um failover após perder o primário (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":"Promove o standby ao papel de primário quando o primário está indisponível; um failover completo aplica antes todo o redo recebido, IMMEDIATE pula a aplicação.","when":"Quando o site primário, o storage ou o banco foram perdidos sem possibilidade de recuperação e o RTO não permite esperar por um switchover.","caution":"Esta troca de papel é irreversível. Antes, confirme que o primário está REALMENTE fora; se o antigo primário continuar aberto e a aplicação seguir gravando nele, ocorre split-brain e dados divergentes (desligue/isole o antigo primário). No modo MaxPerformance você perde tantos dados quanto o transport lag. Depois, revise todos os standbys e a estratégia de backup do novo primário.","note":"Para recuperar o antigo primário veja a receita dg-reinstate-database (exige flashback).","tags":["data guard","failover","dgmgrl","disaster","disaster recovery","data loss","split-brain"],"untested":true},{"id":"dg-reinstate-database","task":"Recuperar o antigo primário como standby após um failover (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":"Retorna o antigo primário a um ponto anterior ao SCN do failover com flashback database, converte-o em physical standby e começa a receber redo do novo primário; não é preciso recriar o standby do zero.","when":"Após um failover, assim que o servidor/storage do antigo primário voltar a ficar acessível; após um failover automático do FSFO (o observer normalmente faz o reinstate sozinho).","caution":"O flashback precisa ter sido habilitado no antigo primário ANTES do failover e os flashback logs devem cobrir o SCN do failover (db_flashback_retention_target, tamanho da FRA); caso contrário o reinstate falha e o standby precisa ser recriado com RMAN duplicate. Os dados gravados no antigo primário após o failover são perdidos definitivamente.","note":"Verificação de pré-requisito: a coluna flashback_on na receita dg-readiness-sql.","tags":["data guard","reinstate","flashback","failover","old primary","standby","dgmgrl"],"untested":true},{"id":"dg-apply-transport-state","task":"Parar / iniciar o redo apply ou o redo transport com o broker; configurar aplicação com atraso","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":"Para/inicia de forma persistente, via broker, o redo apply (MRP) no standby ou o envio de redo no primário; DelayMins retém o redo pelo tempo indicado antes de aplicá-lo.","when":"Para manutenção ou backups no standby, indisponibilidades de rede planejadas, controle do transporte durante grandes cargas em massa no primário ou para criar um standby com atraso contra exclusões acidentais.","caution":"Com o broker habilitado, não use ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL em SQL; o broker restaura o estado. Durante APPLY-OFF o apply lag e o tempo de failover (RTO) crescem; durante TRANSPORT-OFF os dados gerados no primário ficam desprotegidos (RPO). Se o FSFO estiver habilitado, essas operações podem impedir um failover.","note":"Com DelayMins > 0, o redo é aplicado a partir dos archived logs após o atraso, em vez de via real-time apply; o standby continua recebendo redo durante o atraso.","tags":["data guard","apply","transport","mrp","delaymins","stop","dgmgrl"],"untested":true},{"id":"dg-fsfo-observer","task":"Habilitar o Fast-Start Failover (FSFO) e iniciar o 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":"Permite que o observer faça failover automático para o standby após o limite quando o primário está inacessível e faça o reinstate automático do antigo primário quando ele voltar.","when":"Em sistemas críticos cuja meta de RTO é de minutos, sem esperar intervenção humana.","caution":"O observer não deve rodar no mesmo servidor/data center do primário ou do standby; caso contrário o FSFO falha na perda de um site ou pode tomar a decisão errada durante uma partição de rede. O flashback deve estar habilitado nos dois bancos. Um limite baixo demais transforma pequenas oscilações de rede em failovers desnecessários. Para manutenção planejada, execute DISABLE FAST_START FAILOVER ou leve o observer em conta antes de desligar o primário.","since":"12c","note":"FASTSYNC é do 12.2+, IN BACKGROUND e múltiplos observers (SHOW OBSERVER) são do 12.2+. IN BACKGROUND exige credenciais em um Oracle wallet (mkstore).","tags":["data guard","fsfo","fast-start failover","observer","automatic failover","maxavailability","dgmgrl"],"untested":true},{"id":"dg-snapshot-standby","task":"Converter um physical standby em snapshot standby e voltar (ambiente de teste)","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":"Cria um guaranteed restore point automático no standby e o abre em leitura e escrita; ao converter de volta, faz flashback até esse ponto e aplica o redo acumulado do primário.","when":"Para ensaiar um upgrade, testar uma versão da aplicação ou executar Real Application Testing (DB Replay) com dados de produção sem criar uma cópia separada.","caution":"Enquanto for snapshot standby nenhum redo é aplicado: o RPO é preservado, mas o tempo de failover (RTO) cresce com o redo acumulado e ele não pode ser alvo do FSFO. Os flashback logs podem encher a FRA; monitore o espaço da FRA. As mudanças feitas no snapshot são descartadas definitivamente ao converter de volta.","note":"Equivalente em SQL: ALTER DATABASE CONVERT TO SNAPSHOT STANDBY / CONVERT TO PHYSICAL STANDBY (sem o broker).","tags":["data guard","snapshot standby","test","restore point","flashback","convert","dgmgrl"],"untested":true},{"id":"rman-catalog-create","task":"Criar um recovery catalog do RMAN e registrar o banco de dados","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":"Cria um recovery catalog que armazena os metadados de backup em um schema central, independente da retenção do controlfile (control_file_record_keep_time), e registra o banco de destino.","when":"Para manter o histórico de backup de vários bancos em um só lugar, usar backups do primário/standby de forma intercambiável no Data Guard e para backups de longo prazo (KEEP) e stored scripts.","caution":"O banco do catálogo deve estar em um servidor diferente dos bancos que protege e também precisa de backup. A versão do schema do catálogo não pode ser inferior à do cliente RMAN mais recente em uso; um cliente mais novo exige UPGRADE CATALOG. No Data Guard registre apenas o primário; os standbys são definidos pelo DB_UNIQUE_NAME com CONFIGURE DB_UNIQUE_NAME ... CONNECT IDENTIFIER.","note":"Mantenha o schema do catálogo em um banco separado; se ele ficar junto com o alvo, um desastre leva o catálogo junto.","tags":["rman","catalog","catalog","recovery catalog","register","backup","backup"],"untested":true},{"id":"rman-duplicate-standby","task":"Criar um physical standby a partir do banco ativo com 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":"Copia os datafiles do primário pela rede para o servidor standby (sem arquivos de backup intermediários), cria o spfile adaptado para o standby e aplica os archivelogs disponíveis com DORECOVER.","when":"Ao criar um novo standby Data Guard ou recriar um standby que não pode ser reinstaurado.","caution":"Gera carga de rede e de I/O no primário; não execute em horários de pico ou limite o número de canais. NOFILENAMECHECK só é seguro quando o standby está em um servidor SEPARADO; no mesmo servidor pode sobrescrever os arquivos do primário. Adicione standby redo logs (mesmo tamanho do online redo do primário, um grupo extra por thread) antes ou depois e então configure o broker.","since":"12c","note":"Active duplicate com USING [COMPRESSED] BACKUPSET e SECTION SIZE é do 12c+; o 11g usa image copies. Se usar um file system em vez de ASM, defina 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":"Validar e limpar registros de backup do 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 verifica se os backups dos registros do RMAN ainda existem em disco/fita; DELETE EXPIRED remove os registros dos arquivos ausentes e DELETE OBSOLETE apaga dos registros e do disco os backups que a política de retenção não exige mais.","when":"Quando arquivos de backup foram apagados/movidos no nível do SO, quando a FRA enche e como parte da rotina regular de manutenção de backup.","caution":"DELETE OBSOLETE apaga arquivos fisicamente; confira antes a lista com REPORT OBSOLETE e garanta que a política de retenção (RECOVERY WINDOW / REDUNDANCY) é a esperada. Se você rodar CROSSCHECK enquanto a fita/media manager estiver temporariamente inacessível, backups válidos aparecem como EXPIRED; não execute DELETE EXPIRED nesse momento.","note":"No Data Guard, use CONFIGURE ARCHIVELOG DELETION POLICY TO APPLIED ON ALL STANDBY para a exclusão de archivelogs.","tags":["rman","crosscheck","expired","obsolete","cleanup","retention","backup"],"untested":true},{"id":"rman-validate","task":"Validar o banco de dados e os backups contra corrupção (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":"Lê datafiles e backup sets para detectar corrupção física e (com CHECK LOGICAL) lógica de blocos, registrando os achados em v$database_block_corruption. A consulta SQL mostra a qual tabela/índice pertence o bloco corrompido.","when":"Após erros de corrupção como ORA-01578/ORA-08103, após problemas de storage e como verificação regular (semanal) de integridade; para provar que os backups são realmente restauráveis.","caution":"Faz uma leitura completa; em bancos grandes gera I/O pesado, então execute fora dos horários de pico. A consulta em dba_extents pode ser lenta em bancos grandes. Se o bloco corrompido estiver em espaço temporário (TEMP) ou livre, nenhum objeto correspondente é retornado.","since":"11g","note":"As consultas não retornam linhas quando não há corrupção. VALIDATE com SECTION SIZE é do 11g+.","tags":["rman","validate","corruption","corruption","check logical","block","ora-01578"],"untested":true},{"id":"rman-restore-preview","task":"Ver quais backups um restore usaria e validá-los (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 informa, a partir do catálogo/controlfile, quais backup sets/cópias e qual intervalo de archivelogs um restore usaria; VALIDATE de fato lê esses backups e verifica que não há corrupção nem arquivo ausente.","when":"Para planejamento antes de um restore real, para provar que a estratégia de backup atende à meta de RPO e como teste periódico de restore.","caution":"PREVIEW olha apenas os registros; é enganoso se arquivos tiverem sido apagados, então rode CROSSCHECK antes ou use RESTORE ... VALIDATE. VALIDATE lê o backup inteiro; pode demorar via fita/rede. Faça a data depender da máscara do TO_DATE, não das configurações NLS da sessão.","note":"PREVIEW RECALL também pode solicitar backups que precisam ser recuperados da fita (exige suporte do media manager).","tags":["rman","restore","preview","validate","restore test","backup","rpo"],"untested":true},{"id":"rman-block-media-recovery","task":"Reparar blocos corrompidos online (block media recovery, 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":"Restaura apenas os blocos corrompidos a partir de um backup (ou de flashback logs / de um standby Active Data Guard) e os avança com redo; o datafile e o tablespace permanecem online, e a aplicação só recebe erros ao acessar esses blocos.","when":"Quando surge corrupção isolada de blocos com ORA-01578 / ORA-01110; quando restaurar o datafile inteiro causaria indisponibilidade desnecessária.","caution":"Exige um backup íntegro que contenha o bloco e todos os archivelogs desde então até agora; a corrupção causada por uma operação NOLOGGING (ORA-26040) não pode ser reparada assim, o objeto precisa ser recriado. É um recurso do Enterprise Edition. Se você não encontrar a origem da corrupção (storage, HBA, firmware), ela vai se repetir.","note":"Com Active Data Guard, o block media recovery automático do 11.2+ repara blocos corrompidos a partir do standby automaticamente.","tags":["rman","block recovery","corrupt block","corruption","ora-01578","recover","repair"],"untested":true},{"id":"rman-tspitr","task":"Retornar um tablespace a um ponto no passado (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":"O RMAN recupera SYSTEM/UNDO/SYSAUX e o tablespace de destino até o horário solicitado em uma instância auxiliar temporária e depois o reconecta ao banco de destino com transportable tablespace; o restante do banco permanece atual.","when":"Quando um job batch com defeito ou um DROP/TRUNCATE errado danificou dados em apenas um tablespace (ou em um conjunto autocontido de tablespaces) e as opções de flashback não bastam.","caution":"TODAS as mudanças feitas nesse tablespace e todos os objetos criados após o horário de destino são perdidos. O conjunto de tablespaces deve ser autocontido (nenhum índice/tabela, partição, LOB ou FK em outro tablespace). Não pode ser usado para tablespaces que contenham objetos SYSTEM, UNDO ou SYS. Após o TSPITR, os backups anteriores desse tablespace ficam inutilizáveis; faça um backup imediatamente. AUXILIARY DESTINATION precisa de espaço livre para SYSTEM+SYSAUX+UNDO+o tablespace de destino.","note":"Para uma única tabela, rman-recover-table é menos destrutivo.","tags":["rman","tspitr","tablespace","pitr","point-in-time","auxiliary","rollback"],"untested":true},{"id":"rman-recover-table","task":"Recuperar uma única tabela a um ponto no passado a partir de um backup 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":"O RMAN recupera uma instância auxiliar automática até o horário solicitado, exporta a tabela (ou partição) com Data Pump e a importa no banco de destino com outro nome usando REMAP; a instância auxiliar é removida em seguida.","when":"Para recuperar os dados de uma única tabela apagados/alterados por engano ou removida com PURGE, além do que a retenção de undo do Flashback Table/Query permite.","caution":"AUXILIARY DESTINATION precisa de espaço livre para SYSTEM, SYSAUX, UNDO e o tablespace da tabela; a operação pode levar horas. Sem REMAP TABLE a operação falha se existir uma tabela com o mesmo nome; use sempre REMAP ou NOTABLEIMPORT para não sobrescrever a original. Tabelas nos schemas SYS/SYSTEM e nos tablespaces SYSTEM/SYSAUX não podem ser recuperadas assim. Exige Enterprise Edition.","since":"12c","note":"Necessário: um backup completo mais archivelogs cobrindo o horário de destino. Para uma partição: 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":"Criar um novo PDB a partir do PDB$SEED","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":"Cria um novo pluggable database vazio a partir do template seed; define o usuário admin local, o tablespace padrão e o limite total de tamanho no mesmo comando.","when":"Ao abrir um banco isolado para uma nova aplicação/schema; ao preparar ambientes de teste e desenvolvimento.","caution":"O novo PDB sobe em MOUNTED; precisa de OPEN e SAVE STATE (para continuar aberto após um restart do CDB). Caminhos FILE_NAME_CONVERT errados gravam os arquivos no diretório errado; sem OMF o caminho completo do arquivo é obrigatório para DATAFILE (ORA-02236). Licenciamento: no 19c EE, 3 PDBs de usuário por CDB podem ser usados sem a opção Multitenant.","since":"12c","note":"No RAC, adicione um serviço de aplicação ao PDB com srvctl add service -pdb.","tags":["multitenant","pdb","create","create pluggable database","seed","cdb","pdb$seed"]},{"id":"pdb-clone-local","task":"Clonar um PDB no mesmo CDB (local / hot clone)","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":"Cria um novo PDB no mesmo CDB copiando os datafiles do PDB de origem; com local undo e ARCHIVELOG pode rodar com a origem aberta em leitura e escrita (hot clone).","when":"Para criar uma cópia de teste/desenvolvimento de um PDB de produção, ensaiar um upgrade ou patch ou fazer uma cópia rápida antes de uma mudança arriscada.","caution":"A cópia gera I/O extra na origem e precisa no destino de tanto espaço quanto a origem. No modo shared undo ou em NOARCHIVELOG a origem deve estar READ ONLY (documentação do 19c). O clone contém dados de produção: verifique mascaramento, DB links, jobs (DBMS_SCHEDULER) e conexões com sistemas externos antes de abri-lo.","since":"12c","note":"Um hot clone com a origem em leitura e escrita exige local undo + ARCHIVELOG no 19c. Para uma cópia thin rápida use SNAPSHOT COPY (exige storage adequado).","tags":["multitenant","pdb","clone","clone","hot clone","copy","local undo"]},{"id":"pdb-clone-remote","task":"Clonar um PDB de outro CDB via DB link (remote clone)","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":"Copia um PDB do CDB de origem para o CDB de destino pela rede através de um DB link; não precisa de arquivos intermediários nem de unplug.","when":"Para mover um PDB para outro servidor/CDB, criar uma cópia de teste da produção em um servidor separado ou migrar para um CDB de versão mais nova.","caution":"Os CDBs de origem e destino devem ser compatíveis em endianness, character set (ou destino AL32UTF8) e opções; um PDB clonado para uma versão mais nova abre RESTRICTED no início e precisa de datapatch/upgrade. Remova o DB link e o common user ao final do clone. Hot clone exige local undo + ARCHIVELOG na origem.","since":"12c","note":"Para movê-lo (a origem é removida) use a opção RELOCATE do 12.2+: CREATE PLUGGABLE DATABASE <pdb> FROM <pdb>@clone_link RELOCATE.","tags":["multitenant","pdb","remote clone","db link","clone","migration","relocate"]},{"id":"pdb-unplug-plug","task":"Fazer unplug de um PDB e plug em outro (ou no mesmo) 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":"Desconecta o PDB do CDB e grava seus metadados em um manifesto XML (ou em um único arquivo .pdb junto com os datafiles); após uma verificação de compatibilidade, conecta-o de volta ao CDB de destino com os mesmos arquivos.","when":"Para mover um PDB para um CDB de versão mais nova no mesmo servidor (upgrade via unplug/plug), para consolidação de CDBs ou para migrações em que clonar pela rede não é possível.","caution":"Após o unplug, o PDB fica indisponível no CDB de origem (downtime). Arquivos conectados com NOCOPY passam a pertencer ao CDB de destino; faça antes uma cópia em nível de arquivo ou um backup RMAN para poder voltar em caso de falha. Enquanto as violações do tipo ERROR não forem resolvidas, o PDB abre RESTRICTED. Ao reconectar no mesmo CDB, omitir AS CLONE pode causar conflito de GUID.","since":"12c","note":"Um arquivo .pdb (12.2+) inclui os datafiles e é movido como um único arquivo; no método XML os datafiles são copiados separadamente.","tags":["multitenant","pdb","unplug","plug","migration","xml manifest","check_plug_compatibility"]},{"id":"pdb-open-save-state","task":"Abrir PDBs e mantê-los abertos após restarts do 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":"Abre os PDBs em READ WRITE e salva o estado de abertura atual para que o PDB abra automaticamente no mesmo modo quando o CDB reiniciar.","when":"Após criar, conectar ou clonar um PDB; quando você percebe que os PDBs ficam MOUNTED após um restart do CDB.","caution":"SAVE STATE registra o estado no momento do comando: se você o executar com o PDB fechado, o estado \"fechado\" é registrado (ou o registro é removido). No RAC o estado é por instância; com gerenciamento baseado em serviços (serviços de PDB via srvctl), a inicialização pelo Clusterware é preferível ao SAVE STATE. Em um standby Data Guard o modo de abertura depende do papel.","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":"Definir limites de CPU, memória, I/O e storage por PDB","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":"Limita, por meio de parâmetros em nível de PDB, quanto de CPU, SGA/PGA, IOPS/MBPS e storage total um PDB pode usar do CDB; impede que PDBs \"vizinhos barulhentos\" afetem os demais.","when":"Em CDBs consolidados, ao rodar aplicações com SLAs diferentes no mesmo CDB ou quando se vê um PDB esgotar o servidor inteiro.","caution":"O sga_target do PDB deve ser menor que o sga_target do CDB; valores baixos demais causam ORA-04031 e problemas de desempenho. A soma de sga_min_size não deve reservar toda a SGA do CDB. Para que cpu_count em um PDB tenha efeito, um plano do resource manager deve estar ativo no CDB. Ao atingir MAXSIZE o PDB recebe ORA-65114.","since":"12c","note":"O 23ai exige sga_min_size abaixo de 20% de sga_target (ORA-56746), no 19c o limite é 50%. MAX_IOPS/MAX_MBPS são do 12.2+, os parâmetros de memória de PDB são do 12.2+.","tags":["multitenant","pdb","resource","resource","cpu_count","sga_target","maxsize"]},{"id":"pdb-container-context","task":"Confirmar em qual container você está e consultar todos os PDBs a partir do root (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":"Mostra o container ao qual a sessão está conectada; a partir do root, as views CDB_ e a cláusula CONTAINERS() coletam informações do dicionário de todos os PDBs abertos em uma única consulta.","when":"Para garantir que você está no container certo antes de uma DDL/mudança de parâmetro e para montar um inventário de espaço, usuários e objetos em todos os PDBs.","caution":"Somente leitura. Não crie por engano objetos de aplicação ou usuários locais no root (CDB$ROOT); ALTER SYSTEM no root afeta todo o CDB. As views CDB_ e CONTAINERS() retornam apenas PDBs abertos; PDBs MOUNTED não aparecem no resultado.","since":"12c","note":"Para trocar de container: ALTER SESSION SET CONTAINER = <pdb>; (veja rosetta \"Change the active database\").","tags":["multitenant","container","con_name","cdb_","containers","pdb","root"]},{"id":"pdb-refreshable-clone","task":"Criar um refreshable PDB, atualizá-lo e convertê-lo em um PDB independente","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":"Cria uma cópia mantida atualizada aplicando o redo do PDB de origem periodicamente ou sob demanda; abre READ ONLY para relatórios e se torna um PDB independente de leitura e escrita com REFRESH MODE NONE.","when":"Para uma cópia de relatório/teste da produção atualizada regularmente, uma migração de PDB com baixo downtime (refresh final + REFRESH MODE NONE) ou um \"standby barato em nível de PDB\".","caution":"O PDB deve estar fechado durante um refresh; enquanto aberto READ ONLY, o refresh automático aguarda. Os archivelogs necessários para o refresh devem estar acessíveis na origem. REFRESH MODE NONE é irreversível; a cópia não pode mais ser atualizada. Exige local undo + ARCHIVELOG na origem. Não substitui o Data Guard para DR de verdade.","since":"12c","note":"12.2+. Após REFRESH MODE NONE o clone se torna um PDB comum e pode ser aberto READ WRITE; isso não pode ser desfeito.","tags":["multitenant","pdb","refreshable","refresh","refresh","reporting","clone"]}]},"recipes/oracle-ops.json":{"engineId":"oracle","engine":"Oracle","order":2,"recipes":[{"id":"awr-snapshot-report","task":"Tirar um snapshot do AWR e gerar um relatório AWR entre dois snapshots","category":"Desempenho","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":"Gera um relatório entre dois snapshots do AWR cobrindo a janela do problema: load profile, principais wait events, principais SQL e estatísticas da instância. A table function permite obter o relatório a partir de um script ou de um job do scheduler.","when":"Ao analisar uma lentidão em uma janela de tempo específica, para comparação antes/depois em torno de um teste de carga ou batch e para relatórios de capacidade.","caution":"Exige a licença do Diagnostics Pack (CONTROL_MANAGEMENT_PACK_ACCESS='DIAGNOSTIC' ou 'DIAGNOSTIC+TUNING'); sem ela, defina o parâmetro como 'NONE' e use o Statspack. Um relatório não pode atravessar um restart da instância. Intervalos maiores que uma hora fazem a média e escondem picos curtos; mantenha a janela estreita.","note":"Para AWR em nível de PDB (12.2+) verifique AWR_PDB_AUTOFLUSH_ENABLED=TRUE e AWR_SNAPSHOT_TIME_OFFSET/AWR_PDB_MAX_PARALLEL_SLAVES; um relatório gerado dentro de um PDB mostra apenas os dados desse PDB. Intervalo/retenção: 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":"Relatório AWR diff (compare period) entre dois períodos","category":"Desempenho","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":"Coloca dois intervalos de snapshots lado a lado e mostra as diferenças percentuais em DB time, wait events, load profile e estatísticas por SQL. Responde diretamente ao \"ontem estava bom, hoje está lento\".","when":"Análise de regressão após upgrade/patch, mudança de parâmetro, deploy ou coleta de estatísticas; comparar o mesmo horário em dois dias.","caution":"Exige a licença do Diagnostics Pack. Os períodos comparados devem ter a mesma duração e carga semelhante, senão os deltas enganam. Para comparar bancos diferentes (ex.: prod vs test), mova os dados do AWR com awrextr.sql/awrload.sql e passe o dbid2 correspondente.","tags":["awr diff","comparison","compare period","awrddrpt","regression","performance","diagnostics pack"]},{"id":"ash-top-activity","task":"Principais wait events e principais SQL do ASH nos últimos minutos","category":"Desempenho","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":"Usa as amostras do Active Session History para mostrar, em percentuais, quais wait events e quais comandos SQL consumiram DB time nos últimos minutos; diagnostica o incidente sem esperar um snapshot do AWR.","when":"Durante uma lentidão ao vivo, para picos curtos que somem nas médias do AWR e para ver o que uma sessão ou SQL específico estava esperando.","caution":"Consultar V$ACTIVE_SESSION_HISTORY e DBA_HIST_ACTIVE_SESS_HISTORY exige a licença do Diagnostics Pack. O ASH é amostrado: as contagens de amostras estimam tempo, não são medições exatas, e SQL muito curtos podem não aparecer. O buffer do ASH em memória guarda apenas algumas horas em sistemas movimentados.","tags":["ash","active session history","top wait","top sql","wait","ashrpt","real-time analysis","diagnostics pack"]},{"id":"addm-task-report","task":"Executar uma análise ADDM e obter seu relatório","category":"Desempenho","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":"O Automatic Database Diagnostic Monitor analisa o DB time entre dois snapshots do AWR e relata os gargalos com seu impacto (findings) e recomendações concretas.","when":"Para obter um resumo rápido de \"onde devo olhar\" antes de ler o relatório AWR ou para analisar um intervalo personalizado além da execução automática do ADDM após cada snapshot.","caution":"Exige a licença do Diagnostics Pack. Não aplique cegamente as recomendações do ADDM (aumentos de parâmetros, executar o SQL Tuning Advisor etc.); valide as recomendações de memória com as seções de advisory do AWR. O intervalo não pode atravessar um restart.","tags":["addm","dbms_addm","advisor","finding","finding","recommendation","diagnostics pack","performance"]},{"id":"sql-monitor-report","task":"Obter um relatório do SQL Monitor (SQL longo em execução ou concluído)","category":"Desempenho","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":"O Real-Time SQL Monitoring mostra, para cada passo do plano de execução de um SQL longo ou paralelo, as linhas reais, o tempo decorrido, o uso de memória/temp e a atividade do ASH; você pode acompanhar o progresso enquanto o SQL ainda roda.","when":"Ao perguntar se uma consulta de batch/relatório está travada e quanto falta, para análise da distribuição de consulta paralela (PX skew) e para encontrar diferenças entre linhas estimadas (E-Rows) e reais.","caution":"Exige a licença do Tuning Pack (o Diagnostics Pack é pré-requisito). Por padrão só são monitorados SQL que consomem 5 s de CPU/I-O ou rodam em paralelo; use o hint /*+ MONITOR */ para os demais. Planos muito grandes (_sqlmon_max_planlines, padrão 300) não são monitorados. As entradas ficam em memória por tempo limitado; no 12c+ relatórios mais antigos também estão disponíveis em 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":"Habilitar/desabilitar o trace 10046 de uma sessão e resumir com TKPROF","category":"Desempenho","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":"O extended SQL trace (10046) grava em um arquivo de trace os tempos de parse/execute/fetch, os wait events e os valores de bind de cada SQL que a sessão executa; o TKPROF o transforma em um relatório legível agregado por SQL.","when":"Quando AWR/ASH não bastam e é preciso provar de ponta a ponta onde uma única operação de usuário gasta seu tempo; para problemas de round-trip aplicação-banco (SQL*Net).","caution":"Não exige licença. Os arquivos de trace crescem rápido e adicionam overhead à sessão alvo; mantenha-o curto e sempre o desabilite (verifique sobras em DBA_ENABLED_TRACES). binds=TRUE grava dados sensíveis (números de documento, números de cartão etc.) no arquivo de trace. ALTER SESSION SET EVENTS exige o privilégio ALTER SESSION (senão ORA-01031). O TKPROF não mostra valores de bind por padrão; guarde o arquivo .trc bruto.","note":"Tracing de pool de conexões ou em nível de serviço gera vários arquivos; junte-os com trcsess (trcsess output=combined.trc clientid=<id> *.trc) e depois execute o TKPROF.","tags":["10046","trace","tkprof","dbms_monitor","sql trace","wait","bind","session tracing"]},{"id":"xplan-allstats-last","task":"Mostrar o plano de execução real com estatísticas de row source (ALLSTATS LAST)","category":"Desempenho","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 é uma estimativa; isto mostra o plano que realmente rodou, com Starts, E-Rows (estimado), A-Rows (real), A-Time, Buffers e uso de memória por passo. É a forma mais direta de achar o passo em que começa o erro de estimativa de cardinalidade.","when":"Ao fazer tuning de um único SQL lento, para provar a necessidade de estatísticas/histogramas e para medir o efeito de um hint ou de uma mudança de índice.","caution":"Não exige licença. Com SET SERVEROUTPUT ON, sql_id=>NULL mostra a chamada DBMS_OUTPUT como último cursor; defina OFF antes. Não habilite statistics_level=ALL para todo o sistema; adiciona overhead perceptível de CPU. O hint muda o texto do SQL, que ganha um novo sql_id. O usuário precisa de acesso de leitura a 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":"Criar e executar uma tarefa do SQL Tuning Advisor e ler suas recomendações","category":"Desempenho","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":"Executa o otimizador em um \"tuning mode\" estendido para o SQL e gera recomendações sobre estatísticas ausentes, novos índices, um SQL profile, planos alternativos e reestruturação do SQL; valida a recomendação de profile com execuções de teste.","when":"Quando um único SQL problemático precisa de uma segunda opinião rápida ou ao buscar uma correção via SQL profile para uma regressão de plano sem mudar o código.","caution":"Exige a licença do Tuning Pack. O escopo COMPREHENSIVE pode executar o SQL para teste (apenas a parte de consulta em DML); defina time_limit em produção. As recomendações de índice ignoram o restante da carga; avalie o custo de DML separadamente. O usuário precisa do privilégio ADVISOR.","tags":["sql tuning advisor","dbms_sqltune","tuning task","recommendation","sql profile","index recommendation","tuning pack"]},{"id":"sql-profile-accept","task":"Aceitar, desabilitar e remover um SQL profile","category":"Desempenho","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":"Um SQL profile fornece ao otimizador correções extras de cardinalidade/seletividade (OPT_ESTIMATE e similares) para que ele gere um plano melhor sem mudar o texto do SQL; com FORCE_MATCH também se aplica a comandos que diferem apenas nos literais.","when":"Quando o SQL não pode ser alterado (aplicação de pacote), quando o STA recomenda uma melhoria validada ou como correção rápida para uma regressão de plano.","caution":"Exige a licença do Tuning Pack. Um profile não \"trava\" o plano; ele corrige estimativas, então o plano ainda pode mudar quando a distribuição dos dados muda. Se a estabilidade do plano for obrigatória, use um SQL plan baseline. Quando ambos existem, o otimizador escolhe entre os planos aceitos do baseline. Sempre leia os resultados de validação (a seção 'Validation results' do relatório) antes de aceitar.","tags":["sql profile","accept_sql_profile","dbms_sqltune","force_match","plan fix","dba_sql_profiles","tuning pack"]},{"id":"spm-load-from-cursor-cache","task":"Carregar um bom plano do cursor cache como SQL plan baseline","category":"Desempenho","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":"Usa o SQL Plan Management para tornar o plano escolhido um baseline ACCEPTED; o otimizador passa a usar apenas planos aceitos do baseline e guarda os planos recém-encontrados até que sejam evoluídos.","when":"Para voltar a um plano reconhecidamente bom durante uma regressão de plano e para proteger planos de SQL críticos antes de um upgrade ou de uma mudança de estatísticas.","caution":"Sem licença extra no Enterprise Edition (no SE2 é limitado a um plano de baseline por SQL). Exige ADMINISTER SQL MANAGEMENT OBJECT. Um baseline se aplica exatamente ao mesmo texto SQL (assinatura); não ajuda SQL que usa literais. Se um índice usado pelo plano for removido, o plano não pode ser reproduzido (REPRODUCED=NO) e o otimizador volta à escolha baseada em custo. OPTIMIZER_USE_SQL_PLAN_BASELINES deve ser TRUE (padrão).","note":"Se o bom plano não estiver mais no cursor cache, carregue-o do AWR: 12.2+ DBMS_SPM.LOAD_PLANS_FROM_AWR(begin_snap, end_snap, basic_filter => q'[sql_id='<sql_id>']'); em versões anteriores passe por um SQL Tuning Set com 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":"Evoluir planos não aceitos de SQL plan baselines","category":"Desempenho","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":"Quando existe um baseline, novos planos encontrados pelo otimizador são armazenados com ACCEPTED=NO. A tarefa de evolve executa esses candidatos em teste contra o plano aceito e aceita apenas os claramente melhores.","when":"Para SQL com baseline quando um novo índice ou novas estatísticas podem ter gerado um plano melhor; para decidir manualmente sem esperar a SYS_AUTO_SPM_EVOLVE_TASK automática (12c+).","caution":"Exige Enterprise Edition. O evolve de fato executa o SQL (apenas a parte de consulta em DML); defina time_limit para SQL pesados e evite horários de pico. Exige ADMINISTER SQL MANAGEMENT OBJECT e ADVISOR. SQL analisados como SYS não podem ser evoluídos (ORA-16963); execute como o usuário da aplicação.","since":"Oracle 12c","note":"A função DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE anterior ao 12c está obsoleta; o 12c+ usa a API baseada em tarefas (CREATE/EXECUTE/IMPLEMENT_EVOLVE_TASK). Comportamento da tarefa automática: 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":"Fixar, desabilitar ou remover um plano de SQL plan baseline","category":"Desempenho","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":"Gerencia os atributos dos planos do baseline: um plano FIXED tem preferência sobre os demais planos aceitos e interrompe a evolução automática de novos planos; ENABLED=NO desabilita um plano sem apagá-lo; DROP o remove definitivamente.","when":"Para fixar firmemente um plano de um SQL crítico, desabilitar um plano ruim aceito por engano ou limpar baselines que não são mais necessários.","caution":"Exige Enterprise Edition. Planos FIXED podem se degradar com o crescimento dos dados e impedir o otimizador de usar um plano melhor; revise-os periodicamente. Um SQL cujos planos estão todos ENABLED=NO é otimizado livremente. DROP é irreversível; faça antes backup em uma staging table com 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":"Verificar o status de bind peeking e de adaptive cursor sharing","category":"Desempenho","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":"O otimizador escolhe um plano espiando o valor de bind no primeiro hard parse. O adaptive cursor sharing pode criar child cursors/planos diferentes por valor de bind em colunas com histogramas; estas consultas mostram se o cursor é bind-sensitive/aware, qual valor foi espiado e por que os filhos foram criados.","when":"Para reclamações de \"o mesmo SQL às vezes é rápido, às vezes lento\", com distribuição de dados assimétrica e quando a contagem de child cursors explode (high version count).","caution":"Não exige licença; somente leitura. V$SQL_BIND_CAPTURE é amostrado (cerca de a cada 15 minutos por padrão) e guarda apenas binds de WHERE/HAVING; não é o valor de toda execução. O ACS torna um cursor bind-aware só depois de algumas execuções ruins. Para SQL críticos, carregar vários planos em um SQL plan baseline é mais determinístico do que depender do ACS.","since":"Oracle 11g","note":"O adaptive cursor sharing foi introduzido no 11g. Para análise de high version count, a coluna REASON (XML) de V$SQL_SHARED_CURSOR dá a causa detalhada.","tags":["bind peeking","adaptive cursor sharing","acs","bind variable","v$sql_bind_capture","child cursor","version count"]},{"id":"top-sql-awr-history","task":"Encontrar os principais SQL por tempo decorrido/CPU em um período passado (AWR + V$SQLAREA)","category":"Desempenho","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":"Soma as colunas *_DELTA de DBA_HIST_SQLSTAT para listar os SQL mais caros em um intervalo de snapshots, separados por plan_hash_value, o que também revela mudanças de plano do mesmo SQL. A consulta em V$SQLAREA dá valores cumulativos do que ainda está no cache.","when":"Para \"o que carregou o sistema ontem à noite entre 02:00 e 04:00?\", detectar mudanças de plano (mesmo sql_id, plan_hash_value diferente) e montar uma lista de candidatos a tuning.","caution":"Consultar DBA_HIST_* exige a licença do Diagnostics Pack; V$SQLAREA não. O AWR guarda apenas os principais SQL (top-N por padrão), então comandos pequenos mas muito frequentes podem faltar. Os valores de V$SQLAREA se perdem quando o cursor sai do cache. Os deltas continuam corretos após um restart, mas a consulta baseada no cache começa do zero.","tags":["top sql","dba_hist_sqlstat","v$sqlarea","elapsed","cpu","most expensive query","plan change","diagnostics pack"]},{"id":"stats-stale-prefs","task":"Encontrar estatísticas desatualizadas e definir preferências de estatísticas por tabela (prefs)","category":"Estatísticas","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":"As estatísticas ficam desatualizadas quando a taxa de alteração passa de STALE_PERCENT (padrão 10%). As preferências guardam por tabela a amostragem, os histogramas, o paralelismo e os limites de desatualização para que a tarefa automática noturna de estatísticas aplique as mesmas regras.","when":"Quando o limite de 10% dispara tarde demais em tabelas grandes, quando colunas específicas devem sempre ter histograma e para definir a estratégia de coleta no dicionário em vez de em scripts.","caution":"Não exige licença. As preferências são sobrepostas por parâmetros explícitos em uma chamada GATHER manual. Mudar METHOD_OPT adiciona ou remove histogramas e pode mudar planos. DBA_TAB_MODIFICATIONS só fica atualizado após um flush (flush automático aproximadamente a cada 15 minutos).","tags":["stale stats","stale_percent","set_table_prefs","dba_tab_statistics","dba_tab_modifications","statistics preference","gather stale"]},{"id":"stats-lock-unlock","task":"Bloquear e desbloquear estatísticas de tabela/schema","category":"Estatísticas","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":"Bloqueia as estatísticas contra alterações; a tarefa automática ignora objetos bloqueados e uma chamada GATHER em nível de tabela gera ORA-20005. force=>TRUE coleta sem remover o bloqueio.","when":"Para manter estatísticas representativas em tabelas de staging/voláteis que são esvaziadas e recarregadas durante o dia, proteger os planos de uma tabela crítica contra mudanças de estatísticas ou preservar valores definidos com DBMS_STATS.SET_TABLE_STATS.","caution":"Não exige licença. Estatísticas bloqueadas se afastam da realidade com o tempo e causam erros de cardinalidade; reporte os objetos bloqueados regularmente. Um bloqueio de schema não cobre tabelas adicionadas ao schema depois. Em uma tabela bloqueada, CREATE/REBUILD INDEX também não coleta estatísticas do índice automaticamente.","tags":["lock stats","lock statistics","unlock_table_stats","lock_schema_stats","ora-20005","stattype_locked","dbms_stats"]},{"id":"stats-restore-history","task":"Restaurar estatísticas a um ponto no passado","category":"Estatísticas","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":"O DBMS_STATS salva as estatísticas anteriores no SYSAUX antes de toda coleta (31 dias por padrão). As procedures RESTORE_* devolvem as estatísticas de tabela/schema ao estado do horário informado; com no_invalidate=>FALSE os cursores são reanalisados imediatamente.","when":"Como o rollback mais rápido quando uma regressão de plano segue a coleta noturna de estatísticas e para testar se uma mudança foi causada pelas estatísticas.","caution":"Não exige licença. Estatísticas bloqueadas não podem ser restauradas (desbloqueie antes). A próxima coleta automática traz novas estatísticas de volta após o restore; para uma correção permanente defina preferências da tabela, bloqueie as estatísticas ou use um SQL plan baseline. Uma retenção longa faz o SYSAUX crescer (tabelas 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":"Coletar estatísticas como pending, testá-las e publicá-las","category":"Estatísticas","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":"Com a preferência PUBLISH=FALSE, as estatísticas coletadas são gravadas em uma área pending em vez do dicionário, então as outras sessões não são afetadas. Os planos são validados em uma sessão de teste com optimizer_use_pending_statistics e depois publicados ou descartados com um único comando.","when":"Para testar sem risco, em produção, o impacto no plano de estatísticas atualizadas em tabelas OLTP críticas e para uma virada controlada após uma grande carga de dados.","caution":"Não exige licença. Enquanto PUBLISH=FALSE permanecer, as estatísticas coletadas pela tarefa automática também se acumulam como pending e nunca são publicadas; lembre-se de voltar a preferência para TRUE. EXPLAIN PLAN é uma estimativa; quando possível execute a consulta e verifique o 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":"Configurar estatísticas incrementais para uma tabela particionada","category":"Estatísticas","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":"No modo incremental um synopsis é armazenado por partição; as estatísticas globais (em nível de tabela), em especial o NDV, são calculadas mesclando os synopses sem reler a tabela inteira. Apenas as partições alteradas são lidas novamente.","when":"Em tabelas grandes (escala de TB) particionadas por range/interval em que os dados novos caem apenas nas partições recentes, quando a coleta de estatísticas globais excede a janela de manutenção.","caution":"Não tem licença própria, mas a opção Partitioning (EE com custo extra) já é necessária. Os synopses consomem espaço no SYSAUX (o formato HyperLogLog do 12.2+ é bem menor). A primeira coleta é um full scan; inicie-a em uma janela de manutenção. Definir ESTIMATE_PERCENT com qualquer valor diferente de AUTO_SAMPLE_SIZE desabilita o incremental.","since":"Oracle 11g","note":"As preferências INCREMENTAL_STALENESS e INCREMENTAL_LEVEL foram adicionadas no 12c; no 12.2+ o formato do synopsis é controlado por APPROXIMATE_NDV_ALGORITHM (HYPERLOGLOG).","tags":["incremental stats","synopsis","partition statistics","global stats","incremental_staleness","dbms_stats","large table"]},{"id":"partition-split-merge-online","task":"Dividir e mesclar partições online","category":"Particionamento","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 divide uma partição em duas em um valor de limite (12c+: em várias); MERGE combina partições adjacentes. Com ONLINE, o DML continua durante a operação; com UPDATE INDEXES, os índices locais e globais não ficam UNUSABLE.","when":"Para dividir uma partição MAXVALUE/\"outros\" que cresceu, mesclar partições antigas pequenas antes de arquivar ou mudar o esquema de particionamento (mensal para trimestral).","caution":"Exige a opção Partitioning (EE com custo extra); ONLINE exige Enterprise Edition. SPLIT/MERGE reescreve fisicamente os dados: é lento em partições grandes e gera redo/undo e espaço temporário. Sem ONLINE a tabela fica bloqueada para DML durante a operação; sem UPDATE INDEXES os índices globais ficam UNUSABLE. Dividir uma partição vazia é rápido (fast split).","since":"Oracle 12.2","note":"ONLINE SPLIT chegou no 12.2 e ONLINE MERGE no 18c; ambos estão disponíveis no 19c. Em versões mais antigas retire a palavra-chave ONLINE e execute a operação em uma janela de manutenção.","tags":["split partition","merge partition","add partition","split a partition","merge partitions","update indexes","online","partitioning"]},{"id":"partition-exchange","task":"Carregar ou arquivar dados em massa com exchange partition","category":"Particionamento","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":"Troca no dicionário o segmento de uma partição pelo segmento de uma tabela comum; milhões de linhas \"entram\" na tabela ou \"saem\" dela para arquivamento em segundos. FOR EXCHANGE WITH TABLE cria uma staging table que garante compatibilidade de colunas e de colunas ocultas.","when":"Para cargas em massa de DWH/ETL, mover uma partição antiga para uma tabela de arquivo e preparar índices e estatísticas sem afetar a tabela em uso durante a carga.","caution":"Exige a opção Partitioning (EE com custo extra). WITHOUT VALIDATION não verifica se as linhas de staging cabem nos limites da partição; dados errados ficam na partição errada e as consultas podem retornar resultados incorretos; na dúvida use WITH VALIDATION (full scan). Sem UPDATE GLOBAL INDEXES os índices globais ficam UNUSABLE. Os estados das constraints unique/PK devem coincidir dos dois lados.","note":"CREATE TABLE ... FOR EXCHANGE WITH TABLE foi introduzido no 12.2; antes disso, crie a staging table com CREATE TABLE ... AS SELECT * FROM <table> WHERE 1=0 e verifique manualmente as diferenças de colunas ocultas/virtuais.","tags":["exchange partition","staging","for exchange with table","bulk load","archive","update global indexes","partitioning"]},{"id":"partition-drop-truncate-gidx","task":"Truncar/remover uma partição mantendo os índices globais utilizáveis","category":"Particionamento","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":"Remove dados antigos instantaneamente em nível de partição, em vez de DELETE linha a linha. No 12c+, UPDATE INDEXES apenas marca os índices globais no dicionário (manutenção assíncrona) em vez de atualizar cada entrada; o índice fica utilizável imediatamente e as entradas órfãs são limpas depois.","when":"Ao expurgar períodos antigos sob uma política de retenção de dados, em jobs de ILM/expurgo e para evitar a carga de undo/redo de DELETE em tabelas grandes.","caution":"Exige a opção Partitioning (EE com custo extra). DROP/TRUNCATE é irreversível (flashback table não traz uma partição de volta); faça backup ou arquive via exchange antes. Se UPDATE INDEXES for esquecido, os índices globais ficam UNUSABLE e as consultas podem receber ORA-01502. A operação falha se tabelas filhas a referenciarem (FK). Em tabelas interval a última partição range (de transição) não pode ser removida.","since":"Oracle 12c","tags":["drop partition","truncate partition","update indexes","orphaned_entries","cleanup_gidx","global index","data purge","partitioning"]},{"id":"interval-partitioning","task":"Criar particionamento interval e converter uma tabela range existente para interval","category":"Particionamento","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":"O particionamento interval cria automaticamente uma nova partição quando chega a primeira linha além do último limite, eliminando erros ORA-14400 causados por esquecer a partição do mês seguinte. SET INTERVAL converte uma tabela range existente sem mover dados.","when":"Para tabelas que crescem por data, como séries temporais, logs e pedidos, e para reduzir scripts de manutenção de partições.","caution":"Exige a opção Partitioning (EE com custo extra). A chave de partição deve ser uma única coluna NUMBER/DATE/TIMESTAMP; uma partição MAXVALUE deve ser removida antes. Uma data errada ou extrema (ex.: ano 9999) abre uma partição distante e distorce a numeração das partições; com intervalos estreitos você pode se aproximar do limite de 1,048,575 partições (ORA-14300), então valide as datas na aplicação. As partições automáticas vão para o tablespace padrão da tabela (direcione-as com 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":"Verificar chaves de partição e o uso de partition-wise join","category":"Particionamento","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":"Duas tabelas equiparticionadas pela chave de join podem ser unidas par de partição a par de partição (full partition-wise join), o que reduz bastante o tráfego de redistribuição e a memória em consultas paralelas. O formato do plano mostra se o PWJ é usado.","when":"Ao projetar grandes joins fato-fato ou fato-dimensão em um DWH, quando consultas paralelas mostram redistribuição PX pesada (PX Deq Credit: send blkd) e ao validar a estratégia de particionamento.","caution":"Licença: opção Partitioning (EE com custo extra); consulta paralela exige Enterprise Edition. EXPLAIN PLAN é uma estimativa; use DISPLAY_CURSOR/SQL Monitor para o plano real. O full PWJ precisa do mesmo número de partições (uma potência de dois é recomendada para hash) e de tipos de dados de chave correspondentes. O PWJ pode aparecer também em planos seriais, mas o ganho real está na execução paralela.","tags":["partition-wise join","pwj","equi-partitioning","hash partition","parallel query","dba_part_key_columns","partitioning"]},{"id":"online-redefinition-flow","task":"Redefinir uma tabela online com DBMS_REDEFINITION (fluxo completo)","category":"Operações online","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":"Muda a estrutura de uma tabela (particionamento, tipos/ordem de colunas, tablespace, compressão, configurações de LOB) enquanto a aplicação continua rodando: os dados são copiados para uma tabela intermediária, as mudanças são sincronizadas por um MV log e no final os nomes são trocados sob um bloqueio muito curto.","when":"Para mudanças que o ALTER TABLE não faz online, como particionar sem downtime uma tabela grande não particionada, mudar o tipo de uma coluna ou converter LOBs BasicFile em SecureFiles.","caution":"Exige Enterprise Edition (mais a opção Partitioning se o destino for particionado). O processo precisa do dobro do espaço da tabela e adiciona overhead de redo e de MV log. FINISH faz um breve bloqueio exclusivo; transações longas o fazem esperar (dml_lock_timeout). Sempre verifique os erros de COPY_TABLE_DEPENDENTS em DBA_REDEFINITION_ERRORS; FKs podem ser copiadas como NOVALIDATE. Ensaie antes em um ambiente de teste.","note":"O parâmetro dml_lock_timeout foi adicionado no 12c. No 12.2+ acompanhe o progresso em V$ONLINE_REDEF. Para uma simples mudança de move/compressão, ALTER TABLE ... MOVE ONLINE basta em vez de DBMS_REDEFINITION.","tags":["dbms_redefinition","online redefinition","redefinition","zero downtime","convert to partitioned","can_redef_table","finish_redef_table","enterprise edition"]},{"id":"table-move-online","task":"Mover uma tabela ou partição online (ALTER TABLE MOVE ONLINE)","category":"Operações online","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":"Reescreve o segmento da tabela: reduz a fragmentação e a high water mark, muda o tablespace e aplica compressão. Com ONLINE, o DML não é bloqueado durante a operação e os índices são mantidos automaticamente e continuam VALID.","when":"Para recuperar espaço após exclusões em massa, mover uma tabela para um novo tablespace/storage e comprimir partições antigas em um tablespace de arquivo.","caution":"Exige Enterprise Edition; ROW STORE COMPRESS ADVANCED exige a opção Advanced Compression (custo extra). A operação precisa de espaço adicional igual ao tamanho da tabela e gera redo pesado. Bloqueios curtos são feitos no início e no fim; transações abertas longas a fazem esperar. Um MOVE sem ONLINE ou UPDATE INDEXES deixa todos os índices UNUSABLE.","since":"Oracle 12.2","note":"O MOVE ONLINE em nível de tabela foi introduzido no 12.2; o MOVE PARTITION ONLINE em nível de partição existe desde o 12.1. No 12.1 e anteriores use DBMS_REDEFINITION para tabelas.","tags":["move online","alter table move","move table","reorganization","high water mark","compression","enterprise edition"]},{"id":"tde-keystore-setup","task":"Criar, abrir, definir a master key e fazer backup de um keystore TDE (19c+)","category":"Segurança","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":"Configura um software keystore para Transparent Data Encryption em united mode (todos os PDBs compartilham o keystore do CDB), cria a master encryption key e habilita o auto-login para que ele abra após um restart. No 19c+ o método recomendado é WALLET_ROOT/TDE_CONFIGURATION em vez de ENCRYPTION_WALLET_LOCATION no sqlnet.ora.","when":"Como primeiro passo antes da criptografia de tablespaces/colunas em projetos de conformidade que exigem criptografia de dados em repouso (GDPR, PCI-DSS, ISO 27001).","caution":"On-premises exige a opção Advanced Security (custo extra); está incluída no licenciamento do Oracle Cloud (OCI/Autonomous). WALLET_ROOT é estático e precisa de restart da instância (downtime). Se o keystore e sua senha forem perdidos, os dados criptografados ficam ilegíveis PERMANENTEMENTE; guarde os backups do keystore com segurança e separados dos backups do banco. Quem tiver o arquivo de auto-login (cwallet.sso) pode abrir o banco; restrinja as permissões do arquivo e use LOCAL AUTO_LOGIN quando apropriado. Com Data Guard, copie também o keystore para o standby.","since":"Oracle 18c","note":"WALLET_ROOT e TDE_CONFIGURATION foram introduzidos no 18c e são padrão no 19c; o método ENCRYPTION_WALLET_LOCATION no sqlnet.ora do 12c-18c está obsoleto no 19c e sem suporte no 23ai. No 23ai o algoritmo padrão é AES256; a criptografia com GOST e SEED não tem mais suporte e a descriptografia com eles está obsoleta. WALLET_ROOT é um parâmetro estático e exige restart da instância.","tags":["tde","keystore","wallet","master key","encryption","advanced security","wallet_root","administer key management"],"untested":true},{"id":"tde-tablespace-encryption","task":"Criptografar tablespaces com TDE (novos e existentes, online/offline)","category":"Segurança","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":"A criptografia de tablespace criptografa cada bloco gravado nos datafiles; os dados ficam em claro no buffer cache, então não são necessárias mudanças na aplicação ou no SQL. A conversão online cria uma cópia criptografada do datafile e passa a usá-la enquanto o DML continua; a conversão offline criptografa os blocos no próprio local.","when":"Para criptografar em repouso tablespaces de aplicação com dados sensíveis, mover dados para um novo tablespace criptografado ou encerrar um achado de auditoria.","caution":"On-premises exige a opção Advanced Security (custo extra). A conversão online precisa de espaço extra igual ao dos datafiles sendo criptografados e gera I/O e redo pesados; um standby Data Guard faz o mesmo trabalho. A conversão offline deve ser executada separadamente em um standby Data Guard. SYSTEM/SYSAUX/UNDO podem ser criptografados online no 12.2+, mas exigem cuidado extra. Backups de tablespaces criptografados não podem ser restaurados sem o keystore.","since":"Oracle 12.2","note":"A conversão online/offline de tablespaces foi introduzida no 12.2. Para criptografar novos tablespaces automaticamente, o 19c usa TABLESPACE_ENCRYPTION=AUTO_ENABLE (RU 19.16+) ou ENCRYPT_NEW_TABLESPACES=ALWAYS. O keystore precisa estar aberto e com uma master key definida antes (veja 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":"Criar uma política de Unified Auditing, habilitá-la com condição, revisar os registros e removê-la","category":"Segurança","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":"O Unified Auditing reúne todos os registros de auditoria em uma única trilha (schema AUDSYS, UNIFIED_AUDIT_TRAIL). As políticas são definidas por ação em objeto, privilégio de sistema ou ação; a condição WHEN e as listas de usuários BY/EXCEPT reduzem o ruído.","when":"Para registrar acessos a tabelas sensíveis, monitorar DDL privilegiado e mudanças de privilégios, ver tentativas de logon com falha e atender a requisitos de auditoria.","caution":"Sem licença extra. Auditar SELECT em tabelas movimentadas gera muitos registros e crescimento do SYSAUX; restrinja com condições e EXCEPT e agende arquivamento/limpeza com DBMS_AUDIT_MGMT (CLEAN_AUDIT_TRAIL, SET_LAST_ARCHIVE_TIMESTAMP). Uma política habilitada não pode ser removida (ORA-46361); execute NOAUDIT antes. Mudanças de política valem para novas sessões. O 19c roda em mixed mode por padrão, então registros do AUDIT_TRAIL tradicional também podem ser gravados.","since":"Oracle 12c","note":"No 23ai a auditoria tradicional não tem mais suporte; existe apenas a unified auditing, e FLUSH_UNIFIED_AUDIT_TRAIL foi removido porque os registros são gravados diretamente na tabela. No 19c, mudar para o modo unified puro exige relinkar o binário oracle com uniaud_on.","tags":["unified auditing","audit policy","auditing","unified_audit_trail","create audit policy","noaudit","ora_logon_failures","security"]},{"id":"vpd-row-level-policy","task":"Adicionar uma política de acesso em nível de linha com VPD (DBMS_RLS)","category":"Segurança","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":"O Virtual Private Database acrescenta automaticamente o predicado WHERE retornado pela função da política a todo SQL contra a tabela, para que usuários da mesma tabela vejam/alterem apenas as linhas a que têm direito. update_check=>TRUE impede que um usuário atualize uma linha para um valor que ele não poderia ver.","when":"Em aplicações multi-tenant, para isolamento de dados por região/filial e para adicionar segurança em nível de linha sem mexer no código da aplicação.","caution":"Incluído no Enterprise Edition, sem licença extra. CLIENT_IDENTIFIER pode ser definido livremente pelo cliente; em produção use um application context definido por um pacote confiável (CREATE CONTEXT ... USING). SYS e usuários com EXEMPT ACCESS POLICY ignoram a política; exports do Data Pump sem esse privilégio exportam dados parciais silenciosamente. Um erro na função bloqueia todo acesso com ORA-28112. Um policy_type errado (ex.: STATIC) faz cache do predicado e retorna resultados errados.","tags":["vpd","virtual private database","dbms_rls","row security","row level security","add_policy","policy function","security"]},{"id":"password-profile-hardening","task":"Criar um profile de política de senhas e atribuí-lo a usuários","category":"Segurança","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":"Um profile aplica a um grupo de usuários regras de bloqueio por falhas de login, tempo de vida da senha, reutilização, complexidade (verify function) e bloqueio de contas inativas. PASSWORD_ROLLOVER_TIME permite que as aplicações migrem sem indisponibilidade enquanto a senha de uma conta de serviço é alterada.","when":"Para requisitos de auditoria de segurança/CIS benchmark, ao criar novos usuários de aplicação e para separar por grupo de usuários os valores frouxos do profile DEFAULT.","caution":"Sem licença extra. Um limite FAILED_LOGIN_ATTEMPTS em uma conta de serviço permite que um único servidor de aplicação com a senha errada bloqueie a conta e cause indisponibilidade em produção. PASSWORD_LIFE_TIME em contas de aplicação pode causar status EXPIRED inesperado. A verify function deve existir sob o SYS (senão @?/rdbms/admin/utlpwdmg.sql; esse script também modifica o profile DEFAULT). Mudar o profile não revalida as senhas existentes.","note":"INACTIVE_ACCOUNT_TIME foi adicionado no 12.2; PASSWORD_ROLLOVER_TIME veio no 21c e foi portado para o 19c com a RU 19.12. Sessões que fazem login com a senha antiga durante o período de rollover podem ser rastreadas pelos registros de auditoria.","tags":["profile","password policy","password_verify_function","failed_login_attempts","inactive_account_time","password_rollover_time","account lock","security"]},{"id":"privilege-analysis-capture","task":"Encontrar privilégios não utilizados com privilege analysis","category":"Segurança","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":"A privilege analysis registra em tempo de execução quais privilégios de sistema/objeto são de fato usados no escopo escolhido (banco inteiro, role, condição); o resultado lista os privilégios não utilizados para que REVOKEs possam ser planejados segundo o princípio do menor privilégio.","when":"Ao limpar contas de aplicação com privilégios DBA/ANY, em revisões de privilégios antes de uma auditoria e para descobrir o que uma aplicação de pacote realmente precisa.","caution":"Incluída no Enterprise Edition desde 2018 (antes exigia licença do Database Vault); sem licença extra. Há um pequeno overhead durante a captura. O resultado reflete apenas a carga da janela de captura: se jobs de fim de mês, fim de ano ou de emergência não rodaram, um privilégio mostrado como \"não utilizado\" ainda pode ser necessário, então revogue gradualmente. Só uma captura pode estar habilitada por vez; a única exceção é que uma captura G_DATABASE pode ser habilitada junto com uma captura de role ou de contexto.","since":"Oracle 12c","tags":["privilege analysis","dbms_privilege_capture","unused privileges","least privilege","dba_unused_privs","privilege cleanup","security"]},{"id":"opatch-inventory-prereq","task":"Inspecionar o inventário com OPatch e executar verificações pré-patch","category":"Patches e ciclo de vida","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":"Lista os patches binários (RUs, one-offs) aplicados ao Oracle Home e verifica, antes de aplicar um novo patch, se ele conflita com patches existentes e se há espaço em disco suficiente.","when":"Antes de uma RU trimestral/patch de segurança, quando o suporte pede a saída do inventário em um SR e ao comparar o nível de patch de dois ambientes.","caution":"Execute os comandos como o usuário do SO dono do Oracle Home (oracle); opatchauto exige root. As verificações de prereq são somente leitura e não afetam o banco, mas se for reportado um conflito não aplique antes de obter um patch merge/overlay do Oracle Support. Faça backup do Oracle Home (tar) e do inventário antes de aplicar.","note":"Para ver o inventário a partir do SQL, pode-se usar DBMS_QOPATCH.GET_OPATCH_LSINVENTORY (em instalações com inventário do OPatch).","tags":["opatch","lsinventory","lspatches","prereq","patch","patch conflict","opatchauto","release update"],"untested":true},{"id":"datapatch-apply-verify","task":"Atualizar a camada SQL com datapatch -verbose após um patch binário","category":"Patches e ciclo de vida","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":"O datapatch aplica os componentes SQL/PL-SQL (dicionário, pacotes) dos patches binários do Oracle Home ao CDB root, ao PDB$SEED e a todos os PDBs abertos, e registra o resultado em DBA_REGISTRY_SQLPATCH. Também reverte a parte SQL de patches que sofreram rollback.","when":"Após todo patch binário RU/RUR/one-off ou rollback; para PDBs movidos ou desconectados/conectados em um home recém-atualizado; e para executá-lo novamente quando DBA_REGISTRY_SQLPATCH mostrar WITH ERRORS.","caution":"PDBs fechados ou MOUNTED não recebem o patch e podem abrir em modo RESTRICTED; abra todos antes. Não execute sob carga pesada (bloqueios no dicionário, invalidação de pacotes). No RAC execute uma única vez a partir de um só nó. Com Data Guard execute o datapatch apenas no primário; as mudanças chegam ao standby via redo (aplique antes o patch nos binários do standby).","note":"O datapatch das RUs recentes do 19c oferece -sanity_checks para verificar a saúde do dicionário e do ambiente (objetos inválidos, violações de PDB, estado de tablespace/TEMP) antes do patch.","tags":["datapatch","sql patch","release update","dba_registry_sqlpatch","post-patch","utlrp","pdb","patching"],"untested":true},{"id":"sqlpatch-registry-check","task":"Verificar o histórico de patches SQL, o status dos componentes e os objetos inválidos","category":"Patches e ciclo de vida","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":"Mostra de relance se a camada SQL foi realmente atualizada após o patch (dicionário compatível com os binários), qual patch falhou em qual PDB, se os componentes do dicionário estão VALID e o número de objetos inválidos.","when":"Como etapa de verificação após cada datapatch, para registrar uma linha de base antes de patch ou upgrade e quando se suspeita de divergência após conectar um PDB.","caution":"Somente leitura; não exige licença. SOURCE_VERSION/TARGET_VERSION são preenchidos no modelo de RU do 18c+. Se STATUS='WITH ERRORS', corrija o erro no LOGFILE e execute o datapatch novamente. Alguns componentes (ex.: XDB/JAVA não utilizados) podem aparecer como INVALID/REMOVED; compare com o estado anterior ao patch.","note":"Para ver o inventário binário a partir do SQL, use SELECT XMLTRANSFORM(DBMS_QOPATCH.GET_OPATCH_LIST, DBMS_QOPATCH.GET_OPATCH_XSLT) FROM dual; gera ORA-20013 em instalações sem inventário do OPatch.","tags":["dba_registry_sqlpatch","patch history","datapatch","dba_registry","invalid objects","invalid object","patch verification"]},{"id":"scheduler-job-lifecycle","task":"Criar, executar manualmente, desabilitar e remover um job do scheduler","category":"Scheduler","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":"Define um job PL/SQL agendado com DBMS_SCHEDULER; configura max_run_duration (gera um evento quando excedido) e um nível de log detalhado, valida a expressão de calendário antecipadamente e permite uma execução manual sem alterar o agendamento.","when":"Para executar dentro do banco, em vez do cron, tarefas recorrentes como manutenção, ETL e limpeza, com reconhecimento de RAC/Data Guard.","caution":"Sem licença extra. O fuso horário de start_date importa: SYSTIMESTAMP usa o TZ do servidor do banco; use uma região explícita (ex.: 'Europe/Istanbul') para evitar deslocamentos nas mudanças de horário de verão. Se JOB_QUEUE_PROCESSES=0 nenhum job roda. DISABLE com force=>TRUE não para uma execução em andamento, apenas impede as próximas; use STOP_JOB para interrompê-la. Criar um job em outro schema exige CREATE ANY JOB.","tags":["dbms_scheduler","job","scheduled job","create_job","run_job","repeat_interval","disable job","scheduler"]},{"id":"scheduler-job-history","task":"Monitorar o histórico de execução e as falhas de jobs do scheduler","category":"Scheduler","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":"Lista, a partir das views de log do scheduler, o horário de início, a duração, o uso de CPU, o status e a mensagem de erro de cada execução, além dos jobs em execução e dos eventos do ciclo de vida dos jobs.","when":"Quando um job noturno não rodou ou demorou demais, para acompanhamento de SLA de jobs e ao definir regras de falha em um sistema de monitoramento (OEM/Zabbix/Prometheus).","caution":"Somente leitura; não exige licença. A retenção padrão de log é de 30 dias, e jobs com logging_level OFF não geram registros. A coluna ERRORS existe no 12c+; em versões mais antigas verifique ADDITIONAL_INFO. No RAC, RUNNING_INSTANCE mostra qual nó executou o job.","tags":["scheduler","job history","dba_scheduler_job_run_details","failed job","dba_scheduler_running_jobs","job log","monitoring"]},{"id":"resource-plan-basic","task":"Criar e ativar um plano simples do Resource Manager","category":"Scheduler","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":"Decide qual carga vence sob disputa de CPU: dá 70% da CPU ao grupo OLTP e 20% ao grupo de relatórios, limita o paralelismo a 4 no grupo de relatórios e cancela chamadas que passam de 30 minutos (CANCEL_SQL). Os usuários são mapeados para consumer groups automaticamente.","when":"Para cargas mistas em que relatórios diurnos deixam o OLTP lento, limitar consultas paralelas descontroladas e cancelar automaticamente consultas desgovernadas.","caution":"O Resource Manager exige Enterprise Edition (muito limitado no SE2); sem licença extra. Os percentuais mgmt_p1 só valem sob disputa de CPU e não podem passar de 100% no total em um nível. CANCEL_SQL encerra o comando em execução com ORA-00040; um mapeamento errado pode encerrar trabalho crítico, então teste os limites com cuidado. Com um plano ativo, o throttling de CPU aparece como o wait event 'resmgr:cpu quantum'. Para divisão entre PDBs em nível de CDB use 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":"Trocar o segmento de WAL","category":"WAL e checkpoint","command":"SELECT pg_switch_wal();","what":"Fecha o segmento de WAL atual e passa para um novo; dispara o arquivamento.","when":"Para gerar um arquivo de archive ou forçar a saída do WAL após um backup.","caution":"Antes do PostgreSQL 10 era pg_switch_xlog().","since":"PostgreSQL 10","note":"Esta função foi renomeada para pg_switch_wal() no PostgreSQL 10; antes disso era pg_switch_xlog() (o WAL se chamava 'xlog').","tags":["wal","switch","checkpoint","archive"]},{"id":"manual-checkpoint","task":"Executar um CHECKPOINT manual","category":"WAL e checkpoint","command":"CHECKPOINT;","what":"Grava os buffers sujos em disco e cria um registro de checkpoint; avança o ponto de início da recuperação.","when":"Antes de um backup, em uma janela de manutenção ou para sincronizar com o disco antes de parar o servidor.","caution":"Pode gerar I/O pesado; não execute em produção em horários de pico. Apenas um superusuário ou (PG15+) a role pg_checkpoint pode executá-lo.","tags":["checkpoint","wal","io","flush"]},{"id":"wal-status-size","task":"Mostrar o tamanho do WAL e o LSN atual","category":"WAL e checkpoint","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":"Retorna o LSN atual do WAL, o nome do arquivo de WAL sendo gravado e o tamanho total do diretório pg_wal.","when":"Para monitorar o acúmulo de WAL, o uso de disco e o espaçamento dos checkpoints.","caution":"pg_ls_waldir e pg_walfile_name estão disponíveis no PostgreSQL 10+; o acesso pode exigir a role pg_monitor.","tags":["wal","lsn","size","monitor"]},{"id":"archive-lag","task":"Mostrar o atraso de arquivamento (WAL ainda não arquivado)","category":"WAL e checkpoint","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":"Mostra o atraso de arquivamento comparando o último arquivo de WAL arquivado, o WAL sendo gravado no momento e os contadores de falhas de arquivamento.","when":"Para monitorar se o archive_command está ficando para trás e detectar falhas de arquivamento.","caution":"Se failed_count continuar aumentando, o archive_command está falhando e o pg_wal pode encher; aja imediatamente para evitar que o disco transborde.","tags":["archive","wal","lag","monitor"]},{"id":"create-tablespace","task":"Adicionar uma nova tablespace","category":"Armazenamento","command":"CREATE TABLESPACE ssd_ts OWNER postgres LOCATION '/mnt/ssd/pgdata';","what":"Define um novo tablespace no diretório indicado; tabelas e índices podem ser colocados nesse disco.","when":"Para distribuir dados em um disco diferente (ex.: SSD rápido) e separar o I/O.","caution":"O diretório já deve existir, estar vazio e pertencer ao usuário postgres. Não distribua dados para outros discos com links simbólicos; use o próprio mecanismo de tablespaces do PostgreSQL.","tags":["tablespace","storage","disk","create"]},{"id":"move-table-tablespace","task":"Mover uma tabela para outro tablespace","category":"Armazenamento","command":"ALTER TABLE customer SET TABLESPACE ssd_ts;","what":"Move fisicamente todos os dados da tabela para o novo tablespace (disco).","when":"Para mover uma tabela para um disco mais rápido/separado.","caution":"Um lock ACCESS EXCLUSIVE é obtido na tabela durante a movimentação; a tabela fica inacessível até a conclusão. Faça isso em uma janela de manutenção para tabelas grandes.","tags":["tablespace","table","move","storage"]},{"id":"move-index-tablespace","task":"Mover um índice para outro tablespace","category":"Armazenamento","command":"ALTER INDEX customer_email_idx SET TABLESPACE ssd_ts;","what":"Move o índice para o tablespace indicado.","when":"Para colocar os índices em um disco separado dos dados e distribuir o I/O.","caution":"Um lock ACCESS EXCLUSIVE é obtido durante a movimentação; o índice não pode ser usado. ALTER TABLE ... SET TABLESPACE não abrange os índices da tabela, então não consegue movê-los todos de uma vez; mova cada índice separadamente.","tags":["tablespace","index","move","storage"]},{"id":"db-table-size","task":"Consultar o tamanho do banco de dados e das tabelas","category":"Armazenamento","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":"Lista as 20 maiores tabelas com seu tamanho total, incluindo índices e TOAST.","when":"Para analisar o uso de disco e descobrir quais tabelas ocupam espaço.","caution":"Para o tamanho do banco inteiro: SELECT pg_size_pretty(pg_database_size(current_database()));","tags":["size","table","database","storage"]},{"id":"table-bloat","task":"Estimar o bloat de tabelas","category":"Armazenamento","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":"Mostra a taxa de bloat com base na contagem de dead tuples e no horário do último autovacuum.","when":"Para determinar a necessidade de VACUUM e se o autovacuum está dando conta.","caution":"n_dead_tup é uma estimativa atualizada continuamente a partir dos contadores de DML (cai após o VACUUM; o ANALYZE só corrige a estimativa); para o bloat físico exato a extensão pgstattuple (pgstattuple('customer')) é mais precisa.","tags":["bloat","dead-tuple","vacuum","storage"]},{"id":"vacuum-analyze-table","task":"VACUUM ANALYZE em uma tabela específica","category":"Manutenção","command":"VACUUM (ANALYZE, VERBOSE) customer;","what":"Limpa os dead tuples da tabela, torna o espaço reutilizável e atualiza as estatísticas do planner.","when":"Após DELETE/UPDATE em massa ou quando os planos de consulta se degradam.","caution":"O VACUUM não devolve espaço em disco ao SO; recuperar espaço exige VACUUM FULL, que obtém um lock ACCESS EXCLUSIVE. O VACUUM comum não bloqueia a tabela.","tags":["vacuum","analyze","maintenance","cleanup"]},{"id":"vacuum-freeze","task":"Executar um VACUUM FREEZE agressivo","category":"Manutenção","command":"VACUUM (FREEZE, VERBOSE, ANALYZE) customer;","what":"Marca imediatamente como 'frozen' todas as tuplas elegíveis da tabela; reduz o risco de wraparound de transaction ID.","when":"Quando aparece um aviso de wraparound ou preventivamente em tabelas grandes que serão arquivadas/se tornarão somente leitura.","caution":"Gera I/O pesado porque varre a tabela inteira. Em uma emergência de wraparound o banco pode, na prática, ficar somente leitura; monitore o datfrozenxid antes.","tags":["vacuum","freeze","wraparound","maintenance"]},{"id":"reindex-concurrently","task":"Reconstruir um índice sem bloqueio (REINDEX CONCURRENTLY)","category":"Manutenção","command":"REINDEX INDEX CONCURRENTLY customer_email_idx;","what":"Reconstrói o índice sem bloquear gravações; elimina o bloat do índice.","when":"Quando um índice cresceu demais/se corrompeu, em um sistema em produção sem janela de manutenção.","caution":"Exige PostgreSQL 12+. Se falhar, pode deixar um índice INVALID com o sufixo _ccnew; verifique pg_index.indisvalid e limpe com DROP INDEX se necessário. Para reconstruir a tabela inteira: REINDEX TABLE CONCURRENTLY customer;","since":"PostgreSQL 12","note":"REINDEX ... CONCURRENTLY chegou no PostgreSQL 12; antes disso, o REINDEX travava o índice com um lock ACCESS EXCLUSIVE (uma reconstrução sem bloqueio exigia CREATE INDEX CONCURRENTLY + DROP).","tags":["reindex","concurrently","index","maintenance"]},{"id":"autovacuum-per-table","task":"Ajustar o autovacuum para uma tabela específica","category":"Manutenção","command":"ALTER TABLE customer SET (autovacuum_vacuum_scale_factor = 0.02, autovacuum_vacuum_threshold = 5000, autovacuum_analyze_scale_factor = 0.01);","what":"Reduz os limites de disparo do autovacuum apenas para esta tabela, para que tabelas grandes/movimentadas passem por vacuum com mais frequência.","when":"Quando o autovacuum fica para trás em tabelas grandes com muita atividade de UPDATE/DELETE.","caution":"Configurações agressivas demais podem levar a execuções constantes do autovacuum e a carga de I/O. Para reverter a configuração: ALTER TABLE customer RESET (autovacuum_vacuum_scale_factor);","tags":["autovacuum","tuning","table","maintenance"]},{"id":"statistics-target","task":"Aumentar o statistics target de uma coluna","category":"Manutenção","command":"ALTER TABLE customer ALTER COLUMN city SET STATISTICS 500; ANALYZE customer;","what":"Aumenta o nível de detalhe do histograma/amostra coletado para uma coluna específica; melhora as estimativas do planner.","when":"Quando ocorrem planos de consulta ruins em colunas com distribuição assimétrica.","caution":"Um valor alto (padrão 100, máx. 10000) aumenta o tempo de ANALYZE e o tempo de planejamento. A mudança só tem efeito após o ANALYZE.","tags":["statistics","planner","analyze","tuning"]},{"id":"alter-system-reload","task":"Alterar um parâmetro e recarregar (ALTER SYSTEM)","category":"Parâmetros","command":"ALTER SYSTEM SET work_mem = '64MB'; SELECT pg_reload_conf();","what":"Grava o parâmetro no postgresql.auto.conf e recarrega a configuração (efeito imediato para parâmetros que não exigem restart).","when":"Para alterar de forma persistente parâmetros que podem ser aplicados com reload, como work_mem e configurações de log.","caution":"Alguns parâmetros como shared_buffers e max_connections só têm efeito com restart, não com reload; os que têm pg_settings.context = 'postmaster' exigem restart.","tags":["alter-system","reload","parameter","config"]},{"id":"session-set","task":"Alterar um parâmetro para a sessão (SET)","category":"Parâmetros","command":"SET work_mem = '256MB';","what":"Altera o parâmetro apenas para a conexão/sessão atual; volta ao normal quando a sessão termina.","when":"Quando uma configuração precisa ser aumentada temporariamente para uma única consulta pesada ou um job batch.","caution":"Use SET LOCAL para limitá-lo a uma única transação. Uma mudança global exige ALTER SYSTEM.","tags":["set","session","parameter","work-mem"]},{"id":"show-setting","task":"Mostrar o valor atual de um parâmetro","category":"Parâmetros","command":"SELECT name, setting, unit, context, source FROM pg_settings WHERE name = 'shared_buffers';","what":"Mostra o valor efetivo do parâmetro, a unidade, como pode ser aplicado (context) e sua origem.","when":"Para descobrir o valor em uso de um parâmetro e se ele exige restart ou reload.","caution":"Atalho: SHOW shared_buffers; ou SELECT current_setting('shared_buffers'); Se a coluna context for 'postmaster', é necessário restart.","tags":["show","pg_settings","parameter","current-setting"]},{"id":"physical-replica-basebackup","task":"Criar uma réplica física (pg_basebackup)","category":"Replicação","command":"pg_basebackup -h primary_host -U replicator -D /var/lib/postgresql/16/main -Fp -Xs -P -R --slot=replica_slot_1 -C","what":"Faz um backup físico completo do primário, transmite o WAL (-Xs), grava standby.signal e primary_conninfo (-R) e cria o replication slot (-C).","when":"Para criar um novo streaming standby (réplica de leitura ou alvo de failover).","caution":"O diretório de destino (-D) deve estar vazio. No primário, o pg_hba.conf deve conceder acesso 'replication' ao usuário replicator, e deve haver wal_keep_size suficiente / um slot. Com PostgreSQL 12+, -R gera standby.signal em vez de recovery.conf.","tags":["replication","basebackup","standby","physical"]},{"id":"promote-replica","task":"Promover uma réplica a primário","category":"Replicação","command":"SELECT pg_promote(wait := true, wait_seconds := 60);","what":"Tira o servidor standby do modo de recuperação e o transforma em um primário gravável.","when":"Para tornar o standby o novo primário em um failover planejado ou de emergência.","caution":"A promoção não pode ser desfeita; o servidor não consegue mais seguir o antigo primário. Garanta que o antigo primário está realmente fora para evitar split-brain. Alternativa: pg_ctl promote.","since":"PostgreSQL 12","note":"A função SQL pg_promote() chegou no PostgreSQL 12; antes disso, usava-se um arquivo de gatilho (promote_trigger_file) ou pg_ctl promote para promover um standby.","tags":["replication","promote","failover","standby"]},{"id":"replication-lag","task":"Mostrar o lag de replicação","category":"Replicação","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":"No primário, mostra a diferença de replay em bytes de cada standby em relação à posição atual do WAL do primário, além do lag de write/flush/replay.","when":"Para monitorar o quanto a streaming replication está atrasada (execute no primário).","caution":"Para o lag em segundos no standby: SELECT now() - pg_last_xact_replay_timestamp(); esse valor também cresce quando não há gravações no primário, então interprete-o junto com a diferença de LSN. Um resultado vazio significa que nenhum standby está conectado.","tags":["replication","lag","lsn","monitor"]},{"id":"replication-slot","task":"Criar e remover um replication slot","category":"Replicação","command":"SELECT pg_create_physical_replication_slot('replica_slot_1'); -- To drop: SELECT pg_drop_replication_slot('replica_slot_1');","what":"Cria um slot físico que garante que o primário não remova o WAL necessário até que o standby o confirme; o segundo comando remove o slot.","when":"Para garantir que o standby não perca WAL durante indisponibilidades curtas.","caution":"Um slot não utilizado/abandonado leva ao acúmulo de WAL e a um disco cheio. Monitore o status dos slots: SELECT slot_name, active, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained FROM pg_replication_slots; Um slot ativo não pode ser removido.","tags":["replication","slot","wal","cleanup"]},{"id":"logical-replication","task":"Configurar uma publication e uma subscription de replicação lógica","category":"Replicação","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":"Inicia a replicação lógica em nível de tabela criando, na origem, uma publication para tabelas específicas e, no destino, uma subscription que se conecta a ela.","when":"Para upgrades de versão, replicação de tabelas selecionadas para outro servidor ou distribuição de dados em uma única direção.","caution":"Exige PostgreSQL 10+. O schema das tabelas de destino já deve existir; a subscription faz o COPY inicial automaticamente. wal_level deve ser logical (exige restart). Mudanças de DDL e valores de sequences não são replicados; aplique as mudanças de schema nos dois lados separadamente e sincronize as sequences com setval na virada.","since":"PostgreSQL 10","note":"A replicação lógica nativa (CREATE PUBLICATION / CREATE SUBSCRIPTION) chegou no PostgreSQL 10; antes disso, eram necessárias extensões externas como pglogical para o mesmo trabalho.","tags":["logical","replication","publication","subscription"]},{"id":"terminate-backend","task":"Encerrar um backend (pg_terminate_backend)","category":"Sessões","command":"SELECT pg_terminate_backend(12345);","what":"Encerra à força o processo backend com o PID indicado; derruba a conexão e a transação em execução.","when":"Para fechar uma conexão travada ou uma sessão que segura um lock.","caution":"A transação em execução sofre rollback; o trabalho não confirmado é perdido. Tente antes o pg_cancel_backend, mais suave. Confirme o PID em pg_stat_activity.","tags":["terminate","backend","session","kill"]},{"id":"cancel-backend","task":"Cancelar uma consulta em execução (pg_cancel_backend)","category":"Sessões","command":"SELECT pg_cancel_backend(12345);","what":"Cancela a consulta em execução no PID indicado; a conexão permanece aberta.","when":"Para parar uma consulta longa sem derrubar a conexão.","caution":"Ele só cancela uma consulta ativa; não fecha uma sessão no estado idle in transaction, o que exige pg_terminate_backend.","tags":["cancel","backend","query","session"]},{"id":"active-blocking-queries","task":"Mostrar consultas ativas e bloqueadoras","category":"Sessões","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":"Lista todos os backends que não estão ociosos, quais PIDs os estão bloqueando e há quanto tempo estão rodando.","when":"Para diagnosticar problemas de lock/bloqueio e consultas longas.","caution":"pg_blocking_pids está disponível no PostgreSQL 9.6+. Se o array blocking_pids não estiver vazio, esses PIDs seguram o lock; cancele/encerre esse PID se necessário.","since":"PostgreSQL 9.6","note":"A função pg_blocking_pids() chegou no PostgreSQL 9.6; antes disso, encontrar processos bloqueadores exigia fazer join manual com pg_locks.","tags":["activity","blocking","lock","session"]},{"id":"create-extension","task":"Adicionar uma extensão","category":"Extensões","command":"CREATE EXTENSION IF NOT EXISTS pg_stat_statements;","what":"Instala a extensão indicada no banco de dados atual (adiciona funções, views, tipos etc.).","when":"Quando são necessários recursos adicionais como pg_stat_statements, pgcrypto ou postgis.","caution":"Para extensões que exigem shared_preload_libraries, como pg_stat_statements, adicione-as primeiro ao postgresql.conf e reinicie o servidor. Os arquivos da extensão (pacote contrib) devem estar instalados no servidor.","tags":["extension","create","pg_stat_statements","plugin"]},{"id":"list-extensions","task":"Listar as extensões instaladas","category":"Extensões","command":"SELECT extname AS extension, extversion AS version FROM pg_extension ORDER BY extname;","what":"Lista todas as extensões instaladas no banco de dados atual e suas versões.","when":"Para ver quais extensões estão instaladas e se é necessária uma atualização.","caution":"Para ver as extensões instaláveis (mas ainda não instaladas): SELECT * FROM pg_available_extensions; Atualização: 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":"Mostrar o status, a topologia e o histórico do cluster 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":"Mostra a visão do cluster pelo Patroni a partir do DCS: papéis de leader/réplica, estado dos membros (running/streaming), timeline, lag de replicação e restarts pendentes; history lista as mudanças de timeline com o LSN em que ocorreram.","when":"Antes e depois de todo switchover/failover/manutenção e como primeiro passo de diagnóstico quando dispara um alerta.","caution":"A saída reflete o que está armazenado no DCS; se o DCS estiver inacessível, o comando falha ou pode mostrar dados desatualizados. Não inicie um switchover antes de confirmar que todos os membros estão na mesma timeline e que o Lag in MB está abaixo de maximum_lag_on_failover.","untested":true,"tags":["patroni","cluster status","topology","history","lag"]},{"id":"patroni-switchover","task":"Executar um switchover planejado com 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":"Rebaixa o leader saudável de forma controlada e promove a réplica escolhida (--candidate); o antigo leader volta automaticamente como réplica do novo leader. --scheduled adia a operação para o horário indicado.","when":"Para mover o primário para outro nó antes de uma manutenção (patch do SO, troca de hardware, upgrade de versão minor) ou para restaurar os papéis originais após um failover.","caution":"Todas as conexões caem quando o leader muda; a aplicação precisa conseguir reconectar. O Patroni rejeita o switchover se o lag do candidato exceder maximum_lag_on_failover. Com synchronous_mode habilitado, o candidato deve ser um standby síncrono.","note":"Em versões mais antigas do Patroni a opção --leader se chamava --master; o Patroni 4 removeu --master. --primary equivale a --leader.","untested":true,"tags":["patroni","switchover","planned switchover","maintenance","leader"]},{"id":"patroni-failover","task":"Executar um failover manual com 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":"Promove a réplica especificada independentemente do estado do leader; destinado a casos em que o failover automático não ocorreu ou escolheu o nó errado.","when":"Quando o leader está inacessível/não saudável e o failover automático não entrou em ação (ex.: em modo pause) ou quando é preciso forçar a mudança para um nó específico.","caution":"Com replicação assíncrona, as transações ainda não recebidas pelo candidato são perdidas (RPO > 0). Se o leader estiver saudável, use switchover em vez de failover. Quando o antigo leader voltar, pode precisar de pg_rewind (se use_pg_rewind estiver habilitado) ou de um reinit.","note":"No Patroni 3.2+ --candidate é obrigatório para failover; a opção --leader/--primary do failover ficou obsoleta no 3.2 e foi removida no Patroni 4.0. Use switchover se precisar indicar o leader.","untested":true,"tags":["patroni","failover","manual failover","promote","rpo"]},{"id":"patroni-reinit-replica","task":"Reconstruir uma réplica quebrada com 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":"Apaga o diretório de dados da réplica especificada e a reconstrói do zero conforme os create_replica_methods do Patroni (restore do pgBackRest ou pg_basebackup).","when":"Quando uma réplica não consegue voltar à replicação por divergência de timeline, falha do pg_rewind, WAL ausente ou corrupção de dados.","caution":"Todos os dados locais do membro são apagados; confira duas vezes se o comando aponta para o membro certo (o Patroni recusa reinit no leader). Em bancos grandes pode levar horas e adiciona carga de I/O/rede no leader; enquanto isso o cluster fica com uma réplica a menos. --from-leader existe apenas em versões recentes do Patroni 4.x (verifique com patronictl reinit --help); ele ignora os create_replica_methods e faz um pg_basebackup a partir do leader.","untested":true,"tags":["patroni","reinit","rebuild replica","rebuild","basebackup"]},{"id":"patroni-edit-config","task":"Alterar parâmetros de todo o cluster no Patroni (edit-config) e aplicar restarts pendentes","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":"Grava parâmetros do PostgreSQL e do Patroni na configuração dinâmica do DCS; o Patroni aplica a mudança a todos os membros, ativa imediatamente os que permitem reload e marca os que precisam de restart como 'Pending restart'.","when":"Para alterar de forma consistente, em todos os nós de um cluster gerenciado pelo Patroni, parâmetros como max_connections, shared_buffers ou work_mem.","caution":"Sob o Patroni, não edite o postgresql.conf manualmente nem use ALTER SYSTEM: o Patroni reescreve o postgresql.conf, e o postgresql.auto.conf sobrepõe as configurações do Patroni, causando divergência entre os nós. max_connections, max_worker_processes, max_wal_senders, max_prepared_transactions e max_locks_per_transaction em um standby não podem ser menores que no primário; planeje a ordem dos restarts de acordo.","untested":true,"tags":["patroni","edit-config","parameter","pending restart","dcs"]},{"id":"patroni-pause-resume","task":"Colocar o Patroni em modo de manutenção e retirar (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":"Coloca o cluster em modo de manutenção: o Patroni não faz failover automático nem reinicia um PostgreSQL parado; resume volta ao gerenciamento normal.","when":"Durante manutenção do DCS (etcd/Consul), upgrades do Patroni ou quando o PostgreSQL precisa ser gerenciado manualmente sem interferência do Patroni.","caution":"Se o primário cair durante o pause, não há failover automático e a indisponibilidade continua. Não se esqueça do resume após a manutenção; adicione uma verificação de 'Maintenance mode' aos alertas. Iniciar manualmente um PostgreSQL como primário durante o pause pode causar split-brain.","untested":true,"tags":["patroni","pause","resume","maintenance mode","maintenance"]},{"id":"patroni-dcs-health","task":"Verificar a saúde do DCS (etcd/Consul) e da REST API do Patroni","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":"Verifica o quorum, o leader e a capacidade do DCS onde o Patroni guarda o leader lock e a visão que cada membro tem do próprio papel pela REST API do Patroni. O endpoint /primary é a base dos health checks do load balancer (HAProxy).","when":"Quando o Patroni registra 'DCS is not accessible', após um demote/failover inesperado e como verificação de saúde de rotina.","caution":"Se o DCS perder o quorum, o Patroni não consegue renovar o leader lock e rebaixa o primário para somente leitura (a menos que o failsafe_mode, Patroni 3.0+, esteja habilitado); uma queda do etcd é, portanto, uma indisponibilidade de escrita do banco. Quando o tamanho do banco do etcd atinge a cota (padrão 2 GB), um alarme NOSPACE interrompe as gravações. Rode o DCS em pelo menos 3 nós com discos separados.","untested":true,"tags":["patroni","etcd","consul","dcs health","rest api"]},{"id":"pgbackrest-archive-config","task":"Configurar o arquivamento de WAL para o pgBackRest (archive-push/archive-get)","category":"Backup e 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":"Faz o PostgreSQL enviar cada segmento de WAL concluído ao repositório do pgBackRest (archive-push) e buscá-lo de lá durante a recuperação (archive-get); archive-async torna o envio paralelo e assíncrono por meio de um diretório de spool.","when":"Como primeiro passo da configuração de backups físicos e PITR com pgBackRest, antes do stanza-create.","caution":"Enquanto o archive_command falhar, o WAL se acumula no pg_wal e o primário para quando o disco enche; monitore pg_stat_archiver.failed_count. Com Patroni, defina esses parâmetros pelo patroni.yml / edit-config em vez do postgresql.conf. Arquivar dois clusters diferentes no mesmo stanza corrompe o repositório.","untested":true,"tags":["pgbackrest","archiving","archive_command","wal archive","configuration"]},{"id":"pgbackrest-stanza-create-check","task":"Criar o stanza do pgBackRest e verificar o arquivamento (stanza-create/check)","category":"Backup e 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 cria no repositório os metadados do cluster (system identifier, versão); check testa a conexão com o PostgreSQL, o archive_command e a chegada do WAL ao repositório com um WAL switch real.","when":"Na configuração inicial, após mudar o archive_command ou o repositório e como verificação de saúde no monitoramento/cron.","caution":"Execute os comandos como postgres (ou como dono do repositório); executá-los como root quebra a propriedade dos arquivos. Após um upgrade de versão major é necessário stanza-upgrade, não stanza-create. Se o check falhar, o PITR pode ser impossível mesmo que os backups sejam concluídos.","untested":true,"tags":["pgbackrest","stanza","stanza-create","check","archive verification"]},{"id":"pgbackrest-backup-full-diff-incr","task":"Fazer backups full, differential e incremental com pgBackRest","category":"Backup e 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":"Um backup full copia o cluster inteiro, diff copia os arquivos alterados desde o último full, incr copia os arquivos alterados desde o último backup de qualquer tipo; ao final verifica-se que o WAL necessário foi arquivado e o expire roda automaticamente conforme a retenção.","when":"Em uma rotina regular de backup: tipicamente full semanal + diff/incr diário, incr mais frequente em clusters grandes.","caution":"Sem um full anterior, as solicitações diff/incr são promovidas automaticamente a full. Uma cadeia de incr mais longa aumenta o tempo de restore e a dependência; perder um backup da cadeia inutiliza os posteriores. Para aliviar o primário, faça backup a partir de um standby com backup-standby=y (o primário ainda é necessário para a coordenação).","untested":true,"tags":["pgbackrest","backup","full","differential","incremental"]},{"id":"pgbackrest-info","task":"Mostrar o catálogo de backups do pgBackRest e o intervalo do arquivo de WAL (info)","category":"Backup e 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":"Lista o status do stanza e, para cada backup, o label, o tipo, o horário de início/fim, o tamanho, o backup do qual depende e o intervalo min/max do arquivo de WAL no repositório.","when":"Antes de um restore/PITR para confirmar que o horário de destino está coberto, para monitorar se os backups rodam regularmente e para verificar a retenção.","caution":"info mostra que um backup existe, não que ele é restaurável; valide com restores de teste regulares e pgbackrest verify. Se houver uma lacuna no intervalo min/max do WAL, o PITR não consegue atravessá-la.","untested":true,"tags":["pgbackrest","info","backup list","catalog","monitoring"]},{"id":"pgbackrest-restore-latest","task":"Restaurar o backup mais recente com pgBackRest","category":"Backup e 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":"Restaura o backup mais recente e grava recovery.signal e restore_command; na inicialização o PostgreSQL reaplica todo o WAL arquivado até o ponto consistente mais recente e é promovido em uma nova timeline.","when":"Quando o diretório de dados do primário foi perdido/corrompido ou ao testar regularmente se os backups são restauráveis.","caution":"Se o cluster restaurado e o antigo arquivarem no mesmo stanza ao mesmo tempo, o repositório é corrompido; use --archive-mode=off para restores de teste. Sob o Patroni, pause o cluster ou pare o Patroni antes, senão o Patroni interfere. Se existirem tablespaces ou caminhos fora do PGDATA, revise as opções --tablespace-map e de link.","untested":true,"tags":["pgbackrest","restore","restore","recovery","disaster recovery"]},{"id":"pgbackrest-pitr-restore","task":"Restaurar para um ponto no tempo com pgBackRest (PITR, --type=time)","category":"Backup e 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":"Restaura um backup concluído antes do horário de destino e reaplica o WAL apenas até o destino; target-action=pause para no destino para que você valide os dados, e pg_wal_replay_resume() faz a promoção.","when":"Para voltar ao momento imediatamente anterior a um erro lógico como um DELETE/DROP/UPDATE acidental.","caution":"Todas as mudanças após o destino são perdidas neste cluster; quando possível, execute o PITR em um servidor separado e traga de volta apenas os dados afetados com pg_dump. Informe o fuso horário explicitamente no destino. O pgBackRest 2.24+ escolhe automaticamente um backup adequado anterior ao destino; em versões mais antigas especifique com --set um backup concluído antes do destino. Se o destino for anterior ao horário de término do backup, o restore não consegue atingir a consistência.","untested":true,"tags":["pgbackrest","pitr","point in time recovery","point in time","recovery"]},{"id":"pgbackrest-delta-restore-standby","task":"Reconstruir rapidamente um standby com delta restore do pgBackRest","category":"Backup e 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 compara os arquivos do PGDATA existente com o backup (tamanho/timestamp e checksum) e copia apenas os diferentes; --type=standby grava standby.signal e recovery-option adiciona primary_conninfo. O standby primeiro se atualiza a partir do archive e depois passa para streaming.","when":"Para transformar de volta em réplica, sem cópia completa, um standby atrasado ou com timeline divergente, ou um antigo primário em que o pg_rewind falhou.","caution":"O delta substitui/remove os arquivos diferentes ou extras do diretório de destino pelos do backup; executá-lo no servidor errado destrói os dados desse servidor. O pgBackRest se recusa a restaurar sobre um PostgreSQL em execução, mas verifique você mesmo que o serviço está parado. Guarde a senha no .pgpass em vez de no primary_conninfo.","untested":true,"tags":["pgbackrest","delta restore","rebuild standby","rebuild","replica"]},{"id":"pgbackrest-retention-expire","task":"Configurar a retenção do pgBackRest e executar o expire","category":"Backup e 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":"Define quantos backups full/diff manter (count) ou por quantos dias manter backups full (time); o expire apaga os backups fora da política, os backups diff/incr que dependem deles e o arquivo de WAL que não é mais necessário.","when":"Para manter o tamanho do repositório sob controle e garantir o requisito de janela de RPO/PITR (ex.: poder voltar 14 dias).","caution":"A janela de PITR é limitada pelo backup full mais antigo retido; com fulls semanais e retention-full=2, você consegue voltar no máximo cerca de 2 semanas. repo1-retention-archive segue a retenção de full por padrão; defini-lo mais baixo deixa os backups mais antigos utilizáveis apenas até o seu ponto de consistência. O expire não pode ser desfeito.","untested":true,"tags":["pgbackrest","retention","retention period","expire","backup cleanup"]},{"id":"standby-manual-config","task":"Configurar um standby manualmente (standby.signal + primary_conninfo)","category":"Replicação","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":"O arquivo standby.signal faz o servidor iniciar como standby; primary_conninfo define a conexão de streaming e primary_slot_name o replication slot a usar. No PG13+ primary_conninfo e primary_slot_name podem ser alterados com reload.","when":"Para transformar em standby um diretório de dados preparado sem pg_basebackup -R (pgBackRest, snapshot, rsync) ou para apontar um standby existente para um novo primário.","caution":"O slot deve ser criado antes no primário (pg_create_physical_replication_slot), senão o walreceiver continua falhando. Coloque a senha no ~/.pgpass em vez de no conninfo. application_name deve coincidir exatamente com o nome em synchronous_standby_names. Se o standby.signal for esquecido, o servidor inicia como primário e passa para uma timeline separada.","since":"PostgreSQL 12","note":"Antes do PostgreSQL 12 essas configurações ficavam no recovery.conf (standby_mode = on); o PG12 as moveu para standby.signal e postgresql.conf. Antes do PG13, mudar o primary_conninfo exigia restart.","tags":["standby","standby.signal","primary_conninfo","replica setup","streaming"]},{"id":"standby-wal-receiver-lag","task":"Monitorar o lag de recebimento e de replay de WAL no standby (pg_stat_wal_receiver)","category":"Replicação","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":"Mostra quanto WAL o standby recebeu e quanto aplicou (acúmulo de replay), a idade da última transação reaplicada, se o replay está pausado e o estado da conexão do walreceiver (qual primário, slot, timeline, horário da última mensagem).","when":"Para diagnosticar lag quando o primário não está acessível ou em standbys em cascata; em um alerta de 'standby atrasado', para separar um problema de rede (recebimento) de um problema de replay (I/O, conflito).","caution":"Se pg_stat_wal_receiver não retornar linhas, o standby não está em streaming (alimentado pelo archive ou desconectado). last_replay_age cresce mesmo quando o primário não tem gravações; interprete-o junto com a diferença entre receive_lsn/replay_lsn. Se o acúmulo de replay crescer enquanto o recebimento avança, o standby tem consultas longas (max_standby_streaming_delay) ou um gargalo de I/O.","since":"PostgreSQL 14","note":"pg_get_wal_replay_pause_state() foi adicionado no PostgreSQL 14; antes disso só existia pg_is_wal_replay_paused(). O restante da consulta funciona no PG10+.","tags":["standby","replication lag","wal receiver","replay","lag"]},{"id":"pg-rewind-old-primary","task":"Reintegrar o antigo primário como réplica após um failover com pg_rewind","category":"Replicação","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":"Torna o diretório de dados do antigo primário consistente com o novo primário copiando do novo primário os blocos alterados após o ponto de divergência da timeline; transforma-o em réplica em minutos, sem basebackup completo.","when":"Quando o antigo primário volta após um failover/promote e fica atrás da nova timeline com mudanças divergentes.","caution":"As transações deixadas no antigo primário após o failover que nunca chegaram ao novo primário são removidas definitivamente. O pg_rewind também copia da origem os arquivos de configuração (postgresql.conf, postgresql.auto.conf, pg_hba.conf); corrija as configurações de porta e de slot antes de iniciar. Se o WAL necessário desde o ponto de divergência não estiver mais na origem, busque-o do archive com -c (--restore-target-wal). A conexão de origem precisa de um superusuário ou de uma role com os privilégios de função listados na documentação. No Patroni isso é feito automaticamente com use_pg_rewind: true.","since":"PostgreSQL 13","note":"-R/--write-recovery-conf e -c/--restore-target-wal foram adicionados no PostgreSQL 13; no PG13+ o pg_rewind executa ele mesmo o crash recovery em um destino parado de forma não limpa (desabilite com --no-ensure-shutdown). O pg_rewind existe desde o 9.5.","tags":["pg_rewind","after failover","old primary","timeline","rejoin"]},{"id":"sync-standby-quorum","task":"Configurar replicação síncrona com quorum (ANY) ou prioridade (FIRST)","category":"Replicação","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":"Define quais standbys devem confirmar antes que um commit seja concluído: ANY N é baseado em quorum (sync_state = quorum), FIRST N torna síncronos (sync) os N primeiros standbys conectados na ordem da lista e os demais standbys em espera (potential). O nível de confirmação é definido por synchronous_commit (remote_write, on, remote_apply).","when":"Em sistemas que exigem nenhuma perda de dados no failover (RPO = 0); com vários standbys, ANY é preferível para que a falha de um único standby não interrompa as gravações.","caution":"Se o número exigido de standbys síncronos não estiver conectado, os commits travam sem erro e a aplicação congela. Os nomes da lista devem coincidir com o application_name dos standbys. Em uma emergência, uma única sessão pode contornar isso com SET synchronous_commit = local. Sob o Patroni, gerencie isso com synchronous_mode em vez de configurar manualmente.","since":"PostgreSQL 10","note":"A sintaxe FIRST foi adicionada no PostgreSQL 9.6 e ANY (quorum commit) no PostgreSQL 10; a forma 'N (a, b)' sem palavra-chave significa FIRST.","tags":["synchronous replication","synchronous_standby_names","quorum","rpo","sync"]},{"id":"slot-retained-wal-monitor","task":"Monitorar o WAL retido por replication slots e remover com segurança um slot abandonado","category":"Replicação","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":"Mostra quanto WAL cada slot retém no primário, o wal_status (reserved/extended/unreserved/lost), a margem segura restante sob max_slot_wal_keep_size (safe_wal_size) e os valores xmin/catalog_xmin que seguram o VACUUM; a segunda consulta remove o slot apenas se ele não estiver em uso.","when":"Quando o diretório pg_wal cresce, em um alerta de disco e no monitoramento de rotina; para limpeza de slots após um standby ou subscriber ter sido removido definitivamente.","caution":"Um slot inativo retém WAL sem limite e pode encher o disco e parar o primário; um slot que segura xmin/catalog_xmin também bloqueia a limpeza de dead tuples e cria risco de bloat/wraparound. Remover um slot impede que seu standby/subscriber continue de onde parou (é preciso reconstruir); verifique o dono antes de remover. Execute no primário (pg_current_wal_lsn() falha em um standby).","since":"PostgreSQL 13","note":"wal_status e safe_wal_size foram adicionados no PostgreSQL 13. O PG16 adicionou conflicting para slots lógicos e o PG17 adicionou inactive_since; inactive_since é o indicador mais direto de um slot abandonado.","tags":["replication slot","wal accumulation","disk full","drop slot","retained wal"]},{"id":"slot-max-wal-keep-size","task":"Limitar o WAL que os slots podem reter (max_slot_wal_keep_size)","category":"Replicação","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":"Define um limite superior para o WAL que os replication slots podem manter no pg_wal (padrão -1 = ilimitado); quando excedido, o checkpoint remove o WAL antigo e o slot passa a wal_status = 'lost'. O parâmetro tem efeito com reload.","when":"Como proteção em todo cluster que usa slots, contra o risco de um standby ou subscriber desconectado encher o disco do primário e parar o sistema inteiro.","caution":"O limite prioriza manter o primário vivo em detrimento do dono do slot: um standby com slot 'lost' precisa ser reconstruído e uma subscription lógica recriada. Escolha um valor abaixo do espaço livre do disco do pg_wal, mas maior que o WAL gerado durante a indisponibilidade mais longa esperada. Se o wal_status for 'unreserved', o slot está prestes a ser perdido; dispare um alerta.","since":"PostgreSQL 13","note":"max_slot_wal_keep_size foi adicionado no PostgreSQL 13; antes disso não havia como limitar o WAL retido por slots e a única proteção era monitorar e remover slots manualmente.","tags":["max_slot_wal_keep_size","slot limit","wal accumulation","disk protection","replication slot"]},{"id":"logical-add-table-refresh","task":"Adicionar uma tabela a uma publication e atualizar a subscription (REFRESH PUBLICATION)","category":"Replicação lógica","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":"Adiciona uma nova tabela à publication no publisher; no subscriber, REFRESH PUBLICATION inclui as novas tabelas na subscription e inicia a cópia inicial (tablesync) com copy_data = true. srsubstate: i = init, d = data copy, f = copy finished, s = synchronized, r = ready.","when":"Quando uma nova tabela é adicionada a uma replicação lógica em execução ou uma tabela é removida da publication.","caution":"Mesmo com publications FOR ALL TABLES ou TABLES IN SCHEMA, o subscriber não pega uma nova tabela até que o REFRESH seja executado. O REFRESH falha se a tabela não existir no subscriber; DDL não é replicado. Se uma tabela publicada não tiver PRIMARY KEY ou REPLICA IDENTITY, UPDATE/DELETE falham no publisher. A cópia inicial de uma tabela grande segura um slot e um snapshot no publisher por muito tempo.","since":"PostgreSQL 10","note":"ADD TABLES IN SCHEMA foi adicionado no PostgreSQL 15 (o PG15 também adicionou filtros de linha com WHERE e listas de colunas).","tags":["logical replication","publication","add table","refresh publication","subscription"]},{"id":"logical-subscription-monitor","task":"Monitorar a replicação lógica (pg_stat_subscription, erros de apply, lag de slot)","category":"Replicação lógica","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":"No subscriber, mostra os workers de apply/tablesync, o LSN recebido e confirmado, o horário da última mensagem e as contagens cumulativas de erros de apply/sync; no publisher, mostra o WAL não confirmado (confirmed_flush) do slot lógico e o total de WAL que ele retém.","when":"Durante a configuração da replicação lógica, para confirmar que o lag se aproxima de zero na virada de um upgrade/migração e para alertas de erro.","caution":"Se pid for NULL, o apply worker não está rodando (subscription desabilitada ou falhando e reiniciando repetidamente); verifique o log do servidor. Um apply_error_count crescente indica um conflito. Uma subscription parada acumula WAL e catalog_xmin no publisher; monitore o disco e o bloat do catálogo no publisher.","since":"PostgreSQL 15","note":"pg_stat_subscription_stats foi adicionado no PostgreSQL 15 e pg_stat_subscription.leader_pid no PG16 (parallel apply); o PG17 adicionou a coluna worker_type. As colunas básicas de pg_stat_subscription existem desde o PG10.","tags":["logical replication","subscription monitoring","pg_stat_subscription","apply error","lag"]},{"id":"logical-conflict-skip","task":"Resolver um conflito de replicação lógica (disable_on_error, SKIP)","category":"Replicação lógica","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":"Quando um erro como chave duplicada, linha ausente ou problema de permissão interrompe o apply no subscriber: disable_on_error desabilita a subscription automaticamente; corrija os dados conflitantes e faça ENABLE, ou faça SKIP de toda a transação remota identificada pelo LSN 'finished at' no log.","when":"Quando o apply worker falha e continua reiniciando por causa de gravações diretas no subscriber, de uma cópia inicial incompleta ou de gravações bidirecionais.","caution":"SKIP também descarta as mudanças não conflitantes daquela transação e os dois lados divergem definitivamente; prefira corrigir os dados e compare a tabela após um SKIP. Até que o conflito seja resolvido, o slot no publisher continua acumulando WAL. Impeça gravações da aplicação nas tabelas do subscriber com privilégios.","since":"PostgreSQL 15","note":"SKIP e disable_on_error foram adicionados no PostgreSQL 15; antes disso, o mesmo era feito avançando a origin no subscriber com pg_replication_origin_advance() (mais arriscado).","tags":["logical replication","conflict","conflict","skip","duplicate key"]},{"id":"logical-sync-sequences","task":"Sincronizar valores de sequences com o subscriber na replicação lógica","category":"Replicação lógica","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":"Como a replicação lógica não transporta valores de sequences (incluindo identity), isto lê o último valor de cada sequence no publisher e gera e aplica diretamente comandos setval que definem o mesmo valor no subscriber.","when":"Na virada de um upgrade/migração via replicação lógica, logo antes de apontar a aplicação para o subscriber.","caution":"Se executado enquanto o publisher ainda recebe gravações, os valores ficam desatualizados imediatamente e surgem erros de chave duplicada após a virada; execute após parar as gravações ou adicione uma margem de segurança. DDL também não é replicado: aplique as mudanças de schema (ALTER TABLE, novos índices) nos dois lados separadamente, primeiro no subscriber. pg_sequences retorna last_value NULL para sequences que você não pode ler; execute o comando como dono ou superusuário.","since":"PostgreSQL 10","tags":["logical replication","sequence","setval","ddl not replicated","cutover"]},{"id":"logical-orphan-slot-cleanup","task":"Remover uma subscription e limpar um slot lógico órfão no publisher","category":"Replicação lógica","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":"Remove a subscription sem tocar no slot remoto (slot_name = NONE); depois encontra e remove os slots lógicos no publisher que não têm mais consumidor, além de slots de tablesync remanescentes.","when":"Quando uma subscription precisa ser removida com o publisher inacessível, após o fim de uma migração ou quando um slot lógico com active = false está acumulando WAL no publisher.","caution":"Um slot lógico órfão retém tanto WAL quanto catalog_xmin: o disco enche e os catálogos do sistema incham. No entanto, remover o slot impede que aquela subscription continue; antes de remover, verifique que nenhum subscriber (incluindo um em outro servidor) usa este slot. Um slot ativo não pode ser removido; o walsender conectado deve ser encerrado antes.","since":"PostgreSQL 10","tags":["logical replication","slot cleanup","drop subscription","orphaned slot","catalog_xmin"]},{"id":"pg-upgrade-link-runbook","task":"Upgrade de versão major com pg_upgrade --link (runbook de ponta a ponta)","category":"Upgrade","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":"Primeiro valida a compatibilidade com --check e depois faz o upgrade major em minutos, independentemente do tamanho dos dados, criando hard links dos arquivos de dados do cluster antigo para a nova versão em vez de copiá-los; em seguida coleta estatísticas em etapas e remove o cluster antigo.","when":"Para migrar no próprio local um cluster grande para uma nova versão major com uma indisponibilidade aceitavelmente curta (minutos).","caution":"Com --link, depois que o novo cluster é iniciado o cluster antigo não pode mais ser usado com segurança; a única forma de voltar é um backup feito antes do upgrade. Os diretórios de dados antigo e novo devem estar no mesmo file system. Os planos podem ser ruins no novo cluster até o analyze terminar. Se você usa pgBackRest, execute stanza-upgrade e faça um novo backup full imediatamente; backups da versão antiga não podem ser restaurados no novo cluster.","note":"Standbys físicos não são atualizados com pg_upgrade: após o upgrade do primário, atualize-os com o método rsync --hard-links --size-only da documentação ou reconstrua-os. Slots lógicos não são migrados antes do PG17 (são quando o cluster antigo é PG17+); estatísticas do planner não são migradas antes do PG18.","tags":["pg_upgrade","major upgrade","version upgrade","link","check"]},{"id":"logical-upgrade-near-zero-downtime","task":"Upgrade de versão major com downtime quase zero via replicação lógica","category":"Upgrade","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":"Cria um cluster vazio na nova versão, move o schema e transmite continuamente os dados da versão antiga com replicação lógica; apenas a etapa final de virada (parar gravações, sincronizar sequences, redirecionar) causa uma indisponibilidade curta. Uma segunda replicação na direção inversa pode manter aberto um caminho de rollback.","when":"Quando a indisponibilidade exigida pelo pg_upgrade é inaceitável, ao migrar para novo hardware/SO ao mesmo tempo ou ao pular várias versões major.","caution":"DDL, sequences, large objects e o conteúdo de materialized views não são replicados; congele o schema durante a migração. Em tabelas sem primary key/replica identity, UPDATE/DELETE falham no publisher. Em bancos grandes a cópia inicial demora e segura WAL e catalog_xmin no servidor antigo. Cada banco precisa de sua própria publication/subscription. Compare contagens de linhas/checksums antes da virada.","since":"PostgreSQL 10","note":"pg_createsubscriber, adicionado no PostgreSQL 17, converte um standby físico em subscriber lógico sem cópia inicial, eliminando o tempo de cópia inicial em bancos grandes.","tags":["upgrade","logical replication","zero downtime migration","major upgrade","cutover"]},{"id":"pgbouncer-show-pools-stats","task":"Mostrar pools, estatísticas e conexões do 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":"Para cada pool de banco/usuário, mostra os clientes ativos e em espera (cl_active, cl_waiting), as conexões de servidor ativas/ociosas (sv_active, sv_idle), o maior tempo de espera (maxwait) e os contadores de consultas/transações.","when":"Quando a aplicação relata falhas/timeouts de conexão, para dimensionar pools e para ver as conexões ativas antes de uma manutenção.","caution":"O console de administração não aceita SQL; executa apenas comandos do PgBouncer. Se cl_waiting continuar alto, verifique primeiro o lado do servidor em busca de transações longas ou locks; aumentar default_pool_size às cegas empurra o PostgreSQL para o limite de max_connections e para pressão de memória. Os valores de SHOW STATS são cumulativos; as médias se referem ao intervalo stats_period.","untested":true,"tags":["pgbouncer","show pools","connection pooling","statistics","connection pool"]},{"id":"pgbouncer-pause-resume-reload","task":"Segurar conexões durante a manutenção com PgBouncer (PAUSE/RESUME) e recarregar a configuração (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 esvazia as conexões do lado do PostgreSQL sem derrubar as conexões dos clientes e enfileira as novas consultas; RESUME libera a fila novamente. Assim, um restart curto do primário ou um switchover aparece para a aplicação como um breve atraso em vez de erros.","when":"Durante janelas de manutenção curtas (switchover, restart de versão minor, restart por parâmetro) e ao aplicar mudanças no pgbouncer.ini/userlist.","caution":"PAUSE só retorna depois que todas as transações ativas terminam; uma consulta longa segura o PAUSE (encerre essa sessão no PostgreSQL se necessário). Os clientes em espera recebem um erro quando query_wait_timeout (padrão 120 s) expira; conclua a manutenção dentro desse tempo. Esquecer o RESUME após o PAUSE é uma indisponibilidade total. Algumas configurações (listen_addr, listen_port etc.) não mudam com RELOAD e exigem restart.","untested":true,"tags":["pgbouncer","pause","resume","reload","maintenance"]},{"id":"pgbouncer-pool-mode","task":"Escolha do pool_mode do PgBouncer e dimensionamento básico","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":"O modo session vincula um cliente a uma conexão de servidor durante toda a vida da conexão; o modo transaction atribui uma conexão de servidor apenas durante uma transação e atende milhares de clientes com dezenas de conexões PostgreSQL; o modo statement devolve a conexão após cada consulta e não permite transações com vários comandos. O pool_mode também pode ser sobreposto por banco.","when":"Modo transaction para aplicações OLTP/microsserviços que abrem muitas conexões de vida curta; modo session para trabalhos que dependem do estado da sessão (relatórios, migrações, serviços que usam LISTEN).","caution":"No modo transaction o estado da sessão não é preservado entre transações: SET (exceto SET LOCAL), advisory locks em nível de sessão, LISTEN, cursores WITH HOLD, tabelas temporárias entre transações e PREPARE em nível de SQL não são confiáveis. Prepared statements em nível de protocolo só são suportados com PgBouncer 1.21+ e max_prepared_statements > 0 (padrão 200 desde o 1.24, 0 antes). default_pool_size vezes o número de pares (banco, usuário) não deve exceder o max_connections do PostgreSQL (menos a margem de 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":"Encontrar as consultas mais caras (pg_stat_statements: tempo total e médio)","category":"Desempenho","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":"Lista as consultas normalizadas que mais consomem tempo do servidor no banco atual, com sua participação no total; a segunda consulta lista as mais lentas por chamada.","when":"Primeira parada quando a carga de CPU/IO sobe ou usuários relatam 'o banco está lento'; para decidir por onde o tuning deve começar.","caution":"O pg_stat_statements não coleta nada até ser adicionado a shared_preload_libraries, o servidor ser reiniciado e CREATE EXTENSION ser executado no banco. Os valores são cumulativos desde o último reset. Um stddev_ms alto em relação ao mean_ms indica que o plano ou a distribuição dos dados varia entre as chamadas. mean_plan_time só é preenchido com pg_stat_statements.track_planning = on (padrão off; habilitá-lo adiciona overhead). Ver os textos de consulta de outros usuários exige superusuário ou a role pg_read_all_stats.","since":"PostgreSQL 13","note":"No PostgreSQL 13 as colunas total_time/mean_time foram renomeadas para total_exec_time/mean_exec_time e os tempos de planejamento (total_plan_time) ganharam colunas separadas; use os nomes antigos no PG12 e anteriores.","tags":["pg_stat_statements","slow query","most expensive query","top sql","performance","query tuning"]},{"id":"pgss-io-temp-heavy","task":"Encontrar as consultas que geram I/O de disco, arquivos temporários e WAL (pg_stat_statements)","category":"Desempenho","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":"Mostra as consultas que mais leem blocos fora dos shared buffers, mais gravam em arquivos temporários (sorts/hashes que não cabem no work_mem) e mais geram WAL, junto com sua taxa de acerto de cache.","when":"Para encontrar a consulta responsável quando a latência de leitura de disco sobe, disparam alertas de arquivos temporários (log_temp_files) ou o volume de WAL cresce de repente.","caution":"shared_blks_read também conta leituras atendidas pelo page cache do SO; o tempo real de disco exige track_io_timing = on (meça antes o overhead com pg_test_timing). Se temp_written estiver alto, a correção costuma ser aumentar o work_mem por role/sessão ou corrigir a consulta/índice; aumentar o work_mem globalmente aumenta o risco de memória.","since":"PostgreSQL 13","note":"As colunas wal_bytes/wal_records chegaram no PG13. No PG17 blk_read_time/blk_write_time foram renomeadas para shared_blk_read_time/shared_blk_write_time e local_blk_*_time foi adicionado.","tags":["pg_stat_statements","io","temp files","temp_blks_written","work_mem","wal"]},{"id":"pgss-reset","task":"Zerar as estatísticas do pg_stat_statements (todas ou de uma única consulta)","category":"Desempenho","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":"Zera os contadores do pg_stat_statements totalmente ou por usuário/banco/queryid; pg_stat_statements_info mostra o horário do último reset e quantas entradas foram descartadas por falta de espaço.","when":"Para iniciar uma medição limpa antes de uma mudança de tuning (índice, parâmetro, deploy) ou para medir isoladamente o novo plano de uma única consulta.","caution":"Um reset não pode ser desfeito; ferramentas de monitoramento/APM que dependem de contadores cumulativos mostrarão uma lacuna, então tire um snapshot antes (veja a receita de regressão de plano). Se dealloc continuar crescendo, pg_stat_statements.max é pequeno demais (alterá-lo exige restart). Por padrão só superusuários podem executá-lo; conceda com GRANT EXECUTE ON FUNCTION.","since":"PostgreSQL 14","note":"O reset parametrizado (userid, dbid, queryid) chegou no PG12, a view pg_stat_statements_info no PG14. O PG17 adicionou um quarto parâmetro, minmax_only: pg_stat_statements_reset(0, 0, 0, true) zera apenas os tempos min/max; as colunas stats_since e minmax_stats_since também são do PG17.","tags":["pg_stat_statements","reset","clear statistics","queryid","statistics","baseline"]},{"id":"auto-explain-setup","task":"Registrar os planos de execução de consultas lentas com auto_explain","category":"Desempenho","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":"Grava no log do servidor o plano de execução das consultas que excedem o limite (com contagens reais de linhas e dados de buffer quando log_analyze está on); captura o plano produzido com os parâmetros reais da aplicação.","when":"Quando uma consulta só é lenta a partir da aplicação ou com parâmetros específicos e não pode ser reproduzida com um EXPLAIN manual; para capturar mudanças de plano intermitentes.","caution":"log_analyze = on adiciona overhead de instrumentação a toda consulta amostrada, incluindo as abaixo do limite; log_timing = off e sample_rate < 1 o reduzem. log_min_duration = 0 inunda o log em produção. ALTER SYSTEM SET session_preload_libraries sobrescreve o valor existente; verifique SHOW session_preload_libraries antes. session_preload_libraries não afeta sessões existentes; carregá-lo em todo processo exige shared_preload_libraries mais um restart.","note":"auto_explain é um módulo contrib e não precisa de CREATE EXTENSION. As opções log_wal (PG13+) e log_settings (PG12+) também estão disponíveis.","tags":["auto_explain","execution plan","slow query","log","plan capture","explain"]},{"id":"explain-analyze-buffers-wal","task":"Ler um plano em profundidade com EXPLAIN (ANALYZE, BUFFERS, SETTINGS, WAL)","category":"Desempenho","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":"Retorna o plano com estatísticas reais de execução: BUFFERS mostra por nó os blocos shared hit/read/dirtied e temp, SETTINGS mostra parâmetros fora do padrão que afetam o planejamento, WAL mostra os registros/bytes de WAL gerados.","when":"Para analisar a diferença entre linhas estimadas e reais, sorts/hashes que transbordam para disco (Sort Method: external merge, temp read/written) e o custo de WAL de DML.","caution":"ANALYZE realmente executa o comando; sempre rode DML dentro de BEGIN/ROLLBACK (triggers e incrementos de sequence ainda acontecem). Dicas de leitura: uma diferença de 10x ou mais entre 'rows' estimado e 'actual rows' aponta para um problema de estatísticas; em nós dentro de loops, tempo e linhas são por loop, multiplique por loops para o total; 'Heap Fetches' alto em um Index Only Scan significa visibility map desatualizado, e 'Workers Planned' > 'Workers Launched' significa que o pool de workers se esgotou. Use TIMING OFF onde o overhead de tempo for alto; COSTS OFF também esconde a seção de JIT.","since":"PostgreSQL 13","note":"A opção SETTINGS chegou no PG12, WAL no PG13. O PG16 adicionou GENERIC_PLAN, o PG17 adicionou SERIALIZE e MEMORY; no PG18 BUFFERS vem ligado por padrão com ANALYZE.","tags":["explain analyze","buffers","execution plan","reading plans","wal","performance"]},{"id":"plan-regression-queryid","task":"Detectar regressões de plano por queryid (comparação de snapshots do pg_stat_statements)","category":"Desempenho","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":"Salva em uma tabela os contadores cumulativos do pg_stat_statements e os compara com o estado posterior por queryid; mostra o tempo médio e os buffers por chamada das chamadas feitas após o snapshot ao lado dos valores antigos.","when":"Para encontrar a consulta cujo plano mudou após um deploy, upgrade major, atualização de estatísticas ou mudança de parâmetro ('ontem estava rápido, hoje está lento').","caution":"Se pg_stat_statements_reset() for executado entre o snapshot e a comparação, ou se entradas forem descartadas por falta de espaço (dealloc), os deltas não têm sentido; verifique pg_stat_statements_info.stats_reset. Um aumento de buffers por chamada é um sinal mais confiável de mudança de plano do que um aumento de tempo, porque independe do cache. Para confirmar o plano, faça EXPLAIN da consulta com parâmetros reais ou use auto_explain; o PostgreSQL não tem fixação de plano nativa (é necessária a extensão pg_hint_plan). Remova a tabela de snapshot ao terminar.","since":"PostgreSQL 14","note":"pg_stat_activity.query_id e o parâmetro compute_query_id chegaram no PG14 (padrão auto: calculado quando o pg_stat_statements está carregado). A linha 'Query Identifier' na saída do EXPLAIN VERBOSE mostra o mesmo valor. Os passos 1 e 2 também funcionam no PG13.","tags":["plan regression","queryid","pg_stat_statements","snapshot","plan change","performance"]},{"id":"parallel-query-usage","task":"Verificar a capacidade de consulta paralela e o uso atual de workers","category":"Desempenho","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":"Mostra os limites de consulta paralela e quantos parallel workers cada processo leader está usando agora; demonstra a configuração de número de workers por tabela.","when":"Quando consultas analíticas estão mais lentas que o esperado, o plano mostra 'Workers Planned' > 'Workers Launched' ou núcleos de CPU ficam ociosos.","caution":"max_parallel_workers é limitado por max_worker_processes (exige restart), e esse pool é compartilhado com os workers de replicação lógica e outros background workers. Em OLTP, um max_parallel_workers_per_gather alto satura a CPU sob concorrência; cada worker também usa seu próprio work_mem. Consultas que gravam dados ou bloqueiam linhas (exceto CREATE TABLE AS / SELECT INTO), cursores e consultas que chamam funções PARALLEL UNSAFE não recebem planos paralelos. ALTER TABLE ... SET (parallel_workers) obtém um breve ShareUpdateExclusiveLock.","since":"PostgreSQL 13","note":"pg_stat_activity.leader_pid chegou no PG13; antes disso, os parallel workers só aparecem como backend_type = 'parallel worker' e não podem ser ligados ao seu leader.","tags":["parallel query","parallel worker","leader_pid","max_parallel_workers","gather","cpu"]},{"id":"jit-impact-check","task":"Medir o impacto da compilação JIT no tempo de consulta","category":"Desempenho","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":"Mostra, por consulta, a participação do tempo de compilação JIT (generation, inlining, optimization, emission) no tempo de execução; mede o efeito líquido executando a mesma consulta com JIT ligado e desligado.","when":"Quando consultas OLTP curtas ou de relatório mostram atrasos inexplicáveis de dezenas a centenas de ms; especialmente em tabelas muito particionadas, em que estimativas de custo infladas disparam o JIT.","caution":"O JIT só entra em ação quando o custo do plano excede jit_above_cost (padrão 100000); com estimativas de custo infladas, a compilação pode demorar mais que a execução em consultas curtas. Em vez de desabilitá-lo globalmente, considere primeiro ALTER ROLE ... SET jit = off para a role/banco afetado ou aumentar o jit_above_cost. EXPLAIN (ANALYZE, COSTS OFF) não imprime a seção de JIT. Se o PostgreSQL foi compilado sem suporte a LLVM, o JIT nunca é usado; verifique com SELECT pg_jit_available();","since":"PostgreSQL 15","note":"As colunas jit_* foram adicionadas ao pg_stat_statements no PG15; o PG17 adicionou jit_deform_count/jit_deform_time. O JIT foi introduzido no PG11 e vem ligado por padrão desde o PG12.","tags":["jit","llvm","jit_above_cost","pg_stat_statements","compilation time","performance"]},{"id":"blocking-tree","task":"Montar a árvore de bloqueios (encontrar o bloqueador raiz)","category":"Sessões","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":"Segue recursivamente a cadeia de espera com pg_blocking_pids(); a partir do bloqueador raiz (que não espera ninguém), mostra cada sessão em espera como uma árvore indentada com os PIDs que a bloqueiam diretamente e a idade de sua transação.","when":"Quando a aplicação vê timeouts em massa ou filas se acumulando; para encontrar, entre dezenas de sessões em espera, a única sessão raiz que exige intervenção.","caution":"A raiz costuma ser uma sessão 'idle in transaction' esquecida que segura o lock; a coluna query mostra o ÚLTIMO comando dessa sessão, não o que obteve o lock. Um DDL esperando ACCESS EXCLUSIVE também bloqueia SELECTs simples enfileirados atrás dele e aparece como nó intermediário. pg_blocking_pids() trava brevemente o lock manager; não execute esta consulta em um loop apertado. Uma sessão alcançável por vários ramos é mostrada uma única vez, em seu nível mais profundo.","since":"PostgreSQL 9.6","tags":["blocking","lock tree","lock chain","pg_blocking_pids","blocking session","lock"]},{"id":"lock-wait-detail","task":"Inspecionar em detalhe as esperas de lock por objeto e modo de lock (pg_locks)","category":"Sessões","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":"Para cada solicitação de lock não concedida (granted = false), mostra o objeto alvo (tabela, transaction id etc.), o modo solicitado, o PID bloqueador e seu modo, se o bloqueador de fato detém o lock e o tempo aproximado de espera.","when":"Para entender qual tabela e qual conflito de modo de lock causam o bloqueio; ex.: um DDL esperando AccessExclusiveLock ou um lock de linha aparecendo como espera de transactionid.","caution":"Como a correspondência usa pg_blocking_pids(), apenas solicitações realmente conflitantes são listadas. blocker_holds = false significa que o bloqueador ainda não detém o lock, mas está à frente na fila com um modo conflitante (lock queue). locktype = 'transactionid' é um conflito em nível de linha: quem espera aguarda até que termine a transação que modificou a linha; a própria linha não aparece em pg_locks. pg_locks pode ter milhares de linhas em sistemas grandes; não execute isto com frequência. waiting_for é uma aproximação baseada em state_change.","since":"PostgreSQL 9.6","tags":["pg_locks","lock wait","lock waiting","accessexclusivelock","transactionid","lock"]},{"id":"long-idle-transactions","task":"Encontrar transações longas e 'idle in transaction'","category":"Sessões","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":"Mostra as sessões cuja transação aberta tem mais de 5 minutos ou que estão ociosas dentro de uma transação; com a idade da transação, o tempo no estado atual, o XID atribuído e a idade do xmin que seguram.","when":"Quando o bloat cresce, o VACUUM reporta 'dead row versions cannot be removed yet', durante esperas de lock ou quando se suspeita de vazamento no pool de conexões.","caution":"Transações longas (especialmente REPEATABLE READ/SERIALIZABLE ou as que mantêm cursores abertos) seguram o horizonte de limpeza do VACUUM (xmin horizon) via backend_xmin, causando bloat e envelhecimento de XID em todo o banco. 'idle in transaction (aborted)' é uma sessão que teve um erro e está esperando ROLLBACK. Correção permanente: idle_in_transaction_session_timeout por role e limites de transação corretos na aplicação.","tags":["long transaction","idle in transaction","xmin","bloat","session","long running"]},{"id":"terminate-idle-in-transaction","task":"Encerrar em massa, de forma controlada, sessões 'idle in transaction' longas","category":"Sessões","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":"Primeiro lista as sessões que deixaram uma transação aberta e ociosa por um tempo determinado e depois as encerra; o parâmetro timeout espera até que o processo tenha de fato saído (ou o timeout expire).","when":"Para intervenção de emergência quando sessões esquecidas segurando locks causam bloqueio ou seguram o xmin horizon e travam o VACUUM.","caution":"pg_cancel_backend não faz nada em uma sessão 'idle in transaction' (não há consulta em execução para cancelar); é necessário pg_terminate_backend, e todas as mudanças não confirmadas sofrem rollback. Restrinja o filtro por usename/application_name; exclua sessões de replicação, backup e monitoramento. Os pools de conexões reabrirão as conexões encerradas. Se o timeout expirar, a função emite um aviso e retorna false. Como correção permanente, defina idle_in_transaction_session_timeout por role.","since":"PostgreSQL 14","note":"O pg_terminate_backend(pid, timeout) com dois argumentos chegou no PG14; antes disso só existe pg_terminate_backend(pid), que retorna logo após enviar o sinal.","tags":["pg_terminate_backend","idle in transaction","terminate session","kill session","bulk","lock"]},{"id":"role-timeouts","task":"Definir statement_timeout / lock_timeout por role e banco","category":"Sessões","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":"Torna os parâmetros de timeout persistentes em nível de role (e opcionalmente de banco), para que cada carga rode com seus próprios limites sem mexer na configuração global.","when":"Para evitar que consultas desgovernadas esgotem recursos, que filas de DDL/lock congelem a aplicação e que transações esquecidas gerem bloat.","caution":"As configurações valem apenas para NOVAS sessões; recicle as conexões existentes do pool. Os usuários podem sobrepor o valor com SET na própria sessão; isso não é uma barreira de segurança. Não defina statement_timeout globalmente no postgresql.conf: jobs de manutenção como pg_dump, VACUUM e CREATE INDEX também são cancelados. Precedência: role+banco > role > banco > postgresql.conf.","note":"idle_in_transaction_session_timeout chegou no PG9.6, idle_session_timeout no PG14, transaction_timeout no PG17.","tags":["statement_timeout","lock_timeout","idle_in_transaction_session_timeout","alter role","query timeout","timeout"]},{"id":"ddl-lock-timeout-retry","task":"Aplicar DDL com segurança usando lock_timeout e novas tentativas (evitar filas de lock)","category":"Sessões","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":"Evita que um DDL que precisa de ACCESS EXCLUSIVE espere indefinidamente quando não consegue o lock e bloqueie toda consulta que se enfileira atrás dele (lock queue); faz novas tentativas em intervalos curtos.","when":"Ao aplicar em produção, em tabelas movimentadas, mudanças rápidas mas que travam muito, como ALTER TABLE, CREATE/DROP TRIGGER, ATTACH PARTITION ou RENAME.","caution":"Sem lock_timeout, um ALTER TABLE enfileirado atrás de um único SELECT longo também faz toda leitura/gravação seguinte esperar e pode esgotar o pool de conexões em minutos. lock_timeout limita apenas a espera pelo lock; não limita o tempo de execução de DDL que reescreve a tabela (ex.: mudar o tipo de uma coluna). O bloco DO é uma única transação e mantém um snapshot entre as tentativas; para cenários de retentativa longos prefira um loop externo em shell.","tags":["lock_timeout","ddl","alter table","lock queue","retry","lock"]},{"id":"connection-usage","task":"Medir o uso de conexões em relação ao max_connections","category":"Sessões","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":"Mostra os slots de conexão usados e os que restam para usuários comuns em relação ao max_connections, a divisão por banco/usuário/aplicação/estado e os CONNECTION LIMITs configurados.","when":"Em erros 'too many clients already' / 'remaining connection slots are reserved', durante o planejamento de capacidade ou ao avaliar a necessidade de um pooler.","caution":"max_connections limita apenas os client backends; workers do autovacuum, background workers e walsenders usam slots separados. Os últimos superuser_reserved_connections slots (mais reserved_connections no PG16+) ficam fechados para usuários comuns. Em vez de elevar max_connections a centenas ou milhares, use um pooler como o PgBouncer: cada conexão é um processo separado, e os custos de memória e de snapshot crescem com o número de conexões. Muitas sessões 'idle' indicam um pool da aplicação superdimensionado. Impeça que uma aplicação desgovernada consuma todos os slots com ALTER ROLE ... CONNECTION LIMIT; mudar max_connections exige restart.","note":"O parâmetro reserved_connections e a role pg_use_reserved_connections chegaram no PG16; a consulta também funciona em versões mais antigas (o parâmetro conta como 0 quando ausente).","tags":["max_connections","connection count","connection","pooler","superuser_reserved_connections","session"]},{"id":"autovacuum-progress","task":"Acompanhar o progresso de operações autovacuum/VACUUM em execução","category":"Manutenção","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":"Mostra, para cada VACUUM em execução (worker do autovacuum ou manual), a tabela, a fase, o percentual do heap varrido/limpo, o número de passagens de vacuum de índices e o wait event; além do número de workers do autovacuum ocupados.","when":"Para estimar quando um VACUUM em uma tabela grande vai terminar, se todos os workers do autovacuum estão ocupados (tabelas esperando na fila) e se o vacuum está esperando por causa de throttling.","caution":"index_vacuum_count > 1 significa que a lista de dead tuples não coube na memória e os índices foram varridos várias vezes; aumente maintenance_work_mem/autovacuum_work_mem (antes do PG17 no máximo 1GB é usado para isso). wait = Timeout:VacuumDelay é throttling baseado em custo (autovacuum_vacuum_cost_delay/cost_limit). Não encerre um autovacuum cujo texto de consulta diga 'to prevent wraparound'; ele reinicia imediatamente. VACUUM FULL e CLUSTER aparecem em pg_stat_progress_cluster, não nesta view.","since":"PostgreSQL 9.6","note":"No PG17 as colunas max_dead_tuples/num_dead_tuples mudaram para max_dead_tuple_bytes/num_dead_item_ids e foram adicionadas indexes_total/indexes_processed; por isso a consulta usa colunas independentes de versão.","tags":["autovacuum","vacuum progress","pg_stat_progress_vacuum","vacuum","maintenance","progress"]},{"id":"xid-wraparound-risk","task":"Medir o risco de wraparound de transaction ID (idade de XID por banco e tabela)","category":"Manutenção","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":"Mostra a idade do XID não congelado mais antigo e de multixact de cada banco em relação ao autovacuum_freeze_max_age e ao limite de wraparound; no banco atual, as tabelas mais antigas (incluindo TOAST) com tamanho e horário do último vacuum.","when":"No monitoramento de rotina (limites típicos: pct_of_wraparound 50% aviso / 75% crítico), quando o log mostra 'must be vacuumed within N transactions' e para priorizar o trabalho de freeze.","caution":"Para tabelas em que pct_of_freeze_max_age passa de 100, o autovacuum inicia um vacuum obrigatório (anti-wraparound); ele é pesado em I/O e reinicia mesmo se encerrado. Se a idade não cair, a causa é quase sempre algo segurando o xmin horizon (transação longa, prepared transaction, replication slot, hot_standby_feedback); corrija isso primeiro, senão nem o VACUUM FREEZE consegue baixar a idade. Perto do limite o servidor primeiro avisa e depois se recusa a atribuir novos XIDs (gravações) quando restam apenas alguns milhões. Para um freeze direcionado: VACUUM (FREEZE, VERBOSE) <table>;","note":"O PG14 adicionou vacuum_failsafe_age / vacuum_multixact_failsafe_age (padrão 1,6 bilhão): quando uma tabela atinge essa idade, o VACUUM entra em um modo de emergência que ignora o cost delay e a limpeza de índices.","tags":["wraparound","xid age","datfrozenxid","relfrozenxid","freeze","multixact"]},{"id":"xmin-horizon-holders","task":"Encontrar quem segura o xmin horizon e impede o VACUUM de remover dead tuples","category":"Manutenção","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":"Lista, ordenadas pela idade do xmin, as quatro fontes que podem bloquear a limpeza de dead tuples: sessões que seguram snapshots, prepared transactions, replication slots e standbys que enviam hot_standby_feedback.","when":"Quando o VACUUM VERBOSE reporta 'dead row versions cannot be removed yet', o bloat continua crescendo e a idade de XID não cai.","caution":"O xmin mais antigo define o horizonte de limpeza; replication slots e o feedback de standbys afetam todos os bancos. Prepared transactions sobrevivem a restarts; verifique o dono e feche-as com COMMIT PREPARED / ROLLBACK PREPARED '<gid>'. Remover um slot não utilizado quebra o seu downstream (standby, CDC); verifique o dono antes. Executado em um standby, mostra apenas as sessões daquele standby.","tags":["xmin horizon","vacuum blocker","dead tuple","prepared transaction","replication slot","bloat"]},{"id":"pgstattuple-bloat","task":"Medir o bloat de tabelas e índices com pgstattuple","category":"Manutenção","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":"Mostra os percentuais de tuplas vivas/mortas e de espaço livre de uma tabela (estimativa rápida e exato) e o espaço recuperável; para índices B-tree, a densidade das folhas e a fragmentação.","when":"Quando a estimativa n_dead_tup em pg_stat_user_tables não basta; para embasar com dados uma decisão de pg_repack, VACUUM FULL ou REINDEX.","caution":"pgstattuple e pgstatindex leem a relação inteira e geram I/O pesado em tabelas grandes (obtêm apenas AccessShareLock). Use pgstattuple_approx primeiro. Por padrão é necessário superusuário ou a role pg_stat_scan_tables. Algum espaço livre é normal (fillfactor, espaço para HOT updates); o VACUUM o torna reutilizável, mas não reduz o arquivo; recuperá-lo exige pg_repack ou VACUUM FULL (lock ACCESS EXCLUSIVE!). Reconstrua um índice com avg_leaf_density baixo usando REINDEX CONCURRENTLY.","since":"PostgreSQL 12","note":"pgstattuple é uma extensão contrib; pgstattuple_approx chegou no PG9.5. MATERIALIZED na CTE (PG12+) impede que pgstatindex seja chamado, e falhe, em índices que não são B-tree.","tags":["bloat","pgstattuple","pgstatindex","index bloat","dead tuple","free space"]},{"id":"pg-repack-online","task":"Reorganizar uma tabela inchada sem locks longos (pg_repack)","category":"Manutenção","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":"Cria em segundo plano uma cópia compactada da tabela, captura as mudanças concorrentes em uma tabela de log por meio de um trigger e troca as tabelas no final sob um breve lock ACCESS EXCLUSIVE; ao contrário do VACUUM FULL, não bloqueia leituras/gravações durante toda a operação.","when":"Quando é preciso recuperar, em um sistema em produção, um bloat severo que o VACUUM não consegue devolver (verificado com pgstattuple).","caution":"A tabela deve ter uma PRIMARY KEY ou um índice UNIQUE em colunas NOT NULL. Precisa temporariamente de espaço em disco extra igual à tabela mais seus índices e gera WAL pesado (lag de réplicas, volume de archive). Locks ACCESS EXCLUSIVE são necessários no início e no fim; quando --wait-timeout expira, o padrão é cancelar as consultas conflitantes e, se necessário, encerrar suas sessões, enquanto --no-kill-backend pula a tabela. Não execute DDL na tabela alvo durante a execução. As versões do cliente e da extensão devem coincidir. Se for interrompido, limpe os resíduos com DROP EXTENSION pg_repack CASCADE; CREATE EXTENSION pg_repack;","note":"O pg_repack não faz parte do núcleo do PostgreSQL (pacote separado, ex.: postgresql-17-repack).","tags":["pg_repack","bloat","online","vacuum full alternative","table reorganization","repack"]},{"id":"invalid-indexes","task":"Encontrar e limpar índices INVALID","category":"Manutenção","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":"Lista, com seu tamanho, os índices inválidos deixados por execuções de CREATE INDEX CONCURRENTLY ou REINDEX CONCURRENTLY com falha e gera o comando de remoção.","when":"Após operações de índice online com falha ou canceladas, em verificações de saúde de rotina e antes de um upgrade major.","caution":"Um CREATE INDEX CONCURRENTLY / REINDEX CONCURRENTLY em andamento também aparece como INVALID; verifique pg_stat_progress_create_index antes de remover. Um índice INVALID não é usado pelas consultas, mas se indisready = true ainda é mantido em todo INSERT/UPDATE, ou seja, é puro overhead. Pode ser reconstruído com REINDEX INDEX CONCURRENTLY, mas isso falha de novo se a causa (ex.: uma violação de unicidade) não for corrigida. Resíduos de REINDEX CONCURRENTLY têm o sufixo _ccnew/_ccold. DROP INDEX CONCURRENTLY não pode ser executado dentro de um bloco de transação.","tags":["invalid index","indisvalid","create index concurrently","broken index","_ccnew","index"]},{"id":"extended-statistics","task":"Criar estatísticas estendidas para colunas correlacionadas (CREATE STATISTICS)","category":"Manutenção","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":"Ensina ao planner a correlação entre colunas (dependências funcionais, contagens de distintos combinadas, valores mais comuns conjuntos); corrige as estimativas de linhas para condições WHERE e GROUP BY com várias colunas.","when":"Quando o EXPLAIN ANALYZE mostra linhas estimadas muito abaixo das reais em filtros com várias colunas (ex.: 12 vs. 570) e, por isso, é escolhido um método de join/índice errado.","caution":"Só tem efeito após o ANALYZE. Quando o número de combinações de colunas é muito maior que o statistics target (padrão 100), a lista mcv não consegue cobrir a maioria delas, e então o mcv pode não corrigir uma estimativa que dependencies corrigiria. Verifique com EXPLAIN; se necessário retire mcv da definição ou aumente o target com ALTER STATISTICS customer_city_district_stx SET STATISTICS 1000;. dependencies só é usado em condições de igualdade/IN, ndistinct nas estimativas de GROUP BY. Toda definição alonga o ANALYZE; adicione-a apenas a grupos de colunas com erro de estimativa comprovado.","since":"PostgreSQL 12","note":"CREATE STATISTICS chegou no PG10 (ndistinct, dependencies), o tipo mcv no PG12, ALTER STATISTICS ... SET STATISTICS no PG13, estatísticas de expressões no PG14.","tags":["extended statistics","create statistics","correlation","row estimate","cardinality","analyze"]},{"id":"analyze-staleness","task":"Encontrar tabelas com estatísticas desatualizadas (estratégia de ANALYZE)","category":"Manutenção","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":"Mostra o número de linhas modificadas desde o último ANALYZE, sua proporção em relação às linhas vivas e o limite aproximado de modificações em que o autovacuum vai disparar o ANALYZE.","when":"Após cargas/exclusões em massa, quando os planos mostram estimativas de linhas erradas ou quando se suspeita que o autoanalyze está atrasado em tabelas grandes.","caution":"O limite calculado usa as configurações globais; se existirem reloptions autovacuum_analyze_* específicas da tabela (pg_class.reloptions), o limite real é diferente. Em tabelas grandes o scale_factor padrão (0.1) dispara tarde demais; reduza-o por tabela. O autovacuum não faz ANALYZE da tabela pai de uma tabela particionada; as estatísticas em nível de pai precisam de ANALYZE manual. Tabelas temporárias nunca são vistas pelo autovacuum. O ANALYZE lê uma amostra e obtém ShareUpdateExclusiveLock (não bloqueia DML).","tags":["analyze","stale statistics","n_mod_since_analyze","autoanalyze","statistics","planner"]},{"id":"visibility-map-index-only","task":"Verificar a cobertura do visibility map e a eficiência do Index Only Scan","category":"Manutenção","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":"Mostra a proporção de páginas all-visible das tabelas, as linhas inseridas desde o último vacuum e com que frequência um Index Only Scan precisou visitar o heap (Heap Fetches).","when":"Quando um Index Only Scan rende abaixo do esperado; em tabelas com muitas inserções/append-only e ao validar o desenho de um índice de cobertura (INCLUDE).","caution":"relpages/relallvisible são estimativas registradas pelo último VACUUM/ANALYZE. Só o VACUUM define os bits do visibility map; todo UPDATE/DELETE limpa o bit da página afetada. Para uma proporção baixa em tabelas atualizadas com frequência, reduza autovacuum_vacuum_scale_factor por tabela. pg_visibility_map_summary lê o pequeno fork do VM, não o heap.","since":"PostgreSQL 13","note":"n_ins_since_vacuum e o autovacuum disparado por inserções (autovacuum_vacuum_insert_threshold/scale_factor) chegaram no PG13; antes disso, tabelas append-only podem não ter vacuum até um vacuum anti-wraparound, então o visibility map não é definido.","tags":["visibility map","index only scan","heap fetches","relallvisible","pg_visibility","vacuum"]},{"id":"range-partition-monthly","task":"Criar uma tabela particionada por range mensal (gerar as partições em um loop)","category":"Particionamento","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":"Cria uma tabela pai particionada por RANGE em uma coluna de data, um índice que se propaga a todas as partições e 12 partições mensais em um loop; depois lista a hierarquia com limites e tamanhos.","when":"Para tabelas grandes e em crescimento contínuo que descartam dados antigos periodicamente (DETACH/DROP) ou cujas consultas filtram principalmente por intervalo de datas (pedidos, logs, séries temporais).","caution":"Em uma tabela particionada, as constraints PRIMARY KEY/UNIQUE devem incluir a chave de partição (não há índices unique globais). O limite inferior é inclusivo e o superior exclusivo (FROM inclusivo, TO exclusivo). Sem um job que crie antecipadamente as partições futuras (pg_cron, pg_partman), INSERTs fora do intervalo falham. Milhares de partições aumentam o tempo de planejamento e o overhead de locks. CREATE INDEX CONCURRENTLY não é suportado na tabela pai: use CREATE INDEX ... ON ONLY no pai, CREATE INDEX CONCURRENTLY em cada partição e depois ALTER INDEX ... ATTACH PARTITION.","since":"PostgreSQL 12","note":"O particionamento declarativo chegou no PG10, índices/PRIMARY KEY no pai e partições default no PG11, pg_partition_tree() no PG12.","tags":["partition","range partition","declarative partitioning","monthly partition","pg_partition_tree","partitioning"]},{"id":"attach-partition-safely","task":"Anexar uma tabela preparada como partição com um lock curto (ATTACH PARTITION)","category":"Particionamento","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":"Transforma em partição dados carregados em uma tabela separada, sem full scan nem locks longos, usando uma constraint CHECK previamente validada que corresponde aos limites e índices pré-criados.","when":"Para cargas em massa (ETL) ou restaurações a partir de arquivo: prepare os dados sem tocar na tabela em uso e depois coloque-os online em um único passo.","caution":"ATTACH obtém SHARE UPDATE EXCLUSIVE no pai e ACCESS EXCLUSIVE na tabela sendo anexada. Sem um CHECK válido correspondente, a tabela é varrida por completo sob esse lock para validar os limites; se faltarem índices correspondentes aos do pai, o ATTACH os cria sob o lock, então prepare ambos com antecedência. Se existir uma partição default, ela também é varrida para provar que não contém linhas no novo intervalo (veja a receita de partição default). Nomes e tipos de colunas devem coincidir exatamente com os do pai; criar a tabela com LIKE ... INCLUDING é a forma mais segura.","since":"PostgreSQL 12","note":"O ATTACH PARTITION que obtém apenas SHARE UPDATE EXCLUSIVE no pai chegou no PG12; no PG11 e anteriores o pai é bloqueado com ACCESS EXCLUSIVE.","tags":["attach partition","add partition","check constraint","not valid","etl","partitioning"]},{"id":"detach-partition-concurrently","task":"Desanexar uma partição antiga sem bloquear o tráfego em produção (DETACH CONCURRENTLY)","category":"Particionamento","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":"Desanexa a partição em duas transações; obtém apenas SHARE UPDATE EXCLUSIVE no pai, para que as consultas em execução não sejam bloqueadas, e adiciona à tabela desanexada uma constraint CHECK equivalente ao limite da partição.","when":"Ao desanexar períodos antigos em um sistema em produção para retenção/arquivamento (seguido de DROP, de uma movimentação para outro tablespace ou de um arquivo pg_dump).","caution":"Não pode ser executado dentro de um bloco BEGIN ... COMMIT e não pode ser usado quando o pai tem uma partição default. Espera todas as transações que usam o pai e começaram antes dele; transações longas o prolongam. Se interrompido, a partição fica oculta das consultas, mas não desanexada ('detach pending'), e precisa ser concluída com FINALIZE. Um DETACH simples sem CONCURRENTLY é mais rápido, mas precisa de ACCESS EXCLUSIVE no pai; tente-o com lock_timeout.","since":"PostgreSQL 14","tags":["detach partition","concurrently","finalize","retention","archiving","partitioning"]},{"id":"default-partition-pitfall","task":"Armadilha da partição default: nova partição falha com 'would be violated by some row'","category":"Particionamento","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":"Conta, por período, as linhas que caíram na partição default; move as linhas dentro do intervalo da nova partição para uma nova tabela e a anexa, tudo em uma única transação.","when":"Quando CREATE TABLE ... PARTITION OF ou ATTACH falha com 'updated partition constraint for default partition would be violated by some row' ou quando se percebe que a partição default está crescendo.","caution":"Com uma partição default presente, toda nova partição varre a default por completo e mantém ACCESS EXCLUSIVE nela enquanto isso; uma partição default grande significa uma indisponibilidade a cada manutenção. A default fica fechada para gravações enquanto as linhas são movidas; faça isso com tráfego baixo. Correção permanente: crie as partições antecipadamente e mantenha a default vazia com monitoramento (alerta se a contagem de linhas > 0), ou não use uma, para que INSERTs fora do intervalo falhem e o problema apareça cedo. Uma partição default também impede DETACH ... CONCURRENTLY.","since":"PostgreSQL 11","tags":["default partition","partition error","violated by some row","partition constraint","pitfall","partitioning"]},{"id":"partition-pruning-check","task":"Verificar se o partition pruning funciona (em tempo de planejamento e de execução)","category":"Particionamento","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":"Compara o pruning em tempo de planejamento, o pruning em tempo de execução com um plano genérico ('Subplans Removed: N') e como o pruning se perde quando uma função é aplicada à chave de partição.","when":"Quando consultas em uma tabela particionada estão mais lentas que o esperado, o plano varre todas as partições ou a aplicação usa um ORM/prepared statements.","caution":"Aplicar uma função ou cast à chave de partição (date_trunc(created_at), created_at::text) desabilita o pruning; escreva a condição como um intervalo sobre a chave. Com um plano genérico, o pruning acontece na inicialização do executor e aparece apenas como 'Subplans Removed'; para expressões STABLE como now() também é visível no EXPLAIN sem ANALYZE. Com enable_partition_pruning = off não há pruning algum. Com muitas partições, meça também o Planning Time.","since":"PostgreSQL 12","note":"O pruning em tempo de execução chegou no PG11; plan_cache_mode chegou no PG12, que também melhorou muito o desempenho de planejamento com muitas partições.","tags":["partition pruning","subplans removed","generic plan","plan_cache_mode","explain","partitioning"]},{"id":"pg-partman-setup","task":"Automatizar a criação e a retenção de partições com pg_partman","category":"Particionamento","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":"Registra uma tabela pai no pg_partman; cria antecipadamente as partições futuras, remove as que passaram do período de retenção e informa as linhas que caíram na partição default.","when":"Quando você precisa de uma automação padronizada e observável em vez de gerenciar partições diárias/mensais à mão ou com scripts próprios (tabelas de log, métricas, eventos).","caution":"A API mudou entre o pg_partman 4.x e o 5.x: no 5.x p_type aceita apenas 'range'/'list' (padrão 'range'), e o p_type := 'native' do 4.x é inválido; verifique a versão instalada com SELECT extversion FROM pg_extension WHERE extname = 'pg_partman';. create_parent também cria uma partição default por padrão. retention_keep_table = false faz DROP definitivo das partições; se você precisa de um arquivo, mantenha-o true e use retention_schema. Se run_maintenance_proc() não estiver agendado, nenhuma partição nova é criada e os dados caem na default. pg_partman_bgw exige shared_preload_libraries mais um restart.","note":"O pg_partman não faz parte do núcleo do PostgreSQL (pacote separado, ex.: postgresql-17-partman). Os comandos usam a sintaxe do pg_partman 5.x.","tags":["pg_partman","partition maintenance","retention","create_parent","automatic partitioning","partitioning"]},{"id":"least-privilege-roles","task":"Montar uma hierarquia de roles com privilégio mínimo (GRANT + ALTER DEFAULT PRIVILEGES)","category":"Segurança","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":"Monta uma hierarquia de roles de grupo owner, somente leitura e leitura/escrita; concede os privilégios certos em tabelas/sequences existentes e futuras e autoriza os usuários da aplicação apenas por meio de associação a grupos.","when":"Ao configurar um novo schema de aplicação, corrigir aplicações que conectam como superusuário ou dono das tabelas e simplificar privilégios antes de uma auditoria.","caution":"ALTER DEFAULT PRIVILEGES só se aplica a objetos criados DEPOIS pela role indicada em FOR ROLE; se a ferramenta de migração criar tabelas como outro usuário, os privilégios não são aplicados, então execute o DDL com SET ROLE app_owner. GRANT ... ON ALL TABLES cobre apenas os objetos que existem naquele momento. Bancos criados no PG15+ já não concedem CREATE no schema public a PUBLIC; bancos atualizados de versões antigas precisam do REVOKE. REVOKE ALL ON DATABASE ... FROM PUBLIC também remove CONNECT e TEMP; conceda-os separadamente às outras roles que precisam deles. Use psql \\password em vez de colocar senhas na linha de comando (elas ficam fora de logs e do histórico).","note":"As roles pg_read_all_data / pg_write_all_data chegaram no PG14, as opções INHERIT/SET na associação de roles (GRANT ... WITH INHERIT FALSE) no PG16.","tags":["least privilege","role hierarchy","alter default privileges","grant","privilege","security"]},{"id":"row-level-security","task":"Configurar isolamento de tenants com row-level security","category":"Segurança","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":"Habilita RLS na tabela e define uma política que filtra as linhas pelo id do tenant em uma variável de sessão (USING) e bloqueia gravações para outro tenant (WITH CHECK).","when":"Para impor no banco o isolamento de dados de aplicações multi-tenant em vez de depender do código da aplicação.","caution":"Superusuários e roles com o atributo BYPASSRLS sempre ignoram as políticas; o dono da tabela só fica sujeito a elas com FORCE ROW LEVEL SECURITY. Com RLS habilitado e nenhuma política correspondente, o resultado é vazio (sem erro). current_setting(..., true) retorna NULL quando a variável não está definida; NULLIF evita que a string vazia deixada após RESET falhe como ''::int. Os usuários podem alterar app.tenant_id com SET; apenas uma camada de aplicação confiável deve defini-lo e os usuários finais não devem ter acesso SQL. Com um pooler em modo transaction, use SET LOCAL em vez de SET. Indexe a coluna tenant_id usada na política. O pg_dump falha quando executado como um usuário sujeito a RLS; faça backups com uma role BYPASSRLS.","since":"PostgreSQL 9.5","tags":["row level security","rls","create policy","multi-tenant","tenant isolation","security"]},{"id":"pg-hba-validate-reload","task":"Validar a ordem das regras do pg_hba.conf e recarregar com segurança","category":"Segurança","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":"Mostra onde fica o pg_hba.conf, como o PostgreSQL o interpreta (linha, tipo, banco, usuário, endereço, método) e eventuais erros de sintaxe antes do reload; depois recarrega a configuração.","when":"Ao adicionar uma nova rede/aplicação cliente, migrar de md5 para scram-sha-256 ou investigar erros 'no pg_hba.conf entry for host'.","caution":"pg_hba_file_rules mostra o arquivo como está agora, não as regras ativas. Se alguma linha tiver error não vazio, o reload NÃO carrega o pg_hba.conf de forma alguma e as regras antigas continuam valendo (o log diz 'pg_hba.conf was not reloaded'). As mudanças afetam apenas novas conexões. Uma regra ampla colocada no início (ex.: host all all 0.0.0.0/0 trust) neutraliza todas as restrições depois dela. Com SSL desligado, linhas hostssl não podem corresponder e mostram uma mensagem na coluna error. Por padrão só superusuários podem ler a view. Garanta que ferramentas que editam o arquivo como root não mudem seu dono; se o usuário postgres não conseguir lê-lo, o reload falha.","since":"PostgreSQL 10","note":"pg_hba_file_rules chegou no PG10; versões mais novas também têm as colunas rule_number e file_name. O PG16 suporta diretivas include no pg_hba.conf e correspondência por regex nos campos de usuário/banco.","tags":["pg_hba.conf","authentication","rule order","reload","pg_hba_file_rules","security"]},{"id":"ssl-enable-verify","task":"Habilitar SSL/TLS e verificar conexões criptografadas (pg_stat_ssl)","category":"Segurança","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":"Habilita TLS com um certificado de servidor sem restart, define a versão mínima do protocolo e lista se as conexões atuais estão criptografadas, com a versão de TLS e o cipher.","when":"Para requisitos de auditoria de segurança/conformidade (PCI, GDPR), para proteger senhas e dados em trânsito na rede.","caution":"ssl = on sozinho não impõe criptografia; os clientes ainda podem conectar sem criptografia com sslmode=prefer/disable. Para impor, use hostssl em vez de host no pg_hba.conf (e adicione hostnossl ... reject). sslmode=require não verifica a identidade do servidor (aberto a MITM); use verify-full para verificação do certificado. O arquivo de chave deve pertencer ao usuário postgres com modo 0600 (ou ao root com 0640); senão o SSL não é carregado, então verifique o log e SHOW ssl após o reload. Renovações de certificado também são aplicadas com reload.","since":"PostgreSQL 10","note":"Alterar configurações de SSL com reload em vez de restart chegou no PG10, ssl_min_protocol_version no PG12; seu padrão é TLSv1.2 desde o PG13.","tags":["ssl","tls","pg_stat_ssl","hostssl","certificate","encryption"]},{"id":"scram-migration","task":"Migrar de senhas md5 para scram-sha-256","category":"Segurança","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":"Faz com que novas senhas sejam armazenadas como SCRAM-SHA-256, encontra as roles de login que ainda têm hashes md5 e dá os passos para mudar o pg_hba.conf para scram-sha-256 depois que as senhas forem renovadas.","when":"Quando uma auditoria de segurança aponta o md5, após o upgrade para PG14+ ou ao se preparar para versões em que o md5 está obsoleto.","caution":"O SCRAM não pode ser derivado dos hashes md5 existentes; toda senha precisa ser definida novamente em texto claro (exige coordenação com as equipes de aplicação). O método 'md5' no pg_hba.conf faz automaticamente autenticação SCRAM para roles cuja senha é SCRAM, então manter md5 durante a migração é um passo intermediário seguro, mas quando o método for 'scram-sha-256' as roles com senhas md5 não conseguem mais conectar. Drivers de cliente antigos (libpq < 10, drivers JDBC/.NET antigos) podem não suportar SCRAM; atualize os drivers primeiro. ALTER ROLE ... PASSWORD pode gravar a senha no log via log_statement; o psql \\password faz o hash no cliente antes de enviar.","since":"PostgreSQL 10","note":"O SCRAM-SHA-256 chegou no PG10, e o padrão de password_encryption passou a ser scram-sha-256 no PG14. O PG18 torna as senhas md5 obsoletas e emite um aviso.","tags":["scram-sha-256","md5","password_encryption","password","authentication","security"]},{"id":"pgaudit-object-audit","task":"Manter logs de auditoria em nível de role e de objeto com pgaudit","category":"Segurança","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":"Registra, como linhas de log estruturadas com o prefixo 'AUDIT:', DDL e mudanças de privilégios em todo o servidor, todas as leituras/gravações de uma role específica e o acesso a tabelas/colunas sensíveis concedidas à role de auditor.","when":"Para provar quem acessou dados sensíveis em auditorias de conformidade como GDPR, PCI-DSS ou SOX.","caution":"Habilitar pgaudit.log = 'all' ou 'read' em todo o servidor aumenta muito o volume de log e o I/O; restrinja o escopo com auditoria por role ou por objeto. Um superusuário pode desligar a auditoria (ALTER SYSTEM/ALTER ROLE); envie os registros a um sistema central de logs (syslog/SIEM) e armazene-os independentemente do servidor de banco. log_parameter = on também registra os parâmetros de bind (dados pessoais). As configurações de role valem em novas sessões. A versão major do pgaudit deve coincidir com a versão major do PostgreSQL (pgaudit 17.x = PG17).","note":"O pgaudit não faz parte do núcleo do PostgreSQL (pacote separado, ex.: postgresql-17-pgaudit).","tags":["pgaudit","audit","auditing","object audit","log","security"]},{"id":"memory-settings-check","task":"Revisar as configurações de memória (shared_buffers, work_mem, maintenance_work_mem)","category":"Parâmetros","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":"Mostra os parâmetros relacionados à memória com valor, origem (padrão/arquivo de configuração) e contexto de alteração (postmaster = restart); tetos aproximados de memória para work_mem e autovacuum; e o volume de arquivos temporários por banco.","when":"Ao montar um novo servidor, após adicionar RAM, após um evento do OOM killer ou quando se observa uso intenso de arquivos temporários.","caution":"O work_mem não é alocado por conexão, mas por NÓ de sort/hash (vezes hash_mem_multiplier para hashes) e separadamente para cada parallel worker; uma consulta complexa pode usar vários múltiplos do work_mem, então o produto calculado é um aviso aproximado, não um limite superior. Pontos de partida típicos: shared_buffers ~25% da RAM (exige restart), effective_cache_size ~50-75% (apenas uma dica para o planner, não aloca nada), maintenance_work_mem 512MB-2GB. Com autovacuum_work_mem = -1, cada worker do autovacuum pode usar maintenance_work_mem. Se temp_bytes estiver alto, aumente o work_mem por role ou consulta, não globalmente. Com shared_buffers grande no Linux, considere huge_pages.","note":"hash_mem_multiplier chegou no PG13 (padrão 2.0 desde o PG15).","tags":["shared_buffers","work_mem","maintenance_work_mem","memory","memory tuning","temp_bytes"]},{"id":"pending-restart-config-errors","task":"Mostrar parâmetros com restart pendente e erros em arquivos de configuração","category":"Parâmetros","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":"Mostra os parâmetros alterados nos arquivos que aguardam restart, as linhas de arquivos de configuração não aplicadas ou com erros e de qual arquivo/linha vem o valor efetivo de um parâmetro.","when":"Para verificar, após um ALTER SYSTEM ou uma mudança no postgresql.conf, se o reload teve o efeito esperado e para listar as mudanças pendentes antes de um restart planejado.","caution":"pg_file_settings lê os arquivos como estão agora; se um parâmetro estiver definido em vários lugares, apenas o último tem applied = true (o postgresql.auto.conf é lido por último, então o ALTER SYSTEM sempre vence). Uma linha com applied = false e error vazio está sombreada por outra definição; não é um erro. Um parâmetro que precisa de restart mostra o error 'setting could not be applied'. Um arquivo com defeito pode ser aplicado parcialmente no reload; após uma mudança, execute pg_reload_conf() e depois verifique estas consultas e o log do servidor. Não edite o postgresql.auto.conf à mão; use ALTER SYSTEM RESET.","since":"PostgreSQL 9.5","tags":["pending_restart","pg_file_settings","restart","configuration error","alter system","config"]},{"id":"checkpoint-stats","task":"Revisar o comportamento dos checkpoints (PG17+ pg_stat_checkpointer, PG16 e anteriores pg_stat_bgwriter)","category":"Parâmetros","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":"Mostra a proporção entre checkpoints agendados e checkpoints forçados pelo volume de WAL, o tempo médio de write/sync por checkpoint e o volume de buffers gravados (no PG16 e anteriores, junto com as gravações do bgwriter e dos backends).","when":"Quando períodos com muitas gravações mostram picos de I/O, a geração de WAL é alta ou o log avisa 'checkpoints are occurring too frequently'.","caution":"Um req_pct alto (tipicamente acima de 10-20%) significa que os checkpoints são forçados porque o max_wal_size enche; aumente o max_wal_size e observe as linhas 'checkpoint starting: wal' com log_checkpoints = on. Um checkpoint_timeout maior distribui o I/O, mas alonga a crash recovery. No PG16 e anteriores, um written_by_backends alto significa que os backends precisam gravar eles mesmos as páginas sujas (shared_buffers/bgwriter insuficientes); no PG17 isso está em pg_stat_io. As médias também contam checkpoints agendados pulados por falta de trabalho, então leia-as como valores aproximados. Os contadores são cumulativos desde stats_reset.","since":"PostgreSQL 17","note":"No PG17 as estatísticas do checkpointer foram movidas de pg_stat_bgwriter para a nova view pg_stat_checkpointer (checkpoints_timed → num_timed, checkpoints_req → num_requested, buffers_checkpoint → buffers_written); buffers_backend e buffers_backend_fsync foram removidos. O PG18 adicionou as colunas num_done e slru_written.","tags":["checkpoint","pg_stat_checkpointer","pg_stat_bgwriter","max_wal_size","checkpoint_timeout","wal"]},{"id":"relation-size-breakdown","task":"Listar o tamanho das tabelas dividido em heap / índice / TOAST e os maiores índices","category":"Armazenamento","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":"Mostra as maiores tabelas divididas em total, heap, índice e TOAST (+FSM/VM) com sua participação no banco; e os maiores índices com contagens de scans e flags unique/primary.","when":"Para descobrir de onde vem o crescimento (dados, índices ou TOAST) quando o uso de disco sobe e para identificar índices grandes não utilizados.","caution":"As funções de tamanho acessam o file system para cada relação e podem ser lentas em bancos com dezenas de milhares de tabelas. Uma tabela pai particionada (relkind 'p') tem 0 bytes por si só e é excluída; para o total de uma hierarquia: SELECT pg_size_pretty(sum(pg_total_relation_size(relid))) FROM pg_partition_tree('sales'); Índices grandes com idx_scan = 0 são candidatos a remoção, mas os contadores cobrem apenas o tempo desde o último reset de estatísticas e apenas este servidor (o uso nas réplicas não é visível); índices unique/primary impõem constraints e não são removidos.","tags":["table size","index size","toast","disk usage","pg_total_relation_size","storage"]},{"id":"extension-update-check","task":"Encontrar extensões com atualizações pendentes e atualizá-las","category":"Extensões","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":"Compara a versão instalada de cada extensão no banco com a versão padrão do pacote no servidor e gera o comando ALTER EXTENSION para as que têm atualizações pendentes.","when":"Após upgrades minor/major do PostgreSQL e atualizações de pacotes de extensões e durante a manutenção periódica.","caution":"Atualizar o pacote do SO não atualiza o lado SQL automaticamente; ALTER EXTENSION ... UPDATE deve ser executado em cada banco separadamente (especialmente importante após o pg_upgrade). O script de atualização pode obter locks e alterar objetos (ex.: PostGIS); teste-o antes e leia as notas de versão. Para ir para uma versão específica: ALTER EXTENSION pgstattuple UPDATE TO '1.5'; Algumas extensões (ex.: pg_stat_statements) também exigem restart para recarregar a biblioteca compartilhada.","tags":["alter extension update","extension version","extension","pg_available_extensions","upgrade","update"]},{"id":"pg-stat-io-analysis","task":"Analisar de onde vem o I/O com pg_stat_io (tipo de backend, objeto, contexto)","category":"Extensões","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":"Mostra leituras, gravações, extends, evictions e fsyncs por tipo de backend (client backend, autovacuum, checkpointer...), objeto (relation/temp relation) e contexto (normal, vacuum, bulkread, bulkwrite); e de quais tipos de processo vêm as gravações.","when":"Durante um gargalo de I/O, para saber se a carga vem das consultas, do autovacuum ou dos checkpoints e para validar as configurações de shared_buffers/bgwriter.","caution":"pg_stat_io é de todo o cluster e cumulativo desde o último reset; tire a diferença entre duas amostras para ver a variação (para zerar: SELECT pg_stat_reset_shared('io');). read_time/write_time só são preenchidos com track_io_timing = on. reads também inclui leituras atendidas pelo page cache do SO. Muitas gravações ou evictions de client backend significam que os backends gravam eles mesmos os buffers para liberar espaço; revise shared_buffers, bgwriter_lru_maxpages e as configurações de checkpoint. Linhas com context = 'vacuum'/'bulkread' refletem o uso de ring buffer; reuses ali são normais.","since":"PostgreSQL 16","note":"pg_stat_io chegou no PG16. O PG18 removeu a coluna op_bytes, adicionou read_bytes/write_bytes/extend_bytes e também reporta o I/O de WAL nesta view; no PG18 use read_bytes em vez de reads * op_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":"Rotacionar o binary log","category":"Binlog e log","command":"FLUSH BINARY LOGS;","what":"Fecha o arquivo de binary log atual e passa para um novo.","when":"Para criar um ponto de partida limpo de binlog antes de um backup ou para limitar o tamanho dos arquivos.","caution":"Rotações frequentes geram muitos arquivos de binlog pequenos. O mesmo comando funciona no MariaDB; FLUSH LOGS rotaciona todos os logs.","tags":["binlog","rotate","flush","log"]},{"id":"purge-binlog","task":"Expurgar binary logs antigos (PURGE)","category":"Binlog e log","command":"PURGE BINARY LOGS BEFORE NOW() - INTERVAL 7 DAY;","what":"Apaga do disco os arquivos de binary log anteriores à data indicada.","when":"Quando os binlogs estão enchendo o disco, para limpar logs antigos que não são mais necessários.","caution":"Se uma réplica ainda precisar de um binlog que está sendo apagado, a replicação quebra; verifique antes com SHOW REPLICA STATUS que todas as réplicas já passaram dele. Para apagar até um arquivo específico: PURGE BINARY LOGS TO 'mysql-bin.000123'; Para limpeza automática, use a configuração binlog_expire_logs_seconds.","tags":["binlog","purge","cleanup","log"]},{"id":"show-binlogs","task":"Ver o status do binary log","category":"Binlog e log","command":"SHOW BINARY LOGS;","what":"Lista todos os arquivos de binary log do servidor e seus tamanhos.","when":"Para ver o uso de disco dos binlogs e quais arquivos existem.","caution":"Para o arquivo de binlog sendo gravado no momento e sua posição: SHOW BINARY LOG STATUS; (MySQL 8.2+). Versões mais antigas usam SHOW MASTER STATUS (obsoleto no 8.2–8.3, removido no 8.4).","tags":["binlog","status","show","log"]},{"id":"enable-general-slow-log","task":"Habilitar o general log e o slow query log","category":"Binlog e log","command":"SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1; SET GLOBAL general_log = 'ON';","what":"Habilita, em tempo de execução, o slow query log (consultas com mais de 1 segundo) e o general log, que registra todas as consultas.","when":"Para analisar temporariamente consultas lentas ou todo o tráfego de consultas.","caution":"O general_log adiciona overhead significativo de desempenho e de disco; sempre desligue-o ao terminar o diagnóstico (SET GLOBAL general_log='OFF'). Essas configurações voltam ao padrão no restart; use SET PERSIST para torná-las permanentes.","tags":["slow-log","general-log","log","diagnostics"]},{"id":"innodb-redo-capacity","task":"Alterar o tamanho do redo log do InnoDB","category":"Armazenamento","command":"SET GLOBAL innodb_redo_log_capacity = 2147483648;","what":"Define dinamicamente, em tempo de execução, a capacidade total do redo log do InnoDB (em bytes, aqui 2 GB).","when":"Para reduzir a frequência de checkpoints e melhorar o desempenho sob cargas com muitas gravações.","caution":"innodb_redo_log_capacity chegou no MySQL 8.0.30 e substitui as antigas configurações innodb_log_file_size + innodb_log_files_in_group. Em versões mais antigas/MariaDB, innodb_log_file_size é alterado no my.cnf e exige restart. Para torná-lo permanente: SET PERSIST innodb_redo_log_capacity = 2147483648;","since":"MySQL 8.0.30","note":"innodb_redo_log_capacity chegou no MySQL 8.0.30 e permitiu redimensionar o redo log de forma dinâmica (sem restart); antes era preciso definir innodb_log_file_size + innodb_log_files_in_group e reiniciar o servidor.","tags":["innodb","redo-log","capacity","storage"]},{"id":"innodb-undo-tablespace","task":"Adicionar / gerenciar um undo tablespace do InnoDB","category":"Armazenamento","command":"CREATE UNDO TABLESPACE undo_003 ADD DATAFILE 'undo_003.ibu';","what":"Cria um novo undo tablespace do InnoDB; os undo logs são gerenciados separadamente dos arquivos de dados e passam a poder ser truncados.","when":"Para gerenciar o espaço quando transações longas incham o undo log ou para mover o undo para um disco separado.","caution":"O nome do arquivo deve terminar em .ibu. Um undo tablespace precisa ficar inativo antes de ser removido: ALTER UNDO TABLESPACE undo_003 SET INACTIVE; depois DROP UNDO TABLESPACE undo_003; Este é um recurso do MySQL 8.0+.","since":"MySQL 8.0","note":"Criar/remover undo tablespaces com SQL (CREATE/DROP UNDO TABLESPACE) chegou no MySQL 8.0; antes o número de undo tablespaces era fixado por innodb_undo_tablespaces e não podia ser gerenciado em tempo de execução.","tags":["innodb","undo-log","tablespace","storage"]},{"id":"create-tablespace","task":"Adicionar um general tablespace","category":"Armazenamento","command":"CREATE TABLESPACE ssd_ts ADD DATAFILE 'ssd_ts.ibd' ENGINE=InnoDB;","what":"Cria um general tablespace do InnoDB que várias tabelas podem compartilhar.","when":"Para agrupar tabelas em um arquivo/disco específico ou para reduzir o número de arquivos.","caution":"Se o caminho de DATAFILE for relativo, ele é criado sob o datadir; colocá-lo em outro disco exige um caminho absoluto e as permissões necessárias. Para mover uma tabela para cá: ALTER TABLE customer TABLESPACE ssd_ts; Um tablespace só pode ser removido quando está vazio.","tags":["tablespace","innodb","storage","create"]},{"id":"optimize-table","task":"OPTIMIZE em uma tabela","category":"Armazenamento","command":"OPTIMIZE TABLE customer;","what":"Reconstrói a tabela para eliminar a fragmentação, recuperar espaço não utilizado e atualizar as estatísticas de índices.","when":"Para recuperar espaço em uma tabela InnoDB inchada por muitos DELETEs/UPDATEs.","caution":"No InnoDB, o OPTIMIZE na verdade roda como um ALTER online que reconstrói a tabela, mas ainda precisa de I/O e de espaço temporário em disco; tabelas grandes exigem disco livre igual ao tamanho da tabela. Execute com tráfego baixo para reduzir o bloqueio.","tags":["optimize","table","defragment","storage"]},{"id":"table-schema-size","task":"Consultar o tamanho de tabelas e schemas","category":"Armazenamento","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":"Lista as 20 maiores tabelas pelo tamanho combinado de dados e índices (MB).","when":"Para analisar o uso de disco e descobrir quais tabelas ocupam espaço.","caution":"Os tamanhos em information_schema são aproximados para InnoDB. Para totais por schema, faça GROUP BY apenas por table_schema, em vez de table_name.","tags":["size","table","schema","information-schema"]},{"id":"analyze-table","task":"Atualizar as estatísticas da tabela (ANALYZE TABLE)","category":"Manutenção","command":"ANALYZE TABLE customer;","what":"Recalcula as estatísticas de distribuição de índices/chaves da tabela para que o otimizador possa escolher planos melhores.","when":"Quando surgem planos de consulta ruins após grandes mudanças de dados.","caution":"Um metadata lock breve é obtido na tabela durante a execução. No InnoDB é baseado em amostragem; aumente innodb_stats_persistent_sample_pages para mais precisão.","tags":["analyze","statistics","optimizer","maintenance"]},{"id":"rebuild-table","task":"Reconstruir uma tabela/índices","category":"Manutenção","command":"ALTER TABLE customer ENGINE=InnoDB;","what":"Reconstrói a tabela com o mesmo engine; recria os índices e as páginas de dados para eliminar a fragmentação e o bloat dos índices.","when":"Para atualizar uma tabela com um ALTER nulo ou para reparar um layout de páginas danificado.","caution":"Tabelas grandes exigem disco temporário igual ao tamanho da tabela. Para reduzir o bloqueio: ALTER TABLE customer ENGINE=InnoDB, ALGORITHM=INPLACE, LOCK=NONE;","tags":["rebuild","alter","innodb","maintenance"]},{"id":"check-table","task":"Verificar a integridade da tabela (CHECK TABLE)","category":"Manutenção","command":"CHECK TABLE customer;","what":"Verifica a tabela e seus índices em busca de corrupção e retorna um status.","when":"Em erros inesperados ou quando se suspeita de corrupção.","caution":"Um lock de leitura é obtido na tabela durante a verificação. Se for encontrada corrupção, o InnoDB normalmente é reparado via dump/restore; REPAIR TABLE só funciona para engines como MyISAM/Archive.","tags":["check","integrity","corruption","maintenance"]},{"id":"set-global-persist","task":"Alterar uma variável global e persisti-la","category":"Parâmetros","command":"SET PERSIST innodb_buffer_pool_size = 4294967296;","what":"Define a variável tanto no servidor em execução quanto de forma persistente entre restarts (mysqld-auto.cnf).","when":"Para alterar uma variável do servidor permanentemente sem restart.","caution":"SET PERSIST é um recurso do MySQL 8.0+; o MariaDB não o suporta (lá, edite o my.cnf e reinicie). Use SET GLOBAL para uma mudança apenas em tempo de execução. Variáveis que só mudam com restart exigem SET PERSIST_ONLY.","since":"MySQL 8.0","note":"SET PERSIST chegou no MySQL 8.0 e torna uma variável persistente gravando-a no mysqld-auto.cnf; antes (e no MariaDB) a persistência exigia editar o my.cnf manualmente e reiniciar.","tags":["set-persist","global","variable","parameter"]},{"id":"show-variables","task":"Ver o valor atual de uma variável","category":"Parâmetros","command":"SHOW VARIABLES LIKE 'innodb_buffer_pool_size';","what":"Mostra o valor efetivo da variável de servidor especificada (ou das que correspondem ao padrão).","when":"Para verificar o valor em uso de um parâmetro.","caution":"Use SHOW GLOBAL VARIABLES para o valor global em vez do valor da sessão. Para ver de onde vem o valor (arquivo, linha de comando, 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":"Recarregar as tabelas de privilégios (FLUSH PRIVILEGES)","category":"Parâmetros","command":"FLUSH PRIVILEGES;","what":"Recarrega na memória as tabelas de privilégios, como mysql.user, depois de terem sido modificadas diretamente.","when":"Para ativar mudanças feitas com INSERT/UPDATE manual nas tabelas de privilégios.","caution":"GRANT/REVOKE/CREATE USER já aplicam os privilégios imediatamente; FLUSH PRIVILEGES depois deles é desnecessário. Só é necessário quando você modifica as tabelas de privilégios diretamente.","tags":["flush-privileges","grants","privileges","reload"]},{"id":"setup-replica","task":"Configurar uma réplica (CHANGE REPLICATION SOURCE)","category":"Replicação","command":"CHANGE REPLICATION SOURCE TO SOURCE_HOST='source_host', SOURCE_PORT=3306, SOURCE_USER='replicator', SOURCE_PASSWORD='secret', SOURCE_AUTO_POSITION=1;","what":"Configura este servidor como uma réplica que segue a source especificada usando auto-positioning baseado em GTID.","when":"Para configurar uma nova réplica ou mudar a source da replicação.","caution":"Esta é a terminologia do MySQL 8.0.23+; versões mais antigas usam CHANGE MASTER TO ... MASTER_HOST (um alias no 8.0.23–8.3, removido no 8.4). SOURCE_AUTO_POSITION=1 exige GTID habilitado (gtid_mode=ON); caso contrário SOURCE_LOG_FILE e SOURCE_LOG_POS devem ser especificados. A replicação deve estar parada antes de executar o comando. Se o usuário de replicação foi criado com o caching_sha2_password padrão do 8.0+, a conexão exige TLS: adicione SOURCE_SSL=1 ou, sem TLS, defina GET_SOURCE_PUBLIC_KEY=1; caso contrário a I/O thread não consegue conectar e falha com o erro 2061.","since":"MySQL 8.0.23","note":"CHANGE REPLICATION SOURCE TO (SOURCE_HOST etc.) chegou no MySQL 8.0.23; antes usava-se CHANGE MASTER TO ... MASTER_HOST / MASTER_AUTO_POSITION.","tags":["replication","change-source","replica","setup"]},{"id":"start-stop-replica","task":"Iniciar / parar uma réplica","category":"Replicação","command":"STOP REPLICA; START REPLICA;","what":"Para e reinicia as threads de replicação I/O e SQL.","when":"Para manutenção, mudanças de configuração ou para corrigir um erro de replicação.","caution":"Esta é a terminologia do MySQL 8.0.22+; versões mais antigas usam STOP SLAVE / START SLAVE. Apenas para a SQL thread: STOP REPLICA SQL_THREAD; Após STOP REPLICA você pode executar CHANGE REPLICATION SOURCE.","since":"MySQL 8.0.22","note":"START REPLICA / STOP REPLICA chegaram no MySQL 8.0.22; antes usava-se START SLAVE / STOP SLAVE (a sintaxe antiga funciona como alias no 8.0.22–8.3 e foi removida no 8.4).","tags":["replication","start","stop","replica"]},{"id":"replica-status","task":"Ver o status da réplica (SHOW REPLICA STATUS)","category":"Replicação","command":"SHOW REPLICA STATUS\\G","what":"Mostra em detalhe a conexão da réplica com a source, o estado das threads, o lag e eventuais erros.","when":"Para verificar se a replicação está saudável e quanto está atrasada.","caution":"Esta é a terminologia do MySQL 8.0.22+; versões mais antigas usam SHOW SLAVE STATUS (um alias no 8.0.22–8.3, removido no 8.4). Campos principais: Replica_IO_Running e Replica_SQL_Running devem ser 'Yes', Seconds_Behind_Source mostra o lag, Last_Error mostra o erro.","since":"MySQL 8.0.22","note":"SHOW REPLICA STATUS chegou no MySQL 8.0.22; antes usava-se SHOW SLAVE STATUS e os campos tinham nomes como Slave_IO_Running / Seconds_Behind_Master.","tags":["replication","status","replica","lag"]},{"id":"skip-gtid-transaction","task":"Pular uma transação quebrada (GTID)","category":"Replicação","command":"STOP REPLICA; SET GTID_NEXT='aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee:15'; BEGIN; COMMIT; SET GTID_NEXT='AUTOMATIC'; START REPLICA;","what":"Faz commit de uma transação vazia para o GTID especificado, para que essa transação conte como 'aplicada', e deixa a replicação seguir.","when":"Quando um evento duplicado/impossível de aplicar na réplica interrompe a replicação, para pular esse evento.","caution":"Pular uma transação cria inconsistência de dados entre a réplica e a source; use apenas quando souber o efeito do evento pulado. Pegue o valor do GTID em Last_Error / Retrieved_Gtid_Set no SHOW REPLICA STATUS. Se o GTID estiver desligado, use SET GLOBAL sql_replica_skip_counter = 1; (8.0.26+; antes sql_slave_skip_counter, um alias obsoleto no 8.0.26+).","tags":["replication","gtid","skip","recovery"]},{"id":"kill-query-connection","task":"Encerrar uma consulta ou conexão (KILL)","category":"Sessão","command":"KILL QUERY 4567;","what":"Encerra a consulta em execução no ID de conexão indicado sem fechar a conexão.","when":"Para parar uma consulta longa/travada.","caution":"Para fechar a conexão (sessão) inteira: KILL CONNECTION 4567; (ou simplesmente KILL 4567). Se uma transação de escrita em execução for encerrada, ela sofre rollback, o que pode demorar muito em tabelas grandes.","tags":["kill","query","connection","session"]},{"id":"process-list","task":"Ver a lista de processos","category":"Sessão","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":"Lista todas as conexões que não estão ociosas, a consulta que estão executando e o tempo decorrido.","when":"Para diagnosticar sessões ativas e consultas longas.","caution":"Atalho: SHOW FULL PROCESSLIST; performance_schema.processlist fornece todas as colunas e pode ser filtrado com WHERE. A coluna time está em segundos.","tags":["processlist","session","activity","performance-schema"]},{"id":"blocking-locks","task":"Ver locks bloqueadores (data_lock_waits)","category":"Sessão","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":"Mostra qual transação está bloqueada por qual, com as consultas relacionadas e os IDs das threads.","when":"Para diagnosticar esperas de lock e lentidões causadas por deadlocks.","caution":"performance_schema.data_lock_waits chegou no MySQL 8.0; versões mais antigas usam information_schema.innodb_lock_waits. Para parar a thread bloqueadora, use KILL blocking_thread;.","since":"MySQL 8.0","note":"performance_schema.data_lock_waits chegou no MySQL 8.0; no MySQL 5.7 e anteriores, usava-se information_schema.innodb_lock_waits para a mesma informação.","tags":["blocking","lock","data-lock-waits","deadlock"]}]},"recipes/mysql-ext.json":{"engineId":"mysql","engine":"MySQL","order":2,"recipes":[{"id":"replica-applier-health","task":"Monitorar o lag da réplica e os erros dos workers do applier (performance_schema)","category":"Replicação","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":"Detalha por canal e por worker o que o SHOW REPLICA STATUS resume em uma única linha: estado da receiver thread, o último erro de cada worker, o GTID aplicado / em aplicação e o lag real calculado a partir do timestamp de commit original.","when":"Quando o Seconds_Behind_Source parece pouco confiável (pulando entre 0 e valores altos, NULL), para descobrir qual worker está travado em uma réplica multi-threaded e para alimentar o monitoramento com uma métrica de lag precisa.","caution":"current_lag_sec só faz sentido enquanto uma transação está sendo aplicada; uma réplica ociosa retorna 0. Para ver se o receiver também está atrasado, compare LAST_QUEUED_TRANSACTION com o gtid_executed da source. O timestamp de commit original vem do relógio da source; diferenças de relógio entre servidores (NTP) distorcem o resultado. O Seconds_Behind_Source fica perto de zero no início de uma transação grande e salta no fim; transações longas tornam essa métrica enganosa.","note":"As colunas ORIGINAL_COMMIT_TIMESTAMP / END_APPLY_TIMESTAMP chegaram no 8.0.2 e cobrem toda a cadeia (source → intermediária → réplica); o 5.7 só tem Seconds_Behind_Master.","since":"MySQL 8.0","tags":["replication","lag","applier","worker","performance_schema","delay"]},{"id":"replica-parallel-applier","task":"Ajustar a réplica multi-threaded (replica_parallel_workers)","category":"Replicação","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":"Define o número de workers que aplicam transações em paralelo na réplica; replica_preserve_commit_order mantém a ordem de commit idêntica à da source. O rastreamento de dependências WRITESET na source permite que transações que tocam linhas diferentes sejam aplicadas em paralelo mesmo que tenham sido confirmadas em série na source.","when":"Quando a réplica não acompanha a taxa de gravação da source e o lag se acumula enquanto o applier é, na prática, single-threaded.","caution":"Um novo número de workers tem efeito quando o applier reinicia. Rodar mais workers do que núcleos de CPU adiciona overhead de coordenação; comece na faixa de 8–16 e observe o lag e os erros dos workers. Uma única transação enorme ou DML pesado em uma tabela sem PK não pode ser paralelizado, o que normalmente é a causa real de um lag persistente. replica_preserve_commit_order=OFF dá mais paralelismo, mas permite commits momentaneamente fora de ordem na réplica; mantenha ON nas réplicas que atendem leituras.","note":"Desde o 8.0.27 os padrões são replica_parallel_workers=4, replica_parallel_type=LOGICAL_CLOCK e replica_preserve_commit_order=ON. Antes do 8.0.26 as variáveis se chamavam slave_parallel_workers / slave_preserve_commit_order. binlog_transaction_dependency_tracking ficou obsoleto no 8.0.35 e foi removido no 8.4, onde o comportamento WRITESET é o padrão.","since":"MySQL 8.0.26","tags":["replication","parallel","replica_parallel_workers","writeset","lag","mta"]},{"id":"replica-fix-row-conflict","task":"Reparar uma réplica quebrada: conflitos de linha 1062 / 1032","category":"Replicação","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":"Corrige as duas quebras mais comuns da replicação baseada em linhas (1062 chave duplicada, 1032 linha não encontrada) sem pular a transação, levando a linha da réplica ao estado que a source espera; a consistência dos dados é preservada.","when":"Quando Replica_SQL_Running = No com o erro 1062 / 1032; como reparo adequado em vez de pular o GTID com uma transação vazia.","caution":"A correção na réplica deve rodar com sql_log_bin=0; caso contrário cria um errant GTID que causa problemas no failover. Se super_read_only=ON, desabilite-o temporariamente e reabilite-o depois. Os valores da before-image pressupõem binlog_row_image=FULL; com MINIMAL só a PK é registrada e o restante da linha precisa ser lido da source. Um conflito em uma tabela normalmente significa que há outros; após o reparo compare a tabela com a source usando pt-table-checksum. Caminho do relay log: SELECT @@relay_log_basename;","note":"replica_exec_mode=IDEMPOTENT engole silenciosamente esses erros; foi projetado para NDB e casos especiais e não deve ficar ligado permanentemente. Se a transação realmente precisar ser pulada, veja a receita skip-gtid-transaction.","since":"MySQL 8.0.22","tags":["replication","1062","1032","mysqlbinlog","relay log","broken replica"]},{"id":"gtid-errant-transactions","task":"Encontrar e neutralizar transações errant GTID","category":"Replicação","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":"Detecta, por diferença de conjuntos de GTID, transações executadas diretamente em uma réplica sem correspondente na source (errant) e alinha os conjuntos de GTID em toda a topologia marcando-as com transações vazias na source.","when":"Como verificação de rotina antes de failover / switchover; quando o Orchestrator ou o MySQL Shell se recusa a promover uma réplica por causa de errant GTIDs ou quando uma réplica falha com 1236 ao se conectar a uma nova source.","caution":"Primeiro descubra o que a transação errant fez a partir do binlog da réplica (mysqlbinlog --include-gtids=...). Se ela alterou dados, a transação vazia apenas encobre o GTID e a diferença de dados permanece; reconstrua a réplica (CLONE) ou alinhe os dados manualmente. Transações vazias confirmadas na source se propagam para todas as réplicas; isso é intencional. Mantenha super_read_only=ON nas réplicas para evitar recorrência.","note":"Quando a réplica é promovida, as outras réplicas pedem esses GTIDs a ela; se esse binlog já tiver sido expurgado, a replicação quebra com o erro 1236. Por isso errant GTIDs são um risco que permanece invisível até o failover.","since":"MySQL 5.6","tags":["gtid","errant","gtid_subtract","failover","replication","empty transaction"]},{"id":"replica-rebuild-clone","task":"Reconstruir uma réplica do zero com o plugin CLONE","category":"Replicação","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":"Copia fisicamente pela rede os dados InnoDB do donor, reinicia o recipient e transfere o estado de GTID; produz uma réplica consistente sem etapas separadas de backup, transferência e restore.","when":"Para reconstruir uma réplica corrompida, com errant GTIDs ou tão atrasada que seus binlogs foram expurgados, ou para adicionar uma nova réplica.","caution":"Todos os dados do recipient (inclusive usuários) são substituídos pela cópia do donor; a senha do root passa a ser a do donor. Donor e recipient precisam da mesma série de versão, plataforma e conjunto de plugins (antes do 8.0.37 era exigida exatamente a mesma point release). O usuário do recipient que executa o comando precisa de CLONE_ADMIN. Quando o clone termina, o mysqld reinicia sozinho; sem um supervisor como systemd / mysqld_safe ele retorna 3707 'Restart server failed (mysqld is not managed by supervisor process)'. Isso não é uma falha: o clone está completo, inicie o servidor manualmente. O donor sofre carga pesada de IO / rede; limite-a com clone_max_concurrency e clone_max_data_bandwidth. Com GTID desligado, use BINLOG_FILE / BINLOG_POSITION de clone_status como SOURCE_LOG_FILE / SOURCE_LOG_POS.","note":"Apenas dados InnoDB são clonados; tabelas MyISAM e CSV chegam vazias. No InnoDB Cluster, addInstance(..., {recoveryMethod: 'clone'}) usa o mesmo mecanismo.","since":"MySQL 8.0.17","tags":["clone","rebuild","replica","provisioning","gtid","reseed"]},{"id":"delayed-replica-recover","task":"Recuperar-se de um DROP / DELETE errado com uma réplica atrasada (SOURCE_DELAY + UNTIL)","category":"Replicação","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":"Faz a réplica aplicar os eventos com um atraso fixo; quando um DROP / DELETE errado atinge a source, você avança a réplica até logo antes dessa transação e recupera dela os dados perdidos.","when":"Como camada de recuperação rápida contra erro humano em bancos grandes, onde restaurar a partir do backup levaria horas.","caution":"Quando o coordinator estiver OFF, os dados estão no estado imediatamente anterior à operação errada; faça dump da tabela afetada com mysqldump e carregue-a na source. Depois coloque a réplica de volta em modo atrasado; se ela também aplicar a transação errada, os dados se perdem aqui também. Uma réplica atrasada não deve ser candidata a failover (exclua-a no Orchestrator / Router / ProxySQL). Os relay logs se acumulam durante todo o atraso; dimensione o disco de acordo.","note":"Antes do 8.0.23 use CHANGE MASTER TO MASTER_DELAY. O atraso é medido a partir do commit na source imediata, então réplicas intermediárias atrasadas em uma cadeia se somam. SQL_BEFORE_GTIDS para antes do GTID indicado, SQL_AFTER_GTIDS também o aplica; antes do 8.2 (incluindo o 8.0), usar SQL_AFTER_GTIDS com um applier multi-threaded gera um aviso e a réplica passa para o modo single-threaded.","since":"MySQL 8.0.23","tags":["delayed replica","source_delay","until","sql_before_gtids","recovery","drop table"]},{"id":"mysqldump-consistent","task":"Fazer um backup lógico consistente com informações de GTID usando mysqldump","category":"Backup e 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":"Faz o dump das tabelas InnoDB dentro de um único snapshot consistente e grava no topo o arquivo / posição do binlog (como comentário) e um comando SET @@GLOBAL.GTID_PURGED, para que o dump possa alimentar uma réplica ou servir de ponto de partida para um PITR baseado em binlog.","when":"Para bancos de até algumas dezenas de GB, para mover schemas / tabelas e para migração lógica entre versões.","caution":"--single-transaction só é consistente para InnoDB; tabelas MyISAM saem inconsistentes. DDL (ALTER / RENAME / TRUNCATE) em uma tabela durante o dump faz o dump falhar ou perder a tabela. --source-data / --set-gtid-purged obtêm um breve global read lock no início (exige o privilégio RELOAD); se uma consulta longa estiver rodando nesse momento, todas as gravações travam enquanto o lock espera. Um dump parcial (--databases) ainda grava todos os GTIDs; use --set-gtid-purged=OFF ao mover um subconjunto para outro servidor. O dump é single-threaded; para dados grandes prefira o dump do MySQL Shell ou o XtraBackup.","note":"--source-data substituiu --master-data no 8.0.26. O mysqlpump ficou obsoleto no 8.0.34 e foi removido no 8.4; use util.dumpInstance do MySQL Shell para backups lógicos paralelos.","since":"MySQL 8.0.26","tags":["mysqldump","backup","single-transaction","gtid","logical backup","dump"]},{"id":"mysqlsh-dump-load","task":"Dump / load paralelo com MySQL Shell (util.dumpInstance, loadDump)","category":"Backup e 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":"Divide as tabelas em chunks e faz o dump / load com muitas threads; tanto o dump quanto o restore são muitas vezes mais rápidos que o mysqldump. O diretório do dump guarda as coordenadas de GTID e binlog em @.json.","when":"Para backups lógicos de centenas de GB, migração lógica durante upgrades e migrações on-prem → nuvem (RDS, HeatWave).","caution":"--consistent=true obtém um breve global read lock / backup lock; as gravações esperam se uma consulta longa estiver rodando. O loadDump usa LOAD DATA LOCAL, então o destino precisa de local_infile=ON, que deve ser desligado depois. Um load interrompido retoma de onde parou (arquivo de progresso); use --resetProgress para recomeçar. As contas de usuário não são carregadas por padrão (--loadUsers=true). --skipBinlog=true desabilita o binlog durante o load; mantenha false se o destino tiver réplicas.","note":"Isto não é um backup físico; para PITR aplique os binlogs a partir do valor gtidExecuted no @.json do dump. As opções ocimds / compatibility geram dumps que respeitam as restrições do HeatWave / RDS.","since":"MySQL Shell 8.0.21","tags":["mysqlsh","dumpinstance","loaddump","parallel","logical backup","migration"]},{"id":"xtrabackup-full-incremental","task":"Backup físico full + incremental e restore com XtraBackup","category":"Backup e 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":"Faz um backup físico a quente copiando os arquivos InnoDB e o redo log com o servidor em execução; um backup incremental contém apenas as páginas alteradas desde o backup anterior. A etapa de prepare aplica o redo e torna o backup consistente.","when":"Para bancos grandes que precisam de restores rápidos (muitas vezes mais rápidos que o lógico), para alimentar réplicas e para estratégias de full diário + incremental de hora em hora.","caution":"A versão do XtraBackup deve corresponder à série de versão do servidor (servidor 8.0 → XtraBackup 8.0, 8.4 → 8.4); se o servidor usar um formato de redo / data dictionary mais novo que o build do XtraBackup, o backup é recusado. Um backup sem prepare é inconsistente. Esquecer --apply-log-only nas etapas intermediárias inutiliza os incrementais posteriores. O datadir deve estar vazio para o restore; --move-back economiza disco, mas consome o backup. Usuário de backup: BACKUP_ADMIN, PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT e SELECT em performance_schema.log_status, keyring_component_status, replication_group_members.","note":"xtrabackup_binlog_info guarda o arquivo / posição do binlog e o conjunto de GTID do backup; o PITR reaplica os binlogs a partir desse ponto. Para transmitir para outro host use --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":"Recuperação point-in-time com binlogs: encontrar e pular a transação errada","category":"Backup e 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":"Após restaurar o backup, reaplica os binlogs em ordem para levar o banco ao ponto desejado. Com GTID ligado, as transações que já estão no backup são puladas automaticamente; --exclude-gtids remove apenas a operação errada e mantém todas as mudanças posteriores.","when":"Após um DROP / DELETE / UPDATE errado, para recuperar sem perder as mudanças feitas entre o backup e o incidente.","caution":"Restaure em um servidor separado, não em produção; verifique e então mova apenas a tabela afetada. --start/--stop-datetime são interpretados no fuso horário da máquina que executa o mysqlbinlog. --stop-position se aplica apenas ao último arquivo informado; para vários arquivos, reaplique os anteriores por completo em um comando separado. --exclude-gtids só é seguro para uma operação independente; se transações posteriores gravarem na tabela removida, elas também falham. Os binlogs necessários não podem ter sido expurgados na source; mantenha a retenção de binlog maior que pelo menos um intervalo de backup.","note":"Execute o mysqlbinlog e o mysql em um único pipe com todos os arquivos em um só comando; reaplicar os arquivos um a um quebra tabelas temporárias e transações que atravessam arquivos. Para conjuntos de binlog muito grandes, uma alternativa é colocar os binlogs como relay logs no servidor de restore e aplicá-los com a SQL thread (paralela).","since":"MySQL 8.0","tags":["pitr","mysqlbinlog","binlog","point in time","exclude-gtids","recovery"]},{"id":"innodb-cluster-status","task":"Verificar a saúde do 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":"Mostra o estado geral do cluster (OK / OK_NO_TOLERANCE / NO_QUORUM), o primário, o estado de cada membro e as filas de certification / applier; as filas revelam qual membro está atrasado e o risco de flow control.","when":"Antes e depois de toda intervenção; em alertas, lentidão de gravações ou quando um membro mostra RECOVERING / ERROR / UNREACHABLE.","caution":"O statusText deve dizer 'can tolerate up to ONE failure' (3 membros). Com NO_QUORUM as gravações param; use forceQuorumUsingPartitionOf apenas quando tiver certeza de que a outra partição está fora, senão ocorre split-brain. Um membro cujo apply_queue continua crescendo dispara o flow control e deixa as gravações no primário lentas. Um RECOVERING longo significa que a recuperação por clone / incremental está rodando; para ERROR verifique o error log e tente cluster.rejoinInstance(). Caracteres especiais em senhas (#, @) devem ser codificados em URL na URI (# → %23).","note":"MEMBER_COMMUNICATION_STACK chegou no 8.0.27; a pilha MYSQL transporta o tráfego do GR pela 3306 com TLS normal e autenticação de usuário (o XCOM usa uma porta separada, normalmente 33061). No 8.4 group_replication_consistency tem padrão BEFORE_ON_PRIMARY_FAILOVER e exit_state_action tem padrão OFFLINE_MODE.","since":"MySQL 8.0","tags":["innodb cluster","group replication","mysqlsh","status","flow control","quorum"]},{"id":"innodb-cluster-switch-primary","task":"Switchover planejado do primário no 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":"Move o papel de primário para outro membro de forma controlada no modo single-primary; o antigo primário fica super_read_only, o novo aplica seu acúmulo e abre para gravações. O MySQL Router descobre o novo primário automaticamente.","when":"Antes de manutenção, patch do SO ou upgrade do primário e para mudanças de hardware.","caution":"As transações abertas no antigo primário são encerradas quando o timeout expira; sem timeout, a troca espera por elas e demora mais. Se a aplicação não conecta pelo Router, você mesmo precisa redirecioná-la. Com BEFORE_ON_PRIMARY_FAILOVER as gravações esperam até que o novo primário tenha esvaziado seu acúmulo; confirme antes no cluster status que o apply_queue está vazio. No InnoDB Cluster prefira o comando do Shell; ele permanece consistente com os metadados.","note":"group_replication_set_as_primary chegou no 8.0.13; o parâmetro timeout foi adicionado no 8.0.29. Em um failover não planejado o GR elege o novo primário sozinho (group_replication_member_weight define a preferência).","since":"MySQL 8.0.13","tags":["innodb cluster","switchover","primary","group replication","set_as_primary","maintenance"]},{"id":"innodb-cluster-reboot-outage","task":"Trazer o cluster de volta após uma indisponibilidade completa (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":"Refaz o bootstrap do grupo após uma queda de energia ou um restart simultâneo de todos os nós, quando não há quorum; escolhe o membro com o maior conjunto de GTID e reintegra os demais.","when":"Quando o cluster status reporta 'Cluster is not reachable' e todos os membros aparecem como OFFLINE.","caution":"Use apenas quando todos os membros estiverem OFFLINE; se um membro ainda estiver ONLINE o grupo está vivo e os demais entram com rejoinInstance. Inicie todos os nós antes de executá-lo: se um membro inacessível estiver mais atualizado, suas transações são perdidas. force: true ignora membros ausentes; é o último recurso. A opção primary: 'host:port' força um membro específico como primário.","note":"As opções dryRun, primary e force chegaram no Shell 8.0.31; versões anteriores funcionavam com prompts interativos. Mesmo com group_replication_start_on_boot=ON o grupo não se forma sozinho após uma indisponibilidade completa; o bootstrap precisa ser feito deliberadamente a partir de um único ponto.","since":"MySQL Shell 8.0.31","tags":["innodb cluster","outage","reboot","bootstrap","mysqlsh","disaster"]},{"id":"mysql-router-bootstrap","task":"Fazer o bootstrap do MySQL Router em um InnoDB Cluster","category":"Router e proxy","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":"Registra o Router nos metadados do cluster e gera a conta e a configuração; a aplicação alcança o primário atual pela porta RW e os secundários em round-robin pela porta RO.","when":"Ao colocar uma camada de failover transparente na frente de um InnoDB Cluster / ClusterSet / ReplicaSet; tipicamente um Router por servidor de aplicação.","caution":"O Router não guarda estado; rodá-lo ao lado da aplicação evita um ponto único de falha, um único Router central não. A conta de bootstrap é usada apenas durante o bootstrap; o Router lê os metadados com sua própria conta (routeruser). Ele descobre as mudanças de topologia pelo metadata cache sem refazer o bootstrap. A porta de split RW (6450) envia leituras dentro de uma transação ao primário e as demais aos secundários; cuidado com aplicações que esperam read-your-writes. A versão do Router não deve ser mais antiga que os servidores MySQL do cluster.","note":"A porta de separação leitura/escrita (6450) chegou no 8.2. As conexões existentes caem no failover; a aplicação precisa ter lógica de reconexão (retry).","since":"MySQL Router 8.0","tags":["mysql router","bootstrap","innodb cluster","failover","read write split","6446"]},{"id":"proxysql-rw-split","task":"Separação leitura/escrita e health checks de réplicas com ProxySQL","category":"Router e proxy","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":"Gerencia automaticamente os hostgroups writer (10) e reader (20) com base na flag read_only; encaminha SELECTs às réplicas e leituras com lock e gravações à source; remove temporariamente uma réplica que excede max_replication_lag (SHUNNED).","when":"Para distribuir a carga de leitura em uma topologia de replicação assíncrona sem mexer na aplicação; para pooling de conexões e roteamento / cache / firewall por consulta.","caution":"A configuração tem 3 camadas (MEMORY → RUNTIME → DISK): sem LOAD ... TO RUNTIME nada muda, sem SAVE ... TO DISK tudo se perde no restart. A verificação de read_only exige super_read_only=ON nas réplicas; caso contrário as réplicas são movidas para o hostgroup writer. Enviar todo SELECT às réplicas causa erros de read-after-write por causa do lag; escrever regras apenas para consultas pesadas / de relatório com base em stats_mysql_query_digest é mais seguro. A interface de administração é SQLite: funções do MySQL como LEFT() não existem, use substr(). Altere a conta padrão admin:admin (admin-admin_credentials).","note":"A verificação de max_replication_lag exige REPLICATION CLIENT para o usuário de monitoramento. Para Group Replication / InnoDB Cluster use a tabela 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 online: ALGORITHM=INSTANT / INPLACE, LOCK=NONE e acompanhamento do progresso","category":"Operações online","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 altera apenas o data dictionary e termina imediatamente, independentemente do tamanho da tabela. INPLACE + LOCK=NONE processa a tabela no próprio local permitindo leituras e gravações concorrentes. A última consulta mostra em que estágio está um ALTER em execução e seu percentual.","when":"Antes de mudanças de schema em tabelas de produção; para saber quais operações podem rodar sem downtime e estimar quando um ALTER longo vai terminar.","caution":"INSTANT e INPLACE ainda obtêm um breve metadata lock exclusivo no início e no fim; se uma transação longa estiver segurando a tabela, o ALTER espera e toda consulta atrás dele entra na fila (veja o diagnóstico de metadata lock). Reduza lock_wait_timeout na sessão (SET SESSION lock_wait_timeout = 5). O DML que chega durante o INPLACE é registrado até innodb_online_alter_log_max_size; se excedido, o ALTER sofre rollback no final. Mudanças de tipo de coluna, conversão de charset e mudanças de PK precisam de COPY e bloqueiam gravações; em tabelas grandes use gh-ost / pt-online-schema-change. Em uma réplica o ALTER roda single-threaded pela mesma duração; um ALTER INPLACE grande causa lag na réplica, o INSTANT não.","note":"O INSTANT ADD COLUMN chegou no 8.0.12 apenas para a última coluna; desde o 8.0.29 colunas podem ser adicionadas em qualquer posição e INSTANT DROP COLUMN é suportado. Aumentar um VARCHAR é apenas metadado quando o número de bytes de comprimento não muda (o limite de 255 bytes não é ultrapassado); conclui imediatamente com INPLACE, não INSTANT. Uma coluna indexada não pode ser removida com INSTANT; remova o índice primeiro.","since":"MySQL 8.0.29","tags":["online ddl","instant","inplace","alter table","lock=none","progress"]},{"id":"pt-online-schema-change","task":"ALTER sem bloqueio em uma tabela grande com pt-online-schema-change","category":"Operações online","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":"Cria uma cópia vazia com a nova estrutura, copia as linhas em chunks, espelha as mudanças durante a cópia com triggers e por fim troca as tabelas com um RENAME atômico. Desacelera / pausa sozinho quando a carga ou o lag das réplicas passam dos limites.","when":"Para ALTERs que precisam de COPY (tipo de coluna, charset, mudança de PK) ou que causariam um lag longo nas réplicas.","caution":"A tabela precisa de uma PK ou unique key. Os triggers adicionam overhead a toda gravação durante a migração; em tabelas com gravações muito intensas o gh-ost tem menos impacto. Se tabelas filhas referenciam esta tabela via foreign keys, é necessário --alter-foreign-keys-method=auto. Para contas caching_sha2_password adicione s=1 (TLS) ao DSN; caso contrário a conexão com a réplica falha com 'Authentication requires secure connection'. O DSN de --check-replica-lag não herda usuário / senha do DSN principal; especifique-os. A troca obtém um breve metadata lock; mantenha lock_wait_timeout baixo, ele tenta de novo se o lock não puder ser obtido.","note":"Por padrão as réplicas são descobertas via processlist pelo IP; se esses IPs forem inacessíveis, use uma tabela de DSN com --recursion-method=dsn=D=percona,t=dsns. No 3.7 --check-slave-lag foi renomeado para --check-replica-lag (nome antigo obsoleto).","since":"Percona Toolkit 3.7","tags":["pt-online-schema-change","pt-osc","percona toolkit","alter","trigger","online schema change"]},{"id":"gh-ost-migration","task":"Mudança de schema online sem triggers com gh-ost","category":"Operações online","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":"Cria uma ghost table e copia as linhas; aplica as mudanças concorrentes lendo o binlog em vez de triggers. Throttling, pausa e o momento do cut-over são controlados em tempo de execução pelo socket ou por arquivos de flag.","when":"Em tabelas grandes com muitas gravações, em que o overhead de triggers é inaceitável e você quer escolher você mesmo o momento do cut-over (ex.: uma janela de tráfego baixo).","caution":"Exige binlog_format=ROW e binlog_row_image=FULL; a réplica à qual ele se conecta precisa de log_replica_updates=ON. O usuário precisa de SUPER ou REPLICATION CLIENT / REPLICATION SLAVE mais ALL na tabela. Tabelas com foreign keys (pai ou filha) não são suportadas. Após o cut-over a tabela antiga permanece como _<table>_del; remova-a manualmente depois de verificar (--ok-to-drop-table a remove automaticamente). Versões do gh-ost anteriores à 1.1.8 usam SHOW SLAVE STATUS e param com o erro 1064 no MySQL 8.4; o suporte ao 8.4 chegou na 1.1.8. O gh-ost cria ele mesmo o arquivo indicado em --postpone-cut-over-flag-file; o cut-over não acontece até que o arquivo seja removido.","note":"As opções --test-on-replica e --migrate-on-replica permitem testar e verificar a alteração primeiro apenas em uma réplica. O motivo do throttle e o ETA aparecem na saída do comando 'status'.","tags":["gh-ost","online schema change","binlog","cut-over","alter","triggerless"]},{"id":"ps-top-digests","task":"Encontrar as consultas mais caras (digest do performance_schema)","category":"Desempenho","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":"Classifica as consultas normalizadas pelo tempo total, com número de chamadas, latência média e p95, participação no total, linhas examinadas / enviadas por chamada, execuções sem índice e tabelas temporárias gravadas em disco. A segunda consulta mostra em quais esperas (IO, locks, redo) o tempo é gasto.","when":"Primeira parada quando a carga de CPU / IO sobe ou os usuários relatam 'o banco está lento'; funciona mesmo com o slow log desligado.","caution":"Os valores são cumulativos desde o último restart ou TRUNCATE TABLE performance_schema.events_statements_summary_by_digest; tire dois snapshots e compare-os para ver a atividade atual. A tabela é limitada a performance_schema_digests_size linhas; quando cheia, novas consultas são agregadas em uma única linha com DIGEST NULL. DIGEST_TEXT é cortado em performance_schema_max_digest_length (1024) bytes. Os tempos estão em picossegundos. Uma razão rows_exam_per_call / rows_sent_per_call alta é o sinal mais claro de índice ausente.","note":"As colunas QUANTILE_95 / QUANTILE_99 e QUERY_SAMPLE_TEXT surgiram na 8.0. Os mesmos dados em unidades legíveis estão disponíveis nas views sys.statement_analysis e 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":"O que está rodando agora: sessões ativas, latência, locks e transações (sys.session)","category":"Desempenho","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":"Enriquece o SHOW PROCESSLIST com dados do performance_schema: latência do statement em execução, percentual de progresso, tempo de espera por lock, linhas examinadas, informações de full scan / tabela temporária em disco e estado da transação aberta em uma só linha. Também lista sessões em Sleep que mantêm uma transação aberta.","when":"Nos primeiros 30 segundos de um incidente: qual consulta está rodando há quanto tempo, quem está esperando por locks, qual sessão ociosa mantém uma transação aberta.","caution":"sys.session faz vários joins sobre o performance_schema; com milhares de conexões a própria consulta pode levar segundos, então use as views x$ e LIMIT para monitoramento frequente. progress só é preenchido com os instrumentos de stage habilitados e para operações que reportam progresso, como ALTER. Uma sessão em Sleep com trx_state=ACTIVE é uma transação esquecida por uma aplicação / pool de conexões usando autocommit=0, a causa mais comum de problemas de metadata lock e purge.","note":"sys.processlist retorna os mesmos dados incluindo as threads de background. Para encerrar: KILL QUERY conn_id (só o statement) ou KILL conn_id (a conexão; a transação sofre rollback).","since":"MySQL 8.0","tags":["sys.session","processlist","active sessions","incident","trx","session"]},{"id":"metadata-lock-diagnose","task":"Diagnosticar 'Waiting for table metadata lock' e encontrar o verdadeiro bloqueador","category":"Desempenho","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":"Mostra em qual metadata lock de qual sessão um DDL como ALTER / TRUNCATE / RENAME está esperando, e as consultas enfileiradas atrás do DDL. O bloqueador geralmente é uma sessão em Sleep que leu a tabela e nunca fechou sua transação.","when":"Quando, após o início de um ALTER, todas as consultas naquela tabela se acumulam em 'Waiting for table metadata lock'.","caution":"Um DDL em espera também bloqueia os SELECTs que chegam depois dele; decida rápido durante o incidente: faça KILL na sessão bloqueadora ou cancele o ALTER (KILL QUERY). O PROCESSLIST_INFO do bloqueador pode ser NULL (ocioso); use performance_schema.events_statements_history ou sys.session.last_statement para ver seu último statement. Prevenção: execute DDL após SET SESSION lock_wait_timeout = 5 para que o ALTER desista rápido, e evite transações abertas longas na aplicação.","note":"O instrumento wait/lock/metadata/sql/mdl vem habilitado por padrão na 8.0; na 5.7 ele precisa ser habilitado em setup_instruments. sys.schema_table_lock_waits também lista o próprio lock SHARED_UPGRADABLE de um ALTER como bloqueador; o verdadeiro culpado é a sessão que detém um SHARED_READ / SHARED_WRITE em estado GRANTED.","since":"MySQL 8.0","tags":["metadata lock","mdl","alter","waiting for table metadata lock","lock","blocking"]},{"id":"innodb-deadlock-analysis","task":"Analisar deadlocks do InnoDB e registrar todos eles","category":"Desempenho","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":"Mostra as duas transações do deadlock, o lock que cada uma detém e aguarda (índice, lock_mode, registro) e qual delas o InnoDB desfez com rollback; o contador acompanha a frequência e o error log guarda os deadlocks anteriores.","when":"Quando a aplicação recebe o erro 1213 'Deadlock found when trying to get lock' ou os alertas de deadlock aumentam.","caution":"LATEST DETECTED DEADLOCK guarda apenas o último evento e se perde no restart. O nome do índice e o lock_mode (X, S, gap, insert intention) nas linhas 'HOLDS THE LOCK(S)' / 'WAITING FOR THIS LOCK TO BE GRANTED' explicam a causa; 'WE ROLL BACK TRANSACTION (n)' mostra a vítima. No 1213 a aplicação precisa repetir a transação inteira. Correções definitivas: acessar as linhas em ordem consistente, manter as transações curtas, usar o índice certo para reduzir gap locks e READ COMMITTED quando apropriado. log_error_verbosity=3 também habilita todas as mensagens Note; acompanhe o crescimento do error log. A variável de status Innodb_deadlocks não existe no MySQL Community; use INNODB_METRICS para o contador.","note":"Sob concorrência muito alta, a própria detecção de deadlock pode virar um gargalo de CPU; innodb_deadlock_detect=OFF só é considerado com um innodb_lock_wait_timeout baixo. Um lock wait timeout (1205) não é um deadlock; use a receita de locks bloqueadores para encontrar o bloqueador.","since":"MySQL 8.0","tags":["deadlock","innodb","1213","innodb status","lock","error log"]},{"id":"long-trx-history-list","task":"Transações de longa duração e history list length (atraso do purge)","category":"Desempenho","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":"Mostra quão atrasado está o purge (history list length) e as transações mais antigas que o seguram: dono, idade, linhas modificadas e o último SQL executado.","when":"Quando o undo tablespace cresce, quando as mesmas consultas ficam mais lentas com o tempo (elas varrem versões antigas das linhas) ou em alertas de espaço em disco.","caution":"A causa mais comum é uma sessão em Sleep com transação aberta, ou um consistent snapshot esquecido sob REPEATABLE READ (por exemplo, um mysqldump / relatório abandonado). Após o KILL, o rollback leva tanto quanto as linhas que a transação alterou; matar uma transação com trx_rows_modified alto significa um rollback longo e pesado em IO, e um restart não o encurta. O undo é truncado automaticamente quando o purge alcança (innodb_undo_log_truncate=ON).","note":"performance_schema.processlist surgiu na 8.0.22 e substitui o information_schema.PROCESSLIST, que está deprecated. 'History list length' no SHOW ENGINE INNODB STATUS dá o mesmo valor.","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":"Capturar um slow log completo curto e analisá-lo com pt-query-digest","category":"Desempenho","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":"Captura todas as consultas por uma janela curta com long_query_time=0; o pt-query-digest as agrupa por fingerprint e gera um relatório classificado com tempo total / médio / p95, linhas examinadas e uma consulta de exemplo.","when":"Quando os digests do performance_schema não bastam: análise com o texto completo do statement e parâmetros reais, comparação antes / depois de um deploy, revisão offline em outro host.","caution":"long_query_time é copiado do valor global quando a sessão inicia; conexões existentes em um pool não veem o novo limite até reconectarem. long_query_time=0 grava milhares de entradas por segundo em um servidor movimentado; acompanhe espaço em disco e IO, mantenha a janela curta e sempre reverta. Copie o arquivo para fora da produção para análise. O usuário que executa o pt-query-digest precisa de acesso de leitura ao arquivo (modo 640, mysql:mysql).","note":"log_slow_extra (8.0.14) grava campos extras como Bytes_sent, Read_first / Read_next e Created_tmp_disk_tables; o pt-query-digest os mostra no relatório. Para habilitar / desabilitar permanentemente, veja a receita 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":"Depurar um plano ruim com EXPLAIN ANALYZE e o optimizer trace","category":"Desempenho","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 mostra lado a lado os valores estimados (cost, rows) e reais (actual time, rows, loops) de cada etapa do plano; o optimizer trace mostra os caminhos de acesso considerados, seus custos e por que cada um foi escolhido ou rejeitado.","when":"Quando uma consulta fica lenta de repente (mudança de plano), o otimizador escolhe o índice errado, ou para achar a origem de uma divergência entre linhas estimadas e reais.","caution":"EXPLAIN ANALYZE executa a consulta de fato; cuidado com consultas pesadas em produção. Funciona com SELECT, TABLE e UPDATE / DELETE multi-tabela. Uma diferença de mais de 10x entre linhas estimadas e reais aponta para um problema de estatísticas / histograma (ANALYZE TABLE, histogramas). No lado interno de um nested loop, actual rows é por loop; total = rows × loops. Se MISSING_BYTES_BEYOND_MAX_MEM_SIZE > 0, o trace foi truncado; aumente optimizer_trace_max_mem_size. O trace guarda apenas o último statement da mesma sessão.","note":"EXPLAIN FORMAT=TREE surgiu na 8.0.16, EXPLAIN ANALYZE na 8.0.18. Para fixar um plano, optimizer hints (/*+ INDEX(t ix) */, JOIN_ORDER) dão controle mais fino que FORCE INDEX.","since":"MySQL 8.0.18","tags":["explain analyze","optimizer trace","execution plan","query tuning","index","plan"]},{"id":"histogram-statistics","task":"Criar e gerenciar histogramas para colunas não indexadas","category":"Índices e estatísticas","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":"Armazena a distribuição de valores de uma coluna (singleton ou equi-height) no dicionário de dados; o otimizador estima corretamente a seletividade de filtros em colunas não indexadas, melhorando a ordem de join e a qualidade do plano.","when":"Quando o EXPLAIN ANALYZE mostra grande diferença entre linhas estimadas e reais em colunas com distribuição desigual (por exemplo, status, tipo) onde não é desejável adicionar um índice.","caution":"Em colunas indexadas o otimizador usa index dives, então um histograma geralmente não tem efeito (a menos que eq_range_index_dive_limit seja excedido). No modo padrão MANUAL o histograma não é atualizado conforme os dados mudam; agende ANALYZE ... UPDATE HISTOGRAM. Tabelas grandes são amostradas conforme histogram_generation_max_mem_size (sampling-rate < 1). ANALYZE TABLE obtém um metadata lock breve; atualizar um histograma não altera as estatísticas da tabela (cardinalidade dos índices).","note":"Os histogramas surgiram na 8.0; a opção AUTO UPDATE foi adicionada na 8.4 e atualiza junto com o recálculo automático de estatísticas. O máximo é 1024 buckets; se houver menos valores distintos que buckets, é criado um histograma singleton.","since":"MySQL 8.0","tags":["histogram","statistics","optimizer","analyze table","selectivity","cardinality"]},{"id":"invisible-redundant-index","task":"Encontrar índices não usados / redundantes, torná-los invisíveis e removê-los com segurança","category":"Índices e estatísticas","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":"Lista índices não usados e índices cobertos por outro; tornar um índice invisível antes de removê-lo permite testar o comportamento da produção sem ele e reverter na hora (sem rebuild) se necessário.","when":"Ao limpar índices para reduzir o custo de escrita, a pressão no buffer pool e o uso de disco.","caution":"schema_unused_indexes se baseia apenas em estatísticas coletadas desde o último restart; consultas pouco frequentes, como relatórios mensais, podem não aparecer. Se as réplicas atendem cargas diferentes, verifique cada servidor separadamente. Um índice invisível continua sendo mantido no DML (o custo de escrita permanece), mas o otimizador o ignora; um índice único invisível continua garantindo a unicidade. Uma PRIMARY KEY não pode ser tornada invisível. Consultas que citam o índice em FORCE INDEX / USE INDEX falham quando ele fica invisível.","note":"Alternar a visibilidade de um índice altera apenas metadados e termina imediatamente. A lista de redundantes se baseia na ordem das colunas; o índice (a) é coberto por (a,b), mas (b) não é.","since":"MySQL 8.0","tags":["invisible index","unused index","redundant index","sys","drop index","index cleanup"]},{"id":"buffer-pool-sizing","task":"O buffer pool é grande o suficiente: hit ratio, wait_free e redimensionamento online","category":"Memória","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":"Mostra o tamanho do buffer pool, o hit ratio do cache, a contagem de páginas livres / sujas e o contador de espera por página livre (wait_free); redimensiona-o sem restart e acompanha o progresso.","when":"Quando o IO de leitura está alto, após adicionar / remover RAM ou durante o planejamento de capacidade.","caution":"O hit ratio sozinho engana; até 99% pode significar milhares de leituras em disco por segundo. Observe o crescimento por segundo de Innodb_buffer_pool_reads; wait_free > 0 significa que o buffer pool é pequeno demais ou que os page cleaners não dão conta. O novo tamanho é arredondado para um múltiplo de innodb_buffer_pool_chunk_size × instâncias. Pequenas paradas são possíveis durante o redimensionamento, mais ainda ao reduzir; evite horários de pico. Em um servidor dedicado comece com 60–75% da RAM; deixe espaço para a memória por conexão, o cache do SO e outros processos, pois swap é sempre pior que um buffer pool menor.","note":"Innodb_buffer_pool_resize_status_code / _progress surgiram na 8.0.31. innodb_dedicated_server=ON dimensiona o buffer pool e a capacidade de redo automaticamente a partir da RAM. sys.innodb_buffer_stats_by_table mostra o uso do buffer pool por tabela; ela varre INNODB_BUFFER_PAGE e é pesada em buffer pools grandes.","since":"MySQL 8.0","tags":["buffer pool","innodb","memory","hit ratio","resize","sizing"]},{"id":"partition-maintenance","task":"Manutenção de partições RANGE: adicionar partições futuras, arquivar / remover as antigas","category":"Particionamento","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":"Em uma tabela particionada por RANGE com base em data, adiciona a partição do próximo período, move um período antigo para uma tabela separada em milissegundos via EXCHANGE e remove a partição a um custo muito menor que DELETE.","when":"Para retenção mensal e arquivamento em tabelas que crescem com o tempo, como logs, eventos e trilhas de auditoria.","caution":"A coluna de particionamento precisa fazer parte de toda chave única (PK incluída). REORGANIZE PARTITION pmax reescreve os dados em pmax; mantenha pmax vazia e crie partições com antecedência (por exemplo, 3 meses). DROP PARTITION não pode ser desfeito e não é registrado linha a linha; nas réplicas ele roda como DDL. O destino do EXCHANGE precisa ter a mesma estrutura e não ser particionado; linhas fora do intervalo causam erro (WITHOUT VALIDATION é mais rápido, mas pode deixar entrar dados errados). DDL de partição obtém um metadata lock no nível da tabela. Para pruning, use a coluna de particionamento no WHERE sem envolvê-la em uma função.","note":"Na 8.0 o particionamento é suportado apenas pelo InnoDB (e NDB). Adicionar partições futuras / remover as antigas geralmente é automatizado com o Event Scheduler ou cron; ALTER TABLE ... TRUNCATE PARTITION remove os dados, mas mantém a partição.","since":"MySQL 8.0","tags":["partition","range","reorganize","exchange partition","retention","archive"]},{"id":"roles-least-privilege","task":"Montar um modelo de menor privilégio com roles (CREATE ROLE, DEFAULT ROLE)","category":"Segurança","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":"Concede privilégios a roles em vez de usuários individuais; as contas obtêm privilégios por pertencerem a roles. As mudanças acontecem em um só lugar, e auditoria e desligamento de pessoas ficam mais fáceis.","when":"Ao criar novas contas de aplicação / equipe e ao limpar servidores legados com privilégios emaranhados.","caution":"Uma role que não é default role não fica ativa na sessão (CURRENT_ROLE() NONE) e o usuário parece não ter privilégios; use SET DEFAULT ROLE ALL ou activate_all_roles_on_login=ON. Uma role também é uma conta (bloqueada, sem senha) e aparece em mysql.user. Use uma faixa de rede em vez de '%' para contas de aplicação. Nunca conceda ALL, SUPER, FILE, PROCESS ou CONNECTION_ADMIN a uma conta de aplicação. Revogar um privilégio de uma role afeta também as sessões ativas.","note":"mandatory_roles atribui roles a todas as contas automaticamente. CREATE USER ... DEFAULT ROLE concede as roles e as torna default ao mesmo tempo.","since":"MySQL 8.0","tags":["role","grant","least privilege","default role","security","privilege"]},{"id":"password-policy-lockout","task":"Política de senhas, bloqueio por falha de login e rotação de senha sem downtime","category":"Segurança","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":"Habilita uma política que rejeita senhas fracas, bloqueia temporariamente contas após falhas de login consecutivas e define regras de validade e reutilização de senha; com senhas duplas, a senha de uma conta de serviço é trocada sem downtime enquanto as aplicações são atualizadas uma a uma.","when":"Para auditorias de segurança / compliance (PCI, ISO 27001) e rotação de senhas de contas de serviço.","caution":"A política se aplica apenas a senhas novas / alteradas; ela não detecta as fracas já existentes. Em contas de serviço, FAILED_LOGIN_ATTEMPTS permite que um único cliente mal configurado bloqueie a conta e cause uma indisponibilidade; use-o em contas de pessoas. PASSWORD_LOCK_TIME é em dias (UNBOUNDED: até o desbloqueio manual); desbloqueie com ALTER USER ... ACCOUNT UNLOCK. PASSWORD EXPIRE causa indisponibilidades inesperadas em contas de serviço; nelas prefira PASSWORD EXPIRE NEVER mais rotação com senha dupla.","note":"Senhas duplas surgiram na 8.0.14, FAILED_LOGIN_ATTEMPTS / PASSWORD_LOCK_TIME na 8.0.19. O plugin validate_password da 5.7 foi substituído por um componente na 8.0; os nomes das variáveis usam ponto (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":"Exigir TLS, encontrar conexões sem TLS, renovar certificados sem restart","category":"Segurança","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":"Mostra a configuração TLS do servidor, a data de expiração do certificado e se cada conexão usa TLS; proíbe totalmente conexões TCP sem criptografia e renova certificados sem parar o servidor.","when":"Para auditorias de segurança / compliance, antes da expiração do certificado e ao rastrear clientes legados que conectam sem criptografia.","caution":"require_secure_transport=ON não afeta conexões por Unix socket e shared memory; elas contam como seguras. Encontre os clientes que conectam sem TLS antes de habilitá-lo, senão eles falham com o erro 3159. ALTER INSTANCE RELOAD TLS não afeta conexões existentes, só as novas; se o arquivo do certificado for inválido, ele retorna erro e mantém o certificado antigo. O certificado autoassinado gerado automaticamente não pode ser verificado por clientes com VERIFY_CA / VERIFY_IDENTITY; em produção use um certificado assinado pela sua CA.","note":"ALTER INSTANCE RELOAD TLS surgiu na 8.0.16, performance_schema.tls_channel_status na 8.0.21. Para exigir por conta, use ALTER USER ... REQUIRE SSL (ou REQUIRE X509).","since":"MySQL 8.0.21","tags":["tls","ssl","require_secure_transport","certificate","encryption","cert"]},{"id":"risky-accounts-audit","task":"Auditar contas de risco: senha vazia, host '%', SUPER, mysql_native_password","category":"Segurança","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":"Lista os achados de segurança por conta em uma linha: sem senha, conectável de qualquer lugar, plugin de autenticação legado, privilégios SUPER / GRANT / FILE e sem exigência de TLS; a segunda consulta mostra privilégios dinâmicos perigosos.","when":"Em auditorias de segurança periódicas, em um servidor recém-herdado e antes de um upgrade para a 8.4.","caution":"A consulta lê mysql.user diretamente e precisa de SELECT nela. Contas de role ficam bloqueadas e sem senha, então EMPTY PASSWORD é reportado apenas para contas desbloqueadas. Super_priv é o privilégio estático SUPER; como a 8.0 o divide em privilégios dinâmicos, verifique também a segunda consulta. Contas marcadas como NATIVE AUTH precisam migrar para caching_sha2_password antes da 8.4: ALTER USER 'u'@'h' IDENTIFIED WITH caching_sha2_password BY '...'; clientes / conectores antigos podem não suportar caching_sha2_password, teste-os antes.","note":"mysql_native_password foi deprecated na 8.0.34, vem desabilitado por padrão na 8.4 (pode ser habilitado com mysql_native_password=ON) e foi removido na 9.0.","since":"MySQL 8.0","tags":["security audit","mysql.user","mysql_native_password","super","privileges","audit"]},{"id":"upgrade-checker-84","task":"Pré-verificação de upgrade 8.0 → 8.4 LTS (util.checkForServerUpgrade)","category":"Upgrade","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":"Verifica o servidor atual contra a versão de destino: variáveis e privilégios removidos, parâmetros com novos defaults, métodos de autenticação legados, definições de coluna inválidas, problemas de foreign key e de partição. Achados de nível erro bloqueiam o upgrade.","when":"Antes de todo upgrade major / LTS; execute novamente após corrigir os achados.","caution":"Revise também os avisos: na 8.4 defaults como innodb_io_capacity (10000), innodb_log_buffer_size (64 MB), innodb_adaptive_hash_index (OFF), innodb_change_buffering (none), innodb_buffer_pool_instances e group_replication_consistency mudam e podem afetar a performance; fixe no my.cnf os valores cujo comportamento atual você quer manter. Privilégios removidos, como SET_USER_ID, são descartados durante o upgrade. Faça o upgrade de uma réplica primeiro, observe-a sob carga e então faça o switchover; downgrade binário da 8.4 para a 8.0 não é suportado, então o plano de retorno é um backup lógico ou uma réplica mantida na versão antiga.","note":"Removidos na 8.4: a sintaxe antiga de replicação, como START / STOP SLAVE, SHOW SLAVE STATUS e CHANGE MASTER TO, default_authentication_plugin (substituído por authentication_policy), binlog_transaction_dependency_tracking e mysqlpump. mysql_native_password vem desabilitado por padrão.","since":"MySQL Shell 8.0","tags":["upgrade","8.4","checkforserverupgrade","mysqlsh","lts","version upgrade"]},{"id":"charset-utf8mb4-convert","task":"Converter tabelas latin1 / utf8mb3 para utf8mb4","category":"Manutenção","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":"Encontra colunas e tabelas que não são utf8mb4 e gera o DDL de conversão; CONVERT TO altera tanto o default da tabela quanto todas as colunas de caracteres, habilitando emoji / caracteres de 4 bytes.","when":"Em schemas migrados da 5.x, em erros 'Incorrect string value' (1366) e quando joins entre colunas com collations diferentes não conseguem usar índices.","caution":"CONVERT TO reescreve a tabela com COPY e bloqueia escritas durante toda a operação (INPLACE não é suportado); em tabelas grandes rode o mesmo --alter via pt-online-schema-change / gh-ost. utf8mb4 usa 4 bytes por caractere: um VARCHAR(255) indexado passa a ter 1020 bytes; o limite é 3072 bytes com o row format DYNAMIC / COMPRESSED e 767 com COMPACT / REDUNDANT, acima do qual ocorre o erro 1071. Colunas VARCHAR / TEXT são promovidas a um tipo maior (TEXT → MEDIUMTEXT) quando necessário para manter a mesma capacidade de caracteres. Uma mudança de collation afeta ordenação e comparação: utf8mb4_0900_ai_ci é insensível a acentos e maiúsculas/minúsculas, então valores que antes eram diferentes podem colidir em um índice único (1062). Converta juntas as tabelas que fazem join entre si. A conexão do cliente também precisa usar utf8mb4.","note":"utf8 (utf8mb3) está deprecated na 8.0; desde a 8.0.30 aparece como utf8mb3 no SHOW CREATE TABLE. Para as regras de collation do turco (I com e sem ponto) use utf8mb4_tr_0900_ai_ci. O default da 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":"Fazer backup do log de transações","category":"Backup e log","command":"BACKUP LOG [Customer]\nTO DISK = N'D:\\Backup\\Customer_log_20260706_1200.trn'\nWITH COMPRESSION, CHECKSUM, STATS = 10;","what":"Faz um backup do log de transações e (no recovery model FULL/BULK_LOGGED) trunca a parte usada do log para que ela possa ser reutilizada.","when":"Regularmente no recovery model FULL (por exemplo, a cada 15 min), para a cadeia de recuperação point-in-time, e quando o arquivo de log cresce.","caution":"Só faz sentido no recovery model FULL/BULK_LOGGED (no SIMPLE o log é truncado automaticamente). Precisa existir antes pelo menos um backup FULL para que a cadeia de logs não seja quebrada. Defina uma estratégia correta de exclusão/sobrescrita para os arquivos de backup.","tags":["backup log","log backup","transaction log","trn","recovery","backup"]},{"id":"backup-full-diff","task":"Fazer backups FULL e DIFFERENTIAL","category":"Backup e log","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 faz backup do banco inteiro; DIFFERENTIAL faz backup dos extents alterados desde o último FULL.","when":"FULL: backup base diário/semanal. DIFF: backups intermediários rápidos entre FULLs.","caution":"Restaurar um DIFF exige seu backup FULL base. INIT sobrescreve o arquivo existente; com o nome de arquivo errado você perde um backup. CHECKSUM detecta corrupção cedo.","tags":["backup","full","differential","differential backup","bak","backup"]},{"id":"log-reuse-wait","task":"Por que o arquivo de log cresceu / por que não está truncando","category":"Backup e log","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":"A coluna log_reuse_wait_desc diz por que o log de transações não pode ser truncado (por exemplo, LOG_BACKUP, ACTIVE_TRANSACTION, REPLICATION, AVAILABILITY_REPLICA).","when":"Para encontrar a causa raiz quando o arquivo de log não para de crescer ou o log está cheio (erro 9002).","caution":"Se aparecer LOG_BACKUP, a solução é fazer um backup de log, não reduzir o arquivo. Apenas consulta; sem risco.","tags":["log_reuse_wait_desc","log growth","sys.databases","log backup","recovery","diagnostics"]},{"id":"shrink-log","task":"Reduzir o arquivo de log","category":"Backup e log","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":"Reduz o tamanho físico do arquivo de log de transações e devolve espaço ao sistema operacional.","when":"Quando o log ficou permanentemente inchado após um crescimento anormal pontual (transação grande/rebuild de índice).","caution":"PERIGOSO/CUIDADO: reduzir (shrink) rotineiramente é MÁ prática; a performance cai enquanto o log volta a crescer e a fragmentação de VLFs aumenta. Faça um backup de log antes, senão o tamanho não diminui. Reduza apenas um arquivo de log que cresceu sem necessidade, não o arquivo de dados. Depois, faça-o crescer de volta a um tamanho adequado em um único passo.","tags":["shrink","dbcc shrinkfile","shrink log","log","vlf","caution"]},{"id":"vlf-count","task":"Mostrar a quantidade de VLFs (Virtual Log Files)","category":"Backup e log","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":"Retorna o número de arquivos de log virtuais (VLFs) dentro do log de transações. VLFs demais degradam a performance de inicialização/recovery/backup de log.","when":"Quando o log está lento ou a inicialização do banco demora; ao revisar a configuração de crescimento do log.","caution":"Centenas/milhares de VLFs são um sinal de alerta; a solução é reduzir o log e fazê-lo crescer de novo em incrementos adequadamente grandes (por exemplo, passos de 8GB). Apenas consulta; sem risco.","since":"SQL Server 2016 SP2","note":"A DMV sys.dm_db_log_info surgiu com o SQL Server 2016 SP2 e 2017; antes disso, os VLFs eram contados pelo número de linhas da saída não documentada do DBCC LOGINFO.","tags":["vlf","dm_db_log_info","dbcc loginfo","log","virtual log file","performance"]},{"id":"open-transaction","task":"Encontrar a transação aberta mais antiga (ACTIVE_TRANSACTION)","category":"Backup e log","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":"Mostra a transação aberta (sem commit/rollback) mais antiga e a sessão que a detém. Uma transação aberta impede o truncamento do log (LOG_REUSE_WAIT = ACTIVE_TRANSACTION).","when":"Para encontrar a causa raiz quando o log não diminui apesar dos backups de log e log_reuse_wait_desc = ACTIVE_TRANSACTION.","caution":"Confirme com o responsável pelo negócio antes de dar KILL na sessão que mantém uma transação aberta longa; o rollback pode demorar muito. Apenas consulta; sem risco.","tags":["dbcc opentran","open transaction","active_transaction","dm_tran_active_transactions","log","diagnostics"]},{"id":"add-data-file","task":"Adicionar um arquivo de dados a um banco","category":"Armazenamento","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":"Adiciona um novo arquivo de dados (.ndf) a um filegroup existente para aumentar a capacidade e distribuir o I/O.","when":"Quando o disco está cheio, ou quando você quer distribuir o I/O entre vários discos.","caution":"As escritas no novo arquivo são balanceadas por proportional fill; o arquivo mais vazio enche primeiro. Especifique FILEGROWTH como MB fixo, não como percentual. Definir MAXSIZE evita crescimento descontrolado.","tags":["add file","add data file","ndf","alter database","filegroup","storage"]},{"id":"add-filegroup","task":"Adicionar um filegroup","category":"Armazenamento","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":"Cria um novo filegroup com um arquivo dentro; permite colocar tabelas/índices em um disco/filegroup separado.","when":"Para separar dados de arquivo/frios, para backup/restore no nível de filegroup e para separação de I/O.","caution":"Um filegroup vazio não pode ser usado nem ter backup; adicione pelo menos um arquivo a ele. Mudar o filegroup padrão afeta onde os novos objetos são criados.","tags":["filegroup","filegroup","add filegroup","alter database","ndf","storage"]},{"id":"modify-file-growth","task":"Alterar tamanho / autogrowth de arquivo","category":"Armazenamento","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":"Pré-aloca um arquivo de dados/log ou define seu incremento/limite superior de autogrowth.","when":"Para corrigir incrementos de crescimento pequenos e descontrolados, pré-alocar espaço ou definir um MAXSIZE.","caution":"Autogrowth percentual produz incrementos muito grandes em arquivos grandes; use MB fixo. Sem Instant File Initialization, o crescimento do arquivo de dados bloqueia. SIZE não consegue reduzir um arquivo (é preciso shrink).","tags":["modify file","autogrowth","filegrowth","size","alter database","storage"]},{"id":"move-file","task":"Mover um arquivo de dados/log para outro local","category":"Armazenamento","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":"Altera a localização física de um arquivo do banco: o novo caminho é definido nos metadados, o arquivo é movido fisicamente com o banco offline e então o banco volta a ficar online.","when":"Ao substituir um disco ou mover para outra unidade para ganhar espaço.","caution":"OFFLINE + ROLLBACK IMMEDIATE derruba todas as conexões ativas; planeje o downtime. Não coloque o banco ONLINE antes de copiar de fato o arquivo para o novo caminho no SO, senão o banco fica SUSPECT. O tempdb exige outro método (MODIFY FILE + restart do serviço do SQL Server).","tags":["move file","move file","modify file","offline","online","mdf","ldf","storage"]},{"id":"add-tempdb-file","task":"Adicionar um arquivo de dados ao tempdb","category":"Armazenamento","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":"Adiciona um arquivo de dados extra ao tempdb para reduzir a contenção de alocação (PFS/GAM/SGAM) e distribuir o I/O.","when":"Em sistemas com contenção no tempdb (esperas PAGELATCH_UP) ou uso intenso do tempdb.","caution":"Todos os arquivos de dados do tempdb precisam ter o MESMO tamanho e incremento de crescimento (por causa do proportional fill). O arquivo adicionado é usado imediatamente, sem restart; se os arquivos existentes tiverem tamanhos diferentes, iguale todos antes, senão o novo arquivo (vazio) recebe uma carga desproporcional. O número de arquivos costuma acompanhar o número de cores (até 8); o setup do SQL Server 2016+ faz isso por padrão.","tags":["tempdb","add file","tempdb file","ndf","contention","pagelatch","storage"]},{"id":"index-rebuild-reorg","task":"Rebuild / reorganize de índice","category":"Manutenção","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 recria o índice do zero (elimina a fragmentação por completo, atualiza as estatísticas); REORGANIZE compacta o nível folha no lugar (leve, sem bloqueio).","when":"REORGANIZE para fragmentação de 5-30%, REBUILD acima de 30%. Em janelas de manutenção para tabelas grandes.","caution":"ONLINE = ON só está disponível no Enterprise/Developer; use OFF no Standard (a tabela fica bloqueada). REBUILD gera muito log e precisa de espaço. MAXDOP e SORT_IN_TEMPDB afetam o uso de recursos.","tags":["index","rebuild","reorganize","alter index","fragmentation","maintenance","online"]},{"id":"update-statistics","task":"Atualizar estatísticas","category":"Manutenção","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":"Atualiza as estatísticas de coluna/índice que o otimizador usa; garante planos de execução e estimativas de cardinalidade corretos.","when":"Após grandes alterações/cargas de dados, em regressões de plano; um rebuild de índice já atualiza as estatísticas por completo (não é preciso fazer separadamente).","caution":"FULLSCAN é preciso, mas caro; gera carga de I/O em tabelas grandes. sp_updatestats atualiza apenas as estatísticas alteradas e usa amostragem padrão. Repetir UPDATE STATISTICS no mesmo índice após um REBUILD de índice é desnecessário.","tags":["update statistics","statistics","sp_updatestats","fullscan","optimizer","maintenance"]},{"id":"dbcc-checkdb","task":"Verificação de integridade (DBCC CHECKDB)","category":"Manutenção","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":"Verifica a integridade física e lógica do banco (estruturas de página, alocação, consistência de índices) e reporta corrupção.","when":"Na manutenção regular (semanal), sob suspeita de problemas de hardware/IO, após erros 823/824.","caution":"Usa I/O e tempdb intensamente; execute em uma janela de manutenção. Se forem encontrados erros, REPAIR_ALLOW_DATA_LOSS deve ser o ÚLTIMO recurso e CAUSA PERDA DE DADOS; considere primeiro restaurar a partir de um backup íntegro. PHYSICAL_ONLY é mais rápido, mas pula as verificações lógicas.","tags":["dbcc checkdb","integrity","corruption","corruption","integrity","maintenance"]},{"id":"index-fragmentation","task":"Mostrar a fragmentação dos índices","category":"Manutenção","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":"Lista o percentual de fragmentação e a quantidade de páginas dos índices; a base para a decisão entre rebuild/reorganize.","when":"Antes da manutenção, para decidir quais índices tratar.","caution":"A fragmentação é irrelevante em índices pequenos (< 1000 páginas); eles são filtrados. O modo 'DETAILED' é mais preciso, mas muito caro; 'LIMITED' geralmente basta. Apenas consulta; sem risco.","tags":["fragmentation","dm_db_index_physical_stats","index","frag","maintenance","diagnostics"]},{"id":"kill-spid","task":"Matar uma sessão (SPID)","category":"Sessão","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":"Encerra o session_id (SPID) especificado; sua transação aberta sofre rollback.","when":"Para parar uma sessão que segura locks, roda uma consulta descontrolada/longa ou não libera sua conexão.","caution":"Em uma transação aberta grande, o rollback pode demorar muito e não pode ser cancelado; acompanhe o progresso com KILL WITH STATUSONLY. Não mate SPIDs de sistema (is_user_process=0). Confirme o SPID correto.","tags":["kill","spid","kill session","dm_exec_sessions","dm_exec_requests","session"]},{"id":"blocking-chain","task":"Encontrar a cadeia de bloqueio (lock)","category":"Sessão","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":"Lista as sessões em espera e as sessões que as bloqueiam, com tempo de espera e a consulta que executam; torna visível a cadeia de locks.","when":"Para encontrar a origem da contenção de locks em reclamações de \"a aplicação trava / dá timeout\".","caution":"Confirme com o responsável pelo negócio antes de matar o bloqueador raiz (o SPID que não é bloqueado por ninguém, mas bloqueia os outros). Apenas consulta; sem risco.","tags":["blocking","lock","lock","dm_exec_requests","blocking_session_id","session","chain"]},{"id":"active-queries","task":"Mostrar as consultas ativas e seu custo","category":"Sessão","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":"Mostra as consultas de usuário em execução no momento com CPU, tempo decorrido, leituras/escritas e o texto exato do statement.","when":"Para descobrir qual consulta está consumindo recursos durante uma lentidão em andamento.","caution":"statement_start/end_offset extrai o statement exato em execução (não o batch inteiro). Apenas consulta; sem risco.","tags":["active queries","active query","dm_exec_requests","dm_exec_sql_text","cpu","session"]},{"id":"sp-configure-memory","task":"Configurar com sp_configure (max server memory)","category":"Configuração","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":"Limita a memória máxima que o SQL Server pode usar para o buffer pool; deixa RAM para o sistema operacional e outros componentes.","when":"Quando o SO/outros serviços no servidor estão sem memória, ou quando foi adicionada mais RAM.","caution":"Deixe RAM suficiente para o sistema operacional, SSAS/SSIS, CLR e stacks de threads (geralmente pelo menos 4-6 GB para o SO). Um valor baixo demais prejudica gravemente a performance do SQL Server. A mudança não é aplicada sem RECONFIGURE; essa configuração é dinâmica (não exige restart).","tags":["sp_configure","max server memory","reconfigure","memory","configuration","memory"]},{"id":"reconfigure-general","task":"Configuração geral com sp_configure e RECONFIGURE","category":"Configuração","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":"Define valores de configuração no nível do servidor; RECONFIGURE os aplica ao valor em execução.","when":"Ao alterar configurações do servidor como MAXDOP, o limite de paralelismo ou optimize for ad hoc workloads.","caution":"Configurações com is_dynamic = 0 exigem restart do SQL Server. RECONFIGURE WITH OVERRIDE ignora a validação de algumas configurações; use com cuidado. Anote o value_in_use antes de alterar qualquer coisa.","tags":["sp_configure","reconfigure","maxdop","cost threshold","sys.configurations","configuration"]},{"id":"ag-failover","task":"Failover de Availability Group","category":"Configuração","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":"Move o papel de primário do Availability Group para outra réplica; um failover planejado para uma réplica síncrona acontece sem perda de dados.","when":"Transferência de papel para manutenção/patching, failover quando o nó primário falha.","caution":"O comando FAILOVER normal é executado na réplica SECUNDÁRIA que vai assumir. FORCE_FAILOVER_ALLOW_DATA_LOSS só é usado quando o primário está inacessível ou em uma réplica assíncrona e pode CAUSAR PERDA DE DADOS; tenha muito cuidado se a sincronização não estiver saudável.","tags":["availability group","ag","failover","hadr","failover","alwayson","configuration"]},{"id":"change-recovery-model","task":"Alterar o recovery model do banco","category":"Configuração","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":"Altera o recovery model do banco; determina como o log é gerenciado e quais opções de recuperação existem.","when":"FULL: quando são necessários recuperação point-in-time/backups de log/AG. SIMPLE: em sistemas que não precisam de ponto de recuperação (dev/teste, DW).","caution":"Após mudar para FULL, faça um backup FULL para iniciar a cadeia de logs e configure backups de log regulares, senão o log não para de crescer. Mudar de FULL para SIMPLE quebra a cadeia de logs; você perde a recuperação point-in-time. Membros de AG precisam estar no recovery model 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":"Monitorar a saúde e o atraso do availability group (log send / redo queue, RPO)","category":"Always On e 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":"Mostra a saúde de conexão e sincronização das réplicas; por banco, a log send queue, a redo queue, as taxas de envio/redo, o tempo estimado para o redo alcançar e a diferença do último commit em relação ao primário (janela potencial de perda de dados); também retorna o estado do quorum do WSFC.","when":"Em um alerta NOT_HEALTHY / NOT SYNCHRONIZING no dashboard do AG, ao verificar RPO/RTO antes de um failover planejado ou quando usuários relatam dados desatualizados em uma secundária legível.","caution":"Uma log_send_queue crescente é a quantidade de log perdida se o primário falhar (RPO); uma redo_queue crescente é quanto tempo o banco leva para ficar online após o failover (RTO). Em uma secundária só a réplica local é visível; execute no primário para ter o quadro completo. data_loss_window_s só faz sentido enquanto houver tráfego de escrita. Consulta somente leitura; segura.","since":"2016","note":"secondary_lag_seconds é uma coluna do 2016+. Se a redo queue não para de crescer, verifique se a thread de redo na secundária está bloqueada (consultas de leitura longas, DDL) e procure esperas 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":"Failover forçado (FORCE_FAILOVER_ALLOW_DATA_LOSS) e recuperação pós-failover","category":"Always On e 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":"Torna uma réplica de DR o primário, aceitando perda de dados, quando o primário é perdido por completo; depois retoma a movimentação de dados suspensa nas outras réplicas e, quando o antigo primário volta, cria um snapshot para inspecionar as transações que nunca chegaram ao novo primário.","when":"Quando o data center primário está fora, sobrou apenas uma réplica assíncrona, ou uma réplica síncrona não está SYNCHRONIZED e ainda assim é preciso fazer failover.","caution":"PERDA DE DADOS: as transações após o último LSN hardened são perdidas. Obtenha antes o aval do negócio sobre o RPO. Após um failover forçado, todos os bancos secundários ficam SUSPENDED; o log não é truncado e cresce até o HADR RESUME. Se o quorum do WSFC for perdido, inicie antes o cluster com quorum forçado (PowerShell: Start-ClusterNode -FixQuorum), senão o comando falha. HADR RESUME no antigo primário descarta permanentemente as transações perdidas; não retome sem criar o snapshot.","note":"Para um failover planejado sem perda de dados, use o comando FAILOVER da receita ag-failover. AGs com CLUSTER_TYPE = NONE / EXTERNAL também usam FORCE_FAILOVER_ALLOW_DATA_LOSS; em EXTERNAL (Pacemaker) o failover é conduzido pelo gerenciador do cluster. Um snapshot precisa de todos os arquivos de dados lógicos da origem; para bancos com vários arquivos adicione uma entrada ON por arquivo de dados.","tags":["force failover","allow data loss","dr","availability group","hadr resume","data loss"],"untested":true},{"id":"ag-add-db-autoseed","task":"Adicionar um banco a um AG (automatic seeding) e monitorar o progresso do seeding","category":"Always On e 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":"Adiciona o banco ao AG transmitindo-o para as secundárias pelo endpoint (VDI) sem backup/restore manual; mostra a vazão do seeding, a conclusão estimada e o motivo de falha.","when":"Ao adicionar um novo banco a um AG, adicionar uma nova réplica ou reconstruir um banco secundário quebrado.","caution":"O seeding satura o link do endpoint e é sem compressão por padrão; para bancos muito grandes ou uma WAN fraca, backup/restore manual + JOIN é mais previsível. O log do primário não é truncado durante o seeding (log_reuse_wait_desc = AVAILABILITY_REPLICA). No 2016 a secundária precisa dos mesmos caminhos de pastas de dados/log do primário; no 2017+, se os arquivos do primário estão nos caminhos default da instância, a secundária usa seus próprios caminhos default. Para um banco com TDE, o certificado precisa ser restaurado antes em todas as secundárias. Sem GRANT CREATE ANY DATABASE na secundária, o seeding fica pendente.","since":"2016","note":"A compressão do seeding é habilitada com o trace flag 9567 (consome CPU). Início, conclusão e falhas do seeding são gravados no error log do SQL Server; para acompanhamento detalhado crie uma sessão de Extended Events separada com os eventos hadr_automatic_seeding_* e hadr_physical_seeding_*. Volte com 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":"Verificar o listener, seus IPs e a configuração de read-only routing","category":"Always On e 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":"Mostra o nome DNS do listener, a porta e o estado no cluster de cada IP de sub-rede; para cada cenário de primário na lista de read-only routing, para qual réplica e URL as conexões com intenção de leitura são roteadas.","when":"Quando as aplicações não conseguem conectar após um failover, conexões ApplicationIntent=ReadOnly caem no primário, ou uma nova sub-rede/réplica foi adicionada.","caution":"O read-only routing só funciona para conexões feitas pelo listener com ApplicationIntent=ReadOnly e um banco explícito; conexões diretas a um nome de instância não são roteadas. Uma réplica com read_only_routing_url vazio não pode ser destino de roteamento. Em um listener multi-subnet, clientes sem MultiSubnetFailover=True têm timeouts de conexão de 20-30 s após o failover. Consulta somente leitura; segura.","note":"Para balanceamento de carga no 2016+, a lista de roteamento usa parênteses aninhados: READ_ONLY_ROUTING_LIST = (('SQL02','SQL03'),'SQL01'). Se os IPs do listener aparecerem OFFLINE, verifique as dependências de recurso no lado do cluster (Failover Cluster Manager / Get-ClusterResource).","tags":["listener","read-only routing","applicationintent","multisubnetfailover","availability group","connection"],"untested":true},{"id":"logshipping-monitor","task":"Monitorar o status e a latência do log shipping","category":"Always On e 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":"Mostra a idade do último backup de log no primário, o último arquivo copiado/restaurado e a latência de restore na secundária junto com seus limites, e os erros dos jobs de backup/cópia/restore das últimas 24 horas.","when":"Quando o job de alerta do log shipping dispara (erros 14420/14421), antes de um teste de DR ou ao reportar quão atrasada está a secundária.","caution":"As tabelas de monitoramento contêm apenas o lado que o servidor enxerga: a tabela do primário é preenchida no primário/monitor, a da secundária na secundária/monitor. Um backup de log manual (fora do log shipping) quebra a cadeia e o job de restore continua falhando; use COPY_ONLY para backups de log avulsos. No modo STANDBY as conexões de usuário são derrubadas antes de cada restore. Consulta somente leitura; segura.","note":"As colunas de data estão no horário local do servidor; use as colunas *_utc ao comparar servidores em fusos horários diferentes. Se o job de restore registrar \"skipping log backup file\", esse arquivo já foi aplicado; para encontrar uma lacuna real, verifique a sequência FirstLSN/LastLSN com RESTORE HEADERONLY na secundária.","tags":["log shipping","sp_help_log_shipping_monitor","restore latency","dr","secondary","latency"],"untested":true},{"id":"backup-copy-only","task":"Fazer um backup avulso sem quebrar a cadeia (COPY_ONLY, striping, vazão)","category":"Backup e log","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":"Faz um backup FULL ou de log independente que não afeta a cadeia de backup regular (base diferencial e cadeia de logs); para bancos grandes, striping em vários arquivos e um transfer size maior encurtam o backup.","when":"Ao entregar uma cópia para teste/dev, antes de uma mudança arriscada ou quando um backup é solicitado para auditoria; sempre que precisar de um backup sem mexer na estratégia de backup agendada.","caution":"Um FULL avulso sem COPY_ONLY vira a base dos backups DIFF seguintes; se esse arquivo for apagado, os DIFFs ficam inúteis. COPY_ONLY não tem efeito junto com DIFFERENTIAL. Restaurar um backup com striping exige todos os arquivos; perder um deixa o backup inteiro inutilizável. BUFFERCOUNT x MAXTRANSFERSIZE de memória é alocado fora do buffer pool (256 MB no exemplo); reduza em um servidor sob pressão de memória.","note":"Para um banco com TDE, a compressão de backup exige MAXTRANSFERSIZE maior que 65536 (2016+). Defaults do servidor: sp_configure 'backup compression default' e 'backup checksum default'. No 2022 com hardware Intel QAT, WITH COMPRESSION (ALGORITHM = QAT_DEFLATE) está disponível.","tags":["copy_only","ad-hoc backup","stripe","maxtransfersize","buffercount","backup"]},{"id":"backup-to-url","task":"Backup para URL (Azure Blob SAS / storage compatível com S3)","category":"Backup e log","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":"Grava o backup diretamente em object storage: no Azure Blob como block blobs com uma credencial SAS, ou no 2022 em storage compatível com a API S3 (AWS S3, MinIO etc.) com uma credencial de access key. A credencial é escolhida automaticamente pela correspondência com o prefixo da URL.","when":"Para requisitos de backup off-site, cenários de migração para a nuvem/DR híbrido ou quando o armazenamento local de backup é insuficiente.","caution":"No Azure um único block blob comporta no máximo 50.000 blocos; com MAXTRANSFERSIZE de 4 MB isso dá cerca de 195 GB por arquivo, então faça striping de bancos grandes em várias URLs. No S3 um arquivo tem no máximo 10.000 partes; para bancos grandes aumente o MAXTRANSFERSIZE (até 20 MB, exige COMPRESSION) e faça striping em várias URLs (até 64). O S3 não suporta INIT/append; FORMAT sobrescreve um backup existente com o mesmo nome. Quando o SAS expira, os jobs de backup falham com erro; coloque a data de expiração na agenda. O segredo da credencial fica armazenado no master; principals com CONTROL SERVER podem usá-lo.","since":"2022","note":"Backup em block blob com SAS é 2016+, suporte a S3 é 2022+. O método legado com chave da storage account (IDENTITY = nome da conta) gera page blobs e não é recomendado. Para S3, o certificado TLS do endpoint precisa ser confiável para o servidor; para soluções on-prem como MinIO, a porta vai na URL (s3://minio.local:9000/bucket/...).","tags":["backup to url","azure blob","s3","credential","sas","cloud backup"],"untested":true},{"id":"backup-history-msdb","task":"Histórico de backups no msdb e verificação de backups ausentes","category":"Backup e log","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":"Lista o horário do último backup FULL/DIFF/LOG e a idade do backup de log para cada banco; para um banco, a cadeia de backup com sequência de LSN, tamanho comprimido, flag de checksum e caminho do arquivo.","when":"Na verificação matinal, para descobrir de quais arquivos um restore precisa, para responder \"quando foi o último backup\" em uma auditoria ou para ver se os backups de log estão rodando durante um alerta de log cheio.","caution":"O msdb só conhece backups feitos por esta instância; backups feitos em outro servidor ou em outra réplica do AG não aparecem (verifique cada réplica em um AG). O first_lsn de um backup de log precisa ser igual ao last_lsn do anterior; uma lacuna significa que a cadeia está quebrada. No recovery FULL, last_log NULL significa que nunca é feito backup do log e ele vai continuar crescendo. Consulta somente leitura; segura.","note":"O histórico do msdb cresce sem limite e deixa os jobs de backup lentos; expurgue-o regularmente com EXEC msdb.dbo.sp_delete_backuphistory @oldest_date = '2026-01-01';. Valores de type: D = FULL, I = DIFF, L = LOG, F = arquivo/filegroup.","tags":["backupset","msdb","backup history","last backup","lsn","backup chain"]},{"id":"backup-restore-progress","task":"Ver o progresso e a conclusão estimada de backup / restore / CHECKDB","category":"Backup e log","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":"Mostra o progresso percentual, o horário estimado de término e a espera atual de operações longas que reportam percent_complete (BACKUP, RESTORE, DBCC CHECKDB/SHRINK, ALTER INDEX REORGANIZE, rollback após KILL).","when":"Quando o backup noturno avança pelo horário comercial, para responder \"quando vai terminar\" durante um restore grande ou para acompanhar o rollback de uma sessão morta.","caution":"A estimativa assume progresso linear; durante as fases de redo/undo de um restore e durante a inicialização com zeros do log, o percentual pode ficar parado por muito tempo. Arquivos de log não se beneficiam de instant file initialization (exceto crescimentos de até 64 MB no 2022); restores com logs grandes passam muito tempo na primeira fase. Consulta somente leitura; segura.","note":"Se o wait_type for majoritariamente BACKUPIO / ASYNC_IO_COMPLETION, o gargalo é o disco de destino/origem; BACKUPTHREAD ou CPU alto aponta para o custo da compressão. Para ver em detalhe no error log a longa fase de zeragem de um restore, use os trace flags 3004 + 3605.","tags":["percent_complete","backup progress","restore progress","eta","dm_exec_requests","progress"]},{"id":"tail-log-backup","task":"Fazer um backup tail-log antes de um restore (NORECOVERY / NO_TRUNCATE)","category":"Restore e recuperação","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":"Faz backup da parte do log gravada desde o último backup de log (o tail), para que a cadeia de restore chegue ao momento da falha e os últimos minutos de transações não se percam.","when":"Antes de restaurar sobre o mesmo banco, quando o disco dos arquivos de dados falha ou no corte final de uma migração.","caution":"NORECOVERY coloca o banco em RESTORING e encerra o acesso dos usuários; não execute no banco errado. Restaurar WITH REPLACE sem backup tail-log descarta permanentemente as transações após o último backup de log. Um backup feito com NO_TRUNCATE pode conter metadados incompletos; execute DBCC CHECKDB após o restore. Backup tail-log não é possível no recovery SIMPLE.","note":"Para tirar o banco de RESTORING sem um restore: RESTORE DATABASE [Musteri] WITH RECOVERY;. NO_TRUNCATE equivale a COPY_ONLY + CONTINUE_AFTER_ERROR e tenta ler o log mesmo que o banco não possa ser aberto.","tags":["tail-log","backup log","norecovery","no_truncate","restore","recovery"]},{"id":"restore-pitr-stopat","task":"Restaurar para um ponto no tempo (point-in-time restore, STOPAT)","category":"Restore e recuperação","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":"Aplica FULL + (opcional) DIFF + backups de log WITH NORECOVERY e interrompe a reaplicação do log no horário informado; devolve o banco ao estado logo antes da operação ruim (DELETE/UPDATE errado, DROP).","when":"Para recuperar dados excluídos/alterados por engano, inspecionar os dados em um momento específico ou para uma auditoria.","caution":"Restaure com outro nome em vez de sobre o original e depois copie de volta as linhas necessárias; se precisar restaurar sobre ele, faça antes um backup tail-log. STOPAT está no horário local do servidor. O recovery model precisa ser FULL; se o backup de log que contém o horário do STOPAT incluir operações minimamente logadas sob BULK_LOGGED, não é possível parar dentro desse backup. Após RESTORE ... WITH RECOVERY nenhum log adicional pode ser aplicado.","note":"Especificar STOPAT em todo restore de log é o padrão recomendado; a mensagem informativa \"contains records that were logged before the designated point in time\" nos arquivos anteriores é normal. Para parar em uma marca nomeada (BEGIN TRAN ... WITH MARK) use STOPATMARK / STOPBEFOREMARK. Use fn_dump_dblog ou os logs da aplicação para descobrir o horário exato.","tags":["stopat","point-in-time","restore log","norecovery","standby","rollback to time"]},{"id":"restore-verify-header","task":"Inspecionar e verificar um arquivo de backup (VERIFYONLY, HEADERONLY, FILELISTONLY)","category":"Restore e recuperação","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":"Verifica se o backup é legível e se seus checksums de página são válidos sem restaurá-lo; mostra os backup sets contidos (Position, BackupType, FirstLSN/LastLSN, DatabaseVersion), os nomes lógicos dos arquivos e as informações de stripe.","when":"Antes de restaurar um backup recebido de outra equipe, para descobrir os nomes de arquivo para o MOVE, como verificação rápida após um job de backup ou para escolher o FILE = n certo quando um arquivo contém vários sets.","caution":"VERIFYONLY não garante que o banco seja restaurável e consistente; ele só verifica a estrutura do backup e (se feito WITH CHECKSUM) os checksums de página. Para garantia real, faça restores de teste regulares + DBCC CHECKDB. Um backup de uma versão mais nova não pode ser restaurado em uma mais antiga (verifique DatabaseVersion). Operações de leitura; seguras.","note":"Se o HEADERONLY mostrar HasBackupChecksums = 0, o backup foi feito sem CHECKSUM e o VERIFYONLY WITH CHECKSUM não consegue validar as páginas. Arquivos gravados sem INIT acumulam vários sets; passe WITH FILE = <Position> no restore.","tags":["restore verifyonly","headeronly","filelistonly","labelonly","backup verification","checksum"]},{"id":"page-restore-suspect","task":"Encontrar páginas corrompidas (suspect_pages) e restaurar páginas individuais","category":"Restore e recuperação","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":"Lista as páginas que sofreram erros de I/O (823/824), checksum ou torn page a partir de msdb.dbo.suspect_pages; repara páginas corrompidas individualmente, pegando-as do backup FULL e avançando-as com os logs, sem restaurar o banco inteiro.","when":"Em erros 823/824 no error log, erros de consistência limitados a poucas páginas no CHECKDB ou quando uma consulta de usuário falha com \"incorrect checksum\".","caution":"Exige recovery FULL ou BULK_LOGGED e uma cadeia de logs íntegra. Page restore online é exclusivo do Enterprise/Developer; nas outras edições o banco fica offline durante o restore. Páginas de alocação (GAM/SGAM/PFS), cabeçalhos de arquivo e a boot page (1:9) não podem ser restauradas assim. 823/824 geralmente indica um problema de storage; não encerre o caso sem verificar disco/controladora/SAN, senão vai se repetir. Com muitas páginas ruins, um restore completo do banco é mais rápido.","note":"suspect_pages comporta no máximo 1.000 linhas; quando cheia, novos erros não são registrados, então apague as linhas antigas (event_type 4/5/7). Várias páginas são separadas por vírgula: PAGE = '1:336, 1:337'. Em um AG, uma página corrompida no primário é corrigida automaticamente a partir de uma secundária pelo automatic page repair (sys.dm_hadr_auto_page_repair).","tags":["suspect_pages","page restore","823","824","corruption","bad page"]},{"id":"top-queries-cpu","task":"Encontrar as consultas mais caras no plan cache (CPU, leituras, duração)","category":"Desempenho","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":"Agrupa os statements do plan cache por query_hash (consultas ad-hoc que diferem apenas nos literais se reduzem a uma linha) e retorna CPU, duração, leituras lógicas, memory grant e quantidade de planos, totais e médios.","when":"Quando a CPU está no talo, em uma reclamação de \"o servidor está lento\", para bancos sem Query Store ou quando você precisa de uma visão de todo o servidor, abrangendo todos os bancos.","caution":"Só enxerga planos que ainda estão em cache: faltam as consultas cujos planos foram removidos por restart, DBCC FREEPROCCACHE, pressão de memória ou RECOMPILE. Use o Query Store para análise persistente e por janela de tempo. plan_count > 1 sugere sensibilidade a parâmetros ou opções SET diferentes. Em um plan cache muito grande a consulta pode levar alguns segundos; segura.","since":"2016","note":"total_grant_kb é uma coluna do 2016+. Para totais por stored procedure, use sys.dm_exec_procedure_stats.","tags":["dm_exec_query_stats","top queries","cpu","query_hash","plan cache","expensive query"]},{"id":"wait-stats-top","task":"Wait statistics: em que o servidor está esperando","category":"Desempenho","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":"Filtra as esperas benignas de background e detalha o tempo total de espera do servidor por wait type, com percentual e participação de resource vs. signal (fila de CPU); também mostra as requisições de usuário esperando neste momento.","when":"Como primeiro passo de uma investigação de desempenho, para classificar o gargalo (I/O, CPU, lock, log, memória, paralelismo); para comparações de baseline antes/depois.","caution":"Os valores são cumulativos desde o restart; para um problema atual, tire dois snapshots e compare o delta. DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR) zera os contadores do servidor inteiro e quebra as ferramentas de monitoramento; evite. Interpretação: PAGEIOLATCH_* = leituras de disco, WRITELOG = disco de log, LCK_M_* = bloqueio, CXPACKET/CXCONSUMER = paralelismo, RESOURCE_SEMAPHORE = memory grants, SOS_SCHEDULER_YIELD + signal alto = pressão de CPU. Consulta somente leitura; segura.","note":"Para esperas por sessão, use sys.dm_exec_session_wait_stats (2016+); para categorias de espera por consulta no Query Store, use sys.query_store_wait_stats (2017+).","tags":["wait stats","dm_os_wait_stats","waits","pageiolatch","writelog","performance"]},{"id":"deadlock-system-health","task":"Ler deadlocks passados da sessão system_health (deadlock graph)","category":"Desempenho","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":"Lê os eventos xml_deadlock_report do target event_file da sessão de Extended Events system_health (ativa por padrão); para cada deadlock, retorna o horário (UTC), o processo vítima, o número de participantes, o banco de dados e o XML completo do deadlock graph.","when":"Quando a aplicação reporta o erro 1205, ao analisar a frequência de deadlocks e os objetos envolvidos; em servidores sem o trace flag 1222.","caution":"Os arquivos do system_health são rotacionados; em um servidor movimentado, deadlocks mais antigos podem ter sumido, então crie uma sessão XE dedicada para um arquivo permanente. Ler muitos arquivos consome CPU; mantenha o TOP em horário comercial. Os eventos são gravados com atraso, então um deadlock novo aparece após alguns segundos. Somente leitura; seguro.","note":"Clique no valor de deadlock_graph e salve como .xdl para abri-lo graficamente no SSMS. O padrão do event_file do system_health é 10 x 100 MB no 2016 SP2 CU12 / 2017 CU20 / 2019 CU3 e posteriores (Standard/Enterprise); 4 x 5 MB em builds mais antigos e outras edições. No grafo, inputbuf, waitresource (KEY/PAGE/OBJECT) e lockMode são os campos-chave; a maioria dos deadlocks se resolve com um índice faltante ou uma ordem de acesso consistente.","tags":["deadlock","system_health","xml_deadlock_report","extended events","1205","deadlock graph"]},{"id":"xe-long-query-session","task":"Criar uma sessão de Extended Events: capturar consultas lentas em arquivo e lê-las","category":"Desempenho","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":"Cria uma sessão leve de Extended Events que grava em disco statements e chamadas RPC com mais de 1 segundo, com aplicação, host, usuário, banco de dados e texto SQL; transforma os arquivos .xel em linhas com T-SQL.","when":"Para reclamações de lentidão intermitente, quando você precisa de detalhes do cliente (app/host) que o Query Store não mostra, e como substituto do SQL Trace/Profiler.","caution":"Um limite muito baixo (ex.: 0) enche os arquivos rapidamente e adiciona overhead em um servidor movimentado; filtre no predicado WHERE, não depois. A action sql_text é cara em alto volume. A pasta precisa ter permissão de escrita para a conta de serviço do SQL Server. duration e cpu_time estão em microssegundos. Pare/remova a sessão ao terminar; com STARTUP_STATE = OFF ela não inicia após um restart.","note":"Para restringir a um banco de dados, adicione sqlserver.database_name = N'Musteri' à cláusula WHERE. Para uma olhada rápida, use SSMS > Management > Extended Events > Watch Live Data.","tags":["extended events","xe","event session","slow query","sql_statement_completed","event_file"]},{"id":"tempdb-contention","task":"Diagnosticar contenção e uso de espaço no tempdb","category":"Desempenho","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":"Mostra esperas PAGELATCH nas páginas de alocação do tempdb (PFS/GAM/SGAM) e nas tabelas de sistema, as sessões que mais usam o tempdb (tabelas temporárias vs. spills de sort/hash), qual banco está inflando o version store e a configuração dos arquivos.","when":"Quando as esperas PAGELATCH_UP/EX sobem sob cargas pesadas de tabelas temporárias, quando o tempdb enche (1105/9002) ou quando o version store cresce.","caution":"As páginas 2:1:1, 2:1:2, 2:1:3 e as páginas PFS em múltiplos de 8088 indicam contenção de alocação: a correção é ter vários arquivos de dados de mesmo tamanho e com o mesmo crescimento (um por core até 8, depois adicione de 4 em 4). Para contenção em páginas de tabelas de sistema, o 2019+ oferece memory-optimized tempdb metadata (exige restart). Se o version store crescer, encontre a transação snapshot aberta mais antiga; fazer shrink do tempdb não é solução. Consulta somente leitura; segura.","note":"Memory-optimized metadata: ALTER SERVER CONFIGURATION SET MEMORY_OPTIMIZED TEMPDB_METADATA = ON; + restart (2019+). O 2022 adicionou atualizações de GAM/SGAM sem latch, o que reduz muito a contenção. A transação que segura o version store: 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":"Habilitar o Query Store, aplicar as configurações recomendadas e verificar seu estado","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":"Habilita o Query Store no banco de dados; passa a persistir textos de consulta, planos, estatísticas de execução e de espera em intervalos de tempo. As opções definem o limite de armazenamento, a limpeza e o modo de captura.","when":"Quando um novo banco de dados entra em produção, antes de um upgrade de versão/nível de compatibilidade (para ter um baseline) ou quando há suspeita de regressão de plano.","caution":"Quando MAX_STORAGE_SIZE_MB é atingido, o Query Store muda silenciosamente para READ_ONLY (readonly_reason = 65536) e para de coletar; monitore current_storage_size_mb. QUERY_CAPTURE_MODE = ALL enche o armazenamento rapidamente e adiciona overhead sob cargas ad-hoc pesadas. Sistemas OLTP muito movimentados podem mostrar esperas QDS_*. Colocar em OFF mantém os dados coletados; CLEAR os apaga.","since":"2016","note":"No 2022, bancos de dados recém-criados têm o Query Store ativo em READ_WRITE por padrão. No 2019+, QUERY_CAPTURE_MODE = CUSTOM aceita limites (EXECUTION_COUNT, TOTAL_COMPILE_CPU_TIME_MS, TOTAL_EXECUTION_CPU_TIME_MS). O Query Store para secundárias legíveis (ALTER DATABASE ... FOR SECONDARY SET QUERY_STORE = ON) é um preview limitado no 2022, habilitado só com o trace flag 12606 e não suportado em produção; o 2025 não precisa de trace flag (ainda em preview).","tags":["query store","enable","max_storage_size_mb","query_capture_mode","read_only","qds"]},{"id":"qs-regressed-queries","task":"Encontrar regressões de plano com o Query Store (mesma consulta, planos diferentes)","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":"Encontra consultas que rodaram com mais de um plano nas últimas 24 horas; coloca lado a lado, para cada plano, o número de execuções, a média ponderada de duração/CPU/leituras e quantas vezes ele é mais lento que o melhor plano.","when":"Quando uma consulta \"era rápida ontem e está lenta hoje\", após uma atualização de estatísticas, mudança de índice, upgrade do nível de compatibilidade ou patch.","caution":"A duração média também depende da distribuição dos dados; ao comparar planos que rodaram com valores de parâmetro diferentes, olhe também avg_reads (parameter sniffing). As janelas de tempo estão em UTC. Os resultados são estatisticamente fracos para planos com poucas execuções. Consulta somente leitura; segura.","since":"2016","note":"SSMS > Query Store > Regressed Queries faz o mesmo graficamente. No 2022 com nível de compatibilidade 160, a otimização Parameter Sensitive Plan (PSP) cria vários query_ids variantes para um mesmo statement; mapeie-os para o pai com sys.query_store_query_variant (parent_query_id). O automatic tuning do 2017+ (FORCE_LAST_GOOD_PLAN) pode corrigir essas regressões automaticamente.","tags":["query store","plan regression","regressed queries","parameter sniffing","query_store_runtime_stats","plan"]},{"id":"qs-force-plan-hints","task":"Forçar um plano bom ou anexar um hint com o 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":"Força um plano específico do Query Store para a consulta escolhida; o otimizador usa esse plano em toda compilação. No 2022, como alternativa, você pode anexar hints como RECOMPILE, MAXDOP ou OPTIMIZE FOR sem alterar o código da aplicação.","when":"Quando uma regressão de plano precisa de correção urgente em produção, até que uma correção definitiva (índice, reescrita da consulta, estatísticas) esteja pronta.","caution":"Um plano forçado pode degradar à medida que os dados crescem e não é uma correção definitiva; revise-o regularmente. Se um índice usado pelo plano for removido/renomeado, o forcing falha (last_force_failure_reason_desc = NO_INDEX etc.) e a consulta compila normalmente. Após o forcing, um plano \"moralmente equivalente\" pode aparecer com um novo plan_id; isso é esperado. O forcing funciona enquanto o Query Store está em READ_ONLY, mas verifique após um restore ou failover do AG.","since":"2016","note":"Os hints do Query Store são do 2022+ (antes no Azure SQL). Os hints substituem os plan guides; se um hint não puder ser aplicado, a consulta roda sem ele e o motivo aparece em last_query_hint_failure_reason_desc. O plan forcing em secundárias legíveis (@replica_group_id) exige o Query Store para réplicas secundárias, que no 2022 é um preview limitado habilitado com o trace flag 12606.","tags":["force plan","sp_query_store_force_plan","query store hints","plan forcing","regression","recompile"]},{"id":"missing-index-dmv","task":"Ler sugestões de índices faltantes das DMVs (com ressalvas)","category":"Manutenção","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":"Pontua as sugestões de índices faltantes que o otimizador registrou no momento da compilação por uso, custo estimado e impacto, e gera um rascunho de statement CREATE INDEX; no 2019+ também mostra a consulta por trás de cada sugestão.","when":"Após um novo release da aplicação, para uma varredura rápida das necessidades de índice de consultas com muita leitura, ou como lista inicial para uma revisão de design de índices.","caution":"Não aplique sugestões às cegas: o otimizador ignora os índices existentes, frequentemente produz sugestões quase duplicadas (sobrepostas) e listas INCLUDE largas demais, e ordena as colunas por igualdade/desigualdade, e não por seletividade. Todo índice novo custa escrita e armazenamento; considere primeiro ampliar um índice existente. As DMVs são zeradas em restart, banco offline e mudanças de índice na tabela. Consulta somente leitura; segura.","note":"Antes de criar um índice sugerido, compare-o com os índices existentes da tabela (sp_helpindex ou sys.index_columns) e revise-o junto com a receita de índices não utilizados. O elemento MissingIndex no XML do plano dá a mesma informação por consulta.","tags":["missing index","missing index dmv","dm_db_missing_index_details","index suggestion","create index","tuning"]},{"id":"unused-indexes","task":"Encontrar índices não utilizados / só de escrita","category":"Manutenção","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":"Lista os índices nonclustered que não foram lidos (seek/scan/lookup = 0) desde o restart, mas ainda geram custo de escrita, com seu tamanho, e gera um rascunho de statement DROP INDEX.","when":"Para INSERT/UPDATE lentos em tabelas com muita escrita, para reduzir tempo de armazenamento e manutenção (rebuild, CHECKDB) ou antes de uma consolidação de índices.","caution":"Os contadores são zerados em restart, banco offline/detach e (em alguns builds mais antigos de 2012/2014) rebuild de índice; índices usados apenas por relatórios de fim de mês/fim de ano parecem \"não utilizados\" em uma janela curta. Observe por pelo menos um ciclo de negócio completo antes de remover e, em um AG, verifique o uso nas secundárias legíveis separadamente (os contadores são por réplica). Índices únicos garantem constraints mesmo quando não são lidos; eles são excluídos. Consulta somente leitura; segura.","note":"Desabilitar com ALTER INDEX ... DISABLE antes de remover facilita o rollback (a definição permanece; REBUILD o traz de volta). Procurar o nome do índice no Query Store ou no plan cache mostra se ele é referenciado por um hint.","tags":["unused index","write-only index","dm_db_index_usage_stats","drop index","write overhead","index"]},{"id":"stats-health","task":"Saúde das estatísticas: quando foram atualizadas, quantas linhas mudaram","category":"Manutenção","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":"Mostra, para cada estatística, a hora da última atualização, a taxa de amostragem, as linhas modificadas desde a última atualização e o limite em que o auto update dispara (limite dinâmico para compat 130+).","when":"Para planos com grande diferença entre linhas estimadas e reais, após uma carga grande de dados ou ao verificar se o job de manutenção de estatísticas é eficaz.","caution":"A fórmula do limite se aplica ao nível de compatibilidade 130+ (MIN(500 + 20%, SQRT(1000 x rows))); níveis de compatibilidade inferiores usam a regra de 20% + 500. Estatísticas nunca atualizadas (tabelas vazias) retornam NULL. Colunas com distribuição enviesada e sample_pct baixo podem precisar de FULLSCAN ou PERSIST_SAMPLE_PERCENT. Consulta somente leitura; segura.","since":"2016","note":"persisted_sample_percent reflete UPDATE STATISTICS ... WITH PERSIST_SAMPLE_PERCENT = ON (2016 SP1 CU4 / 2017 CU1+). Veja a receita update-statistics para os comandos de atualização.","tags":["statistics","stats health","dm_db_stats_properties","modification_counter","auto update","cardinality"]},{"id":"checkdb-strategy","task":"Estratégia de DBCC CHECKDB: última verificação bem-sucedida, divisão do trabalho, interpretação dos resultados","category":"Manutenção","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":"Mostra a hora do último CHECKDB bem-sucedido de cada banco de dados, estima o tempdb necessário, permite dividir a verificação de bancos grandes em partes CHECKALLOC + CHECKCATALOG + CHECKTABLE e retorna os resultados como linhas (objeto, índice, página).","when":"Ao auditar a manutenção, para bancos de dados muito grandes que não cabem na janela de manutenção ou ao determinar a extensão da corrupção após 823/824.","caution":"A frase \"repair_allow_data_loss is the minimum repair level\" no resultado significa que o reparo vai apagar dados; considere primeiro um restore a partir de um backup bom (ou page restore). Se apenas índices nonclustered (index_id > 1) forem afetados, remover e recriar o índice resolve sem perda de dados. Após encontrar corrupção, investigue o subsistema de disco. PHYSICAL_ONLY pula as verificações lógicas; um CHECKDB completo continua sendo necessário periodicamente. Ao dividir com CHECKTABLE, a cobertura fica incompleta a menos que CHECKALLOC/CHECKCATALOG também rodem.","note":"DATABASEPROPERTYEX(..., 'LastGoodCheckDbTime') está disponível no 2016 SP2, 2017 CU9 e 2019+; em builds mais antigos, leia dbi_dbccLastKnownGood de DBCC DBINFO WITH TABLERESULTS. Para descarregar a carga, rodar o CHECKDB em uma cópia restaurada a partir do backup (ex.: em um servidor de teste) também valida o banco de produção. A opção MAXDOP é do 2014 SP2 / 2016+.","tags":["dbcc checkdb","lastgoodcheckdbtime","checktable","corruption","repair_allow_data_loss","integrity"]},{"id":"resource-governor","task":"Limitar a carga de relatórios com o Resource Governor (pool, workload group, classifier)","category":"Configuração","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":"Direciona as sessões de logins ou aplicações específicas para um workload group separado no momento da conexão; protege a carga OLTP limitando a CPU, os memory grants, o DOP e o tempo de CPU por requisição desse grupo.","when":"Quando consultas de relatório/BI sufocam o OLTP, quando o ETL se sobrepõe à carga do horário comercial ou para compartilhamento de recursos em um servidor multi-tenant.","caution":"A classifier function roda em toda nova conexão; uma função lenta ou com falha deixa lento ou quebra todo login (nada de consultas ou acesso a tabelas nela). Se ela se comportar mal, conecte-se via DAC e defina CLASSIFIER_FUNCTION = NULL. A classificação acontece apenas no momento da conexão; sessões existentes não são afetadas. CAP_CPU_PERCENT é um teto rígido aplicado mesmo com a CPU ociosa. MAX_CPU_PERCENT só se aplica sob contenção de CPU. O Resource Governor é um recurso Enterprise/Developer.","note":"Exceder REQUEST_MAX_CPU_TIME_SEC só gera um evento por padrão (cpu_threshold_exceeded); com o trace flag 2422 (2016 SP2 / 2017 CU3+) a requisição é abortada. Para limites de I/O, use MAX_IOPS_PER_VOLUME no pool (2014+). Estatísticas: sys.dm_resource_governor_resource_pools / _workload_groups.","tags":["resource governor","resource pool","workload group","classifier","cpu limit","resource management"]},{"id":"tde-enable","task":"Configurar TDE: master key, certificado, backup do certificado e progresso da criptografia","category":"Segurança","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":"Cria uma database master key e um certificado no master, faz backup do certificado com sua chave privada, cria uma database encryption key AES-256 e criptografa em repouso os arquivos de dados e de log; mostra o progresso do scan de criptografia em background.","when":"Para requisitos de criptografia de dados em repouso, como GDPR/PCI, e contra roubo de arquivos de backup e arquivos MDF/LDF.","caution":"Se o backup do certificado + chave privada ou sua senha for perdido, o banco TDE e todos os seus backups ficam ilegíveis PERMANENTEMENTE; guarde o backup em um cofre seguro, longe do servidor. Habilitar TDE em qualquer banco também criptografa o tempdb (um pequeno custo de CPU no servidor inteiro). O scan de criptografia é pesado em I/O; no 2019+ ele pode ser pausado com ALTER DATABASE ... SET ENCRYPTION SUSPEND/RESUME. Para AG/log shipping, o certificado precisa ser instalado antes em cada servidor de destino. O TDE não criptografa dados em memória nem na rede.","note":"A expiração do certificado não interrompe o TDE existente, mas para rotação crie um novo certificado e recriptografe com ALTER DATABASE ENCRYPTION KEY ENCRYPTION BY SERVER CERTIFICATE [new] (só a DEK é recriptografada, não os dados). encryption_state_desc e encryption_scan_state_desc são colunas do 2019+; em versões mais antigas, use encryption_state (3 = criptografado, 2 = em andamento). O TDE está disponível na edição Standard a partir do 2019.","tags":["tde","transparent data encryption","certificate","backup certificate","encryption","dek"]},{"id":"sql-server-audit","task":"Configurar o SQL Server Audit: logins, mudanças de permissão e acesso a tabelas","category":"Segurança","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":"Cria um server audit que grava em arquivo; registra logins com falha, membros de roles, mudanças de principals e permissões em todo o servidor e acessos SELECT/DML a uma tabela escolhida no nível do banco, e lê os registros com T-SQL.","when":"Para requisitos de auditoria/compliance (GDPR, PCI, SOX), para perguntas do tipo \"quem leu/alterou esta tabela\" ou quando há suspeita de escalonamento de privilégios.","caution":"A auditoria de SELECT em uma tabela movimentada gera registros muito rapidamente e custa desempenho; restrinja por objeto e principal. ON_FAILURE = SHUTDOWN derruba o servidor quando o audit não pode ser gravado; use apenas quando exigido. A pasta do audit precisa ter permissão de escrita para a conta de serviço do SQL Server e não pode ser apagável por quem não é DBA. event_time está em UTC. Uma database audit specification é restaurada com o banco, mas fica órfã se o GUID do server audit não coincidir.","note":"As database audit specifications estão disponíveis na edição Standard a partir do 2016 SP1. Sempre inclua AUDIT_CHANGE_GROUP para que mudanças no próprio audit, inclusive desligá-lo, sejam registradas.","tags":["sql server audit","server audit","audit specification","fn_get_audit_file","auditing","compliance"]},{"id":"orphaned-users-fix","task":"Encontrar usuários órfãos e remapeá-los para logins (após restore / AG)","category":"Segurança","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":"Encontra usuários do banco cujo SID não corresponde a nenhum login do servidor (órfãos); remapeia um usuário para um login existente e gera um script para recriar os logins em outro servidor com o mesmo SID e hash de senha.","when":"Após restaurar/anexar um banco de dados em outro servidor, quando a aplicação recebe \"Login failed for user\" após um failover de AG/log shipping, ou durante uma migração de servidor.","caution":"ALTER USER ... WITH LOGIN muda o SID do usuário para o do login; em um AG, essa mudança flui da primária para as secundárias, mas se os logins nos servidores secundários tiverem SIDs diferentes, o problema volta no próximo failover. A correção definitiva é criar os logins com o mesmo SID em todas as réplicas. O hash de senha é sensível; guarde o script com segurança. Usuários de contained database (authentication_type = DATABASE) não precisam de login e não são listados.","note":"sp_change_users_login está obsoleto; use ALTER USER WITH LOGIN. Para um dbo órfão (login do dono do banco ausente), use ALTER AUTHORIZATION ON DATABASE::[Musteri] TO [sa];. Para migração de logins em massa, use o 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":"Auditoria de logins e permissões: membros de sysadmin, permissões arriscadas, senhas fracas","category":"Segurança","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":"Lista os membros de server roles, permissões arriscadas como CONTROL SERVER/IMPERSONATE, logins SQL com a política de senha desligada, bloqueados, ou com senha igual ao nome do login ou vazia; no banco, os membros de roles e as permissões explícitas em objetos que não são de sistema.","when":"Para revisões periódicas de acesso, antes de uma auditoria, após alguém sair da equipe ou quando há suspeita de incidente de segurança.","caution":"Permissões concedidas por grupos do Windows aparecem sob o nome do grupo; para ver as pessoas, use EXEC xp_logininfo N'DOMAIN\\Group', 'members';. Verifique as dependências da aplicação antes de revogar qualquer coisa. PWDCOMPARE funciona apenas para logins SQL e exige CONTROL SERVER. Consulta somente leitura; segura.","note":"Para as permissões efetivas de um principal: EXECUTE AS USER = N'app_user'; SELECT * FROM fn_my_permissions(NULL, 'DATABASE'); REVERT;. No 2022, as novas roles granulares (##MS_ServerStateReader##, ##MS_DefinitionReader## etc.) concedem direitos de monitoramento sem sysadmin.","tags":["permission audit","sysadmin","server_role_members","database_permissions","pwdcompare","security"]},{"id":"ledger-tables","task":"Criar uma ledger table, ler seu histórico de alterações e verificar a integridade","category":"Segurança","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":"Cria uma ledger table que registra as alterações de linhas em uma cadeia de hashes criptográficos; a view _Ledger mostra quem fez cada INSERT/UPDATE/DELETE e quando, e a verificação contra um digest armazenado prova que os dados não foram alterados depois (inclusive por DBAs).","when":"Para dados cuja imutabilidade precisa ser comprovável: registros financeiros, trilhas de auditoria, registros de contratos/aprovações.","caution":"O ledger não pode ser desligado depois que a tabela é criada; uma ledger table não pode ser convertida em tabela comum, e uma ledger table removida é mantida como dropped ledger table. O updatable ledger grava uma linha de histórico a cada alteração e o armazenamento cresce. A menos que os digests sejam armazenados fora do banco em armazenamento imutável (WORM, Azure immutable blob), a verificação não tem valor probatório. sp_verify_database_ledger falha com o erro 37498 sem snapshot isolation.","since":"2022","note":"sp_generate_database_ledger_digest retorna JSON; sp_verify_database_ledger aceita um único digest ou um array JSON e pode verificar uma única tabela com @table_name. Para armazenamento automático de digests: ALTER DATABASE SCOPED CONFIGURATION SET LEDGER_DIGEST_STORAGE_ENDPOINT = '<blob url>'. CREATE DATABASE ... WITH LEDGER = ON torna toda tabela uma ledger table por padrão.","tags":["ledger","append-only","sp_verify_database_ledger","digest","immutable","tamper-evident"]},{"id":"agent-job-failures","task":"Histórico de falhas de jobs do SQL Agent e status da última execução","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":"Mostra os steps de jobs que falharam ou foram cancelados nas últimas 24 horas com sua mensagem de erro; o último resultado de cada job, se está rodando agora e sua próxima execução agendada; e o estado do serviço Agent.","when":"Na verificação matinal, em um alerta de job de backup/manutenção, para \"o job noturno rodou?\" ou após um failover para verificar se os jobs rodam na réplica certa.","caution":"O histórico de jobs no msdb é limitado (padrão de 1.000 linhas no total, 100 por job); jobs que rodam com frequência empurram rapidamente as falhas antigas para fora, então aumente o limite nas propriedades do Agent. A coluna message é truncada em 4.000 caracteres; defina um output file no step do job para saídas longas. Se o serviço Agent estiver parado, nenhum job agendado roda e nenhum reporta erro. Consulta somente leitura; segura.","note":"msdb.dbo.agent_datetime não é documentada, mas é amplamente usada. Em um AG, os jobs precisam existir em todas as réplicas e verificar o papel no primeiro step com 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":"Adicionar um membro ao replica set","category":"Replica Set","command":"rs.add({ host: \"mongo2:27017\", priority: 1, votes: 1 })","what":"Adiciona um novo membro (secundário) ao replica set existente e inicia um initial sync.","when":"Ao adicionar um novo nó para aumentar a capacidade de leitura ou para redundância.","caution":"O novo membro puxa os dados do primário durante o initial sync; com grandes volumes de dados, isso gera carga de rede e disco.","tags":["replica","rs.add","member","member","add"]},{"id":"rs-remove-member","task":"Remover um membro do replica set","category":"Replica Set","command":"rs.remove(\"mongo2:27017\")","what":"Remove o host especificado da configuração do replica set.","when":"Ao tirar um nó de serviço ou substituir hardware.","caution":"Não remova o primário; remover membros de forma a quebrar a maioria pode deixar o set indisponível para leituras e escritas.","tags":["replica","rs.remove","member","member","remove"]},{"id":"rs-step-down","task":"Rebaixar o primário (stepDown)","category":"Replica Set","command":"rs.stepDown(60)","what":"Rebaixa o primário atual a secundário pelo número de segundos especificado e dispara uma nova eleição.","when":"Para passar o papel de primário a outro nó antes de uma manutenção planejada.","caution":"Ocorre uma breve indisponibilidade de escrita durante o stepDown; a aplicação precisa se reconectar.","tags":["replica","stepdown","primary","failover","step down"]},{"id":"rs-set-priority","task":"Alterar a prioridade de um membro","category":"Replica Set","command":"cfg = rs.conf(); cfg.members[1].priority = 2; rs.reconfig(cfg)","what":"Altera a prioridade do membro especificado para se tornar primário nas eleições.","when":"Quando você quer que um nó específico seja o primário preferido.","caution":"O reconfig pode disparar uma eleição e causar uma breve troca de primário/indisponibilidade de escrita.","tags":["replica","priority","reconfig","priority","election"]},{"id":"rs-status","task":"Ver o status do replica set","category":"Replica Set","command":"rs.status()","what":"Mostra o estado, os papéis, o lag de replicação e a saúde dos membros do set.","when":"Ao verificar a saúde e o lag da replicação.","caution":"Comando somente leitura; sem risco.","tags":["replica","status","status","health","rs.status"]},{"id":"rs-hidden-member","task":"Configurar um membro oculto / sem voto","category":"Replica Set","command":"cfg = rs.conf(); cfg.members[2].hidden = true; cfg.members[2].priority = 0; cfg.members[2].votes = 0; rs.reconfig(cfg)","what":"Torna um membro oculto (invisível para a aplicação), sem voto e com prioridade 0, usando-o apenas para backup/análises.","when":"Quando você quer isolar backups ou consultas analíticas.","caution":"Um membro oculto precisa ter prioridade 0; caso contrário, o reconfig falha.","tags":["replica","hidden","votes","hidden","non-voting"]},{"id":"rs-resync","task":"Ressincronizar um membro do zero","category":"Replica Set","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":"O MongoDB não tem um comando de resync separado; parar o secundário, esvaziar seu diretório de dados e reiniciá-lo inicia um novo initial sync a partir do primário (ou de uma sync source).","when":"Quando um membro fica tão atrasado que sai da janela do oplog (RECOVERING / too stale) ou seus dados ficam inconsistentes.","caution":"Todos os dados locais do membro são apagados e puxados novamente; faça isso apenas em um secundário e garanta que a maioria continue no ar. O tempo de sincronização e a carga de rede/disco são altos; para volumes de dados muito grandes, fazer o seeding a partir de um snapshot de file system de um membro saudável é mais rápido.","tags":["replica","resync","initialsync","sync","resync"]},{"id":"sh-add-shard","task":"Adicionar um shard ao cluster","category":"Sharding","command":"sh.addShard(\"shardRS/mongoShard1:27018\")","what":"Adiciona um novo shard (replica set) ao cluster shardado.","when":"Ao escalar horizontalmente a capacidade de armazenamento ou de throughput.","caution":"Após adicionar um shard, o balancer começa a migrar chunks; isso gera carga de IO adicional.","tags":["sharding","addshard","shard","add","cluster"]},{"id":"sh-shard-collection","task":"Shardar uma collection","category":"Sharding","command":"sh.shardCollection(\"shop.customer\", { customerId: \"hashed\" })","what":"Sharda a collection especificada pela shard key informada.","when":"Quando você quer distribuir uma collection em crescimento por vários shards.","caution":"A shard key pode ser alterada com reshardCollection no 5.0+ (e estendida com refineCollectionShardKey no 4.4+), mas isso é caro porque redistribui todos os dados; uma escolha ruim de chave leva a uma distribuição desigual.","tags":["sharding","shardcollection","key","customer","shard key"]},{"id":"sh-start-balancer","task":"Iniciar o balancer","category":"Sharding","command":"sh.startBalancer()","what":"Habilita o processo do balancer que distribui os chunks.","when":"Quando você quer reabilitar o balanceamento após uma manutenção.","caution":"O balancer gera carga de IO e de rede ao migrar chunks; defina uma janela de balanceamento fora dos horários de pico.","tags":["sharding","balancer","start","start","rebalance"]},{"id":"sh-stop-balancer","task":"Parar o balancer","category":"Sharding","command":"sh.stopBalancer()","what":"Desabilita o balancer que executa as migrações de chunks.","when":"Para interromper as migrações antes de um backup, de uma manutenção ou de uma carga de dados em massa.","caution":"Se ficar desligado por muito tempo, os shards ficam desbalanceados; não se esqueça de reabilitá-lo depois.","tags":["sharding","balancer","stop","stop","maintenance"]},{"id":"sh-status","task":"Ver o status do sharding","category":"Sharding","command":"sh.status()","what":"Resume os shards, bancos de dados, collections shardadas e a distribuição de chunks.","when":"Ao examinar o estado de distribuição do cluster e a saúde do balancer.","caution":"Comando somente leitura; sem risco.","tags":["sharding","status","status","chunk","sh.status"]},{"id":"sh-add-zone","task":"Adicionar uma zona (tag) e atribuir um intervalo","category":"Sharding","command":"sh.addShardToZone(\"shard0000\", \"TR\"); sh.updateZoneKeyRange(\"shop.customer\", { region: \"TR\" }, { region: \"TR~\" }, \"TR\")","what":"Atribui um shard a uma zona e vincula um intervalo de chaves específico a essa zona (zone sharding).","when":"Quando você quer manter dados em shards específicos por geografia ou hardware.","caution":"Os intervalos de zona precisam corresponder à shard key; um intervalo errado impede que os chunks sejam migrados.","tags":["sharding","zone","tag","region","range"]},{"id":"sh-move-chunk","task":"Mover um chunk manualmente","category":"Sharding","command":"sh.moveChunk(\"shop.customer\", { customerId: 1000 }, \"shard0001\")","what":"Move manualmente o chunk que contém a chave especificada para o shard de destino.","when":"Para corrigir uma distribuição desigual ou posicionar dados específicos.","caution":"Uma movimentação manual pode conflitar com o balancer; migrações de chunks grandes geram carga de IO e bloqueios breves.","tags":["sharding","movechunk","chunk","move","manual"]},{"id":"compact-collection","task":"Compactar uma collection","category":"Manutenção","command":"db.runCommand({ compact: \"customer\" })","what":"Reescreve a collection e seus índices em disco, recuperando o espaço livre.","when":"Quando você quer recuperar espaço em disco após muitos deletes/updates.","caution":"No 4.4+, o compact não bloqueia leituras/escritas; ele só bloqueia certas operações DDL na mesma collection (drop, createIndex, dropIndex etc.); ainda assim gera IO pesado e nem sempre devolve espaço ao sistema operacional. Rode-o em um secundário e em uma janela de manutenção quando possível.","tags":["compact","storage","maintenance","disk","storage"]},{"id":"create-index-background","task":"Criar um índice (sem bloqueio)","category":"Manutenção","command":"db.customer.createIndex({ email: 1 }, { name: \"idx_email\" })","what":"Cria um índice no campo especificado; desde o MongoDB 4.2, as construções de índice não bloqueiam escritas por padrão.","when":"Ao adicionar um novo índice para melhorar o desempenho de consultas.","caution":"Em collections grandes, a construção de índices consome CPU e IO; a carga no primário pode aumentar.","since":"MongoDB 4.2","note":"O MongoDB 4.2 introduziu um novo processo de construção de índices, e a criação de índices não bloqueia mais escritas por padrão; por isso a antiga opção { background: true } é desnecessária e é ignorada a partir do 4.2.","tags":["index","createindex","background","create","performance"]},{"id":"collection-stats","task":"Ver os tamanhos de índices e collections","category":"Manutenção","command":"db.customer.stats({ indexDetails: true })","what":"Informa o tamanho da collection, o tamanho de armazenamento e o tamanho de cada índice.","when":"Ao analisar o uso de armazenamento e o custo dos índices.","caution":"Comando somente leitura; sem risco.","tags":["stats","index","size","collection","storage"]},{"id":"log-rotate","task":"Rotacionar o arquivo de log","category":"Manutenção","command":"db.adminCommand({ logRotate: 1 })","what":"Fecha o arquivo de log atual e abre um novo (rotação de log).","when":"Quando o arquivo de log cresceu ou antes de arquivar.","caution":"Se usado junto com a rotação de logs do SO, verifique a configuração para evitar conflitos.","tags":["log","logrotate","rotate","maintenance","archive"]},{"id":"current-op-long","task":"Encontrar operações de longa duração","category":"Manutenção","command":"db.currentOp({ \"active\": true, \"secs_running\": { $gt: 5 } })","what":"Lista as operações ativas que estão rodando há mais de 5 segundos.","when":"Ao identificar consultas problemáticas durante lentidão ou travamentos.","caution":"Comando somente leitura; sem risco.","tags":["currentop","long","long-running","operation","diagnostics"]},{"id":"kill-op","task":"Encerrar uma operação","category":"Manutenção","command":"db.killOp(12345)","what":"Encerra a operação em execução com o opid especificado.","when":"Quando uma consulta trava o sistema ou roda por tempo demais.","caution":"Encerrar uma operação de escrita pode deixar alterações parciais; evite encerrar operações de sistema/replicação.","tags":["killop","kill","operation","kill","diagnostics"]},{"id":"set-parameter","task":"Alterar um parâmetro de runtime","category":"Parâmetros","command":"db.adminCommand({ setParameter: 1, cursorTimeoutMillis: 600000 })","what":"Altera um parâmetro de runtime sem reiniciar o servidor.","when":"Quando você quer ajustar um comportamento do servidor temporariamente.","caution":"A alteração não é persistente; no restart, volta ao valor do arquivo de configuração. Um valor errado pode degradar o desempenho.","tags":["setparameter","parameter","runtime","setting","admin"]},{"id":"set-profiling","task":"Definir o nível de profiling","category":"Parâmetros","command":"db.setProfilingLevel(1, { slowms: 100 })","what":"Registra as consultas lentas (acima de 100 ms) na collection system.profile (nível 1).","when":"Quando você quer diagnosticar consultas lentas.","caution":"O nível 2 registra todas as operações e adiciona overhead significativo; os dados de profiling ocupam espaço em disco.","tags":["profiling","slowms","profiler","slow","diagnostics"]}]},"recipes/mongodb-ext.json":{"engineId":"mongodb","engine":"MongoDB","order":2,"recipes":[{"id":"rs-oplog-window","task":"Medir a janela do oplog e o lag de replicação","category":"Replica Set","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":"Mostra quantas horas de escritas o oplog comporta (janela do oplog) e quantos segundos cada secundário está atrás do primário, junto com sua sync source.","when":"Em um alerta de lag de replicação, antes de uma manutenção planejada para calcular quanto tempo um membro pode ficar fora do ar e após jobs de escrita em massa.","caution":"Se um membro ficar fora do ar por mais tempo que a janela do oplog, ele fica 'too stale' e precisa de um initial sync. Jobs de update/delete em massa podem encolher a janela em poucas horas; avalie a janela pelo seu valor no pico de carga. O cálculo do lag se baseia na diferença de optimeDate; se o primário não recebe escritas, o lag não parece alto, mas a janela também não encolhe.","since":"MongoDB 4.4","note":"rs.printSlaveReplicationInfo() foi renomeado para rs.printSecondaryReplicationInfo() no 4.4. Se a janela for pequena demais, aumente o oplog com replSetResizeOplog (veja rs-oplog-resize). Membros com atraso aparecem atrasados em secondaryDelaySecs (slaveDelay no 4.4); exclua-os dos alertas de lag.","tags":["oplog","oplog window","replication lag","delay","secondary","printReplicationInfo"],"untested":true},{"id":"rs-oplog-resize","task":"Redimensionar o oplog online (replSetResizeOplog)","category":"Replica Set","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":"Aumenta ou reduz o oplog de um membro em execução sem restart; minRetentionHours mantém as entradas do oplog por um período mínimo mesmo que o limite de tamanho seja excedido.","when":"Quando a janela do oplog não cobre a duração da manutenção ou do initial sync, ou quando jobs de escrita em massa encolhem a janela.","caution":"O comando afeta apenas o membro em que roda e não é replicado; aplique-o em todos os membros. A janela também precisa ser suficiente nos membros que atuam como sync sources. Reduzir não devolve o espaço em disco ao SO imediatamente; para isso é preciso um compact em oplog.rs. Com minRetentionHours, o oplog pode crescer além de size dependendo do volume de escritas; planeje o disco de acordo.","since":"MongoDB 4.4","note":"O novo tamanho persiste entre restarts; o minRetentionHours definido pelo comando não, então defina também storage.oplogMinRetentionHours para mantê-lo. size precisa ser de pelo menos 990 MB. Alterar replication.oplogSizeMB na configuração só tem efeito quando o oplog é criado pela primeira vez.","tags":["oplog","resize","replSetResizeOplog","minRetentionHours","size","oplog window"],"untested":true},{"id":"rs-force-reconfig","task":"Forçar a reconfiguração de um replica set após perder a maioria (force reconfig)","category":"Replica Set","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":"Quando a maioria dos membros com voto é perdida permanentemente (ex.: um data center inteiro caiu), monta uma nova configuração a partir dos membros sobreviventes para que o set possa eleger um primário novamente.","when":"Apenas em um cenário de desastre: a maioria não vai voltar e o set está preso em somente leitura.","caution":"Este é o último recurso. Se os membros perdidos voltarem depois com a configuração antiga, pode ocorrer split-brain e rollback; isole-os da rede e, ao trazê-los de volta, apague seus dados e adicione-os com um initial sync. Escolha o membro com o optime mais recente; caso contrário, as escritas não confirmadas pela maioria nos outros membros caem em rollback. Não use force para mudanças rotineiras de membros.","since":"MongoDB 4.4","note":"O force reconfig aumenta a versão da configuração com um incremento aleatório grande e é a única forma de reconfig que pode rodar em um secundário. No 4.4+, reconfigs normais podem adicionar ou remover no máximo um membro com voto por vez; o force não está sujeito a esse limite.","tags":["force reconfig","majority","disaster","recovery","split-brain","rs.reconfig"],"untested":true},{"id":"rs-rolling-maintenance","task":"Manutenção rolling em um replica set (restart, patch do SO, upgrade menor)","category":"Replica Set","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":"Dá a ordem para colocar os membros em manutenção um de cada vez, secundários primeiro e o primário por último, para que restarts, patches do SO ou atualizações de binários sejam feitos sem tirar o set de serviço.","when":"Durante atualizações planejadas de SO/kernel, upgrades de versão menor, mudanças de parâmetros do mongod ou manutenção de disco/hardware.","caution":"Nunca desligue mais de um membro por vez; em um set de 3 membros, perder dois membros significa perder a maioria. Após cada membro, confirme o estado SECONDARY e que o lag foi zerado. O stepDown causa uma breve interrupção de escrita; garanta que os drivers se reconectem com retryable writes. Se houver um arbiter, trate-o na mesma sequência.","since":"MongoDB 4.4","note":"rs.stepDown(stepDownSecs, secondaryCatchUpPeriodSecs): o segundo parâmetro é quanto tempo o primário espera que um secundário o alcance; se nenhum alcançar, o stepDown falha e o primário permanece. Para impedir que um membro específico se torne primário durante a manutenção, rode rs.freeze(seconds) nele.","tags":["rolling","maintenance","restart","stepDown","upgrade","patching"],"untested":true},{"id":"sh-balancer-window","task":"Estado do balancer, janela ativa e balanceamento por collection","category":"Sharding","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":"Mostra se o balancer está habilitado e executando uma rodada, restringe as migrações de chunks a uma janela de tempo e desabilita ou habilita o balanceamento para uma única collection.","when":"Quando as migrações de chunks prejudicam o desempenho durante o dia, durante a janela de backup ou ao isolar um problema de migração em uma collection.","caution":"Uma janela estreita demais não acompanha o crescimento dos dados e os shards ficam desbalanceados; verifique o equilíbrio regularmente com balancerCollectionStatus. Uma migração iniciada antes do fim da janela roda até terminar. Se o balanceamento por collection ficar desabilitado, essa collection continua crescendo em um único shard.","since":"MongoDB 6.0","note":"Os horários de activeWindow são avaliados no fuso horário local do primário do replica set do config server. No 6.0.3+, o balancer decide com base na diferença de tamanho dos dados entre os shards, não no número de chunks; as contagens de chunks em sh.status() podem parecer desiguais enquanto os dados estão balanceados.","tags":["balancer","activeWindow","window","migration","sharding","balancerCollectionStatus"],"untested":true},{"id":"sh-jumbo-chunks","task":"Encontrar jumbo chunks, dividi-los e limpar a flag","category":"Sharding","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":"Lista os chunks marcados como jumbo porque o balancer não conseguiu movê-los, divide os que podem ser divididos e limpa a flag jumbo; mostra como refinar a shard key para chunks enormes de valor único.","when":"Quando um shard fica visivelmente maior que os outros, jumbo aparece na saída de sh.status() ou o balancer reporta erros de migração.","caution":"Um chunk cujos documentos compartilham todos o mesmo valor de shard key não pode ser dividido; a única correção duradoura é mudar a shard key com refineCollectionShardKey ou reshardCollection. refineCollectionShardKey exige que um índice de suporte para a nova chave exista previamente. Limpar a flag jumbo sem dividir faz o balancer tentar o mesmo chunk de novo e falhar outra vez.","since":"MongoDB 5.0","note":"Shard keys de baixa cardinalidade ou chaves concentradas em um valor (ex.: status, país) são a causa mais comum de jumbo chunks. Antes do 5.0, os documentos de config.chunks são consultados pelo campo ns. clearJumboFlag surgiu no 4.2.3/4.0.15.","tags":["jumbo","chunk","split","clearJumboFlag","shard key","refineCollectionShardKey"],"untested":true},{"id":"sh-shard-key-check","task":"Verificar a escolha da shard key e a distribuição dos dados (getShardDistribution, analyzeShardKey)","category":"Sharding","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":"Mostra o percentual dos dados de uma collection em cada shard; analyzeShardKey informa a cardinalidade, os valores mais frequentes e a monotonicidade da shard key atual ou candidata, e se as consultas amostradas atingem um único shard ou todos os shards (scatter-gather).","when":"Antes de shardar uma nova collection, quando se nota um shard quente ou crescimento desigual, e antes de decidir por um reshardCollection.","caution":"analyzeShardKey precisa de um índice que suporte a chave e faz amostragem de documentos em collections grandes; isso adiciona carga de leitura no horário de pico. Enquanto a amostragem de consultas está ativa, as amostras são gravadas em config.sampledQueries; desligue-a quando a análise terminar. Uma chave monotonicamente crescente (ObjectId, timestamp) concentra todos os inserts em um shard.","since":"MongoDB 7.0","note":"analyzeShardKey e configureQueryAnalyzer surgiram no 7.0 e também funcionam em replica sets. Uma boa shard key tem alta cardinalidade, baixa frequência, não é monotônica e aparece no filtro das consultas frequentes. Uma chave hashed corrige a distribuição, mas transforma consultas de intervalo em scatter-gather.","tags":["shard key","analyzeShardKey","getShardDistribution","cardinality","distribution","hot shard"],"untested":true},{"id":"explain-execstats","task":"Inspecionar um plano de consulta com estatísticas reais de execução (explain executionStats)","category":"Desempenho","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":"Executa a consulta e mostra o plano vencedor (IXSCAN/COLLSCAN, estágio SORT), o número de documentos retornados, as chaves de índice e os documentos examinados e o tempo gasto.","when":"Ao analisar uma consulta que aparece como lenta no profiler ou no log, e ao verificar se um novo índice é realmente usado.","caution":"executionStats realmente executa a consulta; fazer explain de uma consulta pesada no horário de pico também adiciona carga. Para comandos de escrita (update/delete/findAndModify), o explain não modifica dados, mas executa o plano. Uma razão totalDocsExamined/nReturned alta ou um estágio SORT em memória no plano indica que o índice não é adequado.","since":"MongoDB 4.4","note":"Aplique a regra ESR ao projetar índices compostos: primeiro os campos de igualdade (Equality), depois Sort, depois Range. Use explain(\"allPlansExecution\") para ver também os planos rejeitados. No 7.0+, quando uma consulta roda no Slot-Based Engine, winningPlan contém os campos queryPlan e slotBasedPlan.","tags":["explain","executionStats","IXSCAN","COLLSCAN","plan","index"]},{"id":"profiler-analyze","task":"Extrair as consultas e query shapes mais lentas dos dados do profiler","category":"Desempenho","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":"A partir dos registros da collection system.profile, lista as operações lentas recentes, o tempo total por query shape (queryHash) e as consultas COLLSCAN que não usam índice.","when":"Em uma reclamação de lentidão, para descobrir qual consulta consome o tempo do servidor e determinar necessidades de índice.","caution":"system.profile é uma capped collection de 1 MB por padrão e é por banco de dados; em um sistema movimentado, os registros são sobrescritos em minutos, então analise com o profiling ativo ou logo depois. O nível de profiling 2 ou slowms 0 grava todas as operações e adiciona overhead significativo. Os registros ficam apenas no membro onde rodaram e não são replicados.","since":"MongoDB 4.4","note":"Mesmo com o profiling desligado, as operações acima de slowms (padrão 100 ms) são gravadas no log do mongod como 'Slow query'; attr.durationMillis e attr.planSummary no log dão o mesmo diagnóstico. No 8.0+, um campo planCacheShapeHash também é gravado para a query shape.","tags":["profiler","system.profile","slow query","top queries","COLLSCAN","queryHash"]},{"id":"index-usage-hide","task":"Encontrar índices não utilizados e ocultá-los antes de remover (hideIndex)","category":"Desempenho","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 mostra quantas vezes cada índice foi usado; hideIndex oculta um índice do query planner sem removê-lo, de modo que o efeito de removê-lo pode ser testado de forma reversível.","when":"Ao limpar índices desnecessários que adicionam overhead de escrita e armazenamento.","caution":"Os contadores são por membro e zeram no restart; se as leituras vão para os secundários, verifique todos os membros e observe um período longo o suficiente (incluindo relatórios de fim de mês). Índices únicos ou TTL com ops 0 ainda podem ser necessários: a unique constraint e os deletes do TTL não aparecem no contador. Um índice oculto continua sendo mantido nas escritas, e um índice único oculto continua garantindo a constraint.","since":"MongoDB 4.4","note":"hideIndex exige featureCompatibilityVersion 4.4 ou superior. O índice _id não pode ser ocultado. Reexibir com unhideIndex não precisa de rebuild e tem efeito imediato.","tags":["indexStats","hideIndex","unused index","index cleanup","dropIndex","index"]},{"id":"connections-by-app","task":"Contar conexões por aplicação e cliente (diagnóstico de connection storm)","category":"Desempenho","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":"Mostra o total de conexões e as disponíveis no servidor e depois agrupa as conexões abertas por appName e IP do cliente, junto com quantas estão ativas.","when":"Quando o número de conexões salta de repente, em erros de 'connection refused' ou timeout do pool, para descobrir qual servidor de aplicação vaza conexões.","caution":"idleConnections: true também retorna todas as conexões ociosas, então em sistemas com milhares de conexões a saída é grande; por isso resumir com $group é importante. Linhas com cliente null são threads internas. Cada conexão consome cerca de 1 MB de memória; um connection storm também aumenta a memória fora do cache do WiredTiger.","since":"MongoDB 4.4","note":"A correção duradoura geralmente está no lado do driver: maxPoolSize, maxIdleTimeMS e o número de instâncias da aplicação. Se as aplicações não definem appName, distingui-las é difícil; peça appName=<service> na connection string. net.maxIncomingConnections e o valor de ulimit -n do SO definem o limite superior rígido.","tags":["connections","connection count","currentOp","appName","connection storm","pool"]},{"id":"index-build-monitor","task":"Monitorar e abortar uma construção de índice em andamento","category":"Manutenção","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":"Lista as construções de índice em execução com o número de documentos varridos e o percentual de progresso (progress.done / progress.total); se necessário, aborta a construção com dropIndex.","when":"Para estimar quando um createIndex iniciado em uma collection grande vai terminar, ou para parar uma construção que gera carga no horário de pico.","caution":"Aborte uma construção de índice com dropIndex/dropIndexes, não com killOp; em um replica set, rode-o no primário para que o abort se propague a todos os membros. Algumas operações DDL na collection esperam durante a construção. Um lock exclusivo curto é obtido no fim da construção; sob escritas muito pesadas, esse momento pode causar latência.","since":"MongoDB 4.4","note":"Em replica sets 4.4+, uma construção de índice roda simultaneamente em todos os membros que carregam dados e faz commit quando o commitQuorum (padrão votingMembers) é satisfeito; se um secundário estiver atrasado, a construção também não termina no primário. No 5.0+, uma construção interrompida por um clean shutdown retoma de onde parou após o restart.","tags":["index build","createIndex","progress","monitor","dropIndex","commitQuorum"]},{"id":"rolling-index-build","task":"Construção de índice rolling em um replica set (membro a membro)","category":"Manutenção","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":"Constrói o índice em cada membro separadamente, rodando temporariamente o membro como standalone fora do set; o primário nunca carrega a carga da construção.","when":"Quando o impacto da construção distribuída padrão no primário e no lag de replicação é inaceitável para uma collection muito grande.","caution":"O tempo de manutenção de cada membro precisa ser menor que a janela do oplog; caso contrário, o membro fica too stale ao voltar. Ao construir um índice único pelo método rolling, pare as escritas na collection durante toda a construção; caso contrário, alguns membros podem acabar com documentos que violam o índice. Inicie o membro standalone em outra porta para que as aplicações não se conectem a ele.","since":"MongoDB 4.4","note":"No 4.4+, a construção padrão já não bloqueia e roda simultaneamente em todos os membros; o método rolling só é necessário quando essa carga é inaceitável. Em um cluster shardado, o procedimento é feito para cada replica set de shard separadamente, com o balancer parado antes.","tags":["rolling index","index build","standalone","replica","createIndex","maintenance"],"untested":true},{"id":"ttl-index","task":"Criar um índice TTL, alterar sua expiração e monitorar os deletes do TTL","category":"Manutenção","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":"Cria um índice TTL que apaga automaticamente os documentos um tempo definido após um campo de data, altera a expiração com collMod sem rebuild e mostra quantos documentos o TTL monitor apagou.","when":"Para limpar dados com prazo, como sessões, logs ou tokens temporários, sem escrever um job de delete na aplicação, e para investigar por que uma collection em crescimento não está diminuindo.","caution":"O TTL monitor roda a cada 60 segundos por padrão; a exclusão não é instantânea. O campo precisa ser do tipo Date (ou um array de Dates); datas em string ou documentos sem o campo nunca são apagados. Encurtar a expiração faz muitos documentos serem apagados de uma vez, gerando carga de escrita e lag de replicação. Os deletes acontecem apenas no primário e são gravados no oplog.","since":"MongoDB 5.1","note":"Um índice TTL precisa ser de campo único (TTL composto não é suportado). Adicionar expireAfterSeconds a um índice de campo único existente não TTL com collMod é possível no 5.1+; alterar a expiração de um TTL existente também funciona em versões mais antigas. Para apagar em um horário específico, use expireAfterSeconds: 0 e armazene o horário de exclusão no campo.","tags":["ttl","expireAfterSeconds","collMod","auto delete","index","metrics.ttl"]},{"id":"wt-cache-pressure","task":"Medir a pressão no cache do WiredTiger (ocupação, taxa de dirty, eviction pela aplicação)","category":"Desempenho","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":"Mostra o tamanho do cache do WiredTiger, seus percentuais de ocupação e de dirty, quantas páginas as threads da aplicação foram forçadas a fazer eviction e o status dos tickets de leitura/escrita.","when":"Quando as leituras de disco aumentam, a latência dispara de repente ou o throughput de escrita cai; ao dimensionar o cache.","caution":"Quando a ocupação passa de 80% (eviction_target), começa o eviction em background; em 95% (eviction_trigger), as threads da aplicação também participam do eviction e as consultas ficam lentas. Para dados dirty, 5% é o alvo e 20% o gatilho; ficar constantemente perto de 20% significa que a capacidade de escrita em disco é insuficiente. Um contador pages evicted by application threads crescente é latência sentida diretamente pelos usuários. Os valores são contadores cumulativos; olhe a diferença entre duas amostras.","since":"MongoDB 7.0","note":"O tamanho padrão do cache é o maior entre (RAM - 1 GB) / 2 e 256 MB; dentro de containers, é calculado a partir do limite do cgroup. Aumentar storage.wiredTiger.engineConfig.cacheSizeGB reduz o page cache do SO; passar de metade da RAM raramente ajuda. No 7.0, o número de tickets é ajustado dinamicamente; no 8.0+, as métricas de tickets também aparecem em serverStatus().queues.execution.","tags":["wiredtiger","cache","eviction","dirty","tickets","memory"]},{"id":"dump-restore-archive","task":"Fazer um backup em arquivo com mongodump/mongorestore e restaurar uma única collection","category":"Backup","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":"Faz backup de um banco de dados em um único arquivo archive gzip; restaura o banco inteiro ou uma única collection a partir do archive, opcionalmente com outro nome (nsFrom/nsTo).","when":"Para backups lógicos, mover dados entre ambientes ou recuperar uma única collection removida ou corrompida por engano.","caution":"O mongodump é um backup lógico: é lento em grandes volumes de dados e os índices são reconstruídos durante o restore. Um dump feito sem --oplog não é consistente em um ponto no tempo em um sistema ativo. --drop apaga a collection de destino antes do início do restore; restaure primeiro com outro nome usando nsTo e verifique. O restore grava no primário e pode causar lag de replicação.","since":"MongoDB 4.4","note":"Desde o 4.4, as database tools (mongodump/mongorestore) têm versionamento separado do servidor (100.x). Adicione readPreference=secondary à URI para tirar a carga de leitura do primário durante o backup. Para levar também usuários e roles, use um dump completo da instância com --restoreDbUsersAndRoles ou faça backup do banco admin separadamente.","tags":["mongodump","mongorestore","backup","archive","nsFrom","restore"]},{"id":"pitr-oplog-replay","task":"Restore point-in-time com replay do oplog (voltar para antes de um drop/delete indevido)","category":"Backup","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":"Torna o backup completo consistente com --oplog e depois aplica o oplog acumulado após o backup até o timestamp da operação indevida (drop, delete em massa), trazendo os dados de volta àquele momento.","when":"Quando uma collection foi removida por engano ou um update/delete em massa com defeito rodou e você precisa do último estado antes do dano.","caution":"Restaure em um destino separado, não no sistema ativo, e mova os dados necessários após a verificação. O oplog desde o início do backup até a operação indevida ainda precisa estar dentro da janela do oplog; operações que saíram da janela não podem ser recuperadas. --oplog só funciona com um dump completo da instância (não pode ser combinado com --db). PITR consistente com mongodump não é possível em um cluster shardado; é necessário um snapshot de file system ou um produto de backup.","since":"MongoDB 4.4","note":"--oplogLimit=<seconds>:<ordinal> não aplica as entradas no timestamp informado ou depois dele; passar diretamente o ts da operação indevida a deixa de fora. Os valores de ts aparecem no oplog como Timestamp(t, i). Faça o dump do oplog logo após a operação indevida, antes que a janela se feche.","tags":["pitr","point in time","oplogReplay","oplogLimit","rollback","mongorestore"],"untested":true},{"id":"user-role-admin","task":"Definir uma role customizada, criar um usuário, conceder/revogar roles e alterar a senha","category":"Segurança","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":"Define uma role customizada com ações específicas de banco de dados e de cluster, cria um usuário com essa role e roles built-in, concede e revoga roles, altera a senha e lista os usuários de todos os bancos.","when":"Ao criar contas de aplicação e de monitoramento com privilégio mínimo, durante revisões de acesso ou rotação de senhas.","caution":"O banco onde o usuário é definido (aqui, admin) é usado como authSource; ele precisa corresponder à connection string da aplicação. Não conceda roles amplas como root/dbOwner a contas de aplicação. Mudanças de role se aplicam imediatamente às sessões existentes; uma mudança de senha não derruba as conexões abertas e se aplica às novas.","since":"MongoDB 4.4","note":"passwordPrompt() pede a senha sem deixá-la no histórico do shell ou na lista de processos. Em replica sets e clusters shardados, os usuários são gerenciados pelo primário/mongos e são replicados. Use showPrivileges: true em getUser para ver os privilégios efetivos de um usuário.","tags":["createUser","createRole","grantRolesToUser","privileges","rbac","password"]},{"id":"fcv-upgrade","task":"Verificar o featureCompatibilityVersion (fCV) e a sequência de upgrade de versão major","category":"Upgrade","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":"Mostra o fCV em execução; dá a ordem em que são feitos o upgrade do binário e o upgrade do fCV, que são etapas separadas.","when":"Ao planejar um upgrade de versão major (ex.: 6.0 -> 7.0), quando novos recursos não estão disponíveis após um upgrade ou antes de passar para a próxima major.","caution":"Versões major não podem ser puladas: para 5.0 -> 7.0, passe primeiro para o 6.0 e defina o fCV como 6.0. Depois que o fCV é elevado, os arquivos de dados podem mudar para o novo formato e o downgrade do binário fica mais difícil; eleve o fCV só depois que a nova versão rodar sem problemas por alguns dias. O downgrade de binário não é oficialmente suportado no 7.0+ Community; baseie o plano de retorno em um backup. Verifique a compatibilidade dos drivers antes do upgrade.","since":"MongoDB 7.0","note":"Desde o 7.0, setFeatureCompatibilityVersion exige confirm: true. Se uma transição de fCV falhar, targetVersion/previousVersion aparece na saída de getParameter; rode o mesmo comando de novo para concluí-la. O valor do fCV é replicado dentro do replica set.","tags":["fcv","featureCompatibilityVersion","upgrade","major upgrade","major","downgrade"]}]},"recipes/redis.json":{"engineId":"redis","engine":"Redis","order":6,"recipes":[{"id":"bgrewriteaof","task":"Reescrever (compactar) o arquivo AOF","category":"Persistência","command":"BGREWRITEAOF","what":"Reescreve o arquivo AOF em background em uma forma mais compacta.","when":"Quando o arquivo AOF inchou, para encurtar o tempo de restart.","caution":"O uso de memória e IO aumenta durante o fork; tenha cuidado nos horários de pico.","tags":["aof","rewrite","persistence","persistence"]},{"id":"bgsave","task":"Fazer um snapshot RDB em background","category":"Persistência","command":"BGSAVE","what":"Grava um snapshot RDB em disco em background usando um processo filho criado por fork.","when":"Quando você quer fazer um backup ou criar um snapshot.","caution":"No momento do fork, o uso de memória pode subir temporariamente por causa do copy-on-write.","tags":["rdb","bgsave","snapshot","persistence","backup"]},{"id":"save","task":"Fazer um snapshot RDB síncrono","category":"Persistência","command":"SAVE","what":"Grava um snapshot RDB em disco de forma síncrona na thread principal.","when":"Apenas antes de manutenção/desligamento, quando nenhum cliente está sendo atendido.","caution":"O SAVE bloqueia o servidor inteiro e nenhum comando é processado até ele terminar; prefira BGSAVE em produção.","tags":["rdb","save","snapshot","blocking","persistence"]},{"id":"lastsave","task":"Ver o horário do último snapshot bem-sucedido","category":"Persistência","command":"LASTSAVE","what":"Retorna o timestamp Unix do último save RDB bem-sucedido.","when":"Para verificar se um BGSAVE foi concluído.","caution":"Comando somente leitura; sem risco.","tags":["lastsave","rdb","timestamp","check","persistence"]},{"id":"config-rewrite","task":"Gravar a configuração em execução em disco","category":"Persistência","command":"CONFIG REWRITE","what":"Persiste no arquivo redis.conf as mudanças feitas em runtime com CONFIG SET.","when":"Quando você quer que as mudanças de runtime sobrevivam a um restart.","caution":"Sobrescreve o arquivo redis.conf existente; o arquivo precisa estar definido e ter permissão de escrita.","tags":["config","rewrite","persistent","conf","setting"]},{"id":"config-appendonly","task":"Habilitar ou desabilitar o AOF","category":"Persistência","command":"CONFIG SET appendonly yes","what":"Habilita (yes) ou desabilita (no) a persistência AOF em runtime.","when":"Quando você quer ligar ou desligar a persistência AOF sem restart.","caution":"Desabilitar o AOF enfraquece a garantia de durabilidade; ao habilitá-lo, o rewrite inicial do AOF gera carga de IO.","tags":["aof","appendonly","config","persistence","setting"]},{"id":"config-save-rdb","task":"Definir as regras de snapshot RDB","category":"Persistência","command":"CONFIG SET save \"900 1 300 10 60 10000\"","what":"Define as regras (segundos/número de mudanças) que disparam os snapshots RDB automáticos.","when":"Quando você quer mudar a frequência dos snapshots automáticos.","caution":"Se você passar um valor vazio (\"\"), o save RDB automático é desabilitado completamente e a persistência pode ser perdida.","tags":["rdb","save","config","snapshot","setting"]},{"id":"replicaof","task":"Tornar um nó uma réplica","category":"Replicação","command":"REPLICAOF redis-master 6379","what":"Torna este nó uma réplica do master no host e porta especificados e inicia a sincronização.","when":"Ao adicionar uma nova réplica de leitura ou atribuir papéis.","caution":"Os dados existentes no nó que se torna réplica são descartados e um full sync é puxado do master.","since":"Redis 5.0","note":"O comando REPLICAOF substituiu o SLAVEOF no Redis 5.0; o antigo comando SLAVEOF ainda funciona como alias.","tags":["replicaof","replica","replication","master","sync"]},{"id":"replicaof-no-one","task":"Promover uma réplica a master","category":"Replicação","command":"REPLICAOF NO ONE","what":"Quebra o vínculo de réplica do nó, transformando-o em um master standalone.","when":"Quando você quer promover uma réplica em um cenário de failover.","caution":"Após a promoção, gerencie a topologia com cuidado para que não haja divergência de dados (split-brain) com o antigo master.","since":"Redis 5.0","note":"REPLICAOF NO ONE substituiu SLAVEOF NO ONE no Redis 5.0; o antigo SLAVEOF NO ONE ainda funciona como alias.","tags":["replicaof","promote","master","failover","replication"]},{"id":"cluster-failover","task":"Executar um failover manual","category":"Cluster","command":"CLUSTER FAILOVER","what":"Quando executado em uma réplica, inicia um failover controlado promovendo essa réplica a master.","when":"Quando você quer passar o papel de master para uma réplica antes de uma manutenção.","caution":"Este comando precisa ser executado na réplica de destino, não no próprio master.","tags":["cluster","failover","promote","maintenance","replication"]},{"id":"cluster-meet","task":"Adicionar um nó ao cluster","category":"Cluster","command":"CLUSTER MEET 10.0.0.12 6379","what":"Une o nó no IP e porta especificados à rede gossip do cluster.","when":"Ao adicionar um novo nó ao cluster (escalonamento).","caution":"Se nenhuma atribuição de slots (ADDSLOTS) ou reshard for feita após adicionar o nó, ele não recebe dados.","tags":["cluster","meet","node","add","node"]},{"id":"cluster-addslots","task":"Atribuir slots do cluster","category":"Cluster","command":"CLUSTER ADDSLOTS 0 1 2 3 4 5","what":"Atribui os hash slots especificados a este nó master.","when":"Ao configurar manualmente um novo nó master ou corrigir a distribuição de slots.","caution":"O mesmo slot não pode ser atribuído a mais de um nó; se todos os 16384 slots não estiverem totalmente atribuídos, o cluster entra no estado down.","tags":["cluster","addslots","slot","assign","node"]},{"id":"info-replication","task":"Ver o status da replicação","category":"Cluster","command":"INFO replication","what":"Mostra o papel (master/replica), as réplicas conectadas e as informações de offset de replicação.","when":"Ao verificar o lag de replicação e o status do vínculo.","caution":"Comando somente leitura; sem risco.","tags":["info","replication","status","replication","lag"]},{"id":"cluster-info","task":"Ver o status do cluster","category":"Cluster","command":"CLUSTER INFO","what":"Mostra o estado geral do cluster (ok/fail), o número de slots atribuídos e o número de nós conhecidos.","when":"Ao verificar a saúde do cluster e a integridade dos slots.","caution":"Comando somente leitura; sem risco.","tags":["cluster","info","status","slot","health"]},{"id":"config-maxmemory","task":"Definir maxmemory e a política","category":"Memória","command":"CONFIG SET maxmemory 4gb maxmemory-policy allkeys-lru","what":"Define o limite de memória e a política de eviction aplicada quando o limite é excedido. O Redis 7.0+ aceita vários parâmetros em um único CONFIG SET; em versões mais antigas, rode dois comandos CONFIG SET separados.","when":"Quando você quer limitar o uso de memória e definir o comportamento de eviction.","caution":"Com a política noeviction, as escritas falham quando o limite é atingido; um limite errado pode levar a perda de dados/indisponibilidade.","tags":["maxmemory","policy","memory","eviction","config"]},{"id":"memory-doctor","task":"Analisar a memória","category":"Memória","command":"MEMORY DOCTOR","what":"Analisa o uso de memória e produz um relatório legível sobre possíveis problemas.","when":"Para diagnóstico quando há suspeita de uso alto de memória ou fragmentação.","caution":"Análise somente leitura; para detalhes, você também pode usar o comando MEMORY STATS.","tags":["memory","doctor","memory","analysis","diagnostics"]},{"id":"slowlog-get","task":"Ver o log de comandos lentos","category":"Manutenção","command":"SLOWLOG GET 10","what":"Retorna as 10 entradas mais recentes de comandos lentos (duração, horário, argumentos) do slowlog.","when":"Ao identificar comandos lentos e investigar gargalos de desempenho.","caution":"Comando somente leitura; use SLOWLOG RESET para limpar as entradas.","tags":["slowlog","get","slow","diagnostics","performance"]},{"id":"slowlog-config","task":"Definir o limite de comandos lentos","category":"Manutenção","command":"CONFIG SET slowlog-log-slower-than 10000","what":"Define o limite de duração, em microssegundos, para que um comando seja registrado no slowlog (10000 = 10 ms).","when":"Quando você quer ajustar a sensibilidade do slowlog.","caution":"Definir como 0 registra todos os comandos e adiciona overhead; -1 desabilita o slowlog.","tags":["slowlog","threshold","threshold","config","slow"]},{"id":"slowlog-reset","task":"Zerar o log de comandos lentos","category":"Manutenção","command":"SLOWLOG RESET","what":"Limpa todas as entradas do slowlog.","when":"Ao limpar as entradas para iniciar uma nova janela de observação.","caution":"O histórico existente de comandos lentos é apagado permanentemente.","tags":["slowlog","reset","reset","clear","maintenance"]},{"id":"client-kill","task":"Encerrar a conexão de um cliente","category":"Manutenção","command":"CLIENT KILL ADDR 10.0.0.5:53210","what":"Encerra a conexão do cliente no endereço especificado.","when":"Quando você quer encerrar um cliente travado ou com comportamento anômalo.","caution":"A conexão é derrubada imediatamente; operações em andamento podem ficar incompletas. Certifique-se de escolher o endereço correto.","tags":["client","kill","client","kill","maintenance"]},{"id":"client-list","task":"Listar os clientes conectados","category":"Manutenção","command":"CLIENT LIST","what":"Lista todos os clientes conectados com detalhes como endereço, tempo ocioso e último comando.","when":"Ao inspecionar conexões ou encontrar um cliente problemático.","caution":"Comando somente leitura; sem risco.","tags":["client","list","client","list","connection"]},{"id":"config-get","task":"Ver o valor de um parâmetro","category":"Runtime","command":"CONFIG GET maxmemory-policy","what":"Retorna o valor atual de um ou mais parâmetros de configuração (padrões glob são suportados).","when":"Ao verificar o valor de runtime de uma configuração.","caution":"Comando somente leitura; sem risco.","tags":["config","get","parameter","view","runtime"]},{"id":"config-set","task":"Alterar o valor de um parâmetro","category":"Runtime","command":"CONFIG SET appendfsync everysec","what":"Altera um parâmetro de configuração em runtime sem restart.","when":"Quando você quer ajustar um comportamento do servidor imediatamente.","caution":"A mudança é temporária; rode CONFIG REWRITE para persisti-la. Um valor errado pode degradar o desempenho/durabilidade.","tags":["config","set","parameter","runtime","setting"]}]},"recipes/redis-ext.json":{"engineId":"redis","engine":"Redis","order":2,"recipes":[{"id":"mem-fragmentation","task":"Analisar o uso de memória e a fragmentação, habilitar o active defrag","category":"Memória","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":"Mostra a diferença entre a memória que o Redis aloca para dados (used_memory) e o RSS visto pelo SO, a taxa de fragmentação e o detalhamento da memória; habilita o active defrag em runtime se necessário.","when":"Quando o RSS é claramente maior que o dataset, a memória não cai após deletes em massa/expiração ou surge um risco de OOM.","caution":"mem_fragmentation_ratio é enganoso em datasets pequenos (ex.: 4.0 com 2 MB de dados); olhe mem_fragmentation_bytes para o valor absoluto. Uma razão abaixo de 1 significa swap, não fragmentação, e causa latência. O active defrag consome CPU; limite-o com active-defrag-cycle-max. É necessário CONFIG REWRITE ou redis.conf para torná-lo persistente.","since":"Redis 4.0","note":"O active defrag só funciona em builds compilados com o jemalloc que acompanha o Redis. allocator_frag_ratio mostra a fragmentação interna que o defrag consegue corrigir; allocator_rss_ratio mostra o espaço que o alocador não devolveu ao SO. A fragmentação cresce mais rápido em cargas que atualizam com frequência valores de tamanho variável.","tags":["memory","ram","fragmentation","activedefrag","rss","info memory"]},{"id":"bigkeys-memkeys","task":"Encontrar big keys (--bigkeys, --memkeys, MEMORY USAGE)","category":"Memória","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":"Varre o keyspace com SCAN e informa as chaves com mais elementos e mais memória por tipo; mostra o consumo real de memória e o encoding de uma chave suspeita.","when":"Quando a memória cresce inesperadamente, um único comando (HGETALL, SMEMBERS, DEL) causa latência ou um nó do cluster usa mais memória que os outros.","caution":"A varredura usa SCAN e não bloqueia o servidor, mas percorre o keyspace inteiro; -i 0.01 dorme a cada 100 chamadas SCAN para reduzir a carga. Apagar uma big key com DEL bloqueia a thread principal; use UNLINK. MEMORY USAGE com SAMPLES 0 é O(N) em coleções grandes. Rodar em uma réplica não gera carga no master.","since":"Redis 6.0","note":"--bigkeys olha a contagem de elementos, --memkeys o MEMORY USAGE; para tipos como list/hash, eles podem destacar chaves diferentes. Hashes/zsets/lists pequenos usam encoding listpack e ocupam muito menos memória; quando limites como hash-max-listpack-entries são excedidos, eles são convertidos para hashtable. Em um cluster, rode em cada master separadamente.","tags":["bigkeys","memkeys","big key","memory usage","keystats","large key"]},{"id":"hotkeys-lfu","task":"Encontrar hot keys (--hotkeys, OBJECT FREQ)","category":"Desempenho","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":"Lista as chaves acessadas com mais frequência usando os contadores LFU; mostra o contador de frequência de acesso de uma única chave.","when":"Quando a CPU de um nó se aproxima de 100%, um slot/nó do cluster recebe muito mais tráfego que os outros ou a banda de rede é saturada por uma única chave.","caution":"--hotkeys só funciona quando maxmemory-policy é *-lfu. Mudar a política também muda o comportamento de eviction: se maxmemory estiver definido e a política anterior era volatile-* ou noeviction, allkeys-lfu também pode fazer eviction de chaves sem TTL. Mantenha a análise curta e reverta a política. Os contadores LFU são logarítmicos e decaem com o tempo; não são contagens absolutas de acesso.","since":"Redis 4.0","note":"Após a mudança de política, é preciso algum tráfego até que os contadores LFU fiquem significativos. Se a política não puder ser mudada, uma amostra curta com MONITOR é uma alternativa, mas o MONITOR reduz seriamente o throughput em sistemas movimentados. Para hot keys de leitura, client-side caching (CLIENT TRACKING) ou dividir a chave é a correção duradoura.","tags":["hotkeys","hot keys","lfu","object freq","hot key","cpu"]},{"id":"scan-unlink-pattern","task":"Encontrar chaves que correspondem a um padrão sem KEYS e apagá-las com segurança (SCAN + UNLINK)","category":"Manutenção","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":"Varre o keyspace com um cursor sem bloquear o servidor, conta as chaves que correspondem a um padrão e tipo e as apaga em massa com UNLINK, liberando a memória em background.","when":"Ao limpar chaves deixadas por uma versão antiga da aplicação, ao descobrir quantas chaves existem sob um prefixo ou quando, de outra forma, seria preciso usar KEYS em produção.","caution":"KEYS retorna o keyspace inteiro de uma vez e bloqueia o servidor por segundos em grandes volumes de dados; não use em produção. O SCAN não dá garantia total para chaves adicionadas/removidas durante a varredura e pode retornar a mesma chave mais de uma vez. Nomes de chaves com espaços ou aspas quebram com xargs. Verifique a contagem e algumas amostras antes de apagar; não há como desfazer.","since":"Redis 4.0","note":"A opção TYPE do SCAN surgiu no 6.0. COUNT é uma sugestão e não garante o número de elementos retornados. Em um cluster, --scan só varre o nó conectado; rode em cada master. UNLINK libera valores grandes em uma thread separada via lazyfree; para chaves pequenas, custa o mesmo que DEL.","tags":["scan","unlink","keys","bulk delete","pattern","match"]},{"id":"latency-diagnosis","task":"Diagnosticar a origem da latência (LATENCY DOCTOR, histograma, commandstats)","category":"Desempenho","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":"O latency monitor registra picos de latência de eventos como fork, fsync do AOF, o ciclo de expire e comandos lentos; mostra os percentis de latência por comando e os comandos mais caros por tempo total de CPU; mede a latência de base no nível do host.","when":"Quando a aplicação vê picos de latência p99 e as reclamações de lentidão continuam mesmo com o SLOWLOG limpo.","caution":"latency-monitor-threshold tem padrão 0 (desligado); restaure o valor antigo após o diagnóstico. O SLOWLOG mede apenas o tempo de execução do comando e não vê esperas de rede ou de fila; os eventos LATENCY também capturam travamentos internos do servidor, como fork e fsync. --intrinsic-latency consome CPU e precisa rodar na máquina que hospeda o servidor Redis.","since":"Redis 7.0","note":"LATENCY HISTOGRAM e INFO latencystats surgiram no 7.0 (latency-tracking vem ligado por padrão). Se eventos de fork dominam o LATENCY HISTORY, olhe o tamanho do dataset e o THP (transparent huge pages); se os eventos aof-fsync-always/aof-write estão altos, olhe a latência do disco. Comandos com usec_per_call alto no commandstats indicam uso O(N).","tags":["latency","slowness","latency doctor","histogram","commandstats","intrinsic-latency"]},{"id":"eviction-oom-diag","task":"Diagnosticar eviction, expiração e erros de OOM","category":"Memória","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":"Mostra as contagens de chaves evicted e expired, a taxa de acerto do cache, a proporção de chaves com TTL e o valor de memória que dispara o eviction em relação ao maxmemory.","when":"Quando a aplicação recebe 'OOM command not allowed when used memory > maxmemory', a taxa de acerto do cache cai ou chaves são relatadas como desaparecendo inesperadamente.","caution":"Com a política noeviction, os comandos de escrita recebem erro de OOM quando o maxmemory é atingido, enquanto as leituras continuam funcionando. Com as políticas volatile-*, chaves sem TTL nunca sofrem eviction; se não houver chaves com TTL, o comportamento é como noeviction (verifique expires em INFO keyspace). Não defina maxmemory muito perto da RAM física: deixe espaço para os buffers de replicação e o copy-on-write durante o fork.","since":"Redis 6.0","note":"Taxa de acerto = keyspace_hits / (keyspace_hits + keyspace_misses). Se evicted_keys cresce continuamente enquanto a taxa de acerto cai, a memória é insuficiente. Um expired_stale_perc alto significa uma grande proporção de chaves expiradas ainda não removidas; o ciclo de expire pode ser acelerado com active-expire-effort. Os buffers de réplica e o buffer do AOF estão incluídos em mem_not_counted_for_evict.","tags":["eviction","oom","maxmemory","expire","hit ratio","evicted_keys"]},{"id":"client-memory","task":"Encontrar conexões que inflam a memória (output buffer, query buffer, maxmemory-clients)","category":"Memória","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":"Ordena as conexões por memória total (tot-mem), output buffer (omem) e query buffer (qbuf); mostra as conexões pub/sub e os limites de buffer; define um limite superior geral para a memória dos clientes.","when":"Quando used_memory cresce sem crescimento dos dados, mem_clients_normal parece alto ou um cliente pub/sub/MONITOR que consome devagar enche a memória.","caution":"Um omem grande geralmente indica um cliente lendo resultados devagar (resposta grande de KEYS/HGETALL, assinante pub/sub lento, um MONITOR deixado aberto). Quando maxmemory-clients é excedido, os clientes que mais ocupam memória são fechados sem aviso; os vínculos de réplica e master são excluídos, mas as conexões da aplicação podem cair. Use CLIENT NO-EVICT on para conexões críticas.","since":"Redis 7.0","note":"maxmemory-clients surgiu no 7.0 e tem padrão 0 (ilimitado). client-output-buffer-limit aplica limites hard/soft para as classes pubsub e replica; clientes normais são ilimitados por padrão. Feche uma conexão problemática com CLIENT KILL ID <id> (veja client-kill).","tags":["client list","omem","output buffer","maxmemory-clients","connections","pubsub"]},{"id":"persistence-health","task":"Diagnosticar o estado de erro de RDB/AOF, o tempo de fork e a causa do MISCONF","category":"Persistência","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":"Mostra se o último snapshot RDB e o rewrite/escrita do AOF tiveram sucesso, quantas chaves mudaram desde o último save, a contagem de fsync atrasados e a duração do fork.","when":"Quando a aplicação recebe 'MISCONF Redis is configured to save RDB snapshots, but it's currently unable to persist to disk', o BGSAVE/BGREWRITEAOF falha ou se observa latência relacionada ao fork.","caution":"Com stop-writes-on-bgsave-error yes (padrão), todas as escritas são rejeitadas após um BGSAVE com falha. Silenciar o erro definindo-o como 'no' esconde o risco de perda de dados; corrija primeiro a causa: disco cheio, sem permissão de escrita em dir ou fork que não consegue memória (vm.overcommit_memory=0). O tempo de fork pode chegar a centenas de milissegundos em um dataset grande, e o Redis não responde durante esse tempo.","since":"Redis 7.0","note":"vm.overcommit_memory=1 e transparent huge pages desabilitadas no Linux são as recomendações oficiais do Redis. Um aof_delayed_fsync crescente significa que o disco não acompanha o fsync (appendfsync everysec). Os detalhes do erro estão no log do Redis ('Background saving error', 'Can't save in background: fork').","tags":["misconf","bgsave","aof","fork","persistence","durability"]},{"id":"aof-repair","task":"Reparar um Redis que não inicia por causa de um AOF corrompido (redis-check-aof, redis-check-rdb)","category":"Persistência","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":"Valida os arquivos AOF (base + incr + manifest) e o arquivo RDB; trunca o final incompleto ou corrompido do AOF para que o Redis possa iniciar novamente.","when":"Quando o Redis não inicia com 'Bad file format reading the append only file' ou 'Unexpected EOF' após uma queda de energia, um disco cheio ou um desligamento abrupto.","caution":"--fix apaga tudo do primeiro ponto corrompido até o fim do arquivo; se a corrupção estiver no meio do arquivo, todas as escritas posteriores são perdidas. Verifique na saída quantos bytes serão truncados (ok_up_to, diff) antes de confirmar. Um último comando incompleto (ex.: um HSET grande) é descartado por inteiro. Sempre faça uma cópia antes.","since":"Redis 7.0","note":"Com aof-load-truncated yes (padrão), um AOF truncado apenas no final é aparado automaticamente na inicialização; o redis-check-aof geralmente é necessário quando a corrupção está no meio do arquivo. No AOF multi-part do 7.0+, os arquivos ficam no diretório appenddirname e o arquivo base pode estar em formato RDB. Para um RDB corrompido, o redis-check-rdb apenas diagnostica e não repara.","tags":["aof","redis-check-aof","corrupted","corrupt","repair","redis-check-rdb"]},{"id":"replication-backlog","task":"Corrigir quedas de replicação e um loop infinito de full resync (backlog, buffer da réplica)","category":"Replicação","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":"Mostra o estado do vínculo, a diferença de offset e os contadores de sync parcial/completo no master e na réplica; aumenta o replication backlog para que desconexões curtas não virem full syncs e o limite do output buffer da réplica para que um full sync não seja cortado no meio.","when":"Quando uma réplica fica em loop em 'MASTER <-> REPLICA sync started', o contador sync_full cresce ou o log do master mostra 'scheduled to be closed ASAP for overcoming of output buffer limits'.","caution":"Todo full sync significa um fork + geração de RDB no master; o loop sobrecarrega a memória e o disco do master. repl-backlog-size é alocado da memória do master. Aumentar o limite do buffer da réplica significa que o master pode usar essa quantidade extra de memória durante um full sync; inclua isso no cálculo do maxmemory. É necessário CONFIG REWRITE ou redis.conf para tornar as mudanças persistentes.","since":"Redis 4.0","note":"Dimensionamento aproximado do backlog: o volume de escrita por segundo do master (crescimento de master_repl_offset) x a duração de desconexão a tolerar. O nome de classe 'replica' em client-output-buffer-limit é aceito no lugar de 'slave' desde o 5.0; a saída de CONFIG GET ainda pode mostrar slave. Se o disco for lento, repl-diskless-sync yes (padrão no 7.0+) envia o RDB pelo socket sem gravá-lo em disco.","tags":["replication","backlog","full sync","psync","replica","output buffer"]},{"id":"sentinel-status","task":"Verificar o estado do Sentinel, o master atual e o quorum","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":"Lista os masters monitorados pelo Sentinel, o endereço do master atual, as réplicas conhecidas e os outros sentinels; verifica se o quorum e a maioria necessários para o failover estão disponíveis.","when":"Quando a aplicação se conecta ao nó errado, ao verificar a topologia após um failover e antes de toda manutenção.","caution":"Cada sentinel informa sua própria visão; GET-MASTER-ADDR-BY-NAME precisa retornar o mesmo endereço em todos os sentinels, caso contrário há uma partição de rede ou uma divergência de configuração. s_down/o_down no campo flags ou disconnected em uma réplica exige investigação urgente. A porta do Sentinel (26379) deve estar aberta no firewall apenas entre os sentinels e os clientes.","since":"Redis 5.0","note":"SENTINEL REPLICAS substituiu SENTINEL SLAVES no 5.0 (o nome antigo ainda funciona). O número de sentinels deve ser ímpar e no mínimo 3, distribuídos em domínios de falha diferentes (host/rack/AZ). Se o Redis usa ACL/senhas, sentinel auth-user/auth-pass precisam estar definidos no sentinel.conf.","tags":["sentinel","master","quorum","ckquorum","topology","failover"],"untested":true},{"id":"sentinel-failover","task":"Executar um failover manual com o Sentinel e limpar a topologia","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":"Passa o papel de master para a réplica mais adequada mesmo quando o master está saudável; depois verifica o novo master e remove da memória dos sentinels as réplicas que não existem mais.","when":"Antes de uma manutenção planejada no host do master, durante um teste de failover ou ao mover o master para outro data center.","caution":"Há uma interrupção de escrita de alguns segundos durante o failover, e dados gravados no master mas ainda não replicados podem ser perdidos. Réplicas com replica-priority 0 nunca são escolhidas; se não houver réplica elegível, o comando retorna erro. Se o SENTINEL RESET rodar em todos os sentinels de uma vez, as informações de topologia se perdem temporariamente; rode-o em cada um separadamente e com intervalo. Garanta que os clientes usem um driver que pergunta ao Sentinel o endereço do master.","since":"Redis 5.0","note":"SENTINEL FAILOVER não pede acordo aos outros sentinels, mas propaga a nova config epoch. Ordem de seleção: replica-priority (menor primeiro), replication offset (maior primeiro), run ID. Quando o antigo master volta após o failover, o Sentinel o reconfigura automaticamente como réplica do novo master.","tags":["sentinel","failover","manual failover","master","reset","switchover"],"untested":true},{"id":"cluster-check-fix","task":"Verificar a saúde do cluster e reparar inconsistências de slots (--cluster check/fix)","category":"Cluster","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":"Verifica se todos os nós veem o mesmo mapa de slots, se todos os 16384 slots estão atribuídos e se não há slots incompletos (migrating/importing); corrige os problemas encontrados e mostra em qual slot/nó uma chave está.","when":"Quando aparece cluster_state:fail, os clientes recebem CLUSTERDOWN ou erros MOVED/ASK constantes, e após um reshard interrompido.","caution":"--cluster fix pode atribuir slots sem dono a nós arbitrários e mover chaves em slots abertos; revise primeiro a saída do check. Se um master e todas as suas réplicas forem perdidos, os dados desses slots se foram; o fix apenas atribui o slot vazio a outro nó. Com cluster-require-full-coverage yes (padrão), um único slot sem dono interrompe as escritas no cluster inteiro.","since":"Redis 7.0","note":"CLUSTER SHARDS surgiu no 7.0 e substitui CLUSTER SLOTS. Se a autenticação estiver habilitada, adicione -a <password> ou --user/--pass aos comandos --cluster. As flags fail/pfail na saída de CLUSTER NODES significam que o nó é visto como inacessível pelos outros.","tags":["cluster","check","fix","slot","clusterdown","cluster nodes"],"untested":true},{"id":"cluster-reshard","task":"Adicionar nós, mover slots e remover nós em um cluster (add-node, reshard, rebalance)","category":"Cluster","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":"Adiciona um novo master ou réplica ao cluster, move slots e suas chaves entre nós online, rebalanceia a distribuição de slots automaticamente e remove do cluster um nó esvaziado.","when":"Ao escalar horizontalmente memória/throughput, espalhar a carga de um nó quente ou desativar um nó.","caution":"A migração de slots transfere as chaves uma a uma com MIGRATE; enquanto big keys são movidas, os dois nós podem bloquear brevemente. Durante a migração, os clientes recebem redirecionamentos ASK; é necessário um cliente cluster-aware. Se um reshard for interrompido, os slots ficam no estado migrating/importing; conclua-o com --cluster fix. Não remova com del-node um master que ainda possui slots; mova seus slots primeiro.","since":"Redis 5.0","note":"Os IDs dos nós vêm de CLUSTER NODES ou CLUSTER MYID. --cluster-pipeline define quantas chaves cada chamada MIGRATE move (padrão 10). --cluster rebalance com --cluster-weight pode dar pesos diferentes aos nós. Os comandos redis-cli --cluster substituíram o redis-trib.rb no 5.0.","tags":["cluster","reshard","rebalance","add-node","slot","del-node"],"untested":true},{"id":"acl-users","task":"Criar usuários ACL, testar permissões e torná-los persistentes","category":"Segurança","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":"Cria usuários de aplicação e de monitoramento autorizados por prefixo de chave, canal pub/sub e categoria de comando; testa com DRYRUN se um comando é permitido sem executá-lo e grava as ACLs em disco.","when":"Ao migrar de uma única senha compartilhada (requirepass) para acesso por usuário, isolar as aplicações das chaves umas das outras ou criar uma conta somente leitura para uma ferramenta de monitoramento.","caution":"A ordem das regras importa: resetchannels remove quaisquer regras &channel dadas antes dele. -@dangerous também bloqueia comandos como KEYS, FLUSHALL, CONFIG e DEBUG; verifique com DRYRUN os comandos que a aplicação usa. Se o usuário default continuar habilitado com nopass e +@all, as ACLs não oferecem proteção; rode ACL SETUSER default off depois de criar um usuário admin. No redis-cli, se o AUTH com --user/--pass falhar, a conexão continua como usuário default e o comando ainda roda; por isso use DRYRUN para testes de permissão.","since":"Redis 7.0","note":"As ACLs surgiram no 6.0; ACL DRYRUN, selectors e regras de subcomando (client|list) foram adicionados no 7.0. aclfile e linhas user no redis.conf não podem ser usados juntos. As senhas são armazenadas como hashes SHA-256; ACL GETUSER não mostra a senha em texto puro.","tags":["acl","setuser","users","permissions","dryrun","security"]},{"id":"acl-log-denied","task":"Investigar erros NOPERM e WRONGPASS (ACL LOG)","category":"Segurança","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":"Lista os acessos negados a comandos, chaves e canais e as tentativas de AUTH com falha, com nome de usuário, objeto, contagem de repetições e informações do cliente (IP, último comando); mostra os contadores cumulativos de negações.","when":"Quando a aplicação recebe NOPERM ou WRONGPASS após um deploy, para encontrar o comando quebrado por uma regra ACL mais restrita ou para detectar tentativas de adivinhar senhas.","caution":"O ACL LOG fica em memória, é limpo no restart e é limitado a acllog-max-len (padrão 128) entradas; quando o mesmo erro se repete, count aumenta em vez de surgir uma nova linha. O campo client-info contém o IP do cliente e o usuário em uso; registre o que precisar antes de zerar.","since":"Redis 7.0","note":"Os contadores acl_access_denied_* foram adicionados ao INFO stats no 7.2; ligue-os ao monitoramento para alertar quando aumentarem. Os campos entry-id e timestamp-created/last-updated surgiram no 7.2. Tentativas com senha errada aparecem como reason=auth, falta de permissão de comando como reason=command.","tags":["acl log","noperm","wrongpass","access denied","auth","security"]},{"id":"keyspace-notifications","task":"Monitorar eventos de exclusão e expiração de chaves com keyspace notifications","category":"Manutenção","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":"Publica eventos sobre chaves (expire, del, set etc.) em canais pub/sub para que você possa acompanhar ao vivo qual chave foi apagada ou expirou e quando.","when":"Para provar qual comando ou expiração remove chaves quando elas 'somem sozinhas', ou para alimentar fluxos que dependem de eventos de expiração (fechamento de sessão).","caution":"Os eventos adicionam carga de CPU e de rede; 'A' (todas as classes) é especialmente caro em sistemas movimentados, então habilite só as classes de que precisa e desligue-as depois. O pub/sub é fire-and-forget: um assinante que não está conectado perde o evento, e nada é persistido. O evento expired é gerado quando a chave é de fato apagada (no acesso ou pelo ciclo de expire em background), não no momento do TTL.","since":"Redis 2.8","note":"Adicione a classe e (evicted) para chaves removidas por eviction. Em um cluster, os eventos são publicados apenas no nó que contém a chave; assine cada master separadamente. Defina notify-keyspace-events no redis.conf para uma configuração persistente.","tags":["keyspace notifications","notify-keyspace-events","expired","pubsub","events","psubscribe"]}]},"recipes/elasticsearch.json":{"engineId":"elasticsearch","engine":"Elasticsearch","order":7,"recipes":[{"id":"flush","task":"Fazer flush de um índice","category":"Ciclo de vida do índice","command":"POST /customer/_flush","what":"Executa um commit do Lucene: grava de forma durável em disco, como segmentos, os dados de indexação em memória e apara as entradas do translog que não são mais necessárias.","when":"Para reduzir o translog antes de uma manutenção ou restart.","caution":"Normalmente é feito automaticamente; um flush manual causa um leve aumento de IO.","tags":["flush","translog","index","customer","maintenance"]},{"id":"force-merge","task":"Mesclar segmentos do índice (force merge)","category":"Ciclo de vida do índice","command":"POST /customer/_forcemerge?max_num_segments=1","what":"Mescla os segmentos do índice para reduzir o número de segmentos e melhorar o desempenho de leitura.","when":"Apenas em índices que não recebem mais escritas (somente leitura), para melhorar o desempenho das consultas.","caution":"Consome IO e CPU pesados; nunca rode em índices com escrita ativa. Pode levar muito tempo e não pode ser cancelado.","tags":["forcemerge","segment","merge","merge segments","performance"]},{"id":"rollover","task":"Fazer rollover via alias","category":"Ciclo de vida do índice","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":"Quando o write index para o qual o alias aponta atende às condições, cria um novo índice e aponta o alias para ele.","when":"Para gerenciar o tamanho dos índices em dados de séries temporais (uma alternativa/complemento ao ILM).","caution":"O alias precisa ter um único write index via is_write_index; uma configuração errada bloqueia o rollover.","tags":["rollover","alias","index","time series","ilm"]},{"id":"set-refresh-interval","task":"Alterar o intervalo de refresh","category":"Ciclo de vida do índice","command":"PUT /customer/_settings\n{\n  \"index\": { \"refresh_interval\": \"30s\" }\n}","what":"Define com que frequência o índice torna os novos documentos pesquisáveis (refresh).","when":"Ao aumentar o intervalo para acelerar a indexação durante cargas em massa.","caution":"-1 desabilita o refresh completamente; os documentos não ficam pesquisáveis. Volte para um valor razoável após a carga.","tags":["refresh","interval","settings","bulk","refresh interval"]},{"id":"set-replicas","task":"Alterar o número de réplicas","category":"Ciclo de vida do índice","command":"PUT /customer/_settings\n{\n  \"index\": { \"number_of_replicas\": 2 }\n}","what":"Altera dinamicamente o número de replica shards do índice.","when":"Para aumentar/diminuir a redundância ou a capacidade de leitura.","caution":"Adicionar réplicas gera uso extra de disco e tráfego de rede (recovery); baixar para 0 remove a redundância.","tags":["replica","settings","number_of_replicas","redundancy","capacity"]},{"id":"open-close-index","task":"Abrir ou fechar um índice","category":"Ciclo de vida do índice","command":"POST /customer/_close\nPOST /customer/_open","what":"Fecha o índice para leituras/escritas (liberando recursos) ou o abre novamente.","when":"Para reduzir o uso de recursos de índices pouco usados ou para alterar certas configurações.","caution":"Um índice fechado não pode ser consultado nem receber escritas; enquanto fechado, não é acessível, exceto via snapshots.","tags":["open","close","index","open index","close index"]},{"id":"node-join-note","task":"Adicionar um nó ao cluster","category":"Cluster/Nó","command":"GET /_cat/nodes?v","what":"Iniciar o novo nó com o mesmo cluster.name e o discovery.seed_hosts correto no elasticsearch.yml é suficiente; este comando verifica se o nó entrou no cluster.","when":"Para verificar a associação ao adicionar um novo nó ao cluster.","caution":"No 7.0+ não existe minimum_master_nodes; a configuração de votação é gerenciada automaticamente. Adicione e remova nós master-eligible um de cada vez e nunca remova metade ou mais deles de uma vez; ao remover permanentemente mais de um nó master-eligible, use antes POST _cluster/voting_config_exclusions?node_names=....","tags":["node","join","cluster","cat","add node"]},{"id":"node-decommission","task":"Esvaziar um nó (decommission)","category":"Cluster/Nó","command":"PUT /_cluster/settings\n{\n  \"persistent\": {\n    \"cluster.routing.allocation.exclude._name\": \"node-3\"\n  }\n}","what":"Esvazia com segurança o nó especificado, movendo seus shards para outros nós.","when":"Para retirar os dados de um nó antes de tirá-lo de serviço.","caution":"A realocação de shards gera carga pesada de rede/IO; garanta que os nós restantes tenham disco e capacidade suficientes. Remova a configuração com null após a remoção do nó. As configurações transient estão obsoletas desde o 7.16; use persistent.","tags":["decommission","exclude","allocation","drain","node"]},{"id":"reroute-shard","task":"Mover um shard manualmente (reroute)","category":"Cluster/Nó","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":"Move manualmente um shard específico de um nó para outro.","when":"Para corrigir uma distribuição desbalanceada de shards ou esvaziar um nó específico.","caution":"Pode conflitar com o rebalanceamento automático; mover shards grandes gera carga de rede e IO.","tags":["reroute","shard","move","relocate","cluster"]},{"id":"allocation-enable","task":"Habilitar ou desabilitar a alocação de shards","category":"Cluster/Nó","command":"PUT /_cluster/settings\n{\n  \"persistent\": {\n    \"cluster.routing.allocation.enable\": \"primaries\"\n  }\n}","what":"Restringe a alocação de shards em todo o cluster (primaries: só primários são alocados, none: nada) ou a retorna ao padrão (all / null).","when":"Antes de um rolling restart, para evitar realocações desnecessárias de réplicas (o valor oficialmente recomendado é \"primaries\").","caution":"Lembre-se de reverter a configuração com null (ou \"all\") depois; se ela continuar restrita, as réplicas ficam não atribuídas. As configurações transient estão obsoletas; use persistent.","tags":["allocation","enable","restart","shard","cluster"]},{"id":"cluster-settings","task":"Alterar uma configuração do cluster","category":"Cluster/Nó","command":"PUT /_cluster/settings\n{\n  \"persistent\": {\n    \"indices.recovery.max_bytes_per_sec\": \"100mb\"\n  }\n}","what":"Altera uma configuração persistent ou transient de todo o cluster.","when":"Ao ajustar o comportamento do cluster, como a velocidade de recovery.","caution":"As configurações persistent sobrevivem a restarts; as transient se perdem e estão obsoletas desde o 7.16, então não as use. Para redefinir uma configuração para o padrão, defina seu valor como null. Um valor errado afeta a estabilidade do cluster.","tags":["cluster","settings","persistent","transient","setting"]},{"id":"snapshot-repo","task":"Registrar um repositório de snapshots","category":"Snapshot","command":"PUT /_snapshot/backup_repo\n{\n  \"type\": \"fs\",\n  \"settings\": {\n    \"location\": \"/mnt/es_backups\"\n  }\n}","what":"Registra um repositório onde os snapshots serão armazenados.","when":"Ao configurar a infraestrutura de backup pela primeira vez.","caution":"Para um repositório fs, o caminho precisa estar definido em path.repo e acessível em todos os nós master e de dados.","tags":["snapshot","repository","repo","backup","register"]},{"id":"snapshot-create","task":"Fazer um snapshot","category":"Snapshot","command":"PUT /_snapshot/backup_repo/snap1?wait_for_completion=false\n{\n  \"indices\": \"customer\",\n  \"include_global_state\": false\n}","what":"Faz um backup point-in-time (snapshot) dos índices especificados no repositório.","when":"Para backups regulares ou como backup de segurança antes de uma mudança grande.","caution":"wait_for_completion=true mantém a conexão HTTP esperando por muito tempo em índices grandes; use false para snapshots grandes.","tags":["snapshot","create","backup","backup snapshot","take"]},{"id":"snapshot-restore","task":"Restaurar a partir de um snapshot","category":"Snapshot","command":"POST /_snapshot/backup_repo/snap1/_restore\n{\n  \"indices\": \"customer\",\n  \"rename_pattern\": \"customer\",\n  \"rename_replacement\": \"customer_restored\"\n}","what":"Restaura índices de um snapshot no cluster (opcionalmente renomeando-os).","when":"Para recuperação após perda de dados ou ao levar um backup para um ambiente de teste.","caution":"Para restaurar com o mesmo nome, o índice de destino precisa estar fechado ou removido; não é possível restaurar sobre um índice aberto.","tags":["snapshot","restore","restore snapshot","recovery","backup"]},{"id":"cache-clear","task":"Limpar o cache","category":"Manutenção","command":"POST /customer/_cache/clear","what":"Limpa os caches de consulta, de request e de fielddata do índice.","when":"Para reduzir a pressão de memória ou resolver problemas de fielddata.","caution":"Após limpar o cache, as primeiras consultas rodam mais devagar até que ele aqueça novamente.","tags":["cache","clear","clear cache","fielddata","maintenance"]},{"id":"pending-tasks","task":"Ver as tarefas pendentes do cluster","category":"Manutenção","command":"GET /_cluster/pending_tasks","what":"Lista as tarefas de nível de cluster aguardando processamento no nó master.","when":"Para diagnosticar a carga no master quando o cluster fica lento ou as atualizações travam.","caution":"Comando somente leitura; sem risco.","tags":["pending","tasks","master","diagnostics","pending tasks"]},{"id":"hot-threads","task":"Obter uma análise de hot threads","category":"Manutenção","command":"GET /_nodes/hot_threads","what":"Mostra os stack traces das threads que mais consomem CPU nos nós.","when":"Ao diagnosticar a origem de um uso alto de CPU.","caution":"Comando somente leitura; a saída pode ser longa, restrinja com o parâmetro thread_type.","tags":["hotthreads","cpu","diagnostics","thread","performance"]},{"id":"cat-shards","task":"Ver a distribuição de shards","category":"Manutenção","command":"GET /_cat/shards?v&s=state","what":"Lista todos os shards com índice, tipo (primário/réplica), estado e o nó onde estão.","when":"Ao revisar o posicionamento de shards e shards não atribuídos.","caution":"Comando somente leitura; sem risco.","tags":["cat","shards","distribution","state","shard"]},{"id":"allocation-explain","task":"Descobrir por que um shard não está atribuído","category":"Manutenção","command":"GET /_cluster/allocation/explain\n{\n  \"index\": \"customer\",\n  \"shard\": 0,\n  \"primary\": true\n}","what":"Explica em detalhes por que um shard específico não pôde ser alocado (unassigned).","when":"Ao procurar o motivo de shards não atribuídos em um cluster yellow/red.","caution":"Comando de diagnóstico somente leitura; sem risco.","tags":["allocation","explain","unassigned","diagnostics","shard"]},{"id":"cluster-health","task":"Ver a saúde do cluster","category":"Manutenção","command":"GET /_cluster/health","what":"Mostra a saúde geral do cluster (green/yellow/red) e o número de shards ativos e não atribuídos.","when":"Ao verificar rapidamente o status do cluster.","caution":"Comando somente leitura; sem risco.","tags":["cluster","health","health check","status","green"]},{"id":"refresh-index","task":"Fazer refresh manual de um índice","category":"Ciclo de vida do índice","command":"POST /customer/_refresh","what":"Torna as mudanças pendentes no índice imediatamente pesquisáveis.","when":"Quando você quer que os dados fiquem consultáveis logo após uma carga em massa.","caution":"Refreshes manuais frequentes podem gerar muitos segmentos pequenos e degradar o desempenho.","tags":["refresh","index","search","segment","customer"]}]},"recipes/elasticsearch-ext.json":{"engineId":"elasticsearch","engine":"Elasticsearch","order":2,"recipes":[{"id":"red-yellow-triage","task":"Fluxo de triagem de cluster red/yellow (qual índice, qual shard, por quê)","category":"Cluster/Nó","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":"Dá um fluxo ordenado de triagem, do status do cluster até os índices com problema, depois aos shards não atribuídos e ao motivo de não serem alocados (unassigned.reason, allocation explain); _health_report resume qual indicador (disco, disponibilidade de shards, master) não está saudável.","when":"Como primeira resposta quando o cluster fica red ou yellow.","caution":"Red: pelo menos um shard primário não está atribuído; escritas nesse índice e buscas que atingem esse shard falham. Yellow: todos os primários estão presentes, mas faltam réplicas; os dados estão acessíveis, mas não há redundância. Em um cluster de um único nó, índices com replicas > 0 ficam yellow permanentemente (decisão same_shard). Se um nó saiu recentemente, os delayed_unassigned_shards são retidos de propósito até que index.unassigned.node_left.delayed_timeout (padrão 1m) expire.","since":"Elasticsearch 8.7","note":"_health_report surgiu no 8.7; em versões mais antigas, use os quatro primeiros passos. Valores de unassigned.reason: NODE_LEFT (o nó saiu), ALLOCATION_FAILED (limite de tentativas atingido, veja retry-failed-allocation), INDEX_CREATED, CLUSTER_RECOVERED. Para um shard específico, use a receita allocation-explain com um corpo index/shard/primary.","tags":["red","yellow","cluster health","unassigned","health report","triage"]},{"id":"retry-failed-allocation","task":"Realocar shards que atingiram o limite de tentativas (reroute retry_failed)","category":"Cluster/Nó","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":"Mostra os detalhes de falha dos shards cuja alocação foi interrompida após falhas consecutivas (ALLOCATION_FAILED, max_retry) e dispara a alocação novamente; monitora o progresso do recovery.","when":"Quando o allocation explain mostra 'shard has exceeded the maximum number of retries'; após resolver um disco cheio, um translog corrompido ou um problema de rede transitório.","caution":"Rodar retry_failed sem corrigir a causa faz o shard tentar mais 5 vezes e falhar de novo; resolva primeiro o erro em unassigned_info.details. Se muitos shards entrarem em recovery de uma vez, a carga de rede e disco sobe; isso é limitado por cluster.routing.allocation.node_concurrent_recoveries e indices.recovery.max_bytes_per_sec.","since":"Elasticsearch 7.0","note":"O limite de tentativas é index.allocation.max_retries (padrão 5). O Elasticsearch também tenta novamente de forma periódica, mas retry_failed elimina a espera. metric=none suprime o cluster state grande na resposta.","tags":["reroute","retry_failed","allocation failed","max_retries","unassigned","recovery"]},{"id":"allocate-stale-primary","task":"Alocar um shard primário perdido como último recurso (allocate_stale_primary)","category":"Cluster/Nó","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":"Quando o nó que contém a cópia primária atualizada é perdido permanentemente, atribui como primária uma cópia mais antiga (não in-sync) em outro nó para tirar o índice do estado red.","when":"Apenas quando o nó que hospeda o primário não pode ser recuperado e restaurar a partir de um snapshot não é uma opção ou levaria mais tempo.","caution":"A cópia stale não contém as escritas mais recentes; todas as escritas feitas após essa cópia são perdidas permanentemente. Se o nó perdido voltar depois, a cópia mais recente nele é apagada. Considere primeiro recuperar o nó e restaurar a partir de snapshot. allocate_empty_primary cria o shard completamente vazio e apaga todos os dados desse shard; use apenas quando não restar nenhuma cópia.","since":"Elasticsearch 7.0","note":"Na saída de _shard_stores, o tipo de alocação aparece como 'primary', 'replica' ou 'unused'; não escolha cópias com store_exception. Você pode rodar o comando com ?dry_run=true&explain=true primeiro para ver as decisões. Após a operação, feche a lacuna de dados reindexando a partir do lado da aplicação.","tags":["allocate_stale_primary","red","primary","data loss","shard_stores","reroute"],"untested":true},{"id":"disk-watermark","task":"Gerenciar os disk watermarks e remover o bloqueio de escrita do flood-stage","category":"Cluster/Nó","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":"Mostra o uso de disco por nó e os valores efetivos dos watermarks; ajusta os limites low/high/flood_stage e remove o bloqueio read_only_allow_delete aplicado aos índices no flood stage.","when":"Quando as escritas são rejeitadas com 'TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark, index has read-only-allow-delete block', novos shards não são alocados ou shards começam a sair de um nó cheio.","caution":"Acima de low, nenhum shard novo é alocado ao nó; acima de high, shards são movidos para fora do nó; acima de flood_stage, os índices com shard nesse nó ficam somente leitura. Elevar os limites só ganha tempo; a correção duradoura é apagar índices antigos, reduzir réplicas ou adicionar disco/nós. Se o disco encher completamente, shards podem ser corrompidos.","since":"Elasticsearch 8.5","note":"No 7.4+, o bloqueio é removido automaticamente quando o uso de disco cai abaixo do high watermark; a remoção manual encurta a espera. No 8.5+, discos grandes usam max_headroom (low 200GB, high 150GB, flood 100GB) como espaço livre absoluto em vez do percentual; esses headrooms padrão só se aplicam enquanto os watermarks ficam nos valores padrão, então definir percentuais explicitamente como acima os desabilita. Os watermarks também se aplicam a clusters com um único nó de dados.","tags":["disk watermark","flood_stage","read_only_allow_delete","disk full","allocation","cat allocation"]},{"id":"rolling-restart","task":"Rolling restart / rolling upgrade (nó a nó, sem movimentação desnecessária de shards)","category":"Cluster/Nó","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":"Dá a ordem para reiniciar ou fazer upgrade dos nós um de cada vez, evitando que as réplicas sejam recopiadas para outros nós enquanto um nó está fora; quando o nó volta, os shards se recuperam rapidamente a partir da cópia local.","when":"Ao reiniciar nós em sequência para um patch do SO, mudança de JVM/heap, mudança no elasticsearch.yml ou upgrade de versão minor/major.","caution":"Não passe para o próximo nó sem esperar o green; com dois nós fora ao mesmo tempo, todas as cópias de um shard podem sumir. Reinicie os nós master-eligible por último e um de cada vez; se a maioria for perdida, o cluster não consegue eleger um master. Se você esquecer de reabilitar allocation.enable, as réplicas ficam não atribuídas. Durante um upgrade, os nós de dados são atualizados primeiro (frozen/cold primeiro, hot por último), depois os masters.","since":"Elasticsearch 7.16","note":"Se houver jobs de ML, rode POST _ml/set_upgrade_mode?enabled=true no início e enabled=false no fim. O synced flush foi removido no 8.0; um _flush normal é suficiente. Use persistent, pois as configurações transient estão obsoletas desde o 7.16. Para restarts curtos, aumentar index.unassigned.node_left.delayed_timeout em vez de desabilitar a alocação também funciona.","tags":["rolling restart","rolling upgrade","allocation","primaries","maintenance","upgrade"],"untested":true},{"id":"shard-sizing","task":"Auditar o tamanho e a quantidade de shards (detecção de oversharding / shards grandes demais)","category":"Manutenção","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":"Lista os maiores shards, os tamanhos primários dos índices, a quantidade de shards por nó, o total de shards e o limite cluster.max_shards_per_node.","when":"Durante o planejamento de capacidade, quando os tempos de recovery crescem ou a pressão no heap sobe, e no erro 'this action would add [x] shards, but this cluster currently has [y]/[z] maximum normal shards open'.","caution":"Muitos shards muito pequenos (oversharding) sobrecarregam o master e o heap; shards muito grandes estendem o recovery e o rebalanceamento para horas. A quantidade de shards primários não pode mudar após a criação do índice; é preciso shrink, split ou reindex para corrigir. Aumentar max_shards_per_node remove o limite, mas não resolve o problema.","since":"Elasticsearch 8.3","note":"Orientação geral da Elastic: 10-50 GB por shard e no máximo cerca de 200 milhões de documentos. No 8.3+, a antiga regra de '20 shards por GB de heap' foi substituída por uma estimativa de heap baseada no número de campos mapeados. Para séries temporais, fixe o tamanho dos shards com max_primary_shard_size no rollover.","tags":["shard size","oversharding","cat shards","max_shards_per_node","capacity","sizing"]},{"id":"shrink-index","task":"Fazer shrink de um índice com shards demais","category":"Ciclo de vida do índice","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":"Reduz a quantidade de shards primários de um índice que não recebe mais escritas, criando hard links dos seus segmentos em um novo índice; diminui o overhead de heap e de quantidade de shards.","when":"Quando índices diários foram criados com mais shards que o necessário, o limite de shards está próximo ou antes de mover índices antigos para o warm tier.","caution":"O índice de origem fica fechado para escritas durante o shrink; aplique apenas a índices que não recebem mais escritas. A quantidade de shards de destino precisa ser um divisor da quantidade de origem (8 -> 4, 2 ou 1). O nó onde todas as cópias são reunidas precisa de tanto disco livre quanto o índice de origem. Com replicas 0, o shard de origem tem uma única cópia; não apague a origem até a operação terminar e o novo índice ficar green.","since":"Elasticsearch 7.0","note":"Após o shrink, apague a origem ou mude o alias para o novo índice. A operação costuma ser rápida porque o mesmo nó consegue criar hard links dos arquivos no mesmo file system; caso contrário, os arquivos são copiados. Use _split para aumentar a quantidade de shards e a action shrink na fase warm para automatizar com o ILM.","tags":["shrink","shard count","oversharding","index","blocks.write","warm"]},{"id":"ilm-policy-bootstrap","task":"Definir uma política ILM, anexá-la via template e iniciar a cadeia de rollover","category":"Ciclo de vida do índice","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":"Cria uma política ILM com as fases hot (rollover), warm (shrink + force merge) e delete, aplica a política e o rollover alias aos novos índices por meio de um template e cria o primeiro índice da cadeia com o write alias.","when":"Ao automatizar tamanho, retenção e exclusão de índices para dados de séries temporais, como logs ou métricas.","caution":"min_age nas fases warm e delete é contado a partir do horário do rollover, não da criação do índice. Mudanças na política se aplicam aos índices existentes só depois que a fase atual deles termina. Shrink e forcemerge na fase warm geram IO pesado; o índice não pode receber escritas até o force merge terminar. O ILM roda a cada 10 minutos por padrão, então as condições não são avaliadas instantaneamente.","since":"Elasticsearch 7.8","note":"Para projetos novos, um data stream faz o mesmo de forma mais simples: adicione \"data_stream\": {} ao index template, e não é preciso rollover alias nem índice de bootstrap. As condições de rollover são avaliadas contra estatísticas após refresh. Os composable index templates (_index_template) surgiram no 7.8; a API legada _template está obsoleta.","tags":["ilm","lifecycle","rollover","policy","index template","retention"]},{"id":"ilm-explain-retry","task":"Diagnosticar um step do ILM travado e tentar novamente (_ilm/explain, _ilm/retry)","category":"Ciclo de vida do índice","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":"Mostra os índices esperando no step ERROR, em qual phase/action/step estão travados e o motivo da falha (step_info); reexecuta o step com falha após a causa ser corrigida.","when":"Quando o rollover não acontece, índices antigos não são apagados ou o disco enche com índices que o ILM deveria ter removido.","caution":"_ilm/retry só funciona para índices no step ERROR; caso contrário, retorna 'has not encountered an error'. Causas comuns: configuração rollover_alias ausente ou o alias tem is_write_index em outro índice, disco insuficiente em um único nó para o shrink, uma regra de alocação (_tier_preference) que não pode ser satisfeita. Apagar a política não remove o gerenciamento do ILM dos índices; remova antes a configuração da política dos índices.","since":"Elasticsearch 7.0","note":"Erros com is_auto_retryable_error true são retentados pelo próprio ILM (failed_step_retry_count cresce). O intervalo de verificação do ILM é definido por indices.lifecycle.poll_interval (padrão 10m). Use POST <index>/_ilm/remove para tirar um índice do ILM.","tags":["ilm","explain","retry","error step","rollover","lifecycle"]},{"id":"index-template-component","task":"Montar um index template a partir de component templates e simular o resultado","category":"Ciclo de vida do índice","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":"Define um component template reutilizável de mapping, o compõe em um index template e mostra as configurações e o mapping finais que se aplicariam a um determinado nome de índice, sem criar o índice.","when":"Quando novos índices são criados com o mapping ou a quantidade de shards errados (explosão de dynamic mapping, text em vez de keyword), e antes de aplicar uma mudança de template.","caution":"Um template se aplica apenas a índices recém-criados; o mapping dos índices existentes não muda (veja reindex-alias-swap). Se dois templates corresponderem ao mesmo padrão, apenas o de maior priority é usado; eles não são mesclados. dynamic: strict rejeita documentos que contêm campos não definidos; se a aplicação enviar um campo novo, a indexação falha.","since":"Elasticsearch 7.8","note":"O campo overlapping na saída de _simulate_index mostra outros templates que correspondem ao mesmo padrão e são sobrepostos. Mantenha priority acima de 200 para evitar conflito com os templates built-in (logs-*-*, metrics-*-*). Os composable templates têm precedência sobre a API legada _template.","tags":["index template","component template","simulate","mapping","priority","dynamic strict"]},{"id":"reindex-alias-swap","task":"Alterar um mapping sem downtime (reindex + troca atômica de alias)","category":"Ciclo de vida do índice","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":"Cria um índice com o novo mapping, copia os dados em background com reindex, compara as contagens de documentos e muda o alias usado pela aplicação para o novo índice em uma única operação atômica.","when":"Quando o tipo de um campo existente precisa mudar (text -> keyword, integer -> long), um analyzer precisa mudar ou a quantidade de shards precisa ser redefinida; isso não pode ser feito no próprio índice existente.","caution":"A aplicação precisa se conectar ao alias, não ao nome do índice; caso contrário, a troca exige um deploy. Novas escritas na origem durante o reindex não chegam ao destino: pare as escritas ou rode o reindex novamente com op_type create + conflicts proceed logo antes da troca para fechar a lacuna (updates e deletes não são levados dessa forma). O reindex gera carga de leitura na origem e de escrita no destino; limite com requests_per_second.","since":"Elasticsearch 7.0","note":"Documentos carregados enquanto refresh_interval é -1 não aparecem nas contagens até um refresh; rode _refresh antes de comparar. Se _cat/count receber vários índices separados por vírgula, retorna o total deles; use _cat/indices para uma comparação por índice. A velocidade de um reindex em execução pode ser alterada com POST _reindex/<task_id>/_rethrottle?requests_per_second=500. wait_for_completion=false grava o resultado no índice .tasks; verifique response.failures com GET _tasks/<task_id>.","tags":["reindex","alias","mapping change","zero downtime","_aliases","no downtime"]},{"id":"tasks-cancel","task":"Encontrar, cancelar ou limitar tarefas de busca e de reindex de longa duração","category":"Manutenção","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":"Ordena por duração as tarefas em execução no cluster, mostra buscas e operações bulk com as descrições das consultas; cancela uma tarefa selecionada ou todas as buscas e limita jobs de reindex/by-query.","when":"Quando o thread pool de search enche, a CPU sobe de repente, um dashboard sobrecarrega o cluster com uma agregação pesada ou um update_by_query afeta a produção.","caution":"O cancelamento é cooperativo: a tarefa para no próximo checkpoint; algumas fases (ex.: force merge) não podem ser canceladas. Cancelar todas as buscas retorna erros aos usuários. Um reindex/by-query cancelado não desfaz as mudanças feitas até ali; o destino contém dados parciais. Quando uma tarefa pai é cancelada, as tarefas filhas também são.","since":"Elasticsearch 7.0","note":"O parâmetro detailed grava o corpo da consulta das tarefas de busca no campo description. Para proteção duradoura, use search.default_search_timeout, um timeout na requisição de busca e search.max_buckets para agregações grandes. No 7.x+, buscas cuja conexão HTTP é fechada são canceladas automaticamente.","tags":["tasks","cancel","kill query","rethrottle","long query","search"]},{"id":"search-slowlog","task":"Habilitar o slow log de busca e de indexação (limites por índice)","category":"Desempenho","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":"Para um determinado índice, grava no slow log as requisições que excedem o limite nas fases query e fetch e na indexação, junto com o corpo da consulta.","when":"Para descobrir qual consulta causa buscas lentas ou para pegar consultas pesadas de um dashboard ou cliente específico.","caution":"O limite é medido por shard: em um índice com muitos shards, cada shard pode gravar sua própria linha. Um limite muito baixo (0ms) aumenta significativamente o volume de log e o IO; desligue com null após o diagnóstico. indexing.slowlog.source grava a origem do documento no log; defina como false se contiver dados sensíveis. A configuração se aplica apenas ao índice informado; adicione-a ao template para novos índices.","since":"Elasticsearch 8.0","note":"Os arquivos de slow log são gravados no diretório logs como <cluster>_index_search_slowlog.json e <cluster>_index_indexing_slowlog.json; se o log4j2 for direcionado ao console, vão para o stdout. A configuração index.search.slowlog.level foi removida no 8.0; o nível é determinado pelos limites (warn/info/debug/trace). No 8.14+, index.search.slowlog.include.user: true também grava no log o usuário que fez a requisição. Para inspecionar uma única consulta em detalhes, adicione \"profile\": true à requisição de busca.","tags":["slowlog","slow log","slow search","search","indexing","threshold"]},{"id":"rejections-heap-breaker","task":"Diagnosticar rejeições 429, pressão no heap e nos circuit breakers","category":"Desempenho","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":"Mostra as requisições rejeitadas porque as filas dos thread pools de write/search estavam cheias, o estado de heap/CPU por nó, os disparos de circuit breaker, a contagem de old GC e o uso de memória de fielddata.","when":"Quando os clientes recebem 429 Too Many Requests ou es_rejected_execution_exception, aparece CircuitBreakingException ([parent] Data too large) ou os nós sofrem pausas longas de GC.","caution":"Os contadores rejected são cumulativos desde o início do nó; olhe o aumento entre duas amostras. Aumentar queue_size esconde as rejeições, mas aumenta o heap e a latência; a correção real é reduzir o tamanho/concorrência dos bulks ou adicionar capacidade. Se o heap fica acima de 85% e o old GC roda com frequência, o nó está se aproximando de um OOM. Habilitar fielddata em um campo text consome heap rapidamente.","since":"Elasticsearch 7.0","note":"O parent breaker tem padrão de 95% do heap (real memory circuit breaker, 7.0+). As rejeições de escrita geralmente se concentram em um único nó quente: verifique a distribuição de shards e o roteamento (_routing). Para liberar fielddata temporariamente, use POST _cache/clear?fielddata=true (veja cache-clear).","tags":["429","rejected","thread pool","circuit breaker","heap","fielddata"]},{"id":"slm-snapshot-monitor","task":"Automatizar snapshots e retenção com SLM, monitorar o progresso dos snapshots","category":"Snapshot","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":"Define uma política SLM que faz snapshots em um agendamento cron e apaga os antigos de acordo com uma regra de retenção; mostra o progresso por shard de um snapshot em execução, os snapshots anteriores e a acessibilidade do repositório.","when":"Ao configurar backups regulares, em um alerta de que o snapshot noturno falhou ou ao estimar quando um snapshot de longa duração vai terminar.","caution":"O agendamento é avaliado em UTC. Se mais de um cluster gravar no mesmo repositório, ou o repositório estiver registrado como gravável em outro cluster, ele pode ser corrompido; use readonly: true nos outros clusters. A retenção apaga apenas snapshots feitos pelo SLM. include_global_state true também pode restaurar templates e configurações persistentes do cluster durante um restore.","since":"Elasticsearch 7.5","note":"Os snapshots são incrementais: só os segmentos ausentes no snapshot anterior são copiados, então snapshots frequentes não ocupam espaço proporcional no repositório. O SLM surgiu no 7.4, a retenção no 7.5. Sem um nome de repositório, _status retorna todos os snapshots em execução no cluster; com o nome de um snapshot antigo, lê a partir do repositório e pode ser lento.","tags":["slm","snapshot","retention","backup","schedule","snapshot status"],"untested":true},{"id":"security-user-role","task":"Criar uma role e um usuário nativo, alterar a senha, emitir uma API key","category":"Segurança","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":"Cria uma role com acesso de leitura em um padrão de índices e um usuário do native realm com essa role, altera a senha, verifica a identidade de quem faz a chamada e emite uma API key com prazo e privilégios restritos.","when":"Ao criar contas de relatório, aplicação ou monitoramento com privilégio mínimo, durante a rotação de senhas e ao migrar serviços de usuários para API keys.","caution":"Não use o superusuário elastic em aplicações. Os privilégios de uma API key não podem exceder os do usuário que a criou; role_descriptors apenas os restringem. Uma API key é limitada por um snapshot point-in-time dos privilégios do seu dono na criação; mudanças posteriores de role não afetam as chaves existentes. Após uma mudança de senha, os serviços que usam a senha antiga recebem 401; planeje a transição. O valor encoded na resposta da API key é retornado apenas uma vez; guarde-o.","since":"Elasticsearch 8.0","note":"A segurança vem habilitada por padrão no 8.0+ e a senha do elastic é gerada na primeira inicialização. A ferramenta elasticsearch-reset-password surgiu no 8.0. Liste as API keys com GET _security/api_key?name=rapor-key e revogue-as com DELETE _security/api_key. O mapeamento de roles para usuários em realms LDAP/AD/SAML é feito com _security/role_mapping.","tags":["security","users","roles","api key","password","rbac"],"untested":true}]},"solver/slow-query.json":{"id":"slow-query","title":"Consulta lenta: diagnóstico aprofundado","icon":"🐢","category":"Desempenho","intro":"Uma consulta ou o sistema inteiro está lento. Restrinja passo a passo: rode uma verificação em cada nó e escolha o ramo com base no resultado. No fim, você chega a uma causa raiz + correção.","start":"scope","nodes":{"scope":{"kind":"step","title":"O que está lento?","detail":"Uma ou algumas consultas específicas estão lentas, ou o sistema inteiro? Isso divide a investigação em uma de duas trilhas: 'focada na query' ou 'focada em recursos/gargalo'.","choices":[{"label":"Uma ou algumas consultas específicas estão lentas","next":"running"},{"label":"O sistema inteiro está lento","next":"system"}]},"running":{"kind":"step","title":"A consulta está rodando agora?","detail":"É uma consulta rodando/travada agora ou uma que é 'lenta em geral'? Olhe as sessões ativas.","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":"Rodando / travada agora","next":"blocked"},{"label":"Lenta em geral; quero olhar o plano","next":"plan"}]},"blocked":{"kind":"step","title":"A consulta está esperando por algo?","detail":"Se está ativa mas não progride, muito provavelmente está esperando. blocking_session / wait_event está preenchido?","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":"Bloqueada por outra sessão","next":"sol_blocking"},{"label":"Esperando por um recurso (IO / log / latch)","next":"wait"},{"label":"Sem espera; consumindo CPU ativamente","next":"plan"}]},"wait":{"kind":"step","title":"Qual espera predomina?","detail":"O wait event predominante indica o tipo de gargalo.","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":"Espera de IO (db file read / PAGEIOLATCH)","next":"sol_io"},{"label":"Espera de log / commit (log file sync / WRITELOG)","next":"sol_log"},{"label":"Lock / enqueue (enq: TX / LCK)","next":"sol_blocking"}]},"plan":{"kind":"step","title":"Obter o plano de execução (EXPLAIN)","detail":"Obtenha o plano. Há um full table scan, uma ordem de join inesperada ou uma diferença entre linhas estimadas e reais?","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":"Full scan / índice faltante","next":"sol_index"},{"label":"Era rápida ontem; o plano mudou de repente","next":"sol_planchange"},{"label":"Processa linhas demais / N+1","next":"sol_rewrite"},{"label":"O plano parece bom, mas está lenta","next":"stats"}]},"stats":{"kind":"step","title":"As estatísticas estão atualizadas?","detail":"Uma grande diferença entre linhas estimadas e reais (E-rows vs A-rows) é sinal de estatísticas desatualizadas.","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":"As estatísticas estão desatualizadas / antigas","next":"sol_stats"},{"label":"As estatísticas estão atualizadas, mas continua lenta","next":"sol_deep"}]},"system":{"kind":"step","title":"No sistema inteiro: onde está o gargalo?","detail":"Se tudo está lento, e não uma única consulta, procure um gargalo de recurso: CPU, IO, memória ou bloqueio generalizado?","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 perto de 100%","next":"sol_cpu"},{"label":"Espera de IO alta","next":"sol_io"},{"label":"Pressão de memória / cache hit baixo","next":"sol_mem"},{"label":"Muito bloqueio","next":"sol_blocking"}]},"sol_blocking":{"kind":"solution","title":"Causa raiz: bloqueio","detail":"A consulta está esperando por um lock mantido por outra sessão. Encontre a sessão no início da cadeia (root blocker) e resolva-a.","steps":["Encontre o início da cadeia de bloqueio (a sessão que não está esperando, mas faz as outras esperarem).","Entenda o que o root blocker está fazendo: uma transação longa sem commit ou 'idle in transaction'?","Se a aplicação puder fazer commit/rollback, acione isso; se não puder e o trabalho estiver parado, encerre o root blocker.","Corrija a causa raiz: um índice faltante pode estar causando bloqueio amplo; encurte as transações e revise o nível de isolamento."],"related":["blocking-sessions","kill-session"],"playbook":"blocking"},"sol_io":{"kind":"solution","title":"Causa raiz: gargalo de IO","detail":"A consulta lê muito do disco. Geralmente por causa de full scans (índice faltante) ou memória insuficiente (buffer cache).","steps":["Adicione um índice adequado para o filtro que causa o full scan (o plano deve passar para um index scan, IXSCAN).","Verifique a taxa de acerto do buffer cache / buffer pool; aumente a memória se estiver baixa.","Reduza leituras desnecessárias de colunas/linhas (as colunas necessárias em vez de SELECT *, paginação).","Se o storage for realmente lento (latência de IO alta), melhore a camada de disco."],"related":["cache-hit-ratio","create-index"]},"sol_log":{"kind":"solution","title":"Causa raiz: gargalo de commit / log","detail":"Se 'log file sync' / 'WRITELOG' predomina, os commits estão esperando as escritas de redo/WAL.","steps":["Transforme commits frequentes de linha única em commits em lote; reduza commits desnecessários.","Acelere o disco de redo/WAL (disco separado e rápido); revise o tamanho/quantidade dos arquivos de log.","Avalie as configurações synchronous_commit / commit_write considerando a carga e o trade-off de durabilidade."],"related":["show-config-param"]},"sol_index":{"kind":"solution","title":"Causa raiz: índice faltante","detail":"O plano faz um full scan. Um índice adequado nas colunas de filtro/join dá um grande ganho de velocidade.","steps":["Adicione online um índice adequado (composto, se necessário) nas colunas do WHERE/JOIN.","Após adicionar o índice, obtenha o plano novamente e verifique se ele passou para um index scan (IXSCAN).","Se a carga de escrita for pesada, pondere o custo do índice; remova índices desnecessários.","Um índice não ajuda em colunas com baixa seletividade; verifique a seletividade."],"related":["create-index","explain-plan"]},"sol_planchange":{"kind":"solution","title":"Causa raiz: regressão de plano","detail":"A consulta era rápida ontem, mas hoje não; o plano mudou. Geralmente por estatísticas desatualizadas ou mudança de parâmetro.","steps":["Primeiro colete estatísticas novas (estatísticas desatualizadas são a causa mais comum).","Fixe o plano bom: Oracle SQL Plan Baseline / hint, MSSQL Query Store 'force plan', configurações do PG.","Se houve um upgrade/patch/mudança de parâmetro recente, revise-o (comportamento do otimizador)."],"related":["update-statistics"]},"sol_rewrite":{"kind":"solution","title":"Causa raiz: design da consulta","detail":"O plano é razoável, mas a consulta em si faz trabalho demais (linhas demais, N+1, joins desnecessários).","steps":["Reduza o conjunto de resultados: paginação (LIMIT/OFFSET ou keyset), filtragem antecipada.","Transforme o padrão N+1 em uma única consulta em lote; simplifique joins/subqueries desnecessários.","Considere uma materialized view / tabela de resumo para relatórios pesados recorrentes."],"related":["explain-plan","materialized-view"]},"sol_stats":{"kind":"solution","title":"Causa raiz: estatísticas desatualizadas","detail":"O otimizador erra as estimativas porque as estatísticas não estão atualizadas.","steps":["Colete estatísticas manualmente para a(s) tabela(s) afetada(s).","Verifique se o job de coleta automática (autovacuum/auto stats/gather job) está rodando.","Adicione a coleta de estatísticas ao fluxo de trabalho após grandes cargas de dados repentinas."],"related":["update-statistics"]},"sol_deep":{"kind":"solution","title":"Análise aprofundada","detail":"Se o plano e as estatísticas estão bons, mas continua lento, aprofunde.","steps":["Habilite um trace no nível da sessão: Oracle 10046, PG auto_explain, MySQL profiling, MSSQL Extended Events.","Examine paralelismo, memory grants e spills de sort/hash (tempdb/temp).","Descarte a camada de hardware/SO (CPU steal, latência de IO, rede).","Avalie a contenção causada pelo número de conexões e pela concorrência."],"related":["session-trace","top-wait-events"]},"sol_cpu":{"kind":"solution","title":"Causa raiz: gargalo de CPU","detail":"O sistema inteiro está limitado por CPU. Geralmente algumas consultas mal planejadas estão consumindo a CPU.","steps":["Encontre as 10 consultas que mais consomem CPU e corrija seus planos (índices/estatísticas).","Limite as consultas descontroladas (Resource Manager / Resource Governor).","Se a utilização continuar alta, escale (adicione CPU, distribua as leituras para réplicas de leitura)."],"related":["top-slow-queries"],"playbook":"high-cpu"},"sol_mem":{"kind":"solution","title":"Causa raiz: pressão de memória","detail":"Cache hit baixo e/ou swap: a memória é insuficiente ou está mal alocada.","steps":["Dimensione corretamente o buffer pool / SGA e a memória de sessão (work_mem/PGA) (Ferramentas > Calculadora de memória).","Encontre e corrija a consulta descontrolada que consome memória.","Se o sistema estiver fazendo swap, sair do swap é a prioridade; adicione RAM se necessário."],"related":["cache-hit-ratio","show-config-param"],"playbook":"memory-pressure"}}},"solver/deadlock.json":{"id":"deadlock","title":"Deadlock / conflito de lock (ORA-00060, 1213, 40P01)","icon":"♻️","category":"Locks","intro":"Você encontrou um deadlock (Oracle ORA-00060, MySQL 1213, PG 40P01, MSSQL 1205). Capture o grafo, descubra o padrão, evite a recorrência. Deadlocks se resolvem pelo design — o objetivo é reduzir sua frequência.","start":"capture","nodes":{"capture":{"kind":"step","title":"Primeiro capture o deadlock graph","detail":"Quais duas (ou mais) sessões, quais recursos, quais modos de lock colidiram? Não aplique correções às cegas sem ver isso.","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":"Tenho o grafo — duas transações bloqueiam recursos em ordem inversa","next":"sol_order"},{"label":"Muitas transações se acumulam em uma única linha/tabela (hotspot)","next":"sol_hotspot"},{"label":"Há locks de intervalo amplos (muitas linhas ficam bloqueadas)","next":"index_check"}]},"index_check":{"kind":"step","title":"A consulta que bloqueia usa um índice?","detail":"Sem índice, um UPDATE/DELETE bloqueia muitas linhas (até a tabela inteira) para satisfazer a cláusula WHERE → uma fonte de deadlocks. Verifique o plano.","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":"Sem índice / faz full scan","next":"sol_index"},{"label":"Há um índice, mas ainda há conflito","next":"sol_order"}]},"sol_order":{"kind":"solution","title":"Causa raiz: ordem de lock inversa","detail":"A causa mais comum de deadlock: duas transações acessam recursos em ordens diferentes. Quando A→B e B→A acontecem ao mesmo tempo, ocorre o deadlock.","steps":["Acesse os recursos na MESMA ordem em todos os caminhos de código (ex.: sempre do menor id → para o maior id).","Mantenha as transações curtas; tire a interação do usuário/trabalho longo de dentro da transação.","Se necessário, obtenha os locks cedo, em uma ordem determinística (SELECT ... FOR UPDATE ordenado).","Adicione retry automático (retry + backoff) para a vítima do deadlock na aplicação — isso é obrigatório."],"related":["blocking-sessions","open-transactions"]},"sol_index":{"kind":"solution","title":"Causa raiz: índice faltante → locks amplos","detail":"Um UPDATE/DELETE sem índice bloqueia mais linhas que o necessário e torna os deadlocks muito mais prováveis.","steps":["Adicione um índice na coluna da cláusula WHERE; o lock passa a se limitar às linhas afetadas.","Obtenha o plano novamente e verifique se o full scan (Seq Scan / type=ALL) virou acesso por índice.","Rode updates em massa em lotes pequenos (chunks)."],"related":["create-index","list-indexes"]},"sol_hotspot":{"kind":"solution","title":"Causa raiz: hotspot","detail":"Muitas transações se acumulam ao mesmo tempo em um único recurso, como uma linha/chave de contador.","steps":["Espalhe a linha quente: use uma sequence/identity, divida os contadores (sharded counter).","Encurte a duração das transações para que o lock fique retido por menos tempo.","Se possível, use optimistic locking (version/timestamp) ou um padrão de fila."],"related":["sequence","open-transactions"]}}},"solver/disk-full.json":{"id":"disk-full","title":"Disco / tablespace cheio","icon":"💽","category":"Capacidade","intro":"Você recebeu 'unable to extend', 'disk full', 'could not extend' ou 'log full'. Sem pânico: primeiro descubra O QUE está cheio, recupere espaço com segurança e depois corrija de forma definitiva.","start":"what","nodes":{"what":{"kind":"step","title":"O que está cheio?","detail":"Limpar o lugar errado não ajuda. Meça o uso primeiro: é um datafile, o transaction log, archive/redo, temp ou o disco do SO?","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":"O datafile / tablespace está cheio","next":"data"},{"label":"O transaction log / archive-redo está cheio","next":"log"},{"label":"O temp / undo está cheio","next":"sol_temp"},{"label":"O disco do SO está cheio (não o banco)","next":"sol_os"}]},"data":{"kind":"step","title":"Qual é o maior consumidor?","detail":"Na maioria das vezes, uma única tabela/segmento descontrolado é o culpado. Encontre os maiores.","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":"Há uma tabela inesperadamente grande/descontrolada","next":"sol_runaway"},{"label":"Crescimento normal, o espaço realmente acabou","next":"sol_extend"},{"label":"Linhas mortas demais / bloat","next":"sol_reclaim"}]},"log":{"kind":"step","title":"Por que o log está crescendo?","detail":"O log/archive não pode ser limpo até que a transação/backup ativo mais antigo termine. Por que ele se acumulou?","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: não estão sendo feitos backups de log (LOG_BACKUP)","next":"sol_logbackup"},{"label":"PG: um replication slot parado está retendo WAL","next":"sol_slot"},{"label":"Oracle: a área de archived logs (FRA) está cheia","next":"sol_archive"},{"label":"Uma transação longa aberta está segurando o log","next":"sol_longtxn"}]},"sol_runaway":{"kind":"solution","title":"Causa raiz: tabela/segmento descontrolado","detail":"Um único objeto cresceu inesperadamente (inserts sem controle, uma tabela de fila/log que nunca é expurgada).","steps":["Verifique se o objeto é realmente necessário; se for uma tabela de log/fila, aplique retenção.","Expurgue dados antigos desnecessários com drop de partição / TRUNCATE (após backup/aprovação).","Interrompa o crescimento descontrolado na aplicação; configure um alerta de crescimento."],"related":["largest-tables","create-partition"]},"sol_extend":{"kind":"solution","title":"Causa raiz: necessidade real de capacidade","detail":"Crescimento normal; é preciso adicionar espaço.","steps":["Adicione espaço ao datafile ou habilite o AUTOEXTEND (Oracle: ALTER DATABASE DATAFILE ... AUTOEXTEND ON MAXSIZE).","Se necessário, adicione um novo datafile/tablespace ou aumente o disco.","Configure alertas de uso em 80%/90% para não haver mais surpresas."],"related":["free-space"]},"sol_reclaim":{"kind":"solution","title":"Causa raiz: bloat / linhas mortas","detail":"O espaço das linhas apagadas/atualizadas não foi recuperado.","steps":["Recupere o espaço: PG VACUUM (pg_repack se necessário), Oracle SHRINK SPACE, MySQL OPTIMIZE TABLE, Mongo compact.","Torne mais agressivas as configurações do autovacuum/manutenção automática.","VACUUM FULL / OPTIMIZE bloqueiam a tabela — rode-os fora dos horários de pico."],"related":["reclaim-space","free-space"]},"sol_temp":{"kind":"solution","title":"Causa raiz: temp / undo cheio","detail":"Um sort/hash grande ou uma transação longa aberta encheu o espaço temporário.","steps":["Encontre a consulta que estourou o temp (spill grande de sort/hash) e otimize-a.","Encontre a transação longa aberta; é ela que está segurando o undo (Oracle).","Se necessário, aumente o espaço de temp/undo; revise a configuração de retenção."],"related":["open-transactions","reclaim-space"]},"sol_os":{"kind":"solution","title":"Causa raiz: disco do SO cheio","detail":"O problema está no disco do sistema operacional, não no banco. Logs, core dumps, backups antigos ou arquivos de trace podem estar ocupando espaço.","steps":["Encontre o filesystem cheio com df -h; procure os maiores diretórios (du -sh *).","Limpe arquivos antigos de log/trace/core dump/backup (com aprovação).","Coloque os diretórios de diagnóstico do banco (Oracle ADR, logs do PG) sob rotação."]},"sol_logbackup":{"kind":"solution","title":"Causa raiz: backups de log não estão sendo feitos (SQL Server)","detail":"No recovery model FULL, o log cresce indefinidamente se não forem feitos backups de log.","steps":["Faça um backup de log (BACKUP LOG) — isso torna o log reutilizável.","Se o recovery model realmente deveria ser SIMPLE, altere-o.","Faça shrink do arquivo de log apenas se necessário (DBCC SHRINKFILE) e configure um job regular de backup de log."],"related":["last-backup-status"],"playbook":"log-growth"},"sol_slot":{"kind":"solution","title":"Causa raiz: replication slot abandonado (PG)","detail":"Um slot parado (inativo) impede que o WAL seja removido e incha o pg_wal.","steps":["Verifique se o slot está realmente em uso.","Se não for necessário, remova-o: SELECT pg_drop_replication_slot('slot_name');","Corrija a réplica ativa para que o slot avance; configure um alerta de lag do slot."],"related":["free-space"],"playbook":"log-growth"},"sol_archive":{"kind":"solution","title":"Causa raiz: área de archived logs (FRA) cheia (Oracle)","detail":"Os archived logs se acumularam e a FRA está cheia; quando o archiver para, o banco pode deixar de aceitar escritas.","steps":["Apague com o RMAN os archived logs antigos que já tenham backup (NUNCA os apague sem backup).","Aumente o tamanho da FRA (db_recovery_file_dest_size) se necessário.","Configure o job de limpeza/backup dos archived logs para rodar regularmente."],"related":["last-backup-status"]},"sol_longtxn":{"kind":"solution","title":"Causa raiz: transação longa aberta","detail":"A transação ativa mais antiga está impedindo que o log/undo seja recuperado.","steps":["Encontre a transação aberta mais antiga e faça com que receba commit/rollback (ou fale com o responsável).","Corrija o comportamento da aplicação que deixa sessões 'idle in transaction'; defina um timeout.","Mova relatórios longos para uma réplica/janela separada."],"related":["open-transactions"],"playbook":"log-growth"}}},"solver/connection-storm.json":{"id":"connection-storm","title":"Connection storm (conexões demais)","icon":"🌊","category":"Capacidade","intro":"Você recebeu 'too many connections', 'remaining connection slots reserved' ou ORA-00018; novas conexões estão sendo rejeitadas. Encontre a origem, alivie a pressão agora e corrija de vez.","start":"measure","nodes":{"measure":{"kind":"step","title":"Meça a situação: quantas conexões, e quantas estão ativas?","detail":"Primeiro olhe o total de conexões, o limite e a divisão entre ativas/ociosas.","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":"A maioria das conexões está idle / idle in transaction","next":"sol_idle"},{"label":"A maioria está ativa; preciso encontrar a origem","next":"who"}]},"who":{"kind":"step","title":"Quem/de onde? Agrupe as conexões por origem","detail":"Geralmente o pool de um único servidor de aplicação estourou ou há um vazamento de conexões. Olhe a distribuição por host/usuário/aplicação.","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":"Uma única aplicação/host estourou as conexões (pool)","next":"sol_pool"},{"label":"A carga realmente aumentou; todas são legítimas e ativas","next":"sol_scale"}]},"sol_idle":{"kind":"solution","title":"Causa raiz: acúmulo de conexões ociosas / vazamento","detail":"As conexões são abertas e nunca fechadas, ou ficam 'idle in transaction'; elas ocupam slots à toa.","steps":["Limpe as conexões idle / idle-in-transaction longas; use o slot reservado para admins.","Defina timeouts no lado do servidor: PG idle_in_transaction_session_timeout, MySQL wait_timeout, Oracle profile idle_time.","Garanta que a aplicação feche as conexões (e as transações); corrija o vazamento na origem."],"related":["open-transactions","kill-session","connection-count"],"playbook":"connection-storm"},"sol_pool":{"kind":"solution","title":"Causa raiz: o pool da aplicação estourou","detail":"O pool de conexões de um servidor de aplicação está ilimitado/grande demais ou vazando. É ele que está gerando as conexões.","steps":["Imediato: encerre as conexões ociosas da aplicação responsável e reinicie o pool dela.","Defina um tamanho de pool razoável no lado da aplicação (Ferramentas > Calculadora de Connection Pool).","Coloque um pooler entre o servidor e o banco (PgBouncer / ProxySQL / Oracle DRCP / Connection Manager (CMAN)).","Não aumente o max_connections às cegas; isso consome memória e só adia o problema."],"related":["connection-count","kill-session"],"playbook":"connection-storm"},"sol_scale":{"kind":"solution","title":"Causa raiz: aumento real de carga","detail":"As conexões são legítimas e ativas; a capacidade realmente é insuficiente.","steps":["Reduza o número de conexões que chegam ao banco multiplexando-as por meio de um pooler de conexões.","Distribua a carga de leitura entre réplicas de leitura.","Se necessário, aumente o max_connections de forma controlada de acordo com o orçamento de memória; escale também a memória do servidor."],"related":["connection-count"],"playbook":"connection-storm"}}},"solver/replication-lag.json":{"id":"replication-lag","title":"Lag de replicação / replicação parada","icon":"🔁","category":"Replicação","intro":"O standby/réplica está ficando para trás do primário, ou a replicação parou completamente. Esta árvore restringe passo a passo o tipo de lag (crescente, constante ou parado) para chegar à causa raiz, como um erro de apply, um gargalo de thread única, um recovery conflict ou corrupção.","start":"root","nodes":{"root":{"kind":"step","title":"Como o lag está se comportando?","detail":"Meça a situação primeiro. Olhe o fluxo da réplica e a métrica de lag: o lag está crescendo com o tempo, preso em um nível constante, ou o apply parou completamente? Isso divide a investigação em três ramos principais.","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":"O apply parou completamente / há um erro","next":"stopped"},{"label":"O lag continua crescendo (não consegue alcançar)","next":"growing"},{"label":"O lag é constante, mas há suspeita de uma consulta longa","next":"standby_query"},{"label":"Muito atrasado / parece inconsistente","next":"sol_rebuild"}]},"stopped":{"kind":"step","title":"O que diz o erro de apply?","detail":"Se a replicação parou, geralmente há um erro em um evento sendo aplicado. Olhe a mensagem de erro: é uma linha/tabela ausente no destino, um conflito de primary key ou uma queda de conexão/rede?","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":"Erro de linha ou tabela em conflito/ausente","next":"sol_apply_error"},{"label":"Rede/conexão caiu, IO thread parada","next":"sol_connection"}]},"growing":{"kind":"step","title":"Por que não consegue alcançar?","detail":"Se o lag continua crescendo, a réplica não acompanha a taxa de escrita do primário. O gargalo é o apply em thread única ou o disco/IO da réplica está lento? Olhe o estado do worker de apply e as esperas de 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":"Apply em thread única + carga de escrita pesada","next":"sol_parallel"},{"label":"O disco/IO da réplica está lento","next":"sol_io"}]},"standby_query":{"kind":"step","title":"Há uma consulta longa no standby?","detail":"Uma consulta longa rodando em um standby somente leitura pode bloquear o apply (recovery). No PostgreSQL, é assim que surge um recovery conflict. Olhe as consultas ativas e os contadores de conflito no standby.","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":"Sim, uma consulta longa está bloqueando o apply","next":"sol_recovery_conflict"},{"label":"Não, não há consulta, mas continua atrasado","next":"sol_parallel"}]},"sol_apply_error":{"kind":"solution","title":"Causa raiz: erro de apply (conflito de dados)","detail":"A réplica está presa em um evento que não consegue aplicar: uma linha ausente no destino, um conflito de primary key ou uma tabela ausente. Corrija a causa da inconsistência em vez de pular às cegas.","steps":["Examine o erro e o evento travado: qual tabela e qual operação (delete/update/insert) falhou?","Encontre a causa raiz: dados gravados manualmente no destino, DDL ausente (tabela/coluna) ou uma entrada de binlog/WAL corrompida.","Alinhe o schema: adicione a tabela/coluna ausente; compare a linha em conflito com o primário e corrija-a.","Se precisar pular o evento (ex.: um único evento no MySQL), documente e depois verifique a consistência dos dados da réplica.","Evite a recorrência: desabilite escritas diretas no destino e rode o DDL pelo primário."],"related":["replication-status"],"playbook":"replication-lag"},"sol_connection":{"kind":"solution","title":"Causa raiz: queda de conexão / rede","detail":"A thread receptora (IO/receiver) não consegue se conectar ao primário. A rede, a autenticação ou segmentos de log acumulados/expurgados podem ser o problema.","steps":["Verifique o acesso de rede entre primário e réplica e os privilégios do usuário de replicação.","Verifique se os segmentos de WAL/binlog necessários ainda existem no primário (retenção/expire).","No PostgreSQL, verifique se o replication slot existe e está ativo; sem um slot, o WAL pode ter sido removido cedo.","Reinicie a conexão; quando os logs voltarem a fluir, o lag deve se fechar."],"related":["replication-status","list-replicas"],"playbook":"replication-lag"},"sol_parallel":{"kind":"solution","title":"Causa raiz: gargalo de apply em thread única","detail":"Enquanto o primário grava em paralelo, a réplica aplica as mudanças em uma única sequência e não acompanha. Paralelize o apply.","steps":["Habilite o apply paralelo: no MySQL, replica_parallel_workers + replica_parallel_type=LOGICAL_CLOCK.","Na replicação física do PostgreSQL, o apply é um único processo; reduza a taxa de geração no primário dividindo transações grandes.","Mova jobs em lote pesados para horários de pouco tráfego ou divida-os.","Monitore a métrica de lag após a mudança; ela deve diminuir até zero."],"related":["replication-status"],"playbook":"replication-lag"},"sol_io":{"kind":"solution","title":"Causa raiz: gargalo de IO na réplica","detail":"A thread de apply está esperando o disco, não a CPU. O storage da réplica não acompanha a taxa de escrita do primário.","steps":["Meça a latência/saturação de IO do disco da réplica; compare com o primário.","Se o hardware da réplica for mais fraco (disco lento, menos RAM), iguale-o ao do primário; hardware assimétrico é uma causa comum.","Acelere o disco para o apply de redo/WAL; dimensione o buffer/cache adequadamente.","Se não melhorar, reduza a carga de escrita ou distribua o tráfego de leitura para outra réplica."],"related":["replication-status"],"playbook":"replication-lag"},"sol_recovery_conflict":{"kind":"solution","title":"Causa raiz: recovery conflict no standby","detail":"Uma consulta longa somente leitura no standby está bloqueando a aplicação das mudanças vindas do primário (conflito de vacuum/lock). O PostgreSQL resolve isso atrasando o apply ou cancelando a consulta.","steps":["Encontre a consulta longa que bloqueia; se for realmente necessária, espere que termine, caso contrário encerre-a.","Com hot_standby_feedback=on, faça o primário respeitar as consultas do standby (ao custo de bloat no primário).","Como alternativa, ajuste max_standby_streaming_delay à carga (equilíbrio entre tolerância ao lag e cancelamento de consultas).","Mova relatórios longos para uma réplica separada onde não bloqueiem o apply, ou para outro horário."],"related":["replication-status","open-transactions"],"playbook":"replication-lag"},"sol_rebuild":{"kind":"solution","title":"Causa raiz: réplica atrasada demais / corrompida - reconstrua-a","detail":"A réplica está atrasada demais para se recuperar, os logs necessários foram removidos ou os dados estão inconsistentes. O caminho mais seguro é reconstruí-la a partir de um backup novo.","steps":["Faça um base backup atual do primário: PG pg_basebackup, MySQL clone/xtrabackup, Oracle RMAN duplicate.","Restaure o backup na réplica e restabeleça a configuração de replicação (slot/usuário/posição).","Inicie a replicação e monitore o progresso da sincronização inicial (catch-up).","Depois que o lag chegar a zero, verifique a consistência dos dados e o tráfego de leitura e então coloque-a em serviço."],"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":"O erro 'ORA-01555: snapshot too old' do Oracle indica que os dados antigos (undo) de que uma consulta precisa para uma leitura consistente já foram sobrescritos. Esta árvore restringe a origem do erro (consulta longa + UNDO insuficiente, alta rotatividade de undo ou LOB) e leva você à correção certa.","start":"root","nodes":{"root":{"kind":"step","title":"Onde o erro ocorre?","detail":"Primeiro determine o contexto do erro. O ORA-01555 clássico ocorre durante um SELECT/relatório de longa duração ou ao acessar uma coluna LOB (CLOB/BLOB)? O ORA-01555 relacionado a LOB é um mecanismo diferente (PCTVERSION/RETENTION) e é resolvido separadamente.","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":"Durante uma consulta/relatório de longa duração","next":"undo_size"},{"label":"Ao acessar uma coluna LOB","next":"sol_lob"}]},"undo_size":{"kind":"step","title":"O UNDO é suficiente, a retenção é adequada?","detail":"Uma consulta longa lê do UNDO a imagem antiga dos blocos alterados desde que ela começou. Se o UNDO tablespace for pequeno ou undo_retention for menor que a duração da consulta, o undo antigo é sobrescrito. Meça o uso do UNDO e a retenção.","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":"O UNDO é pequeno / retenção menor que a consulta","next":"sol_undo"},{"label":"O UNDO é suficiente, mas os commits são muito frequentes","next":"sol_commits"},{"label":"A consulta roda por tempo excessivo","next":"sol_query"}]},"sol_undo":{"kind":"solution","title":"Causa raiz: UNDO / retenção insuficiente","detail":"O undo antigo necessário para a consulta longa foi sobrescrito porque o período de retenção expirou ou o tablespace encheu. Aumente o UNDO e defina a retenção para cobrir a duração da consulta.","steps":["Com base na duração da consulta mais longa (v$undostat.maxquerylen), eleve undo_retention acima dela: ALTER SYSTEM SET undo_retention=10800;","Aumente o UNDO tablespace o suficiente para acomodar a retenção ou habilite o autoextend: ALTER DATABASE DATAFILE '...' AUTOEXTEND ON MAXSIZE ...;","Garanta para consultas longas críticas: ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;  (cuidado: se o UNDO encher, o DML pode falhar).","Após a mudança, rode o mesmo relatório novamente e confirme que o ORA-01555 sumiu."],"related":["show-config-param"],"playbook":"ora-01555"},"sol_commits":{"kind":"solution","title":"Causa raiz: alta rotatividade de undo (commits frequentes)","detail":"DML pesado com commits muito frequentes recicla os blocos de undo rapidamente e apaga a imagem antiga de que a consulta longa precisa. O efeito 'commit cleanout' piora isso.","steps":["Reduza commits desnecessariamente frequentes: use commits em lote em vez de fazer commit de cada linha dentro de um loop.","Para desacelerar a rotatividade do undo, não agende cargas pesadas de DML ao mesmo tempo que o relatório longo.","Aumente undo_retention e, se necessário, proteja o undo antigo com RETENTION GUARANTEE.","Mova o relatório para fora da janela de escrita pesada ou fixe-o em um ponto de leitura consistente."],"related":["open-transactions","show-config-param"],"playbook":"ora-01555"},"sol_query":{"kind":"solution","title":"Causa raiz: duração excessiva da consulta","detail":"A consulta roda por tanto tempo que nem um undo_retention razoável é suficiente. A correção definitiva é acelerar a consulta ou descarregar sua carga.","steps":["Otimize a consulta: corrija índices faltantes, planos ruins ou full scans desnecessários; encurte sua duração.","Divida o job grande (por data/intervalo) para que cada parte caiba dentro da janela de undo.","Mova o relatório pesado para um standby/réplica ou para um horário de leitura separado — para que não colida com o DML ativo.","Quando a duração for aceitável, defina undo_retention de acordo."],"related":["explain-plan"],"playbook":"ora-01555"},"sol_lob":{"kind":"solution","title":"Causa raiz: retenção de LOB / PCTVERSION","detail":"O ORA-01555 ao ler um LOB indica que o espaço que guarda as versões antigas do LOB (RETENTION ou PCTVERSION) é insuficiente. Os LOBs têm um mecanismo de versionamento separado.","steps":["Veja a configuração atual da coluna LOB: SELECT retention, pctversion FROM dba_lobs WHERE table_name='...' AND column_name='...';","Eleve a configuração adequada conforme o modo de undo AUTO/MANUAL: ALTER TABLE t MODIFY LOB (my_column) (RETENTION);  ou aumente PCTVERSION no modo MANUAL.","Os LOBs que usam RETENTION se baseiam no valor de undo_retention do banco — mantenha-o suficiente também.","Encurte as operações longas que acessam o LOB; teste o erro novamente após a mudança."],"related":["show-config-param"],"playbook":"ora-01555"}}},"solver/backup-restore.json":{"id":"backup-restore","title":"Decisão de backup e restore","icon":"💾","category":"Backup e recuperação","intro":"Uma árvore de decisão que guia você passo a passo pelo que precisa fazer com backups (fazer um backup, restaurar, voltar a um ponto específico no tempo - PITR, ou verificar um backup) e leva aos comandos e passos certos para cada banco de dados.","start":"root","nodes":{"root":{"kind":"step","title":"O que você quer fazer?","detail":"Escolha seu objetivo. Você vai fazer um novo backup, restaurar um backup existente, voltar a um horário específico (logo antes de uma falha) ou verificar se o backup que você tem está íntegro?","choices":[{"label":"Quero FAZER um backup","next":"take"},{"label":"Quero RESTAURAR um backup","next":"restore"},{"label":"Voltar a um ponto específico no tempo (PITR)","next":"pitr"},{"label":"Quero VERIFICAR um backup","next":"verify"}]},"take":{"kind":"step","title":"Qual tipo de backup?","detail":"Um backup lógico (dump) é portável e serve para restores seletivos, mas é lento para grandes volumes de dados. Um backup físico (nível de arquivo/bloco) serve para bancos grandes e recuperação rápida. Escolha de acordo com sua necessidade.","choices":[{"label":"Backup lógico (dump / export)","next":"sol_logical_backup"},{"label":"Backup físico / completo","next":"sol_physical_backup"}]},"sol_logical_backup":{"kind":"solution","title":"Fazendo um backup lógico (dump)","detail":"Exporta os dados como statements SQL/BSON. Ideal para mover entre versões/plataformas e restaurar uma única tabela/collection.","steps":["PostgreSQL: pg_dump -Fc -d mydb -f backup.dump  (pg_dumpall para o cluster inteiro).","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: faça um snapshot RDB em background com BGSAVE (dump.rdb).","Elasticsearch: primeiro registre um repositório de snapshots, depois PUT _snapshot/my_repo/snap1?wait_for_completion=true","Mova o backup para um local seguro e registre seu tamanho/status de conclusão."],"related":["logical-dump","last-backup-status"],"playbook":"backup-restore"},"sol_physical_backup":{"kind":"solution","title":"Fazendo um backup físico / completo","detail":"Uma cópia dos datafiles em nível de bloco/arquivo. Rápida para bancos grandes e a base para PITR e recuperação completa.","steps":["Oracle: RMAN> BACKUP DATABASE PLUS ARCHIVELOG;  (junto com os archived logs).","PostgreSQL: pg_basebackup -D /backup/base -Fp -Xs -P  (com o arquivamento de WAL habilitado).","SQL Server: BACKUP DATABASE [mydb] TO DISK='D:\\backup\\db.bak' WITH CHECKSUM, COMPRESSION;","MySQL/MariaDB: xtrabackup --backup --target-dir=/backup/base  (cópia física consistente).","MongoDB: faça um snapshot de file system ou um snapshot consistente a partir de um membro do replica set.","Copie o backup para um local offline/remoto e registre o status do último backup."],"related":["last-backup-status"],"playbook":"backup-restore"},"restore":{"kind":"solution","title":"Restaurando um backup","detail":"Restaure no destino o backup mais adequado que você tem. Primeiro verifique a integridade e o timestamp do backup, depois carregue-o com o comando apropriado ao engine.","steps":["Verifique a data e a integridade do backup a ser restaurado (conheça sua janela de perda de dados).","PostgreSQL: pg_restore -d new_db backup.dump   (para um dump SQL: psql -d new_db -f backup.sql).","Oracle: RMAN> RESTORE DATABASE; RECOVER DATABASE; ALTER DATABASE OPEN;  (import lógico com impdp).","MySQL/MariaDB: mysql mydb < backup.sql   (físico: xtrabackup --copy-back).","SQL Server: RESTORE DATABASE [mydb] FROM DISK='D:\\backup\\db.bak' WITH RECOVERY, REPLACE;","MongoDB: mongorestore --db mydb /backup/dir","Após o restore, valide os dados com contagens de linhas/verificações da aplicação."],"related":["restore-dump","last-backup-status"],"playbook":"backup-restore"},"pitr":{"kind":"solution","title":"Voltando a um ponto específico no tempo (PITR)","detail":"Você quer voltar, com precisão de segundos, para logo antes de um delete acidental/corrupção. Você precisa de um backup completo + os logs de transação até aquele ponto (archived logs / WAL / binlog).","steps":["Determine o horário-alvo com precisão (logo antes do incidente) e verifique se os logs necessários estão disponíveis.","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: restaure o base backup, depois defina recovery_target_time='2026-07-04 10:00:00' e aplique o WAL até aquele ponto.","SQL Server: RESTORE ... WITH NORECOVERY; depois RESTORE LOG ... WITH STOPAT='2026-07-04 10:00:00', RECOVERY;","MySQL/MariaDB: restaure o backup completo, depois aplique o binlog até aquele ponto com mysqlbinlog --stop-datetime='2026-07-04 10:00:00'.","Após abrir, verifique se os dados estão no ponto no tempo esperado."],"related":["restore-dump","last-backup-status"],"playbook":"backup-restore"},"verify":{"kind":"solution","title":"Verificando um backup","detail":"Um backup só é um backup depois que se comprova que pode ser restaurado. Teste regularmente a integridade e a capacidade real de restauração.","steps":["Oracle: RMAN> RESTORE DATABASE VALIDATE;  e, para consistência de blocos, VALIDATE CHECK LOGICAL DATABASE;","SQL Server: faça os backups WITH CHECKSUM e rode RESTORE VERIFYONLY ... WITH CHECKSUM (verifica apenas o arquivo de backup); para uma prova real, restaure o backup em um servidor de teste e rode DBCC CHECKDB([mydb]) WITH NO_INFOMSGS; nele (o CHECKDB verifica um banco ativo/restaurado, não o arquivo de backup).","PostgreSQL: restaure de fato o backup em um servidor separado/temporário e confirme que o pg_restore termina sem erros.","MySQL/MongoDB: restaure o dump em um ambiente de teste e compare as contagens de linhas/collections e dados de amostra.","Agende 'restore drills' regulares — fazer backups não basta, comprove também o restore.","Registre os resultados e a data da última verificação bem-sucedida."],"related":["last-backup-status","restore-dump"],"playbook":"backup-restore"}}},"solver/upgrade-wizard.json":{"id":"upgrade-wizard","title":"Assistente de upgrade de versão","icon":"⬆️","category":"Ciclo de vida","intro":"Patch ou major, no local ou por migração? Planeje o upgrade passo a passo; cada ramo cobre as verificações prévias, o método e o trabalho pós-upgrade. Ensaie aqui antes de mexer na produção.","start":"kind","nodes":{"kind":{"kind":"step","title":"Que tipo de upgrade você está fazendo?","detail":"Uma versão de patch/minor (dentro da mesma versão major, por exemplo, 16.2 -> 16.4, ou um CU do SQL Server) tem baixo risco e geralmente é feita in-place. Uma versão major (por exemplo, 15 -> 16) pode envolver mudanças no formato dos dados e exige um planejamento mais cuidadoso.","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":"Versão minor / patch (mesma versão major, CU)","next":"patch_prep"},{"label":"Versão major (a versão major muda)","next":"major_method"},{"label":"Não sei a diferença; explique","next":"explain"}]},"explain":{"kind":"step","title":"Patch ou major?","detail":"Patch: a versão major continua a mesma (16.2 -> 16.4); o formato dos datafiles não muda, geralmente basta trocar os binários + restart. Major: a versão major muda (15 -> 16); o catálogo/formato pode mudar, é necessário pg_upgrade / AutoUpgrade / dump-restore, e a compatibilidade da aplicação precisa ser testada.","choices":[{"label":"O meu é um patch (mesma versão major)","next":"patch_prep"},{"label":"O meu é um major (a versão major muda)","next":"major_method"}]},"patch_prep":{"kind":"step","title":"Seu backup e seu plano de rollback estão prontos?","detail":"Mesmo que um patch seja de baixo risco, a regra de ouro de todo upgrade é: backup completo primeiro (e um snapshot, se possível). Você precisa de um ponto para onde voltar se algo der errado.","choices":[{"label":"Sim, backup + rollback estão prontos","next":"sol_patch"},{"label":"Não, ainda não","next":"sol_backupfirst"}]},"sol_backupfirst":{"kind":"solution","title":"Primeiro, backup + plano de rollback","detail":"Monte a rede de segurança antes de iniciar o upgrade.","steps":["Faça um backup completo (e, se possível, um snapshot de storage / guaranteed restore point do Oracle).","Anote os passos de rollback: se algo der errado, como volto para a versão antiga?","Finalize a janela de manutenção e o plano de comunicação e então siga para o passo do patch."],"related":["logical-dump","last-backup-status"]},"sol_patch":{"kind":"solution","title":"Aplicar o patch","detail":"Um patch dentro da mesma versão major. Aplicá-lo de forma rolling em um cluster (começando pelas réplicas) reduz o downtime.","steps":["Oracle: instale o novo RU com opatch, depois aplique as mudanças de SQL com 'datapatch -verbose'.","PostgreSQL: upgrade minor = instalar os novos binários e reiniciar o serviço (sem necessidade de initdb/dump).","MySQL: atualize o pacote; no 8.0, o servidor faz o upgrade automaticamente na inicialização.","SQL Server: rode o instalador do CU/GDR correspondente e depois reinicie.","MongoDB/Redis/Elasticsearch: rolling restart; nós secundários primeiro, o primário por último.","Depois verifique a versão e a aplicação; se vir erros, execute o plano de rollback."],"related":["apply-patch","check-version"],"playbook":"upgrade-rollback"},"major_method":{"kind":"step","title":"Método de upgrade major","detail":"Dois caminhos principais: (1) No local: converter no servidor existente (pg_upgrade, Oracle AutoUpgrade/DBUA, MySQL in-place). Rápido, mas difícil de reverter. (2) Por migração: montar um servidor novo na nova versão, mover os dados (com dump/restore ou replicação) e depois fazer o cutover. Mais seguro, com downtime mínimo.","choices":[{"label":"Quero fazer uma verificação de preparação/compatibilidade primeiro","next":"precheck"},{"label":"No local","next":"sol_inplace"},{"label":"Migrando para um novo servidor (downtime mínimo)","next":"sol_migrate"}]},"precheck":{"kind":"step","title":"Verificação de compatibilidade / prontidão","detail":"Antes do upgrade, colete os avisos da versão de destino: recursos removidos (obsoletos), objetos inválidos, nível de compatibilidade.","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":"Saída limpa, continuar","next":"major_method"},{"label":"Há avisos/incompatibilidades","next":"sol_fixwarn"}]},"sol_fixwarn":{"kind":"solution","title":"Corrija os avisos primeiro","detail":"Resolva todos os avisos do relatório ANTES do upgrade; caso contrário, o upgrade pode falhar no meio ou a aplicação pode quebrar.","steps":["Atualize os objetos e consultas que usam recursos/sintaxe removidos (obsoletos).","Compile/corrija os objetos inválidos; resolva as dependências ausentes.","Planeje as etapas de nível de compatibilidade / feature version para a versão de destino.","Depois que os avisos forem resolvidos, rode a verificação prévia novamente e volte à escolha do método."],"related":["check-upgrade-readiness","set-compatibility"]},"sol_inplace":{"kind":"solution","title":"Upgrade major no local","detail":"Converter no servidor existente. Rápido, mas o rollback geralmente significa restaurar a partir do backup, então um snapshot é obrigatório.","steps":["Faça um backup completo + snapshot/guaranteed restore point (o único caminho de volta).","Oracle: AutoUpgrade (modo deploy) ou DBUA. PostgreSQL: pg_upgrade (--link é rápido, mas não tem volta). MySQL: novos binários + upgrade in-place automático. SQL Server: setup /ACTION=upgrade.","Execute as tarefas pós-upgrade (veja os relacionados abaixo).","Valide a aplicação sob carga real; se ocorrer uma regressão de plano, fixe o comportamento do otimizador."],"related":["upgrade-major","post-upgrade-tasks"],"playbook":"upgrade-rollback"},"sol_migrate":{"kind":"solution","title":"Upgrade por migração (downtime mínimo)","detail":"Monte um servidor novo na nova versão, mova os dados e depois troque com um cutover curto. O método mais seguro; o sistema antigo permanece intacto.","steps":["Monte o novo servidor na versão de destino e prepare o schema.","Transfira a carga inicial com dump/restore ou replicação; depois mantenha-a sincronizada com replicação contínua (CDC / logical replication).","Em uma janela de manutenção curta: pare as escritas, espere o delta restante e aponte a aplicação para o novo servidor (cutover).","Verifique a migração (contagens de linhas/checksums); se houver problema, volte para o servidor antigo imediatamente."],"related":["setup-cdc-replication","verify-migration","export-for-migration"]}}},"solver/migration-wizard.json":{"id":"migration-wizard","title":"Assistente de migração (migração de dados/schema)","icon":"🚚","category":"Ciclo de vida","intro":"Você está migrando dados/schema. É homogênea ou heterogênea, e qual é sua tolerância a downtime? Planeje passo a passo: avaliar → migrar → verificar. Ensaie o cutover aqui primeiro.","start":"kind","nodes":{"kind":{"kind":"step","title":"De onde para onde você está migrando?","detail":"Homogênea: o mesmo motor de banco de dados (por exemplo, Oracle 19 → Oracle 23, ou PostgreSQL para outro servidor). Heterogênea: um motor diferente (por exemplo, Oracle → PostgreSQL, MySQL → SQL Server). Migrações heterogêneas exigem muito mais trabalho de compatibilidade (tipos de dados, funções, PL/SQL).","choices":[{"label":"Mesmo motor, novo servidor/versão (homogênea)","next":"downtime"},{"label":"Para um motor diferente (heterogênea)","next":"hetero"},{"label":"Estou na fase de planejamento; como devo abordar?","next":"downtime"}]},"downtime":{"kind":"step","title":"Qual é sua tolerância a downtime?","detail":"Isso determina o método de migração. Se houver uma janela de manutenção, o caminho mais simples é dump/restore. Se for exigido downtime quase zero, você carrega os dados iniciais, os mantém sincronizados com replicação contínua (CDC) e faz um cutover curto.","choices":[{"label":"Há uma janela de manutenção (downtime é aceitável)","next":"sol_offline"},{"label":"É exigido downtime quase zero","next":"sol_online"}]},"hetero":{"kind":"step","title":"Você avaliou a compatibilidade de schema e de tipos?","detail":"Em uma migração heterogênea, o trabalho real não é copiar os dados, mas resolver as diferenças: tipos de dados (VARCHAR2↔TEXT), funções (NVL↔COALESCE), valores de auto-increment, PL/SQL ↔ PL/pgSQL, recursos removidos/diferentes.","choices":[{"label":"Mapeei as diferenças de schema/tipos","next":"sol_hetero"},{"label":"Ainda não as avaliei","next":"sol_assess"}]},"sol_assess":{"kind":"solution","title":"Avalie a compatibilidade primeiro","detail":"Antes de migrar, mapeie as diferenças entre origem e destino; se esta etapa for pulada, a migração trava no meio do caminho.","steps":["Gere o diff de schema: tabelas, constraints, índices, views, procedures.","Mapeie os tipos de dados e as funções (o módulo DBAtlas > Tipos e Funções foi feito exatamente para isso).","Decida como os recursos específicos do engine (identity/sequence, particionamento, PL/SQL, triggers) serão tratados no destino.","Escolha uma ferramenta de conversão (ora2pg, pgloader, AWS SCT/DMS) e ensaie com uma amostra pequena."],"related":["compare-schema","heterogeneous-migration"]},"sol_offline":{"kind":"solution","title":"Migração offline (dump / restore)","detail":"O método homogêneo mais simples e confiável: faça um backup consistente, carregue-o no destino, verifique e troque.","steps":["Faça um export CONSISTENTE da origem (pg_dump -Fc, expdp FLASHBACK_SCN, mysqldump --single-transaction, BACKUP, mongodump --oplog).","Carregue-o no destino (pg_restore -j, impdp, mysql <, RESTORE, mongorestore).","Verifique a migração: as contagens de linhas e os checksums críticos batem entre origem e destino?","Durante a janela de manutenção, aponte a aplicação para o destino (cutover); se algo der errado, volte para a origem."],"related":["export-for-migration","import-for-migration","verify-migration"]},"sol_online":{"kind":"solution","title":"Downtime mínimo (CDC / replicação)","detail":"Carregue os dados iniciais e depois mantenha o destino sincronizado com a origem via replicação contínua; o downtime ocorre apenas durante o cutover curto.","steps":["Carregue os dados iniciais (baseline) com dump/restore ou um snapshot.","Configure a replicação contínua: PG logical replication (PUBLICATION/SUBSCRIPTION), MySQL binlog replication, Oracle GoldenGate, MSSQL transactional replication/CDC, Mongo change streams/mongosync.","Espere e monitore até que o destino alcance a origem e o lag fique em ~0.","Cutover curto: pare as escritas na origem, espere o delta restante, aponte a aplicação para o destino e verifique."],"related":["setup-cdc-replication","verify-migration"]},"sol_hetero":{"kind":"solution","title":"Migração heterogênea (para outro engine)","detail":"Converta o schema, mova os dados, adapte a lógica, verifique. Avance em fases; não migre tudo de uma vez.","steps":["Converta o schema: com uma ferramenta (ora2pg, pgloader, AWS SCT) ou à mão; adapte os tipos e as constraints ao destino.","Mova os dados: carga em massa ou uma ferramenta; particione/divida em partes as tabelas grandes.","Adapte a lógica do lado do servidor: PL/SQL → PL/pgSQL, equivalentes de funções/triggers.","Verifique a fundo: contagens de linhas, dados de amostra, resultados das consultas críticas; teste a aplicação no destino.","Se o downtime precisar ser reduzido, mantenha o destino sincronizado com uma camada de CDC após a conversão e depois faça o cutover."],"related":["heterogeneous-migration","verify-migration","setup-cdc-replication"]}}},"solver/high-cpu.json":{"id":"high-cpu","title":"CPU alta","icon":"🔥","category":"Desempenho","intro":"A CPU do servidor está no limite. Primeiro verifique se é realmente o banco de dados que a está consumindo e depois siga os ramos até a causa raiz: consultas mal planejadas, uma regressão de plano, concorrência excessiva ou um processo que não é do banco.","start":"root","nodes":{"root":{"kind":"step","title":"O banco de dados está realmente consumindo a CPU?","detail":"Verifique no sistema operacional qual processo está consumindo CPU. A maior parte da carga está nos processos do banco ou em um processo vizinho (backup, antivírus, outra aplicação)? Isso divide a investigação em duas.","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":"Sim, os processos do banco estão consumindo a CPU","next":"db_confirm"},{"label":"Não, um processo vizinho / job de backup está consumindo","next":"sol_os"}]},"db_confirm":{"kind":"step","title":"Como a carga apareceu?","detail":"Se o banco está consumindo a CPU, identifique o padrão: algumas consultas pesadas predominam, o problema começou de repente após uma mudança ou há alta concorrência/contenção de conexões?","choices":[{"label":"Algumas consultas pesadas estão consumindo a CPU","next":"topcpu"},{"label":"Começou de repente; houve um deploy / mudança de parâmetro recente","next":"sol_regression"},{"label":"Muitas conexões / contenção por concorrência","next":"sol_concurrency"}]},"topcpu":{"kind":"step","title":"Encontrar as consultas que mais consomem CPU","detail":"Obtenha as principais consultas por consumo total de CPU. Depois decida se cada uma é pesada por chamada (plano ruim) ou barata por chamada, mas chamada com muita frequência.","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":"Pesada por chamada; plano ruim / full scan","next":"sol_query"},{"label":"Barata por chamada, mas chamada com muita frequência","next":"sol_frequency"}]},"sol_query":{"kind":"solution","title":"Causa raiz: consultas mal planejadas estão consumindo a CPU","detail":"Algumas consultas consomem CPU excessiva por chamada por causa de full scans ou de uma ordem de join ruim. Corrigir seus planos é a solução central.","steps":["Obtenha os planos (EXPLAIN) das consultas que mais consomem CPU; procure full scans, uma ordem de join ruim ou diferenças entre linhas estimadas e reais.","Adicione índices adequados nas colunas de filtro/join; verifique se o plano passa para um index scan (IXSCAN).","Se o otimizador errar as estimativas, colete estatísticas novas.","Limite as consultas descontroladas (Oracle Resource Manager / MSSQL Resource Governor) e reescreva a consulta se necessário."],"related":["top-slow-queries","explain-plan","create-index","update-statistics"],"playbook":"high-cpu"},"sol_frequency":{"kind":"solution","title":"Causa raiz: frequência de chamadas excessiva","detail":"As consultas são baratas individualmente, mas chamadas milhares de vezes por segundo; é daí que vem o custo total de CPU. Geralmente um padrão N+1 ou um hot path sem cache.","steps":["Identifique os statements chamados com mais frequência (calls / execution_count) e encontre o caminho da aplicação que os chama.","Transforme o padrão N+1 em uma consulta em lote; reduza leituras repetidas com um cache de aplicação/resultados.","Use prepared statements para cortar o custo do parse repetido (hard parse).","Considere uma materialized view / tabela de resumo para consultas pesadas frequentes e que não mudam."],"related":["top-slow-queries","explain-plan"],"playbook":"high-cpu"},"sol_regression":{"kind":"solution","title":"Causa raiz: regressão de plano / estatísticas desatualizadas","detail":"O sistema estava normal ontem; a CPU disparou após um deploy, mudança de parâmetro ou carga de dados. O otimizador pode ter mudado para um plano pior.","steps":["Identifique a mudança: deploy recente, upgrade/patch, mudança de parâmetro ou carga grande de dados.","Colete estatísticas novas para as tabelas afetadas (estatísticas desatualizadas são a causa mais comum).","Fixe o plano bom: Oracle SQL Plan Baseline / hint, MSSQL Query Store 'force plan'.","Se a mudança veio de um parâmetro, reverta-o e reavalie de forma controlada."],"related":["update-statistics","explain-plan","show-config-param"],"playbook":"high-cpu"},"sol_concurrency":{"kind":"solution","title":"Causa raiz: alta concorrência / contenção de conexões","detail":"As consultas individuais são aceitáveis, mas sessões demais rodam ao mesmo tempo; mais sessões ativas que cores de CPU causam troca de contexto e contenção de latch/spin.","steps":["Compare o número de sessões ativas com o número de cores de CPU; com mais sessões ativas que cores, forma-se uma run queue.","Coloque um pooler de conexões entre a aplicação e o banco (PgBouncer / ProxySQL) e defina um tamanho de pool razoável.","Se houver paralelismo excessivo, limite o grau de paralelismo (Oracle parallel_degree_limit / parallel_max_servers, MSSQL MAXDOP).","Alivie a CPU do nó primário distribuindo a carga de leitura entre réplicas de leitura."],"related":["connection-count","active-sessions"],"playbook":"connection-storm"},"sol_os":{"kind":"solution","title":"Causa raiz: um processo que não é do banco está consumindo CPU","detail":"Não é o banco de dados, mas um processo vizinho que está consumindo a CPU: um job de backup/compressão, uma varredura de antivírus, um log shipper ou outra aplicação na mesma máquina.","steps":["Identifique o processo culpado com uma ferramenta do SO (top / Gerenciador de Tarefas).","Se for um job de backup, coleta de estatísticas ou manutenção, reagende-o para fora dos horários de pico.","Adicione os diretórios de dados à lista de exclusão dos processos de antivírus/varredura.","Se o conflito for permanente, mova o banco para um servidor separado, com recursos próprios."],"related":["os-resource"],"playbook":"high-cpu"}}},"solver/memory-pressure.json":{"id":"memory-pressure","title":"Pressão de memória / OOM","icon":"🧠","category":"Desempenho","intro":"A memória do servidor está acabando, o sistema está fazendo swap ou o OOM killer está ativo. Primeiro determine quem está consumindo a memória: a memória alocada (buffer pool/SGA), a memória de sessão (work_mem/PGA), o SO como um todo ou uma situação específica do Redis?","start":"root","nodes":{"root":{"kind":"step","title":"Quem está consumindo a memória?","detail":"Separe por camada a origem da pressão de memória. A memória alocada (fixa) é grande demais, a memória por sessão está explodindo, um processo que não é do banco a está consumindo ou é o próprio gerenciamento de memória do 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":"A memória alocada (buffer pool / SGA) predomina","next":"allocated"},{"label":"A memória de sessão (work_mem / PGA) está explodindo","next":"sol_session"},{"label":"Um processo que não é do banco / o SO como um todo","next":"sol_os"},{"label":"Específico do Redis (maxmemory / eviction / fragmentação)","next":"sol_redis"}]},"allocated":{"kind":"step","title":"A memória total configurada excede a RAM física?","detail":"Se a memória alocada fixa é grande, há duas possibilidades: ou o total configurado (buffer pool + sessões + SO) excede a RAM física (over-commit), ou o tamanho é razoável, mas a taxa de acerto do cache ainda é baixa. Some as configurações e compare com a 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":"Sim, o total configurado excede a RAM (over-commit)","next":"sol_overcommit"},{"label":"Não, o tamanho é razoável, mas a taxa de acerto do cache é baixa","next":"sol_cache"}]},"sol_overcommit":{"kind":"solution","title":"Causa raiz: over-commit de memória","detail":"A soma de buffer pool/SGA + memória de sessão + necessidades do SO excede a RAM física. O sistema está fazendo swap ou o OOM killer está matando o processo.","steps":["Refaça o orçamento de memória: reserve uma parte para o SO e então dimensione corretamente a memória alocada (Ferramentas > Calculadora de memória).","Reduza o alvo do buffer pool/SGA e o teto de memória de sessão para que caibam no limite da RAM.","Aplique as mudanças de forma controlada e verifique se o uso de swap e os eventos de OOM pararam.","Se a capacidade for permanentemente insuficiente, adicione RAM ou divida a carga."],"related":["show-config-param","cache-hit-ratio"],"playbook":"memory-pressure"},"sol_cache":{"kind":"solution","title":"Causa raiz: cache insuficiente (taxa de acerto do cache baixa)","detail":"A memória alocada não excede a RAM, mas é pequena em relação ao working set; a taxa de acerto do buffer cache é baixa e o banco lê constantemente do disco.","steps":["Meça a taxa de acerto do buffer cache / buffer pool; se for persistentemente baixa (ex.: abaixo de 90%), o cache é pequeno demais.","Se houver RAM disponível, aumente o buffer pool/SGA de forma controlada e meça a taxa de acerto novamente.","Se os dados quentes forem realmente grandes, reduza leituras desnecessárias: adicione índices, selecione apenas as colunas necessárias em vez de SELECT *, pagine.","Se aumentá-lo sobrecarregar a RAM, rebalanceie a memória de sessão em relação à memória alocada."],"related":["cache-hit-ratio","show-config-param"],"playbook":"memory-pressure"},"sol_session":{"kind":"solution","title":"Causa raiz: explosão da memória de sessão","detail":"A memória por sessão, como work_mem/PGA, multiplicada pela alta concorrência, esgota a RAM. Cada operação de sort/hash pode alocar essa memória separadamente.","steps":["Estime o pior caso: memória de sessão × sessões simultâneas × número de operações; compare com a RAM.","Reduza a configuração global de memória de sessão (work_mem / sort_buffer_size / PGA target).","Para consultas pesadas que realmente precisam de sorts/hashes grandes, eleve a configuração apenas no nível da sessão.","Limite a concorrência com um pooler de conexões para reduzir a demanda total de memória."],"related":["show-config-param","connection-count"],"playbook":"memory-pressure"},"sol_redis":{"kind":"solution","title":"Causa raiz: gerenciamento de memória do Redis","detail":"No Redis, used_memory atingiu maxmemory, a eviction está ativa ou a fragmentação está alta (used_memory_rss >> used_memory). É preciso tratar a política e a fragmentação.","steps":["Leia used_memory, maxmemory e mem_fragmentation_ratio com INFO memory.","Defina uma política de eviction adequada ao propósito: CONFIG SET maxmemory-policy allkeys-lru (cache) ou noeviction (dados persistentes).","Use TTLs para que as chaves expiradas sejam removidas e reduza as chaves grandes (BIG KEYS).","Se a fragmentação estiver alta, habilite o active defrag (CONFIG SET activedefrag yes) ou reinicie em uma janela de manutenção adequada."],"related":["show-config-param"],"playbook":"memory-pressure"},"sol_os":{"kind":"solution","title":"Causa raiz: consumo de memória fora do banco","detail":"A memória não está sendo consumida pelo banco de dados, mas pelo SO como um todo ou por um processo vizinho: outra aplicação, pressão do cache do sistema de arquivos ou um processo auxiliar com vazamento.","steps":["Identifique o processo que mais consome memória com uma ferramenta do SO (top / free / Gerenciador de Tarefas).","Se o culpado for um processo fora do banco, mova-o, limite-o (cgroup / job object) ou corrija o vazamento de memória.","Se o OOM killer estiver encerrando o processo do banco, revise as configurações de OOM e garanta memória para o banco.","Se o conflito for persistente, mova o banco para um servidor separado com memória própria."],"related":["os-resource"],"playbook":"memory-pressure"}}},"solver/install-setup.json":{"id":"install-setup","title":"Nova instalação e baseline seguro","icon":"🛠️","category":"Ciclo de vida","intro":"Etapas puladas ao preparar um banco de dados recém-instalado para produção levam às falhas mais caras. Escolha a etapa em que você está e obtenha um checklist ordenado de configuração inicial, hardening de segurança, durabilidade e monitoramento.","start":"root","nodes":{"root":{"kind":"step","title":"Em qual etapa você está?","detail":"Preparar uma nova instalação para produção tem quatro etapas: configuração inicial, hardening de segurança, durabilidade (backup/replicação) e monitoramento. Em qual delas você está trabalhando agora? Recomenda-se passar por todas, em ordem.","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":"Configuração inicial após a instalação","next":"firstconfig"},{"label":"Hardening de segurança","next":"sol_security"},{"label":"Configuração de backup e durabilidade","next":"durability"},{"label":"Configuração de monitoramento e alertas","next":"sol_monitoring"}]},"firstconfig":{"kind":"step","title":"Qual é a prioridade na configuração inicial?","detail":"A configuração inicial se divide em dois temas principais: dimensionamento de recursos/parâmetros (memória, conexões) e fundações permanentes (character set/collation, diretório de dados/layout de arquivos). São as decisões mais difíceis de mudar depois.","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":"Dimensionamento de memória / parâmetros","next":"sol_sizing"},{"label":"Character set, collation e layout de arquivos","next":"sol_layout"}]},"durability":{"kind":"step","title":"Qual parte da durabilidade você está configurando?","detail":"A durabilidade se apoia em duas pernas: uma estratégia de backup verificada (primeiro backup + teste de restore) e continuidade (modo archive/log, replicação). Dizer 'tenho backup' sem testá-lo é o equívoco mais comum.","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":"Estratégia de backup + primeiro backup + teste de restore","next":"sol_backup"},{"label":"Modo archive/log + replicação","next":"sol_replication"}]},"sol_sizing":{"kind":"solution","title":"Configuração inicial: dimensionamento de memória e parâmetros","detail":"Os padrões são conservadores na maioria dos engines; dimensione-os de acordo com a RAM e a CPU do servidor, mas evite over-commit.","steps":["Divida a RAM total: reserve uma parte para o SO e defina o buffer pool/SGA como cache principal.","Defina a memória de sessão (work_mem/PGA) de forma conservadora com base na concorrência esperada; não ultrapasse a RAM total.","Defina max_connections conforme a necessidade real; planeje um pooler de conexões para alta concorrência.","Revise os principais parâmetros específicos do engine (WAL/redo, checkpoint, paralelismo) e documente as alterações."],"related":["show-config-param","connect-cli"]},"sol_layout":{"kind":"solution","title":"Configuração inicial: character set, collation e layout de arquivos","detail":"O character set/collation e o layout do diretório de dados são definidos na instalação; alterá-los depois geralmente exige reinstalação ou migração.","steps":["Escolha um character set Unicode no nível do servidor (ex.: UTF-8 / AL32UTF8) e defina uma collation consistente.","Coloque os diretórios de dados, de log/WAL e de backup em discos/volumes separados; reduza a contenção de IO e os pontos únicos de falha.","Faça o hardening do sistema de arquivos e das permissões: somente o usuário do banco deve conseguir ler o diretório de dados.","Documente as decisões de layout e character set para que os nós adicionados depois sigam o mesmo padrão."],"related":["show-config-param","connect-cli"]},"sol_security":{"kind":"solution","title":"Hardening de segurança","detail":"Uma nova instalação vem com contas padrão, acesso de rede permissivo e portas abertas. Reduzir a superfície de ataque antes de ir para produção é obrigatório.","steps":["Remova ou bloqueie as contas padrão/de exemplo; desabilite contas administrativas não utilizadas.","Aplique uma política de senhas fortes e altere todas as senhas padrão.","Menor privilégio: conceda a cada aplicação apenas os privilégios de que ela precisa e evite roles amplas.","Habilite TLS, restrinja o listener/porta a redes confiáveis e habilite o log de auditoria."],"related":["create-user-grant","change-password","enable-audit"]},"sol_backup":{"kind":"solution","title":"Durabilidade: estratégia de backup e teste de restore","detail":"Um backup só vale o quanto ele pode ser restaurado. Faça o primeiro backup, configure a continuidade e sempre execute um teste de restore.","steps":["Defina os objetivos de recuperação (RPO/RTO) e configure uma rotina de backup full + incremental.","Faça o primeiro backup full; armazene os backups em um local separado do servidor de banco.","Teste o backup restaurando-o em um ambiente separado; um backup cuja integridade não foi comprovada não conta.","Agende o job de backup, envie sua saída para o monitoramento e verifique regularmente o status do último backup."],"related":["logical-dump","restore-dump","last-backup-status"]},"sol_replication":{"kind":"solution","title":"Durabilidade: modo archive/log e replicação","detail":"Para recuperação point-in-time e alta disponibilidade, o modo archive/log deve estar habilitado e deve haver pelo menos uma réplica.","steps":["Habilite o modo archive/log (PG archive_mode/wal_level, Oracle ARCHIVELOG, MySQL binlog, MSSQL FULL recovery).","Configure pelo menos uma réplica (standby/replica) e conclua a sincronização inicial.","Monitore o lag de replicação e defina um alerta de lag.","Valide o failover executando um exercício controlado de failover/switchover."],"related":["replication-status","list-replicas"],"playbook":"replication-lag"},"sol_monitoring":{"kind":"solution","title":"Configuração de monitoramento e alertas","detail":"A última etapa antes da produção: ver os problemas antes dos usuários. Configure health checks e alertas com os limites corretos.","steps":["Colete health checks básicos: cache hit ratio, sessões ativas/em espera, consultas mais lentas.","Defina alertas de capacidade: uso de disco, número de conexões se aproximando do limite, lag de replicação.","Encaminhe os alertas para um canal (e-mail/chat) e calibre os limites de acordo com a carga real.","Adicione também ao monitoramento o sucesso dos backups e os logs de erro, para detectar falhas silenciosas."],"related":["cache-hit-ratio","connection-count","free-space"]}}},"solver/corruption-recovery.json":{"id":"corruption-recovery","title":"Recuperação de corrupção de dados","icon":"🧯","category":"Recuperação","intro":"Uma árvore de decisão passo a passo para corrupção de dados (erros de checksum de bloco/página, tabelas ilegíveis, RDB/AOF corrompidos): primeiro confirme o escopo da corrupção e, em seguida, escolha corretamente entre recuperação no nível de bloco, restore completo/PITR a partir do backup e ferramentas de reparo de último recurso.","start":"root","nodes":{"root":{"kind":"step","title":"Qual é o escopo da corrupção?","detail":"Primeiro execute uma verificação de integridade para determinar até onde a corrupção se espalhou. Apenas alguns blocos/páginas estão corrompidos, um único objeto (tabela/índice) foi afetado ou a corrupção é generalizada? Faça a varredura com os comandos abaixo para determinar o escopo e escolha o ramo adequado.","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":"Apenas alguns blocos / páginas estão corrompidos","next":"block_level"},{"label":"Um único objeto (tabela/índice) foi afetado","next":"restore"},{"label":"A corrupção é generalizada / muitos objetos","next":"restore"},{"label":"As ferramentas de verificação não funcionam, o banco não abre","next":"last_resort"},{"label":"A corrupção continua se repetindo (suspeita de causa raiz)","next":"hardware"}]},"block_level":{"kind":"solution","title":"Causa raiz: corrupção limitada de blocos/páginas → recuperação direcionada","detail":"Se apenas alguns blocos/páginas estiverem corrompidos, não é necessário restaurar o banco inteiro. Minimize a perda de dados reparando apenas as partes corrompidas a partir do backup/logs com o recurso de recuperação no nível de bloco/página do engine.","steps":["Oracle: após revisar a lista de blocos corrompidos em v$database_block_corruption (execute RMAN> VALIDATE DATABASE; antes se a lista estiver desatualizada), recupere um único bloco com RMAN> RECOVER DATAFILE 5 BLOCK 1234; ou todos os blocos listados com RMAN> RECOVER CORRUPTION LIST;.","SQL Server: restore de página única — RESTORE DATABASE [db] PAGE='5:1234' FROM DISK='D:\\backup\\db.bak' WITH NORECOVERY;  em seguida aplique os backups de log subsequentes WITH NORECOVERY e o último WITH RECOVERY.","PostgreSQL: não há reparo automático no nível de bloco; restaure parcialmente a tabela afetada a partir do backup ou habilite zero_damaged_pages=on temporariamente SOMENTE para extrair dados (as linhas corrompidas são perdidas).","MySQL/InnoDB: não há reparo de página única; restaure a tabela afetada a partir do último backup bom e avance com PITR, se necessário.","Após o reparo, execute novamente o comando de verificação (VALIDATE / DBCC CHECKDB / pg_amcheck) para confirmar que não resta corrupção.","Verifique os dados de negócio nos blocos recuperados por amostragem no lado da aplicação."],"related":["restore-dump","last-backup-status"],"playbook":"corruption"},"restore":{"kind":"solution","title":"Causa raiz: corrupção no nível de objeto/generalizada → restore completo ou PITR a partir do backup","detail":"Se a corrupção se espalhou para um ou mais objetos, o caminho mais seguro é restaurar a partir de um backup bom e, quando possível, avançar até o momento da corrupção (PITR). Isso evita a perda de dados que as ferramentas de reparo causariam.","steps":["Determine o horário aproximado em que a corrupção começou (alert log / error log) para definir o alvo do PITR logo antes dele.","Verifique o último backup full BOM e os logs de transação até esse ponto (logs arquivados / 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: restaure o base backup, defina recovery_target_time='2026-07-04 09:59:00' e aplique o WAL até esse ponto.","MySQL/MariaDB: restaure o backup full e, em seguida, aplique o binlog até esse ponto com mysqlbinlog --stop-datetime='2026-07-04 09:59:00'.","MongoDB: restaure com mongorestore a partir de uma réplica/snapshot bom; Elasticsearch: restaure os índices corrompidos com POST _snapshot/my_repo/snap1/_restore.","Após a abertura, execute novamente a verificação de integridade e valide os dados com contagens de linhas/verificações da aplicação."],"related":["restore-dump","logical-dump","last-backup-status"],"playbook":"corruption"},"last_resort":{"kind":"step","title":"Sem backup / o banco não abre — partindo para o último recurso?","detail":"As ferramentas de reparo (REPAIR_ALLOW_DATA_LOSS, innodb_force_recovery, --fix) PODEM CAUSAR PERDA DE DADOS e podem violar restrições de integridade. Elas são o último recurso somente quando não existe backup utilizável e o banco não pode ser aberto. Primeiro, certifique-se de que realmente não há backup utilizável.","choices":[{"label":"Encontrei um backup bom, vou restaurar","next":"restore"},{"label":"Não há nenhum backup, uma ferramenta de reparo é a única opção","next":"repair"}]},"repair":{"kind":"solution","title":"Último recurso: ferramentas de reparo com risco de perda de dados","detail":"Essas ferramentas descartam linhas/páginas corrompidas para tornar o banco possível de abrir. Use-as somente se não houver backup e depois de ter feito uma cópia dos arquivos existentes. Objetivo: abrir o suficiente para exportar os dados e depois movê-los para uma cópia limpa.","steps":["PRIMEIRO faça uma cópia bruta dos datafiles existentes (as tentativas podem piorar a situação).","SQL Server: DBCC CHECKDB (N'db', REPAIR_ALLOW_DATA_LOSS) WITH ALL_ERRORMSGS;  (o banco deve estar em modo SINGLE_USER; este comando pode causar perda de dados).","MySQL/InnoDB: inicie com innodb_force_recovery=1 em [mysqld] no my.cnf; se não abrir, aumente para 2, 3... (até 6); assim que abrir, exporte imediatamente os dados com mysqldump, importe-os em uma instalação limpa e remova a configuração.","PostgreSQL: como último recurso, pg_resetwal (alto risco de perda de dados) somente quando o WAL estiver corrompido; depois extraia os dados com pg_dump e carregue-os em um novo cluster.","Oracle: sem backup, a recuperação via DBMS_REPAIR / eventos é avaliada com o Oracle Support; os blocos podem ser ignorados com 'skip corrupt' (perda de dados).","MongoDB: abra com mongod --repair ou WiredTiger salvage e depois mova os dados para um novo replica set.","Após o reparo, SEMPRE migre para uma instalação limpa, execute novamente a verificação de integridade e reporte os dados perdidos."],"related":["logical-dump","restore-dump"],"playbook":"corruption"},"hardware":{"kind":"solution","title":"Causa raiz: hardware/infraestrutura → corrija a origem e habilite checksums","detail":"Se a corrupção continua se repetindo, a causa real é muito provavelmente o disco, a controladora, a memória (RAM) ou uma camada de armazenamento instável. Recuperar os dados não basta; se você não corrigir a origem, a corrupção voltará. Habilite também a verificação de checksum/integridade para detecção precoce.","steps":["Verifique a saúde do disco: valores SMART (smartctl -a /dev/sdX), logs da controladora RAID e alertas do storage.","Execute um teste de memória (memtest86+ ou contadores de erro ECC); erros de bit único são uma causa clássica de corrupção.","Revise os logs de erro do SO/sistema de arquivos e do hardware (dmesg, Visualizador de Eventos, alertas do storage array).","PostgreSQL: crie um cluster com checksums com initdb --data-checksums (ou pg_checksums --enable) para que a corrupção seja detectada quando for gravada em disco.","Oracle: habilite a verificação de blocos com DB_BLOCK_CHECKSUM=FULL e DB_BLOCK_CHECKING=FULL; adicione DB_LOST_WRITE_PROTECT=TYPICAL.","SQL Server: certifique-se de que o banco usa PAGE_VERIFY CHECKSUM (ALTER DATABASE [db] SET PAGE_VERIFY CHECKSUM).","MySQL/InnoDB: proteja contra gravações parciais com innodb_checksum_algorithm=crc32 e, se necessário, innodb_doublewrite=ON.","Após corrigir a origem, restaure a partir do último backup bom em uma cópia limpa e reforce o monitoramento."],"related":["restore-dump","last-backup-status"],"playbook":"corruption"}}},"solver/failover-drill.json":{"id":"failover-drill","title":"Exercício de failover / transição de papel planejada","icon":"🔀","category":"Replicação","intro":"Uma árvore de decisão que identifica o tipo de troca de papel (switchover planejado, failover de emergência ou um exercício que não toca a produção) e fornece a sequência correta de comandos e as etapas de verificação para cada cenário. Objetivo: estar pronto para fazer a transição sem perda de dados quando planejada, com perda mínima em uma emergência e sem nenhuma indisponibilidade em um exercício.","start":"root","nodes":{"root":{"kind":"step","title":"O que você quer fazer?","detail":"Escolha o contexto da troca de papel. Você está fazendo uma transição planejada com o primário saudável (manutenção/migração), o primário realmente caiu e é necessária uma transição de emergência, ou você está executando um exercício/validação de prontidão sem tocar a produção?","choices":[{"label":"Switchover planejado (primário saudável)","next":"planned"},{"label":"Failover de emergência (primário caiu)","next":"emergency_check"},{"label":"Exercício / teste de prontidão (não tocar a produção)","next":"drill"}]},"planned":{"kind":"step","title":"Transição planejada — você está pronto?","detail":"O objetivo de um switchover planejado é ZERO perda de dados. Para isso, antes da transição você deve garantir que a réplica alcançou o primário (lag ~0) e está saudável. Verifique o lag com os comandos abaixo; se o lag estiver próximo de zero, siga para as etapas de transição.","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":"O lag está próximo de zero, pronto para a transição","next":"sol_planned"},{"label":"O lag está alto, aguarde a sincronização primeiro","next":"drill"}]},"sol_planned":{"kind":"solution","title":"Switchover planejado (transição controlada sem perda de dados)","detail":"Com o primário e o standby saudáveis e sincronizados, troque os papéis de forma controlada. A ordem importa: pare as gravações, garanta que as alterações restantes chegaram ao standby, depois transfira o papel e redirecione a aplicação para o novo primário.","steps":["Anuncie a janela de manutenção e segure a aplicação de forma controlada para leituras e gravações.","Oracle Data Guard (12c+): SQL> ALTER DATABASE SWITCHOVER TO standby_db VERIFY; depois SQL> ALTER DATABASE SWITCHOVER TO standby_db;  (com o Broker: DGMGRL> SWITCHOVER TO 'standby_db'; 11g e anteriores: COMMIT TO SWITCHOVER TO PHYSICAL STANDBY).","PostgreSQL: desligue o primário de forma limpa (pg_ctl stop -m fast), promova o standby com SELECT pg_promote(); e depois reanexe o antigo primário como novo standby com pg_rewind.","SQL Server AG: em uma réplica síncrona, ALTER AVAILABILITY GROUP [ag] FAILOVER;  (failover planejado sem perda de dados; SYNCHRONOUS_COMMIT é obrigatório).","MongoDB: use rs.stepDown(60) para forçar o primário atual a deixar o papel por 60 s; o secondary mais atualizado é eleito automaticamente e se torna primário.","Redis: no novo candidato a master, REPLICAOF NO ONE; depois, nos demais nós, REPLICAOF new_master port; (com Sentinel, SENTINEL FAILOVER master_name).","Aponte a connection string / roteamento da aplicação para o novo primário (VIP, service name ou connection string).","Verifique: o novo primário aceita gravações, o antigo primário está fazendo streaming como standby com lag ~0 e a aplicação não apresenta erros."],"related":["promote-failover","replication-status","list-replicas"],"playbook":"replication-lag"},"emergency_check":{"kind":"step","title":"Transição de emergência — o primário realmente caiu?","detail":"Antes de forçar um failover, verifique se o primário está de fato inacessível e avalie o risco de split-brain. Se o primário estiver na verdade ativo (ex.: uma queda de rede transitória), uma transição forçada leva a duas cópias graváveis separadas (split-brain). Compare também o lag para escolher o standby mais atualizado.","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":"Sim, o primário caiu — forçar a transição","next":"emergency"},{"label":"Não tenho certeza / o primário pode voltar","next":"planned"}]},"emergency":{"kind":"solution","title":"Failover de emergência (primário caiu, transição com risco de perda de dados)","detail":"O primário está inacessível e você não pode esperar que ele volte. É preciso forçar a promoção do standby; com replicação assíncrona, algumas das últimas transações podem ser perdidas. Sua prioridade é restabelecer o serviço, depois identificar a janela de perda e trazer o antigo primário de volta com segurança.","steps":["Verifique se o primário realmente caiu (isole o antigo primário da rede / desligue-o para evitar split-brain — fencing/STONITH).","Escolha o standby mais atualizado: compare lag/offset antes de agir, para promover aquele com menor perda de dados.","Oracle Data Guard: DGMGRL> FAILOVER TO 'standby_db';  (ou SQL> ALTER DATABASE ACTIVATE STANDBY DATABASE;).","PostgreSQL: promova o standby imediatamente com SELECT pg_promote();; quando o antigo primário voltar, NÃO o ABRA como primário sem pg_rewind (risco de split-brain).","SQL Server AG: ALTER AVAILABILITY GROUP [ag] FORCE_FAILOVER_ALLOW_DATA_LOSS;  (perda de dados é possível com uma réplica assíncrona).","MongoDB: se não restar maioria, reconfigure os membros sobreviventes com rs.reconfig(cfg, {force:true}).","Redis: sem Sentinel, execute REPLICAOF NO ONE no novo candidato a master; anexe os demais a ele; nunca deixe o antigo master reingressar automaticamente.","Redirecione a aplicação para o novo primário; depois identifique e reporte a janela de dados perdidos (transações perdidas) e reconstrua de forma limpa o antigo primário como novo standby."],"related":["promote-failover","replication-status","list-replicas"],"playbook":"db-down"},"drill":{"kind":"solution","title":"Exercício / teste de prontidão (validar sem tocar a produção)","detail":"Comprove que você está pronto para o failover sem executar uma transição real. Verifique a saúde da réplica, se o lag é aceitável e se a aplicação pode ser redirecionada, sem afetar a produção. Opcionalmente, ensaie um switchover real em uma cópia isolada.","steps":["Meça o lag e verifique se está abaixo do limite (PG: pg_stat_replication.replay_lag; MySQL: Seconds_Behind_Source; Oracle: v$dataguard_stats; Mongo: rs.printSecondaryReplicationInfo()).","Verifique a saúde da réplica: todos os standbys estão fazendo streaming e o modo síncrono está ativo nos membros esperados (SQL Server: synchronization_state_desc='SYNCHRONIZED').","Teste de leitura/papel: execute uma consulta somente leitura no standby e confirme que recebe resposta sem atraso (PG hot standby, Oracle Active Data Guard, read replica).","Ensaio de roteamento da aplicação: em um ambiente de teste, aponte a connection string/service name para o novo primário e verifique se a aplicação se conecta sem problemas (não toque no tráfego de produção).","Ensaie um switchover real de ponta a ponta em uma cópia isolada e meça o tempo de transição (RTO).","Ensaie também as etapas de failback: reconstrução do antigo primário com pg_rewind / DG reinstate / AG resume.","Registre as constatações, os tempos e as lacunas; atualize o runbook e agende o exercício periodicamente."],"related":["replication-status","list-replicas","promote-failover"],"playbook":"replication-lag"}}},"solver/security-incident.json":{"id":"security-incident","title":"Incidente de segurança / acesso suspeito","icon":"🚨","category":"Segurança","intro":"Para acesso suspeito, alteração inesperada de privilégios ou possível vazamento de dados, uma árvore de decisão que conduz, com base no sintoma, às etapas de resposta corretas (bloquear a conta, revogar privilégios excessivos, cortar conexões, determinar o escopo) e ao hardening permanente pós-incidente.","start":"root","nodes":{"root":{"kind":"step","title":"O que você notou?","detail":"Escolha o tipo de incidente. O sintoma é um login suspeito ou uma rajada de logins com falha, uma alteração inesperada de privilégio (GRANT/role), um possível vazamento de dados / exportação anormal, ou o incidente está encerrado e você está fazendo o hardening permanente? Escolha o ramo mais adequado com base na sua primeira observação. Primeiro, anote o horário do incidente e a conta/recurso afetado.","choices":[{"label":"Login suspeito / rajada de logins com falha","next":"identity"},{"label":"Alteração inesperada de privilégio (GRANT/role)","next":"privilege"},{"label":"Vazamento de dados / exportação anormal","next":"data"},{"label":"Medidas permanentes pós-incidente (hardening)","next":"harden"}]},"identity":{"kind":"step","title":"Incidente de identidade: qual sintoma?","detail":"Muitos logins com falha indicam um ataque de força bruta / credential stuffing. Por outro lado, um login bem-sucedido, mas inesperado (de um IP incomum/em horário incomum), indica que a conta pode ter sido comprometida. Em ambos os casos, colete evidências primeiro e depois responda.","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":"Rajada de logins com falha (força bruta)","next":"id_bruteforce"},{"label":"Login bem-sucedido, mas inesperado (comprometimento)","next":"id_compromised"}]},"id_bruteforce":{"kind":"solution","title":"Força bruta → bloqueie a origem e proteja a conta","detail":"Com uma rajada de logins com falha, o acesso pode ainda não ter sido obtido; o objetivo é bloquear a origem, proteger a conta com bloqueio/atraso e descartar qualquer invasão bem-sucedida.","steps":["Identifique os IPs atacantes (consultas acima) e bloqueie-os no nível de rede: firewall / pg_hba.conf reject / listener ACL / security group.","Bloqueie temporariamente a conta-alvo: 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.","Aplique um limite de tentativas de login / política de bloqueio: Oracle: FAILED_LOGIN_ATTEMPTS no profile; PostgreSQL: o módulo auth_delay (shared_preload_libraries; ele atrasa as tentativas com falha em vez de bloquear); MySQL: FAILED_LOGIN_ATTEMPTS ... PASSWORD_LOCK_TIME.","Redefina a senha da conta-alvo para um valor forte de qualquer forma (uma tentativa pode ter tido sucesso).","Verifique se alguma tentativa teve sucesso: procure um login bem-sucedido a partir do mesmo IP; se houver, siga também o ramo de comprometimento.","Registre o incidente com uma linha do tempo e siga a etapa de hardening para medidas permanentes ('Medidas permanentes pós-incidente' a partir da raiz)."],"related":["change-password","list-users"],"playbook":"harden-sql"},"id_compromised":{"kind":"solution","title":"Conta comprometida → interrompa, investigue, troque as credenciais","detail":"Um login bem-sucedido inesperado indica que a conta foi comprometida. Primeiro interrompa a conta e suas sessões, investigue o que ela fez, depois redefina a senha e restrinja a origem de acesso.","steps":["Bloqueie a conta imediatamente (comandos LOCK/DISABLE acima) e encerre suas sessões ativas: 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.","Investigue o que a conta fez em suas sessões: as consultas executadas, as tabelas acessadas e quaisquer operações GRANT/CREATE na trilha de auditoria/logs.","Redefina a senha para um valor forte e troque todas as credenciais de serviço/aplicação relacionadas.","Procure novas contas ou alterações de privilégio que o atacante possa ter criado (siga também o ramo de privilégios).","Restrinja a origem de acesso: permita que a conta se conecte apenas a partir de IPs conhecidos (pg_hba.conf / listener ACL / firewall).","Siga a etapa de hardening para medidas permanentes ('Medidas permanentes pós-incidente' a partir da raiz)."],"related":["change-password","list-users","show-privileges"],"playbook":"harden-sql"},"privilege":{"kind":"solution","title":"Escalonamento de privilégios → audite e revogue privilégios excessivos","detail":"Um GRANT inesperado, uma atribuição de role ou uma nova conta com privilégios elevados pode ser a segunda fase de um comprometimento (persistência/escalonamento de privilégios). Audite as alterações recentes de privilégios, revogue as que não forem legítimas e volte ao princípio do menor privilégio.","steps":["Audite as alterações recentes de privilégios: Oracle: SELECT * FROM dba_audit_trail WHERE action_name IN ('GRANT','REVOKE','CREATE USER') ORDER BY timestamp DESC;  SQL Server: eventos GRANT no default trace / Server Audit e SELECT * FROM sys.server_permissions;  MySQL: entradas GRANT no audit log e SELECT * FROM mysql.user;  MongoDB: db.getRoles({showPrivileges:true}).","Liste os privilégios atuais: 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'@'%';","Revogue os privilégios excessivos ilegítimos: 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'@'%';","Procure e remova contas ocultas/de reserva que o atacante possa ter criado (registros inesperados de CREATE USER).","Revise e restrinja privilégios excessivos concedidos a PUBLIC ou a roles amplas.","Verifique se as alterações correspondem a uma solicitação de mudança legítima; trate tudo o que não corresponder como parte do incidente e siga a etapa de hardening."],"related":["show-privileges","list-users","create-user-grant"],"playbook":"harden-sql"},"data":{"kind":"solution","title":"Vazamento de dados → corte o acesso e determine o escopo","detail":"Consultas/exportações anormalmente grandes ou conexões externas inesperadas indicam vazamento de dados. Primeiro corte as conexões perigosas ativas e depois determine o escopo com a trilha de auditoria/logs: quais dados foram acessados, por quem e quando.","steps":["Revise as origens das conexões ativas: 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.","Corte imediatamente as conexões suspeitas/externas e bloqueie a conta envolvida (comandos KILL/LOCK).","Bloqueie a origem no nível de rede: feche o bloco de IPs suspeito com firewall / pg_hba.conf / listener ACL.","Revise o audit log: determine quais tabelas foram alvo de SELECT/EXPORT, as contagens de linhas e a janela de tempo (Oracle unified_audit_trail; SQL Server sys.fn_get_audit_file; logs do pgaudit no PostgreSQL; MongoDB auditLog).","Procure rastros de exportação: grandes result sets, COPY / SELECT ... INTO OUTFILE, mongoexport, padrões de leitura em massa.","Documente o escopo dos dados afetados (quais tabelas, quais campos pessoais/confidenciais) e o possível volume de dados; avalie as obrigações legais/de notificação e siga a etapa de hardening."],"related":["show-privileges","list-users"],"playbook":"harden-sql"},"harden":{"kind":"solution","title":"Hardening permanente pós-incidente","detail":"Após a resposta emergencial, aplique controles permanentes para evitar a recorrência: habilite a auditoria, aplique o menor privilégio, restrinja o acesso de rede e registre o incidente por completo.","steps":["Habilite a auditoria: capture eventos críticos (logins, GRANT/REVOKE, acesso a tabelas sensíveis) na trilha de auditoria; para detalhes, siga a árvore 'Configuração de auditoria'.","Menor privilégio: conceda a cada conta apenas os privilégios de que ela precisa, separe contas compartilhadas/de serviço, desabilite contas não utilizadas.","Política de senha/identidade: senhas fortes, rotação regular, autenticação multifator quando possível e identidade centralizada (LDAP/Kerberos).","Restrição de rede: abra o banco apenas para os servidores de aplicação (firewall, security group, pg_hba.conf, listener ACL); bloqueie o acesso direto pela internet.","Criptografia: habilite TLS em trânsito e, quando exigido, criptografia em repouso.","Monitoramento/alertas: configure alertas para picos de logins com falha, novos GRANTs e volumes de dados anormais.","Registro do incidente: documente a linha do tempo, os ativos afetados, as ações tomadas e as lições aprendidas; atualize o runbook."],"related":["list-users","show-privileges","change-password"]}}},"solver/audit-setup.json":{"id":"audit-setup","title":"Configuração de auditoria","icon":"🧾","category":"Segurança","intro":"Uma árvore de decisão que, conforme o que você deseja auditar (logins/sessões, alterações de DDL/schema, acesso a dados ou alterações de privilégios), habilita a auditoria para esse escopo no engine de banco correto e, em seguida, fornece as etapas para ler os registros e para retenção/rotação.","start":"root","nodes":{"root":{"kind":"step","title":"O que você deseja auditar?","detail":"Escolha o escopo da auditoria. Auditar tudo gera ruído e custo; restrinja às suas necessidades. Você quer acompanhar eventos de login/sessão, alterações de DDL/schema, acesso a dados (DML/SELECT) ou alterações de privilégios (GRANT/REVOKE)?","choices":[{"label":"Logins / sessões (login, connect)","next":"login"},{"label":"Alterações de DDL / schema (CREATE/ALTER/DROP)","next":"ddl"},{"label":"Acesso a dados (DML / SELECT)","next":"dml"},{"label":"Alterações de privilégios (GRANT / REVOKE)","next":"grants"},{"label":"Leitura dos registros de auditoria e retenção / rotação","next":"retention"}]},"login":{"kind":"solution","title":"Auditoria de logins / sessões","detail":"Registra logins bem-sucedidos e com falha: quem se conectou, de onde e quando. É a base para detectar acessos não autorizados e tentativas de força bruta. Habilite a política correspondente em cada engine e depois leia e retenha os registros.","steps":["Oracle (Unified Auditing): CREATE AUDIT POLICY login_pol ACTIONS LOGON, LOGOFF;  AUDIT POLICY login_pol;  (para falhas: AUDIT POLICY login_pol WHENEVER NOT SUCCESSFUL;).","PostgreSQL: defina log_connections=on e log_disconnections=on no postgresql.conf e faça reload; as conexões são registradas sem necessidade do pgaudit.","MySQL/MariaDB: instale o plugin audit_log (INSTALL PLUGIN audit_log ...) e execute SET GLOBAL audit_log_policy='LOGINS'; (MariaDB: server_audit_events='CONNECT').","SQL Server: crie um Server Audit (CREATE SERVER AUDIT ...), adicione FAILED_LOGIN_GROUP e SUCCESSFUL_LOGIN_GROUP a uma Server Audit Specification e aplique ENABLE em ambos.","MongoDB: inicie com --auditDestination file --auditFilter '{ atype: { $in: [\"authenticate\", \"logout\"] } }' (Enterprise/Percona).","Redis: acompanhe as tentativas de autenticação/comandos com falha com ACL LOG (para detalhes, use o ACL log, não 'notify').","Elasticsearch: defina xpack.security.audit.enabled: true no elasticsearch.yml e adicione authentication_success, authentication_failed à lista include.","Para ler e reter/rotacionar os registros, siga a etapa 'Leitura dos registros de auditoria e retenção / rotação' a partir da raiz."],"related":["list-users","change-password"]},"ddl":{"kind":"solution","title":"Auditoria de alterações de DDL / schema","detail":"Registra alterações de schema como CREATE/ALTER/DROP. Usada para detectar alterações não autorizadas de objetos, tabelas ocultas/backdoors e schema drift.","steps":["Oracle: CREATE AUDIT POLICY ddl_pol ACTIONS CREATE TABLE, ALTER TABLE, DROP TABLE, CREATE USER, ALTER USER;  AUDIT POLICY ddl_pol;","PostgreSQL (pgaudit): carregue-o com shared_preload_libraries='pgaudit' e depois ALTER SYSTEM SET pgaudit.log='ddl'; SELECT pg_reload_conf();","MySQL/MariaDB: com audit_log, SET GLOBAL audit_log_policy='ALL'; depois filtre as instruções DDL no log (MariaDB: server_audit_events='QUERY_DDL').","SQL Server: adicione SCHEMA_OBJECT_CHANGE_GROUP (e DATABASE_OBJECT_CHANGE_GROUP) a uma Database Audit Specification e aplique ENABLE.","MongoDB: --auditFilter '{ atype: { $in: [\"createCollection\",\"dropCollection\",\"createIndex\",\"dropIndex\",\"createDatabase\",\"dropDatabase\"] } }'.","Elasticsearch: adicione os eventos relacionados a index_creation/index_deletion à lista include da auditoria; para alterações de schema (mapping), registre as chamadas _mapping como requests.","Para ler e reter/rotacionar os registros, siga a etapa 'Leitura dos registros de auditoria e retenção / rotação' a partir da raiz."],"related":["show-privileges"]},"dml":{"kind":"solution","title":"Auditoria de acesso a dados (DML / SELECT)","detail":"Registra o acesso de leitura/gravação (SELECT/INSERT/UPDATE/DELETE) a tabelas sensíveis. Como pode gerar alto volume, limite a auditoria aos objetos sensíveis. É crítica para detecção de vazamentos e conformidade (KVKK/GDPR).","steps":["Restrinja o escopo: audite apenas tabelas/colunas sensíveis, não todos os dados (para controlar ruído e custo).","Oracle: CREATE AUDIT POLICY dml_pol ACTIONS SELECT, INSERT, UPDATE, DELETE ON HR.SALARIES;  AUDIT POLICY dml_pol;","PostgreSQL (pgaudit): para registro amplo, use ALTER SYSTEM SET pgaudit.log='read,write'; ou, para auditoria direcionada no nível de objeto, conceda privilégios à role de auditoria somente nas tabelas relevantes e defina pgaudit.role.","MySQL/MariaDB: registre apenas as tabelas/usuários relevantes com um filtro do audit_log (audit_log_filter / MariaDB server_audit_events='QUERY_DML').","SQL Server: adicione as ações SELECT, INSERT, UPDATE, DELETE para tabelas específicas e um principal (ex.: public) a uma Database Audit Specification e aplique ENABLE.","MongoDB: --auditFilter '{ atype: \"authCheck\", \"param.command\": { $in: [\"find\",\"insert\",\"update\",\"delete\"] }, \"param.ns\": \"db.sensitive\" }' (atenção ao volume).","Elasticsearch: adicione access_granted/access_denied à lista include da auditoria e use emit_request_body para ver qual índice uma consulta atinge (cuidado ao registrar bodies com dados sensíveis).","Para ler e reter/rotacionar os registros, siga a etapa 'Leitura dos registros de auditoria e retenção / rotação' a partir da raiz."],"related":["show-privileges","list-users"]},"grants":{"kind":"solution","title":"Auditoria de alterações de privilégios (GRANT / REVOKE)","detail":"Registra alterações de privilégios e roles (GRANT/REVOKE, atribuição de role, criação de usuário). É a base para detectar escalonamento de privilégios e contas backdoor; geralmente é uma auditoria de baixo volume, mas de alto valor.","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();  (captura eventos GRANT/REVOKE/CREATE ROLE).","MySQL/MariaDB: registre as instruções GRANT/REVOKE/CREATE USER com o audit_log (política 'ALL' ou DDL) e mantenha as instruções de ACL no filtro.","SQL Server: adicione SERVER_PERMISSION_CHANGE_GROUP, SERVER_ROLE_MEMBER_CHANGE_GROUP e DATABASE_PERMISSION_CHANGE_GROUP a uma Server Audit Specification e aplique ENABLE.","MongoDB: --auditFilter '{ atype: { $in: [\"grantRolesToUser\",\"revokeRolesFromUser\",\"createUser\",\"dropUser\",\"createRole\"] } }'.","Elasticsearch: para alterações de roles/usuários, registre na trilha de auditoria os eventos de requests relacionados à segurança (chamadas às APIs de realm/role).","Para ler e reter/rotacionar os registros, siga a etapa 'Leitura dos registros de auditoria e retenção / rotação' a partir da raiz."],"related":["show-privileges","create-user-grant","list-users"]},"retention":{"kind":"solution","title":"Leitura dos registros de auditoria e retenção / rotação","detail":"A auditoria só é útil quando os registros são lidos e retidos. Defina aqui como consultar os registros, onde eles ficam armazenados e a política de retenção/rotação que mantém seu crescimento sob controle.","steps":["Leia os registros: Oracle: SELECT event_timestamp, dbusername, action_name, object_name, sql_text FROM unified_audit_trail ORDER BY event_timestamp DESC;  PostgreSQL: a saída do pgaudit vai para o arquivo de log do servidor (log_directory); filtre as linhas 'AUDIT:' com grep.","SQL Server: SELECT * FROM sys.fn_get_audit_file('D:\\audit\\*.sqlaudit', DEFAULT, DEFAULT);  MySQL: leia o arquivo do audit_log (JSON/XML) ou o server_audit.log do MariaDB; MongoDB: faça o parse do audit.json; Elasticsearch: consulte os índices .security-audit-*.","Defina o período de retenção (conforme os requisitos de conformidade, ex.: 90 dias / 1 ano) e registre-o na política.","Rotação/limpeza: Oracle: arquive/expurgue registros antigos com DBMS_AUDIT_MGMT.SET_LAST_ARCHIVE_TIMESTAMP e CLEAN_AUDIT_TRAIL; para logs em arquivo de PostgreSQL/MySQL/MongoDB, rotacione por tamanho/tempo com logrotate.","Elasticsearch: defina uma política ILM (rollover + delete) para os índices de auditoria.","Envie os registros de auditoria para um local imutável (WORM) com acesso separado dos DBAs (segregação de funções); restrinja o acesso.","Monitore o crescimento do armazenamento: verifique periodicamente se a auditoria não está enchendo o disco nem afetando excessivamente o desempenho."],"related":["list-users","show-privileges"]}}},"solver/decide-ha.json":{"id":"decide-ha","title":"Decisão: qual solução de HA/DR?","icon":"🧭","category":"Guia de decisão","intro":"A escolha de uma solução de alta disponibilidade e recuperação de desastres não começa pela tecnologia, mas pelo equilíbrio entre os requisitos de negócio (RTO/RPO), a necessidade de distribuição geográfica e o custo. A partir da sua tolerância a indisponibilidade e perda de dados, esta árvore indica a abordagem correta entre réplicas síncronas, standbys assíncronos, clusters com failover automático e backup+PITR.","start":"root","nodes":{"root":{"kind":"step","title":"Qual é a sua tolerância a perda de dados (RPO)?","detail":"Comece pela restrição mais rígida: em um desastre, quantos segundos de dados você pode se dar ao luxo de perder? Se for exigida perda de dados zero (RPO=0), a replicação síncrona é obrigatória; se alguns segundos/minutos forem aceitáveis, abrem-se soluções assíncronas e abordagens mais baratas. A meta de RPO geralmente orienta todas as outras decisões.","choices":[{"label":"Perda de dados zero é obrigatória (RPO = 0)","next":"rpo_zero"},{"label":"Alguns segundos/minutos de perda de dados são aceitáveis","next":"rpo_soft"}]},"rpo_zero":{"kind":"step","title":"Também é exigida assunção automática e rápida (RTO baixo)?","detail":"Você quer perda de dados zero; mas com que rapidez precisa voltar quando o primário cair? Failover automático em segundos, ou uma breve janela de intervenção manual é aceitável? Isso define a diferença entre uma réplica síncrona simples e um cluster totalmente automatizado.","choices":[{"label":"É necessário failover automático em segundos","next":"sol_cluster"},{"label":"Assunção manual/planejada basta; perda zero vem primeiro","next":"sol_sync"}]},"rpo_soft":{"kind":"step","title":"É necessária outra região/geografia (DR)?","detail":"Se alguma perda de dados for aceitável, a verdadeira questão é o escopo da resiliência: é preciso se proteger contra a perda de um data center/região inteiro, ou basta a proteção contra a falha de um único nó na mesma região? Se a distribuição geográfica for necessária, o standby assíncrono ganha destaque; caso contrário, avaliam-se opções que priorizam o custo.","choices":[{"label":"Sim, uma região separada contra desastres geográficos é obrigatória","next":"sol_async"},{"label":"Não, orçamento e simplicidade vêm primeiro","next":"budget"}]},"budget":{"kind":"step","title":"Você aceita um tempo de recuperação longo (RTO alto)?","detail":"Você vai ficar em uma única região e tolera alguma perda de dados. Seu objetivo é o menor custo, ou você quer um nó standby que assuma rapidamente em caso de falha? Se uma recuperação de horas for aceitável, apenas backup+PITR é o caminho mais econômico; caso contrário, você precisa de um warm standby.","choices":[{"label":"Sim, uma recuperação de horas é aceitável (mais barato)","next":"sol_backup"},{"label":"Não, é necessário um warm standby que assuma em minutos","next":"sol_async"}]},"sol_sync":{"kind":"solution","title":"Recomendação: réplica síncrona (perda de dados zero)","detail":"O primário não conclui um commit até que pelo menos um standby o confirme; assim, mesmo que o primário seja perdido, nenhuma transação confirmada é perdida (RPO=0). A solução ideal dentro de uma região, em uma rede de baixa latência.","steps":["Por quê: um commit não é concluído até que as transações confirmadas sejam gravadas no standby, então a perda de dados é matematicamente zero.","Quando: OLTP financeiro/crítico, na mesma região (mesma zona de disponibilidade ou adjacente), com rede de baixo RTT disponível.","Exemplo: PostgreSQL synchronous_commit + synchronous_standby_names, MySQL Group Replication / semisync, Oracle Data Guard SYNC (Maximum Protection/Availability).","Atenção: a confirmação síncrona adiciona latência de rede a cada commit; se o standby ficar lento/desconectar e houver apenas uma cópia síncrona, o primário também pode parar de aceitar gravações. Projete com pelo menos dois standbys ou um fallback adequado.","Atenção: não replique de forma síncrona para uma região remota/de alta latência; o desempenho de gravação despenca. Use replicação assíncrona para DR geográfico."],"related":["replication-status","promote-failover"]},"sol_async":{"kind":"solution","title":"Recomendação: standby assíncrono (DR geográfico)","detail":"O standby aplica as alterações como um fluxo, sem atrasar os commits do primário. É a forma padrão de manter uma cópia em outra região sem prejudicar o desempenho de gravação; em troca, aceita-se uma pequena janela de perda de dados (igual ao lag de replicação).","steps":["Por quê: o primário não espera a confirmação do standby, então a replicação para uma região remota não adiciona latência de gravação.","Quando: quando é necessária recuperação de desastres no nível de região/data center e uma perda de dados da ordem de segundos é aceitável.","Exemplo: PostgreSQL streaming replication (async), replicação assíncrona do MySQL, Oracle Data Guard ASYNC (Maximum Performance).","Atenção: no failover você pode perder tantos dados quanto o lag; monitore o lag de replicação continuamente e configure alertas de limite.","Atenção: a assunção geralmente é feita manualmente ou por orquestração externa; um procedimento de failover claro e exercícios regulares são essenciais."],"related":["replication-status","promote-failover"]},"sol_cluster":{"kind":"solution","title":"Recomendação: cluster com failover automático","detail":"Uma solução de cluster que combina monitoramento de saúde, eleição de líder e assunção automática; visa tanto RTO baixo (failover automático em segundos) quanto RPO baixo/zero com uma cópia síncrona. A sobrecarga operacional é maior, mas a intervenção humana é minimizada.","steps":["Por quê: o gerenciador do cluster detecta automaticamente a falha do primário, promove uma cópia saudável e redireciona o tráfego; nada de intervenção manual à meia-noite.","Quando: se RTO baixo e RPO baixo forem ambos obrigatórios e a equipe de operações conseguir gerenciar a complexidade adicional.","Exemplo: Patroni/etcd para PostgreSQL, MySQL InnoDB Cluster (Group Replication + MySQL Router), SQL Server Always On Availability Groups, Oracle RAC + Data Guard com Fast-Start Failover (o failover automático exige FSFO e um observer).","Atenção: o risco de split-brain é real; não implante sem fencing/quorum adequados (número ímpar de nós, um armazenamento distribuído confiável).","Atenção: o próprio cluster é uma nova superfície de falha; ensaie o failover regularmente e valide a automação em condições reais."],"related":["promote-failover","replication-status"]},"sol_backup":{"kind":"solution","title":"Recomendação: backup + PITR (mais econômico)","detail":"Em vez de um standby em execução, mantêm-se apenas backups regulares e recuperação point-in-time (PITR) via WAL/logs arquivados. É a solução de menor custo; o preço é que a recuperação pode levar horas (RTO alto).","steps":["Por quê: não há custo de um segundo nó em execução contínua; mantêm-se apenas o armazenamento de backup e os logs arquivados.","Quando: sistemas não críticos com alta tolerância a indisponibilidade; ambientes de dev/teste; quando orçamento e simplicidade vêm primeiro.","Exemplo: PITR com backup físico + logs arquivados (PG base backup + WAL, Oracle RMAN + archivelog, MySQL xtrabackup + binlog).","Atenção: o RTO é alto — o tempo de restore + aplicação de logs cresce com o tamanho dos dados; meça-o para confirmar que cabe no tempo que você aceita.","Atenção: um backup não testado não é um backup; execute exercícios de restore e verificação de backup regularmente."],"related":["last-backup-status","logical-dump"]}}},"solver/decide-isolation.json":{"id":"decide-isolation","title":"Decisão: qual nível de isolamento?","icon":"🧭","category":"Guia de decisão","intro":"O nível de isolamento de transação determina o equilíbrio entre concorrência e consistência. Isolamento maior significa menos anomalias, porém mais bloqueios/conflitos e novas tentativas. Esta árvore ajuda a escolher entre Read Committed, Repeatable Read/Snapshot e Serializable com base em quais anomalias de leitura (dirty, non-repeatable, phantom) você pode tolerar.","start":"root","nodes":{"root":{"kind":"step","title":"Você pode tolerar dirty reads?","detail":"Comece pela anomalia mais básica: uma transação deve poder ler dados que ainda não foram confirmados (e que podem sofrer rollback)? Quase nenhuma aplicação séria quer isso; na maioria dos engines modernos, o padrão já impede dirty reads. Só é relaxado para contagens aproximadas/analíticas e velocidade máxima.","choices":[{"label":"Não, devo ler apenas dados confirmados","next":"committed"},{"label":"Sim, uma leitura aproximada basta (raro)","next":"sol_read_uncommitted"}]},"committed":{"kind":"step","title":"Você precisa ver o mesmo resultado ao reler dentro da mesma transação?","detail":"Descartados os dirty reads, a próxima pergunta: se você ler a mesma linha duas vezes dentro de uma transação, é um problema ver um valor diferente porque alguém fez commit no meio (non-repeatable read), ou que surjam novas linhas (phantom)? Lógicas que exigem consistência de relatório/cálculo geralmente precisam de um snapshot consistente.","choices":[{"label":"Não, tudo bem cada instrução ver os dados confirmados mais recentes","next":"sol_read_committed"},{"label":"Sim, é necessário um snapshot consistente para a transação inteira","next":"consistent"}]},"consistent":{"kind":"step","title":"As transações concorrentes precisam ser logicamente totalmente ordenadas?","detail":"Você quer leituras consistentes; isso basta, ou as transações concorrentes precisam produzir um resultado como se tivessem sido executadas uma a uma, em sequência (serializable)? Se você puder tolerar anomalias sutis como write skew (ex.: duas transações lendo linhas diferentes e gravando de forma a invalidar uma à outra), Snapshot basta; caso contrário, é necessária a serialização completa.","choices":[{"label":"Não, um snapshot consistente basta","next":"sol_repeatable_read"},{"label":"Sim, nenhuma anomalia de concorrência é aceitável","next":"sol_serializable"}]},"sol_read_uncommitted":{"kind":"solution","title":"Recomendação: Read Uncommitted (apenas casos especiais)","detail":"O isolamento mais baixo; permite dirty reads. Lê quase sem esperar por locks, mas você pode ver dados que podem sofrer rollback. Não recomendado para aplicações de uso geral.","steps":["Por quê: o leitor não espera pelo lock do escritor; concorrência máxima, mas sem garantia de consistência.","Quando: apenas em casos como métricas aproximadas/contagens de progresso, em que a exatidão não importa.","Atenção: no PostgreSQL este nível se comporta como Read Committed, e o Oracle nem oferece Read Uncommitted; dirty reads reais aparecem principalmente no SQL Server, baseado em locks (NOLOCK).","Atenção: 'NOLOCK para ganhar velocidade' não deve virar hábito permanente; traz o risco de ler linhas erradas/duplicadas/ausentes."]},"sol_read_committed":{"kind":"solution","title":"Recomendação: Read Committed (OLTP padrão)","detail":"Cada instrução vê os dados mais recentes confirmados naquele momento; dirty reads são impedidos. É o padrão na maioria dos engines e oferece o melhor equilíbrio entre concorrência e consistência para cargas OLTP típicas.","steps":["Por quê: impede dirty reads sem obrigar a transação a manter locks por tempo desnecessário; oferece alta concorrência.","Quando: transações OLTP curtas e direcionadas; o padrão correto para a grande maioria das aplicações web.","Exemplo: Read Committed é o padrão no PostgreSQL, SQL Server e Oracle (no Oracle, a consistência é garantida por um snapshot no nível de instrução).","Atenção: duas leituras na mesma transação podem retornar resultados diferentes (non-repeatable/phantom); não baseie nele lógicas que precisam de relatórios consistentes.","Atenção: o padrão do MySQL/InnoDB é Repeatable Read; esteja atento à diferença entre engines ao migrar."]},"sol_repeatable_read":{"kind":"solution","title":"Recomendação: Repeatable Read / Snapshot (leituras consistentes)","detail":"A transação trabalha sobre um snapshot consistente fixado no seu início (ou na sua primeira leitura); as leituras não mudam durante a transação. Com MVCC, leitores não bloqueiam escritores e escritores não bloqueiam leitores.","steps":["Por quê: oferece uma visão fixa para a transação inteira; impede non-repeatable reads (e, na prática, também phantoms em engines MVCC), tornando consistentes as lógicas de relatório/cálculo com muitas leituras.","Quando: relatórios, conciliações e cálculos em lote que leem os mesmos dados várias vezes em uma transação e precisam de resultados consistentes.","Exemplo: Repeatable Read padrão do MySQL/InnoDB; SQL Server SNAPSHOT (row versioning); PostgreSQL REPEATABLE READ; o SERIALIZABLE do Oracle tem, na verdade, semântica de snapshot.","Atenção: não impede anomalias de serialização como write skew; suba para Serializable se a regra de negócio exigir.","Atenção: snapshot/row versioning pode causar crescimento do tempdb ou do undo/version store; transações longas incham as versões antigas."]},"sol_serializable":{"kind":"solution","title":"Recomendação: Serializable (isolamento completo)","detail":"O isolamento mais alto: transações concorrentes produzem um resultado como se tivessem sido executadas serialmente (uma a uma, em sequência). Impede todas as anomalias de leitura e o write skew; o preço é mais conflitos e a necessidade de novas tentativas.","steps":["Por quê: garante que o resultado seja sempre equivalente a uma execução serial válida; elimina todas as anomalias de concorrência.","Quando: lógicas com invariantes críticas para a correção: verificações de saldo/estoque, casos em que reserva dupla nunca pode acontecer.","Exemplo: PostgreSQL SSI (Serializable Snapshot Isolation), SQL Server SERIALIZABLE (range locks); no Oracle, a serialização verdadeira é tratada no nível da aplicação.","Atenção: falhas de serialização (ex.: 40001 no PG) são comportamento esperado; uma lógica de retry que reexecute automaticamente a transação na aplicação é OBRIGATÓRIA.","Atenção: o throughput pode cair sob carga com muitos conflitos; aplique-o não em todo lugar, mas apenas às transações em que a correção é crítica."]}}},"solver/decide-sqlnosql.json":{"id":"decide-sqlnosql","title":"Decisão: SQL ou NoSQL (qual família de banco de dados)?","icon":"🧭","category":"Guia de decisão","intro":"A escolha da família de banco de dados correta é determinada pelo formato do modelo de dados, pelas suas prioridades de consistência e escala e pela complexidade das suas consultas. Generalizações como 'NoSQL é mais moderno' são enganosas; cada família é projetada para padrões de acesso específicos. A partir da estrutura dos dados, esta árvore orienta você para a ferramenta certa entre engines relacionais, de documentos, chave-valor e de busca, e lembra a abordagem poliglota quando necessário.","start":"root","nodes":{"root":{"kind":"step","title":"Qual é a natureza dos dados e o padrão de acesso dominante?","detail":"Comece pela pergunta mais decisiva: os dados são registros estruturados com relacionamentos fortes, documentos com schema flexível/variável, consultas simples por chave-valor, ou uma necessidade especial como busca textual? O formato dos dados e a forma como você os consulta determinam em grande parte a família.","choices":[{"label":"Registros relacionais e estruturados e consultas complexas","next":"relational_check"},{"label":"Documentos aninhados com schema flexível/variável","next":"sol_document"},{"label":"Chave-valor simples, latência muito baixa/cache","next":"sol_keyvalue"},{"label":"Busca full-text / facetada, análise de logs","next":"sol_search"}]},"relational_check":{"kind":"step","title":"A prioridade é consistência forte (ACID) ou escala horizontal?","detail":"Os dados parecem relacionais; mas qual é a sua prioridade? Joins entre várias tabelas, integridade transacional e consistência forte (ACID) são essenciais, ou o objetivo é escalar horizontalmente um volume enorme que não cabe em um único nó? O modelo relacional é o padrão correto para a maioria das cargas; ele só fica sob pressão quando a escala realmente excede um único nó.","choices":[{"label":"ACID, joins e integridade de consultas complexas vêm primeiro","next":"sol_relational"},{"label":"Escala acima de tudo, relacionamentos/joins fracos","next":"sol_document"}]},"sol_relational":{"kind":"solution","title":"Recomendação: banco de dados relacional (RDBMS)","detail":"O padrão correto para cargas com dados estruturados e fortemente relacionados que exigem integridade transacional. Garantias ACID, um engine de consultas SQL maduro e joins permitem responder a perguntas complexas de forma confiável.","steps":["Por quê: oferece transações ACID, integridade de foreign keys e consistência forte, além de um planner maduro que otimiza consultas complexas que fazem join de várias tabelas.","Quando: cargas OLTP e de relatórios em que relacionamentos e consistência são críticos, como finanças, pedidos/estoque, ERP/CRM.","Exemplo: PostgreSQL, MySQL, Oracle, SQL Server; para necessidades de séries temporais, extensões como PostgreSQL + TimescaleDB.","Atenção: alterações de schema (migrations) exigem disciplina; se as alterações de schema forem frequentes e imprevisíveis, avalie o modelo de documentos.","Atenção: se você atingir o limite de gravação/dados de um único nó, escale com read replicas, particionamento e, se necessário, sharding."],"related":["create-partition"]},"sol_document":{"kind":"solution","title":"Recomendação: banco de dados de documentos","detail":"Armazena dados flexíveis e aninhados, com schema que muda com frequência, em sua forma natural (documentos semelhantes a JSON). Adequado para aplicações que leem/gravam principalmente por meio de um único documento, precisam de poucos joins e de escala horizontal.","steps":["Por quê: o schema é flexível; os documentos podem ganhar ou perder campos, trazer estruturas aninhadas em uma única leitura e se prestam à escala horizontal (sharding).","Quando: modelos de dados centrados em documentos, de estrutura variável e em rápida evolução, como catálogos, perfis de usuário, conteúdo/CMS, registros de eventos.","Exemplo: MongoDB, Couchbase; no mundo relacional, o JSONB (PostgreSQL) oferece flexibilidade semelhante de forma limitada.","Atenção: joins complexos entre vários documentos e relatórios são pontos fracos; se os relacionamentos predominarem, o modelo relacional é mais adequado.","Atenção: a responsabilidade pela consistência e pela validação de schema passa em grande parte para a aplicação; proteja a qualidade dos dados no código."]},"sol_keyvalue":{"kind":"solution","title":"Recomendação: armazenamento chave-valor / cache","detail":"Projetado para cargas que precisam de leituras/gravações muito rápidas por chave e nenhuma consulta complexa. Geralmente roda em memória e oferece latência de microssegundos/milissegundos; ideal para tarefas como cache, sessões e contadores.","steps":["Por quê: latência extremamente baixa e alto throughput para acesso simples por chave; as estruturas em memória tiram carga do banco relacional.","Quando: camada de cache, armazenamento de sessões, contadores de rate limit, leaderboards, filas temporárias/pub-sub.","Exemplo: Redis, Memcached; o Redis também oferece estruturas ricas como lists/sets/sorted sets e opções de persistência.","Atenção: geralmente não é a fonte única da verdade; mantenha os dados de origem em um banco durável e armazene aqui os dados derivados/em cache.","Atenção: a memória é limitada e cara; planeje a política de eviction, os TTLs e as configurações de persistência/durabilidade conforme as necessidades do negócio."]},"sol_search":{"kind":"solution","title":"Recomendação: engine de busca / analytics","detail":"Um engine baseado em índice invertido, especializado em busca full-text, ranqueamento por relevância, filtragem facetada e análise de logs/textos em alto volume. Entrega a experiência de busca que consultas LIKE relacionais não conseguem.","steps":["Por quê: com um índice invertido e scoring, realiza busca full-text, autocomplete, facets e agregações com alto desempenho.","Quando: busca de produtos/no site, análise de logs e observabilidade, aplicações que precisam de uma experiência de busca ranqueada por relevância.","Exemplo: Elasticsearch/OpenSearch, Apache Solr; o tsvector do PostgreSQL pode bastar para busca full-text em média escala.","Atenção: geralmente não é o sistema de registro principal; mantenha os dados principais em um banco relacional/de documentos e alimente o índice de busca a partir dele (CDC/sync).","Atenção: as garantias de consistência forte em tempo real são fracas (indexação near-real-time); considere a latência de indexação no projeto."],"related":["setup-cdc-replication"]}}},"solver/decide-shard-replica.json":{"id":"decide-shard-replica","title":"Decisão: sharding ou replicação (escalabilidade)?","icon":"🧭","category":"Guia de decisão","intro":"A decisão de escalabilidade do banco depende de o gargalo estar nas leituras ou nas gravações e de os dados caberem em um único nó. A estratégia errada significa complexidade desnecessária ou um gargalo não resolvido. Esta árvore primeiro lembra as opções mais baratas e simples (escala vertical, cache) e depois ajuda a escolher corretamente entre read replicas e sharding.","start":"root","nodes":{"root":{"kind":"step","title":"Você tentou primeiro o caminho mais simples: escala vertical e tuning de consultas?","detail":"Antes de partir para uma arquitetura distribuída, aproveite o ganho mais barato: aumentar o hardware (CPU/RAM/IOPS), adicionar índices ausentes e corrigir consultas caras resolve a maioria dos gargalos. Adicione complexidade somente quando essas opções se esgotarem.","choices":[{"label":"Não / ainda não cheguei ao limite","next":"sol_vertical"},{"label":"Sim, escala vertical e tuning não bastam","next":"bottleneck"}]},"bottleneck":{"kind":"step","title":"O gargalo está nas leituras, ou nas gravações/volume de dados?","detail":"Isole a origem do problema de escalabilidade: muitas consultas de leitura estão sufocando um único nó (carga de leitura), ou a taxa de gravação ou o tamanho total dos dados excede a capacidade de um único nó (carga de gravação/volume)? Essa distinção é a diferença fundamental entre réplicas e sharding.","choices":[{"label":"O tráfego de leitura predomina, as gravações cabem em um único nó","next":"read_path"},{"label":"A taxa de gravação ou o volume de dados excede um único nó","next":"sol_sharding"}]},"read_path":{"kind":"step","title":"As leituras são repetitivas/cacheáveis, ou atuais e variadas?","detail":"Divida o gargalo de leitura mais um passo: os mesmos resultados são lidos repetidamente (um cache é muito eficaz), ou as leituras pedem dados variados, amplos e atuais (é necessária capacidade de leitura extra)? Isso decide entre uma camada de cache e read replicas.","choices":[{"label":"Os mesmos dados são lidos repetidamente, uma leve defasagem é aceitável","next":"sol_cache"},{"label":"Leituras variadas/atuais, é necessária capacidade bruta de leitura","next":"sol_read_replica"}]},"sol_vertical":{"kind":"solution","title":"Recomendação: escala vertical + tuning de consultas primeiro","detail":"O primeiro e mais barato caminho antes de partir para uma arquitetura distribuída. Aumentar o hardware e corrigir consultas/índices resolve a maioria dos problemas de escalabilidade sem adicionar complexidade operacional.","steps":["Por quê: menor complexidade e risco; se você permanece em um único nó, seu modelo de transação/consistência não muda e você não precisa dividir o código da aplicação.","Quando: se você ainda não chegou ao teto de hardware de um único nó, ou se o gargalo na verdade vem de consultas ruins/índices ausentes.","Passo: faça o profiling das consultas lentas, adicione os índices ausentes, corrija planos/estatísticas; depois aumente CPU/RAM/IOPS.","Atenção: a escala vertical é finita e seu custo cresce exponencialmente; um único nó continua sendo um ponto único de falha (configure uma réplica separadamente para HA).","Atenção: planeje o próximo passo (réplicas/sharding) com antecedência à medida que o teto se aproxima; migrações às pressas são arriscadas."]},"sol_read_replica":{"kind":"solution","title":"Recomendação: read replicas (escala de leitura)","detail":"As gravações permanecem em um único nó (o primário) enquanto o tráfego de leitura é distribuído para uma ou mais réplicas. É a forma padrão de aumentar a capacidade bruta de leitura e a resiliência em cargas com muitas leituras.","steps":["Por quê: as consultas de leitura são distribuídas por várias cópias; o primário cuida apenas das gravações e o throughput de leitura cresce de forma quase linear.","Quando: cargas com alta relação leitura/gravação; separar consultas de relatórios e analytics do primário; ganhar ao mesmo tempo um standby de HA.","Exemplo: réplicas de streaming do PostgreSQL, réplicas do MySQL + roteamento por proxy, separação de leitura/gravação na aplicação (read-write split).","Atenção: com réplicas assíncronas, o lag de replicação cria um problema de read-your-writes (você não consegue ler imediatamente o que acabou de gravar); direcione as leituras críticas para o primário.","Atenção: réplicas não resolvem um gargalo de gravação; o único nó gravador continua sendo o limite — se as gravações também forem gargalo, é necessário sharding."],"related":["replication-status"]},"sol_cache":{"kind":"solution","title":"Recomendação: camada de cache","detail":"Manter resultados relidos com frequência em uma camada rápida em memória reduz drasticamente a carga do banco. Com o padrão correto, responde sem ir ao banco, reduzindo tanto a latência quanto a carga.","steps":["Por quê: leituras repetidas são respondidas na velocidade da memória sem sequer chegar ao banco; é o método de escala de leitura com a maior relação benefício/custo.","Quando: os mesmos dados são lidos muitas vezes e uma leve defasagem é aceitável; ex.: detalhes de produtos, configurações, dados de referência.","Exemplo: o padrão cache-aside com Redis/Memcached; a aplicação vai primeiro ao cache e, em caso de miss, ao banco.","Atenção: a invalidação de cache é difícil; projete explicitamente o TTL e a estratégia de atualização/expurgo na gravação.","Atenção: não dependa de um cache defasado para leituras que exigem consistência forte (dinheiro/estoque); atenda essas leituras a partir da origem."]},"sol_sharding":{"kind":"solution","title":"Recomendação: sharding (escala de gravação/dados)","detail":"Os dados são divididos por uma shard key e distribuídos entre vários nós independentes; cada nó é dono de uma fatia dos dados e de suas gravações. É a forma de escalar a taxa de gravação e o volume total de dados, mas adiciona complexidade significativa.","steps":["Por quê: gravações e armazenamento são distribuídos entre vários nós; os limites de gravador único e de dados em nó único desaparecem e a escala horizontal se torna possível.","Quando: quando o throughput de gravação ou o tamanho dos dados não cabe mais em um único nó (nem com read replicas); quando não resta outra opção.","Exemplo: roteamento de shards na camada de aplicação, Vitess (MySQL), Citus (PostgreSQL), sharding nativo em bancos de documentos.","Atenção: a escolha da shard key é crítica e difícil de reverter; uma chave ruim cria hotspots e distribuição desigual. Escolha uma chave de alta cardinalidade que corresponda ao padrão de acesso.","Atenção: joins, transações e unicidade entre shards ficam difíceis; a complexidade da aplicação, o rebalanceamento (resharding) e a carga operacional aumentam significativamente."],"related":["create-partition"]}}},"solver/decide-backup.json":{"id":"decide-backup","title":"Decisão: qual estratégia de backup?","icon":"🧭","category":"Guia de decisão","intro":"Uma estratégia de backup é escolhida equilibrando três fatores: quanta perda de dados você tolera (RPO), o tamanho dos seus dados e a rapidez com que precisa se recuperar (RTO). Nenhum método serve para todos os cenários. A partir da meta de RPO, esta árvore orienta você entre dumps lógicos, backups físicos + PITR e snapshots, e lembra que 3-2-1 e verificação são inegociáveis.","start":"root","nodes":{"root":{"kind":"step","title":"Qual é a sua meta de perda de dados (RPO)?","detail":"Comece pela restrição mais decisiva: em um desastre, quantos minutos/horas de dados você pode se dar ao luxo de perder? Se for exigida perda de dados próxima de zero, o arquivamento contínuo de logs (PITR) é obrigatório; se a tolerância de backup diário/semanal for aceitável, métodos mais simples bastam. O RPO define a estrutura da estratégia.","choices":[{"label":"Próximo de zero — preciso poder voltar a qualquer ponto no tempo","next":"sol_physical_pitr"},{"label":"Backups diários/periódicos (algumas horas de perda) são aceitáveis","next":"size"},{"label":"Primeiro, lembre-me das boas práticas gerais (3-2-1 / verificação)","next":"sol_321"}]},"size":{"kind":"step","title":"Quais são os requisitos de tamanho dos dados e portabilidade?","detail":"Se backups periódicos bastam, a próxima pergunta é escala e finalidade: o banco é pequeno/médio e você quer que o backup seja portável para outro ambiente/versão, ou os dados são grandes e sua principal preocupação é voltar em minutos? Isso decide entre um dump lógico e um snapshot.","choices":[{"label":"Pequeno/médio, portável e compatível entre versões","next":"sol_logical"},{"label":"Dados grandes, a recuperação precisa ser muito rápida (RTO baixo)","next":"sol_snapshot"}]},"sol_logical":{"kind":"solution","title":"Recomendação: dump lógico","detail":"Exporta os dados no nível lógico (definições de schema + linhas); a saída é SQL/texto (pg_dump em formato plain, mysqldump) ou um dump binário específico da ferramenta (pg_dump -Fc, Oracle Data Pump). Um método flexível e portável para bancos pequenos e médios, migrações, upgrades de versão e recuperação de tabelas/objetos selecionados.","steps":["Por quê: a saída é portável (e legível em formato texto); adequada para mover entre versões/engines e para restaurar uma única tabela/objeto.","Quando: dados pequenos/médios, upgrades de versão/migrações, cópias para ambiente de desenvolvimento, necessidade de recuperação lógica (no nível de linha).","Exemplo: PostgreSQL pg_dump/pg_dumpall, MySQL mysqldump, Oracle Data Pump (expdp/impdp; produz um .dmp binário, use impdp SQLFILE= para ver o DDL como texto).","Atenção: como um restore reprocessa os dados, tanto o backup quanto o restore são muito lentos para bancos grandes (RTO alto).","Atenção: sozinho, não oferece RPO baixo; a recuperação point-in-time exige backup físico + arquivo de logs. Use as opções de consistência adequadas para obter um snapshot consistente."],"related":["logical-dump","last-backup-status"]},"sol_physical_pitr":{"kind":"solution","title":"Recomendação: backup físico + WAL/logs arquivados (PITR)","detail":"Você faz base backups físicos regulares e arquiva continuamente os logs de transação (WAL/redo/binlog). Isso permite executar Point-in-Time Recovery para qualquer momento e reduzir a perda de dados a quase zero.","steps":["Por quê: graças ao arquivamento contínuo de logs, você pode avançar até qualquer transação após o último base backup e voltar ao momento desejado (ex.: logo antes de um comando errado) — o menor RPO.","Quando: bancos de produção grandes e críticos; sistemas que precisam de RPO baixo e RTO razoável.","Exemplo: PostgreSQL base backup + arquivo de WAL (pgBackRest/barman), Oracle RMAN + archivelog, MySQL backup físico + binlog (xtrabackup).","Atenção: a configuração e a operação são mais complexas; monitore continuamente se os logs arquivados fluem sem interrupções nem lacunas — uma única lacuna quebra a cadeia de PITR.","Atenção: o armazenamento do arquivo de logs cresce continuamente; sem uma política de retenção e um plano de armazenamento, o disco enche."],"related":["last-backup-status","logical-dump"]},"sol_snapshot":{"kind":"solution","title":"Recomendação: snapshot","detail":"Tira um snapshot dos dados no nível de bloco na camada de armazenamento ou de virtualização. Backup e restore são muito rápidos mesmo para bancos muito grandes; porém, depende da infraestrutura e exige uso cuidadoso.","steps":["Por quê: uma cópia no nível de bloco é criada quase instantaneamente e os restores são muito rápidos; oferece o menor RTO para dados grandes.","Quando: terabytes de dados, recuperação rápida como prioridade; se a camada de armazenamento/nuvem suportar snapshots.","Exemplo: snapshot de SAN/LVM, snapshot de disco em nuvem (EBS etc.), snapshot de ZFS/sistema de arquivos; disparado de forma consistente com o engine do banco.","Atenção: um snapshot depende do sistema de armazenamento e geralmente fica na mesma infraestrutura; sozinho, não atende ao 3-2-1 — copie-o para fora do site (offsite).","Atenção: para ser consistente com a aplicação, o banco precisa estar no modo adequado (fsfreeze/backup mode/hot backup) no momento do snapshot; caso contrário, você obtém um backup 'crash-consistent'."],"related":["last-backup-status"]},"sol_321":{"kind":"solution","title":"Recomendação: regra 3-2-1 + offsite + verificação obrigatória","detail":"Qualquer que seja o método escolhido, estes princípios devem estar acima da estratégia. A mera existência de um backup não basta; ele precisa estar em mídias diferentes, em outro local e ser testado regularmente. É uma estrutura que complementa todas as opções acima.","steps":["3-2-1: mantenha pelo menos 3 cópias, em 2 mídias/tipos diferentes, com 1 cópia offsite.","Por que offsite: incêndio, enchente, ransomware ou a perda de uma região podem destruir de uma só vez todas as cópias em um único local; pelo menos uma cópia deve estar isolada/remota.","Verificação é obrigatória: um backup não testado não é um backup; execute exercícios reais de restore regularmente e meça o tempo de recuperação (RTO).","Imutabilidade: contra ransomware, mantenha uma cópia que não possa ser excluída/alterada (immutable/WORM) ou isolada fisicamente (air-gapped).","Atenção: monitore automaticamente a integridade (checksum) e a recuperabilidade dos backups; configure alertas para backups com falha/desatualizados. Criptografe também os próprios backups."],"related":["last-backup-status"]}}},"solver/decide-index.json":{"id":"decide-index","title":"Decisão: qual tipo de índice?","icon":"🧭","category":"Guia de decisão","intro":"O tipo de índice correto depende do padrão de acesso da consulta (igualdade, intervalo ou busca textual/JSON), da cardinalidade da coluna e do equilíbrio entre leitura e gravação. O índice errado desperdiça espaço e ainda deixa as gravações mais lentas. Esta árvore parte do formato da consulta e orienta você entre as opções B-tree, Hash, Bitmap, GIN/GiST, índice parcial e covering index, e lembra que a ordem das colunas é crítica em um índice composto.","start":"root","nodes":{"root":{"kind":"step","title":"Como a sua consulta usa esta coluna?","detail":"O padrão de acesso é o fator mais decisivo na escolha de um índice. Você apenas compara a coluna com '=', faz intervalo/ordenação (>, <, BETWEEN, ORDER BY), ou busca texto completo, um campo JSON, dados geométricos/arrays? Comece por aqui; não escolha um tipo de índice até que a necessidade esteja clara.","choices":[{"label":"Igualdade e intervalo/ordenação combinados (=, >, <, BETWEEN, ORDER BY)","next":"cardinality"},{"label":"Apenas igualdade (=), sem intervalo nem ordenação","next":"sol_hash"},{"label":"Busca full-text, em campo JSON/JSONB, array ou geométrica","next":"sol_gin_gist"},{"label":"A consulta sempre visa o mesmo pequeno subconjunto de linhas (ex.: WHERE status='active')","next":"sol_partial"}]},"cardinality":{"kind":"step","title":"Qual é a cardinalidade da coluna (número de valores distintos)?","detail":"Se houver necessidade de intervalo/ordenação, o padrão é B-tree; porém, para colunas com pouquíssimos valores distintos (baixa cardinalidade: gênero, status, sim/não) em um data warehouse com muitas leituras, um índice Bitmap pode ser melhor. A coluna tem muitos valores únicos ou poucos valores que se repetem?","choices":[{"label":"Alta cardinalidade (muitos valores únicos) ou carga OLTP","next":"coverage"},{"label":"Baixa cardinalidade e muitas leituras / data warehouse (DWH)","next":"sol_bitmap"}]},"coverage":{"kind":"step","title":"A consulta lê apenas as colunas do índice?","detail":"O padrão de acesso é adequado a um B-tree. Uma última otimização: se todas as colunas que a consulta retorna e filtra estiverem no índice, o engine pode responder apenas pelo índice, sem visitar a tabela (index-only / covering scan). Sua consulta lê poucas colunas ou precisa da maior parte da linha?","choices":[{"label":"Sim, poucas colunas; pode ser respondida sem visitar a tabela","next":"sol_covering"},{"label":"Não, o acesso padrão basta","next":"sol_btree"}]},"sol_btree":{"kind":"solution","title":"Recomendação: B-tree (padrão)","detail":"Um B-tree é uma estrutura de árvore balanceada que suporta uma ampla gama de padrões de acesso: igualdade, intervalo, ordenação (ORDER BY), correspondência de prefixo com LIKE 'abc%' e MIN/MAX. É o tipo de índice padrão na maioria dos engines relacionais e o ponto de partida certo em caso de dúvida.","steps":["Por quê: uma única estrutura atende com eficiência tanto igualdade quanto intervalo/ordenação; é o índice de uso mais geral.","Quando: consultas OLTP, WHERE + intervalo + ORDER BY juntos, chaves primárias/únicas.","A ORDEM das colunas é crítica em um índice composto: coloque primeiro a coluna mais seletiva usada com igualdade e deixe a coluna de intervalo por último. Um índice (a,b) ajuda um filtro em 'a' ou 'a,b'; geralmente não ajuda um filtro apenas em 'b' (regra do prefixo mais à esquerda).","Exemplo: o índice B-tree/B+tree padrão no PostgreSQL/Oracle/MySQL(InnoDB)/MSSQL.","Atenção: todo índice aumenta o custo de gravação (INSERT/UPDATE/DELETE) e o espaço em disco; não mantenha índices desnecessários ou duplicados."],"related":["slow-query"]},"sol_hash":{"kind":"solution","title":"Recomendação: índice Hash (apenas igualdade)","detail":"Um índice hash armazena o hash do valor da coluna e é muito rápido apenas para buscas de igualdade exata ('='). Não suporta buscas por intervalo, ordenação nem prefixo, por isso seu caso de uso é restrito.","steps":["Por quê: oferece acesso em tempo constante médio (O(1)) para buscas de igualdade; pode ser vantajoso para cargas de igualdade muito grandes que cabem em memória.","Quando: a coluna é usada apenas com '=' e nunca há necessidade de intervalo/ordenação.","Diferenças entre engines: o PostgreSQL tem índices hash, mas na prática o B-tree é suficiente e mais flexível na maioria dos casos; o MySQL(InnoDB) gerencia indexação hash apenas internamente como adaptive hash index, enquanto o engine MEMORY usa hash explicitamente; no Oracle, aparece no contexto de clusters/hash clusters.","Atenção: consultas por intervalo, BETWEEN, ORDER BY e LIKE 'abc%' não são suportados; escolha um B-tree assim que essas necessidades surgirem.","Atenção: como o B-tree padrão geralmente é suficiente, não mude para hash sem medir."],"related":["slow-query"]},"sol_bitmap":{"kind":"solution","title":"Recomendação: índice Bitmap (baixa cardinalidade / DWH)","detail":"Um índice bitmap mantém um array de bits para cada valor distinto e combina muito rapidamente várias condições de baixa cardinalidade com AND/OR bit a bit. É forte em cargas com muitas leituras, como data warehousing e relatórios.","steps":["Por quê: ocupa pouquíssimo espaço em colunas com poucos valores distintos e combina com eficiência várias condições (WHERE gender=.. AND region=..) com operações de bitmap.","Quando: colunas de baixa cardinalidade, consultas em star schema, data warehouse/relatórios, cargas com muitas leituras.","Diferenças entre engines: um ponto forte clássico do Oracle; o PostgreSQL não tem índice bitmap persistente, mas o planner pode gerar um 'bitmap heap scan' em tempo de execução. MySQL/MSSQL não têm índice bitmap persistente propriamente dito.","Atenção: não use em tabelas atualizadas com frequência (OLTP); os locks de bitmap reduzem severamente a concorrência no nível de linha.","Atenção: a vantagem desaparece em colunas de alta cardinalidade; nesse caso, prefira um B-tree."],"related":["slow-query"]},"sol_gin_gist":{"kind":"solution","title":"Recomendação: GIN / GiST (texto, JSON, array, geometria)","detail":"O PostgreSQL tem famílias de índices especializadas para tipos de acesso que um B-tree padrão não consegue tratar. O GIN aponta para muitos componentes dentro de um valor (palavras, chaves JSONB, elementos de array); o GiST se adequa a consultas geométricas/de intervalo/de vizinho mais próximo.","steps":["Por quê: para esses tipos de dados, consultas como 'contém/sobrepõe/próximo de' não podem ser atendidas com eficiência por um B-tree; GIN/GiST as aceleram.","Quando GIN: busca full-text (tsvector), buscas por campo/chave JSONB (@>, ?), consultas de contenção em arrays; muitas leituras, poucas gravações.","Quando GiST: dados geométricos/geoespaciais (PostGIS), tipos range, consultas de vizinho mais próximo (KNN).","Diferenças entre engines: GIN/GiST são específicos do PostgreSQL. Os índices FULLTEXT e SPATIAL (R-tree) no MySQL, Oracle Text e Spatial no Oracle e o Full-Text Index no MSSQL servem a um propósito semelhante.","Atenção: o GIN é caro nas gravações e lento para criar (pode ser atenuado com fastupdate); meça o custo em tabelas com muitas gravações."],"related":["slow-query"]},"sol_partial":{"kind":"solution","title":"Recomendação: índice parcial / filtrado","detail":"Um índice parcial indexa apenas as linhas que satisfazem uma condição (WHERE ...) em vez da tabela inteira. Se as consultas sempre visam o mesmo pequeno subconjunto, o índice fica muito menor e mais rápido, e o custo de gravação cai.","steps":["Por quê: como indexa apenas as linhas relevantes, o espaço e o custo de manutenção diminuem; o subconjunto 'quente' consultado com frequência fica muito mais rápido.","Quando: condições estáveis e restritas, como WHERE status='active', deleted_at IS NULL, priority='high'.","Diferenças entre engines: o PostgreSQL suporta isso diretamente com 'partial index' (CREATE INDEX ... WHERE ...), o MSSQL com 'filtered index'. No Oracle, usam-se padrões de índice baseado em função/condicional como equivalente; o MySQL(InnoDB) não suporta diretamente.","Atenção: a condição WHERE do índice deve corresponder à condição da consulta; caso contrário, o planner não consegue usar o índice.","Atenção: se o subconjunto crescer, a vantagem diminui; certifique-se de que a condição é estável."],"related":["slow-query"]},"sol_covering":{"kind":"solution","title":"Recomendação: covering index (INCLUDE)","detail":"Um covering index contém todas as colunas de que a consulta precisa, permitindo que o engine responda apenas pelo índice, sem visitar a tabela (heap) (index-only scan). Oferece um ganho significativo de velocidade para consultas executadas com frequência que retornam poucas colunas.","steps":["Por quê: o acesso à tabela (heap fetch) é eliminado; o I/O de disco e a latência caem visivelmente.","Quando: consultas executadas com frequência, com colunas de WHERE + SELECT bem definidas e um result set restrito.","Diferenças entre engines: MSSQL e PostgreSQL adicionam colunas não chave à folha do índice com 'INCLUDE'; no MySQL(InnoDB), os índices secundários já contêm a chave primária, então a cobertura é obtida com um índice composto; no Oracle, o acesso apenas pelo índice ocorre quando todas as colunas necessárias estão no índice.","Atenção: colunas INCLUDE extras/largas incham o índice e deixam as gravações mais lentas; adicione apenas as colunas realmente necessárias.","Atenção: no PostgreSQL, um index-only scan exige um visibility map atualizado; VACUUM regular é essencial."],"related":["slow-query"]}}},"solver/decide-partition.json":{"id":"decide-partition","title":"Decisão: qual estratégia de particionamento?","icon":"🧭","category":"Guia de decisão","intro":"O particionamento divide uma tabela grande em várias partes físicas sob um único nome lógico, facilitando a remoção de dados antigos e permitindo que as consultas olhem apenas as partes relevantes (partition pruning). Em tabelas pequenas, porém, só adiciona complexidade. Esta árvore primeiro questiona se o particionamento é realmente necessário e depois orienta você entre Range, List, Hash e Composite com base nos padrões de acesso e distribuição.","start":"root","nodes":{"root":{"kind":"step","title":"A tabela é realmente grande o suficiente para precisar de particionamento?","detail":"Particionamento não é mágica de desempenho; é uma ferramenta de escala e de manutenção (ciclo de vida). Se a tabela não for grande o suficiente ou as consultas já tiverem bom desempenho com índices, o particionamento só traz complexidade de planos e sobrecarga de gerenciamento. Sua tabela está chegando a dezenas de milhões+ de linhas/centenas de GB, ou ainda é pequena/média?","choices":[{"label":"Sim, é muito grande e/ou dados antigos precisam ser excluídos/arquivados em massa","next":"access"},{"label":"Não, tabela pequena/média, ou não tenho certeza","next":"sol_no_partition"}]},"access":{"kind":"step","title":"Como você acessa os dados e como eles devem ser divididos?","detail":"A chave de partição deve ser a coluna pela qual a maioria das consultas filtra; só assim o pruning entra em ação. Qual é o padrão de acesso dominante? Por data/intervalos sequenciais (últimos 30 dias), por valores específicos de categoria/região, ou não há filtro claro e você quer distribuir a carga de forma uniforme?","choices":[{"label":"Intervalos sequenciais como data/número de sequência (últimos X dias, por mês)","next":"sol_range"},{"label":"Conjuntos de valores discretos como categoria/região/tenant","next":"sol_list"},{"label":"Sem intervalo/categoria claros; o objetivo é distribuir a carga uniformemente","next":"sol_hash"},{"label":"Data e alto volume ao mesmo tempo; é preciso dividir em duas dimensões","next":"sol_composite"}]},"sol_no_partition":{"kind":"solution","title":"Recomendação: não particione (ainda)","detail":"O particionamento não traz benefício em tabelas pequenas/médias; índices bem escolhidos e manutenção normal bastam. O particionamento prematuro complica os planos de execução, perde o pruning com a chave errada e adiciona sobrecarga operacional.","steps":["Por quê: em uma tabela pequena, um full scan ou o acesso por índice já é rápido; o particionamento só acrescenta gerenciamento extra e complexidade de planos.","Quando permanecer assim: abaixo de alguns milhões de linhas, sem necessidade de remover dados antigos em massa, consultas com bom desempenho com índices.","Em vez disso: os índices certos, uma tabela de arquivo se necessário, estatísticas/VACUUM/ANALYZE regulares.","Atenção: não configure o particionamento cedo supondo que 'vai crescer'; mude quando o crescimento for comprovado e a chave certa estiver clara.","Diferenças entre engines: um princípio geral válido para todos os engines; o particionamento declarativo do PostgreSQL, o PARTITION BY do MySQL e o particionamento do Oracle e do MSSQL podem ser facilmente adicionados depois."],"related":[]},"sol_range":{"kind":"solution","title":"Recomendação: particionamento por Range","detail":"O particionamento por Range divide as linhas por intervalos sequenciais de uma coluna (ex.: intervalos de datas: uma partição por mês/trimestre). É a estratégia mais comum e mais poderosa para séries temporais e tabelas em crescimento contínuo.","steps":["Por quê: quando as consultas filtram por data/intervalo, o engine lê apenas as partições relevantes (partition pruning); dados antigos são removidos instantaneamente com um único comando (DROP de partição).","Quando: séries temporais, logs, histórico de pedidos/transações; consultas dos 'últimos N dias' e arquivamento baseado em tempo.","Chave de partição: escolha a coluna de data/sequencial presente na cláusula WHERE da esmagadora maioria das consultas; caso contrário, o pruning não funciona.","Exemplo: particionamento RANGE do PostgreSQL, particionamento range/interval do Oracle (novas partições automáticas), MySQL PARTITION BY RANGE (geralmente RANGE COLUMNS para datas), partition function/scheme do MSSQL.","Atenção: automatize a criação de novas partições para intervalos futuros (Oracle interval ou um job agendado); uma partição 'default/maxvalue' cheia vira um hotspot."],"related":[]},"sol_list":{"kind":"solution","title":"Recomendação: particionamento por List","detail":"O particionamento por List agrupa as linhas por valores discretos e conhecidos de uma coluna (ex.: region = 'TR','EU','US' ou ID do tenant). Quando existem categorias naturais e finitas, ele torna o acesso e o gerenciamento claros.","steps":["Por quê: quando as consultas filtram por valores específicos de categoria, apenas aquela partição é lida; a manutenção/exclusão por categoria fica mais fácil.","Quando: conjuntos de valores discretos e relativamente estáveis, como região/país, tipo de produto, status, separação multi-tenant.","Chave de partição: o conjunto de valores deve ser finito e previsível; se novos valores forem adicionados com frequência, considere Hash em vez de List.","Exemplo: particionamento LIST do PostgreSQL, list partitioning do Oracle, MySQL PARTITION BY LIST, partition scheme do MSSQL com limites adequados.","Atenção: mantenha uma partição 'default' para valores indefinidos/novos; caso contrário, a linha não pode ser inserida e ocorre um erro."],"related":[]},"sol_hash":{"kind":"solution","title":"Recomendação: particionamento por Hash (distribuição uniforme)","detail":"O particionamento por Hash distribui as linhas de forma relativamente uniforme entre um número predefinido de partições com base no hash da coluna-chave. É usado para evitar hotspots e equilibrar a carga quando não há intervalo/categoria natural.","steps":["Por quê: as linhas são distribuídas uniformemente; o hotspot de gravação que se acumula em uma única partição ou no final da chave primária é reduzido.","Quando: alto volume de gravação, sem intervalo/categoria natural, o objetivo é equalizar I/O e tamanho (ex.: um id de alta cardinalidade).","Chave de partição: escolha uma coluna de alta cardinalidade e distribuída uniformemente (geralmente a chave primária/única).","Exemplo: particionamento HASH do PostgreSQL, hash partitioning do Oracle, MySQL PARTITION BY HASH/KEY.","Atenção: não oferece pruning para consultas por intervalo (o hash destrói a ordem); consultas como 'últimos N dias' varrem todas as partições. Alterar o número de partições depois exige redistribuição."],"related":[]},"sol_composite":{"kind":"solution","title":"Recomendação: particionamento Composite (multinível)","detail":"O particionamento Composite combina duas estratégias: divide primeiro no nível superior e depois subdivide cada partição em subpartições (ex.: Range-by-Hash ou Range-by-List). É usado quando são necessários ao mesmo tempo ciclo de vida baseado em tempo e distribuição uniforme/separação por categoria.","steps":["Por quê: quando uma única estratégia não basta, atende às duas necessidades juntas; por exemplo, dividir por mês (arquivamento) e distribuir por hash dentro do mês (prevenção de hotspots).","Quando: séries temporais muito grandes + muitas gravações concorrentes, ou um padrão de acesso duplo de data + região/tenant.","Exemplo: composite do Oracle (range-hash, range-list, list-hash etc.); no PostgreSQL é montado manualmente particionando novamente as partições (partition of partition); subpartições do MySQL (RANGE/LIST + HASH/KEY).","Atenção: é a opção com maior complexidade de gerenciamento e de schema; escolha-a apenas quando as duas dimensões forem uma necessidade comprovada.","Atenção: uma escolha errada da chave superior/inferior perde o pruning; verifique se os dois níveis correspondem ao padrão das consultas."],"related":[]}}},"solver/decide-pooling.json":{"id":"decide-pooling","title":"Decisão: como configurar o pooling de conexões?","icon":"🧭","category":"Guia de decisão","intro":"Cada conexão com o banco carrega custo de memória e de escalonamento; um crescimento descontrolado do número de conexões deixa o servidor lento ou até o derruba. Um pool de conexões resolve isso reutilizando um pequeno número de conexões persistentes. Esta árvore orienta as decisões sobre onde o pool fica, qual modo usar (session/transaction/statement) e o tamanho correto, e enfatiza por que um pooler externo é obrigatório em ambientes serverless.","start":"root","nodes":{"root":{"kind":"step","title":"Como a arquitetura da sua aplicação se conecta?","detail":"A decisão de pooling começa pela arquitetura. É um único processo de aplicação de longa duração (servidor clássico), muitos processos/instâncias independentes (microsserviços, muitos pods) ou funções serverless/Lambda que nascem e morrem a cada request? Cada caso exige um posicionamento diferente do pool.","choices":[{"label":"Um/poucos processos de aplicação de longa duração","next":"sol_app_pool"},{"label":"Muitos processos/instâncias/pods se conectam ao mesmo banco","next":"middleware"},{"label":"Serverless / Lambda / funções de curta duração","next":"sol_serverless"},{"label":"Primeiro, mostre-me como escolher o tamanho certo do pool","next":"sol_size"}]},"middleware":{"kind":"step","title":"Como escolher o modo do pooler intermediário?","detail":"Com muitos clientes, um pooler intermediário (PgBouncer, ProxySQL) mantém baixo o número de conexões no banco. Mas o modo do pool depende dos recursos que a aplicação usa: você depende de estado vinculado à sessão (prepared statements, tabelas temporárias, SET, advisory locks, recursos no nível de sessão), ou tudo se conclui dentro de uma única transação?","choices":[{"label":"Dependo do estado da sessão (SET, tabelas temporárias, prepared statements de sessão)","next":"sol_session_mode"},{"label":"As transações são curtas e independentes; não mantenho estado de sessão","next":"sol_txn_mode"}]},"sol_app_pool":{"kind":"solution","title":"Recomendação: pool de conexões dentro da aplicação","detail":"Para um/poucos processos de longa duração, uma biblioteca de pool dentro da aplicação (HikariCP, o pool nativo do database/sql do Go, o pooling de conexões do .NET) atende à maioria das necessidades. As conexões são abertas uma vez e reutilizadas repetidamente.","steps":["Por quê: o custo de abrir/fechar conexões desaparece; um número de conexões limitado e previsível protege o banco.","Quando: um monólito clássico ou poucas instâncias da aplicação; a demanda total de conexões fica abaixo da capacidade do banco.","Exemplo: Java HikariCP, pooling do .NET SqlConnection/Npgsql, Node pg-pool, pool do Python SQLAlchemy.","Para o dimensionamento: determine o tamanho do pool com base em núcleos/discos (próxima decisão); 'quanto mais, melhor' não se aplica.","Atenção: cada instância da aplicação abre o próprio pool; número de instâncias × tamanho do pool não deve exceder o max_connections do banco. Se exceder, passe para um pooler intermediário."],"related":["connection-storm"]},"sol_size":{"kind":"solution","title":"Recomendação: dimensione o pool corretamente","detail":"O pool não deve ser pequeno demais (os requests esperam) nem grande demais. Conexões em excesso geram troca de contexto de CPU e contenção de locks e reduzem o throughput. O tamanho não é um número a crescer indefinidamente, mas um número pequeno baseado em núcleos e I/O.","steps":["Fórmula inicial: um ponto de partida comum é tamanho do pool ≈ (número de núcleos × 2) + número efetivo de spindles; em SSD/muitos núcleos, algo em torno de 'núcleos × 2-4' é um bom começo.","Por que mantê-lo pequeno: o paralelismo real do banco é limitado pelo número de núcleos; conexões extras apenas entram em fila e deixam tudo mais lento por troca de contexto/contenção de locks.","Regra: com centenas de clientes concorrentes, a solução não é aumentar o pool, mas girar rapidamente um pool pequeno (transações curtas + enfileiramento).","Limite total: (número de instâncias da aplicação × tamanho do pool) < max_connections do banco; deixe folga para conexões de superusuário e de manutenção.","Atenção: comece pela fórmula, mas sempre meça; ajuste usando métricas de tempo de espera, conexões ativas e profundidade da fila."],"related":["connection-storm"]},"sol_session_mode":{"kind":"solution","title":"Recomendação: modo de pool session","detail":"No modo session, a conexão de um cliente fica presa a uma conexão de servidor backend até o fim da sessão. O estado no nível de sessão (SET, tabelas temporárias, advisory locks, prepared statements de sessão) é preservado, mas o compartilhamento de conexões é mínimo.","steps":["Por quê: é o único modo seguro para aplicações que precisam de estado preservado durante toda a sessão; o comportamento é o mesmo de uma conexão direta ao banco.","Quando: aplicações que usam variáveis de sessão com SET, tabelas temporárias, LISTEN/NOTIFY, prepared statements no nível de sessão ou advisory locks.","Exemplo: PgBouncer pool_mode=session; no ProxySQL, roteamento separado do tráfego sensível à sessão.","Atenção: o compartilhamento de conexões é baixo, então o benefício diminui com muitos clientes; sempre que possível, busque deixar a aplicação sem estado de sessão e passe para o modo transaction.","Diferenças entre engines: PgBouncer para PostgreSQL; no lado do MySQL, o ProxySQL trata um comportamento semelhante de outra forma, e as variáveis de sessão exigem cuidado."],"related":["connection-storm"]},"sol_txn_mode":{"kind":"solution","title":"Recomendação: modo de pool transaction","detail":"No modo transaction, uma conexão de servidor é emprestada ao cliente apenas durante uma transação e volta ao pool quando ela termina. Assim, milhares de clientes podem trabalhar com pouquíssimas conexões reais no banco; é o modo mais comum em alta escala.","steps":["Por quê: como as conexões são repassadas por transação, o compartilhamento é máximo; você atende muitos clientes com poucas conexões no banco.","Quando: transações curtas e independentes; arquiteturas de microsserviços/multi-pod que não mantêm estado de sessão (ou são adaptadas para não manter).","Exemplo: PgBouncer pool_mode=transaction (a configuração mais comum), o comportamento de multiplexação padrão do ProxySQL.","Atenção: recursos que abrangem a sessão quebram: prepared statements no nível de sessão, tabelas temporárias, SET e advisory locks não são seguros. Para named prepared statements no nível de protocolo, verifique a compatibilidade entre aplicação e pooler.","Modo statement: o modo (statement), ainda mais agressivo, repassa a conexão a cada instrução; é considerado apenas para cenários muito específicos, somente leitura e sem transações, e é muito restritivo."],"related":["connection-storm"]},"sol_serverless":{"kind":"solution","title":"Recomendação: um pooler externo é obrigatório em serverless","detail":"Funções serverless/Lambda escalam rapidamente e cada instância abre a própria conexão; um pool dentro da aplicação não ajuda aqui porque as instâncias têm vida curta e não compartilham nada. Quando centenas/milhares de instâncias surgem de repente, o limite de conexões do banco estoura. A solução é um pool de conexões externo à frente do banco.","steps":["Por quê: em instâncias de função de curta duração e não compartilhadas, um pool dentro da aplicação não consegue persistir; ocorre uma tempestade de conexões no scale-out.","Quando: ambientes que criam uma instância por request, como AWS Lambda, Cloud Functions, Azure Functions.","Exemplo: PgBouncer/ProxySQL como camada separada, ou um pooler gerenciado (ex.: AWS RDS Proxy, Data API/serviços de pooler externo para PostgreSQL).","Modo: geralmente se prefere o modo de pool transaction; deixe o código da função sem estado de sessão.","Atenção: defina também um limite de concorrência por função (reserved concurrency); dimensione o pooler e o max_connections do banco em conjunto, caso contrário o próprio pooler vira o gargalo."],"related":["connection-storm"]}}},"solver/decide-cache.json":{"id":"decide-cache","title":"Decisão: qual estratégia de cache?","icon":"🧭","category":"Guia de decisão","intro":"Um cache mantém os dados lidos com frequência em uma camada rápida à frente do banco (ex.: Redis), reduzindo a latência e a carga do banco. Mas nem todos os dados são adequados para cache, e uma invalidação errada cria risco de dados defasados/incorretos. Esta árvore primeiro verifica se você realmente precisa de cache e depois ajuda a escolher entre cache-aside, read-through, write-through e write-behind com base no padrão de leitura/gravação, além de tratar da prevenção de stampedes.","start":"root","nodes":{"root":{"kind":"step","title":"Como é a sua carga: predominam leituras ou gravações?","detail":"Um cache compensa mais quando os mesmos dados são lidos muitas vezes (muitas leituras) e não mudam com frequência. Primeiro, estabeleça o padrão geral: os dados são muito lidos e raramente alterados, são atualizados constantemente, ou você não tem certeza se vale a pena adicionar um cache?","choices":[{"label":"Muitíssimas leituras, os dados mudam relativamente pouco","next":"read_pattern"},{"label":"As gravações também são intensas; os dados gravados são lidos imediatamente/com frequência","next":"write_pattern"},{"label":"Não tenho certeza; eu realmente preciso de cache?","next":"sol_no_cache"}]},"read_pattern":{"kind":"step","title":"Quem deve ser responsável por popular o cache?","detail":"Em um cenário com muitas leituras, a escolha-chave é quem popula o cache. Sua aplicação deve gerenciar o cache explicitamente e recorrer ela mesma ao banco (alta flexibilidade), ou a camada de cache deve buscar os dados no banco subjacente em caso de miss e retorná-los de forma transparente?","choices":[{"label":"Deixar a aplicação gerenciar explicitamente; quero flexibilidade e controle","next":"sol_cache_aside"},{"label":"Deixar a camada de cache buscar no banco em caso de miss (transparente)","next":"sol_read_through"}]},"write_pattern":{"kind":"step","title":"Nas gravações, a prioridade é a consistência ou a velocidade de gravação?","detail":"Se as gravações forem intensas, você precisa decidir quão consistentes os dados gravados serão entre o cache e o banco. O cache e o banco devem ser atualizados juntos a cada gravação para garantir consistência (gravações um pouco mais lentas), ou as gravações devem ir primeiro ao cache e ser aplicadas ao banco de forma assíncrona em segundo plano (gravações muito rápidas, mas com risco de perda)?","choices":[{"label":"A consistência importa; as leituras devem estar sempre atualizadas","next":"sol_write_through"},{"label":"A velocidade de gravação é crítica; consistência levemente atrasada e risco de perda são aceitáveis","next":"sol_write_behind"}]},"sol_no_cache":{"kind":"solution","title":"Recomendação: não adicione cache por enquanto","detail":"Um cache não é gratuito: introduz um problema de consistência (dados defasados), infraestrutura extra e complexidade de invalidação. Se a consulta já for rápida ou os dados mudarem a cada request, um cache não acrescenta benefício, apenas superfície de falha.","steps":["Por quê: um cache adiciona sobrecarga de consistência, invalidação e operação. Sem retorno, é prejuízo líquido.","Quando não é necessário: a consulta já é rápida graças a um índice, os dados são diferentes a cada leitura/são específicos do usuário e não são reutilizados, ou as gravações superam muito as leituras.","Em vez disso: primeiro otimização de índices/consultas, uma materialized view ou o próprio buffer/plan cache do banco.","Atenção: não adicione cache 'por via das dúvidas'; não adicione sem um gargalo de leitura medido e dados reutilizados.","Próximo passo: assim que um hot spot real de leitura for comprovado, comece com cache-aside."],"related":["slow-query","high-cpu"]},"sol_cache_aside":{"kind":"solution","title":"Recomendação: cache-aside (lazy loading)","detail":"Com cache-aside, a aplicação verifica primeiro o cache; se o dado não estiver lá (miss), lê do banco, grava no cache e o retorna. É o padrão mais comum e flexível; o cache é preenchido apenas com dados realmente solicitados.","steps":["Por quê: simples, flexível e resiliente; mesmo que o cache falhe, a aplicação continua funcionando recorrendo ao banco. Apenas os dados solicitados vão para o cache.","Quando: aceleração de leitura de uso geral; muitas leituras, gravações moderadas; o uso clássico com Redis/Memcached.","Invalidação: na gravação, atualize ou exclua a chave relacionada (write-invalidate); limite a defasagem dando a cada chave um TTL razoável.","Exemplo: Redis GET → se ausente, consulta no banco → SET key value EX <ttl>.","Atenção: o primeiro request é sempre um miss (cold start). Se a mesma chave for solicitada por muitos clientes ao mesmo tempo, pode ocorrer um cache stampede — veja a prevenção de stampede (próximo item).","Stampede: quando uma chave popular expira, milhares de requests atingem o banco ao mesmo tempo; evite com lock/single-flight, atualização antecipada ou TTLs com jitter."],"related":["high-cpu","slow-query"]},"sol_read_through":{"kind":"solution","title":"Recomendação: cache read-through","detail":"Com read-through, a aplicação conversa apenas com o cache; em caso de miss, a própria camada de cache busca os dados no banco e os popula (por meio de um provider/loader). O código da aplicação fica mais simples e a lógica de preenchimento fica em um só lugar.","steps":["Por quê: a lógica de preenchimento é centralizada na camada de cache; o código da aplicação deixa de repetir 'tratar o miss em todo lugar'.","Quando: cargas com muitas leituras em que você pode usar uma camada de acesso ao cache consistente (biblioteca/serviço).","Exemplo: uma biblioteca/cliente de cache (ex.: um cache local com um loader definido ou uma camada de acesso à frente do Redis) carrega do banco em caso de miss.","Invalidação: TTLs e invalidação na gravação continuam necessários; o read-through sozinho não garante dados atualizados.","Atenção: muito semelhante ao cache-aside; a diferença é 'quem popula'. O risco de stampede existe aqui também; aplique as mesmas contramedidas.","Nota sobre o engine: o Redis não faz read-through sozinho; a camada da aplicação/biblioteca fornece esse padrão."],"related":["slow-query"]},"sol_write_through":{"kind":"solution","title":"Recomendação: cache write-through","detail":"Com write-through, toda gravação vai tanto para o cache quanto para o banco (de forma síncrona); ambos são atualizados juntos. Assim, o cache nunca fica atrás do banco e as leituras sempre veem dados atualizados.","steps":["Por quê: o cache e o banco permanecem consistentes; se os dados gravados forem lidos logo em seguida, não há risco de leituras defasadas.","Quando: cenários em que os dados gravados são lidos imediatamente e com frequência e é exigida consistência forte de leitura.","Exemplo: na gravação, a aplicação atualiza primeiro o banco e, imediatamente depois, define a chave do cache com o novo valor (ou a exclui).","Atenção: toda gravação vai para dois destinos, então a latência de gravação aumenta; dados que nunca serão lidos também podem ir para o cache sem necessidade. As duas gravações não são atômicas (uma tem sucesso, a outra falha), o que pode causar inconsistência — em caso de erro, exclua a entrada do cache.","Armadilha da gravação dupla: em vez de gravar o banco e o cache separadamente, a abordagem 'grave o banco, exclua (invalide) o cache' geralmente é mais segura."],"related":[]},"sol_write_behind":{"kind":"solution","title":"Recomendação: cache write-behind (write-back)","detail":"Com write-behind, a gravação vai primeiro ao cache e retorna imediatamente ao usuário; a gravação no banco acontece em segundo plano, de forma assíncrona (em lotes/com atraso). A velocidade de gravação é a maior, mas traz riscos de durabilidade e consistência.","steps":["Por quê: a latência de gravação cai drasticamente e as gravações podem ser agrupadas em lotes e transferidas ao banco com eficiência; o banco fica aliviado sob carga com muitas gravações.","Quando: volumes de gravação muito altos, como contadores, métricas ou feeds de atividade, em que uma consistência levemente atrasada é aceitável.","Exemplo: gravar no Redis → uma fila/worker em segundo plano descarrega no banco em lotes, a intervalos.","Atenção: se o nó de cache cair antes de gravar no banco, os dados são PERDIDOS; não use para dados críticos que exigem durabilidade, ou proteja com uma fila durável/AOF.","Atenção: o banco fica defasado por um tempo; outros sistemas que leem o banco diretamente veem dados desatualizados. Aceite conscientemente o atraso de consistência e a janela de perda."],"related":[]}}},"solver/decide-datatype.json":{"id":"decide-datatype","title":"Decisão: escolha o tipo de dado certo","icon":"🧭","category":"Guia de decisão","intro":"Escolher um tipo de dado é uma das decisões mais caras de corrigir depois: o tipo errado produz resultados errados (ex.: float para dinheiro), desperdício de espaço e consultas lentas. Esta árvore orienta você para o tipo certo para campos numéricos, de texto, de data/hora, de chave (PK), semiestruturados (JSON) e de categoria (ENUM), e destaca armadilhas clássicas como dinheiro e character sets.","start":"root","nodes":{"root":{"kind":"step","title":"Que tipo de dado você está armazenando?","detail":"O tipo certo é determinado pela natureza do dado. Em qual categoria o campo se enquadra: um número, texto, uma data/hora, a chave primária da tabela, dados flexíveis/semiestruturados (JSON) ou um conjunto limitado de categorias?","choices":[{"label":"Valor numérico (quantidade, dinheiro, medida, contador)","next":"numeric"},{"label":"Texto (nome, descrição, código)","next":"sol_text"},{"label":"Data e/ou hora","next":"sol_datetime"},{"label":"Estou projetando uma chave primária (PK)","next":"sol_pk"},{"label":"Campos flexíveis/aninhados/variáveis (dados semiestruturados)","next":"sol_json"},{"label":"Um conjunto limitado e conhecido de categorias (status, tipo, prioridade)","next":"sol_enum"}]},"numeric":{"kind":"step","title":"O número é inteiro ou decimal — e é dinheiro?","detail":"Para numéricos, a distinção mais crítica é a exatidão. O valor é inteiro (quantidade, ID, contador) ou decimal? Se for decimal, é DINHEIRO/um valor financeiro? Ponto flutuante binário (FLOAT/DOUBLE) nunca é usado para dinheiro nem onde se exige exatidão, porque produz erros de arredondamento.","choices":[{"label":"Inteiro (quantidade, contador, id)","next":"sol_integer"},{"label":"Dinheiro ou decimal exato (preço, saldo, taxa)","next":"sol_decimal"}]},"sol_integer":{"kind":"solution","title":"Recomendação: inteiro (SMALLINT / INT / BIGINT)","detail":"Para inteiros, escolha o menor tipo que cubra o intervalo necessário. Um tipo desnecessariamente grande desperdiça espaço e tamanho de índice; mas, para campos que podem crescer, como contadores/PKs, largura suficiente é essencial para evitar overflow.","steps":["Por quê: a largura certa otimiza tanto o armazenamento quanto o uso de índice/memória; a aritmética é rápida.","Quando SMALLINT/INT: para um intervalo limitado (idade, quantidade, contador pequeno), SMALLINT/INT basta.","Quando BIGINT: escolha BIGINT para IDs/contadores sempre crescentes e PKs cujo número de linhas pode chegar a bilhões — o overflow de INT é uma causa séria de indisponibilidade em produção.","Diferenças entre engines: no MySQL, INT UNSIGNED dobra o intervalo; o PostgreSQL não tem UNSIGNED, passe para BIGINT. Oracle NUMBER(p), MSSQL INT/BIGINT.","Atenção: não coloque BIGINT em todo lugar 'caso cresça'; mas, para uma PK crescente, BIGINT desde o início é um seguro barato."],"related":[]},"sol_decimal":{"kind":"solution","title":"Recomendação: NUMERIC / DECIMAL — NUNCA FLOAT para dinheiro","detail":"Para dinheiro e decimais exatos, use NUMERIC/DECIMAL de ponto fixo (exato). FLOAT/DOUBLE são ponto flutuante binário e não conseguem armazenar valores como 0.1 com exatidão; somas/multiplicações produzem desvios de centavos, saldos errados e problemas de auditoria.","steps":["Por quê: NUMERIC/DECIMAL armazenam valores exatamente em decimal; a aritmética monetária dá resultados corretos sem erros de arredondamento.","Quando: todo campo que exige exatidão, como preço, saldo, imposto, taxa ou juros. Especifique uma escala adequada: DECIMAL(precision, scale), ex.: DECIMAL(19,4) para um valor monetário.","Alternativa: alguns sistemas armazenam dinheiro na menor unidade (centavos) como BIGINT; isso também oferece exatidão total.","Diferenças entre engines: PostgreSQL NUMERIC, MySQL DECIMAL, Oracle NUMBER(p,s), MSSQL DECIMAL/MONEY (atenção às limitações do MONEY).","Atenção: FLOAT/DOUBLE servem apenas para valores aproximados científicos/medidos e casos em que o desempenho pesa mais que a exatidão — nunca para dinheiro."],"related":[]},"sol_text":{"kind":"solution","title":"Recomendação: texto — VARCHAR vs TEXT vs CHAR","detail":"Para texto, usa-se VARCHAR/TEXT para comprimento variável e CHAR para comprimento realmente fixo. Nos engines modernos, a diferença de armazenamento entre VARCHAR e TEXT é em geral desprezível; a decisão real é se deve haver um limite semântico (uma restrição de comprimento).","steps":["VARCHAR(n): se o comprimento for variável e houver um limite superior sensato (ex.: e-mail, nome), use VARCHAR(n) — o limite é uma ferramenta de validação de dados.","TEXT: para textos livres longos de comprimento imprevisível (descrição, corpo), use TEXT.","CHAR(n): use apenas para comprimentos realmente fixos (ex.: código de país 'TR', sempre 2 caracteres); para textos curtos, CHAR preenche com espaços à direita e geralmente é desnecessário.","Diferenças entre engines: no PostgreSQL, VARCHAR e TEXT têm o mesmo desempenho, o limite é apenas uma restrição. No MySQL, VARCHAR é armazenado na linha, TEXT pode ser armazenado separadamente e a indexação tem limite de prefixo. No Oracle, use VARCHAR2.","Charset/collation: para emoji e Unicode completo, use sempre utf8mb4 no MySQL (o antigo 'utf8' tem 3 bytes e quebra emojis); escolha a collation (ex.: utf8mb4_0900_ai_ci) conforme as necessidades de ordenação/comparação. No PostgreSQL, normalmente um banco UTF-8 + uma collation adequada."],"related":[]},"sol_datetime":{"kind":"solution","title":"Recomendação: data/hora — TIMESTAMP com fuso horário","detail":"Se você armazena um instante (o horário de um evento), escolha um tipo que considere o fuso horário. Armazenar sem fuso horário leva a cálculos e comparações errados entre regiões/mudanças de horário de verão.","steps":["Por quê: um tipo com fuso horário normaliza o instante para UTC e oferece comparação e conversão consistentes; essencial para sistemas globais.","Quando TIMESTAMPTZ: para instantes de eventos/transações no PostgreSQL, use TIMESTAMP WITH TIME ZONE (timestamptz); armazene em UTC e converta para o fuso horário do usuário na exibição.","Apenas data ou hora: DATE para um dia do calendário, TIME para um horário sem relação com fuso horário; INTERVAL para durações (nos engines que o suportam).","Diferenças entre engines: PostgreSQL timestamptz (na verdade armazena UTC). No MySQL, TIMESTAMP é convertido conforme o fuso horário, mas seu intervalo é limitado (2038); DATETIME não é convertido — imponha na aplicação a disciplina de armazenar em UTC. Oracle TIMESTAMP WITH TIME ZONE, MSSQL DATETIMEOFFSET.","Atenção: armazenar o tempo como texto (VARCHAR) ou como INT epoch quebra as operações de ordenação, intervalo e fuso horário; use um tipo real de data/hora."],"related":[]},"sol_pk":{"kind":"solution","title":"Recomendação: chave primária — BIGINT vs UUID","detail":"Há duas opções principais para uma PK: um número crescente (BIGINT identity/sequence) ou um UUID. Uma PK numérica é pequena e amigável ao índice, mas previsível e exige geração centralizada; um UUID pode ser gerado de forma distribuída, mas é maior e sua ordem aleatória pode prejudicar o índice.","steps":["BIGINT (crescente): o índice menor e mais rápido; inserções sequenciais são ideais para um B-tree. A escolha padrão para um único banco/geração centralizada; BIGINT em vez de INT desde o início é seguro contra overflow.","UUID: pode ser gerado em clientes/sistemas distribuídos sem colisões e não revela um número sequencial quando o ID é exposto. Mas ocupa 16 bytes (2×BIGINT).","A ordem do UUID importa: UUIDs totalmente aleatórios (v4) não são sequenciais, então causam inserções dispersas no índice (page splits, cache hit ratio baixo); UUIDs ordenados por tempo (v7/ULID) eliminam isso em grande parte.","Diferenças entre engines: o PostgreSQL tem um tipo uuid nativo; no MySQL, armazene o UUID como BINARY(16) (em vez de texto CHAR(36)) e gere-o em ordem quando possível. MSSQL uniqueidentifier + NEWSEQUENTIALID, Oracle RAW(16).","Atenção: armazenar um UUID como texto VARCHAR/CHAR(36) praticamente dobra ou triplica o espaço e o tamanho do índice; armazene-o em binário."],"related":[]},"sol_json":{"kind":"solution","title":"Recomendação: JSON / JSONB — use com moderação","detail":"O tipo JSON é poderoso para campos com schema flexível, aninhados ou esparsos; mas a disciplina relacional (constraints, índices, segurança de tipos) pode se perder. Regra: mova os campos fixos e consultados com frequência para colunas normais e mantenha no JSON apenas a parte realmente variável.","steps":["Por quê: armazena campos variáveis/opcionais de forma flexível em uma única coluna; campos podem ser adicionados sem migration de schema.","Quando: estruturas imprevisíveis, como payloads de APIs externas, campos definidos pelo usuário ou atributos de produtos.","Diferenças entre engines: no PostgreSQL, use JSONB (binário, indexável, consultas @>/? com GIN) — prefira-o ao JSON simples. O tipo JSON do MySQL também é binário e é consultado com generated column + índice. O Oracle 21c+ tem um tipo JSON/OSON; o MSSQL anterior ao 2025 mantém JSON em NVARCHAR e o processa com funções; o SQL Server 2025 e o Azure SQL têm um tipo json nativo (binário).","Atenção: indexe os campos JSON filtrados com frequência (PostgreSQL GIN, índice em generated column no MySQL); caso contrário, toda consulta varre o documento inteiro.","Atenção: não enfie tudo em JSON — a integridade relacional, as foreign keys e a tipagem se perdem. Campos que precisam de consultas/constraints devem ser colunas reais."],"related":["decide-sqlnosql"]},"sol_enum":{"kind":"solution","title":"Recomendação: ENUM vs tabela de lookup (referência)","detail":"Há duas opções para conjuntos limitados de categorias: o tipo ENUM do engine, ou uma tabela de lookup + foreign key. O ENUM é compacto e simples, mas adicionar um valor exige uma alteração de schema; uma tabela de lookup é flexível e pode carregar atributos extras (descrição, flag de ativo, ordem).","steps":["Quando ENUM: se os valores forem muito estáveis e raramente mudarem (ex.: gênero, dia da semana) e não forem necessários atributos extras; compacto e legível.","Quando tabela de lookup: se os valores puderem mudar com o tempo, forem necessários campos extras como traduções/descrição/ordem/flag de ativo, ou se os relatórios fizerem join com ela — é mais flexível.","Diferenças entre engines: PostgreSQL e MySQL oferecem um tipo ENUM nativo (no PostgreSQL, adicionar um valor a um ENUM exige ALTER TYPE, e a ordenação segue a ordem de definição). Oracle e MSSQL não têm ENUM nativo; use uma CHECK constraint ou uma tabela de lookup.","Atenção: adicionar/remover um valor em um ENUM é uma migration de schema e pode causar locks/custo em uma tabela grande; prefira uma tabela de lookup para conjuntos que mudam com frequência.","Alternativa: texto livre + uma CHECK constraint também é um meio-termo prático para conjuntos pequenos e estáveis."],"related":[]}}},"solver/decide-capacity.json":{"id":"decide-capacity","title":"Decisão: dimensionamento de servidor","icon":"🧭","category":"Guia de decisão","intro":"O dimensionamento correto parte do perfil da carga (OLTP, data warehouse, misto) e exige encontrar o gargalo real (CPU, I/O ou RAM). Regra de ouro: o conjunto de dados acessado com frequência (working set) deve caber na RAM; meça primeiro, depois escale, e deixe folga para picos de carga. Esta árvore ajuda a identificar a carga e a escolher o recurso e a direção de escala (vertical/horizontal) com base no gargalo.","start":"root","nodes":{"root":{"kind":"step","title":"Qual é o perfil da sua carga?","detail":"O dimensionamento começa pela carga, porque cargas OLTP e analíticas exigem perfis de recursos completamente diferentes. Qual é o trabalho predominante do sistema: muitas transações pequenas e rápidas (OLTP), relatórios/analytics com grandes scans e agregações (DWH), ou uma mistura dos dois? Se não tiver certeza, você precisa medir primeiro.","choices":[{"label":"OLTP — muitas transações pequenas e curtas (web/aplicação)","next":"bottleneck"},{"label":"Analytics / data warehouse (DWH) — grandes scans e agregações","next":"sol_dwh"},{"label":"Carga mista, ou não tenho certeza","next":"sol_measure"},{"label":"Conheço o gargalo; devo escalar vertical ou horizontalmente?","next":"sol_scale"}]},"bottleneck":{"kind":"step","title":"Onde está o gargalo: RAM, I/O ou CPU?","detail":"Em OLTP, encontre o gargalo real em vez de adicionar recursos às cegas. Olhe suas métricas: os dados acessados com frequência não cabem na RAM e há muitas leituras de disco (RAM/I/O), a latência/IOPS do disco é insuficiente (I/O), ou os dados já estão em memória, mas a CPU está saturada (CPU)? Escalar o recurso errado desperdiça dinheiro e tempo.","choices":[{"label":"Os dados acessados com frequência não cabem na RAM; as leituras de disco são altas","next":"sol_ram"},{"label":"Os dados estão em memória, mas a latência/IOPS do disco é insuficiente (muitas gravações)","next":"sol_io"},{"label":"Os dados estão em memória e o disco está bem, mas a CPU está constantemente saturada","next":"sol_cpu"}]},"sol_measure":{"kind":"solution","title":"Recomendação: meça primeiro, depois dimensione","detail":"Comprar hardware com base em palpites quase sempre resulta no tamanho errado. O perfil da carga e o gargalo surgem de métricas reais. Dimensionamento não é palpite, mas uma iteração guiada por medições.","steps":["Por quê: se a carga é OLTP ou DWH, e se o gargalo é CPU, I/O ou RAM, só fica claro quando medido sob carga real; adivinhar é um erro caro.","Meça: uso de CPU e run queue, memória/cache hit ratio (buffer cache hit), IOPS e latência de disco, conexões ativas e wait events.","Ferramentas por engine: PostgreSQL pg_stat_* e wait events, Oracle AWR/ASH, MySQL Performance Schema, MSSQL DMVs e wait stats.","Abordagem: teste com uma carga representativa, encontre o recurso mais restrito, escale apenas ele e meça de novo. Altere um recurso por vez para conseguir isolar o efeito.","Próximo passo: assim que o perfil estiver claro, passe para a decisão correspondente (gargalo de OLTP, DWH ou escala horizontal/vertical)."],"related":["high-cpu","memory-pressure","slow-query"]},"sol_ram":{"kind":"solution","title":"Recomendação: adicione RAM — o working set deve caber na memória","detail":"A regra mais crítica de OLTP: os dados e índices acessados com frequência (o working set) devem caber na memória (buffer/cache). Se não couberem, toda consulta vai ao disco, a latência explode e o I/O vira o gargalo. A RAM costuma ser o investimento de maior retorno.","steps":["Por quê: ler da memória é centenas a milhares de vezes mais rápido que do disco; quando o working set cabe na RAM, o cache hit ratio sobe e o I/O de disco despenca.","Quando: cache hit ratio baixo, wait events frequentes de 'disk read', um conjunto de dados ativo maior que a RAM disponível.","Como: dimensione corretamente a área de memória do banco — PostgreSQL shared_buffers + page cache do SO, MySQL innodb_buffer_pool_size (geralmente a maior parte da RAM), Oracle SGA/buffer cache, MSSQL max server memory.","Meta: idealmente, o working set + índices cabem na memória; se nem tudo couber, pelo menos a parte 'quente' acessada com mais frequência deve caber.","Atenção: não entregue toda a RAM física ao buffer pool; deixe espaço para o SO, a memória por conexão e outros processos, caso contrário o swapping deixa tudo mais lento."],"related":["memory-pressure","slow-query"]},"sol_io":{"kind":"solution","title":"Recomendação: reforce a camada de I/O (IOPS/latência)","detail":"Mesmo com os dados em memória, a velocidade do disco é decisiva sob carga com muitas gravações (commit, WAL/redo/binlog, checkpoint). A questão aqui não é capacidade, mas IOPS e latência. A classe de disco errada derruba o sistema apesar de CPU/RAM rápidas.","steps":["Por quê: para garantir durabilidade, cada commit grava o log em disco; um disco com IOPS baixo/latência alta limita diretamente o throughput de transações.","Quando: latência de disco alta, esperas longas de 'log/WAL write', gargalo durante checkpoints, OLTP com muitas gravações.","Como: use NVMe/SSD; mova o log de transações para um disco rápido separado dos arquivos de dados; na nuvem, escolha uma classe de disco com IOPS/throughput provisionados suficientes (ex.: provisioned IOPS).","Meta: defina metas tanto de IOPS quanto de latência — não só IOPS, a latência p99 também importa. RAID/cache de gravação (BBU) pode reduzir a latência de gravação.","Atenção: na nuvem, o throughput e o IOPS do disco frequentemente também dependem do tamanho da instância; a latência em discos conectados pela rede é maior que em NVMe local."],"related":["disk-full","slow-query"]},"sol_cpu":{"kind":"solution","title":"Recomendação: resolva o gargalo de CPU (consultas primeiro, depois núcleos)","detail":"Se a CPU está saturada enquanto os dados estão em memória e o disco está bem, a causa raiz geralmente são consultas ineficientes (planos ruins, índices ausentes, muitas consultas pequenas) ou concorrência excessiva. Reduzir a carga antes de adicionar núcleos costuma ser mais barato e mais eficaz.","steps":["Por quê: a CPU é consumida principalmente por full scans, sorts/hashes, compilação de planos e pela troca de contexto de conexões em excesso. Corrigir isso é mais barato que núcleos.","Otimize primeiro: encontre as consultas mais caras (pg_stat_statements / AWR / Performance Schema), adicione os índices ausentes, reduza consultas N+1, diminua o pool de conexões.","Depois escale: se as consultas estiverem saudáveis e a CPU continuar saturada, aumente o número de núcleos (vertical) — especialmente para OLTP com alta concorrência.","Nota sobre o engine: mais conexões = mais troca de contexto; um pool pequeno com giro rápido frequentemente supera mais núcleos (veja a decisão de pool de conexões).","Atenção: se o licenciamento for por núcleo (Oracle/MSSQL), adicionar núcleos é caro; otimizar as consultas primeiro reduz o custo."],"related":["high-cpu","slow-query"]},"sol_dwh":{"kind":"solution","title":"Recomendação: analytics/DWH — throughput, paralelismo e escala horizontal","detail":"Uma carga de data warehouse consiste em um pequeno número de consultas pesadas que varrem e agregam tabelas grandes. A prioridade aqui não é baixa latência, mas alto throughput de scan, paralelismo e, geralmente, uma arquitetura com escala horizontal.","steps":["Por quê: as consultas varrem terabytes; a largura de banda de disco/memória e os núcleos trabalhando em paralelo são decisivos, não a latência de transações individuais.","Como: armazenamento com alto throughput de I/O, bastante RAM (para agregações/hash joins), muitos núcleos e parallel query; um armazenamento colunar ou uma arquitetura MPP é muito eficiente em grande escala.","Escala horizontal: para um DWH grande, uma arquitetura distribuída/MPP (ex.: engines analíticos com sharding) geralmente escala melhor do que aumentar uma única máquina; particionamento + partition pruning reduz os scans.","Nota sobre o engine: não reaproveite as configurações de OLTP — para DWH, preferem-se work_mem/áreas de sort maiores, maior grau de paralelismo e blocos/readahead grandes.","Atenção: não misture OLTP e DWH no mesmo servidor; relatórios pesados sufocam o OLTP. Se possível, mova o analytics para uma réplica/data warehouse separado."],"related":["decide-shard-replica","decide-partition"]},"sol_scale":{"kind":"solution","title":"Princípio geral: vertical vs horizontal + folga + medir primeiro","detail":"Como você escala importa tanto quanto qual recurso você escala. A escala vertical (uma máquina maior) é simples, mas tem teto e ponto único de falha; a horizontal (mais máquinas) escala, mas adiciona complexidade. Em todos os casos, deixe folga para picos de carga e valide a decisão com medições.","steps":["Vertical (scale-up): aumente os recursos (CPU/RAM/IO) de uma única máquina — a opção mais simples e o primeiro passo para a maioria dos casos de OLTP; mas há um teto físico/de custo e um ponto único de falha.","Horizontal (scale-out): adicione read replicas (para carga de leitura) ou sharding (para gravações/volume de dados) — escala quase ilimitada, mas traz complexidade de consistência e operacional.","Folga: não planeje os recursos para 100%; deixe ~30% de folga no pico normal de carga para acomodar picos repentinos, manutenção e crescimento.","Meça primeiro: antes de escalar, confirme o gargalo com medições, ataque o recurso mais restrito e meça de novo após a alteração.","Atenção: a escala horizontal não resolve todos os problemas — transações e joins distribuídos são caros; mude somente quando a escala vertical e a otimização se esgotarem."],"related":["decide-shard-replica","decide-ha"]}}},"solver/slow-write.json":{"id":"slow-write","title":"Gravações lentas (latência de INSERT/UPDATE)","icon":"🐢","category":"Desempenho","intro":"As operações de INSERT/UPDATE/DELETE estão mais lentas que o esperado. Primeiro determinamos pelo que a gravação está esperando (commit/redo, locks, disco ou overhead por linha) e depois descemos passo a passo até a causa raiz.","start":"root","nodes":{"root":{"kind":"step","title":"Pelo que a gravação está esperando?","detail":"Classifique o gargalo observando os wait events: predomina a sincronização de commit/redo (WAL), locks, latência de gravação em disco ou overhead de índices/triggers por linha?","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":"Esperando commit / redo (sincronização do WAL)","next":"commit"},{"label":"Esperando um lock","next":"lock"},{"label":"Suspeita de overhead por linha (índices/triggers)","next":"overhead"},{"label":"A latência de gravação em disco está alta","next":"sol_disk"}]},"commit":{"kind":"step","title":"Padrão de commit ou fsync?","detail":"Um commit separado por linha (autocommit) dispara a sincronização de redo/log tantas vezes quanto há linhas. Por outro lado, se o número de commits for razoável, mas cada commit esperar pelo fsync, o problema é a latência do disco de log.","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 / um commit a cada linha","next":"sol_batch"},{"label":"O commit espera pela sincronização do log (fsync)","next":"sol_disk"}]},"lock":{"kind":"step","title":"Quem está segurando o lock?","detail":"Se a gravação está esperando um lock: outra sessão pode estar segurando a mesma linha/índice, ou muitas sessões podem estar tentando gravar na mesma linha 'quente'.","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":"Outra sessão está segurando o lock","next":"sol_lock"},{"label":"Muitas sessões gravam na mesma linha quente","next":"sol_hotrow"}]},"overhead":{"kind":"step","title":"De onde vem o overhead por linha?","detail":"Todo INSERT/UPDATE também atualiza todos os índices da tabela e dispara eventuais triggers/constraints. Um número excessivo de índices ou um trigger pesado deixa as gravações significativamente mais lentas.","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":"A tabela tem índices demais / desnecessários","next":"sol_index"},{"label":"Há um custo pesado de trigger ou constraint","next":"sol_trigger"}]},"sol_batch":{"kind":"solution","title":"Causa raiz: autocommit / commit por linha","detail":"Um commit separado para cada linha repete a sincronização de redo/log tantas vezes quanto há linhas. Agrupando as operações, você pode reduzir drasticamente o número de commits (e, portanto, de fsyncs).","steps":["Desabilite o autocommit na aplicação e aplique commits em lote, fazendo commit a cada N linhas (ex.: 500-5000).","Use INSERT de várias linhas / caminhos de carga em massa em vez de INSERTs de uma linha (Postgres COPY, Oracle bulk insert, MySQL LOAD DATA, MSSQL BULK INSERT).","Use prepared statements para reduzir o custo de parse repetido (hard parse).","Após a alteração, verifique se a espera 'log file sync' / WRITELOG diminuiu."],"related":["active-sessions"]},"sol_disk":{"kind":"solution","title":"Causa raiz: disco de redo/log lento (latência de fsync)","detail":"Cada commit espera até que o registro de redo/WAL seja gravado em armazenamento durável (fsync). Se o disco de log for lento (alta latência de gravação, IOPS insuficiente), cada commit paga essa latência.","steps":["Mova os arquivos de log/redo para um disco dedicado de baixa latência (de preferência SSD NVMe); separe-os fisicamente dos datafiles.","Meça a latência do armazenamento (estatísticas de I/O de arquivos); se os ms por gravação forem altos, revise o hardware/cache de gravação do RAID.","Em ambientes virtuais/nuvem, aumente os limites de IOPS e throughput provisionados.","Se os requisitos de durabilidade permitirem, considere configurações de group commit / commit delay (ex.: Postgres commit_delay); mas pondere o risco de perda de dados."],"related":[]},"sol_lock":{"kind":"solution","title":"Causa raiz: outra sessão está segurando o lock","detail":"A gravação está esperando um lock de linha/índice mantido por outra sessão. O bloqueador geralmente é uma transação longa ou uma cujo commit foi esquecido.","steps":["Identifique a sessão bloqueadora e examine o que ela está fazendo (um lote longo, ou idle in transaction?).","Se o bloqueador ficar aberto/longo sem motivo, corrija o padrão de commit/rollback na aplicação.","Em uma emergência, encerre o bloqueador de forma controlada (kill session / pg_terminate_backend / KILL).","Mantenha as transações curtas; não espere por interação do usuário dentro de uma transação."],"related":["blocking-sessions","current-locks"]},"sol_hotrow":{"kind":"solution","title":"Causa raiz: contenção de linha quente","detail":"Muitas sessões tentam gravar na mesma linha (ex.: um contador, número de sequência, saldo); todas entram na fila do mesmo lock e as gravações são serializadas.","steps":["Para o padrão de contador quente, divida o valor em buckets paralelos (sharded counter) e some-os na leitura.","Mova a geração de sequência/ID de uma única linha central para um mecanismo de sequence/identity.","Reduza a frequência de atualização: acumule os totais parciais na aplicação e grave-os periodicamente.","Reduza a contenção padronizando a ordem das operações e encurtando a duração dos locks."],"related":["current-locks"]},"sol_index":{"kind":"solution","title":"Causa raiz: overhead excessivo de índices","detail":"Todo índice da tabela é atualizado a cada gravação. Índices em excesso ou não utilizados deixam INSERT/UPDATE diretamente mais lentos.","steps":["Identifique os índices não utilizados/sobrepostos (estatísticas de uso) e remova-os com segurança.","Simplifique índices compostos largos; mescle índices que repetem as mesmas colunas iniciais.","Para grandes cargas em massa, considere desabilitar temporariamente os índices e reconstruí-los após a carga.","Após a alteração, meça de novo a latência de gravação e confirme a melhoria."],"related":["slow-queries"]},"sol_trigger":{"kind":"solution","title":"Causa raiz: trigger / constraint pesado","detail":"Um trigger disparado a cada gravação ou uma constraint sendo validada (especialmente uma verificação de foreign key sem índice) adiciona custo extra a cada linha.","steps":["Torne assíncrono/baseado em fila o trabalho pesado no corpo do trigger (ex.: gravações síncronas de log).","Indexe as colunas de foreign key referenciadoras (filhas); caso contrário, todo DELETE/UPDATE na tabela pai varre a tabela filha por completo.","Quando possível, mova triggers no nível de linha para o nível de instrução.","Mova a lógica de trigger desnecessária, ou que se tornou regra de negócio, para a camada de aplicação."],"related":[]}}},"solver/io-bottleneck.json":{"id":"io-bottleneck","title":"IO wait alto / latência de disco","icon":"💽","category":"Desempenho","intro":"O sistema está esperando IO de disco. Primeiro separamos se a carga é predominantemente de leitura ou de gravação e depois descemos até as causas: buffer cache insuficiente, full table scans, checkpoint storms, limites de IOPS ou spills para o espaço temporário.","start":"root","nodes":{"root":{"kind":"step","title":"O IO é predominantemente de leitura ou de gravação?","detail":"Use as estatísticas de IO de arquivos para determinar se a espera está do lado da leitura (dados sendo lidos do disco) ou do lado da gravação (redo/checkpoint/gravação de dados). Isso divide a árvore em duas.","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":"Principalmente IO de leitura","next":"read"},{"label":"Principalmente IO de gravação","next":"write"}]},"read":{"kind":"step","title":"Por que o IO de leitura está alto?","detail":"Leituras físicas excessivas vêm de três causas principais: o buffer cache é pequeno demais (o working set não cabe na RAM), as consultas fazem full table scans, ou grandes operações de sort/hash fazem spill para o espaço temporário.","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":"O buffer cache hit está baixo, o working set não cabe","next":"sol_cache"},{"label":"As consultas fazem full table scans","next":"sol_scan"},{"label":"Grandes sorts/hashes fazem spill para o espaço temporário","next":"sol_spill"}]},"write":{"kind":"step","title":"Por que o IO de gravação está alto?","detail":"Um gargalo no lado da gravação vem de checkpoints/flushes periódicos que saturam brevemente o disco (checkpoint storm) ou de um armazenamento sem IOPS/throughput suficientes para sustentar a carga.","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":"Ondas repentinas de checkpoint/flush (checkpoint storm)","next":"sol_checkpoint"},{"label":"O armazenamento não acompanha a carga sustentada (limite de IOPS)","next":"sol_iops"}]},"sol_cache":{"kind":"solution","title":"Causa raiz: buffer cache insuficiente","detail":"O conjunto de dados acessado com frequência (working set) não cabe no buffer cache, então os blocos são relidos do disco constantemente. O hit ratio é baixo e as leituras físicas são altas.","steps":["Aumente o tamanho do buffer/cache: Oracle db_cache_size/SGA, Postgres shared_buffers, MySQL innodb_buffer_pool_size, MSSQL max server memory.","Compare o hit ratio e as leituras físicas antes e depois da alteração.","Se a RAM for fisicamente insuficiente, adicione memória ao servidor ou reduza o working set com arquivamento/particionamento.","Se o gargalo real vier de um único padrão de scan, passe para o ramo de scan da árvore de cache hit."],"related":["cache-hit-ratio"]},"sol_scan":{"kind":"solution","title":"Causa raiz: full table scans","detail":"As consultas varrem tabelas grandes de ponta a ponta porque não há índice adequado; isso causa muitas leituras físicas e ainda polui o cache com blocos inúteis.","steps":["Obtenha os planos (EXPLAIN) das consultas com mais leituras físicas e encontre os full scans.","Adicione índices adequados nas colunas de filtro e de join; verifique se o plano passa a usar acesso por índice.","Para tabelas muito grandes, reduza os dados varridos com particionamento por data/intervalo.","Selecione apenas as colunas necessárias em vez de um 'SELECT *' desnecessário para reduzir o número de blocos lidos."],"related":["slow-queries"]},"sol_spill":{"kind":"solution","title":"Causa raiz: sorts/hashes fazendo spill para o espaço temporário","detail":"Grandes operações de sort, hash join ou group by não cabem na memória de trabalho e gravam no espaço temporário (temp/tempdb), gerando IO intenso de leitura/gravação.","steps":["Aumente a configuração de memória de trabalho: Oracle pga_aggregate_target, Postgres work_mem, MySQL sort_buffer_size/join_buffer_size, MSSQL memory grant.","Reduza o volume da operação: aplique filtros cedo, remova sorts desnecessários, melhore a ordem dos joins.","Evite spills para disco adicionando índices adequados para ordenações/agrupamentos usados com frequência.","Mova o espaço temporário para um disco rápido; se o problema persistir, aprofunde com a árvore de pressão em undo/temp."],"related":["slow-queries"]},"sol_checkpoint":{"kind":"solution","title":"Causa raiz: checkpoint storm","detail":"As páginas sujas se acumulam por muito tempo e são gravadas em disco em massa em intervalos curtos; essas ondas repentinas de gravação saturam o IO periodicamente.","steps":["Distribua os checkpoints no tempo: no Postgres, aumente checkpoint_completion_target e equilibre checkpoint_timeout.","No MySQL, defina innodb_io_capacity / innodb_io_capacity_max conforme o armazenamento e ajuste o adaptive flushing.","No MSSQL, suavize as ondas repentinas com indirect checkpoints (target_recovery_time).","No Oracle, equilibre a frequência de checkpoints com fast_start_mttr_target e aumente os arquivos de redo log."],"related":[]},"sol_iops":{"kind":"solution","title":"Causa raiz: IOPS / throughput insuficientes","detail":"O armazenamento não tem IOPS ou largura de banda para atender às solicitações de leitura+gravação que a carga exige; a profundidade da fila e a latência ficam persistentemente altas.","steps":["Meça a latência do disco (ms por solicitação) e compare-a com o limite de IOPS do hardware/nuvem.","Migre para um armazenamento mais rápido (HDD→SSD/NVMe) ou aumente o nível de IOPS/throughput provisionado na nuvem.","Reduza a contenção distribuindo dados, redo/log e espaço temporário em discos diferentes.","Como correção duradoura, reduza a demanda total de IO (indexação, arquivamento, otimização de consultas)."],"related":[]}}},"solver/undo-temp-pressure.json":{"id":"undo-temp-pressure","title":"Pressão em undo / TempDB / espaço temporário","icon":"🧯","category":"Capacidade","intro":"O espaço de undo/rollback, o espaço temporário (temp) ou o TempDB está sob pressão. Determinamos onde está a pressão e descemos até a causa raiz, como um grande sort/hash, uma consulta/transação longa ou um vazamento de espaço.","start":"root","nodes":{"root":{"kind":"step","title":"Onde está a pressão: undo, temp ou contenção no tempdb?","detail":"Classifique a origem da pressão observando o uso de espaço: está enchendo o tablespace de undo/rollback, o espaço temporário (temp) geral, ou, no MSSQL, trata-se de contenção de latch na alocação de páginas do 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":"O espaço de undo/rollback está enchendo (ORA-01555 / ORA-30036)","next":"undo"},{"label":"O espaço temporário (temp) está enchendo (spill de sort/hash)","next":"temp"},{"label":"Contenção de latch de alocação no TempDB (PFS/GAM/SGAM)","next":"tempdb"}]},"undo":{"kind":"step","title":"O que está consumindo o undo?","detail":"A pressão em undo normalmente é de dois tipos: uma QUERY longa precisa de undo antigo para a leitura consistente referente ao seu horário de início (ORA-01555), ou uma TRANSAÇÃO longa/aberta gera tanto undo que enche o espaço e leva ao 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":"Uma consulta longa precisa de undo antigo (ORA-01555)","next":"sol_undo_query"},{"label":"Uma transação longa/aberta está acumulando undo (ORA-30036)","next":"sol_undo_tx"}]},"temp":{"kind":"step","title":"O que está enchendo o espaço temporário?","detail":"A pressão em temp vem de uma grande operação de sort/hash fazendo spill para o disco (normal, mas enorme) ou de uma única sessão segurando temp continuamente (cursor aberto, vazamento, consulta que nunca termina).","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":"Uma grande operação de sort/hash está fazendo spill para o disco","next":"sol_temp_sort"},{"label":"Uma única sessão está segurando temp (vazamento/cursor aberto)","next":"sol_temp_leak"}]},"tempdb":{"kind":"step","title":"A contenção no TempDB é de alocação ou de volume?","detail":"Dois problemas diferentes ocorrem no TempDB do MSSQL: contenção de PAGELATCH nas páginas PFS/GAM/SGAM (muitos objetos temporários pequenos), ou um grande sort/version store enchendo o TempDB em volume.","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":"Contenção de latch em PFS/GAM/SGAM","next":"sol_tempdb_latch"},{"label":"Um grande sort/version store está enchendo o TempDB","next":"sol_temp_sort"}]},"sol_undo_query":{"kind":"solution","title":"Causa raiz: consulta longa + undo insuficiente (ORA-01555)","detail":"O undo antigo de que a consulta longa precisa para uma leitura consistente foi sobrescrito porque a retenção expirou ou o espaço era insuficiente.","steps":["Aumente undo_retention para um valor que supere a duração da consulta mais longa (v$undostat.maxquerylen).","Aumente o tablespace UNDO ou habilite o autoextend para que o período de retenção tenha espaço de respaldo.","Para relatórios críticos, proteja o undo antigo com ALTER TABLESPACE undotbs RETENTION GUARANTEE (DML pode falhar se o espaço encher; tenha cuidado).","Para uma correção permanente, otimize a consulta longa ou mova-a para um standby/réplica."],"related":["slow-queries"]},"sol_undo_tx":{"kind":"solution","title":"Causa raiz: uma transação longa/aberta encheu o undo (ORA-30036)","detail":"Um único DML enorme ou uma transação aberta com commit atrasado gerou undo demais; o tablespace UNDO não conseguiu se estender e o ORA-30036 foi gerado.","steps":["Identifique a transação ativa que mais segura undo (v$transaction.used_ublk) e encontre seu dono.","Execute o DML enorme em blocos por data/intervalo, com commits intermediários.","Corrija na aplicação as sessões com commit esquecido / idle-in-transaction; encerre-as de forma controlada, se necessário.","Adicione espaço temporariamente ao tablespace UNDO; de forma permanente, planeje a retenção e o tamanho do espaço conforme a carga."],"related":["active-sessions"]},"sol_temp_sort":{"kind":"solution","title":"Causa raiz: um grande sort/hash está enchendo o espaço temporário","detail":"Grandes operações de sort/hash/group by que não cabem na memória fazem spill para o espaço temporário e podem enchê-lo.","steps":["Aumente a memória de trabalho: Oracle pga_aggregate_target, Postgres work_mem, MySQL sort_buffer_size, MSSQL memory grant.","Melhore a consulta: remova sorts desnecessários, aplique filtros cedo, adicione índices nas colunas de ordenação/agrupamento.","Divida jobs muito grandes em blocos; limite a concorrência para que não segurem temp todos ao mesmo tempo.","Aumente o espaço temporário e mova-o para um disco rápido; configure o TempDB do MSSQL com vários arquivos com base no número de núcleos."],"related":["slow-queries"]},"sol_temp_leak":{"kind":"solution","title":"Causa raiz: uma sessão está segurando espaço temporário (vazamento)","detail":"Uma única sessão não libera o espaço temporário por causa de cursores não fechados, uma consulta que nunca termina ou tabelas temporárias abertas.","steps":["Identifique a sessão que mais segura temp e o SQL que ela está executando.","Garanta que cursores/result sets e tabelas temporárias sejam fechados corretamente na aplicação.","Encerre de forma controlada a sessão travada/excessivamente longa e verifique se o espaço foi devolvido.","Defina tabelas temporárias globais de modo que sejam limpas automaticamente no fim da sessão/transação."],"related":["active-sessions"]},"sol_tempdb_latch":{"kind":"solution","title":"Causa raiz: contenção de latch em PFS/GAM/SGAM no TempDB","detail":"Quando muitas sessões criam pequenos objetos temporários ao mesmo tempo, surge contenção de PAGELATCH nas páginas de mapa de alocação do TempDB (PFS/GAM/SGAM).","steps":["Configure o número de arquivos de dados do TempDB proporcional ao número de núcleos de CPU, com tamanhos iguais (ex.: 4-8 arquivos, todos com o mesmo tamanho/autogrowth).","No SQL Server moderno, habilite as opções que reduzem a contenção de alocação (memory-optimized tempdb metadata).","Reduza a criação de tabelas temporárias: substitua tabelas #temp desnecessárias por table variables / uma única consulta.","Após a alteração, verifique se os tempos de espera de PAGELATCH diminuíram."],"related":["current-locks"]}}},"solver/long-transaction.json":{"id":"long-transaction","title":"Transação longa / aberta","icon":"⏱️","category":"Locks","intro":"Uma transação longa ou aberta está acumulando locks, undo e bloat. Encontramos a transação responsável, determinamos seu tipo (idle in transaction, lote longo, impacto) e a resolvemos com segurança.","start":"root","nodes":{"root":{"kind":"step","title":"Qual é a transação aberta mais antiga?","detail":"Liste as transações abertas por horário de início. A mais antiga geralmente é a origem do problema. Verifique seu estado: está em execução ativa ou está 'idle in transaction' esperando um commit?","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 (commit esquecido, parada ociosa)","next":"idle"},{"label":"Lote/DML ativo, mas muito longo","next":"batch"},{"label":"Acumulando locks/bloat/undo enquanto a transação continua","next":"impact"}]},"idle":{"kind":"step","title":"Por que ocorre idle in transaction?","detail":"A sessão abriu uma transação, mas fica ociosa sem executar consultas; ou seja, o commit/rollback foi esquecido. Isso segura locks e undo sem necessidade. Basta uma correção na aplicação, ou é preciso encerrá-la com urgência?","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":"A aplicação/connection pool não faz commit (correção permanente)","next":"sol_idle"},{"label":"Preciso encerrá-la agora mesmo","next":"sol_kill"}]},"batch":{"kind":"step","title":"O que a transação longa ativa está fazendo?","detail":"A sessão está de fato em execução (ativa). É um único DML/relatório enorme, ou um bloqueador que está fazendo outras sessões esperarem e precisa ser cortado com urgência?","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":"Um único DML/relatório enorme; precisa ser dividido","next":"sol_batch"},{"label":"Está fazendo outras esperarem; encerre com urgência","next":"sol_kill"}]},"impact":{"kind":"step","title":"O que a transação longa está acumulando?","detail":"Determine o efeito colateral da transação longa: é principalmente um acúmulo de locks fazendo outras sessões esperarem, ou bloat por segurar versões antigas de linhas e impedir a limpeza (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":"Um acúmulo de locks está fazendo outras sessões esperarem","next":"sol_lock_backlog"},{"label":"O acúmulo de versões antigas está impedindo a limpeza (undo/bloat)","next":"sol_bloat"}]},"sol_idle":{"kind":"solution","title":"Causa raiz: a aplicação não faz commit (idle in transaction)","detail":"O pool de conexões ou a aplicação abre uma transação e depois mantém a conexão ociosa sem commit/rollback. Isso segura locks e undo sem necessidade.","steps":["No código da aplicação, garanta commit/rollback em todo caminho em que uma transação é aberta; não espere por entrada do usuário nem por IO longo dentro de uma transação.","Corte automaticamente as transações ociosas: Postgres idle_in_transaction_session_timeout, configurações de conexão/timeout do MySQL, maxLifetime do pool da aplicação.","Configure o pool de conexões segundo o princípio 'autocommit ligado, transações curtas'.","Configure monitoramento: gere um alerta para sessões idle-in-transaction longas."],"related":["active-sessions","blocking-sessions"]},"sol_kill":{"kind":"solution","title":"Solução: encerre a sessão responsável com segurança","detail":"Se uma sessão bloqueadora/longa está fazendo outras esperarem, ela deve ser encerrada de forma controlada. O encerramento dispara um rollback, que pode precisar de espaço/tempo; tenha cuidado.","steps":["Primeiro verifique de que sessão se trata (qual usuário/aplicação, qual job) para não cortar um job crítico.","Encerrar: Oracle ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE; Postgres SELECT pg_terminate_backend(pid); MySQL KILL thread_id; MSSQL KILL session_id;","Se você encerrar uma grande transação de gravação, aguarde a conclusão do rollback (reversão via undo/log).","Após o encerramento, verifique se os locks e as sessões em espera foram liberados; corrija a causa raiz (ociosa/lote) de forma permanente."],"related":["blocking-sessions"]},"sol_batch":{"kind":"solution","title":"Causa raiz: um único DML/relatório enorme","detail":"Um DML que processa milhões de linhas em uma única transação, ou um relatório muito longo, acumula locks e undo/bloat durante toda a sua duração.","steps":["Divida o DML grande em blocos por data/intervalo/chave e faça commit após cada bloco.","Mova o relatório pesado para fora do horário de pico ou desvie-o para um standby/read replica.","Otimize a consulta longa para encurtar sua duração total (e, portanto, o tempo em que segura locks/undo).","Torne o job em lote observável: registre o progresso em log e torne-o retomável do ponto em que parou."],"related":["slow-queries"]},"sol_lock_backlog":{"kind":"solution","title":"Causa raiz: fila de acúmulo de locks","detail":"Por causa dos locks que segura, a transação longa criou uma fila de espera atrás de si; muitas sessões estão esperando pelo mesmo recurso.","steps":["Identifique a sessão na cabeça da cadeia de locks (head blocker); é o único nó que vai liberar a fila.","Encurte o head blocker (commit/rollback) ou encerre-o de forma controlada; acompanhe o esvaziamento da fila.","Para encurtar a duração dos locks, torne as transações menores e defina uma ordem de acesso consistente.","Quando apropriado, mude para abordagens que exijam locks mais fracos (no nível de linha, um nível de isolamento adequado)."],"related":["blocking-sessions","current-locks"]},"sol_bloat":{"kind":"solution","title":"Causa raiz: acúmulo de versões antigas (undo/bloat)","detail":"A transação longa impede a limpeza das versões antigas de linhas anteriores a ela. No Postgres, isso aparece como bloat de tabelas/índices; no Oracle, como pressão em undo.","steps":["Encontre a sessão que segura o xmin/transação mais antigo (Postgres backend_xmin, no Oracle a transação ativa mais antiga).","Encurte/finalize essa transação para que a limpeza (VACUUM / reciclagem de undo) volte a avançar.","No Postgres, após o fim da transação, execute VACUUM nas tabelas com bloat (VACUUM FULL/pg_repack, se necessário).","Adote de forma permanente um padrão de aplicação que mantenha as transações curtas e torne o autovacuum mais agressivo."],"related":[]}}},"solver/plan-regression.json":{"id":"plan-regression","title":"Plano de execução regrediu (lentidão repentina)","icon":"📉","category":"Desempenho","intro":"Uma consulta que ontem era rápida está de repente lenta hoje. Geralmente o otimizador mudou para um plano pior. Encontramos a causa raiz entre estatísticas desatualizadas, sensibilidade a parâmetros, crescimento do volume de dados ou uma mudança repentina de plano, e estabilizamos o plano.","start":"root","nodes":{"root":{"kind":"step","title":"O plano realmente mudou, e quando?","detail":"Há vários planos (plan_hash/plan_generation) para a mesma consulta, e quando a lentidão começou? Coincide com um deploy, upgrade, mudança de parâmetro ou carga grande de dados recente?","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":"As estatísticas podem estar desatualizadas","next":"stats"},{"label":"A mesma consulta se comporta de forma diferente conforme o parâmetro (sniffing/peeking)","next":"sniff"},{"label":"O volume de dados cresceu significativamente","next":"sol_datagrowth"},{"label":"O plano mudou de repente após um upgrade/flush","next":"sol_planflip"}]},"stats":{"kind":"step","title":"As estatísticas estão atualizadas?","detail":"O otimizador baseia suas decisões nas estatísticas. Se a data do último analyze for antiga ou o contador de modificações estiver alto, as estimativas podem ter de fato se desviado, o que leva a um plano ruim.","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":"As estatísticas estão desatualizadas/ausentes","next":"sol_stats"},{"label":"As estatísticas estão atualizadas, mas o plano continua sensível a parâmetros","next":"sniff"}]},"sniff":{"kind":"step","title":"Há sensibilidade a parâmetros?","detail":"A consulta escolhe e coloca em cache um plano com base no valor do parâmetro da sua primeira execução (parameter sniffing no MSSQL / bind peeking no Oracle). Esse plano pode ser ruim para outros valores com distribuição desigual.","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":"Sim, o plano alterna entre bom e ruim conforme o parâmetro","next":"sol_sniff"},{"label":"O plano correto é conhecido, quero fixá-lo de forma permanente","next":"sol_forceplan"}]},"sol_stats":{"kind":"solution","title":"Causa raiz: estatísticas desatualizadas / ausentes","detail":"Com base em estatísticas antigas que não correspondem à realidade, o otimizador estimou errado o número de linhas e escolheu um plano ruim. Esta é a causa mais comum de regressão de plano.","steps":["Colete estatísticas atualizadas das tabelas e índices afetados: Oracle DBMS_STATS.GATHER_TABLE_STATS, Postgres ANALYZE, MySQL ANALYZE TABLE, MSSQL UPDATE STATISTICS ... WITH FULLSCAN.","Crie histogramas/estatísticas estendidas em colunas com distribuição desigual.","Após coletar as estatísticas, verifique o plano com EXPLAIN e confirme que ele voltou ao plano bom.","Para evitar a recorrência, mantenha a coleta automática de estatísticas (autovacuum/auto update stats) habilitada com limites adequados."],"related":["slow-queries"]},"sol_sniff":{"kind":"solution","title":"Causa raiz: sensibilidade a parâmetros (sniffing / bind peeking)","detail":"O plano em cache foi escolhido para o primeiro valor de parâmetro que chegou e é ruim para outros valores com distribuição desigual. O objetivo é garantir que seja escolhido um plano adequado ao valor.","steps":["No MSSQL, defina um comportamento direcionado na consulta crítica com OPTION (RECOMPILE) ou OPTIMIZE FOR; prefira recompile para valores que mudam com frequência.","No Oracle, use adaptive cursor sharing / comportamento bind-aware; se necessário, divida a consulta por faixa de valores.","No Postgres, observe a escolha entre plano genérico e plano customizado; direcione-a com plan_cache_mode, se necessário.","Se for necessário um único plano preciso e permanente, passe para a solução de fixação de plano."],"related":["slow-queries"]},"sol_forceplan":{"kind":"solution","title":"Solução: fixe o plano correto (baseline / force plan)","detail":"Se existir um plano bom conhecido, fixá-lo para que o otimizador não se desvie dele interrompe a regressão de forma permanente.","steps":["Oracle: crie um SQL Plan Baseline para o plano bom (DBMS_SPM) ou aceite-o por meio do SQL Plan Management.","MSSQL: selecione o plano bom no Query Store e force-o com sp_query_store_force_plan.","MySQL/Postgres: direcione o plano com optimizer hints (ex.: index hints) ou pg_hint_plan.","Monitore o desempenho após a fixação; se o padrão dos dados mudar fundamentalmente, reavalie o baseline."],"related":[]},"sol_datagrowth":{"kind":"solution","title":"Causa raiz: o volume de dados cresceu e o plano não serve mais","detail":"À medida que a tabela cresce, um plano que antes era ideal (ex.: nested loop) passa a escalar mal; o otimizador precisa de estatísticas e caminhos de acesso que reflitam corretamente o crescimento.","steps":["Colete estatísticas atualizadas para que o otimizador veja o novo número de linhas.","Adicione índices adequados para as tabelas em crescimento; corrija o caminho de acesso que agora escala mal (ex.: full scan/nested loop).","Em tabelas muito grandes, limite os dados varridos com particionamento por data/intervalo.","Reescreva a consulta de acordo com o crescimento (filtragem antecipada, paginação, views de resumo/materializadas)."],"related":["slow-queries"]},"sol_planflip":{"kind":"solution","title":"Causa raiz: mudança repentina de plano (upgrade / flush do cache)","detail":"O plano mudou de repente após um upgrade de versão, uma mudança de parâmetro ou o esvaziamento do plan cache. O comportamento do otimizador ou as condições do ambiente mudaram.","steps":["Identifique o gatilho da mudança: upgrade/patch, parâmetros do otimizador, uma carga de dados ou um restart/flush do cache.","Se um parâmetro for a causa, reverta a alteração e reavalie-a de forma controlada.","Fixe o plano bom conhecido (baseline / force plan) para que o otimizador não volte a se desviar.","Para regressões após upgrade, revise as configurações de compatibilidade/prontidão do otimizador."],"related":[]}}},"solver/replica-resync.json":{"id":"replica-resync","title":"Réplica quebrada / ressincronização necessária","icon":"🔗","category":"Replicação","intro":"A sincronização entre a réplica/standby e o primário está quebrada. Determine se a replicação parou, quão atrasada está e se a cadeia de posição/GTID está quebrada; depois siga o caminho certo entre pular um erro, esperar ou reconstruir (reseed). Inclui um alerta de split-brain.","start":"root","nodes":{"root":{"kind":"step","title":"Qual é o estado geral da replicação?","detail":"Primeiro leia a saúde da replicação: as threads de aplicação estão rodando, qual o tamanho do lag, há algum erro? Verifique também se os dois nós não estão ambos aceitando gravações (split-brain).","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":"A replicação parou / está falhando","next":"error"},{"label":"Rodando, mas muito atrasada (lag grande)","next":"lag"},{"label":"GTID/posição quebrados, inconsistente — reconstruir","next":"sol_reseed"},{"label":"Ambos os nós estão gravando como primário (suspeita de split-brain)","next":"sol_splitbrain"}]},"error":{"kind":"step","title":"O erro pode ser reparado, ou é necessária uma reconstrução?","detail":"Examine o erro de aplicação. Alguns erros (chave duplicada, linha ausente) podem ser resolvidos pulando com segurança um único evento; mas, se houver inconsistência/corrupção de dados, o único caminho correto é reconstruir a réplica.","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":"Um ou poucos erros de aplicação (podem ser pulados)","next":"sol_skiperror"},{"label":"Inconsistência / corrupção irreparável","next":"sol_reseed"}]},"lag":{"kind":"step","title":"O lag é temporário ou persistente?","detail":"Observe a tendência do lag ao longo do tempo. Ele se fecha (alcança o primário) após um pico temporário de carga, ou continua crescendo de modo que a réplica nunca alcança o primário?","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":"Pico temporário de carga; o lag está diminuindo","next":"sol_lag_wait"},{"label":"Continua crescendo; não consegue alcançar","next":"sol_lag_perm"}]},"sol_skiperror":{"kind":"solution","title":"Solução: pule o erro de aplicação com cuidado","detail":"Se a replicação parou em um único erro de aplicação (ex.: chave duplicada) e você tem certeza de que os dados estão de fato consistentes, pode pular esse evento e continuar o fluxo. É um último recurso; pular às cegas cria divergência silenciosa de dados.","steps":["Primeiro entenda por que o erro ocorreu e verifique a consistência dos dados comparando a linha afetada nos dois lados.","No MySQL sem GTID, pule um único evento: STOP REPLICA; SET GLOBAL sql_replica_skip_counter=1; START REPLICA; (antes da 8.0.26: sql_slave_skip_counter; com cuidado).","Com GTID, para pular a transação com falha, marque esse GTID com uma transação vazia e depois inicie a réplica.","Depois de pular, execute uma verificação de consistência no nível de linha (checksum) entre os dois lados; se houver divergência, passe para um reseed."],"related":["replication-status"]},"sol_reseed":{"kind":"solution","title":"Solução: reconstrua a réplica (reseed / rebuild)","detail":"Se a cadeia de posição/GTID estiver quebrada, os dados tiverem divergido ou houver um erro irreparável, o único caminho confiável é reconstruir a réplica a partir de uma cópia nova obtida do primário.","steps":["Faça um base backup consistente do primário: MySQL xtrabackup/mysqldump ou CLONE, Postgres pg_basebackup, Oracle RMAN duplicate, MSSQL full+log backup.","Limpe o estado antigo na réplica e restaure o backup (Postgres pg_basebackup -R, MSSQL RESTORE ... WITH NORECOVERY).","Inicie a replicação a partir da posição/GTID correta: MySQL CHANGE REPLICATION SOURCE TO ...; START REPLICA; no MSSQL, adicione novamente o banco ao AG (automatic seeding).","Monitore o catch-up; quando o lag chegar a zero, verifique a consistência dos dois lados com um checksum."],"related":["replication-status"]},"sol_lag_wait":{"kind":"solution","title":"Causa raiz: pico temporário de carga (o lag está diminuindo)","detail":"A replicação está saudável; o lag se abriu por causa de uma rajada temporária de gravações no primário ou de oscilação da rede, mas a réplica está alcançando.","steps":["Confirme com várias medições que a tendência do lag está realmente diminuindo.","Até o fim da janela de carga, direcione para o primário apenas as leituras sensíveis ao lag, se necessário.","Se se repetir, distribua as rajadas de gravação (jobs em lote, ETL) no tempo ou mova-as para fora do horário de pico.","Adicione a latência de rede/aplicação ao monitoramento para que o lag temporário seja detectado antes de se tornar persistente."],"related":["replication-status"]},"sol_lag_perm":{"kind":"solution","title":"Causa raiz: a réplica não consegue acompanhar o primário","detail":"O lado de aplicação (apply/redo) não consegue acompanhar o ritmo de alterações gerado pelo primário; o lag continua crescendo. Geralmente é aplicação single-thread, hardware lento na réplica ou gargalo de rede.","steps":["Encontre o gargalo do apply: o limite é o apply single-thread, o disco/CPU da réplica ou a largura de banda da rede?","Habilite/aumente a aplicação paralela: vários replica workers no MySQL (replica_parallel_workers); revise os recursos de aplicação no Postgres/Oracle.","Leve o hardware da réplica pelo menos ao nível do primário (especialmente o IOPS de disco).","Reduza consultas pesadas de leitura desnecessárias na réplica para deixar recursos para a aplicação; se mesmo assim não acompanhar, reavalie após um reseed."],"related":["replication-status"]},"sol_splitbrain":{"kind":"solution","title":"ALERTA: split-brain (dois primários) — risco de perda de dados","detail":"Se os dois nós aceitarem gravações no papel de primário, alterações conflitantes se acumulam nos dois lados; esta é a situação mais perigosa e pode levar à perda de dados. Reduzir as gravações a um único nó vem em primeiro lugar.","steps":["Consolide imediatamente as gravações em um único nó: direcione o tráfego da aplicação estritamente para um primário e torne o outro somente leitura/isole-o.","Identifique o nó autoritativo (correto): decida quais dados são considerados válidos do ponto de vista do negócio.","Compare as alterações conflitantes (divergentes) nos dois lados; reconcilie manualmente as alterações críticas do lado perdedor.","Reconstrua o outro nó com um reseed usando o nó autoritativo como origem; depois configure um mecanismo de fencing/quorum que impeça primários duplos."],"related":["replication-status"]}}},"solver/cache-hit-low.json":{"id":"cache-hit-low","title":"Cache hit ratio baixo (buffer/cache hit)","icon":"🎯","category":"Desempenho","intro":"O cache hit ratio está baixo; os dados são lidos constantemente do disco (ou da origem). Determine se o problema está no buffer/shared cache do banco ou no cache do Redis/aplicação e, em seguida, meça e corrija.","start":"root","nodes":{"root":{"kind":"step","title":"Qual cache tem hit ratio baixo?","detail":"Meça o hit ratio e isole o problema: o buffer/shared cache do banco está baixo (muitas leituras físicas), ou o cache do Redis/aplicação está tendo muitos misses e evictions?","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":"O hit ratio do buffer/shared cache do banco está baixo","next":"dbcache"},{"label":"Muitos misses / evictions no cache do Redis/aplicação","next":"rediscache"}]},"dbcache":{"kind":"step","title":"Por que está lendo do disco: tamanho ou padrão de scan?","detail":"Há duas causas típicas para um buffer hit ratio baixo: os dados acessados com frequência (working set) não cabem na memória (cache pequeno demais), ou grandes full table scans poluem o cache com blocos de uso único e expulsam páginas úteis.","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":"O working set não cabe na RAM (cache pequeno demais)","next":"sol_sizing"},{"label":"Full table scans poluem o cache","next":"sol_scan"}]},"rediscache":{"kind":"step","title":"Por que os misses no Redis: eviction por maxmemory ou gerenciamento de TTL/chaves?","detail":"Se o hit ratio do Redis estiver baixo, ou a memória atingiu maxmemory e as chaves estão sendo removidas (eviction), ou o gerenciamento de TTL/o padrão de cache das chaves é fraco (chaves frias, baixa reutilização).","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 cheio, eviction alta","next":"sol_maxmem"},{"label":"Padrão de TTL/chaves fraco (baixa reutilização)","next":"sol_ttl"}]},"sol_sizing":{"kind":"solution","title":"Causa raiz: o cache é pequeno demais para o working set","detail":"Os dados acessados com frequência são maiores que o buffer/cache alocado, então são constantemente removidos e relidos do disco. O hit ratio é baixo e as leituras físicas são altas.","steps":["Aumente o cache para cobrir o working set: Oracle db_cache_size/SGA, Postgres shared_buffers, MySQL innodb_buffer_pool_size, MSSQL max server memory.","Se a RAM física for insuficiente, adicione memória ao servidor; este é o principal recurso com que o banco escala.","Reduza o working set: arquive/particione dados antigos, elimine colunas/índices desnecessários.","Após a alteração, compare o hit ratio e as leituras físicas para confirmar a melhoria."],"related":["cache-hit-ratio"]},"sol_scan":{"kind":"solution","title":"Causa raiz: o padrão de scan polui o cache","detail":"Grandes full table scans enchem o cache com blocos usados uma vez e descartados, expulsando as páginas quentes; isso reduz o hit ratio.","steps":["Obtenha os planos de execução das consultas com mais leituras físicas e transforme os full scans em acesso por índice (adicione os índices adequados).","Selecione apenas as colunas necessárias em vez de 'SELECT *'; reduza o volume de blocos varridos.","Em tabelas grandes, restrinja os scans ao intervalo relevante com particionamento.","Separe os jobs pesados de analytics/scan do cache de OLTP (uma read replica ou uma janela de tempo separada)."],"related":["slow-queries","cache-hit-ratio"]},"sol_maxmem":{"kind":"solution","title":"Causa raiz: eviction por maxmemory no Redis","detail":"A memória do Redis atingiu o limite de maxmemory; chaves antigas são removidas para abrir espaço para novas (evicted_keys continua subindo). Isso perde entradas ainda necessárias e reduz o hit ratio.","steps":["Aumente maxmemory para corresponder ao working set real, ou reduza o conjunto de dados.","Escolha a política de eviction de acordo com o padrão de acesso (ex.: LRU/LFU: allkeys-lfu costuma ser eficaz para separar o quente do frio).","Elimine estruturas grandes/raramente usadas; reduza os valores, remova campos desnecessários, use tipos de dados adequados.","Se a necessidade for permanente, escale o Redis (mais RAM ou cluster/sharding) e comece a monitorar evicted_keys."],"related":[]},"sol_ttl":{"kind":"solution","title":"Causa raiz: padrão de TTL / cache fraco","detail":"Ou as chaves não recebem TTL algum, e a memória se enche de dados frios, ou o padrão de cache tem baixa reutilização, e a maioria dos requests acaba em miss.","steps":["Atribua TTLs adequados às chaves em cache para que os dados que esfriam expirem sozinhos.","Coloque em cache os dados lidos com frequência (quentes); não coloque em cache dados raramente usados (evite encher o cache com entradas que nunca dão hit).","No padrão cache-aside, implemente corretamente o preenchimento após o miss e use lock/deduplicação de requests contra o 'thundering herd'.","Monitore a razão keyspace_hits/misses e refine o TTL e o design das chaves com base nos dados."],"related":[]}}},"solver/arch-oltp.json":{"id":"arch-oltp","title":"Arquitetura de referência: aplicação OLTP em 3 camadas","icon":"🏛️","category":"Arquitetura de referência","intro":"Aplicações de negócio clássicas (pedidos, pagamentos, estoque) executam um grande número de transações curtas, de linha única e críticas para a consistência (OLTP). Esta árvore mostra passo a passo, a partir da identificação do perfil de carga, quando introduzir o banco relacional primário, um pooler de conexões, read replicas, uma camada de cache, backup + PITR e monitoramento. O objetivo não é 'adicionar tudo de início', mas adicionar o componente certo à medida que cada gargalo é comprovado.","start":"root","nodes":{"root":{"kind":"step","title":"Qual é o seu perfil de carga: mix de transações e requisitos de consistência?","detail":"A primeira decisão em uma arquitetura OLTP é se a carga é realmente transacional (um mix curto de gravações e leituras que exige ACID). Os dados são naturalmente relacionais e a consistência é crítica (dinheiro, estoque, pedidos), a carga é majoritariamente de leitura, ou a carga ainda é muito baixa?","choices":[{"label":"Transações curtas, consistência forte (dinheiro/estoque/pedidos)","next":"primary_db"},{"label":"As leituras predominam fortemente, poucas gravações, e o tráfego está crescendo","next":"scale_reads"},{"label":"A carga é muito baixa; a configuração mais simples basta?","next":"sol_single_node"}]},"primary_db":{"kind":"step","title":"Você escolheu o engine de banco principal, e está preocupado com escala?","detail":"Um engine relacional é a base certa para o núcleo transacional (PostgreSQL, MySQL/InnoDB, Oracle, SQL Server). Com a escolha do engine definida, a próxima questão é a escalabilidade: uma única instância basta por enquanto, ou o número de conexões e a carga de leitura estão aumentando?","choices":[{"label":"O engine está definido; uma única instância basta por enquanto","next":"sol_single_node"},{"label":"O número de conexões disparou, os recursos estão se esgotando","next":"sol_pooler"},{"label":"A carga de leitura está crescendo e sobrecarregando a instância primária de gravação","next":"scale_reads"}]},"scale_reads":{"kind":"step","title":"Como você vai escalar as leituras: réplica ou cache?","detail":"Se a carga de leitura está sobrecarregando a instância primária, há duas opções complementares. Leituras que toleram dados levemente atrasados, como relatórios/listagens, podem ser direcionadas para uma read replica; se os mesmos dados 'quentes' forem solicitados repetidamente, um cache com latência de microssegundos (Redis) alivia o banco.","choices":[{"label":"Muitas leituras de relatórios/listagens; um leve lag é aceitável","next":"sol_read_replica"},{"label":"Os mesmos dados populares são lidos repetidamente","next":"sol_cache"}]},"sol_single_node":{"kind":"solution","title":"Recomendação: comece com um único primário + pool + backup","detail":"Mantenha a arquitetura simples no início: uma única instância primária relacional, um pool de conexões à frente dela e backups regulares bastam. Adicione complexidade somente quando um gargalo medido exigir.","steps":["Banco primário: um engine relacional compatível com ACID, como PostgreSQL ou MySQL/InnoDB; configure corretamente o schema, as constraints e os índices.","Pool de conexões: implante desde o início um pool no lado da aplicação (ex.: HikariCP) ou um PgBouncer no lado do servidor; ele evita tempestades de conexões.","Backup + PITR: backups full diários + arquivamento de WAL/binlog para recuperação point-in-time; armazene os backups em um armazenamento separado.","Atenção: não adicione réplicas/sharding/cache no início; tentar resolver um problema não medido só aumenta a superfície de falha.","Monitoramento: colete desde o início métricas de latência, taxa de erros e número de conexões; não perca o sinal de crescimento."],"related":["decide-pooling","decide-backup"]},"sol_pooler":{"kind":"solution","title":"Recomendação: adicione um pooler de conexões","detail":"Em OLTP, quando cada instância da aplicação abre as próprias conexões, o banco primário sufoca com o overhead de memória e de escalonamento sob milhares de conexões. Colocar um pooler no meio compartilha um pequeno número de conexões reais com o banco entre muitos requests da aplicação.","steps":["PostgreSQL: o PgBouncer (modo transaction pooling) reduz muitos clientes a um pequeno número de conexões de backend.","MySQL: o ProxySQL oferece de forma semelhante multiplexação de conexões e roteamento.","Tamanho do pool: geralmente proporcional ao número de núcleos de CPU; algumas dezenas de conexões de backend bastam. 'Quanto mais, melhor' não se aplica.","Atenção: no transaction pooling, recursos no nível de sessão (prepared statements, tabelas temporárias, variáveis de sessão) são restritos; escreva a aplicação de acordo.","Próximo passo: se o pool também saturar, o problema não são as conexões, mas a duração das consultas/transações; cace as consultas lentas e as transações longas."],"related":["decide-pooling","connection-storm"]},"sol_read_replica":{"kind":"solution","title":"Recomendação: adicione uma read replica","detail":"As gravações permanecem no primário enquanto o tráfego somente leitura (relatórios, listagens, busca) é direcionado para uma ou mais réplicas assíncronas alimentadas pelo primário. Isso libera o primário para gravações e leituras críticas para a consistência.","steps":["Topologia: primário -> uma ou mais réplicas assíncronas; a aplicação separa leituras/gravações e envia as leituras para a réplica.","Engine: PostgreSQL streaming replication, réplicas do MySQL ou read replicas gerenciadas.","Quando: para leituras que toleram um pouco de lag, como relatórios/analytics/listagens; quando você quer aliviar a CPU/IO do primário.","Atenção: o lag de replicação produz leituras defasadas; atenda a partir do primário os fluxos que precisam 'ler imediatamente a própria gravação' (read-your-writes).","Próximo passo: se as réplicas também não bastarem, considere um cache para dados quentes ou sharding no lado da gravação."],"related":["replication-lag","decide-shard-replica"]},"sol_cache":{"kind":"solution","title":"Recomendação: adicione uma camada de cache (Redis)","detail":"Se os mesmos dados populares (sessões, catálogo, perfis, fragmentos de página) são lidos repetidamente, coloque um cache em memória à frente do banco e atenda a maioria das leituras sem sequer chegar ao banco. A latência cai e o banco primário fica aliviado.","steps":["Engine: o padrão cache-aside com Redis (ou Memcached); a aplicação verifica primeiro o cache e, em caso de miss, busca no banco e grava no cache.","TTL + invalidação: dê a cada chave um TTL razoável; na gravação, exclua/atualize a chave relacionada para que não restem dados defasados.","Quando: muitas leituras, dados que mudam relativamente pouco, e as mesmas chaves solicitadas repetidamente.","Atenção: cache stampede; quando uma chave popular expira, milhares de requests podem atingir o banco ao mesmo tempo. Use lock/single-flight e TTLs com jitter.","Atenção: não trate o cache como a 'fonte da verdade'; a verdade durável sempre fica no banco, e a aplicação deve continuar funcionando recorrendo ao banco mesmo que o cache falhe."],"related":["decide-cache","cache-hit-low"]}}},"solver/arch-dwh.json":{"id":"arch-dwh","title":"Arquitetura de referência: data warehouse / analytics","icon":"🏛️","category":"Arquitetura de referência","intro":"Consultas analíticas (relatórios, agregações, scans amplos) são fundamentalmente diferentes das transações OLTP: poucas, mas muito amplas e longas. A partir da decisão de separar o analytics do OLTP, esta árvore percorre passo a passo componentes como o método de carga (ETL vs ELT), armazenamento colunar/columnstore, modelagem em star schema, particionamento + compressão e pré-cálculo com materialized views, ponderando o trade-off entre concorrência e throughput.","start":"root","nodes":{"root":{"kind":"step","title":"Sua carga analítica roda no mesmo banco que o OLTP?","detail":"O erro mais comum é executar relatórios pesados no banco transacional de produção e degradar a latência do OLTP. A primeira decisão é a separação: o analytics ainda roda na instância OLTP, você está montando um ambiente analítico separado, ou está decidindo como levar os dados até lá?","choices":[{"label":"Os relatórios ainda rodam no OLTP de produção; eles deixam o OLTP lento","next":"sol_separate"},{"label":"Já existe um warehouse separado; como devo carregar os dados?","next":"load_method"},{"label":"Já existe um warehouse; as consultas continuam lentas, como devo modelar?","next":"model"}]},"load_method":{"kind":"step","title":"Onde você vai transformar: antes ou depois da carga?","detail":"Ao mover dados das origens para o warehouse, você fará a limpeza/transformação em uma camada de processamento separada antes da carga (ETL), ou carregará primeiro os dados brutos no warehouse e os transformará com SQL dentro do poderoso engine do warehouse (ELT)? A decisão depende do poder de processamento do warehouse e da necessidade de flexibilidade de schema.","choices":[{"label":"A transformação é complexa/externa; faça-a antes da carga","next":"sol_etl"},{"label":"O warehouse é poderoso; carregue bruto e transforme dentro com SQL","next":"sol_elt"}]},"model":{"kind":"step","title":"O gargalo das consultas está no layout de armazenamento ou no modelo de dados?","detail":"Se o analytics está lento, há duas alavancas principais. Scans amplos leem a linha inteira no armazenamento por linhas; o armazenamento colunar lê apenas as colunas necessárias e comprime bem. Do lado do modelo, a normalização excessiva significa muitos joins que deixam as consultas lentas; um star schema (fato + dimensão) simplifica as coisas para analytics.","choices":[{"label":"Scans amplos de agregação estão lentos; poucas colunas são lidas","next":"sol_columnar"},{"label":"Joins demais, schema normalizado complexo","next":"sol_star"},{"label":"O mesmo relatório pesado produz o mesmo resultado repetidamente","next":"sol_matview"}]},"sol_separate":{"kind":"solution","title":"Recomendação: separe o analytics do OLTP","detail":"Cargas transacionais e analíticas se sufocam mutuamente no mesmo engine: relatórios longos seguram locks/IO e atrasam as transações curtas. Mover o analytics para um destino separado (uma read replica ou um warehouse analítico separado) alivia os dois lados.","steps":["Primeiro passo: direcione relatórios leves para uma read replica do OLTP e o analytics pesado para um engine analítico separado.","Engine analítico: um engine colunar/analítico (ex.: SQL Server com columnstore, ClickHouse ou um warehouse colunar) é muitas vezes mais rápido que o armazenamento por linhas em scans amplos.","Concorrência vs throughput: o OLTP é ajustado para muitas transações pequenas (alta concorrência), o warehouse para poucas consultas enormes (alto throughput); não dá para otimizar os dois na mesma máquina.","Atenção: o warehouse não é uma 'cópia em tempo real da produção'; são dados carregados em intervalos, atrasados, mas organizados para análise.","Próximo passo: após separar, decida o método de carga (ETL/ELT) e o modelo (star schema)."],"related":["decide-sqlnosql","slow-query"]},"sol_etl":{"kind":"solution","title":"Recomendação: ETL (transformar antes da carga)","detail":"No ETL, os dados são extraídos das origens (Extract), limpos e transformados em uma camada de processamento separada (Transform) e só então carregados no warehouse (Load). Somente dados limpos e conformes ao modelo entram no warehouse.","steps":["Quando: a transformação é complexa, é preciso combinar várias origens, ou você quer que dados brutos/sensíveis nunca entrem no warehouse.","Fluxo: origem (OLTP/arquivo/API) → camada de transformação → carga em lote no warehouse.","Prós: mantém limpo o armazenamento do warehouse; dados sensíveis podem ser mascarados antes da carga.","Contras: a transformação depende do poder de um sistema separado; não aproveita a flexibilidade do SQL do warehouse.","Atenção: carregue em uma janela de lote (ex.: durante a madrugada); planeje para evitar conflitos com consultas pesadas durante a carga."],"related":["decide-capacity"]},"sol_elt":{"kind":"solution","title":"Recomendação: ELT (transformar dentro do warehouse)","detail":"No ELT, os dados brutos são carregados primeiro no warehouse e a transformação acontece dentro do próprio engine SQL poderoso do warehouse. Como os warehouses colunares modernos têm alto poder de processamento, você move os dados uma vez e os processa lá dentro, em vez de levar a transformação até os dados.","steps":["Quando: o engine do warehouse é poderoso e escalável; você também quer manter os dados brutos (auditoria/reprocessamento).","Fluxo: origem → camada bruta (staging) → views SQL/de transformação → camada modelada de fatos/dimensões.","Prós: um único engine, flexível; como os dados brutos são mantidos, você pode alterar a transformação depois e regenerar.","Contras: dados brutos (possivelmente sensíveis) entram no warehouse; controle de acesso e mascaramento são obrigatórios.","Atenção: modele em camadas (raw → staging → mart); escreva as transformações de forma idempotente para que as reexecuções sejam seguras."],"related":["decide-capacity"]},"sol_columnar":{"kind":"solution","title":"Recomendação: armazenamento colunar / columnstore + compressão","detail":"Consultas analíticas normalmente varrem poucas colunas em todas as linhas. O armazenamento colunar guarda os dados coluna por coluna; lê apenas as colunas necessárias, comprime muito bem porque valores semelhantes ficam lado a lado, e o IO cai drasticamente.","steps":["Engine/recurso: columnstore index do SQL Server, ClickHouse ou warehouses colunares; extensões colunares no lado do PostgreSQL.","Compressão: o layout colunar oferece alta compressão; menos disco, menos bytes lidos, scans mais rápidos.","Particionamento: particione as tabelas de fatos grandes por data/intervalo para que o partition pruning ignore completamente as partições irrelevantes.","Atenção: o colunar é ruim para muitas atualizações de linha única/leituras pontuais; não mova o OLTP para ele.","Concorrência vs throughput: o colunar brilha em poucas consultas de scan enormes, não em milhares de consultas pequenas concorrentes."],"related":["decide-partition","io-bottleneck"]},"sol_star":{"kind":"solution","title":"Recomendação: star schema (fato + dimensão)","detail":"Em um modelo analítico, uma tabela de fatos com as medidas fica no centro, cercada por tabelas de dimensão descritivas. Em comparação com um schema excessivamente normalizado, o número de joins diminui, as consultas ficam mais simples e o engine gera planos melhores.","steps":["Estrutura: o fato (medidas + chaves de dimensão) no centro; as dimensões (tempo, produto, cliente) formam uma estrela ao redor.","Quando: os relatórios fazem join de muitas tabelas e o schema normalizado se afoga em joins.","Desnormalização: a desnormalização deliberada é normal em analytics; a consistência é garantida no processo de carga (ETL/ELT).","Próximo passo: pré-calcule com materialized views as agregações pesadas executadas com frequência.","Atenção: não converta o OLTP em star schema; este modelo é para analytics, não para gravações transacionais."],"related":["decide-index"]},"sol_matview":{"kind":"solution","title":"Recomendação: pré-cálculo com materialized views","detail":"Se a mesma agregação pesada (receita diária, resumo mensal) é executada repetidamente e produz o mesmo resultado, armazene fisicamente o resultado em uma materialized view e faça os relatórios lerem o resultado pré-calculado. O cálculo pesado é executado uma vez e as consultas retornam instantaneamente.","steps":["Quando: determinadas consultas de resumo varrem com frequência e repetidamente a mesma tabela grande.","Atualização: atualize a materialized view de forma agendada (ex.: lote noturno ou incremental); defina a frequência conforme a necessidade de atualidade dos dados.","Engine: materialized view do PostgreSQL (REFRESH), materialized view do Oracle (inclusive query rewrite), indexed view do SQL Server.","Atenção: a view vem com uma janela de defasagem; onde dados em tempo real forem exigidos, uma consulta ao vivo é obrigatória.","Próximo passo: se o custo de atualização for alto, considere refresh incremental ou refresh por partição."],"related":["decide-partition"]}}},"solver/arch-microservice.json":{"id":"arch-microservice","title":"Arquitetura de referência: camada de dados de microsserviços","icon":"🏛️","category":"Arquitetura de referência","intro":"Em microsserviços, a decisão mais crítica é a propriedade dos dados: cada serviço deve ser dono dos seus dados (database-per-service) e não deve acessar diretamente as tabelas de outro serviço. Esta árvore percorre passo a passo o antipadrão do banco compartilhado, como obter consistência entre serviços sem transações distribuídas (saga + outbox), a sincronização de dados com CDC e as consultas entre serviços (API composition vs um read model CQRS). O objetivo é manter os serviços realmente independentes e implantáveis separadamente.","start":"root","nodes":{"root":{"kind":"step","title":"Como os serviços são donos dos dados: um banco compartilhado ou um por serviço?","detail":"O isolamento dos dados é a espinha dorsal de uma arquitetura de microsserviços. Os serviços usam um único banco compartilhado (uma dependência oculta), cada serviço tem o próprio banco (o padrão correto), ou o verdadeiro desafio é a consistência/as consultas entre serviços? Estabeleça primeiro o estado atual.","choices":[{"label":"Todos os serviços usam um único banco compartilhado","next":"sol_db_per_service"},{"label":"Cada serviço tem o próprio banco, mas as operações precisam de consistência entre serviços","next":"consistency"},{"label":"Cada serviço tem o próprio banco, mas são necessárias consultas/relatórios combinados","next":"query"}]},"consistency":{"kind":"step","title":"Como você vai manter consistente um fluxo entre serviços?","detail":"Para uma operação que abrange vários serviços (criar pedido → receber pagamento → baixar estoque), uma transação distribuída clássica (2PC) é frágil e não escala. Em vez disso, divida o fluxo em etapas de transação local + evento (saga) e publique os eventos de forma confiável (outbox). Com qual problema você está lidando?","choices":[{"label":"Estou tentando manter atômico um fluxo com vários serviços (2PC?)","next":"sol_saga"},{"label":"Não consigo tornar consistentes a gravação local e a publicação do evento (dual write)","next":"sol_outbox"}]},"query":{"kind":"step","title":"Como você vai atender a uma consulta que mostra dados de vários serviços?","detail":"Depois que os dados são divididos entre serviços, não é possível montar uma tela combinada com um único join. Há duas abordagens principais: chamar as APIs dos serviços envolvidos no momento da requisição e mesclar os resultados (API composition), ou manter um modelo de leitura pré-combinado alimentado por eventos (CQRS). A frequência e a complexidade das consultas determinam a escolha.","choices":[{"label":"Join simples e pouco frequente; basta chamar alguns serviços e mesclar","next":"sol_api_composition"},{"label":"Consulta combinada complexa/frequente; é necessário um modelo de leitura pronto","next":"sol_cqrs"}]},"sol_db_per_service":{"kind":"solution","title":"Recomendação: database-per-service (divida o banco compartilhado)","detail":"Serviços que compartilham um banco são uma dependência oculta e perigosa: a alteração de schema de um serviço quebra os outros, a propriedade das tabelas fica indefinida e a implantação independente se torna impossível. Cada serviço deve ser dono dos seus dados.","steps":["Princípio: cada serviço lê/grava apenas no próprio banco; não pode acessar diretamente as tabelas de outro serviço, apenas solicitar dados pela API desse serviço.","Independência de engine: cada serviço pode escolher um engine conforme suas necessidades (ex.: PostgreSQL para pedidos, MongoDB para o catálogo, Elasticsearch para busca, Redis para o carrinho).","Antipadrão: o 'banco compartilhado': tabelas comuns, joins cruzados e um único schema; isso não é microsserviços, mas um monólito distribuído.","Decomposição: primeiro a separação lógica (schema/usuário separados), depois a separação física; remova os joins entre tabelas de serviços diferentes.","Atenção: após a divisão, surgem problemas de consistência (saga/outbox) e de consultas combinadas (composition/CQRS); esse é o custo natural desta transição."],"related":["decide-isolation","decide-sqlnosql"]},"sol_saga":{"kind":"solution","title":"Recomendação: padrão saga (evite transações distribuídas)","detail":"Não tente tornar atômica com uma única transação distribuída (2PC) uma operação que abrange vários serviços; o 2PC segura locks e traz fragilidade de ponto único e baixa disponibilidade. Em vez disso, divida o fluxo em etapas que sejam, cada uma, uma transação local no próprio serviço, e desfaça-as com etapas de compensação em caso de falha.","steps":["Princípio: modele o fluxo como uma cadeia de transações locais + eventos; cada etapa dispara a seguinte.","Compensação: se uma etapa falhar, execute ações compensatórias que desfaçam as etapas anteriores (ex.: cancelar o pedido se o pagamento falhar).","Coreografia vs orquestração: em fluxos simples, os serviços disparam uns aos outros com eventos (coreografia); em fluxos complexos, um orquestrador central gerencia as etapas.","Atenção: uma saga não é atômica; ela oferece consistência eventual. Estados intermediários podem ficar visíveis externamente, então projete as regras de negócio de acordo.","Atenção: não use 2PC/XA em microsserviços de alta escala; o bloqueio e a duração dos locks vão travar o sistema."],"related":["decide-isolation","long-transaction"]},"sol_outbox":{"kind":"solution","title":"Recomendação: transactional outbox (a armadilha do dual write)","detail":"Quando um serviço quer tanto gravar no próprio banco quanto publicar um evento, fazer as duas coisas separadamente é a armadilha do 'dual write': se uma tiver sucesso e a outra falhar, o sistema fica inconsistente. A solução é gravar o evento em uma tabela outbox na MESMA transação local dos dados de negócio e depois publicá-lo com um processo separado.","steps":["Princípio: o registro de negócio + o registro do evento são gravados na tabela outbox em uma única transação local; ou ambos acontecem ou nenhum (atômico).","Publicação: um processo relay/CDC separado lê as linhas da outbox, publica-as em um message broker (ex.: Kafka) e as marca.","Com CDC: uma ferramenta de CDC como o Debezium lê o log do banco (WAL/binlog) e leva as alterações da outbox ao Kafka de forma confiável.","Idempotência: os consumidores podem receber o mesmo evento mais de uma vez; processe de forma idempotente usando o id do evento (assuma entrega at-least-once).","Atenção: não use diretamente a abordagem 'gravar primeiro no banco e depois publicar no Kafka'; uma queda no momento da publicação causa perda de eventos."],"related":["replication-lag"]},"sol_api_composition":{"kind":"solution","title":"Recomendação: API composition (combinar no momento do request)","detail":"Onde são necessários dados combinados, o chamador (ex.: um gateway/BFF) chama as APIs dos serviços relevantes e combina os resultados em memória. É a solução mais simples para joins simples que abrangem poucos serviços; nenhuma cópia extra de dados é mantida.","steps":["Princípio: um compositor (API gateway/BFF) chama o service-A e o service-B, combina o resultado e o retorna.","Quando: o join é simples, abrange poucos serviços e a frequência das consultas é moderada; você não quer o ônus de manutenção de um read model extra.","Prós: nenhum armazenamento ou sincronização de dados extra; cada serviço retorna os próprios dados atuais.","Atenção: em joins entre muitos serviços ou grandes conjuntos de dados, a latência se acumula e os joins em memória são caros.","Próximo passo: se o join ficar complexo ou muito frequente, passe para um read model CQRS."],"related":[]},"sol_cqrs":{"kind":"solution","title":"Recomendação: read model CQRS (alimentado por eventos)","detail":"Para consultas combinadas complexas e frequentes, mantenha um read model pré-combinado e otimizado para consultas (materialized view/cópia desnormalizada), alimentado pelos eventos emitidos pelos serviços. O lado da gravação fica nos serviços; o lado da leitura entrega rapidamente dados prontos a partir de um único lugar.","steps":["Princípio: os serviços publicam alterações de estado como eventos; uma projeção escuta esses eventos e atualiza o read model.","Escolha do armazenamento: escolha o armazenamento do read model pelo tipo de consulta: Elasticsearch para busca, MongoDB para documentos flexíveis, Redis para acesso rápido por chave, PostgreSQL para relatórios relacionais.","Quando: a consulta combinada é complexa/frequente, é exigida baixa latência e o custo da API composition cresceu.","Atenção: o read model tem consistência eventual; fica levemente atrasado até que os eventos sejam processados.","Idempotência: a projeção pode ver o mesmo evento duas vezes; atualize de forma idempotente com o id do evento e controle ordem/versão, se necessário."],"related":["decide-cache"]}}},"solver/arch-eventdriven.json":{"id":"arch-eventdriven","title":"Arquitetura de referência: orientada a eventos / CQRS","icon":"🏛️","category":"Arquitetura de referência","intro":"Em uma arquitetura orientada a eventos, os serviços publicam eventos em um log de eventos (ex.: Kafka) em vez de chamarem uns aos outros diretamente, e os consumidores os processam de forma assíncrona. A partir da construção do backbone de eventos, esta árvore percorre passo a passo event sourcing (derivar o estado dos eventos), separação de comandos/consultas com CQRS, projeção do read model, idempotência, tolerância à consistência eventual e a falácia da 'entrega exactly-once'. O objetivo é um sistema fracamente acoplado e escalável, cujos trade-offs de consistência sejam bem compreendidos.","start":"root","nodes":{"root":{"kind":"step","title":"Qual decisão você enfrenta na sua arquitetura orientada a eventos?","detail":"A base de um sistema orientado a eventos é um log de eventos durável que conecta os serviços por meio de eventos assíncronos. Você ainda está construindo o backbone, quer derivar o estado dos eventos (event sourcing), ou está separando os caminhos de leitura e gravação (CQRS)?","choices":[{"label":"Estou construindo o backbone de eventos que conecta os serviços","next":"sol_event_log"},{"label":"Quero derivar o estado do histórico de eventos","next":"sol_event_sourcing"},{"label":"Quero separar os caminhos de leitura e gravação (CQRS)","next":"cqrs_split"}]},"cqrs_split":{"kind":"step","title":"Como você vai construir o lado da leitura no CQRS, e qual é a sua tolerância de consistência?","detail":"No CQRS, os lados de comando (gravação) e de consulta (leitura) são separados; os eventos de gravação atualizam a projeção que alimenta o read model. A questão-chave: você tolera que o read model fique atrás das gravações (consistência eventual), ou espera que cada evento seja processado exatamente uma vez?","choices":[{"label":"Vou alimentar o read model a partir dos eventos via projeção","next":"sol_read_model"},{"label":"As leituras precisam estar atualizadas; lag é inaceitável","next":"sol_consistency"},{"label":"Quero eventos processados 'exactly once'","next":"sol_idempotency"}]},"sol_event_log":{"kind":"solution","title":"Recomendação: um backbone de log de eventos durável","detail":"No centro de uma arquitetura orientada a eventos está um log de eventos durável e ordenado, no qual os produtores gravam e que os consumidores leem no próprio ritmo. Esse backbone desacopla os serviços no tempo e na escala.","steps":["Engine: Apache Kafka (ou uma plataforma semelhante baseada em log): um log de eventos particionado, persistente e que pode ser reproduzido (replay).","Partições e ordenação: a ordenação é garantida apenas dentro de uma partição; preserve a ordem direcionando os eventos da mesma entidade para a mesma chave.","Independência dos consumidores: cada consumer group mantém o próprio offset; pode reler/retroceder sem afetar o produtor.","Retenção: retenha o log por tempo suficiente para que novos consumidores e reprocessamentos possam ler o histórico.","Atenção: o Kafka não é uma fila, mas um log que pode ser reproduzido; assuma entrega at-least-once e escreva consumidores idempotentes."],"related":[]},"sol_event_sourcing":{"kind":"solution","title":"Recomendação: event sourcing (derivar o estado dos eventos)","detail":"No event sourcing, você não armazena o estado atual de uma entidade, mas todos os eventos de alteração (imutáveis) aplicados a ela; o estado atual é derivado aplicando esses eventos em ordem. Oferece um histórico de auditoria completo e a capacidade de voltar a qualquer ponto do passado.","steps":["Princípio: o fluxo de eventos é a fonte da verdade; o estado é reconstruído reproduzindo os eventos desde o início (ou um snapshot + os eventos seguintes).","Snapshots: para fluxos longos, tire snapshots periódicos para evitar reproduzir desde o início toda vez e aplique por cima os eventos posteriores.","Prós: uma trilha de auditoria completa, a resposta para 'como chegamos a este estado' ao longo do tempo e a capacidade de derivar diferentes read models.","Atenção: os schemas dos eventos evoluem; ler eventos antigos exige versionamento/upcasting, porque os eventos vivem para sempre.","Atenção: não é necessário em todos os cenários; se o estado atual bastar, o CRUD clássico é mais simples. Geralmente é usado junto com CQRS."],"related":[]},"sol_read_model":{"kind":"solution","title":"Recomendação: projeção do read model","detail":"No CQRS, o lado da gravação produz eventos; uma projeção escuta esses eventos e atualiza um read model otimizado para consultas (view desnormalizada). As leituras são atendidas a partir desse modelo pronto, totalmente separado do caminho de gravação, e os dois lados escalam de forma independente.","steps":["Princípio: eventos → projeção → armazenamento de leitura; as consultas de leitura atingem apenas esse modelo desnormalizado.","Escolha do armazenamento: pelo tipo de consulta: Elasticsearch para busca, MongoDB para documentos flexíveis, Redis para acesso rápido, PostgreSQL para relacional.","Reconstrução: como o read model é derivado dos eventos, ele pode ser descartado e reconstruído do zero relendo o log.","Idempotência: a projeção pode ver o mesmo evento mais de uma vez; atualize de forma idempotente usando o id/versão do evento.","Atenção: o read model tem consistência eventual; fica atrás das gravações até que o evento seja processado, então projete a interface de acordo."],"related":["decide-cache"]},"sol_consistency":{"kind":"solution","title":"Recomendação: projete para tolerar a consistência eventual","detail":"Em sistemas orientados a eventos/CQRS, o read model fica levemente atrás das gravações (consistência eventual). Em vez de tentar 'eliminar' isso, projete para tolerá-lo; mantenha separados os poucos fluxos que exigem consistência imediata estrita.","steps":["Princípio: a maioria dos fluxos de negócio tolera consistência com um pequeno atraso; dê ao usuário o retorno 'solicitação recebida, em processamento'.","Read-your-writes: se os usuários precisam ver as próprias gravações imediatamente, atenda essa leitura a partir do lado da gravação/de forma síncrona.","Núcleo que exige consistência estrita: mantenha o trabalho que precisa de consistência imediata absoluta, como um saldo monetário, dentro de um único serviço/banco com uma transação ACID; não o distribua por eventos.","Atenção: não esconda a consistência eventual; trate explicitamente os estados intermediários/transitórios nas telas e nas regras de negócio.","Atenção: o objetivo de 'tornar o sistema inteiro fortemente consistente' destrói os benefícios da arquitetura orientada a eventos (escala, acoplamento fraco)."],"related":["decide-ha","replication-lag"]},"sol_idempotency":{"kind":"solution","title":"Recomendação: idempotência (a falácia do exactly-once)","detail":"Em mensageria distribuída, a 'entrega exactly-once' de ponta a ponta é, na prática, uma falácia; mensagens duplicadas são inevitáveis por causa da rede e das novas tentativas. O objetivo correto é o processamento idempotente: processar o mesmo evento duas vezes deve dar o mesmo resultado que processá-lo uma vez.","steps":["Princípio: aceite a entrega at-least-once; torne as duplicatas inofensivas no consumidor.","Método: dê a cada evento um id único; registre os ids processados e ignore-os se chegarem de novo (dedup), ou use operações naturalmente idempotentes (upsert, set).","Semântica exactly-once: o recurso 'exactly-once' do Kafka vale apenas dentro do limite de transação do próprio Kafka; efeitos colaterais em um banco externo não são garantidos sem idempotência.","Ordenação: evite reordenação direcionando os eventos da mesma entidade para a mesma chave de partição.","Atenção: a suposição 'configurei entrega exactly-once, não preciso de dedup' produz inconsistências em produção; processe sempre de forma idempotente."],"related":[]}}},"solver/arch-multiregion.json":{"id":"arch-multiregion","title":"Arquitetura de referência: multirregião / global","icon":"🏛️","category":"Arquitetura de referência","intro":"Quando os usuários estão distribuídos geograficamente ou é exigida resiliência a um desastre regional, os dados se espalham por várias regiões. Esta árvore percorre passo a passo a localidade de leitura (uma read replica em cada região), a topologia de gravação (single-leader vs multi-leader vs quorum), residência de dados/conformidade (GDPR), resolução de conflitos e os trade-offs entre RPO/RTO e latência. A verdade básica: por causa das leis da física, baixa latência, consistência forte e gravações multirregião não podem ser plenamente alcançadas ao mesmo tempo; um trade-off deliberado é obrigatório.","start":"root","nodes":{"root":{"kind":"step","title":"Por que ir para multirregião: localidade de leitura, gravações/resiliência ou conformidade?","detail":"Uma arquitetura multirregião é cara e complexa; esclareça a motivação. Você quer baixa latência de leitura para usuários distantes, gravações entre regiões/resiliência a desastres, ou o requisito real é que os dados fiquem em um país específico (residência legal)?","choices":[{"label":"Leituras rápidas para usuários distantes; as gravações podem ficar em uma região","next":"sol_read_locality"},{"label":"São necessárias gravações entre regiões / resiliência à perda de uma região","next":"write_topology"},{"label":"Os dados devem legalmente permanecer em um país/região específico","next":"sol_data_residency"}]},"write_topology":{"kind":"step","title":"Qual deve ser a topologia de gravação: single-leader, multi-leader ou quorum?","detail":"Para gravações entre regiões, a decisão-chave é o modelo de liderança. Todas as gravações vão para uma única região (simples, consistente, mas gravações remotas são lentas), toda região pode gravar (baixa latência de gravação, mas com conflitos), ou uma gravação é aceita com a confirmação da maioria das regiões (quorum: consistente, mas com latência adicional)?","choices":[{"label":"Uma região grava, as outras leem (simples e consistente)","next":"sol_single_leader"},{"label":"Toda região pode gravar localmente (baixa latência de gravação)","next":"sol_multi_leader"},{"label":"Gravar com confirmação da maioria; a consistência vem primeiro","next":"sol_quorum"}]},"sol_read_locality":{"kind":"solution","title":"Recomendação: uma read replica por região (localidade de leitura)","detail":"As gravações permanecem em uma única região primária enquanto você coloca em cada região de usuários uma read replica alimentada por ela. Os usuários leem da réplica mais próxima e a latência de leitura cai; como as gravações continuam indo para um único centro, o modelo de consistência permanece simples.","steps":["Topologia: uma região primária (gravações) → uma read replica assíncrona em cada região de usuários.","Engines: PostgreSQL streaming replication, réplicas do MySQL entre regiões ou read replicas globais gerenciadas.","Roteamento: a aplicação direciona as leituras para a réplica mais próxima e as gravações para a região primária (geo DNS / roteador inteligente).","Atenção: o lag de replicação entre regiões causa leituras defasadas; faça os fluxos que precisam de read-your-writes lerem do primário.","RPO/RTO: se a região primária cair, uma réplica assíncrona pode ser promovida com alguma perda de dados (RPO > 0); prepare o plano de failover com antecedência."],"related":["replication-lag","decide-shard-replica"]},"sol_single_leader":{"kind":"solution","title":"Recomendação: gravações single-leader","detail":"Todas as gravações vão para uma única região líder; as outras regiões são read replicas alimentadas de forma assíncrona por esse líder. É o modelo mais simples e de consistência mais forte; não há conflitos porque há um único ponto de gravação. O preço é a alta latência de gravação a partir de regiões remotas.","steps":["Princípio: uma única autoridade de gravação → sem conflitos, modelo de consistência simples.","Quando: o volume de gravações pode ser atendido em uma região e a latência de gravação remota é tolerável.","Failover: se a região líder cair, uma réplica é promovida a líder; failover automático/controlado e proteção contra split-brain são obrigatórios.","RPO/RTO: com replicação assíncrona, uma pequena quantidade de dados pode ser perdida no failover (RPO); a replicação síncrona dá RPO=0, mas aumenta a latência de gravação.","Atenção: as gravações de usuários remotos são lentas; se a localidade de gravação for crítica, considere multi-leader ou quorum."],"related":["decide-ha","failover-drill"]},"sol_multi_leader":{"kind":"solution","title":"Recomendação: gravações multi-leader + resolução de conflitos","detail":"Como toda região pode gravar localmente, a latência de gravação é baixa e, mesmo que uma região fique isolada, as outras continuam gravando. O preço é alto: duas regiões podem atualizar o mesmo registro de forma diferente, e você precisa projetar a resolução de conflitos.","steps":["Princípio: toda região é líder; as gravações são propagadas de forma assíncrona para as outras regiões e mescladas.","Resolução de conflitos: last-write-wins (simples, mas com risco de perda de dados), mesclagem específica da aplicação ou tipos de dados livres de conflito, como CRDTs.","Exemplos de engines: configurações multi-master/multi-leader (ex.: EDB Postgres Distributed (BDR)/pgEdge para PostgreSQL, Redis Enterprise Active-Active (CRDT), CouchDB). O Cassandra é leaderless, e não multi-leader; com LOCAL_ONE/LOCAL_QUORUM permite gravações locais em todas as regiões com resultado semelhante e resolve conflitos com last-write-wins (timestamps).","Quando: a latência de gravação local e a independência regional importam mais que a consistência forte.","Atenção: projete a resolução de conflitos desde o início; a suposição de que 'conflitos não vão acontecer' produz perda silenciosa de dados. Cuidado com colisões entre regiões na geração de IDs únicos."],"related":["decide-ha"]},"sol_quorum":{"kind":"solution","title":"Recomendação: gravações baseadas em quorum (confirmação da maioria)","detail":"Uma gravação é aceita quando a maioria (quorum) das regiões/réplicas a confirma; quando as leituras também vão para a maioria, o valor mais recente é garantido. É resiliente à perda de regiões e fortemente consistente; o preço é a latência de cada gravação até alcançar a maioria.","steps":["Princípio: confirmação da maioria com a regra W + R > N; mesmo que uma região minoritária caia, o sistema continua gravando de forma consistente.","Exemplos de engines: bancos distribuídos baseados em consenso (ex.: sistemas que usam Raft/Paxos), o nível de consistência QUORUM no Cassandra.","Quando: são exigidas tanto resiliência a desastres regionais quanto consistência forte, e uma latência de gravação maior é aceitável.","RPO/RTO: como a maioria grava de forma durável, RPO≈0; com a reformação automática da maioria após a perda de uma região, o RTO pode ser baixo.","Atenção: o quorum entre regiões geograficamente distantes adiciona dezenas de ms a cada gravação por causa da latência imposta pela velocidade da luz; escolha com cuidado o número e o posicionamento das regiões."],"related":["decide-ha","decide-shard-replica"]},"sol_data_residency":{"kind":"solution","title":"Recomendação: residência de dados / conformidade (GDPR)","detail":"Alguns dados (pessoais, de saúde, financeiros) devem legalmente permanecer dentro das fronteiras de um país/região específico (ex.: GDPR). Nesse caso, você não projeta a arquitetura em torno de 'copiar para todo lugar', mas de modo que os dados fiquem fixados geograficamente.","steps":["Princípio: mantenha os dados pessoais/regulados na região de origem; restrinja ou proíba a replicação para fora da região.","Particionamento regional: direcione os usuários para a região em que estão registrados (geo-partitioning); cada região mantém os dados dos próprios residentes.","Dados globais vs locais: dados globais, como um catálogo, podem ser replicados para todo lugar; os dados pessoais permanecem na região.","Atenção: backups e read replicas também movem dados; a região de armazenamento dos backups e a região de DR também estão no escopo da conformidade.","Atenção: uma decisão como 'vamos copiar para todo lugar só pela baixa latência' pode ser uma violação legal para dados regulados; incorpore as restrições de residência à arquitetura desde o início."],"related":["security-incident","audit-setup"]}}},"solver/arch-highscale.json":{"id":"arch-highscale","title":"Arquitetura de referência: alta escala / alto tráfego","icon":"🏛️","category":"Arquitetura de referência","intro":"À medida que o tráfego cresce, há uma ordem certa para proteger o banco: primeiro as alavancas simples e baratas, depois as complexas. Esta árvore percorre passo a passo a ordem escala vertical → read replica → sharding, padrões de cache (cache-aside, write-back), buffer com fila + backpressure, rate limiting, isolamento do banco com bulkheads/circuit breakers e prevenção de hot spots. Princípio central: deixe para o fim as decisões difíceis de reverter, como sharding, e esgote primeiro os ganhos baratos.","start":"root","nodes":{"root":{"kind":"step","title":"Onde está o gargalo: uma única instância saturada, leituras ou gravações intensas, ou tráfego em rajadas?","detail":"Para resolver um problema de escalabilidade no lugar certo, identifique primeiro o gargalo. Uma única instância está saturada em CPU/memória, as leituras predominam, as gravações estão atingindo o limite, ou picos repentinos de tráfego estão esmagando o banco? Cada caso aponta para um componente diferente.","choices":[{"label":"Uma única instância está saturada; ainda não tentei as alavancas simples","next":"scale_path"},{"label":"As leituras são muito intensas e estão crescendo","next":"sol_cache"},{"label":"Picos repentinos de tráfego / carga em rajadas estão esmagando o banco","next":"protect"}]},"scale_path":{"kind":"step","title":"Em qual etapa de escala você está: vertical, read replicas ou sharding?","detail":"A escalabilidade tem uma ordem certa. A escala vertical (hardware mais potente) é o primeiro passo mais simples; depois você distribui as leituras entre réplicas; somente quando um único primário não dá mais conta das gravações você passa para o particionamento horizontal (sharding). Onde você está?","choices":[{"label":"Ainda não aumentei o hardware / não esgotei o tuning básico","next":"sol_vertical"},{"label":"As gravações cabem em uma instância, mas preciso distribuir a carga de leitura","next":"sol_read_replica"},{"label":"Um único primário não dá mais conta da carga de gravação","next":"sol_sharding"}]},"protect":{"kind":"step","title":"Como você vai proteger o banco da carga: buffer, limitação ou isolamento?","detail":"Escalar nem sempre é aumentar o banco; muitas vezes é proteger o banco da sobrecarga. Você vai suavizar picos repentinos de gravação com uma fila, limitar a taxa de requests recebidos (rate limiting), ou evitar que uma única dependência derrube o sistema inteiro (bulkhead/circuit breaker)?","choices":[{"label":"Quero suavizar picos repentinos de gravação","next":"sol_queue"},{"label":"Quero limitar/compartilhar de forma justa a taxa de requests recebidos","next":"sol_ratelimit"},{"label":"Não quero que uma dependência com falha derrube o sistema inteiro","next":"sol_bulkhead"}]},"sol_vertical":{"kind":"solution","title":"Recomendação: escala vertical e tuning básico primeiro","detail":"O passo mais barato e menos arriscado é a escala vertical: adicionar mais CPU/RAM/discos mais rápidos e corrigir o básico (índices, pooling de conexões, parâmetros de memória). Esgote esses ganhos antes de decisões complexas como sharding.","steps":["Primeiro passo: aumente o hardware (CPU/RAM/NVMe) e ajuste os parâmetros de memória de buffer/cache à carga.","Ganhos baratos: adicione os índices ausentes, corrija consultas pesadas, coloque um pooler de conexões (PgBouncer/ProxySQL) à frente; a maioria dos problemas de 'escala' são na verdade problemas de tuning.","Quando basta: se a instância única ampliada atender à meta de latência/throughput, pare; não adicione mais complexidade.","Atenção: a escala vertical tem um teto físico e de custo; à medida que se aproximar dele, passe para read replicas e cache.","Próximo passo: se as leituras predominarem, réplicas + cache; se as gravações predominarem e o teto for ultrapassado, sharding."],"related":["decide-capacity","high-cpu"]},"sol_read_replica":{"kind":"solution","title":"Recomendação: distribua as leituras com read replicas","detail":"As gravações permanecem em um único primário enquanto o tráfego somente leitura é distribuído entre uma ou mais réplicas. É muito mais simples que sharding e resolve a maioria das cargas com muitas leituras; o primário fica apenas para gravações e leituras críticas para a consistência.","steps":["Topologia: primário (gravações) → várias read replicas assíncronas; as leituras são distribuídas entre as réplicas por um load balancer.","Engines: PostgreSQL streaming replication, réplicas do MySQL, read replicas gerenciadas.","Quando: a relação leitura/gravação é fortemente inclinada para as leituras e as gravações ainda podem ser atendidas por uma única instância.","Atenção: o lag de replicação causa leituras defasadas; atenda a partir do primário as leituras que precisam de read-your-writes.","Próximo passo: se nem as réplicas bastarem, ou se o gargalo real forem as gravações, adicione um cache e depois considere sharding."],"related":["replication-lag","decide-shard-replica"]},"sol_sharding":{"kind":"solution","title":"Recomendação: sharding (particionamento horizontal) como último recurso","detail":"Quando um único primário não dá conta da carga de gravação, você divide os dados por uma chave em várias partes independentes (shards); cada shard assume parte das gravações. É poderoso, mas difícil de reverter; complica as consultas e transações entre shards, por isso fica para o fim.","steps":["Shard key: escolha uma chave que distribua a carga e os dados de forma uniforme e permita que a maioria das consultas caia em um único shard (ex.: customer_id).","Método: particionamento baseado em hash (distribuição uniforme) ou em intervalo (consultas por intervalo fáceis, mas com risco de hot spots).","Exemplos de engines: sharding do MongoDB, Citus (PostgreSQL), Vitess (MySQL) ou sharding no nível da aplicação.","Atenção: joins/transações entre shards são caros e complexos; projete o schema de modo que a maioria das transações se conclua dentro de um único shard.","Atenção: uma chave errada cria hot spots (carga acumulando em um shard); evite chaves monotônicas como ids/datas crescentes e lembre-se de que o resharding é difícil."],"related":["decide-shard-replica","decide-partition"]},"sol_cache":{"kind":"solution","title":"Recomendação: padrões de cache (cache-aside + write-back)","detail":"Com alto tráfego de leitura, você coloca um cache em memória (Redis) à frente do banco e atende a maioria das leituras sem que elas cheguem ao banco. Para gravações de alto volume, o write-back acumula as gravações e as descarrega no banco em lotes, aliviando o primário.","steps":["Cache-aside: a aplicação verifica primeiro o Redis; em caso de miss, busca no banco e grava no cache. Isso tira do banco a maior parte da carga de leitura.","Write-back (write-behind): para volumes de gravação muito altos, como contadores/métricas, grave primeiro no cache e descarregue no banco em lotes, em segundo plano.","TTL + invalidação: dê às chaves um TTL razoável; na gravação, atualize/exclua a chave relacionada para que não restem dados defasados.","Atenção: cache stampede: quando uma chave popular expira, milhares de requests atingem o banco ao mesmo tempo; use lock/single-flight, atualização antecipada e TTLs com jitter.","Atenção: com write-back, se o nó de cache cair antes de gravar no banco, os dados são perdidos; proteja os dados críticos com uma fila durável/AOF."],"related":["decide-cache","cache-hit-low"]},"sol_queue":{"kind":"solution","title":"Recomendação: buffer com fila (backpressure)","detail":"Para evitar que picos repentinos de gravação atinjam o banco diretamente, você coloca uma fila durável (ex.: Kafka/uma fila de mensagens) no meio e consome as gravações no ritmo que o banco consegue sustentar. A fila absorve o pico; em vez de falhar de forma síncrona, o sistema opera com latência controlada (backpressure).","steps":["Princípio: o produtor grava o evento na fila; o consumidor grava no banco no ritmo sustentável (possivelmente em lotes).","Engine: Kafka ou uma fila de mensagens; atua como um buffer que isola o banco do tráfego de pico.","Backpressure: se a fila continuar crescendo, desacelere/sinalize o produtor; não permita acúmulo ilimitado, caso contrário a latência explode.","Quando: o tráfego de gravação ocorre em rajadas intensas e o processamento síncrono imediato não é obrigatório (processamento assíncrono é aceitável).","Atenção: uma fila introduz assincronia; o resultado tem consistência eventual. Torne o consumidor idempotente (as mensagens podem ser reentregues)."],"related":["connection-storm"]},"sol_ratelimit":{"kind":"solution","title":"Recomendação: rate limiting (limitar a taxa de requisições)","detail":"Limitando os requests recebidos por origem (rate limiting), você evita tanto abusos quanto que um único cliente consuma todos os recursos. Limitar a carga que chega ao banco mantém o sistema previsível e justo.","steps":["Posicionamento: aplique a limitação antes do banco (API gateway / borda da aplicação); apenas os requests aceitos devem chegar ao banco.","Método: taxa por cliente ou por usuário com token bucket / sliding window; retorne 429 quando excedida.","Compartilhamento justo: use cotas para impedir que um 'vizinho barulhento' engula toda a capacidade.","Quando: o tráfego pode ter picos repentinos, ou há risco de abuso/clientes automatizados.","Atenção: rate limiting é uma medida de proteção, não de escala; se houver uma necessidade real de capacidade, resolva também o gargalo de fato (vertical/réplica/shard)."],"related":["connection-storm"]},"sol_bulkhead":{"kind":"solution","title":"Recomendação: bulkhead + circuit breaker (isolamento)","detail":"Para evitar que uma dependência (ex.: um banco que está ficando lento ou um serviço externo) derrube o sistema inteiro, você divide os recursos em compartimentos (bulkheads) e corta temporariamente as chamadas para uma dependência que continua falhando (circuit breaker). Assim, uma falha parcial não se espalha para o sistema inteiro.","steps":["Bulkhead: aloque pools de conexões/threads separados para tipos diferentes de trabalho; um caminho lento não deve esgotar o pool inteiro e deixar os outros sem recursos.","Circuit breaker: quando uma dependência ultrapassar um limite de erros/latência, 'abra' o circuito e falhe rápido por um tempo; depois teste a recuperação com chamadas de teste (half-open).","Timeouts: coloque um timeout razoável em toda chamada ao banco/serviço; chamadas travadas não devem bloquear o pool.","Quando: em um sistema com muitas dependências, em que a lentidão de um componente traz risco de falha em cascata.","Atenção: projete uma degradação graciosa para quando o circuito estiver aberto: retorne dados defasados do cache ou um resultado parcial em vez de rejeitar o request inteiro."],"related":["connection-storm","high-cpu"]}}},"types/types-functions.json":{"schemaVersion":1,"sections":[{"id":"datatypes","title":"Tipos de dados","icon":"🔤","rows":[{"id":"var-text","concept":"Texto de comprimento variável","engines":{"oracle":"VARCHAR2(n)","postgres":"VARCHAR(n) / TEXT","mysql":"VARCHAR(n)","mssql":"NVARCHAR(n)","mongodb":"string","redis":"string (value)","elasticsearch":"text / keyword"},"note":"No ES, text é usado para busca full-text e keyword para correspondência exata/agregações."},{"id":"fixed-text","concept":"Texto de comprimento fixo","engines":{"oracle":"CHAR(n)","postgres":"CHAR(n)","mysql":"CHAR(n)","mssql":"NCHAR(n)","mongodb":"string","redis":"string","elasticsearch":"keyword"},"note":"Sistemas de documentos/chave-valor não têm o conceito de comprimento fixo; os valores são armazenados como strings."},{"id":"large-text","concept":"Texto grande (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":"Inteiro (32 bits)","engines":{"oracle":"NUMBER(10)","postgres":"INTEGER / INT4","mysql":"INT","mssql":"INT","mongodb":"int (NumberInt / int32)","redis":"string (interpreted as an integer)","elasticsearch":"integer"},"note":"O Oracle não tem um tipo INT separado; usa-se NUMBER."},{"id":"int64","concept":"Inteiro grande (64 bits)","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":"Número decimal/exato (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":"Para valores exatos, como dinheiro, estes tipos são preferíveis a float."},{"id":"float","concept":"Ponto flutuante (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":"Lógico (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":"Um tipo de coluna BOOLEAN chegou ao Oracle SQL somente com o 23c; antes disso, é simulado com NUMBER/CHAR."},{"id":"date","concept":"Data","engines":{"oracle":"DATE (includes time)","postgres":"DATE","mysql":"DATE","mssql":"DATE","mongodb":"Date (ISODate)","redis":"none (epoch string/number)","elasticsearch":"date (with format)"},"note":"O tipo DATE do Oracle guarda data e hora; não é apenas data."},{"id":"datetime","concept":"Data e hora (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":"Data e hora com fuso horário","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 e ES armazenam datas em UTC; o fuso horário é aplicado na exibição."},{"id":"binary","concept":"Dados binários (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":"As strings do Redis são binary-safe e podem conter qualquer sequência de bytes."},{"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":"O _id nativo do Mongo é ObjectId; um UUID também pode ser armazenado como 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":"No Postgres, o JSONB é preferível para consultas/indexação; o MongoDB já é baseado em documentos."},{"id":"auto-increment","concept":"Autoincremento (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":"Enum/lista fixa","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":"Array","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":"No ES, todo campo pode conter implicitamente um array; não há um tipo array separado."},{"id":"ip-address","concept":"Endereço 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":"Os tipos de IP nativos do Postgres e do ES suportam consultas por intervalo/sub-rede."},{"id":"money","concept":"Dinheiro","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":"Para evitar erros de arredondamento, dinheiro é armazenado com DECIMAL/Decimal128 em vez de float."},{"id":"spatial","concept":"Geográfico/espacial","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":"Funções comuns","icon":"🧩","rows":[{"id":"coalesce","concept":"Retornar um padrão se 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":"Substituir se 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":"Data e hora atuais (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":"Data atual","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":"Concatenar texto (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":"No MySQL, || significa OR por padrão; use CONCAT para concatenar."},{"id":"substring","concept":"Substring","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":"Comprimento da string","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":"Maiúsculas/minúsculas","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":"Remover espaços (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":"Substituir texto (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":"Conversão de tipo (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":"Formatar uma data como texto (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":"Converter texto em data (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":"Somar a uma data (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":"Diferença entre duas datas (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":"Extrair uma parte da data (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":"Arredondar (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":"Módulo (resto)","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":"Condicional (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":"Maior/menor (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":"Concatenar dentro de um grupo (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":"Número da linha (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":"Primeiras N linhas (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":"Usuário atual","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":"Gerar um 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":"Extrair um campo 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":"Correspondência de expressão regular (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":"O SQL Server 2025 (e o Azure SQL) adicionaram funções de regex nativas, como REGEXP_LIKE, REGEXP_REPLACE e REGEXP_SUBSTR (REGEXP_LIKE exige o nível de compatibilidade 170); versões anteriores exigem LIKE ou uma função CLR."}]}]},"reference/params-oracle.json":{"engineId":"oracle","engine":"Oracle","order":1,"params":[{"name":"sga_target","default":"0","recommended":"~60% da RAM em um servidor dedicado","unit":"bytes (K/M/G)","dynamic":"dynamic","desc":"Define o tamanho total da SGA para o Automatic Shared Memory Management (ASMM); distribui os subpools automaticamente.","tags":["memory","memory","sga"]},{"name":"sga_max_size","default":"Same as sga_target","recommended":"Igual ou um pouco acima de sga_target","unit":"bytes (K/M/G)","dynamic":"restart","desc":"Define o limite superior até o qual a SGA pode crescer em tempo de execução; aumentá-lo exige reiniciar a instância.","tags":["memory","memory","sga"]},{"name":"pga_aggregate_target","default":"10M or 20% of the SGA","recommended":"~20% da RAM","unit":"bytes (K/M/G)","dynamic":"dynamic","desc":"Define a meta total de memória PGA usada por todos os processos de servidor; afeta as operações de sort e hash.","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":"O padrão geralmente é suficiente","unit":"bytes (K/M/G)","dynamic":"dynamic","desc":"Limite superior rígido para a memória PGA de toda a instância; quando excedido, as chamadas das sessões que mais consomem são abortadas (exceto SYS e processos em segundo plano). Introduzido no Oracle 12c.","tags":["memory","memory","pga","limit"]},{"name":"memory_target","default":"0","recommended":"0 (prefere-se o gerenciamento separado de SGA/PGA)","unit":"bytes (K/M/G)","dynamic":"dynamic","desc":"Combina SGA e PGA sob uma única meta com o Automatic Memory Management (AMM); não recomendado em sistemas grandes.","tags":["memory","memory","amm"]},{"name":"db_cache_size","default":"0 (automatic)","recommended":"Deixe em 0 se sga_target for usado","unit":"bytes (K/M/G)","dynamic":"dynamic","desc":"Define o tamanho do buffer cache para o tamanho de bloco padrão; mantém os blocos de dados em memória.","tags":["memory","memory","cache","buffer"]},{"name":"shared_pool_size","default":"0 (automatic)","recommended":"Deixe em 0 se sga_target for usado","unit":"bytes (K/M/G)","dynamic":"dynamic","desc":"Tamanho do shared pool, que armazena resultados de parse de SQL/PLSQL, o dictionary cache e o library cache.","tags":["memory","memory","shared","pool"]},{"name":"processes","default":"100 / 300 (depending on version)","recommended":"Aumente conforme as conexões simultâneas esperadas","unit":"integer","dynamic":"restart","desc":"Número máximo de processos do sistema operacional que podem se conectar à instância; alterá-lo exige reinicialização.","tags":["connection","connection","process","process"]},{"name":"sessions","default":"Derived from processes (1.5x+22)","recommended":"A derivação padrão geralmente é suficiente","unit":"integer","dynamic":"restart","desc":"Número máximo de sessões que podem existir ao mesmo tempo; derivado automaticamente do valor de processes.","tags":["connection","connection","session","session"]},{"name":"open_cursors","default":"50","recommended":"300-1000 conforme a necessidade da aplicação","unit":"integer","dynamic":"dynamic","desc":"Define o número máximo de cursores que uma sessão pode manter abertos ao mesmo tempo.","tags":["cursor","cursor","session","session"]},{"name":"cursor_sharing","default":"EXACT","recommended":"EXACT (use bind variables)","unit":"EXACT | FORCE","dynamic":"dynamic","desc":"Determina se instruções SQL com literais são compartilhadas via bind variables; FORCE substitui os literais.","tags":["cursor","cursor","sql","parse"]},{"name":"optimizer_mode","default":"ALL_ROWS","recommended":"ALL_ROWS","unit":"ALL_ROWS | FIRST_ROWS_n","dynamic":"dynamic","desc":"Define o objetivo do otimizador baseado em custo; se a prioridade é o throughput total ou o tempo de resposta da primeira linha.","tags":["optimizer","optimize","plan","sql"]},{"name":"undo_retention","default":"900","recommended":"Com base na consulta/duração de flashback mais longa","unit":"seconds","dynamic":"dynamic","desc":"Define por quanto tempo os dados de undo confirmados são retidos, se possível; afeta o risco de ORA-01555.","tags":["undo","rollback","retention","flashback"]},{"name":"undo_tablespace","default":"UNDOTBS1","recommended":"Um tablespace de undo dedicado e bem dimensionado","unit":"string (tablespace name)","dynamic":"dynamic","desc":"Define o tablespace de undo ativo usado pelo gerenciamento automático de undo; pode ser alterado online.","tags":["undo","rollback","tablespace"]},{"name":"db_recovery_file_dest_size","default":"0","recommended":"Grande o suficiente para archivelogs + backups + flashback logs","unit":"bytes (K/M/G)","dynamic":"dynamic","desc":"Define o tamanho máximo em disco da Fast Recovery Area (FRA); armazena logs arquivados e backups.","tags":["recovery","recovery","fra","archive"]},{"name":"db_writer_processes","default":"1 or based on CPU count","recommended":"Cerca de CPU/8 (aumente sob carga de escrita intensa)","unit":"integer","dynamic":"restart","desc":"Define o número de processos database writer (DBWn) que gravam blocos sujos em disco; paraleliza a carga de escrita.","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":"Defina conforme a carga de trabalho e o número de CPUs","unit":"integer","dynamic":"dynamic","desc":"Limita o número máximo de servidores de execução paralela (PX) que podem ser executados ao mesmo tempo na instância.","tags":["parallel","parallel","px","query"]},{"name":"statistics_level","default":"TYPICAL","recommended":"TYPICAL","unit":"BASIC | TYPICAL | ALL","dynamic":"dynamic","desc":"Define o nível do AWR/ADDM e da coleta automática de estatísticas; BASIC desativa muitos diagnósticos.","tags":["statistics","statistics","awr","monitoring"]},{"name":"deferred_segment_creation","default":"TRUE","recommended":"TRUE (economiza espaço em tabelas vazias)","unit":"TRUE | FALSE","dynamic":"dynamic","desc":"Adia a criação do primeiro segmento de uma tabela/índice vazio até a inserção da primeira linha; economiza espaço.","tags":["segment","deferred-segment","space","storage"]},{"name":"audit_trail","default":"NONE (DB in databases created with DBCA)","recommended":"Use DB ou unified auditing","unit":"NONE | DB | DB,EXTENDED | OS | XML","dynamic":"restart","desc":"Determina onde e como os registros de auditoria tradicional são gravados; alterá-lo exige reinicialização.","tags":["audit","audit","security","security"]},{"name":"compatible","default":"Installed version (e.g., 19.0.0)","recommended":"Aumente quando os recursos da nova versão estiverem estáveis","unit":"version string","dynamic":"restart","desc":"Determina quais recursos de versão estão habilitados; não pode ser reduzido depois de aumentado e exige reinicialização.","tags":["compatible","compatibility","version","version"]},{"name":"db_block_size","default":"8192","recommended":"8K (OLTP); definido apenas na criação","unit":"bytes","dynamic":"restart","desc":"Define o tamanho de bloco padrão do banco de dados; é definido apenas na criação do banco e não pode ser alterado depois.","tags":["block","block","storage","io"]},{"name":"filesystemio_options","default":"none (platform-dependent)","recommended":"SETALL (Direct + Async I/O)","unit":"none | asynch | directio | setall","dynamic":"restart","desc":"Controla o uso de I/O assíncrono e direto para datafiles em sistemas de arquivos.","tags":["io","io","async","directio"]},{"name":"log_archive_max_processes","default":"4","recommended":"Aumente conforme o número de destinos de arquivamento","unit":"integer","dynamic":"dynamic","desc":"Define o número máximo de processos ARCn que arquivam os redo logs; aumentado para reduzir o atraso de arquivamento.","tags":["archive","archive","redo","log"]}]},"reference/params-postgres.json":{"engineId":"postgres","engine":"PostgreSQL","order":2,"params":[{"name":"shared_buffers","default":"128MB","recommended":"~25% da RAM","unit":"bytes (kB/MB/GB)","dynamic":"restart","desc":"Quantidade de memória compartilhada que o PostgreSQL aloca para cache de blocos de dados; alterá-la exige reinicialização.","tags":["memory","memory","cache","buffer"]},{"name":"effective_cache_size","default":"4GB","recommended":"~50-75% da RAM","unit":"bytes (kB/MB/GB)","dynamic":"dynamic","desc":"Informa ao planejador o tamanho total estimado do cache do SO + PostgreSQL; influencia o uso de índices.","tags":["memory","memory","planner","cache"]},{"name":"work_mem","default":"4MB","recommended":"16-64MB (atenção ao número de conexões)","unit":"bytes (kB/MB/GB)","dynamic":"dynamic","desc":"Memória que operações de sort e hash podem usar antes de transbordar para o disco; alocada por nó do plano de consulta.","tags":["memory","memory","sort","query"]},{"name":"maintenance_work_mem","default":"64MB","recommended":"256MB-1GB","unit":"bytes (kB/MB/GB)","dynamic":"dynamic","desc":"Define a memória máxima que operações de manutenção como VACUUM, CREATE INDEX e ALTER TABLE podem usar.","tags":["memory","memory","vacuum","maintenance"]},{"name":"max_connections","default":"100","recommended":"100-200 (use um pooler acima disso)","unit":"integer","dynamic":"restart","desc":"Número máximo de conexões de cliente simultâneas aceitas; alterá-lo exige reinicialização.","tags":["connection","connection","limit"]},{"name":"wal_buffers","default":"-1 (1/32 of shared_buffers)","recommended":"16MB","unit":"bytes (kB/MB/GB)","dynamic":"restart","desc":"Define o tamanho do buffer de memória compartilhada que mantém os registros de WAL antes de serem gravados em disco. O valor -1 (automático) fica limitado a no mínimo 64kB e no máximo um segmento de WAL (geralmente 16MB).","tags":["wal","memory","memory","buffer"]},{"name":"max_wal_size","default":"1GB","recommended":"4-16GB conforme a carga de trabalho","unit":"bytes (MB/GB)","dynamic":"dynamic","desc":"Define o limite superior flexível até o qual o WAL pode crescer antes que um checkpoint automático seja disparado.","tags":["wal","checkpoint","disk"]},{"name":"min_wal_size","default":"80MB","recommended":"1-2GB","unit":"bytes (MB/GB)","dynamic":"dynamic","desc":"Limite inferior abaixo do qual os arquivos de WAL são mantidos para reciclagem; reduz realocações frequentes.","tags":["wal","checkpoint","disk"]},{"name":"checkpoint_completion_target","default":"0.9","recommended":"0.9","unit":"ratio (0-1)","dynamic":"dynamic","desc":"Define a fração do intervalo de checkpoint ao longo da qual as gravações do checkpoint são distribuídas; suaviza picos de I/O. O padrão passou a ser 0.9 no PG14; antes era 0.5.","tags":["checkpoint","io","wal"]},{"name":"checkpoint_timeout","default":"5min","recommended":"15-30min","unit":"time (s/min)","dynamic":"dynamic","desc":"Define o tempo máximo entre checkpoints automáticos; aumentá-lo reduz a carga de escrita, mas prolonga o tempo de recuperação.","tags":["checkpoint","wal","recovery"]},{"name":"random_page_cost","default":"4.0","recommended":"1.1 para SSD","unit":"decimal","dynamic":"dynamic","desc":"Define o custo relativo de acesso aleatório ao disco para o planejador; reduzi-lo em SSD favorece index scans.","tags":["planner","optimize","io","index"]},{"name":"effective_io_concurrency","default":"1","recommended":"200 para SSD","unit":"integer","dynamic":"dynamic","desc":"Número estimado de operações de I/O simultâneas que o disco consegue atender; afeta o prefetch em bitmap scans. O padrão é 1 no PG17 e anteriores, e 16 no PG18.","tags":["io","gc","ssd","prefetch"]},{"name":"default_statistics_target","default":"100","recommended":"100 (aumente por coluna em tabelas grandes)","unit":"integer","dynamic":"dynamic","desc":"Define o nível de detalhe das estatísticas coletadas pelo ANALYZE; aumentá-lo melhora a precisão dos planos e aumenta o tempo de analyze.","tags":["statistics","statistics","analyze","planner"]},{"name":"autovacuum","default":"on","recommended":"on","unit":"on | off","dynamic":"dynamic","desc":"Habilita o processo automático de vacuum que remove dead tuples e coleta estatísticas; desativá-lo leva a bloat.","tags":["autovacuum","vacuum","maintenance","bloat"]},{"name":"autovacuum_vacuum_scale_factor","default":"0.2","recommended":"0.05-0.1 em tabelas grandes","unit":"ratio (0-1)","dynamic":"dynamic","desc":"Define a fração das linhas de uma tabela que deve mudar antes do vacuum; reduzi-la limpa tabelas grandes com mais frequência.","tags":["autovacuum","vacuum","bloat","maintenance"]},{"name":"autovacuum_max_workers","default":"3","recommended":"3-6 (aumente em sistemas com muitas tabelas)","unit":"integer","dynamic":"restart","desc":"Define o número máximo de processos worker do autovacuum que podem ser executados ao mesmo tempo; no PG17 e anteriores, alterá-lo exige reinicialização. No PG18 pode ser alterado com reload até o limite de autovacuum_worker_slots.","tags":["autovacuum","vacuum","worker","maintenance"]},{"name":"synchronous_commit","default":"on","recommended":"on (dados críticos); off (desempenho em primeiro lugar)","unit":"on | off | local | remote_write | remote_apply","dynamic":"dynamic","desc":"Determina se um commit aguarda o WAL ser gravado em disco; off traz risco de pequena perda de dados em caso de crash.","tags":["wal","commit","durability","performance"]},{"name":"wal_level","default":"replica","recommended":"replica (para replicação/PITR)","unit":"minimal | replica | logical","dynamic":"restart","desc":"Determina quanta informação é gravada no WAL; necessário para replicação e replicação lógica, e alterá-lo exige reinicialização.","tags":["wal","replication","replication","pitr"]},{"name":"max_wal_senders","default":"10","recommended":"Com base no número de standbys + backups","unit":"integer","dynamic":"restart","desc":"Define o número máximo de processos que podem transmitir WAL simultaneamente (para standbys e backups).","tags":["wal","replication","replication","standby"]},{"name":"wal_keep_size","default":"0","recommended":"O suficiente para cobrir o atraso do standby","unit":"bytes (MB/GB)","dynamic":"dynamic","desc":"Quantidade mínima de WAL mantida em pg_wal para standbys; protege um standby atrasado quando não há replication slot. Introduzido no PG13; antes era usado wal_keep_segments (número de segmentos).","tags":["wal","replication","replication","standby"]},{"name":"log_min_duration_statement","default":"-1 (disabled)","recommended":"1000ms para capturar consultas lentas","unit":"milliseconds","dynamic":"dynamic","desc":"Registra em log as instruções que executam por mais tempo que o especificado; usado para detectar consultas lentas, -1 desativa.","tags":["logging","log","slow-query","slow-query"]},{"name":"idle_in_transaction_session_timeout","default":"0 (disabled)","recommended":"60000ms para evitar locks retidos","unit":"milliseconds","dynamic":"dynamic","desc":"Encerra sessões que ficam ociosas dentro de uma transação aberta pelo tempo especificado; reduz o risco de bloqueio e bloat.","tags":["timeout","transaction","transaction","lock"]},{"name":"statement_timeout","default":"0 (disabled)","recommended":"Depende da aplicação (baixo para OLTP)","unit":"milliseconds","dynamic":"dynamic","desc":"Cancela automaticamente instruções que excedem o tempo especificado; impede que consultas descontroladas consumam recursos.","tags":["timeout","query","query","limit"]},{"name":"shared_preload_libraries","default":"'' (empty)","recommended":"pg_stat_statements (para monitoramento)","unit":"string (comma-separated list)","dynamic":"restart","desc":"Especifica as bibliotecas compartilhadas carregadas na inicialização do servidor; extensões como pg_stat_statements são configuradas aqui.","tags":["extension","extension","preload","monitoring"]},{"name":"max_parallel_workers_per_gather","default":"2","recommended":"2-4 (conforme o número de CPUs)","unit":"integer","dynamic":"dynamic","desc":"Define o número máximo de workers paralelos que um único nó Gather/GatherMerge pode iniciar; 0 desativa o paralelismo.","tags":["parallel","parallel","worker","query"]}]},"reference/params-mysql.json":{"engineId":"mysql","engine":"MySQL","order":3,"params":[{"name":"innodb_buffer_pool_size","default":"128MB","recommended":"~70-80% da RAM em um servidor dedicado","unit":"bytes (M/G)","dynamic":"dynamic","desc":"O principal pool de memória onde o InnoDB faz cache de dados e índices; no 8.0 pode ser alterado online, mas grandes alterações exigem cuidado.","tags":["memory","memory sizing","innodb","buffer"]},{"name":"innodb_buffer_pool_instances","default":"1 (or 8 if size>1GB)","recommended":"8 para pools grandes","unit":"integer","dynamic":"restart","desc":"Define o número de instâncias em que o buffer pool é dividido; reduz a contenção de mutex sob concorrência, alterá-lo exige reinicialização.","tags":["memory","memory sizing","innodb","concurrency"]},{"name":"innodb_redo_log_capacity","default":"100MB (8.0.30+)","recommended":"1-8GB (conforme a carga de escrita; ~1 hora de redo no pico)","unit":"bytes (M/G)","dynamic":"dynamic","desc":"Define o espaço total em disco ocupado pelo redo log do InnoDB; aumentá-lo suaviza a pressão de checkpoint e a carga de escrita no pico. Introduzido no MySQL 8.0.30 e alterável sem reinicialização via SET GLOBAL/SET PERSIST. Os antigos innodb_log_file_size (padrão 48MB) e innodb_log_files_in_group estão obsoletos desde o 8.0.30; antes do 8.0.30 o tamanho do redo é definido com esses dois e exige reinicialização.","tags":["innodb","redo","log","io"]},{"name":"innodb_flush_log_at_trx_commit","default":"1","recommended":"1 (ACID completo); 2 (desempenho)","unit":"0 | 1 | 2","dynamic":"dynamic","desc":"Controla se o redo log é gravado e sincronizado em disco a cada commit; 1 oferece durabilidade total, 2/0 trazem risco de perda.","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":"Define como o InnoDB descarrega os arquivos de dados e de log em disco; O_DIRECT evita buffer duplo, alterá-lo exige reinicialização.","tags":["innodb","io","flush","gc"]},{"name":"innodb_io_capacity","default":"8.0: 200 / 8.4: 10000","recommended":"Com base no IOPS real do storage (1000-2000 para SSD no 8.0)","unit":"integer (IOPS)","dynamic":"dynamic","desc":"Define a capacidade estimada de IOPS do disco usada pelas tarefas em segundo plano do InnoDB (flush, merge). No MySQL 8.4 os padrões foram elevados para innodb_io_capacity=10000 e innodb_io_capacity_max=20000 (200/2000 no 8.0).","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 (conforme a carga de leitura)","unit":"integer","dynamic":"restart","desc":"Define o número de threads em segundo plano do InnoDB que tratam requisições de I/O de leitura; alterá-lo exige reinicialização.","tags":["innodb","io","thread","read"]},{"name":"innodb_write_io_threads","default":"4","recommended":"4-8 (conforme a carga de escrita)","unit":"integer","dynamic":"restart","desc":"Define o número de threads em segundo plano do InnoDB que tratam requisições de I/O de escrita; alterá-lo exige reinicialização.","tags":["innodb","io","thread","write"]},{"name":"max_connections","default":"151","recommended":"200-500 conforme a carga de trabalho","unit":"integer","dynamic":"dynamic","desc":"Define o número máximo de conexões de cliente simultâneas permitidas; pode ser alterado online.","tags":["connection","connections","limit"]},{"name":"thread_cache_size","default":"-1 (autosized)","recommended":"Automático; aumente com muitas conexões de curta duração","unit":"integer","dynamic":"dynamic","desc":"Define quantas threads são mantidas em cache para reutilização; reduz a criação de threads para novas conexões.","tags":["connection","connections","thread","cache"]},{"name":"table_open_cache","default":"4000","recommended":"4000-8000 conforme o número de tabelas abertas","unit":"integer","dynamic":"dynamic","desc":"Define o tamanho do cache de handles de tabelas abertas para todas as threads; reduz o overhead de reabrir tabelas.","tags":["cache","table","table cache","open"]},{"name":"tmp_table_size","default":"16MB","recommended":"64-256MB","unit":"bytes (M/G)","dynamic":"dynamic","desc":"Define o tamanho máximo de uma tabela temporária em memória antes de ser convertida em tabela em disco; funciona junto com max_heap_table_size.","tags":["memory","memory sizing","temp","temporary table"]},{"name":"max_heap_table_size","default":"16MB","recommended":"Igual a tmp_table_size","unit":"bytes (M/G)","dynamic":"dynamic","desc":"Define o tamanho máximo até o qual tabelas do engine MEMORY e tabelas temporárias em memória podem crescer.","tags":["memory","memory sizing","temp","heap"]},{"name":"sort_buffer_size","default":"256KB","recommended":"256KB-2MB (atenção ao custo por conexão)","unit":"bytes (K/M)","dynamic":"dynamic","desc":"Buffer alocado por sessão para ordenações de ORDER BY e GROUP BY; torná-lo grande demais consome memória.","tags":["memory","memory sizing","sort","buffer"]},{"name":"join_buffer_size","default":"256KB","recommended":"256KB-1MB (prefira resolver com um índice)","unit":"bytes (K/M)","dynamic":"dynamic","desc":"Buffer alocado por sessão para joins que não podem usar índice; a correção definitiva é adicionar um índice adequado.","tags":["memory","memory sizing","join","buffer"]},{"name":"sync_binlog","default":"1","recommended":"1 (segurança total); 100-1000 sob carga intensa","unit":"integer","dynamic":"dynamic","desc":"Define após quantos commits o binary log é sincronizado em disco; 1 é o mais seguro, valores maiores trocam durabilidade por desempenho.","tags":["binlog","replication","durability","commit"]},{"name":"binlog_expire_logs_seconds","default":"2592000 (30 days)","recommended":"Conforme a janela de backup/replicação","unit":"seconds","dynamic":"dynamic","desc":"Define por quanto tempo os arquivos de binary log são mantidos antes da limpeza automática; controla o uso de disco.","tags":["binlog","log","retention","replication"]},{"name":"long_query_time","default":"10","recommended":"1 (capturar consultas lentas)","unit":"seconds","dynamic":"dynamic","desc":"Define a duração que uma consulta deve exceder para ser registrada no slow query log; aceita valores fracionários.","tags":["slow-query","slow-query-log","log","performance"]},{"name":"slow_query_log","default":"OFF","recommended":"ON (para diagnóstico)","unit":"ON | OFF","dynamic":"dynamic","desc":"Controla se consultas que excedem long_query_time são gravadas no slow query log; habilite-o para análise de desempenho.","tags":["slow-query","slow-query-log","log","monitoring"]},{"name":"wait_timeout","default":"28800 (8 hours)","recommended":"Conforme o pool da aplicação (ex.: 600)","unit":"seconds","dynamic":"dynamic","desc":"Define o tempo máximo que uma conexão não interativa pode ficar ociosa antes de ser fechada; limpa conexões ociosas.","tags":["timeout","connection","connections","idle"]},{"name":"max_allowed_packet","default":"64MB","recommended":"64-256MB para BLOBs/linhas grandes","unit":"bytes (M/G)","dynamic":"dynamic","desc":"Define o tamanho máximo de um único pacote ou de qualquer linha gerada/intermediária; aumente-o para transferências de BLOBs grandes.","tags":["packet","packet size","blob","network"]},{"name":"innodb_lock_wait_timeout","default":"50","recommended":"10-50 para OLTP","unit":"seconds","dynamic":"dynamic","desc":"Define por quanto tempo uma transação InnoDB aguarda um lock de linha antes de expirar.","tags":["innodb","lock","lock wait","timeout"]},{"name":"character_set_server","default":"utf8mb4","recommended":"utf8mb4","unit":"text (character set)","dynamic":"dynamic","desc":"Define o character set padrão do servidor; utf8mb4 oferece suporte completo a Unicode (incluindo emoji).","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 total menos a parcela reservada ao SO e outros serviços (~10-25%)","unit":"MB","dynamic":"dynamic","desc":"Define a quantidade máxima de memória que o buffer pool do SQL Server e outros consumidores de memória podem usar. O padrão é praticamente ilimitado; se outros serviços rodam no servidor, deve ser reduzido para deixar memória suficiente para o sistema operacional. Definido com sp_configure; entra em vigor imediatamente com RECONFIGURE.","tags":["memory","memory limit","buffer pool"]},{"name":"min server memory (MB)","default":"0","recommended":"Em instâncias críticas, um limite inferior razoável em relação ao max","unit":"MB","dynamic":"dynamic","desc":"A quantidade mínima de memória que o SQL Server não devolve ao sistema operacional depois de alocada. Usada para evitar que o SQL Server libere memória demais sob pressão de memória. Definido com sp_configure; entra em vigor com RECONFIGURE.","tags":["memory","memory limit"]},{"name":"max degree of parallelism","default":"0","recommended":"Geralmente 8 ou o número de núcleos físicos por nó NUMA","unit":"count","dynamic":"dynamic","desc":"Limita o número máximo de processadores (núcleos) que uma única consulta pode usar em execução paralela. 0 significa que todos os núcleos podem ser usados; é limitado para evitar paralelismo excessivo em cargas OLTP. Entra em vigor imediatamente com sp_configure + RECONFIGURE.","tags":["parallelism","parallel query","maxdop","cpu"]},{"name":"cost threshold for parallelism","default":"5","recommended":"25-50 em hardware moderno","unit":"cost","dynamic":"dynamic","desc":"O limite mínimo de custo estimado que um plano de consulta deve atingir para ser executado em paralelo. O padrão de 5 é muito baixo e faz consultas pequenas serem paralelizadas desnecessariamente; aumentá-lo melhora o comportamento de paralelismo em todo o servidor. Entra em vigor imediatamente com sp_configure + RECONFIGURE.","tags":["parallelism","parallel query","cpu"]},{"name":"max worker threads","default":"0","recommended":"0 (deixe o SQL Server calcular)","unit":"count","dynamic":"dynamic","desc":"Define o número máximo de worker threads que o SQL Server pode criar para processar requisições de clientes. 0 faz com que seja calculado automaticamente com base no número de processadores e na arquitetura. É uma opção avançada; aplicada com sp_configure + RECONFIGURE sem reinicialização (sys.configurations.is_dynamic = 1).","tags":["threads","worker","cpu","concurrency"]},{"name":"optimize for ad hoc workloads","default":"0","recommended":"1 (ligado)","unit":"0/1","dynamic":"dynamic","desc":"Para consultas ad hoc executadas apenas uma vez, armazena em cache um pequeno stub de plano compilado na primeira execução em vez do plano completo. Evita que o plan cache se encha de planos de uso único e melhora o uso de memória. Entra em vigor imediatamente com sp_configure + RECONFIGURE.","tags":["plan cache","memory","memory usage"]},{"name":"backup compression default","default":"0","recommended":"1 (ligado)","unit":"0/1","dynamic":"dynamic","desc":"Faz com que novos backups sejam compactados por padrão. A compactação reduz significativamente o tamanho e a duração do backup ao custo de algum CPU. Entra em vigor imediatamente com sp_configure + RECONFIGURE.","tags":["backup","backup size","compression","backup compression"]},{"name":"fill factor (%)","default":"0","recommended":"0 ou 90-100 (conforme a carga de trabalho)","unit":"%","dynamic":"restart","desc":"Define, em percentual, o quanto as páginas de nível folha são preenchidas quando um índice é criado ou reconstruído (REBUILD). 0 e 100 preenchem as páginas completamente; valores menores reduzem page splits, mas aumentam o uso de disco e memória. O padrão no nível do servidor é alterado com sp_configure, mas só entra em vigor após reiniciar o serviço (is_dynamic = 0); a opção FILLFACTOR por índice pode ser usada imediatamente.","tags":["index","page split","storage","disk usage"]},{"name":"recovery interval (min)","default":"0","recommended":"0 (automático)","unit":"minutes","dynamic":"dynamic","desc":"Define a frequência dos checkpoints automáticos em termos do tempo máximo de recuperação desejado. 0 permite que o SQL Server gerencie automaticamente o tempo de recuperação alvo por banco de dados. Entra em vigor imediatamente com sp_configure + RECONFIGURE.","tags":["checkpoint","recovery","crash recovery"]},{"name":"remote query timeout (s)","default":"600","recommended":"600 ou 0 (ilimitado), conforme a carga de trabalho","unit":"seconds","dynamic":"dynamic","desc":"O tempo que o servidor aguarda uma resposta a consultas remotas (via linked server) antes de expirar. 0 significa aguardar indefinidamente. Entra em vigor imediatamente com sp_configure + RECONFIGURE.","tags":["timeout","remote","linked server"]},{"name":"network packet size (B)","default":"4096","recommended":"4096 (não altere, exceto em casos especiais)","unit":"bytes","dynamic":"dynamic","desc":"O tamanho de pacote usado para transferência de dados pela rede. O padrão é recomendado, exceto em operações em massa especiais que transferem volumes muito grandes de dados; uma configuração errada pode degradar o desempenho. Entra em vigor com sp_configure + RECONFIGURE.","tags":["network","network packet","packet"]},{"name":"nível de compatibilidade do banco de dados (ALTER DATABASE)","default":"Depends on server version","recommended":"O nível mais recente testado","unit":"level","dynamic":"dynamic","desc":"Determina com quais comportamentos de versão do SQL Server e com qual modelo do otimizador de consultas um banco de dados é executado. Definido por banco de dados com ALTER DATABASE ... SET COMPATIBILITY_LEVEL e entra em vigor imediatamente; afeta recursos do otimizador como a estimativa de cardinalidade.","tags":["database","compatibility level","optimizer","compatibility"]},{"name":"MAXDOP (database scoped configuration)","default":"0 (inherits the server setting)","recommended":"Um valor adequado à carga de trabalho do banco de dados","unit":"count","dynamic":"dynamic","desc":"Sobrepõe, no nível do banco de dados, a configuração max degree of parallelism de todo o servidor. Definido com ALTER DATABASE SCOPED CONFIGURATION SET MAXDOP e entra em vigor imediatamente; permite comportamentos de paralelismo diferentes para bancos de dados diferentes.","tags":["parallelism","parallel query","maxdop","database scoped"]},{"name":"quantidade de arquivos do tempdb (recomendação)","default":"SQL Server 2016+ setup: equal to the number of logical cores, at most 8 (1 before)","recommended":"Igual ao número de núcleos lógicos, no máximo 8 (aumente em passos de 4 se necessário)","unit":"count","dynamic":"dynamic","desc":"O número de arquivos de dados do tempdb é importante para reduzir a contenção de páginas de alocação. A recomendação geral é usar arquivos de tamanho igual até o número de núcleos (máx. 8). Um arquivo adicionado com ALTER DATABASE tempdb ADD FILE é usado imediatamente sem reinicialização; porém, se os arquivos existentes estiverem cheios, deixe todos os arquivos com o mesmo tamanho para equilibrar o preenchimento proporcional. Remover um arquivo do tempdb (REMOVE FILE) muitas vezes só é possível após uma reinicialização, porque o arquivo não se esvazia.","tags":["tempdb","storage","data files","contention"]},{"name":"Trace Flag 1117 / 1118 (nota)","default":"Default behavior for tempdb in SQL 2016+","recommended":"Geralmente desnecessário no SQL 2016+; ligado em versões mais antigas","unit":"flag","dynamic":"restart","desc":"O TF 1117 força todos os arquivos de um filegroup a crescerem juntos; o TF 1118 força a alocação de extents uniformes em vez de extents mistos. Desde o SQL Server 2016 esses comportamentos são o padrão para o tempdb, então as flags geralmente são desnecessárias. Exige reinicialização quando adicionado como flag de inicialização.","tags":["trace flag","tempdb","note"]},{"name":"Trace Flag 3226","default":"Off","recommended":"Ligado (suprime mensagens de backup bem-sucedido)","unit":"flag","dynamic":"dynamic","desc":"Impede que operações de backup bem-sucedidas sejam gravadas no error log do SQL Server e no log de eventos do Windows. Em sistemas com backups de log frequentes, evita que os logs se encham de mensagens desnecessárias (log spam). Pode ser habilitado imediatamente em tempo de execução com DBCC TRACEON(3226, -1); para persistir após reinicializações, adicione também -T3226 como parâmetro de inicialização.","tags":["trace flag","backup","backup messages","log"]},{"name":"lock pages in memory (nota sobre política do Windows)","default":"Off","recommended":"Concedido à conta de serviço em cenários específicos","unit":"policy","dynamic":"restart","desc":"Uma política de direitos de usuário do Windows que permite à conta de serviço do SQL Server impedir que suas páginas de memória sejam paginadas para o disco pelo sistema operacional. Pode reduzir oscilações de desempenho sob pressão de memória, mas deve ser configurada com cuidado. Alterar a política exige reinicialização do serviço.","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":"Mantenha o padrão ou ~50% da RAM disponível","unit":"GB","dynamic":"restart","desc":"Define, em gigabytes, a quantidade de memória alocada ao cache interno do storage engine WiredTiger. Por padrão é usada metade de (RAM total - 1GB). Definir o valor manualmente só é necessário em casos especiais e exige reinicialização do mongod.","tags":["memory","memory","cache","wiredtiger"]},{"name":"net.maxIncomingConnections","default":"1000000 (effectively limited by OS limits)","recommended":"Conforme a carga de trabalho e o ulimit do sistema operacional","unit":"count","dynamic":"restart","desc":"Limita o número máximo de conexões de entrada simultâneas que uma instância mongod ou mongos aceita. Se o valor for maior que o limite de file descriptors/conexões do sistema operacional (ulimit), não tem efeito; o SO determina o teto real (visível como current + available em db.serverStatus().connections). A alteração é feita no arquivo de configuração e exige reinicialização.","tags":["network","network","connections","connection"]},{"name":"operationProfiling.slowOpThresholdMs","default":"100","recommended":"100 ou menos, conforme a carga de trabalho","unit":"ms","dynamic":"dynamic","desc":"Define, em milissegundos, o limite de duração para que uma operação seja considerada lenta e registrada pelo profiler e no log. As operações que excedem esse limite são registradas para facilitar o diagnóstico. Pode ser alterado imediatamente em tempo de execução com db.setProfilingLevel().","tags":["profiling","slow query","slow query","monitoring"]},{"name":"replication.oplogSizeMB","default":"~5% of disk size (max 50GB)","recommended":"Grande o suficiente para cobrir a janela de manutenção","unit":"MB","dynamic":"dynamic","desc":"Define, em megabytes, o tamanho máximo da coleção oplog que armazena as operações nos membros do replica set. Um oplog suficientemente grande permite que membros atrasados se atualizem sem precisar de um resync completo. Pode ser alterado imediatamente em um replica set em execução com o comando replSetResizeOplog.","tags":["replication","oplog","replica set"]},{"name":"security.authorization","default":"disabled","recommended":"enabled (controle de acesso baseado em roles)","unit":"enabled/disabled","dynamic":"restart","desc":"Habilita o controle de acesso baseado em roles (RBAC); quando habilitado, os clientes precisam se autenticar e ser autorizados. Deve estar sempre habilitado em ambientes de produção. É definido no arquivo de configuração e exige reinicialização.","tags":["security","security","authorization","authorization","rbac"]},{"name":"net.compression.compressors","default":"snappy,zstd,zlib","recommended":"snappy,zstd (o padrão é adequado)","unit":"list","dynamic":"restart","desc":"Define os algoritmos de compressão, e sua ordem de preferência, que podem ser usados no tráfego de rede de clientes e intra-cluster. Reduz o uso de largura de banda de rede a um certo custo de CPU. É definido no arquivo de configuração e exige reinicialização.","tags":["network","network","compression","compression"]},{"name":"storage.wiredTiger.collectionConfig.blockCompressor","default":"snappy","recommended":"snappy (velocidade) ou zstd (alta compressão)","unit":"algorithm","dynamic":"restart","desc":"Define o algoritmo de compressão de blocos que o WiredTiger usa ao gravar dados de coleções em disco. snappy privilegia a velocidade, enquanto zlib e zstd oferecem taxas de compressão maiores. Aplica-se apenas a coleções criadas após a configuração e exige reinicialização.","tags":["storage","storage","compression","compression","wiredtiger"]},{"name":"storage.directoryPerDB","default":"false","recommended":"true se quiser separar discos","unit":"true/false","dynamic":"restart","desc":"Armazena os dados de cada banco de dados em um subdiretório separado, permitindo colocar bancos diferentes em volumes de disco diferentes. Só pode ser habilitado em um diretório de dados vazio. A alteração é feita no arquivo de configuração e exige reinicialização.","tags":["storage","storage","directory"]},{"name":"setParameter.cursorTimeoutMillis","default":"600000","recommended":"O padrão (10 minutos), conforme a carga de trabalho","unit":"ms","dynamic":"dynamic","desc":"Define, em milissegundos, quanto tempo cursores ociosos aguardam antes que o servidor os feche automaticamente. Impede que cursores abandonados consumam recursos. Pode ser alterado imediatamente em tempo de execução com db.adminCommand({setParameter:1}).","tags":["cursor","timeout","setparameter"]},{"name":"setParameter.transactionLifetimeLimitSeconds","default":"60","recommended":"O padrão, a menos que transações longas sejam necessárias","unit":"seconds","dynamic":"dynamic","desc":"Define, em segundos, o tempo máximo que uma transação multidocumento pode ficar aberta antes de ser abortada automaticamente. Impede que transações de longa duração prendam recursos e o cache do WiredTiger. Pode ser alterado imediatamente com setParameter.","tags":["transaction","transaction","setparameter"]},{"name":"setParameter.maxTransactionLockRequestTimeoutMillis","default":"5","recommended":"O padrão, conforme a contenção de locks","unit":"ms","dynamic":"dynamic","desc":"Define, em milissegundos, o tempo máximo que uma transação aguarda para adquirir um lock de que precisa antes de expirar. Ajustar o comportamento de espera por locks evita que transações fiquem bloqueadas por muito tempo. Pode ser alterado imediatamente com setParameter.","tags":["transaction","lock","lock","setparameter"]},{"name":"net.tls.mode","default":"disabled","recommended":"requireTLS (em produção)","unit":"mode","dynamic":"restart","desc":"Determina o uso de conexões criptografadas TLS/SSL pelo servidor. requireTLS obriga todas as conexões a serem criptografadas; preferTLS e allowTLS oferecem modos intermediários para períodos de transição. É usado em conjunto com a configuração de certificados e exige reinicialização.","tags":["security","security","tls","ssl","encryption"]},{"name":"storage.syncPeriodSecs","default":"60","recommended":"60 (não altere o padrão)","unit":"seconds","dynamic":"dynamic","desc":"Define, em segundos, com que frequência o WiredTiger faz checkpoints, ou seja, o intervalo entre as descargas dos dados em memória para o disco. O padrão é adequado para a maioria das cargas e alterá-lo geralmente não é recomendado. É definido no arquivo de configuração; em tempo de execução também pode ser alterado sem reinicialização com db.adminCommand({ setParameter: 1, syncdelay: <seconds> }).","tags":["storage","storage","checkpoint","sync"]},{"name":"replication.enableMajorityReadConcern","default":"true","recommended":"true (não pode ser alterado no 5.0+)","unit":"true/false","dynamic":"restart","desc":"Permite usar o nível de read concern majority; esse nível garante a leitura de dados gravados na maioria dos membros e que não sofrerão rollback. Desde o MongoDB 5.0 essa configuração não pode ser alterada e é sempre true; em versões mais antigas (ex.: em uma arquitetura PSA) podia ser definida como false. É definida no arquivo de configuração e exige reinicialização.","tags":["replication","read concern","replica set"]},{"name":"processManagement.fork","default":"false","recommended":"false com systemd, true para um daemon manual","unit":"true/false","dynamic":"restart","desc":"Faz o processo mongod executar fork e rodar em segundo plano como daemon. Com systemd ou um gerenciador de serviços semelhante, geralmente fica como false, porque o gerenciador de serviços cuida do gerenciamento do processo. É definido no arquivo de configuração e afeta o comportamento de inicialização.","tags":["process","process","daemon","fork"]}]},"reference/params-redis.json":{"engineId":"redis","engine":"Redis","order":6,"params":[{"name":"maxmemory","default":"0 (unlimited)","recommended":"~70-75% da RAM física","unit":"bytes","dynamic":"dynamic","desc":"Define a quantidade máxima de memória que o Redis pode usar para dados. O valor 0 significa uso ilimitado e pode levar a situações de falta de memória; definir um limite é fortemente recomendado. Pode ser alterado imediatamente com CONFIG SET maxmemory.","tags":["memory","memory"]},{"name":"maxmemory-policy","default":"noeviction","recommended":"allkeys-lru para cache, caso contrário noeviction","unit":"policy","dynamic":"dynamic","desc":"A política que determina quais chaves o Redis remove, e como, quando o limite de maxmemory é atingido. noeviction retorna erros de escrita, enquanto allkeys-lru remove as chaves usadas há mais tempo. Pode ser alterada imediatamente com CONFIG SET.","tags":["memory","memory","eviction","cache"]},{"name":"maxclients","default":"10000","recommended":"Com base na carga de trabalho e no ulimit do SO","unit":"count","dynamic":"dynamic","desc":"Define o número máximo de conexões de cliente simultâneas aceitas. O limite de file descriptors do sistema operacional pode restringir esse valor. Pode ser alterado imediatamente com CONFIG SET maxclients.","tags":["connections","connection","clients"]},{"name":"appendonly","default":"no","recommended":"yes se a persistência for necessária","unit":"yes/no","dynamic":"dynamic","desc":"Habilita o mecanismo de persistência AOF (Append Only File); quando habilitado, toda operação de escrita é acrescentada a um arquivo de log. Oferece menor risco de perda de dados que os snapshots RDB. Pode ser habilitado imediatamente com CONFIG SET appendonly yes.","tags":["persistence","persistence","aof"]},{"name":"appendfsync","default":"everysec","recommended":"everysec (equilibrado)","unit":"policy","dynamic":"dynamic","desc":"Define com que frequência o arquivo AOF é sincronizado em disco (fsync). always sincroniza a cada escrita e é o mais seguro, porém lento; everysec sincroniza uma vez por segundo, equilibrando desempenho e durabilidade; no deixa a sincronização a cargo do sistema operacional. Pode ser alterado imediatamente com CONFIG SET.","tags":["persistence","persistence","aof","fsync"]},{"name":"save","default":"3600 1 300 100 60 10000","recommended":"Depende da carga de trabalho, ou desativado (apenas AOF)","unit":"rule","dynamic":"dynamic","desc":"Define as condições (um determinado número de alterações em um determinado tempo) em que um snapshot RDB é salvo em disco. Definir um valor vazio desativa completamente os snapshots RDB. Pode ser alterado imediatamente com CONFIG SET save.","tags":["persistence","persistence","rdb","snapshot"]},{"name":"tcp-keepalive","default":"300","recommended":"300 (o padrão é adequado)","unit":"seconds","dynamic":"dynamic","desc":"Define, em segundos, o intervalo em que o Redis envia ACKs de TCP keepalive às conexões de clientes. Garante que conexões mortas sejam detectadas e fechadas e que conexões semiabertas sejam limpas. Pode ser alterado imediatamente com CONFIG SET.","tags":["network","network","tcp","keepalive"]},{"name":"timeout","default":"0","recommended":"0 (nunca fechar conexões) ou um tempo ocioso razoável","unit":"seconds","dynamic":"dynamic","desc":"Define, em segundos, o tempo máximo que uma conexão de cliente pode ficar ociosa; a conexão é fechada quando esse tempo é excedido. O valor 0 significa que os clientes podem ficar ociosos indefinidamente. Pode ser alterado imediatamente com CONFIG SET timeout.","tags":["connections","connection","timeout","idle"]},{"name":"hz","default":"10","recommended":"10 (até 100 em sistemas muito ocupados)","unit":"Hz","dynamic":"dynamic","desc":"Define quantas vezes por segundo o Redis executa suas tarefas em segundo plano (expiração de chaves, verificação de timeouts de clientes etc.). Valores maiores dão controle mais preciso, mas aumentam o uso de CPU. Pode ser alterado imediatamente com CONFIG SET hz.","tags":["performance","cpu","background"]},{"name":"activedefrag","default":"no","recommended":"yes se a fragmentação de memória for alta","unit":"yes/no","dynamic":"dynamic","desc":"Habilita a desfragmentação ativa de memória; reorganiza os dados durante a execução para reduzir a fragmentação de memória. Útil em instâncias de longa duração com fragmentação alta. Pode ser habilitado imediatamente com CONFIG SET activedefrag yes.","tags":["memory","memory","defragmentation"]},{"name":"maxmemory-samples","default":"5","recommended":"5 (pode ser aumentado para eviction mais precisa)","unit":"count","dynamic":"dynamic","desc":"Define o número de chaves que os algoritmos de eviction LRU e LFU amostram ao escolher uma chave. Valores maiores se aproximam do comportamento real de LRU/LFU, mas consomem um pouco mais de CPU. Pode ser alterado imediatamente com CONFIG SET.","tags":["memory","memory","eviction","lru"]},{"name":"io-threads","default":"1","recommended":"2-4 em servidores multi-core (conforme o número de núcleos)","unit":"count","dynamic":"restart","desc":"Define o número de threads de I/O usadas para escrever e ler nos sockets de clientes. Pode aumentar o throughput em sistemas multi-core com tráfego de rede intenso. Essa configuração só pode ser alterada no arquivo de configuração e exige reinicialização.","tags":["performance","threads","io","cpu"]},{"name":"repl-backlog-size","default":"1mb","recommended":"Maior, com base na taxa de escrita e na duração das interrupções","unit":"bytes","dynamic":"dynamic","desc":"Define o tamanho do buffer de replicação mantido no primário para ressincronização parcial quando a conexão de uma réplica cai. Um buffer grande o suficiente permite que a réplica se atualize após interrupções curtas sem sincronização completa. Pode ser alterado imediatamente com CONFIG SET.","tags":["replication","replication","backlog"]},{"name":"repl-diskless-sync","default":"yes","recommended":"yes (em redes rápidas)","unit":"yes/no","dynamic":"dynamic","desc":"Durante uma sincronização completa, envia os dados RDB às réplicas diretamente pelo socket, sem gravá-los em disco. Acelera a sincronização em sistemas com gargalo de I/O de disco. Pode ser alterado imediatamente com CONFIG SET repl-diskless-sync.","tags":["replication","replication","diskless","sync"]},{"name":"requirepass","default":"(empty)","recommended":"Defina uma senha forte","unit":"password","dynamic":"dynamic","desc":"Define a senha com a qual os clientes devem se autenticar via AUTH antes de executar comandos. Uma senha forte deve ser definida para impedir acesso não autorizado ao Redis. Pode ser alterada imediatamente com CONFIG SET requirepass.","tags":["security","security","authentication","password"]},{"name":"cluster-enabled","default":"no","recommended":"yes se for necessário escalonamento horizontal","unit":"yes/no","dynamic":"restart","desc":"Habilita o modo Redis Cluster; quando habilitado, os dados são distribuídos entre vários nós via hash slots. Usado para escalonamento horizontal e particionamento automático de dados. Essa configuração só pode ser alterada no arquivo de configuração e exige reinicialização.","tags":["cluster","cluster","scaling","scaling"]},{"name":"cluster-node-timeout","default":"15000","recommended":"15000 ou um valor ajustado à latência da rede","unit":"ms","dynamic":"dynamic","desc":"No modo cluster, define em milissegundos o tempo máximo que um nó pode ficar sem responder antes de ser considerado inalcançável (fail). Afeta diretamente o comportamento de failover e a estabilidade do cluster. Pode ser alterado imediatamente com CONFIG SET.","tags":["cluster","cluster","timeout","failover"]},{"name":"aof-use-rdb-preamble","default":"yes","recommended":"yes (recarga rápida)","unit":"yes/no","dynamic":"dynamic","desc":"Habilita o formato de persistência híbrido em que um rewrite do AOF grava um snapshot RDB compacto no início do arquivo, seguido dos comandos AOF incrementais. Isso reduz o tempo de carga do AOF na reinicialização. Pode ser alterado imediatamente com CONFIG SET.","tags":["persistence","persistence","aof","rdb"]}]},"reference/params-elasticsearch.json":{"engineId":"elasticsearch","engine":"Elasticsearch","order":7,"params":[{"name":"-Xms / -Xmx (heap da JVM)","default":"Automatic depending on version (half of RAM)","recommended":"50% da RAM física, no máximo ~30-31GB (Xms=Xmx)","unit":"GB","dynamic":"restart","desc":"Define o tamanho inicial (-Xms) e máximo (-Xmx) do heap da JVM; ambos devem ser iguais. Recomenda-se não exceder metade da RAM total nem o limite de ~32GB a partir do qual os compressed object pointers deixam de se aplicar. Definido em jvm.options e exige reinicialização do nó.","tags":["memory","memory","jvm","heap"]},{"name":"indices.memory.index_buffer_size","default":"10%","recommended":"10% (pode ser aumentado sob carga intensa de indexação)","unit":"% / bytes","dynamic":"restart","desc":"Define a parcela do heap alocada ao buffer de memória que mantém novos documentos durante a indexação. Aumentar esse buffer pode melhorar o throughput de indexação em cargas com muita escrita. Definido por nó em elasticsearch.yml e exige reinicialização.","tags":["memory","memory","indexing","buffer"]},{"name":"thread_pool.write.queue_size","default":"10000","recommended":"10000 (aumente com cuidado se ocorrerem rejeições na fila)","unit":"count","dynamic":"restart","desc":"Define o tamanho da fila do thread pool para operações de escrita index, delete e bulk. Quando a fila está cheia, as requisições são rejeitadas. Aumentar demais o valor pode causar pressão de memória. Definido em elasticsearch.yml e exige reinicialização.","tags":["thread pool","write","queue","queue"]},{"name":"thread_pool.search.queue_size","default":"1000","recommended":"1000 (aumente com cuidado se ocorrerem rejeições de busca)","unit":"count","dynamic":"restart","desc":"Define o tamanho da fila do thread pool para operações de busca. Quando as buscas simultâneas excedem a capacidade do pool, as requisições aguardam nessa fila e são rejeitadas se ela encher. Definido em elasticsearch.yml e exige reinicialização.","tags":["thread pool","search","search","queue"]},{"name":"indices.fielddata.cache.size","default":"unbounded","recommended":"Um limite como 20-40% (para proteção de memória)","unit":"% / bytes","dynamic":"restart","desc":"Define o tamanho máximo do cache de fielddata usado para ordenação e agregações em campos text. Como o padrão é ilimitado, recomenda-se definir um limite para evitar o esgotamento da memória. Definido em elasticsearch.yml e exige reinicialização.","tags":["memory","memory","fielddata","cache"]},{"name":"index.number_of_shards","default":"1","recommended":"Com base no volume de dados; meta de 10-50GB por shard","unit":"count","dynamic":"restart","desc":"Define o número de shards primários em que um índice é dividido. É uma configuração estática de índice (não exige reinicialização, mas só é informada na criação do índice): não pode ser alterada diretamente em um índice existente; altere-a gerando um novo índice com new index + _reindex, ou com as APIs _split (multiplicar) / _shrink (reduzir para um divisor). Shards demais aumentam o overhead do cluster, enquanto poucos demais limitam o escalonamento.","tags":["index","index","shard","scaling"]},{"name":"index.number_of_replicas","default":"1","recommended":"Pelo menos 1 em produção (para alta disponibilidade)","unit":"count","dynamic":"dynamic","desc":"Define o número de shards réplica mantidos para cada shard primário. As réplicas oferecem alta disponibilidade e desempenho de leitura. Essa configuração pode ser alterada instantaneamente em um índice ativo com a API _settings.","tags":["index","index","replica","availability"]},{"name":"index.refresh_interval","default":"1s","recommended":"30s ou -1 (temporariamente) sob indexação intensa","unit":"duration","dynamic":"dynamic","desc":"Define com que frequência a operação de refresh é executada para tornar documentos recém-indexados visíveis para a busca. Aumentar o valor, ou defini-lo como -1 durante cargas em massa, melhora significativamente o throughput de indexação. Pode ser alterado instantaneamente com a API _settings.","tags":["index","index","refresh","indexing"]},{"name":"indices.breaker.total.limit","default":"95%","recommended":"95% (padrão; altere com cuidado)","unit":"%","dynamic":"dynamic","desc":"Evita que o nó caia com OutOfMemory definindo a parcela máxima do heap que todos os circuit breakers juntos podem usar. Pode ser alterado instantaneamente em todo o cluster com a API _cluster/settings.","tags":["memory","memory","circuit breaker","stability"]},{"name":"cluster.routing.allocation.disk.watermark.low","default":"85%","recommended":"85% (o padrão é adequado)","unit":"% / bytes","dynamic":"dynamic","desc":"Quando o uso de disco de um nó excede esse limite, o Elasticsearch deixa de alocar novos shards nesse nó (os shards existentes permanecem). É o primeiro nível de alerta para evitar disco cheio. Pode ser alterado instantaneamente com a API _cluster/settings.","tags":["disk","allocation","watermark","storage"]},{"name":"cluster.routing.allocation.disk.watermark.high","default":"90%","recommended":"90% (o padrão é adequado)","unit":"% / bytes","dynamic":"dynamic","desc":"Quando o uso de disco de um nó excede esse limite, o Elasticsearch começa a realocar shards desse nó para outros nós. Alivia nós cujos discos estão enchendo. Pode ser alterado instantaneamente com a API _cluster/settings.","tags":["disk","allocation","watermark","storage"]},{"name":"cluster.routing.allocation.disk.watermark.flood_stage","default":"95%","recommended":"95% (o padrão é adequado)","unit":"% / bytes","dynamic":"dynamic","desc":"Quando o uso de disco excede esse limite crítico, os índices com shard no nó afetado são colocados em modo somente leitura (read-only-allow-delete) e as escritas são bloqueadas. Evita corrupção de dados antes que o disco fique totalmente cheio; no 7.4+ o bloqueio é liberado automaticamente quando o uso de disco cai abaixo do high watermark. No 8.x, em discos grandes, o max_headroom (padrão de 100GB livres) é determinante, e não o percentual. Pode ser alterado instantaneamente com a API _cluster/settings.","tags":["disk","allocation","watermark","read-only"]},{"name":"index.translog.durability","default":"request","recommended":"request (durabilidade) ou async (desempenho)","unit":"mode","dynamic":"dynamic","desc":"Define quando o log de transações (translog) é sincronizado (fsync) em disco. request sincroniza após cada requisição e minimiza a perda de dados; async sincroniza periodicamente e melhora o desempenho, mas traz risco de perda de dados em caso de crash. Pode ser alterado instantaneamente com a API _settings.","tags":["translog","durability","durability","indexing"]},{"name":"indices.recovery.max_bytes_per_sec","default":"40mb","recommended":"Pode ser aumentado conforme a capacidade de rede e disco","unit":"bytes/s","dynamic":"dynamic","desc":"Define a taxa máxima de transferência de dados por nó durante a recuperação de shards. Aumentar o valor acelera a recuperação, mas pode consumir os recursos de rede e disco da carga normal. Pode ser alterado instantaneamente com a API _cluster/settings.","tags":["recovery","recovery","throttle","network"]},{"name":"action.destructive_requires_name","default":"true","recommended":"true (bloqueia operações destrutivas com curinga)","unit":"true/false","dynamic":"dynamic","desc":"Bloqueia operações destrutivas, como excluir índices com curinga (*) ou _all, e exige que o nome do índice seja informado explicitamente. Uma configuração de segurança importante para evitar a exclusão acidental de todos os índices. Pode ser alterado instantaneamente com a API _cluster/settings.","tags":["security","security","destructive","safety"]},{"name":"discovery.seed_hosts","default":"(empty / 127.0.0.1)","recommended":"Endereços dos nós master-eligible do cluster","unit":"list","dynamic":"restart","desc":"Define a lista de endereços de seed hosts (nós master-eligible) que um nó contata para ingressar no cluster. Necessário para a descoberta do cluster e para que os nós se encontrem. Definido em elasticsearch.yml e exige reinicialização.","tags":["discovery","cluster","cluster","network"]}]},"reference/waits-oracle.json":{"engineId":"oracle","engine":"Oracle","order":1,"waits":[{"name":"log file sync","kind":"wait","meaning":"A sessão emitiu um COMMIT (ou ROLLBACK) e está aguardando o processo LGWR gravar os registros de redo nos online redo log files e confirmar.","causes":"I/O lento do redo log, commits pequenos muito frequentes, processo LGWR sobrecarregado, LGWR atrasado por falta de CPU, redo logs em discos lentos.","action":"Reduza a frequência de commits (commits em lote), mova os arquivos de redo log para discos rápidos/de baixa latência (SSD), elimine commits desnecessários, considere COMMIT NOWAIT/BATCH apenas para trabalhos em que a perda seja tolerável (ATENÇÃO: reduz a durabilidade; transações que parecem confirmadas podem ser perdidas em um crash) e meça a latência de I/O do log writer (log file parallel write).","tags":["commit","redo","io","lgwr"]},{"name":"db file sequential read","kind":"wait","meaning":"A sessão está fazendo uma leitura física de bloco único; está aguardando o bloco ser trazido do disco para o buffer cache, geralmente durante acesso por índice ou leitura de bloco de tabela por ROWID.","causes":"Index scans, planos de acesso ineficientes, buffer cache pequeno, subsistema de disco lento, blocos não encontrados no cache por causa de muitas leituras físicas.","action":"Ajuste o SQL para reduzir leituras desnecessárias, adicione índices adequados, aumente o tamanho do buffer cache, melhore o subsistema de I/O e identifique as consultas que mais leem com AWR/ASH.","tags":["io","index","single-block","read"]},{"name":"db file scattered read","kind":"wait","meaning":"A sessão está fazendo uma leitura física de múltiplos blocos; está aguardando vários blocos serem lidos do disco, geralmente durante um full table scan ou um fast full index scan.","causes":"Full table scans, índices ausentes ou não utilizados, planos de consulta ineficientes, scans de tabelas grandes, estatísticas do otimizador incorretas.","action":"Evite full scans desnecessários adicionando índices, revise os planos de consulta, atualize as estatísticas, examine a configuração de db_file_multiblock_read_count e considere paralelizar os full scans realmente necessários.","tags":["io","full-scan","multi-block","read"]},{"name":"direct path read","kind":"wait","meaning":"A sessão lê blocos diretamente para a PGA, ignorando o buffer cache; geralmente visto em consultas paralelas, scans de tabelas grandes ou leituras de LOB.","causes":"Full table scans paralelos, decisão de serial direct path read (adaptive direct read), scans de tabelas grandes, leituras do tablespace temporário (temp), acesso a LOB.","action":"Reduza a necessidade de scans grandes com tuning de consultas, avalie o tamanho da PGA, otimize as operações de sort/hash se o uso de temp for alto e aumente a largura de banda de I/O.","tags":["io","direct-path","parallel","read"]},{"name":"direct path write","kind":"wait","meaning":"A sessão grava blocos diretamente em disco sem passar pelo buffer cache; geralmente visto em inserts direct-path, sort spills ou gravações de LOB.","causes":"Operações de INSERT direct-path (APPEND), spills de sort/hash para o tablespace temporário, DML paralelo, gravações de LOB, discos de temp ou de dados lentos.","action":"Aumente a PGA para operações de sort/hash para reduzir spills para temp, coloque o tablespace temp em discos rápidos, revise cargas direct-path desnecessárias e melhore o desempenho de I/O.","tags":["io","direct-path","temp","write"]},{"name":"buffer busy waits","kind":"wait","meaning":"A sessão quer acessar um bloco no buffer cache, mas o bloco está sendo usado por outra sessão em modo incompatível, então ela aguarda sua liberação.","causes":"Acesso concorrente intenso ao mesmo bloco (hot block), freelists/ASSM insuficientes, contenção no bloco mais à direita de um índice sequencial (right-hand index growth), segmentos com alta intensidade de DML.","action":"Distribua os hot blocks (hash partitioning, reverse key index), use ASSM, aumente freelists/freelist groups e melhore o cache e a distribuição de sequences em tabelas que geram chaves sequenciais.","tags":["concurrency","buffer","hot-block","contention"]},{"name":"read by other session","kind":"wait","meaning":"Outra sessão já está lendo do disco o bloco de que esta sessão precisa; esta sessão aguarda a conclusão dessa leitura do mesmo bloco.","causes":"Requisições de leitura física concorrentes para os mesmos hot blocks, buffer cache pequeno, I/O lento, muitas sessões acessando ao mesmo tempo blocos populares de índice ou tabela.","action":"Aumente o buffer cache para reduzir leituras físicas, identifique os segmentos quentes e melhore seus planos de acesso, reduza a latência de I/O e elimine full scans desnecessários.","tags":["io","concurrency","read","hot-block"]},{"name":"latch: cache buffers chains","kind":"wait","meaning":"A sessão está aguardando adquirir o latch que protege uma hash chain do buffer cache; ocorre serialização ao localizar blocos no buffer cache.","causes":"SQL ineficiente gerando I/O lógico excessivo, acesso concorrente intenso a hot blocks, acesso repetido aos mesmos blocos via nested loops, blocos root/branch de índice muito populares.","action":"Ajuste o SQL para reduzir leituras lógicas, elimine acessos nested loop desnecessários, distribua os hot blocks e encontre e corrija as consultas que produzem buffer gets excessivos com AWR/ASH.","tags":["latch","concurrency","logical-io","buffer"]},{"name":"cursor: pin S wait on X","kind":"wait","meaning":"A sessão quer fazer pin de um cursor com um mutex em modo compartilhado (S), mas aguarda porque outra sessão mantém o mesmo cursor em modo exclusivo (X).","causes":"Taxa alta de hard/soft parse, SQL popular com parse muito frequente, consultas com literais que não usam bind variables, proliferação de child cursors, muitas sessões fazendo parse do mesmo SQL simultaneamente.","action":"Reduza a carga de parse usando bind variables, faça cache de cursores na aplicação (session_cached_cursors), reduza re-parses desnecessários e corrija SQL com version count alto.","tags":["mutex","parse","cursor","concurrency"]},{"name":"library cache lock","kind":"wait","meaning":"A sessão está aguardando adquirir um lock no handle de um objeto do library cache (package, view, definição de tabela); geralmente visto durante acesso concorrente à definição do objeto ou alterações nela.","causes":"DDL em objetos em uso, packages/views sendo recompilados constantemente, objetos inválidos, conexões e parses concorrentes intensos, alterações de privilégios (grant).","action":"Execute DDL fora dos horários de pico, evite compilações desnecessárias, corrija objetos inválidos e reduza loops excessivos de connect/parse no lado da aplicação.","tags":["library-cache","concurrency","ddl","parse"]},{"name":"library cache: mutex X","kind":"wait","meaning":"A sessão está aguardando adquirir um mutex para proteger um objeto do library cache em modo exclusivo (X); geralmente visto sob parse intenso e contenção em handles de objetos.","causes":"Parse excessivo (hard/soft), grande variedade de SQL com literais sem binds, número alto de child cursors, invalidação frequente de objetos, muitas sessões acessando o mesmo objeto simultaneamente.","action":"Use bind variables e cache de cursores para reduzir parses, padronize os literais do SQL, corrija problemas de version count alto e melhore o comportamento de conexão da aplicação.","tags":["mutex","library-cache","parse","concurrency"]},{"name":"enq: TX - row lock contention","kind":"wait","meaning":"A sessão quer modificar uma linha bloqueada por outra transação e está aguardando que essa transação faça commit/rollback e libere o lock da linha.","causes":"UPDATE/DELETE concorrentes nas mesmas linhas, transações de longa duração que não fazem commit, fluxo de aplicação mal projetado, locks de linha indiretos via chaves únicas/estrangeiras, sessões travadas.","action":"Mantenha as transações curtas e faça commit prontamente, redesenhe o padrão de acesso com contenção, imponha acesso ordenado com SELECT FOR UPDATE se necessário e encontre e resolva a sessão bloqueadora com ASH.","tags":["lock","transaction","row-lock","contention"]},{"name":"enq: TX - allocate ITL entry","kind":"wait","meaning":"A sessão precisa de um slot ITL (Interested Transaction List) em um bloco para trabalhar nele, mas tem que aguardar porque não resta slot ITL livre no bloco.","causes":"Configuração baixa de INITRANS, tamanho de bloco pequeno, muitas transações concorrentes no mesmo bloco, blocos densamente preenchidos recebendo DML intenso.","action":"Aumente o INITRANS da tabela/índice, aumente o PCTFREE para colocar menos linhas por bloco, distribua os hot blocks e reconstrua o objeto se necessário.","tags":["lock","transaction","itl","block"]},{"name":"gc buffer busy acquire","kind":"wait","meaning":"Em um ambiente RAC, a sessão quer obter um bloco pelo global cache, mas aguarda porque outra sessão na mesma instância já iniciou uma requisição global para o mesmo bloco.","causes":"Compartilhamento de hot blocks entre instâncias no RAC, desempenho insuficiente do interconnect, contenção à direita em índice sequencial, carga de trabalho mal particionada, tráfego intenso de global cache.","action":"Particione a carga de trabalho de forma sensata entre as instâncias (afinidade de aplicação/services), distribua os segmentos quentes (reverse key/partição), melhore a latência do interconnect e analise a contenção gc com a seção RAC do AWR e as views GV$.","tags":["rac","global-cache","concurrency","interconnect"]},{"name":"gc cr block busy","kind":"wait","meaning":"Em um ambiente RAC, a sessão solicitou a outra instância um bloco para leitura consistente (CR) e está aguardando que essa instância prepare o bloco e o envie pelo interconnect.","causes":"Compartilhamento de hot blocks entre instâncias, interconnect lento ou saturado, tráfego intenso de redo/commit, carga de trabalho mal particionada, requisições CR de global cache excessivas.","action":"Melhore a afinidade da carga de trabalho, otimize a largura de banda e a latência do interconnect, reduza os hot blocks, revise os padrões de commit e DML e faça tuning do RAC.","tags":["rac","global-cache","cr","interconnect"]},{"name":"log file switch (checkpoint incomplete)","kind":"wait","meaning":"A sessão quer alternar para um novo redo log, mas o checkpoint do próximo arquivo de log ainda não foi concluído, então o LGWR não pode reutilizar esse log e toda a geração de redo para.","causes":"Arquivos de redo log pequenos ou poucos demais, I/O lento do DBWR/checkpoint, alta taxa de geração de redo, número insuficiente de grupos de log.","action":"Aumente os arquivos de redo log e adicione grupos, melhore o desempenho de I/O do DBWR/checkpoint, faça otimizações na aplicação que reduzam a geração de redo e monitore a frequência de log switch.","tags":["redo","checkpoint","log-switch","io"]},{"name":"free buffer waits","kind":"wait","meaning":"A sessão procura um buffer limpo/livre no buffer cache para ler um novo bloco, mas aguarda um buffer livre porque o DBWR não consegue gravar os buffers sujos em disco com rapidez suficiente.","causes":"I/O de escrita lento do DBWR, buffer cache pequeno, geração rápida de buffers sujos por DML intenso, velocidade de checkpoint insuficiente, subsistema de disco saturado.","action":"Acelere o I/O de escrita dos datafiles, aumente o tamanho do buffer cache, avalie o número de processos DBWR (db_writer_processes) e revise a intensidade de DML e as configurações de checkpoint.","tags":["buffer","dbwr","io","checkpoint"]},{"name":"Buffer Cache Hit Ratio","kind":"metric","meaning":"A proporção de blocos solicitados atendidos pelo buffer cache sem ir ao disco; mostra que percentual das leituras lógicas não exigiu leitura física.","causes":"Uma proporção baixa geralmente se deve a buffer cache pequeno, full scans ineficientes, cache frio ou muitas leituras físicas. Isoladamente pode ser enganosa; uma proporção alta também pode esconder SQL ruim.","action":"Não use a proporção isoladamente como meta; avalie-a junto com os wait events e as tendências de leitura física. Ajuste o SQL ineficiente, reduza leituras lógicas desnecessárias e dimensione o cache para a carga de trabalho.","tags":["metric","buffer-cache","ratio","memory"]},{"name":"Average Active Sessions","kind":"metric","meaning":"O número médio de sessões ativas ao mesmo tempo (executando em CPU ou aguardando um evento) em um intervalo; resume a carga geral e a intensidade dos gargalos do banco de dados.","causes":"Um AAS alto pode se dever a saturação de CPU, esperas de I/O, contenção de lock/latch ou aumento de concorrência. Valores próximos ou acima do número de núcleos de CPU indicam um gargalo de recursos.","action":"Compare o AAS com o número de núcleos de CPU, encontre a wait class dominante (CPU/IO/concurrency) com ASH, ajuste o SQL e as sessões que geram mais carga e resolva o problema de recursos ou de concorrência.","tags":["metric","load","ash","sessions"]}]},"reference/waits-postgres.json":{"engineId":"postgres","engine":"PostgreSQL","order":2,"waits":[{"name":"LWLock:WALWrite","kind":"wait","meaning":"A sessão está aguardando o lightweight lock necessário para gravar os buffers de WAL em disco; geralmente causado pela serialização das gravações de WAL durante o commit.","causes":"I/O lento no disco de WAL, commits muito frequentes/pequenos, alta carga de escrita, largura de banda de gravação de WAL insuficiente, muitos backends gravando WAL ao mesmo tempo.","action":"Mova o WAL para um disco rápido/de baixa latência, agrupe commits (avalie synchronous_commit, commit_delay), aumente wal_buffers, reduza operações de escrita desnecessárias.","tags":["wal","lwlock","commit","io"]},{"name":"LWLock:BufferContent","kind":"wait","meaning":"A sessão está aguardando o lightweight lock de um buffer do shared buffer pool que protege o conteúdo da página; indica contenção por acesso concorrente à página.","causes":"Leituras/escritas concorrentes intensas na mesma página (hot page), contenção na borda direita de índices sequenciais, tabelas pequenas recebendo muitas atualizações, alta concorrência.","action":"Distribua as páginas quentes (configuração de fillfactor, particionamento), reduza a contenção de chaves sequenciais, reestruture linhas muito atualizadas, revise o padrão de acesso concorrente.","tags":["lwlock","buffer","concurrency","contention"]},{"name":"Lock:transactionid","kind":"wait","meaning":"A sessão está aguardando que outra transação, que bloqueou a linha que ela quer modificar, termine (commit/rollback); a espera de lock é no ID da transação alvo.","causes":"UPDATE/DELETE concorrentes nas mesmas linhas, transações de longa duração que não fazem commit, sessões idle-in-transaction, fluxo de trabalho com contenção mal projetado.","action":"Mantenha as transações curtas e faça commit prontamente, limite as sessões idle-in-transaction (idle_in_transaction_session_timeout), redesenhe o padrão de acesso com contenção, encontre a consulta bloqueadora com pg_stat_activity.","tags":["lock","transaction","row-lock","contention"]},{"name":"Lock:tuple","kind":"wait","meaning":"A sessão está aguardando adquirir um lock em uma tupla (linha) específica; visto quando várias sessões entram na fila para atualizar/bloquear a mesma linha.","causes":"SELECT FOR UPDATE/UPDATE concorrentes na mesma linha, contenção em hot rows (ex.: linhas de contador), locks de linha mantidos por muito tempo, alta concorrência.","action":"Distribua ou enfileire as atualizações de hot rows, reduza a duração das transações, redesenhe padrões com contenção como contadores (ex.: atualizações em lote), considere FOR UPDATE SKIP LOCKED.","tags":["lock","tuple","row-lock","contention"]},{"name":"Lock:relation","kind":"wait","meaning":"A sessão está aguardando adquirir um lock em nível de tabela em uma tabela/índice (relation); geralmente visto com contenção entre modos de lock incompatíveis de DDL e DML.","causes":"DDL como ALTER/DROP/TRUNCATE enquanto consultas estão em execução, VACUUM FULL exigindo um lock agressivo, acesso concorrente à mesma tabela em modos incompatíveis, consultas de longa duração.","action":"Execute DDL em períodos tranquilos com um lock_timeout curto, use autovacuum regular em vez de VACUUM FULL, monitore consultas longas, revise operações que serializam o acesso à tabela.","tags":["lock","relation","ddl","table-lock"]},{"name":"IO:DataFileRead","kind":"wait","meaning":"A sessão está aguardando uma página de arquivo de dados ser lida do disco para os shared buffers; é a espera de leitura física que ocorre quando a página solicitada não está em cache.","causes":"shared_buffers pequeno, planos de consulta ineficientes e scans grandes, cache frio, subsistema de disco lento, uso insuficiente de índices.","action":"Ajuste shared_buffers e o page cache do SO para a carga de trabalho, corrija consultas ineficientes e índices ausentes, melhore o desempenho de I/O, configure effective_cache_size corretamente.","tags":["io","read","buffer","disk"]},{"name":"IO:WALSync","kind":"wait","meaning":"A sessão está aguardando o WAL ser gravado de forma durável em disco (fsync/sincronização); para a durabilidade do commit, aguarda o WAL ser fisicamente descarregado.","causes":"Latência alta de fsync no storage, commits muito frequentes, disco de WAL de baixo desempenho, disco sem write-back cache, alta carga de escrita.","action":"Mova o disco de WAL para um storage rápido com baixa latência de fsync, agrupe commits (commit_delay/commit_siblings), avalie synchronous_commit em relação aos requisitos de negócio, melhore a camada de storage.","tags":["wal","io","fsync","commit"]},{"name":"IO:DataFileWrite","kind":"wait","meaning":"A sessão está aguardando uma página de dados suja ser gravada em disco; geralmente visto quando o próprio backend grava para encontrar uma página limpa no buffer pool.","causes":"I/O de escrita lento no disco de dados, congestionamento de checkpoint, background writer insuficiente, buffer pool pequeno, o próprio backend gravando devido à alta carga de escrita.","action":"Suavize os checkpoints (checkpoint_completion_target, max_wal_size), ajuste o background writer (bgwriter_lru_maxpages), melhore o desempenho de escrita em disco, revise shared_buffers.","tags":["io","write","checkpoint","bgwriter"]},{"name":"Client:ClientRead","kind":"wait","meaning":"O backend está aguardando o próximo comando/dado do cliente; visto quando o servidor está ocioso, esperando o cliente enviar dados.","causes":"Rede lenta, sessões idle-in-transaction, aplicação cliente enviando/recebendo dados lentamente, result sets grandes consumidos lentamente, problemas no pool de conexões.","action":"Examine a latência do lado da aplicação e da rede, limite as sessões idle-in-transaction, consuma os resultados de forma eficiente (ex.: cursor/lote), melhore o pool de conexões. Essa espera geralmente não é um gargalo do banco de dados.","tags":["client","network","idle","application"]},{"name":"IPC:ProcArrayGroupUpdate","kind":"wait","meaning":"A sessão está aguardando que o backend líder do grupo marque o fim de sua transação no ProcArray em grupo; é a serialização das atualizações do ProcArray durante o commit.","causes":"Taxa de commits/transações muito alta, excesso de transações curtas concorrentes, número alto de conexões, acesso intenso a snapshot/ProcArray.","action":"Gerencie a taxa de transações e o número de conexões simultâneas (pool de conexões), reduza transações curtas desnecessárias, limite o número de conexões sob concorrência muito alta, equilibre a carga de trabalho.","tags":["ipc","commit","procarray","concurrency"]},{"name":"LWLock:LockManager","kind":"wait","meaning":"A sessão está aguardando o lightweight lock do lock manager que protege a tabela de heavyweight locks; causado pela serialização das operações de aquisição/liberação de locks.","causes":"Consultas que acessam muitas tabelas/partições (excedendo o limite de fast-path locks), alta concorrência, tabelas particionadas em excesso, carga de trabalho que adquire/libera muitos locks.","action":"Reduza o número de partições/tabelas acessadas por consulta (partition pruning), revise o particionamento excessivo, gerencie a concorrência com um pool de conexões, simplifique operações que adquirem locks desnecessários.","tags":["lwlock","lock-manager","concurrency","partitioning"]},{"name":"Timeout:VacuumDelay","kind":"wait","meaning":"O processo de vacuum/autovacuum está pausado deliberadamente devido ao cost-based vacuum delay; uma espera intencional para limitar a carga de I/O.","causes":"Throttling devido às configurações vacuum_cost_delay/autovacuum_vacuum_cost_delay, cost_limit baixo, vacuum limpando muitas tabelas, configurações de autovacuum pouco agressivas.","action":"Se o vacuum estiver lento demais e bloat/dead tuples estiverem se acumulando, aumente cost_limit e reduza cost_delay, ajuste o número de workers e os limites do autovacuum, equilibre com a capacidade de I/O.","tags":["vacuum","timeout","throttle","maintenance"]},{"name":"cache hit ratio","kind":"metric","meaning":"A proporção de requisições de blocos atendidas pelos shared buffers sem ir ao disco; calculada a partir de blks_hit e blks_read em pg_stat_database.","causes":"Uma proporção baixa geralmente indica shared_buffers pequeno, scans grandes ineficientes, cache frio ou memória insuficiente. Como o page cache do SO também atende leituras, a proporção isoladamente pode ser enganosa.","action":"Interprete a proporção junto com os wait events e as tendências de I/O, ajuste shared_buffers e effective_cache_size, corrija consultas ineficientes; se continuar baixa, examine a memória e os planos de consulta.","tags":["metric","cache","ratio","memory"]},{"name":"replication lag","kind":"metric","meaning":"O quanto um servidor standby/réplica está atrasado na aplicação do WAL produzido pelo primário; medido em bytes (diferença de LSN) ou em segundos de atraso.","causes":"Rede lenta, carga intensa de consultas no standby (especialmente conflitos de replay), I/O de disco lento no standby, alta taxa de escrita no primário, consultas de leitura longas atrasando a recuperação.","action":"Monitore o atraso de write/flush/replay com pg_stat_replication, melhore o desempenho de rede e de I/O do standby, gerencie consultas longas conflitantes (hot_standby_feedback/max_standby_streaming_delay), revise a necessidade de replicação síncrona.","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":"A thread está aguardando o mutex que protege a lista LRU do buffer pool do InnoDB; indica serialização durante leituras/eviction de páginas. No 8.0 o antigo buf_pool_mutex único foi dividido; os outros instrumentos relacionados são buf_pool_free_list_mutex, buf_pool_flush_state_mutex e buf_pool_zip_mutex.","causes":"Acesso intenso ao buffer pool sob alta concorrência, uma única instância de buffer pool, leituras/eviction frequentes de páginas, buffer pool subdimensionado.","action":"Divida o mutex aumentando innodb_buffer_pool_instances, dimensione innodb_buffer_pool_size para o working set, ajuste as consultas para reduzir leituras físicas e gerencie a concorrência.","tags":["innodb","mutex","buffer-pool","concurrency"]},{"name":"wait/io/file/innodb/innodb_data_file","kind":"wait","meaning":"A thread está aguardando a conclusão de I/O físico de arquivo (leitura/escrita) nos arquivos de dados do InnoDB (ibd/ibdata).","causes":"Subsistema de disco lento, muitas leituras físicas devido a buffer pool pequeno, scans de tabelas grandes, pressão de checkpoint/flush, capacidade de I/O insuficiente.","action":"Aumente o buffer pool, corrija consultas ineficientes e índices ausentes, migre para storage rápido (SSD/NVMe), configure innodb_io_capacity de acordo com o storage e revise o comportamento de flush.","tags":["innodb","io","datafile","disk"]},{"name":"wait/lock/table/sql/handler","kind":"wait","meaning":"A thread está aguardando adquirir o handler lock em nível de tabela (table lock) na camada SQL; visto com acesso concorrente a uma tabela em modos incompatíveis.","causes":"Operações que exigem table lock, storage engines com lock em nível de tabela como MyISAM, instruções LOCK TABLES, contenção entre DDL e DML, consultas de longa duração.","action":"Use InnoDB com lock em nível de linha, reduza o uso de LOCK TABLES, execute DDL em períodos de pouca atividade, otimize consultas longas e revise padrões que serializam o acesso à tabela.","tags":["lock","table-lock","sql-layer","contention"]},{"name":"wait/synch/mutex/sql/LOCK_open","kind":"wait","meaning":"A thread está aguardando o mutex LOCK_open, que protege as definições de tabelas abertas/o dicionário de objetos; é a serialização das operações de abertura/fechamento de tabelas.","causes":"Acesso constante a muitas tabelas diferentes, table_open_cache/table_definition_cache pequenos, abertura e fechamento frequentes de tabelas, alta concorrência, tabelas/partições demais.","action":"Aumente table_open_cache e table_open_cache_instances, ajuste table_definition_cache, revise um número excessivo de tabelas/partições e reduza aberturas de tabelas desnecessariamente frequentes.","tags":["mutex","table-cache","sql-layer","concurrency"]},{"name":"row lock waits","kind":"wait","meaning":"Uma transação está aguardando a liberação de um row lock do InnoDB mantido por outra transação; indica contenção de locks em nível de linha.","causes":"UPDATE/DELETE concorrentes nas mesmas linhas, transações de longa duração que não fazem commit, faixas de lock amplas (gap locks) devido a índices ausentes, contenção em hot rows, ciclos de deadlock.","action":"Mantenha as transações curtas e faça commit prontamente, reduza a faixa de linhas bloqueadas adicionando um índice adequado, redesenhe os padrões com contenção, monitore deadlocks (SHOW ENGINE INNODB STATUS) e revise o nível de isolamento.","tags":["innodb","row-lock","transaction","contention"]},{"name":"log file waits","kind":"wait","meaning":"A thread está aguardando a liberação de espaço no redo log buffer do InnoDB ou a gravação do redo log em disco; geralmente visto sob pressão de flush do log buffer/checkpoint.","causes":"Redo log pequeno (8.0.30+ innodb_redo_log_capacity; antes disso innodb_log_file_size × innodb_log_files_in_group), disco de log lento, alta taxa de escrita, flushes frequentes (innodb_flush_log_at_trx_commit=1 com commits frequentes), log buffer insuficiente.","action":"Aumente a capacidade de redo (8.0.30+ innodb_redo_log_capacity, dinâmico; antes disso innodb_log_file_size, exige reinicialização) e innodb_log_buffer_size, mova o redo log para um disco rápido, revise o padrão de commits e avalie a configuração de flush em relação aos requisitos de durabilidade.","tags":["innodb","redo","log","io"]},{"name":"wait/io/file/innodb/innodb_log_file","kind":"wait","meaning":"A thread está aguardando a conclusão de I/O físico (escrita e fsync) nos arquivos de redo log do InnoDB; aguarda o redo chegar ao disco para a durabilidade do commit.","causes":"Latência alta de fsync no storage, commits muito frequentes com innodb_flush_log_at_trx_commit=1, disco de log de baixo desempenho, alta carga de escrita.","action":"Mova o disco de redo log para storage rápido de baixa latência, agrupe commits quando possível, avalie innodb_flush_log_at_trx_commit em relação aos requisitos de negócio e melhore a camada de storage.","tags":["innodb","redo","fsync","commit"]},{"name":"wait/synch/mutex/innodb/log_writer_mutex","kind":"wait","meaning":"A thread está aguardando o mutex que protege as estruturas da thread log writer do redo log do InnoDB. O subsistema de redo foi redesenhado no 8.0; em vez do antigo log_sys_mutex único há instrumentos separados como log_writer_mutex, log_flusher_mutex e log_checkpointer_mutex.","causes":"Taxa de escrita/commit muito alta, geração intensa de redo, contenção nas threads log writer/flusher, disco de log lento, log buffer pequeno.","action":"Equilibre a carga de escrita e a frequência de commits, considere operações em lote que reduzam a geração de redo, ajuste o log buffer e aproveite as melhorias de escalabilidade do redo log da sua versão do MySQL.","tags":["innodb","mutex","redo","concurrency"]},{"name":"Innodb_buffer_pool_wait_free","kind":"metric","meaning":"O número de vezes que uma thread não encontrou página livre no buffer pool e teve que aguardar a descarga de páginas sujas para obter uma página livre; um aumento constante indica pressão no buffer pool.","causes":"Buffer pool pequeno, I/O de flush/escrita lento, innodb_io_capacity baixo, geração rápida de páginas sujas sob alta carga de escrita, atraso de checkpoint.","action":"Aumente innodb_buffer_pool_size, configure innodb_io_capacity/io_capacity_max de acordo com o storage, melhore o desempenho de I/O de escrita e revise a proporção de páginas sujas (innodb_max_dirty_pages_pct).","tags":["metric","innodb","buffer-pool","flush"]},{"name":"Threads_running","kind":"metric","meaning":"O número de threads que não estão ociosas e estão executando consultas ativamente naquele momento; mostra a execução concorrente instantânea no servidor e a provável intensidade da contenção.","causes":"Pico repentino de consultas, consultas lentas se acumulando, threads travadas por contenção de lock/mutex, saturação de CPU, efeito thundering herd.","action":"Quando Threads_running disparar, encontre consultas lentas/bloqueadas (SHOW PROCESSLIST), ajuste as consultas, limite a concorrência com pool de conexões e thread pool e elimine a fonte da contenção.","tags":["metric","concurrency","threads","load"]},{"name":"Innodb_row_lock_time_avg","kind":"metric","meaning":"O tempo médio (milissegundos) gasto aguardando para adquirir um row lock; mostra a gravidade da contenção de locks em nível de linha.","causes":"Acesso concorrente intenso às mesmas linhas, transações longas, faixas de lock amplas devido a índices ausentes, esperas se aproximando de deadlock/lock wait timeout.","action":"Reduza a duração das transações, restrinja o escopo dos locks com índices adequados, redesenhe o padrão de acesso com contenção e revise innodb_lock_wait_timeout e o nível de isolamento.","tags":["metric","innodb","row-lock","contention"]},{"name":"history list length","kind":"metric","meaning":"O número de transações no undo log do InnoDB que ainda não passaram por purge (mantendo versões antigas de linhas); mostra o acúmulo de versões antigas mantidas para o MVCC.","causes":"Transações abertas de longa duração (especialmente transações de leitura longas), thread de purge lenta, alta taxa de DML, transações não confirmadas/ociosas.","action":"Identifique e encerre transações de longa duração e ociosas, ajuste o número de threads de purge (innodb_purge_threads) e mantenha as transações curtas na aplicação; um HLL alto causa problemas de desempenho e bloat.","tags":["metric","innodb","undo","mvcc"]},{"name":"Innodb_data_reads","kind":"metric","meaning":"O número total de requisições de leitura física que o InnoDB fez no disco; mostra a carga de leitura que o buffer pool não conseguiu atender e que foi ao disco.","causes":"Buffer pool pequeno, cache frio, consultas ineficientes e scans grandes, índices ausentes, working set maior que a memória.","action":"Aumente o tamanho do buffer pool, corrija consultas ineficientes e índices ausentes, monitore a tendência de leituras físicas junto com o hit ratio do buffer pool e melhore o desempenho de I/O.","tags":["metric","innodb","io","read"]},{"name":"Innodb_buffer_pool_read_requests","kind":"metric","meaning":"O número total de requisições de leitura lógica atendidas pelo buffer pool do InnoDB; usado junto com Innodb_buffer_pool_reads (o número de páginas não encontradas no buffer pool e lidas do disco) para calcular o hit ratio do buffer pool.","causes":"Um valor alto indica atividade intensa de consultas. Se a proporção de Innodb_buffer_pool_reads em relação a esse valor for alta (hit ratio baixo), há falta de memória ou acesso ineficiente.","action":"Monitore o hit ratio do buffer pool (1 - Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests); se estiver baixo, aumente o buffer pool e otimize as consultas, e ajuste as consultas ineficientes que geram leituras lógicas excessivas.","tags":["metric","innodb","buffer-pool","logical-io"]}]},"reference/waits-mssql.json":{"engineId":"mssql","engine":"SQL Server","order":4,"waits":[{"name":"CXPACKET","kind":"wait","meaning":"Espera que ocorre enquanto as threads se sincronizam durante a execução paralela de consultas; vista enquanto a distribuição/correspondência de trabalho entre operadores do plano paralelo está pendente.","causes":"Alto grau de paralelismo, distribuição desigual do trabalho (skew), MAXDOP ilimitado/alto (0) e cost threshold for parallelism baixo (padrão 5), scans paralelos grandes devido a índices ausentes, planos ineficientes.","action":"Ajuste cost threshold for parallelism e MAXDOP à carga de trabalho, corrija índices ausentes e estatísticas e não trate CXPACKET como um problema por si só; separe a espera real usando CXCONSUMER e foque nos planos paralelos ineficientes.","tags":["parallelism","cxpacket","query","cpu"]},{"name":"CXCONSUMER","kind":"wait","meaning":"Em um plano paralelo, a thread consumidora aguardando a chegada de dados das threads produtoras; geralmente uma espera de paralelismo inofensiva.","causes":"A thread consumidora aguardando durante a execução paralela normal, fluxo de dados desigual, atrasos no lado produtor, planos paralelos ineficientes.","action":"CXCONSUMER é quase sempre benigno e não exige ação por si só; para encontrar o gargalo real, concentre-se nos wait types subjacentes do lado produtor (IO, LCK etc.) e na eficiência do plano.","tags":["parallelism","cxconsumer","query","benign"]},{"name":"PAGEIOLATCH_SH","kind":"wait","meaning":"A thread está aguardando um latch para proteger uma página de dados em modo compartilhado (SH) enquanto ela é lida do disco para o buffer pool; uma espera de I/O físico de leitura.","causes":"I/O de disco lento, memória insuficiente (buffer pool pequeno), scans grandes e índices ausentes, cache frio, carga intensa de leitura física.","action":"Avalie a memória (max server memory) e o buffer pool, corrija consultas ineficientes e índices ausentes, melhore a latência de I/O do storage e identifique e ajuste as consultas que mais leem.","tags":["io","pageiolatch","read","buffer-pool"]},{"name":"PAGEIOLATCH_EX","kind":"wait","meaning":"A thread está aguardando um latch para proteger em modo exclusivo (EX) uma página de dados sendo lida do disco; geralmente aguarda o I/O físico de uma página que será lida para modificação.","causes":"I/O de disco lento, carga de escrita intensa, memória insuficiente, pressão de checkpoint/lazy writer, operações que fazem grandes alterações de dados.","action":"Melhore o desempenho de escrita/leitura do storage, aumente a memória do buffer pool, torne as operações com muita escrita mais eficientes e em lote, e separe e meça o I/O do tempdb e do disco de dados.","tags":["io","pageiolatch","write","buffer-pool"]},{"name":"PAGELATCH_UP","kind":"wait","meaning":"A thread está aguardando um latch para proteger uma página já em memória em modo update (UP); não é I/O físico, mas contenção por acesso concorrente a uma página em memória.","causes":"Contenção em páginas quentes em memória, especialmente contenção em páginas de sistema do tempdb (PFS/GAM/SGAM), criação concorrente intensa de objetos no tempdb, contenção de insert na última página (hot page).","action":"Divida o tempdb em arquivos de dados de tamanho igual de acordo com o número de núcleos, reduza a contenção no tempdb, distribua os padrões de hot page e elimine o uso desnecessário do tempdb (spills etc.).","tags":["pagelatch","tempdb","concurrency","contention"]},{"name":"PAGELATCH_EX","kind":"wait","meaning":"A thread está aguardando um latch para proteger uma página em memória em modo exclusivo (EX); geralmente visto com contenção de insert na última página em tabelas com chaves crescentes (sequenciais).","causes":"Contenção de insert na última página em índices com chaves sequenciais/crescentes, contenção em páginas de sistema do tempdb, escritas concorrentes intensas em páginas quentes, alta taxa de inserts.","action":"Para contenção na última página, use OPTIMIZE_FOR_SEQUENTIAL_KEY = ON (SQL Server 2019+) ou distribuição de chaves (hash/GUID/índice reverso), divida o tempdb em vários arquivos e redesenhe o padrão de insert intenso.","tags":["pagelatch","last-page-insert","concurrency","contention"]},{"name":"LCK_M_X","kind":"wait","meaning":"A thread está aguardando adquirir um lock exclusivo em um recurso (linha/página/tabela); geralmente aguarda a liberação de outros locks para modificar dados (UPDATE/DELETE/INSERT).","causes":"Transações de longa duração, alterações concorrentes nos mesmos recursos, lock escalation, escopo de lock amplo devido a índices ausentes, sessões bloqueadoras.","action":"Mantenha as transações curtas e faça commit prontamente, restrinja o escopo de lock com índices apropriados, encontre a consulta bloqueadora (sys.dm_exec_requests/blocking), revise lock escalation e o nível de isolamento e considere RCSI se necessário.","tags":["lock","exclusive","blocking","transaction"]},{"name":"LCK_M_U","kind":"wait","meaning":"A thread está aguardando adquirir um update lock em um recurso; enquanto um UPDATE faz o scan, lendo uma linha e preparando-se para modificá-la, aguarda a liberação de outros locks.","causes":"Atualizações concorrentes nas mesmas linhas, transações longas, muitas linhas lidas e bloqueadas devido a índices ausentes, sessões bloqueadoras, contenção de locks.","action":"Adicione índices apropriados para as instruções UPDATE para reduzir o número de linhas lidas/bloqueadas, reduza a duração das transações, analise a cadeia de bloqueio e avalie as opções de nível de isolamento e RCSI.","tags":["lock","update-lock","blocking","transaction"]},{"name":"WRITELOG","kind":"wait","meaning":"A thread está aguardando que os registros do log de transações sejam gravados em disco (log flush); geralmente aguarda no momento do commit que o log se torne durável.","causes":"I/O lento no disco de log, commits muito frequentes/pequenos, alta carga de escrita, contenção entre o disco de log e o disco de dados, efeito da replicação síncrona do Always On.","action":"Mova o log de transações para um disco rápido e de baixa latência, agrupe commits, reduza commits desnecessariamente frequentes, considere delayed durability (se apropriado) e meça a latência de I/O do log.","tags":["log","writelog","commit","io"]},{"name":"ASYNC_NETWORK_IO","kind":"wait","meaning":"O SQL Server está pronto para enviar resultados, mas aguarda do lado da rede/cliente porque o cliente não está consumindo os dados com rapidez suficiente; geralmente um gargalo do lado da aplicação.","causes":"Aplicação cliente processando os resultados lentamente (consumo linha a linha), result sets grandes, rede lenta, processamento RBAR na aplicação, recursos insuficientes no cliente.","action":"Consuma os resultados rapidamente e em massa na aplicação, reduza result sets desnecessariamente grandes (apenas as colunas/linhas necessárias) e verifique a latência da rede. Geralmente é um problema do cliente/rede, não do SQL Server.","tags":["network","client","application","async"]},{"name":"SOS_SCHEDULER_YIELD","kind":"wait","meaning":"Espera que ocorre quando uma thread esgota sua fatia de tempo de CPU (quantum) e cede voluntariamente o scheduler; indica principalmente pressão de CPU ou processamento intensivo em CPU.","causes":"Consultas intensivas limitadas por CPU, alta concorrência e saturação de CPU, contenção de spinlock, consultas ineficientes com muitas leituras lógicas.","action":"Encontre e ajuste as consultas ineficientes que consomem CPU (índice ausente, plano ruim), reduza leituras lógicas, avalie a capacidade de CPU e a concorrência e, se continuar alto, investigue o gargalo de hardware/plano.","tags":["cpu","scheduler","cpu-bound","yield"]},{"name":"RESOURCE_SEMAPHORE","kind":"wait","meaning":"A consulta está aguardando o memory grant de que precisa para ser executada; a execução não pode começar até que haja memória de consulta livre suficiente.","causes":"Consultas que solicitam memória excessiva (grandes sorts/hashes), estimativas de cardinalidade erradas (infladas), memória insuficiente no servidor, muitas consultas simultâneas com uso intenso de memória, estatísticas desatualizadas.","action":"Atualize as estatísticas para corrigir estimativas excessivas de memory grant, otimize as consultas que precisam de grandes sorts/hashes (índice, filtro), revise as configurações de Resource Governor e max server memory e limite a carga simultânea com uso intenso de memória.","tags":["memory","memory-grant","query","resource"]},{"name":"THREADPOOL","kind":"wait","meaning":"Tarefas aguardando uma thread livre do thread pool porque não há worker thread disponível para executar uma nova tarefa; um wait type crítico que indica esgotamento grave de worker threads.","causes":"Threads presas por bloqueios longos, número muito alto de conexões simultâneas, max worker threads insuficiente, paralelismo intenso, deadlocks/cadeias longas de lock.","action":"Resolva a cadeia de bloqueio com urgência, gerencie as conexões simultâneas com um pool de conexões, elimine locks mantidos por muito tempo, revise a configuração de max worker threads; conecte-se pelo DAC para encontrar a causa raiz.","tags":["threadpool","worker-thread","blocking","critical"]},{"name":"HADR_SYNC_COMMIT","kind":"wait","meaning":"Em uma réplica síncrona do Always On, o primário aguardando que o registro de log seja endurecido (hardened) na réplica secundária antes de confirmar a transação; latência de commit síncrono.","causes":"Rede lenta/de alta latência até a réplica secundária, I/O lento no disco de log da secundária, secundária sobrecarregada, réplica geograficamente distante, alta taxa de escrita.","action":"Melhore a latência e a largura de banda da rede entre as réplicas, aumente o desempenho do disco de log da secundária, equilibre a carga da secundária e, se a latência for crítica, revise a topologia de réplicas síncronas/assíncronas.","tags":["alwayson","replication","sync-commit","hadr"]},{"name":"Page Life Expectancy","kind":"metric","meaning":"Métrica que mostra o número médio de segundos que uma página de dados permanece no buffer pool (sem ser removida da memória); um indicador importante de pressão de memória.","causes":"Um PLE baixo ou em queda rápida significa pressão de memória, scans grandes ineficientes, working set maior que a memória ou memória insuficiente. Os nós NUMA também devem ser avaliados individualmente.","action":"Observe a tendência do PLE e as quedas repentinas em vez de um limite fixo, avalie a memória do buffer pool (max server memory), ajuste as consultas ineficientes que consomem muita memória e monitore o PLE por nó NUMA.","tags":["metric","memory","buffer-pool","ple"]},{"name":"Taxa de acerto do buffer cache","kind":"metric","meaning":"A proporção de requisições de páginas de dados atendidas pelo buffer cache sem ir ao disco; mostra o percentual de páginas lidas da memória.","causes":"Em sistemas modernos essa proporção geralmente é muito alta (graças ao read-ahead), e um valor baixo indica pressão de memória significativa. Uma proporção alta por si só não garante bom desempenho.","action":"Interprete essa métrica não isoladamente, mas junto com o PLE, as esperas PAGEIOLATCH e as tendências de leitura física; se houver sinais de pressão de memória, aumente a memória do buffer pool e corrija as consultas ineficientes.","tags":["metric","memory","buffer-pool","ratio"]}]},"reference/waits-mongodb.json":{"engineId":"mongodb","engine":"MongoDB","order":5,"waits":[{"name":"WiredTiger cache used %","kind":"metric","meaning":"Quanto do cache interno alocado do storage engine WiredTiger está em uso; mostra a pressão de manter os dados em memória (o limite alvo padrão fica em torno de 80%).","causes":"Working set maior que o cache, cache subdimensionado, scans grandes, leituras/escritas intensas, muitas transações abertas.","action":"Avalie o tamanho do cache do WiredTiger (storage.wiredTiger.engineConfig.cacheSizeGB) e a RAM, adicione índices que reduzam o working set e monitore a pressão de eviction e a latência à medida que o uso se aproxima da meta de 80% e do limite de eviction de 95%.","tags":["metric","wiredtiger","cache","memory"]},{"name":"WiredTiger cache dirty %","kind":"metric","meaning":"O percentual de dados no cache do WiredTiger ainda não gravados em disco (sujos); mostra a pressão de escrita e a carga de checkpoint/eviction (o limite de dirty eviction geralmente fica em torno de 20%).","causes":"Alta carga de escrita, I/O de disco lento, escritas grandes/de longa duração, pressão de checkpoint, cache incapaz de acompanhar a taxa de escrita.","action":"Se o percentual sujo se aproximar do limite de eviction (20%), melhore o desempenho de escrita em disco, equilibre a carga de escrita, avalie o tamanho do cache e revise escritas longas e o intervalo de checkpoint.","tags":["metric","wiredtiger","cache","write"]},{"name":"tickets disponíveis (leitura/escrita)","kind":"metric","meaning":"O número restante de tickets de concorrência que o WiredTiger concede para operações simultâneas de leitura e escrita; se cair a zero, novas operações entram na fila por um ticket.","causes":"Operações lentas mantendo tickets por muito tempo, gargalo de I/O de disco, lock/contenção, picos repentinos de carga, tickets esgotados por consultas de longa duração.","action":"Se os tickets disponíveis se aproximarem de zero e se formar uma fila, otimize as consultas lentas (adicione índices), melhore o I/O de disco, equilibre a carga; o esgotamento de tickets geralmente é sintoma de um gargalo mais profundo de I/O/contenção.","tags":["metric","wiredtiger","concurrency","tickets"]},{"name":"global lock queue","kind":"metric","meaning":"O tamanho da fila de operações de leitura (readers) e escrita (writers) aguardando um lock global/de banco de dados/de coleção; mostra o número de operações aguardando sob contenção de lock.","causes":"Locks mantidos por muito tempo, contenção intensa de escrita, operações de longa duração, operações DDL e o breve lock exclusivo de coleção adquirido no início/fim de um index build (builds híbridos no 4.2+; builds em foreground não existem mais), locks mantidos por muito tempo devido a I/O lento.","action":"Se a fila estiver constantemente cheia, encontre e otimize as operações de longa duração (currentOp), agende index builds e outros DDL para fora do horário de pico, melhore o I/O e revise os padrões de escrita com contenção.","tags":["metric","lock","queue","concurrency"]},{"name":"replication lag (secundário)","kind":"metric","meaning":"O quanto (em segundos) um membro secundário está atrasado na aplicação do oplog do primário; mostra o atraso de dados entre os membros do replica set.","causes":"Rede lenta, I/O de disco lento no secundário, carga intensa de leitura no secundário, alta taxa de escrita no primário, hardware insuficiente no secundário, operações de longa duração.","action":"Monitore o atraso com rs.printSecondaryReplicationInfo, melhore o desempenho de rede e de I/O do secundário, equilibre a carga do secundário, mantenha o tamanho do oplog suficiente e revise o requisito de write concern.","tags":["metric","replication","lag","secondary"]},{"name":"oplog window","kind":"metric","meaning":"O intervalo de tempo (horas) entre as operações mais antigas e mais recentes mantidas no oplog; mostra quanto tempo um secundário pode ficar atrasado sem perder a sincronização.","causes":"Tamanho de oplog pequeno, alta taxa de escrita repentina, secundários offline por muito tempo, aumento da carga de replicação.","action":"Se a oplog window tiver diminuído, aumente o tamanho do oplog, mantenha o atraso do secundário abaixo da janela e revise a carga de escrita e os requisitos de backup/sincronização; se a janela for perdida, é necessário um resync completo.","tags":["metric","replication","oplog","window"]},{"name":"page faults","kind":"metric","meaning":"O número de page faults (especialmente hard faults) em que o sistema operacional precisa buscar no disco páginas de dados que não estão em memória; mostra dados transbordando da memória para o disco.","causes":"Working set maior que a RAM, memória insuficiente, scans grandes, pressão no cache, consumo de memória por outros processos.","action":"Avalie a memória do servidor/working set, reduza os dados lidos adicionando índices, equilibre o cache do WiredTiger e a memória do SO e monitore os aumentos de hard page faults junto com a latência de I/O.","tags":["metric","memory","page-fault","io"]},{"name":"connections current","kind":"metric","meaning":"O número de conexões de clientes abertas no momento com o servidor; mostra o uso do pool de conexões e o quanto está próximo do máximo.","causes":"Pools de conexões mal configurados, vazamentos de conexão, aumento repentino de clientes, conexões mantidas por muito tempo, conexões excessivas de microsserviços.","action":"Compare o número de conexões com o limite do servidor (maxIncomingConnections), dimensione corretamente o pool de conexões no lado da aplicação, corrija vazamentos de conexão e monitore picos repentinos.","tags":["metric","connections","pool","capacity"]},{"name":"proporção scanAndOrder / COLLSCAN","kind":"metric","meaning":"A proporção de consultas que varrem uma coleção inteira sem índice (COLLSCAN) ou ordenam em memória (scanAndOrder); um indicador de ineficiência de índices.","causes":"Índices ausentes ou inadequados, chaves de ordenação que não correspondem à consulta, consultas amplas sem filtro, padrões de consulta ruins.","action":"Revise as consultas lentas e seus planos (explain), adicione índices compostos que correspondam aos padrões de consulta e ordenação, corrija as consultas que produzem COLLSCAN e scanAndOrder e monitore a proporção de documentos examinados/retornados.","tags":["metric","index","collscan","query"]},{"name":"queued operations","kind":"metric","meaning":"O número de operações de leitura e escrita na fila (ainda sem poder executar ativamente) porque aguardam um lock ou recurso; mostra que o sistema não consegue atender a demanda.","causes":"Contenção de locks, esgotamento de tickets, gargalo de I/O, consultas de longa duração, picos repentinos de carga, discos lentos.","action":"Se a fila crescer, inspecione e otimize as operações ativas e de longa duração (currentOp), melhore os índices e o I/O, equilibre a carga e encontre a causa raiz junto com as métricas de tickets e de contenção de locks.","tags":["metric","queue","concurrency","load"]}]},"reference/waits-redis.json":{"engineId":"redis","engine":"Redis","order":6,"waits":[{"name":"keyspace hit ratio","kind":"metric","meaning":"A proporção de buscas de chaves encontradas em memória, calculada a partir de keyspace_hits e keyspace_misses; mostra a eficácia do Redis como cache.","causes":"Uma proporção baixa indica eviction por memória insuficiente, TTLs curtos, cache frio, muitas buscas por chaves únicas que nunca foram cacheadas ou um design de chaves ruim.","action":"Monitore o hit ratio como hits/(hits+misses); se estiver baixo, revise a memória/política de eviction e os TTLs, pré-aqueça os dados acessados com frequência e melhore o design de chaves e a estratégia de cache.","tags":["metric","cache","hit-ratio","keyspace"]},{"name":"evicted_keys","kind":"metric","meaning":"O número de chaves removidas (excluídas) da memória pela política de eviction quando o limite de maxmemory é atingido; um indicador direto de pressão de memória.","causes":"Ultrapassagem do limite de maxmemory, memória insuficiente, acúmulo de chaves sem TTL, volume de dados maior que a memória, política de eviction inadequada.","action":"Com eviction em aumento constante, adicione memória ou reduza o volume de dados, escolha a maxmemory-policy (ex.: allkeys-lru/volatile-lru) adequada à carga de trabalho e revise o uso de TTL e as big keys.","tags":["metric","memory","eviction","maxmemory"]},{"name":"blocked_clients","kind":"metric","meaning":"O número de clientes aguardando um evento/dado com comandos bloqueantes como BLPOP, BRPOP, WAIT e XREAD BLOCK; normal em padrões de consumidores de fila, mas um aumento anormal é um sinal de alerta.","causes":"Consumidores usando comandos bloqueantes de list/stream, nenhum dado chegando do lado produtor, espera por confirmação de réplicas com WAIT, desequilíbrio entre consumidores e produtores.","action":"Compare o número de clientes bloqueados com o modelo de consumidores esperado; em caso de aumento anormal, investigue o lado produtor e as confirmações de replicação e equilibre a taxa de consumo da fila.","tags":["metric","clients","blocking","queue"]},{"name":"mem_fragmentation_ratio","kind":"metric","meaning":"A proporção entre a memória física que o sistema operacional alocou ao Redis (RSS) e a memória que o Redis realmente usa; mostra fragmentação de memória ou swapping.","causes":"Valores claramente acima de 1 indicam fragmentação de memória, enquanto valores abaixo de 1 indicam que o Redis foi para o swap (disco). Chaves de tamanho variável e ciclos de delete/insert aumentam a fragmentação.","action":"Com fragmentação alta, considere habilitar activedefrag ou reiniciar; se estiver abaixo de 1, investigue o swapping e adicione memória; revise o comportamento do allocator (jemalloc) e os padrões de big keys.","tags":["metric","memory","fragmentation","swap"]},{"name":"instantaneous_ops_per_sec","kind":"metric","meaning":"O número de comandos que o Redis está processando por segundo neste momento (throughput instantâneo); mostra a intensidade da carga de trabalho e mudanças repentinas de tráfego.","causes":"Picos repentinos de tráfego, carga de jobs em lote, padrões de acesso ineficientes dos clientes, não uso de pipelining em vez de comandos individuais, rajadas intensas de leitura/escrita.","action":"Monitore o throughput junto com a latência e a CPU, correlacione quedas/picos repentinos com o tráfego e os comandos lentos, melhore a eficiência com pipelining/lotes e planeje a capacidade.","tags":["metric","throughput","ops","load"]},{"name":"rdb_last_bgsave_status","kind":"metric","meaning":"O status de sucesso do último salvamento RDB em segundo plano (BGSAVE); mostra se o snapshot de persistência foi feito com sucesso.","causes":"Um status de falha (err) pode ser causado por disco cheio/espaço insuficiente, memória insuficiente para o fork, erro de I/O de disco, problemas de permissão ou carga excessiva.","action":"Se o status for 'err', verifique o espaço em disco, a memória necessária para o fork (configuração de overcommit) e a saúde do disco e revise os logs; um BGSAVE com falha gera risco de perda de dados, então revise a configuração de persistência.","tags":["metric","persistence","rdb","bgsave"]},{"name":"master_link_status","kind":"metric","meaning":"O status (up/down) do link de replicação de uma réplica com o master; mostra se a conexão entre a réplica e o master está saudável.","causes":"Um status 'down' pode resultar de queda de rede, master inalcançável, erro de sincronização da replicação, problema de autenticação ou sobrecarga do master.","action":"Se o status for 'down', verifique a conectividade de rede, a alcançabilidade do master e as configurações de auth, revise os logs da réplica, monitore o atraso de master_repl_offset e verifique se a sincronização foi concluída.","tags":["metric","replication","master-link","availability"]},{"name":"latência (slowlog)","kind":"metric","meaning":"A latência de comandos lentos que excedem um limite definido, detectada via slowlog e latency monitoring; no Redis single-threaded mostra o risco de um comando bloquear os demais.","causes":"Comandos de alta complexidade de tempo (KEYS, SORT grande, SMEMBERS/HGETALL em coleções grandes), big keys, scripts Lua lentos, pausas de fork/persistência, swapping.","action":"Encontre os comandos lentos com os comandos SLOWLOG e LATENCY, elimine comandos O(N) (SCAN em vez de KEYS) e big keys, otimize os scripts e monitore as pausas causadas por fork/AOF/RDB.","tags":["metric","latency","slowlog","performance"]},{"name":"expired_keys","kind":"metric","meaning":"O número total de chaves excluídas porque seu TTL expirou; um indicador do comportamento de expiração baseada em TTL e da recuperação de memória.","causes":"Chaves com TTL expirando é normal. Mudanças repentinas podem indicar alteração na política de TTL, expiração em massa de chaves ou padrões de exclusão inesperados.","action":"Diferencie expired de evicted (expired é o comportamento saudável de TTL, evicted é pressão de memória), monitore o impacto de ondas repentinas de expiração nos cache misses e na carga e distribua melhor os TTLs.","tags":["metric","ttl","expiration","keyspace"]},{"name":"connected_clients vs maxclients","kind":"metric","meaning":"O quanto o número atual de clientes conectados está próximo do limite de maxclients configurado; mostra o risco de esgotar a capacidade de conexões.","causes":"Vazamentos de conexão, pool de conexões mal configurado, aumento repentino de clientes, conexões ociosas mantidas por muito tempo, muitas conexões de microsserviços.","action":"Compare os clientes conectados com maxclients; ao se aproximar do limite, dimensione corretamente o pool de conexões, corrija vazamentos de conexão, defina um timeout para conexões ociosas e aumente maxclients se necessário.","tags":["metric","connections","maxclients","capacity"]}]},"reference/waits-elasticsearch.json":{"engineId":"elasticsearch","engine":"Elasticsearch","order":7,"waits":[{"name":"JVM heap used %","kind":"metric","meaning":"O percentual do heap da JVM de um nó em uso; um heap alto e constantemente cheio significa pressão de memória e risco de GC pesado.","causes":"Memória excessiva de fielddata/agregações, shards demais, carga intensa de bulk/consultas, mappings grandes, heap subdimensionado, padrões de vazamento de memória.","action":"Monitore o uso do heap (intervenha especialmente se permanecer acima de 75% após o GC), reduza o número de shards, limite agregações pesadas e o uso de fielddata e mantenha o heap em no máximo metade da RAM e abaixo de 32GB.","tags":["metric","jvm","heap","memory"]},{"name":"duração/frequência do GC","kind":"metric","meaning":"A duração e a frequência do garbage collection da JVM; pausas de GC longas/frequentes deixam o nó sem resposta e degradam o desempenho.","causes":"Alta pressão no heap, grande acúmulo na geração antiga (old gen), agregações/fielddata pesadas, heap subdimensionado, shards demais, consultas grandes de longa duração.","action":"Elimine a pressão no heap que é a causa raiz das pausas longas (especialmente old GC), otimize as consultas que consomem muita memória, reduza o número de shards; GC frequente e longo é um alerta precoce de instabilidade do nó.","tags":["metric","jvm","gc","pause"]},{"name":"thread_pool write rejected","kind":"metric","meaning":"O número de requisições de indexação rejeitadas porque a fila do thread pool de escrita (indexação/bulk) estava cheia; mostra que o nó não consegue lidar com a carga de escrita.","causes":"Taxa excessiva de bulk/indexação, I/O de disco lento, muitas requisições pequenas em vez de bulk, capacidade insuficiente do nó, pressão de refresh.","action":"Envie as requisições de indexação em bulks de tamanho adequado, limite a taxa de escrita à capacidade do nó (backoff), melhore o I/O de disco, aumente refresh_interval, escale a capacidade.","tags":["metric","thread-pool","indexing","rejection"]},{"name":"thread_pool search rejected","kind":"metric","meaning":"O número de requisições de busca rejeitadas porque a fila do thread pool de busca estava cheia; mostra que o nó não consegue lidar com a carga de consultas.","causes":"Excesso de consultas simultâneas, agregações pesadas/lentas, acesso a shards demais, consultas ineficientes, capacidade insuficiente de nós/CPU.","action":"Limite a concorrência de consultas no lado do cliente, otimize consultas e agregações pesadas, reduza o fan-out desnecessário de shards (routing/filtragem), adicione nós e aumente o número de shards réplica (as buscas também são atendidas pelos shards réplica), escale a capacidade.","tags":["metric","thread-pool","search","rejection"]},{"name":"latência de indexação/busca","kind":"metric","meaning":"A latência média das operações de indexação e busca; derivada das métricas index_time_in_millis e query_time_in_millis, reflete o tempo de resposta percebido pelos usuários.","causes":"I/O de disco lento, consultas/agregações pesadas, pausas de GC, número alto de shards, pressão de refresh/merge, recursos insuficientes.","action":"Encontre e otimize as consultas lentas com o slow log, ajuste o bulk e o refresh_interval para indexação, melhore o desempenho de disco e de heap e interprete a latência junto com as rejeições do thread pool e o GC.","tags":["metric","latency","indexing","search"]},{"name":"tempo de refresh/flush","kind":"metric","meaning":"Tempo gasto no refresh, que torna novos documentos pesquisáveis, e no flush, que persiste o translog no Lucene; mostra o overhead de indexação.","causes":"Refreshes frequentes demais (refresh_interval baixo), I/O de disco lento, indexação intensa, translog grande, muitos segmentos pequenos.","action":"Durante indexação intensa, aumente refresh_interval (ex.: 30s) ou desative-o temporariamente, melhore o I/O de disco, ajuste o tamanho do bulk, revise o comportamento de merge de segmentos.","tags":["metric","refresh","flush","indexing"]},{"name":"unassigned shards","kind":"metric","meaning":"O número de shards não atribuídos a nenhum nó; um primário não atribuído significa dados inacessíveis (saúde red), uma réplica não atribuída significa risco de durabilidade/capacidade.","causes":"Falha/saída de nó, disk watermark excedido, configuração de réplicas alta demais para o número de nós, regras/filtros de alocação, atrasos durante a recuperação de shards.","action":"Encontre o motivo com a API cluster allocation explain, recupere os nós com falha, corrija problemas de espaço em disco/watermark, revise o número de réplicas e as regras de alocação; priorize o status red.","tags":["metric","shards","allocation","cluster-health"]},{"name":"disk watermark %","kind":"metric","meaning":"Uso de disco do nó em relação aos limites low/high/flood-stage (padrão 85%/90%/95%) que afetam a alocação de shards do Elasticsearch.","causes":"Disco enchendo, crescimento de dados, storage insuficiente, distribuição desequilibrada de shards, índices antigos não sendo limpos.","action":"No low watermark, nenhum shard novo é atribuído ao nó; no high watermark, os shards são realocados para outros nós; no flood-stage, os índices ficam somente leitura. Libere espaço em disco (exclua índices antigos/use ILM), aumente o storage, equilibre a distribuição de shards e monitore os limites de watermark.","tags":["metric","disk","watermark","storage"]},{"name":"evictions do fielddata/query cache","kind":"metric","meaning":"O número de entradas removidas do fielddata cache e do consulta (filter) cache por causa de limites de memória; indica ineficiência do cache e pressão de memória.","causes":"Alto uso de fielddata (ordenação/agregações em campos text), limites de cache pequenos, filtros de consulta muito variados, pressão de memória, filtros que nunca são reutilizados.","action":"Use keyword/doc_values em vez de fielddata em campos text, limite agregações pesadas de fielddata, revise os tamanhos de cache; evictions frequentes devem ser avaliadas junto com a pressão no heap.","tags":["metric","cache","fielddata","eviction"]},{"name":"circuit breaker acionado","kind":"metric","meaning":"O número de vezes que os circuit breakers (parent/fielddata/request breaker) previram que uma requisição excederia a memória e a rejeitaram; um mecanismo de segurança que protege o nó contra OOM.","causes":"Agregações/consultas que solicitam memória excessiva, alto uso de fielddata, requisições bulk grandes, pressão geral no heap, result sets muito grandes.","action":"Trate os acionamentos de circuit breaker como sinal de pressão no heap, otimize as consultas que consomem muita memória, reduza o uso de fielddata/agregações, diminua o tamanho do bulk e revise o heap e o número de shards.","tags":["metric","circuit-breaker","memory","oom"]},{"name":"pending tasks","kind":"metric","meaning":"A fila de tarefas de atualização do cluster state aguardando processamento pelo nó master; mostra que o master não consegue acompanhar a carga de gerenciamento do cluster.","causes":"Grande número de índices/shards, alterações frequentes de mapping/settings, recursos insuficientes no nó master, cluster state grande, problemas de rede/eleição de master.","action":"Se a fila estiver constantemente cheia, reduza o número de shards/índices, limite atualizações frequentes de dynamic mapping, use nós master dedicados separados e revise o tamanho do cluster state e os recursos do master.","tags":["metric","master","cluster-state","queue"]}]},"reference/alerts-oracle.json":{"engineId":"oracle","engine":"Oracle Database","order":1,"alerts":[{"metric":"Taxa de acerto do buffer cache","warn":"< 95%","crit":"< 90%","tool":"V$SYSSTAT / V$BUFFER_POOL_STATISTICS","note":"O buffer cache hit ratio mostra o percentual de blocos de dados lidos da memória sem ir ao disco. Valores baixos indicam aumento de leituras físicas e SGA subdimensionada. Isoladamente pode ser enganoso; avalie-o sempre junto com as leituras físicas no relatório AWR.","tags":["memory","cache","sga"]},{"metric":"Uso de tablespace (%used)","warn":"> 85%","crit":"> 95%","tool":"DBA_TABLESPACE_USAGE_METRICS","note":"Se o uso do tablespace chegar a 100%, nenhum extent novo pode ser alocado e as operações param com erros como ORA-01653. Mesmo com autoextend habilitado, observe o limite do disco. A view DBA_TABLESPACE_USAGE_METRICS fornece o percentual correto tanto para arquivos autoextensíveis quanto de tamanho fixo.","tags":["disk","tablespace","capacity"]},{"metric":"Uso de memória PGA","warn":"> 90% pga_aggregate_target","crit":"> 100% (over-alloc)","tool":"V$PGASTAT / V$PGA_TARGET_ADVICE","note":"Quando o alvo da PGA é excedido, as operações de sort e hash transbordam para o disco (temp) e as consultas ficam lentas. Um over allocation count em aumento constante mostra que o alvo é insuficiente. Revise a configuração de pga_aggregate_target em relação à memória do servidor.","tags":["memory","pga","temp"]},{"metric":"Uso do tablespace TEMP","warn":"> 80%","crit":"> 95%","tool":"V$TEMPSEG_USAGE / V$SORT_SEGMENT / DBA_TEMP_FREE_SPACE","note":"O espaço TEMP é usado para sorts grandes, hash joins e operações com global temporary tables. Quando ele enche, ocorre ORA-01652 e as consultas falham. Enchimentos repentinos geralmente vêm de uma única consulta com plano ruim ou que ordena dados demais.","tags":["temp","disk","sort"]},{"metric":"Average Active Sessions (AAS)","warn":"> número de núcleos de CPU","crit":"> 2x o número de núcleos de CPU","tool":"V$ACTIVE_SESSION_HISTORY / OEM","note":"O Average Active Sessions resume a carga atual do banco de dados em um único número. Se o valor exceder o número de núcleos de CPU, as sessões estão na fila por CPU ou por wait events. Se permanecer em um múltiplo do número de núcleos, é necessária uma análise de gargalos.","tags":["cpu","load","session"]},{"metric":"Apply lag do Data Guard","warn":"> 60 s","crit":"> 300 s","tool":"V$DATAGUARD_STATS (apply lag)","note":"Apply lag é o quanto o banco de dados standby está atrás do primário. Um apply lag alto aumenta a quantidade de redo a aplicar durante o failover e, portanto, prolonga o tempo de recuperação (RTO); se o redo já chegou ao standby, nenhum dado é perdido. A perda potencial de dados (RPO) é determinada pelo transport lag. Revise-o junto com o transport lag para determinar se a lentidão está na rede ou na aplicação do redo.","tags":["replication","dataguard","lag"]},{"metric":"Uso da Fast Recovery Area (FRA)","warn":"> 85%","crit":"> 95%","tool":"V$RECOVERY_FILE_DEST / V$RECOVERY_AREA_USAGE","note":"Quando a FRA enche, a geração de archivelogs para e todo o banco de dados trava. É uma das causas mais comuns de indisponibilidade em sistemas de produção. Verifique regularmente as políticas de exclusão do RMAN e o valor de db_recovery_file_dest_size.","tags":["disk","fra","archivelog"]},{"metric":"Número de sessões bloqueadoras","warn":">= 1 (> 30 s)","crit":">= 1 (> 120 s)","tool":"V$LOCK / V$SESSION (blocking_session)","note":"Quando um lock mantido por uma sessão faz outras sessões aguardarem, ocorre uma lentidão em cascata em toda a aplicação. Bloqueios duradouros geralmente vêm de transações não confirmadas ou de bugs da aplicação. Encontre a sessão raiz da cadeia de bloqueio e encerre-a se necessário.","tags":["lock","blocking","concurrency"]},{"metric":"Número de objetos inválidos","warn":"> 0","crit":"> 50","tool":"DBA_OBJECTS (status='INVALID')","note":"Packages, views ou triggers inválidos podem causar erros inesperados em tempo de execução. Geralmente aparecem após uma alteração de DDL. Resolva-os recompilando com UTL_RECOMP.RECOMP_PARALLEL ou utlrp.sql e investigue a causa raiz de objetos que permanecem inválidos.","tags":["object","compile","maintenance"]},{"metric":"Consulta de execução mais longa","warn":"> 5 min","crit":"> 30 min","tool":"V$SQL / V$SESSION_LONGOPS","note":"Uma única consulta de longa duração pode monopolizar recursos e deixar outras operações lentas também. Exceto em jobs em lote, consultas que rodam por minutos em sistemas OLTP geralmente vêm de um índice ausente ou de um plano ruim. Examine o plano e as contagens reais de linhas com um relatório do SQL Monitor.","tags":["query","performance","sql"]},{"metric":"Erros ORA no alert log","warn":">= 1 (não crítico)","crit":"ORA-00600 / ORA-07445 / ORA-04031","tool":"alert log / V$DIAG_ALERT_EXT","note":"O alert log é o diário de saúde do banco de dados. ORA-00600 e ORA-07445 são erros internos que podem indicar corrupção de dados, enquanto ORA-04031 indica esgotamento de memória do shared pool. Se esses erros aparecerem, investigue-os imediatamente e compartilhe-os com o Oracle Support se necessário.","tags":["error","alertlog","monitoring"]},{"metric":"Frequência de log switch do redo","warn":"> 6 / hora","crit":"> 12 / hora","tool":"V$LOG_HISTORY","note":"Log switches de redo muito frequentes indicam arquivos de log subdimensionados e pressão de checkpoint. Idealmente, espera-se um switch a cada 15-20 minutos nos horários de pico. Switches excessivamente frequentes aumentam a carga de IO e de arquivamento; considere aumentar os grupos de redo log.","tags":["redo","io","checkpoint"]},{"metric":"Idade do último backup RMAN bem-sucedido","warn":"> 24 horas","crit":"> 48 horas","tool":"V$RMAN_BACKUP_JOB_DETAILS","note":"A idade do backup determina o ponto mais recente para o qual você pode recuperar e reflete diretamente o risco de perda de dados. Se backups com falha ou ignorados passarem despercebidos, não há volta em um desastre. Monitore também os backups de archivelog separadamente para garantir a capacidade de point-in-time recovery.","tags":["backup","rman","recovery"]},{"metric":"Latência de IO de disco (db file sequential read)","warn":"> 10 ms","crit":"> 20 ms","tool":"V$SYSTEM_EVENT / AWR","note":"O tempo médio de espera das leituras de bloco único mostra o desempenho da camada de storage. Em sistemas modernos flash/SSD esse valor deve ser de poucos milissegundos. Latência constantemente alta indica gargalo de storage ou leituras físicas excessivas; avalie a SGA e a camada de storage em conjunto.","tags":["io","disk","latency"]}]},"reference/alerts-postgres.json":{"engineId":"postgres","engine":"PostgreSQL","order":2,"alerts":[{"metric":"Cache hit ratio","warn":"< 99%","crit":"< 95%","tool":"pg_stat_database / postgres_exporter","note":"O cache hit ratio é o percentual de blocos atendidos apenas pelos shared_buffers; leituras atendidas pelo cache do sistema operacional também são contadas como blks_read, então a proporção pode fazer as leituras reais de disco parecerem piores do que são. Em sistemas PostgreSQL OLTP saudáveis essa proporção deve ficar acima de 99%. Valores baixos indicam memória insuficiente ou cache frio; é calculada a partir de blks_hit e blks_read.","tags":["memory","cache"]},{"metric":"Número de conexões (connections vs max_connections)","warn":"> 80%","crit":"> 90%","tool":"pg_stat_activity / max_connections","note":"Conexões ativas se aproximando do limite de max_connections levam a falhas em novas conexões. Como cada conexão consome memória, um número alto também gera pressão de memória. Recomenda-se manter baixo o número de backends com um pooler de conexões como o PgBouncer.","tags":["connection","limit","pool"]},{"metric":"Replication lag","warn":"> 10 MB","crit":"> 100 MB","tool":"pg_stat_replication (replay_lag / lsn diff)","note":"Replication lag é a quantidade de WAL, em bytes, pela qual o standby está atrás do primário. Um atraso alto significa dados desatualizados nas réplicas de leitura e risco de perda de dados no failover. Monitore a diferença de LSN em bytes junto com a duração de replay_lag.","tags":["replication","lag","standby"]},{"metric":"Idade da transação mais antiga","warn":"> 5 min","crit":"> 30 min","tool":"pg_stat_activity (xact_start)","note":"Transações abertas de longa duração impedem que o VACUUM remova dead tuples e levam a bloat de tabelas. Sessões no estado 'idle in transaction' também mantêm locks desnecessariamente. Identifique essas sessões e limite-as com idle_in_transaction_session_timeout.","tags":["query","vacuum","transaction"]},{"metric":"Deadlocks","warn":"> 1 / min","crit":"> 5 / min","tool":"pg_stat_database (deadlocks)","note":"Um deadlock ocorre quando duas transações aguardam os locks uma da outra, e o PostgreSQL o resolve cancelando uma delas. Deadlocks ocasionais podem acontecer, mas frequentes indicam ordem de locks inconsistente na aplicação. Habilite log_lock_waits para ver quais consultas entram em conflito.","tags":["lock","deadlock","concurrency"]},{"metric":"Uso de arquivos temporários","warn":"> 1 GB / hora","crit":"> 10 GB / hora","tool":"pg_stat_database (temp_bytes)","note":"Arquivos temporários são criados quando operações de sort e hash que não cabem em work_mem transbordam para o disco. Um uso alto de temp causa lentidão e pressão no disco. Para consultas que transbordam com frequência, considere aumentar work_mem ou otimizar a consulta.","tags":["temp","disk","work_mem"]},{"metric":"Atraso do autovacuum (dead tuples)","warn":"> 10% de dead tuples","crit":"> 20% de dead tuples","tool":"pg_stat_user_tables (n_dead_tup)","note":"Uma proporção crescente de dead tuples mostra que o autovacuum não está conseguindo acompanhar e que o bloat das tabelas está aumentando. Tabelas com bloat ocupam espaço e deixam os scans mais lentos. Em tabelas muito movimentadas, reduza autovacuum_vacuum_scale_factor para que a limpeza seja executada com mais frequência.","tags":["vacuum","bloat","maintenance"]},{"metric":"Uso de disco (diretório de dados)","warn":"> 85%","crit":"> 95%","tool":"df / node_exporter","note":"O PostgreSQL não oferece mecanismo de autoproteção antes que o disco encha. Quando o disco de dados enche, as escritas falham com 'could not extend file' / 53100; se o disco do WAL (pg_wal) encher, o servidor é desligado com PANIC. O WAL e os arquivos temporários podem causar crescimento repentino; a intervenção precoce é crítica.","tags":["disk","capacity"]},{"metric":"Retenção de WAL (lag do replication slot)","warn":"> 1 GB","crit":"> 10 GB","tool":"pg_replication_slots (restart_lsn)","note":"Um replication slot não utilizado ou atrasado impede a remoção de arquivos de WAL e incha o diretório pg_wal. Isso pode terminar com disco cheio. Identifique e remova os slots mortos e defina um limite superior com max_slot_wal_keep_size.","tags":["wal","slot","disk"]},{"metric":"Frequência de checkpoints (checkpoints solicitados)","warn":"> 10% de checkpoints solicitados","crit":"> 30% de checkpoints solicitados","tool":"PG16 e anteriores: pg_stat_bgwriter (checkpoints_req) / PG17+: pg_stat_checkpointer (num_requested)","note":"Quando a proporção de checkpoints solicitados em relação aos programados aumenta, max_wal_size está pequeno demais. Checkpoints frequentes causam picos de IO e degradação de desempenho. Revise as configurações de max_wal_size e checkpoint_completion_target para distribuir a carga.","tags":["checkpoint","wal","io"]},{"metric":"Idade do último backup bem-sucedido","warn":"> 24 horas","crit":"> 48 horas","tool":"pgBackRest / barman info","note":"A idade do backup determina o ponto mais recente para o qual você pode voltar e expressa diretamente o seu RPO. Uma cadeia de backups ininterrupta e o arquivamento de WAL são necessários para point-in-time recovery. Não basta fazer backups; sua validade também deve ser verificada com testes de restore regulares.","tags":["backup","recovery","rpo"]},{"metric":"Latência de IO de disco","warn":"> 10 ms","crit":"> 20 ms","tool":"node_exporter / iostat","note":"A latência de leitura/escrita do storage afeta diretamente os tempos das consultas. Em sistemas SSD modernos esse valor deve ser de poucos milissegundos. Latência alta sustentada indica gargalo de disco ou leituras físicas excessivas; avalie shared_buffers e a camada de storage em conjunto.","tags":["io","disk","latency"]},{"metric":"Transaction ID wraparound (age)","warn":"> 1 bilhão","crit":"> 1,5 bilhão","tool":"pg_database (age(datfrozenxid))","note":"Se a idade do transaction ID se aproximar de 2 bilhões, o PostgreSQL interrompe todas as escritas para evitar perda de dados (proteção contra wraparound). É uma das falhas mais perigosas do PostgreSQL. Monitore a idade de datfrozenxid e garanta que o autovacuum não esteja atrasado no trabalho de freeze.","tags":["wraparound","vacuum","critical"]}]},"reference/alerts-mysql.json":{"engineId":"mysql","engine":"MySQL","order":3,"alerts":[{"metric":"Taxa de acerto do InnoDB buffer pool","warn":"< 99%","crit":"< 95%","tool":"SHOW ENGINE INNODB STATUS / mysqld_exporter","note":"O buffer pool hit ratio é o percentual de páginas de dados e de índice lidas da memória sem ir ao disco. Valores baixos indicam que innodb_buffer_pool_size é pequeno demais para o working set. Em um servidor dedicado, normalmente ~70-80% da memória é alocada ao buffer pool (menos em um servidor compartilhado).","tags":["memory","cache","innodb"]},{"metric":"Número de conexões (Threads_connected vs max_connections)","warn":"> 80%","crit":"> 90%","tool":"SHOW STATUS / max_connections","note":"À medida que o número de conexões se aproxima do limite de max_connections, novas conexões são rejeitadas com 'Too many connections'. Max_used_connections mostra o pico histórico. Mantenha as conexões simultâneas sob controle com um pool de conexões no lado da aplicação.","tags":["connections","limit","thread"]},{"metric":"Lag da réplica (Seconds_Behind_Source)","warn":"> 30 s","crit":"> 300 s","tool":"SHOW REPLICA STATUS","note":"Seconds_Behind_Source informa, em segundos, o quanto a réplica está atrás da origem. Um atraso alto significa dados desatualizados nas réplicas de leitura e risco no failover. Com aplicação single-threaded, o valor pode ser enganoso durante transações grandes; confirme-o junto com a diferença de GTID.","tags":["replication","lag","replica"]},{"metric":"Tempo de espera por row lock do InnoDB","warn":"média > 1 s","crit":"média > 5 s","tool":"SHOW STATUS (Innodb_row_lock_time_avg)","note":"O tempo médio de espera por row lock mostra o quanto as transações fazem umas às outras esperarem. Valores altos apontam para atualizações com muito conflito ou transações de longa duração. Revise-o junto com Innodb_row_lock_waits e encontre as consultas em conflito no performance_schema.","tags":["lock","blocking","innodb"]},{"metric":"History list length (undo)","warn":"> 100000","crit":"> 1000000","tool":"SHOW ENGINE INNODB STATUS","note":"O history list length é o número de registros de undo ainda não purgados e cresce por causa de transações abertas de longa duração. Um valor alto mostra que o purge está atrasado e que o desempenho de leitura está degradando devido ao MVCC. Encontre e encerre as transações de longa duração para que a lista possa diminuir.","tags":["undo","transaction","mvcc"]},{"metric":"Conexões com falha (Aborted_connects)","warn":"> 5 / min","crit":"> 20 / min","tool":"SHOW STATUS (Aborted_connects)","note":"Aborted_connects conta as conexões que falham durante a autenticação ou o handshake. Picos repentinos podem indicar senhas erradas, problemas de rede ou uma possível tentativa de ataque. Revise-o junto com Aborted_clients para determinar onde a conexão cai.","tags":["connections","error","security"]},{"metric":"Tabelas temporárias gravadas em disco","warn":"> 25% de proporção","crit":"> 50% de proporção","tool":"SHOW STATUS (Created_tmp_disk_tables)","note":"A proporção de tabelas temporárias em memória que transbordam para o disco mostra que as consultas excedem o limite de tmp_table_size. Tabelas temporárias em disco deixam as consultas visivelmente mais lentas. Otimize as consultas com GROUP BY e colunas BLOB/TEXT e considere aumentar tmp_table_size e max_heap_table_size.","tags":["temp","disk","query"]},{"metric":"Consultas lentas","warn":"> 5 / min","crit":"> 20 / min","tool":"slow query log / status Slow_queries","note":"Consultas que excedem o limite de long_query_time são gravadas no slow query log e são a principal fonte de problemas de desempenho. Consultas lentas frequentes apontam para índices ausentes ou consultas mal escritas. Analise o log com pt-query-digest e priorize as consultas mais caras.","tags":["query","performance","slowlog"]},{"metric":"Uso de CPU","warn":"> 80%","crit":"> 90%","tool":"node_exporter / top","note":"Uso de CPU alto e sustentado pode vir de consultas pesadas, índices ausentes ou conexões demais. Picos curtos são normais, mas a saturação sustentada causa enfileiramento de consultas. Identifique as consultas que mais consomem CPU com o performance_schema ou o slow log.","tags":["cpu","load"]},{"metric":"Uso de disco (diretório de dados)","warn":"> 85%","crit":"> 95%","tool":"df / node_exporter","note":"Um diretório de dados cheio impede o MySQL de gravar e causa erros em tabelas. O crescimento dos arquivos de binlog, dos undo tablespaces e do tablespace temporário (ibtmp1) pode encher o disco de repente; o redo log tem tamanho fixo (8.0.30+ #innodb_redo, innodb_redo_log_capacity). Garanta que os binlogs antigos sejam purgados via binlog_expire_logs_seconds.","tags":["disk","capacity","binlog"]},{"metric":"Consulta de execução mais longa","warn":"> 60 s","crit":"> 300 s","tool":"SHOW PROCESSLIST / information_schema.PROCESSLIST","note":"Uma única consulta de longa duração pode afetar outras transações mantendo locks e consumindo recursos. Em sistemas OLTP, consultas que rodam por minutos geralmente vêm de um plano ruim. Examine o plano com EXPLAIN e, se necessário, encerre a consulta e otimize-a.","tags":["query","performance"]},{"metric":"Idade do último backup bem-sucedido","warn":"> 24 horas","crit":"> 48 horas","tool":"xtrabackup / log do job mysqldump","note":"A idade do backup determina o ponto mais recente para o qual você pode voltar e, portanto, o RPO. Junto com os backups de binlog, o point-in-time recovery se torna possível. Apenas fazer backups não basta; verifique sua validade com testes de restore regulares.","tags":["backup","recovery","rpo"]},{"metric":"Latência de IO de disco","warn":"> 10 ms","crit":"> 20 ms","tool":"iostat / node_exporter","note":"A latência do storage se traduz diretamente nos tempos das consultas e é crítica especialmente para cargas que não cabem no buffer pool. Poucos milissegundos são esperados em sistemas SSD modernos. Latência alta indica gargalo de disco ou leituras físicas excessivas; revise também o tamanho do buffer pool.","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":"O Page Life Expectancy mostra, em segundos, o tempo estimado que uma página de dados pode permanecer em memória antes de ser removida do buffer pool. Valores baixos indicam pressão de memória e páginas sendo descartadas do cache rapidamente. Monitore-o separadamente por nó NUMA e trate quedas repentinas como falta de memória.","tags":["memory","cache","ple"]},{"metric":"Taxa de acerto do buffer cache","warn":"< 98%","crit":"< 95%","tool":"sys.dm_os_performance_counters","note":"O buffer cache hit ratio é o percentual de páginas lidas da memória sem ir ao disco. No SQL Server esse valor geralmente é muito alto; avalie-o junto com o PLE. Como pode ser enganoso isoladamente, use o PLE como métrica principal ao analisar um gargalo de memória.","tags":["memory","cache"]},{"metric":"Processos bloqueados","warn":">= 1 (> 5 s)","crit":">= 1 (> 30 s)","tool":"sys.dm_exec_requests (blocking_session_id)","note":"Quando um lock mantido por uma sessão faz outras aguardarem, forma-se uma cadeia de bloqueio e segue-se uma lentidão em toda a aplicação. Bloqueios duradouros geralmente vêm de transações não confirmadas ou de um nível de isolamento inadequado. Identifique o head blocker com o blocked process report.","tags":["lock","blocking","concurrency"]},{"metric":"Uso do log de transações (%used)","warn":"> 75%","crit":"> 90%","tool":"sys.dm_db_log_space_usage / DBCC SQLPERF(LOGSPACE)","note":"Quando o log de transações enche, o banco de dados não consegue gravar e para com o erro 9002. No recovery model FULL, o log continua crescendo se não forem feitos backups de log. Monitore a frequência dos backups de log e o número de VLFs para garantir que o log esteja sendo truncado e reutilizado.","tags":["log","disk","recovery"]},{"metric":"Uso do tempdb (%used)","warn":"> 80%","crit":"> 95%","tool":"sys.dm_db_file_space_usage","note":"O tempdb é compartilhado por tabelas temporárias, sorts, version store e operações de hash. Quando ele enche, as consultas de todo o servidor falham. Crescimentos repentinos geralmente vêm de uma consulta grande ou de uma transação snapshot de longa duração; monitore o tamanho do version store separadamente.","tags":["tempdb","disk","sort"]},{"metric":"Consulta de execução mais longa","warn":"> 60 s","crit":"> 300 s","tool":"sys.dm_exec_requests / Query Store","note":"Uma única consulta de longa duração pode afetar outros trabalhos mantendo locks e consumindo recursos. Em sistemas OLTP, consultas que rodam por minutos geralmente vêm de um índice ausente, parameter sniffing ou um plano ruim. Investigue regressões de plano com o Query Store.","tags":["query","performance"]},{"metric":"Redo queue do Availability Group","warn":"> 1 MB","crit":"> 100 MB","tool":"sys.dm_hadr_database_replica_states","note":"A redo queue mostra a quantidade de log na réplica secundária ainda aguardando para ser aplicada. Uma redo queue alta prolonga o tempo de recuperação após o failover (RTO) e significa dados desatualizados nas réplicas legíveis. Examine-a junto com redo_rate para prever quando o atraso será eliminado.","tags":["replication","ag","lag"]},{"metric":"Taxa de deadlocks","warn":"> 1 / min","crit":"> 5 / min","tool":"system_health XEvent / Performance counters","note":"Um deadlock ocorre quando duas transações aguardam os locks uma da outra, e o SQL Server o resolve escolhendo uma como vítima. Deadlocks ocasionais podem acontecer, mas frequentes indicam ordem de locks inconsistente. Extraia o deadlock graph da sessão de extended events system_health e corrija as consultas em conflito.","tags":["lock","deadlock","concurrency"]},{"metric":"Uso de worker threads","warn":"> 80%","crit":"> 90%","tool":"sys.dm_os_schedulers / max worker threads","note":"Quando o pool de worker threads se esgota, novas requisições entram na fila com a espera THREADPOOL e o servidor pode parar de responder. Bloqueios de longa duração ou conexões simultâneas excessivas geralmente causam isso. Reduza a pressão sobre as threads resolvendo as cadeias de bloqueio.","tags":["cpu","thread","load"]},{"metric":"Uso de CPU","warn":"> 80%","crit":"> 90%","tool":"sys.dm_os_ring_buffers / Performance Monitor","note":"CPU alta e sustentada pode vir de consultas pesadas, índices ausentes ou planos ruins. Picos curtos são normais, mas a saturação sustentada causa enfileiramento de consultas. Identifique as consultas que mais consomem CPU com sys.dm_exec_query_stats.","tags":["cpu","load"]},{"metric":"Idade do último backup bem-sucedido","warn":"> 24 horas (full)","crit":"> 48 horas (full)","tool":"msdb.dbo.backupset","note":"A idade do backup determina o ponto mais recente para o qual você pode voltar e o seu RPO. No recovery model FULL, o point-in-time recovery é possível com backups de log. Monitore a cadeia de backups full, diferenciais e de log para garantir a recuperabilidade e execute testes de restore regulares.","tags":["backup","recovery","rpo"]},{"metric":"Latência de IO de disco (média de leitura/escrita)","warn":"> 15 ms","crit":"> 30 ms","tool":"sys.dm_io_virtual_file_stats","note":"A latência média de leitura/escrita por arquivo mostra o desempenho do storage. Cerca de 15 ms é esperado para arquivos de dados, e valores menores para arquivos de log. Latência alta sustentada indica gargalo de storage; identifique os arquivos mais lentos com sys.dm_io_virtual_file_stats.","tags":["io","disk","latency"]}]},"reference/alerts-mongodb.json":{"engineId":"mongodb","engine":"MongoDB","order":5,"alerts":[{"metric":"Proporção de dirty no cache do WiredTiger","warn":"> 5%","crit":"> 20%","tool":"db.serverStatus().wiredTiger.cache","note":"A proporção de dirty cache é o percentual de páginas modificadas no cache do WiredTiger que ainda não foram gravadas em disco. Ultrapassar 20% significa pressão de eviction e gargalo de escrita; o MongoDB obriga as threads da aplicação a fazer eviction. Avalie o tamanho do cache e o throughput de escrita em disco em conjunto.","tags":["memory","cache","wiredtiger"]},{"metric":"Uso do cache do WiredTiger (used %)","warn":"> 80%","crit":"> 95%","tool":"db.serverStatus().wiredTiger.cache","note":"Quando o uso do cache excede a meta de eviction de 80%, o WiredTiger começa a remover páginas agressivamente e o desempenho cai. Se o working set não couber no cache, as leituras físicas aumentam. Revise a configuração de wiredTigerCacheSizeGB e a memória do servidor.","tags":["memory","cache","wiredtiger"]},{"metric":"Tickets disponíveis (read/write tickets)","warn":"available/totalTickets < 20% ou queueLength > 0 (sustentado)","crit":"available = 0 e queueLength continua crescendo","tool":"db.serverStatus().wiredTiger.concurrentTransactions","note":"O WiredTiger limita as operações simultâneas de leitura e escrita com um sistema de tickets. Antes do 7.0 o padrão era fixo em 128 tickets; no 7.0+ o número de tickets é ajustado dinamicamente (storageEngineConcurrencyAdjustmentAlgorithm: throughputProbing), então monitore a proporção available/totalTickets e o queueLength em vez do número absoluto. Tickets se esgotando e operações entrando na fila é sinal de um gargalo sério; geralmente é causado por consultas lentas ou saturação de I/O de disco.","tags":["concurrency","ticket","bottleneck"]},{"metric":"Replication lag","warn":"> 10 s","crit":"> 60 s","tool":"rs.printSecondaryReplicationInfo()","note":"O replication lag informa, em segundos, o quanto um membro secundário está atrás do primário. Um atraso alto significa dados desatualizados, dependendo da read preference, e risco de perda de dados no failover. Geralmente é causado por gargalos de I/O de disco ou de rede no secundário, ou por operações de longa duração.","tags":["replication","lag","replicaset"]},{"metric":"Uso de conexões (connections %)","warn":"> 80%","crit":"> 90%","tool":"db.serverStatus().connections","note":"Conexões ativas se aproximando do limite superior configurado fazem com que novas conexões sejam rejeitadas. Como cada conexão consome memória e uma thread, um número alto também gera pressão de recursos. Evite tempestades de conexões dimensionando corretamente o pool de conexões no lado da aplicação.","tags":["connection","limit","pool"]},{"metric":"Taxa de page faults","warn":"> 100 / s","crit":"> 1000 / s","tool":"db.serverStatus() / extra_info page_faults","note":"Um page fault ocorre quando os dados não estão em memória e precisam ser buscados no disco. Uma taxa alta de faults mostra que o working set não cabe na memória e que o sistema está limitado pelo disco. Valores altos sustentados exigem aumento de memória ou otimização de consultas/índices.","tags":["memory","disk","pagefault"]},{"metric":"Operações na fila","warn":"> 10","crit":"> 50","tool":"db.serverStatus().globalLock.currentQueue","note":"O globalLock currentQueue mostra o número de leituras/escritas na fila aguardando um lock ou recurso. Uma fila constantemente cheia indica que o servidor não consegue acompanhar a carga recebida. Examine-a junto com o esgotamento de tickets e o I/O de disco para determinar a origem do gargalo.","tags":["concurrency","queue","lock"]},{"metric":"Oplog window","warn":"< 24 horas","crit":"< 6 horas","tool":"rs.printReplicationInfo()","note":"A oplog window é o intervalo de tempo coberto pelo oplog e determina por quanto tempo um secundário pode ficar desconectado e ainda ressincronizar. Se a janela diminuir, um membro que fique atrasado exigirá um resync completo. A janela encurta à medida que a carga de escrita aumenta; aumente o tamanho do oplog de acordo.","tags":["oplog","replication","recovery"]},{"metric":"Consulta de execução mais longa","warn":"> 30 s","crit":"> 120 s","tool":"db.currentOp() / slow query log","note":"Consultas de longa duração afetam outras operações consumindo recursos e mantendo locks. Geralmente vêm de consultas que fazem collection scan (COLLSCAN) por causa de um índice ausente. Encontre as operações lentas com o profiler e o currentOp e adicione índices adequados.","tags":["query","performance","index"]},{"metric":"Uso de CPU","warn":"> 80%","crit":"> 90%","tool":"node_exporter / mongostat","note":"CPU alta e sustentada pode vir de consultas sem índice, operações de agregação pesadas ou conexões excessivas. Picos curtos são normais, mas a saturação sustentada faz as operações entrarem na fila. Use o profiler para identificar as consultas que mais consomem CPU e otimize-as.","tags":["cpu","load"]},{"metric":"Uso de disco (dbPath)","warn":"> 85%","crit":"> 95%","tool":"df / node_exporter","note":"Um diretório de dados cheio deixa o MongoDB sem conseguir gravar e pode levar a corrupção. Embora a compressão do WiredTiger ajude, o journal e as coleções em crescimento podem encher o disco rapidamente. Faça planejamento de capacidade e remova automaticamente os dados desnecessários com índices TTL.","tags":["disk","capacity"]},{"metric":"Idade do último backup bem-sucedido","warn":"> 24 horas","crit":"> 48 horas","tool":"mongodump / Ops Manager / registro de snapshot","note":"A idade do backup determina o ponto mais recente para o qual você pode voltar e o seu RPO. Combinado com o oplog, o point-in-time recovery se torna possível. Fazer backups não basta; valide-os com testes de restore regulares e garanta que snapshots consistentes sejam feitos em clusters shardados.","tags":["backup","recovery","rpo"]}]},"reference/alerts-redis.json":{"engineId":"redis","engine":"Redis","order":6,"alerts":[{"metric":"Uso de memória (used_memory vs maxmemory)","warn":"> 80%","crit":"> 95%","tool":"INFO memory / redis_exporter","note":"A proporção entre used_memory e maxmemory mostra quanto da memória do Redis está em uso. Quando o limite é atingido, as chaves são removidas ou as escritas são rejeitadas de acordo com a maxmemory-policy. Acompanhe o crescimento da memória para evitar OOM inesperado e ondas de eviction.","tags":["memory","maxmemory","capacity"]},{"metric":"Keyspace hit ratio","warn":"< 90%","crit":"< 80%","tool":"INFO stats (keyspace_hits/misses)","note":"O hit ratio é o percentual de chaves solicitadas encontradas no cache e é calculado a partir de keyspace_hits e keyspace_misses. Uma proporção baixa aponta para uso ineficaz do cache, TTLs errados ou cache frio. Para cargas de cache essa proporção deve ser a mais alta possível.","tags":["cache","hit","performance"]},{"metric":"Chaves removidas por eviction (evicted_keys)","warn":"> 1 / s","crit":"> 100 / s","tool":"INFO stats (evicted_keys)","note":"evicted_keys é o número de chaves removidas pela maxmemory-policy porque a memória está cheia. Eviction contínua mostra que a memória é insuficiente e que dados importantes podem ser perdidos. Reduza a eviction aumentando a memória ou revendo a estratégia de TTL ou o modelo de dados.","tags":["memory","eviction","maxmemory"]},{"metric":"Clientes bloqueados (blocked_clients)","warn":"> 50","crit":"> 200","tool":"INFO clients (blocked_clients)","note":"blocked_clients é o número de clientes aguardando em comandos bloqueantes como BLPOP/BRPOP/WAIT. Valores acima do esperado apontam para consumidores que não estão acompanhando ou para um backlog crescente na fila. Em cargas baseadas em filas, verifique o equilíbrio entre produtores e consumidores.","tags":["client","blocking","queue"]},{"metric":"Proporção de fragmentação de memória (mem_fragmentation_ratio)","warn":"> 1.5","crit":"> 2.0","tool":"INFO memory","note":"A proporção de fragmentação é a memória obtida do sistema operacional dividida pela memória usada pelo Redis. Acima de 1.5 indica fragmentação excessiva; abaixo de 1.0 indica memória transbordando para o swap, o que é muito perigoso. Você pode reduzir a fragmentação habilitando activedefrag ou reiniciando.","tags":["memory","fragmentation"]},{"metric":"Status do link com o master (master_link_status)","warn":"down (< 10 s)","crit":"down (> 30 s)","tool":"INFO replication (master_link_status)","note":"master_link_status mostra o estado (up/down) da conexão da réplica com o master. 'down' significa que a replicação está quebrada e a réplica está servindo dados desatualizados. Desconexões longas exigem um resync completo; verifique a rede e a saúde do master imediatamente.","tags":["replication","master","connection"]},{"metric":"Replication lag (diferença de master_repl_offset)","warn":"> 1 MB","crit":"> 10 MB","tool":"INFO replication (offset diff)","note":"A diferença entre os offsets do master e da réplica mostra, em bytes, o quanto a réplica está atrasada. Uma diferença grande significa risco de perda de dados no failover e inconsistência nas réplicas de leitura. Examine a latência de rede e a carga da réplica para garantir que a diferença diminua.","tags":["replication","lag","offset"]},{"metric":"Status do último bgsave RDB (rdb_last_bgsave_status)","warn":"err (última tentativa)","crit":"err (> 24 horas)","tool":"INFO persistence","note":"rdb_last_bgsave_status mostra se o último snapshot em segundo plano foi bem-sucedido (ok). Um bgsave com falha significa que a persistência não está funcionando e há risco de perda de dados na reinicialização. Geralmente vem de disco cheio ou memória insuficiente para o fork.","tags":["backup","persistence","rdb"]},{"metric":"Uso de conexões (connected_clients)","warn":"> 80% maxclients","crit":"> 90% maxclients","tool":"INFO clients / maxclients","note":"connected_clients se aproximando do limite de maxclients faz com que novas conexões sejam rejeitadas. Vazamentos de conexão ou um pool mal configurado podem causar picos repentinos. Configure corretamente o pool de conexões no lado da aplicação e feche as conexões ociosas.","tags":["connection","limit","client"]},{"metric":"Latência instantânea de comandos","warn":"> 1 ms","crit":"> 10 ms","tool":"redis-cli --latency / LATENCY DOCTOR","note":"Como o Redis é single-threaded, a latência dos comandos geralmente fica na faixa de microssegundos. Latência crescente pode vir de comandos lentos (KEYS, SORT grande), bloqueio durante o fork ou uso de swap. Encontre a origem com o slowlog e os comandos LATENCY.","tags":["latency","performance","slowlog"]},{"metric":"Uso de CPU","warn":"> 80% (núcleo único)","crit":"> 90% (núcleo único)","tool":"top / redis_exporter","note":"Como a thread principal do Redis usa um único núcleo, saturar um núcleo deixa todo o servidor lento. CPU alta pode vir de comandos caros, conexões demais ou scripts Lua. Encontre os comandos caros com SLOWLOG e, se necessário, divida a carga entre várias instâncias.","tags":["cpu","load"]},{"metric":"Conexões rejeitadas (rejected_connections)","warn":"> 0","crit":"> 10 / min","tool":"INFO stats (rejected_connections)","note":"rejected_connections é o número de conexões rejeitadas porque o limite de maxclients foi atingido. Um valor acima de zero significa que clientes não estão sendo atendidos e que estão ocorrendo erros na aplicação. Investigue imediatamente o valor de maxclients e os vazamentos de conexão.","tags":["connection","error","limit"]}]},"reference/alerts-elasticsearch.json":{"engineId":"elasticsearch","engine":"Elasticsearch","order":7,"alerts":[{"metric":"Uso do heap da JVM","warn":"> 75%","crit":"> 85%","tool":"_nodes/stats/jvm / elasticsearch_exporter","note":"O uso do heap da JVM mostra a pressão de memória do nó; valores sustentados acima de 75% significam GC frequente e possível OutOfMemory. Se o heap exceder 85%, o nó pode parar de responder ou sair do cluster. Dimensione o heap em cerca de metade da memória do servidor e no máximo 30-31 GB.","tags":["memory","jvm","heap"]},{"metric":"Número de shards não atribuídos (unassigned shards)","warn":">= 1 (réplica)","crit":">= 1 (primário)","tool":"_cluster/health / _cat/shards","note":"Shards não atribuídos significam que parte dos dados está inacessível ou não replicada. Um shard primário não atribuído significa risco de perda de dados; uma réplica não atribuída significa perda de redundância, e o cluster fica yellow/red. Encontre o motivo com _cluster/allocation/explain.","tags":["shard","cluster","health"]},{"metric":"Uso em relação ao disk watermark","warn":"> 85% (low)","crit":"> 90% (high) / > 95% (flood_stage)","tool":"_nodes/stats/fs / _cat/allocation","note":"O Elasticsearch toma ações graduais com base no uso de disco: no low watermark de 85% deixa de alocar novos shards no nó, no high watermark de 90% realoca os shards existentes para outros nós e no flood_stage de 95% aplica um bloqueio read_only_allow_delete aos índices. No 8.x, em discos grandes, os valores de max_headroom (low 200GB / high 150GB / flood 100GB livres) têm precedência sobre os percentuais. No 7.4+ o bloqueio é liberado automaticamente quando o uso de disco cai abaixo do high watermark; ainda assim, libere espaço em disco antes que os watermarks sejam excedidos.","tags":["disk","watermark","capacity"]},{"metric":"Operações rejeitadas no thread pool (rejected)","warn":"> 0 (write/search)","crit":"> 100 / min","tool":"_cat/thread_pool / _nodes/stats/thread_pool","note":"Quando a fila de um thread pool está cheia, as requisições recebidas são rejeitadas; uma rejeição no pool de write significa indexação perdida, no pool de search uma consulta com falha. Rejeições sustentadas indicam que o nó não consegue acompanhar a carga recebida. Equilibre a carga reduzindo o tamanho do bulk e a concorrência.","tags":["threadpool","rejected","load"]},{"metric":"Tempo de pausa de GC (old gen GC pause)","warn":"> 1 s","crit":"> 5 s","tool":"GC logs / _nodes/stats/jvm","note":"Durante pausas longas de GC o nó não consegue responder e pode perder a conexão com o master, o que dispara a realocação de shards. GC frequente e longo na geração antiga é sintoma de pressão no heap. Revise o tamanho do heap e o uso de agregações e fielddata que consomem muita memória.","tags":["jvm","gc","pause"]},{"metric":"Latência de indexação","warn":"> 50 ms","crit":"> 200 ms","tool":"_nodes/stats/indices (index_time/index_total)","note":"O tempo médio de indexação mostra o desempenho de escrita de documentos e é calculado dividindo index_time_in_millis por index_total. Valores crescentes indicam gargalo de IO de disco, uma cadeia de análise pesada ou pressão de refresh. Otimize o tamanho do bulk e a configuração de refresh_interval.","tags":["indexing","latency","performance"]},{"metric":"Latência de busca","warn":"> 100 ms","crit":"> 500 ms","tool":"_nodes/stats/indices (query_time/query_total)","note":"O tempo médio de consulta reflete diretamente o desempenho de busca percebido pelos usuários e é calculado dividindo query_time_in_millis por query_total. Valores crescentes podem vir de agregações pesadas, shards demais ou cache frio. Habilite o slow log para encontrar as consultas caras.","tags":["search","latency","performance"]},{"metric":"Pending tasks","warn":"> 10","crit":"> 100","tool":"_cluster/pending_tasks","note":"Pending tasks são alterações do cluster state que o nó master ainda não aplicou (mapping, alocação de shards etc.). Um acúmulo constante indica que o master está sobrecarregado ou que o cluster state ficou grande demais. Alivie a pressão sobre o master reduzindo um número excessivo de shards.","tags":["cluster","master","queue"]},{"metric":"Acionamentos de circuit breaker","warn":"> 0 (tripped)","crit":"> 10 / min","tool":"_nodes/stats/breakers","note":"Os circuit breakers cancelam uma requisição para evitar que uma operação consuma memória excessiva e leve o nó a OutOfMemory. Acionamentos frequentes indicam pressão de memória por agregações pesadas ou requisições grandes. Monitore o contador tripped e torne mais leves as consultas problemáticas.","tags":["memory","breaker","jvm"]},{"metric":"Status de saúde do cluster (cluster status)","warn":"yellow","crit":"red","tool":"_cluster/health","note":"O status do cluster pode ser green (todos os shards atribuídos), yellow (réplicas ausentes) ou red (primários ausentes, dados inacessíveis). Red exige ação imediata porque alguns dados estão perdidos ou inacessíveis. Yellow indica perda de redundância e não deve ser ignorado.","tags":["cluster","health","shard"]},{"metric":"Uso de CPU","warn":"> 80%","crit":"> 90%","tool":"_nodes/stats/os / node_exporter","note":"CPU alta e sustentada pode vir de consultas pesadas, indexação excessiva ou operações de merge. Picos curtos são normais, mas a saturação sustentada causa enfileiramento de consultas e de indexação. Identifique as operações que mais consomem CPU com a API hot threads (_nodes/hot_threads).","tags":["cpu","load"]},{"metric":"Idade do último snapshot bem-sucedido","warn":"> 24 horas","crit":"> 48 horas","tool":"_snapshot/_status / SLM","note":"A idade do snapshot determina o ponto mais recente para o qual você pode voltar e o seu RPO. Backups automáticos e regulares devem ser garantidos com o Snapshot Lifecycle Management (SLM). Se snapshots com falha ou ignorados passarem despercebidos, os dados não poderão ser recuperados em um desastre; verifique o status dos snapshots regularmente.","tags":["backup","snapshot","rpo"]}]},"cloud/cloud-ops-1.json":{"category":"Conexão, Backup e Réplica","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":"Listar instâncias / bancos de dados","aliases":["list","instances","list all"],"providers":{"aws-rds":{"command":"aws rds describe-db-instances --query 'DBInstances[].DBInstanceIdentifier'","note":"Lista os identificadores de todas as instâncias RDS. Adicione --region para direcionar a uma região.","danger":"safe"},"aws-aurora":{"command":"aws rds describe-db-clusters --query 'DBClusters[].DBClusterIdentifier'","note":"Lista os identificadores dos clusters Aurora; verifique o campo DBClusterMembers para ver os membros do cluster.","danger":"safe"},"gcp-cloudsql":{"command":"gcloud sql instances list","note":"Lista todas as instâncias Cloud SQL do projeto. Adicione --project para direcionar a um projeto.","danger":"safe"},"azure-sql":{"command":"az sql db list -g <rg> -s <server>","note":"Lista os bancos de dados no resource group (-g) e no servidor lógico (-s) informados. Use 'az sql server list' para listar os servidores.","danger":"safe"},"mongodb-atlas":{"command":"atlas clusters list","note":"Lista todos os clusters do projeto Atlas. Adicione --projectId para direcionar a um projeto.","danger":"safe"}}},{"id":"connect","title":"Conectar a uma instância (encontrar endpoint + conectar)","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":"Retorna o endereço de conexão da instância (host). Obtenha a porta em Endpoint.Port e conecte-se com o cliente psql/mysql.","danger":"safe"},"aws-aurora":{"command":"aws rds describe-db-clusters --db-cluster-identifier <id> --query 'DBClusters[0].Endpoint'","note":"Retorna o endpoint de escrita do cluster. Use o campo ReaderEndpoint para acesso somente leitura.","danger":"safe"},"gcp-cloudsql":{"command":"gcloud sql instances describe <instance> --format='value(ipAddresses[].ipAddress)'","note":"Retorna o(s) endereço(s) IP da instância. O Cloud SQL Auth Proxy é recomendado para conexões seguras.","danger":"safe"},"azure-sql":{"command":"az sql db show-connection-string -s <server> -n <db> -c ado.net","note":"Gera a connection string para o tipo de cliente informado (-c: ado.net, jdbc, odbc, php etc.); você preenche o usuário/senha.","danger":"safe"},"mongodb-atlas":{"command":"atlas clusters connectionStrings describe <clusterName>","note":"Retorna as connection strings padrão e SRV do cluster. São necessários uma entrada na IP access list e um usuário de banco de dados.","danger":"safe"}}},{"id":"take-snapshot","title":"Fazer um backup / snapshot manual","aliases":["snapshot","backup","backup"],"providers":{"aws-rds":{"command":"aws rds create-db-snapshot --db-instance-identifier <id> --db-snapshot-identifier <snap-id>","note":"Faz um snapshot manual da instância (mantido até ser excluído manualmente). Pode ocorrer uma breve suspensão de I/O.","danger":"caution"},"aws-aurora":{"command":"aws rds create-db-cluster-snapshot --db-cluster-identifier <id> --db-cluster-snapshot-identifier <snap-id>","note":"Faz um snapshot manual do cluster Aurora. Como os backups do Aurora são contínuos, esta é uma cópia fixa.","danger":"caution"},"gcp-cloudsql":{"command":"gcloud sql backups create --instance=<instance>","note":"Cria um backup sob demanda da instância. Um breve impacto no desempenho é possível durante a operação.","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":"O Azure SQL tem backup automático; para um backup manual portátil, este comando exporta o banco de dados como BACPAC. O point-in-time restore é um recurso separado.","danger":"caution"},"mongodb-atlas":{"command":"atlas backups snapshots create <clusterName>","note":"Inicia um snapshot de backup sob demanda do cluster. O Cloud Backup deve estar habilitado.","danger":"caution"}}},{"id":"restore-pitr","title":"Restaurar para um ponto no tempo (point-in-time restore)","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":"Cria uma NOVA instância a partir da instância de origem no momento informado; não sobrescreve a instância existente. Use --use-latest-restorable-time para restaurar para o ponto mais recente.","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":"Restaura o cluster Aurora para o momento informado como um novo cluster. Depois é preciso adicionar instâncias com create-db-instance.","danger":"caution"},"gcp-cloudsql":{"command":"gcloud sql instances clone <src> <new> --point-in-time '2026-07-03T10:00:00Z'","note":"Cria um clone da instância de origem no momento informado como uma nova instância. O log binário/WAL deve estar habilitado na origem.","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":"Restaura o banco de dados para o momento informado como um NOVO banco de dados; o banco de origem é preservado. O horário é em UTC.","danger":"caution"},"mongodb-atlas":{"command":"atlas backups restores start pointInTime --clusterName <cluster> --pointInTimeUTCMillis <ms> --targetClusterName <target> --targetProjectId <projId>","note":"Inicia um restore para o horário UTC informado usando o Continuous Cloud Backup. O cluster de destino é sobrescrito; prossiga com cuidado.","danger":"danger"}}},{"id":"read-replica","title":"Criar uma réplica de leitura","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":"Cria uma réplica de leitura assíncrona a partir da instância de origem. Use --source-region para uma cópia entre regiões.","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":"No Aurora, um reader é uma instância adicionada ao cluster; ela compartilha o storage do cluster. Defina o valor de engine de acordo com o cluster (aurora-mysql / aurora-postgresql).","danger":"caution"},"gcp-cloudsql":{"command":"gcloud sql instances create <replica> --master-instance-name=<src> --region=<region>","note":"Cria uma réplica de leitura a partir da instância primária (master). O log binário deve estar habilitado na origem.","danger":"caution"},"azure-sql":{"command":"az sql db replica create -g <rg> -s <server> -n <db> --partner-server <target-server>","note":"Cria uma secundária legível com geo-replicação ativa do banco de dados em outro servidor. O servidor de destino deve existir.","danger":"caution"},"mongodb-atlas":{"command":"atlas clusters update <clusterName> --file cluster.json","note":"Os clusters Atlas já são replica sets replicados. Para capacidade extra de leitura, adicione nós readOnly ou analytics em replicationSpecs e atualize.","danger":"caution"}}},{"id":"failover","title":"Failover","aliases":["failover","fail over","switch to standby"],"providers":{"aws-rds":{"command":"aws rds reboot-db-instance --db-instance-identifier <id> --force-failover","note":"Em uma instância Multi-AZ, força uma reinicialização que dispara o failover para o standby. Espere uma breve indisponibilidade.","danger":"danger"},"aws-aurora":{"command":"aws rds failover-db-cluster --db-cluster-identifier <cluster> --target-db-instance-identifier <reader>","note":"Promove um reader do cluster Aurora a novo writer. Se nenhum destino for informado, uma réplica adequada é escolhida; espere uma breve indisponibilidade.","danger":"danger"},"gcp-cloudsql":{"command":"gcloud sql instances failover <instance>","note":"Faz o failover de uma instância HA (alta disponibilidade) para a zona standby. Funciona apenas em instâncias com HA habilitada; ocorre indisponibilidade.","danger":"danger"},"azure-sql":{"command":"az sql failover-group set-primary -g <rg> -s <secondary-server> -n <fog-name>","note":"Move o papel de primário para o servidor secundário em um auto-failover group (failover planejado). Pode ser forçado com --allow-data-loss, o que traz risco de perda de dados.","danger":"danger"},"mongodb-atlas":{"command":"atlas clusters failover <clusterName>","note":"O Atlas faz failover automaticamente; este comando dispara um failover manual para testes. O nó primário muda e a aplicação precisa se reconectar.","danger":"danger"}}}]},"cloud/cloud-ops-2.json":{"category":"Configuração, Escalonamento e Monitoramento","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":"Alterar o tamanho da instância (escalonamento vertical)","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 aplica a alteração agora e reinicia a instância (breve indisponibilidade). Sem essa flag a alteração é aplicada na próxima janela de manutenção. Em instâncias Multi-AZ a indisponibilidade se reduz a aproximadamente o tempo do failover.","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":"No Aurora cada instância (writer e readers) é escalonada separadamente; muda o tamanho da instância, não do cluster. Escalone primeiro os readers e depois faça failover para substituir o writer e minimizar a indisponibilidade. Com Serverless v2 o escalonamento é feito via ACU mín./máx.","danger":"caution"},"gcp-cloudsql":{"command":"gcloud sql instances patch <id> --tier db-custom-4-16384","note":"Um machine type personalizado é especificado como db-custom-CPU-MEMORY (exemplo: 4 vCPU, 16384 MB de RAM). A alteração reinicia a instância, causando breve indisponibilidade. Também é possível usar tiers predefinidos (ex.: db-n1-standard-4).","danger":"caution"},"azure-sql":{"command":"az sql db update -g <rg> -s <server> -n <db> --service-objective S3","note":"No modelo DTU use um service objective como S3/P2; no modelo vCore use --edition GeneralPurpose --family Gen5 --capacity 4. O escalonamento é feito online; pode ocorrer uma breve queda de conexão de alguns segundos perto do fim da operação.","danger":"caution"},"mongodb-atlas":{"command":"atlas clusters update <name> --tier M30","note":"O Atlas redimensiona os nós do replica set de forma rolling, então não há indisponibilidade. Exige a flag --projectId ou um projeto padrão. Ao reduzir o tamanho, observe os limites de disco e memória.","danger":"caution"}}},{"id":"parameter-group","title":"Alterar parâmetros (parameter group / flags / server config)","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":"Use ApplyMethod=immediate para parâmetros dinâmicos e pending-reboot para parâmetros estáticos. O parameter group deve estar associado à instância; alterações de parâmetros estáticos entram em vigor após uma reinicialização. Use create-db-parameter-group para criar um grupo.","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":"No Aurora, os parâmetros de todo o cluster são gerenciados com o DB cluster parameter group e os parâmetros específicos de instância com o DB parameter group (modify-db-parameter-group). Parâmetros estáticos exigem reinicialização em todo o cluster.","danger":"caution"},"gcp-cloudsql":{"command":"gcloud sql instances patch <id> --database-flags max_connections=500,log_min_duration_statement=1000","note":"--database-flags define TODAS as flags de uma vez; flags definidas anteriormente que não estão na lista são redefinidas, então especifique todas juntas. Algumas flags exigem reinicialização da instância. Veja as flags atuais com '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":"No Azure SQL, em vez da configuração clássica de servidor, as configurações são aplicadas principalmente com T-SQL: ALTER DATABASE SCOPED CONFIGURATION ...; sp_configure no nível do servidor é limitado. Para opções de elastic pool/banco de dados, use as flags de 'az sql db update'.","danger":"caution"},"mongodb-atlas":{"command":"atlas clusters advancedSettings update <name> --oplogMinRetentionHours 24 --oplogSizeMB 20480","note":"No Atlas, argumentos de baixo nível do processo MongoDB só podem ser definidos de forma limitada via 'advancedSettings' (oplog, full-text search, profundidade de índice etc.). A maioria dos parâmetros do servidor é gerenciada pelo Atlas e não pode ser alterada diretamente.","danger":"caution"}}},{"id":"monitoring","title":"Ver métricas e desempenho","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":"As métricas básicas (CPU, conexões, IOPS, latência) ficam no namespace AWS/RDS do CloudWatch. Para análise no nível de consulta, habilite o Performance Insights: 'aws pi get-resource-metrics --service-type RDS ...' ou use o painel do Performance Insights no console.","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":"As métricas específicas do Aurora (AuroraReplicaLag, VolumeReadIOPs, CommitLatency, buffer cache hit) também ficam no namespace AWS/RDS. O Performance Insights é recomendado para o Aurora e oferece análise de top SQL e de wait events.","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":"As métricas do Cloud SQL ficam no Cloud Monitoring em cloudsql.googleapis.com/... Para análise no nível de consulta, habilite o Cloud SQL Query Insights (console ou API); ele mostra as consultas mais lentas e os wait events.","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":"Métricas como cpu_percent, dtu_consumption_percent, storage_percent e connection_successful vêm do Azure Monitor. Para o desempenho de consultas, use os painéis Query Performance Insight e 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":"As medições no nível de processo são obtidas com 'atlas metrics processes' e as de disco com 'atlas metrics disks'. Para recomendações sobre consultas lentas, use o Performance Advisor: 'atlas performanceAdvisor slowQueryLogs list' e 'atlas performanceAdvisor suggestedIndexes list'.","danger":"safe"}}},{"id":"maintenance-window","title":"Janela de manutenção e gerenciamento de atualizações","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":"A janela é em UTC, no formato ddd:hh24:mi-ddd:hh24:mi, e deve ter pelo menos 30 minutos. Liste as manutenções pendentes com 'aws rds describe-pending-maintenance-actions' e aplique-as imediatamente ou na próxima janela com 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":"No Aurora a janela de manutenção no nível do cluster é definida com modify-db-cluster e a do nível da instância com modify-db-instance. As atualizações pendentes de engine/SO são gerenciadas com apply-pending-maintenance-action; upgrades de versão do engine podem exigir indisponibilidade.","danger":"caution"},"gcp-cloudsql":{"command":"gcloud sql instances patch <id> --maintenance-window-day SUN --maintenance-window-hour 3 --maintenance-release-channel production","note":"Define o dia (MON..SUN), a hora (0-23, horário local da instância/UTC) e o release channel (production ou preview). Com as flags --deny-maintenance-period-* também é possível definir um período em que nenhuma manutenção é realizada.","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":"A janela de manutenção do Azure SQL é gerenciada atribuindo uma Maintenance Configuration predefinida (janelas noturnas em dias úteis/fins de semana em vez da padrão). Liste as configurações com '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=domingo ... 7=sábado, hourOfDay 0-23 (UTC). Use 'atlas maintenanceWindows defer' para adiar a manutenção pendente em uma semana e 'atlas maintenanceWindows start' para iniciá-la imediatamente.","danger":"caution"}}},{"id":"encryption","title":"Ver/configurar o status de criptografia (at-rest)","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":"A criptografia at-rest do RDS só pode ser habilitada QUANDO a instância é CRIADA; para habilitá-la em uma instância existente não criptografada, faça uma cópia criptografada de um snapshot e restaure a partir dela. A chave é gerenciada pelo 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":"No Aurora, a criptografia é definida no nível do cluster e somente na criação. Para criptografar um cluster existente não criptografado, copie um snapshot como criptografado e restaure-o. Todas as instâncias e backups usam a mesma chave 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":"O Cloud SQL é criptografado por padrão com uma chave gerenciada pelo Google; uma chave gerenciada pelo cliente (CMEK) só pode ser atribuída na criação da instância com --disk-encryption-key. A conta de serviço do Cloud SQL deve receber permissão de encrypt/decrypt na chave.","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":"No Azure SQL, a criptografia at-rest é fornecida pelo Transparent Data Encryption (TDE) e vem habilitada por padrão em novos bancos de dados. Para usar sua própria chave, configure 'az sql server tde-key set' (Azure Key Vault / BYOK) no nível do servidor.","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":"No Atlas, os dados são criptografados at-rest por padrão. Além disso, a envelope encryption com chave do cliente (BYOK) via AWS KMS / Azure Key Vault / GCP KMS é habilitada em todo o projeto com 'atlas encryptionAtRest' e aplicada ao cluster.","danger":"caution"}}},{"id":"storage-autoscale","title":"Aumentar o storage / habilitar autoscaling","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 define o tamanho atual; --max-allocated-storage define o limite superior do storage autoscaling. O aumento de storage é online; porém, é preciso aguardar pelo menos 6 horas entre modificações de storage, e o storage não pode ser reduzido.","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":"O storage do Aurora escala de forma totalmente automática (em incrementos de 10 GB, até 128 TB dependendo do engine) e cresce conforme é usado; --allocated-storage / --max-allocated-storage não são definidos. Você apenas monitora o uso; não é necessário gerenciar o tamanho.","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 habilita o crescimento automático quando o disco está quase cheio; --storage-auto-increase-limit define o limite superior (0 = ilimitado). O storage só pode ser aumentado, NÃO PODE SER REDUZIDO; escolha o tamanho inicial e o limite com cuidado.","danger":"caution"},"azure-sql":{"command":"az sql db update -g <rg> -s <server> -n <db> --max-size 500GB","note":"No Azure SQL o tamanho máximo do banco de dados é definido com --max-size; o banco cresce automaticamente dentro do espaço alocado. O tamanho máximo depende do service tier/limite de vCore selecionado. No tier Hyperscale o storage escala automaticamente e praticamente sem limite.","danger":"caution"},"mongodb-atlas":{"command":"atlas clusters update <name> --diskSizeGB 200   # for autoscaling, diskGBEnabled=true via extended configuration (advancedSettings / API)","note":"O tamanho do disco é aumentado com --diskSizeGB. No Atlas, o storage autoscaling (Auto-scale storage) vem habilitado por padrão em clusters M10 e maiores; o disco cresce automaticamente quando está 90% cheio. A habilitação/desabilitação é gerenciada na configuração do cluster (autoScaling.diskGBEnabled).","danger":"caution"}}}]},"guide/best-practices.json":{"topics":[{"id":"indexing-strategy","title":"Estratégia de indexação","category":"Desempenho","summary":"Índices aceleram as consultas de leitura, mas acrescentam custo de escrita e de storage; adicione-os com base na necessidade e em medições.","points":["Foque nas colunas de WHERE, JOIN e ORDER BY; coloque a coluna mais seletiva primeiro em um índice composto (regra do prefixo mais à esquerda).","Use covering indexes: inclua no índice todas as colunas de que a consulta precisa para eliminar o acesso à tabela (lookup).","Identifique e remova índices não utilizados e redundantes (duplicados ou prefixos de outro índice); todo índice deixa INSERT/UPDATE/DELETE mais lentos.","Evite índices B-tree isolados em colunas de baixa cardinalidade (ex.: gênero, boolean); use um índice parcial/filtrado se necessário.","Verifique com EXPLAIN/EXPLAIN ANALYZE se o índice é realmente usado; uma função ou conversão de tipo desabilita o índice (como em WHERE UPPER(name))."],"level":"junior"},{"id":"normalization","title":"Normalização vs desnormalização","category":"Design","summary":"A normalização garante integridade dos dados e ausência de redundância; a desnormalização é uma troca deliberada em favor do desempenho de leitura.","points":["Tenha a 3FN como meta padrão em sistemas OLTP; evite redundância de dados e anomalias de atualização.","Desnormalize apenas quando houver um gargalo de desempenho medido, e justifique.","Garanta a consistência dos dados desnormalizados com triggers, materialized views ou a camada de aplicação.","Para cargas de relatórios/analytics, considere um schema desnormalizado separado (star schema) ou uma réplica de leitura.","Desnormalização prematura é dívida técnica; primeiro tente resolver o problema com o índice e a consulta certos."],"level":"senior"},{"id":"data-types","title":"Escolha do tipo de dado certo","category":"Design","summary":"O tipo de dado correto e o menor possível melhora diretamente o storage, o tamanho dos índices e o desempenho.","points":["Escolha o menor tipo que atenda à necessidade: SMALLINT para idade, DECIMAL/NUMERIC para dinheiro (nunca FLOAT).","Armazene sempre dados de tempo com fuso horário (TIMESTAMPTZ / UTC); evite armazenar horário local.","Use um ENUM ou tabela de lookup para conjuntos de valores fixos e limitados; restrinja em vez de permitir texto livre.","Para texto de tamanho variável, dimensione conforme a necessidade real ou use TEXT em vez de um VARCHAR(255) desnecessariamente grande.","Se usar UUID como PK, atenção à fragmentação do índice; considere UUIDs sequenciais (v7) ou BIGINT identity.","Escolha a semântica de NULL deliberadamente; deixe explícita no design a diferença entre 'desconhecido' e 'vazio'."],"level":"junior"},{"id":"naming-conventions","title":"Convenções de nomenclatura","category":"Design","summary":"Uma nomenclatura consistente facilita a legibilidade, a manutenção e a comunicação da equipe; defina o padrão desde o início.","points":["Escolha uma convenção e aplique-a em todo lugar: snake_case é difundido e robusto contra problemas de diferenciação de maiúsculas/minúsculas.","Defina singular ou plural para nomes de tabelas; prefira nomes de colunas significativos e sem abreviações.","Nomeie as chaves estrangeiras de forma que a origem seja óbvia (ex.: customer_id) e dê prefixos padrão a índices/constraints (fk_, ix_, uq_).","Evite usar palavras reservadas (order, user, group) como nomes de tabelas/colunas.","Deixe as colunas booleanas explícitas com os prefixos is_/has_; adicione sufixos consistentes como _at, _date às colunas de data."],"level":"junior"},{"id":"partitioning-strategy","title":"Estratégia de particionamento","category":"Desempenho","summary":"O particionamento divide tabelas grandes em partes gerenciáveis; melhora a manutenção, o expurgo e o desempenho das consultas.","points":["Escolha a chave de partição com base nos padrões de consulta e arquivamento; o particionamento RANGE por data é o mais comum para séries temporais.","Verifique se o partition pruning funciona: as consultas devem incluir a chave de partição na cláusula WHERE, caso contrário todas as partições são lidas.","Em vez de excluir dados antigos, expurgue-os instantaneamente e quase sem locks com DROP/DETACH de partição.","Um número excessivo de partições acrescenta custo de planejamento e de metadados; escolha uma granularidade razoável (mensal/semanal).","Configure um job de manutenção que crie automaticamente as partições futuras; evite erros por escritas sem partição correspondente."],"level":"senior"},{"id":"connection-pooling","title":"Pooling de conexões","category":"Operações","summary":"Um pool de conexões elimina o custo alto de estabelecer conexões e protege o banco de dados contra avalanches de conexões.","points":["Não abra uma nova conexão por requisição; use um pool na aplicação ou em uma camada intermediária (PgBouncer, HikariCP).","Dimensione o pool pelos núcleos de CPU e pela carga de trabalho; um pool superdimensionado sufoca o banco de dados (um pool pequeno geralmente é melhor).","Defina deliberadamente os valores de tempo de vida da conexão, idle e acquire timeout; habilite a detecção de vazamentos.","Planeje o pool em relação ao limite de max_connections do banco de dados; considere o total entre várias instâncias da aplicação.","Use transações curtas para que as conexões voltem rapidamente ao pool; não aguarde I/O externo dentro de uma transação."],"level":"senior"},{"id":"transaction-design","title":"Design de transações (curtas e atômicas)","category":"Desempenho","summary":"As transações devem ser curtas, atômicas e cobrir uma única unidade lógica de trabalho; isso minimiza a duração dos locks.","points":["Mantenha as transações o mais curtas possível; não inclua nelas interação com o usuário, chamadas a APIs externas ou cálculos longos.","Agrupe em uma transação apenas as operações que devem ter sucesso ou falhar juntas.","Atualize as linhas sempre na mesma ordem para reduzir conflitos de lock (a base da prevenção de deadlocks).","Evite locks desnecessariamente amplos; não coloque operações somente leitura em blocos de transação desnecessários.","Defina um caminho claro de rollback em caso de erro; não deixe commits parciais nem transações abertas para trás.","Faça commit de operações em massa longas em lotes; uma única transação gigante causa bloat de WAL/undo."],"level":"senior"},{"id":"isolation-levels","title":"Escolha do nível de isolamento","category":"Desempenho","summary":"O nível de isolamento define o equilíbrio entre consistência e concorrência; escolha-o deliberadamente com base nas regras de negócio.","points":["Conheça os tipos de anomalia: dirty read, non-repeatable read, phantom read; entenda qual nível previne qual.","Read Committed é suficiente para a maioria dos sistemas OLTP; suba de nível apenas quando realmente necessário.","Use Serializable ou locking explícito (SELECT ... FOR UPDATE) em operações críticas de dinheiro/estoque.","Sob Serializable, adicione lógica de retry automático para falhas de serialização.","Conheça a diferença de comportamento entre engines MVCC e baseados em locks; o mesmo nível pode oferecer garantias diferentes em engines diferentes."],"level":"expert"},{"id":"deadlock-prevention","title":"Prevenção de deadlocks","category":"Desempenho","summary":"Um deadlock ocorre quando transações aguardam os recursos umas das outras; pode ser amplamente prevenido pelo design.","points":["Acesse sempre os recursos/linhas em uma ordem consistente e idêntica; diferenças de ordem são a fonte mais comum de deadlocks.","Mantenha as transações curtas e reduza o número de locks; evite atualizações desnecessariamente amplas.","Quando necessário, torne os conflitos previsíveis com locking antecipado (SELECT ... FOR UPDATE).","Capture os erros de deadlock na aplicação e repita a transação automaticamente; eliminar completamente os deadlocks muitas vezes é impossível.","Revise regularmente os logs/grafos de deadlock; elimine padrões recorrentes alterando índices ou a ordem de acesso."],"level":"expert"},{"id":"sharding-strategy","title":"Estratégia de sharding / escalonamento horizontal","category":"Design","summary":"O sharding supera os limites de um único servidor distribuindo os dados entre vários nós; como acrescenta complexidade séria, deve ser o último recurso.","points":["Esgote primeiro o escalonamento vertical, a indexação, o cache e as réplicas de leitura; faça sharding apenas quando realmente necessário.","Escolha a shard key com cuidado: ela deve gerar poucas consultas cross-shard e uma distribuição uniforme, sem criar hotspots.","Use consistent hashing ou shards virtuais para o rebalanceamento (resharding); planeje o crescimento desde o início.","JOINs cross-shard e transações distribuídas são caros; projete o schema para minimizá-los.","Resolva a geração de IDs globalmente únicos (IDs sequenciais estilo snowflake etc.) e a camada de roteamento de shards."],"level":"expert"},{"id":"backup-strategy","title":"Estratégia de backup (3-2-1)","category":"Backup e HA","summary":"Uma estratégia de backup sólida é a última linha de defesa contra desastres; um backup não conta até ser testado.","points":["Aplique a regra 3-2-1: 3 cópias, 2 mídias diferentes, 1 cópia fora do local (offsite/outra região).","Combine backups completos + incrementais com o arquivamento de WAL/binlog para obter recuperação point-in-time (PITR).","Teste os backups regularmente restaurando-os DE FATO; um backup não testado não é um backup.","Criptografe os backups tanto em repouso quanto em trânsito; restrinja o acesso e defina o período de retenção por política.","Mantenha uma cópia imutável ou air-gapped contra ransomware."],"level":"junior"},{"id":"hadr-design","title":"Design de HA/DR e RPO/RTO","category":"Backup e HA","summary":"O design de alta disponibilidade e recuperação de desastres começa definindo os objetivos de negócio como métricas de RPO e RTO.","points":["Defina as metas de RPO (perda de dados aceitável) e RTO (indisponibilidade aceitável) junto com a área de negócio.","A replicação síncrona oferece RPO próximo de zero, mas acrescenta latência; a assíncrona tem bom desempenho, mas traz risco de perda de dados.","Configure o failover automático e verifique se ele realmente funciona com exercícios regulares de failover.","Use um mecanismo de quorum/witness para evitar split-brain; nunca permita que os dois nós se tornem master.","Mantenha o ambiente de DR em uma região física diferente; seja resiliente à falha de uma única região/data center."],"level":"expert"},{"id":"capacity-planning","title":"Planejamento de capacidade e crescimento","category":"Operações","summary":"O planejamento de capacidade evita indisponibilidades inesperadas provisionando recursos à frente da tendência de crescimento.","points":["Meça ao longo do tempo a taxa de crescimento dos dados, IOPS, CPU, memória e uso de conexões e extraia tendências.","Defina alertas antecipados de limite para o uso de disco (ex.: 75%/85%); aja antes que o espaço acabe.","Planeje o crescimento com base em previsões; considere a carga de pico e a variação sazonal.","Revise regularmente o número de conexões, o bloat de tabelas/índices e as necessidades de arquivamento.","Decida o caminho de escalonamento (vertical, réplicas, particionamento/sharding) antes de chegar ao gargalo."],"level":"senior"},{"id":"migration-strategy","title":"Estratégia de migração (indisponibilidade mínima)","category":"Operações","summary":"Migrações de schema e de dados devem seguir um plano reversível que minimize a indisponibilidade, online quando possível.","points":["Projete toda migração para ser reversível e idempotente; nunca vá para produção sem um plano de rollback.","Evite DDL bloqueante em tabelas grandes; use ferramentas de online schema change (PG: pg-osc/pgroll; MySQL: gh-ost, pt-osc).","Aplique o padrão expand-contract para alterações compatíveis para trás/para frente: primeiro adicione, faça o deploy e depois remova o antigo.","Mova grandes volumes de dados em lotes pequenos; não gere locks e bloat de WAL com um único UPDATE gigante.","Ensaie a migração primeiro em um ambiente semelhante ao de produção, com volume de dados realista, e meça sua duração.","Registre antecipadamente em um plano escrito o momento do cutover, as etapas de validação e a decisão de rollback."],"level":"senior"},{"id":"schema-versioning","title":"Versionamento de schema (Flyway/Liquibase)","category":"Operações","summary":"As alterações de schema devem ser gerenciadas com migrations que vivem junto com o código, são versionadas e aplicadas automaticamente; a intervenção manual é propensa a erros.","points":["Versione todas as alterações de schema com ferramentas como Flyway/Liquibase e mantenha-as no controle de versão.","Não execute DDL manualmente em produção; toda alteração deve passar por um arquivo de migration revisado.","Mantenha as migrations ordenadas e únicas; nunca modifique um arquivo de migration já aplicado, corrija com uma nova migration.","Aplique e valide as migrations automaticamente no pipeline de CI/CD; garanta a consistência do schema entre os ambientes.","Avance o código da aplicação e a versão do schema em sincronia; adote o padrão expand-contract para transições compatíveis com versões anteriores."],"level":"senior"},{"id":"least-privilege","title":"Princípio do menor privilégio","category":"Segurança","summary":"Todo usuário e aplicação deve ter apenas os privilégios necessários para fazer seu trabalho; privilégios em excesso ampliam a superfície de ataque.","points":["Use contas separadas e com privilégios limitados para a aplicação; nunca conecte como superuser/admin.","Conceda privilégios a roles, e não diretamente a usuários; gerencie o acesso pela associação a roles.","Permita apenas as tabelas e operações necessárias (SELECT/INSERT/UPDATE); evite GRANT ALL amplo.","Revise os privilégios periodicamente e revogue os não utilizados; remova o acesso imediatamente quando um funcionário/serviço sair.","Não incorpore segredos (senhas, connection strings) no código; use um gerenciador de segredos (vault) e faça a rotação regularmente."],"level":"junior"},{"id":"encryption-basics","title":"Fundamentos de criptografia (at-rest/in-transit)","category":"Segurança","summary":"Os dados devem ser criptografados tanto quando armazenados quanto quando transmitidos; a criptografia é uma proteção básica para compliance e contra vazamentos de dados.","points":["Exija TLS em trânsito; rejeite conexões não criptografadas e habilite a verificação de certificados.","Aplique criptografia em repouso (TDE ou criptografia de disco/volume) para que um disco/backup roubado não possa ser lido.","Leve a sério o gerenciamento de chaves: mantenha as chaves em um KMS/HSM separado e faça a rotação regularmente.","Criptografe adicionalmente na camada de aplicação (por campo) os campos altamente sensíveis, como números de cartão de crédito e documentos de identidade.","Criptografe também os backups; estenda a proteção da produção aos backups e às réplicas.","Mascare ou anonimize os dados sensíveis em ambientes de teste/desenvolvimento (data masking)."],"level":"senior"},{"id":"monitoring-basics","title":"Fundamentos de monitoramento (golden signals)","category":"Operações","summary":"Um monitoramento eficaz significa coletar as métricas certas e alertar em limites significativos; ele detecta os problemas antes que os usuários percebam.","points":["Monitore os golden signals: latência, tráfego, taxa de erros e saturação.","Adicione métricas específicas de banco de dados: consultas lentas, tempos de lock/espera, número de conexões, cache hit ratio, replication lag.","Vincule os alertas ao impacto e a limites acionáveis, e não a sintomas; alertas ruidosos causam fadiga de alertas.","Mantenha o slow query log e as estatísticas de consultas (como pg_stat_statements) sempre habilitados e revise-os regularmente.","Retenha o histórico das métricas; construa uma baseline para tendências e planejamento de capacidade.","Alerte sempre sobre condições críticas como espaço em disco restante e sucesso dos backups."],"level":"junior"},{"id":"query-design","title":"Design de consultas e prevenção de N+1","category":"Desempenho","summary":"Uma consulta eficiente busca apenas os dados necessários com o mínimo de idas e voltas; N+1 é o bug de desempenho mais comum e mais traiçoeiro.","points":["Selecione apenas as colunas necessárias em vez de SELECT *; isso melhora a rede, a memória e as oportunidades de covering index.","Evite o problema N+1: use um JOIN ou uma consulta em lote (IN) em vez de consultas individuais em um loop; habilite o eager loading no ORM.","Pagine result sets grandes; prefira a paginação keyset (seek) ao OFFSET em grandes volumes de dados.","Deixe a lógica de negócio para a consulta tanto quanto possível; não busque a tabela inteira para filtrar/agregar na aplicação.","Examine o plano real e as estimativas de linhas com EXPLAIN ANALYZE; elimine full table scans e estimativas erradas.","Apoie consultas de agregação frequentes e caras com uma materialized view ou uma tabela de resumo pré-calculada."],"level":"junior"},{"id":"large-table-management","title":"Gerenciamento de tabelas grandes (arquivamento/particionamento)","category":"Desempenho","summary":"Tabelas em crescimento contínuo deixam consultas, manutenção e backups mais lentos com o tempo; mantenha-as sob controle com arquivamento e particionamento.","points":["Separe dados quentes (ativos) de dados frios (históricos); mova os dados antigos para uma tabela de arquivo ou storage barato.","Particione a tabela por data/faixa; expurgue dados antigos instantaneamente com DROP de partição em vez de DELETE.","Faça deletes/updates grandes em lotes pequenos; um único DELETE gigante gera locks, bloat de WAL e bloat de tabela.","Monitore regularmente o bloat e o tamanho de tabelas/índices; aplique reorganização online (VACUUM/reorg) quando necessário.","Mantenha os índices adequados às consultas frequentes; manter índices desnecessários em uma tabela grande é muito caro."],"level":"senior"},{"id":"caching-strategy","title":"Estratégia de cache","category":"Desempenho","summary":"Um cache reduz a latência e a carga tirando as leituras repetidas do banco de dados; o verdadeiro desafio é a invalidação.","points":["Use o cache para dados caros, lidos com frequência e que mudam pouco; não tente colocar tudo em cache.","Escolha uma estratégia de invalidação: TTL, atualização na escrita (write-through) ou exclusão na escrita (write-invalidate).","Defina a tolerância a dados desatualizados com base nas regras de negócio; não dependa do cache onde for exigida consistência estrita.","Evite cache stampedes (muitas requisições preenchendo um cache vazio ao mesmo tempo) com locking ou request coalescing.","Monitore o cache hit ratio; um hit ratio baixo mostra que o cache não está agregando valor.","Um cache é uma camada de aceleração, não um estado durável; o sistema deve continuar funcionando corretamente quando o cache for perdido."],"level":"senior"},{"id":"statistics-maintenance","title":"Disciplina de estatísticas e manutenção","category":"Operações","summary":"Estatísticas atualizadas e manutenção regular garantem que o planejador de consultas tome as decisões certas e que o desempenho não se degrade com o tempo.","points":["Mantenha as estatísticas atualizadas (ANALYZE / auto-analyze); estatísticas desatualizadas empurram o planejador para um plano errado.","Execute VACUUM/limpeza regularmente para remover linhas mortas e bloat; isso é crítico em engines MVCC.","Monitore a fragmentação dos índices e reconstrua-os online quando necessário (REINDEX/rebuild).","Atualize as estatísticas manualmente após uma carga em massa; evite que o planejador trabalhe com a distribuição antiga.","Agende os jobs de manutenção em janelas de baixo tráfego, monitore sua duração/impacto e automatize-os.","Fique atento a regressões de plano (uma consulta que fica lenta de repente); a atualização das estatísticas é a primeira coisa a verificar."],"level":"senior"}]},"guide/best-practices-2.json":{"topics":[{"id":"iac","title":"Gerencie a infraestrutura como código (IaC)","category":"Operações","summary":"Servidores de banco de dados, rede e configuração devem ser definidos em código versionado, e não à mão, para que os ambientes sejam reproduzíveis, auditáveis e reversíveis.","points":["Mantenha as definições de servidor, parameter group, rede e usuários como código com ferramentas como Terraform/Pulumi/CloudFormation, sob controle de versão.","Proíba alterações manuais pelo console (click-ops); execute a detecção de drift e corrija os recursos que divergirem do código.","Gerencie as diferenças entre ambientes (dev/stage/prod) com variáveis; construa ambientes semelhantes ao de produção a partir do mesmo módulo.","Mantenha o arquivo de state remoto e com lock (ex.: S3 + DynamoDB lock); não deixe segredos vazarem para o state em texto puro.","Revise as alterações por um fluxo de plan/apply; coloque etapas de aprovação antes da produção."],"level":"senior"},{"id":"automation-idempotency","title":"Automação e idempotência","category":"Operações","summary":"As tarefas operacionais devem deixar de ser comandos repetidos manualmente e se tornar automações idempotentes que produzem o mesmo resultado não importa quantas vezes sejam executadas.","points":["Escreva todo script de forma idempotente, para que executá-lo novamente não falhe nem corrompa o estado (ex.: CREATE IF NOT EXISTS em vez de CREATE).","Vincule as tarefas de manutenção recorrentes (backup, limpeza, estatísticas) a automações agendadas e com log; não as deixe para execuções manuais.","Inclua nos scripts verificações explícitas de pré-condições e saídas seguras; executar novamente uma operação pela metade deve concluí-la a partir de onde parou.","Execute a automação a partir de código (Ansible/scripts + CI); não dependa de alguém digitando comandos em um terminal em produção.","Ofereça suporte a dry-run para operações críticas; mostre o impacto antes de aplicá-lo."],"level":"senior"},{"id":"observability","title":"Observabilidade (métricas/logs/traces)","category":"Operações","summary":"A observabilidade combina métricas, logs e traces distribuídos para que você possa passar de 'o que aconteceu' para 'por que aconteceu'.","points":["Colete os três sinais juntos: métricas (tendências), logs (contexto), traces (caminho da requisição); nenhum deles sozinho revela a causa raiz.","Rastreie as consultas de ponta a ponta: correlacione os traces da aplicação com a latência do banco de dados (usando padrões como OpenTelemetry).","Emita logs estruturados (JSON) com um correlation/trace id; logs em texto livre dificultam a busca.","Evite labels de alta cardinalidade; mantenha sob controle a explosão de cardinalidade e o custo.","Defina SLOs e acompanhe o error budget; vincule a observabilidade aos objetivos de negócio."],"level":"senior"},{"id":"alerting-strategy","title":"Estratégia de alertas (pouco ruído, acionáveis)","category":"Operações","summary":"Uma boa estratégia de alertas acorda uma pessoa apenas para condições reais e acionáveis; o ruído causa fadiga de alertas e esgotamento.","points":["Alerte sobre o impacto e a experiência do usuário (violações de SLO), e não sobre sintomas; não acione o plantão a cada oscilação de métrica.","Todo alerta precisa de um responsável, uma condição e um runbook claros; um alerta sem ação definida não tem valor.","Use histerese e duração (for: 5m) nos limites; evite que picos momentâneos disparem alertas.","Separe o acionamento do plantão (paging) das notificações (ticket/e-mail); acione o plantão apenas para o que exige intervenção imediata.","Revise os alertas regularmente; corrija ou remova os que disparam constantemente e são ignorados.","Cubra sempre os desastres silenciosos, como falhas de backup, discos cheios e replicação parada."],"level":"senior"},{"id":"dr-testing","title":"Disciplina de exercícios de DR/failover","category":"Backup e HA","summary":"Um plano de recuperação de desastres só é confiável quando validado com exercícios regulares e realistas; um plano não testado é apenas uma suposição.","points":["Agende exercícios de failover e de restore e execute-os periodicamente; um plano em papel revisado uma vez por ano não basta.","Meça o RTO e o RPO reais em cada exercício; relate o desvio em relação à meta e melhore.","Ensaie o failover planejado em um ambiente semelhante ao de produção com tráfego real; não se limite a iniciar e parar o standby.","Simule cenários como perda de região, falha de disco e corrupção de dados com game days.","Registre as lições aprendidas no runbook após cada exercício; transforme em automação os passos lembrados de memória."],"level":"expert"},{"id":"blue-green-deploy","title":"Deploy blue-green / zero downtime","category":"Operações","summary":"Os deploys blue-green e canary executam a nova versão ao lado da antiga e deslocam o tráfego gradualmente, minimizando indisponibilidade e risco.","points":["Mantenha dois ambientes de produção (blue/green); faça o deploy da nova versão no ocioso, valide-a e então alterne o tráfego em um único passo.","Se algo der errado, alterne o tráfego de volta para o ambiente antigo imediatamente; o rollback não deve exigir um novo deploy.","Com canary, envie uma pequena porcentagem do tráfego para a nova versão, observe as métricas e aumente gradualmente.","Desacople o schema do banco de dados do deploy: as duas versões do código devem funcionar com o mesmo schema (expand-contract).","Defina antecipadamente os health checks e os limites de rollback automático; reduza o tempo gasto esperando decisões humanas manuais."],"level":"senior"},{"id":"expand-contract","title":"Alterações de schema compatíveis com versões anteriores (expand-contract)","category":"Design","summary":"O padrão expand-contract divide uma alteração de schema em adicionar (expand), depois migrar e, por fim, remover o antigo (contract), permitindo uma transição sem indisponibilidade.","points":["Expanda primeiro: adicione a nova coluna/tabela de forma compatível com versões anteriores (nullable ou com default) sem quebrar a antiga.","Faça o deploy da aplicação de modo que funcione tanto com o schema antigo quanto com o novo, usando dual-write ou dual-read.","Migre os dados para a nova estrutura em segundo plano, em lotes pequenos, e valide-os; não gere locks com uma única migração gigante.","Faça o contract somente depois que todas as instâncias tiverem passado para a nova versão e a validação estiver concluída: remova a coluna/código antigo.","Faça cada etapa em um deploy separado; nunca 'adicione e remova o antigo ao mesmo tempo', ou o rollback se torna impossível.","Adicione NOT NULL e outras constraints por último, quando os dados estiverem consistentes."],"level":"expert"},{"id":"secrets-management","title":"Gerenciamento de segredos (senhas/chaves)","category":"Segurança","summary":"Senhas de banco de dados, chaves de API e connection strings não devem ser incorporadas ao código ou à configuração; devem ser armazenadas com segurança e rotacionadas com um gerenciador de segredos central.","points":["Não incorpore segredos em código, repositórios, arquivos env ou imagens; use um secret store como Vault, AWS Secrets Manager ou KMS.","Injete os segredos nas aplicações em tempo de execução; não os deixe em disco em texto puro.","Faça a rotação de senhas e chaves regularmente; sempre que possível, use credenciais de curta duração geradas automaticamente.","Conceda acesso com menor privilégio e audit log; deve ser possível rastrear quem acessou qual segredo e quando.","Varra a base de código em busca de segredos vazados (git-secrets, trufflehog); revogue e rotacione um segredo vazado imediatamente.","Torne o acesso humano temporário e baseado em aprovação (just-in-time), em vez de pessoal e permanente."],"level":"senior"},{"id":"cost-optimization","title":"Otimização de custos na nuvem","category":"Operações","summary":"O custo de bancos de dados na nuvem pode ser reduzido significativamente sem sacrificar o desempenho por meio de right-sizing, tiering de storage e limpeza de recursos não utilizados.","points":["Dimensione as instâncias com base nas métricas reais de uso; reduza os servidores com utilização constantemente baixa (right-sizing).","Use capacidade reservada/savings plans para a carga base previsível; deixe a carga variável em on-demand.","Mova os dados frios para um tier de storage mais barato; separe os dados quentes dos raramente acessados.","Limpe os recursos não utilizados: snapshots órfãos, réplicas ociosas e bancos de teste abandonados são vazamentos de custo.","Atribua os custos a responsáveis com tags e configure alertas de orçamento; veja as surpresas imediatamente, não no fim do mês.","Revise a retenção de backups e o número de réplicas em relação às necessidades do negócio; o excesso é risco e custo."],"level":"senior"},{"id":"multi-tenancy","title":"Design multi-tenant","category":"Design","summary":"Em sistemas multi-tenant, o modelo de isolamento (tabela compartilhada, schema separado, banco de dados separado) é uma troca deliberada entre segurança, custo e escalabilidade.","points":["Escolha o modelo de isolamento: tabela compartilhada (tenant_id), schema por tenant ou banco de dados por tenant; cada um tem um equilíbrio diferente entre custo e isolamento.","No modelo compartilhado, aplique um filtro de tenant_id em toda consulta; garanta a ausência de vazamentos no nível do engine com row-level security (RLS).","Coloque tenant_id primeiro nos índices relevantes; evite scans entre tenants e hot spots.","Aplique limites de recursos e cotas contra o efeito noisy neighbor; um tenant não deve deixar os outros sem recursos.","Projete desde o início um caminho (migração de tenant) para mover tenants grandes ou premium para um schema/banco de dados separado.","Pense em backup, exclusão e portabilidade de dados por tenant; você deve conseguir atender a pedidos de exclusão da KVKK/GDPR."],"level":"expert"},{"id":"time-series-design","title":"Design de dados de séries temporais","category":"Design","summary":"Dados de séries temporais são especiais devido ao alto volume de escrita e aos padrões de consulta baseados em tempo; devem ser projetados com particionamento por data, rollups e política de retenção.","points":["Divida os dados com particionamento RANGE baseado em timestamp; expurgue dados antigos de forma barata com DROP de partição.","Em vez de acumular os dados brutos como estão, produza resumos em intervalos regulares (rollup/continuous aggregate); deixe as consultas rodarem rápido sobre os resumos.","Coloque primeiro no índice os componentes de tempo e de tag (tag/origem); o padrão típico de consulta é 'origem específica, intervalo específico'.","Escolha a ferramenta certa: em alto volume, engines de séries temporais como TimescaleDB e ClickHouse podem ser muito mais eficientes que os relacionais.","Defina a política de retenção desde o início; mantenha os dados brutos por pouco tempo e os agregados por muito tempo.","Armazene sempre o tempo em UTC; trate o horário local e as mudanças de horário de verão na camada de consulta."],"level":"senior"},{"id":"event-sourcing","title":"Fundamentos de event sourcing / CQRS","category":"Design","summary":"O event sourcing registra não o estado, mas os eventos que o alteram; o CQRS separa os modelos de leitura e escrita para que cada um escale de forma independente.","points":["Em vez de sobrescrever o estado atual, acumule um fluxo de eventos imutável; derive o estado atual reproduzindo os eventos.","Com CQRS, separe o modelo de escrita (commands) do modelo de leitura (consultas); acelere o lado de leitura com projeções desnormalizadas.","Versione o schema dos eventos e evolua-o de forma compatível com versões anteriores; nunca exclua eventos antigos, converta-os para a nova versão com upcasting.","Aceite que as projeções de leitura terão consistência eventual e considere o atraso no design.","Faça snapshots para evitar o custo de reproduzir um longo fluxo de eventos desde o início todas as vezes.","Use esse padrão não em todo lugar, mas em domínios que precisam de trilha de auditoria, regras de negócio complexas e histórico ao longo do tempo; não subestime a complexidade que ele traz."],"level":"expert"},{"id":"data-retention","title":"Política de retenção e arquivamento de dados","category":"Operações","summary":"Nem todos os dados são mantidos para sempre; uma política definida de retenção e arquivamento, baseada em requisitos legais, de negócio e de custo, traz compliance e desempenho.","points":["Defina o período de retenção de cada tipo de dado com base nos requisitos de negócio e legais (KVKK/GDPR); um vago 'guardar por precaução' não é uma política.","Arquive ou exclua automaticamente os dados expirados; não deixe para a limpeza manual, que é esquecida enquanto as tabelas incham.","Mantenha os dados quentes em storage rápido e os arquivos em storage barato/frio; faça tiering pela frequência de acesso.","Projete desde o início o mecanismo para atender a pedidos de exclusão/anonimização de dados pessoais (direito ao esquecimento).","Mantenha os dados arquivados recuperáveis e consultáveis quando necessário; arquivado não deve significar inacessível.","Registre as exclusões no audit log; o que foi excluído, quando e por quê deve ser rastreável."],"level":"senior"},{"id":"change-management","title":"Gestão de mudanças e segurança em produção","category":"Operações","summary":"Toda alteração em um banco de dados de produção deve ser revisada, reversível e rastreável; a intervenção manual descontrolada é a causa mais comum de indisponibilidade.","points":["Não execute DDL/DML ad hoc à mão em produção; toda alteração deve passar por uma migration ou script revisado por pares.","Aplique as alterações em uma janela de baixo tráfego com um plano de rollback pronto; não mexa na produção sem planejamento.","Ensaie os comandos arriscados primeiro em um ambiente semelhante ao de produção com volumes de dados reais; meça sua duração e o impacto de locks.","Restrinja e audite o acesso à produção: quem executou qual comando e quando deve ser registrado em log (acesso just-in-time).","Antes de um delete/update, verifique a cláusula WHERE e o número de linhas afetadas; execute dentro de uma transação e confirme antes com um SELECT.","Vincule as alterações a um calendário e a uma comunicação; não surpreenda outras equipes com alterações em produção não anunciadas."],"level":"senior"}]},"guide/best-practices-3.json":{"topics":[{"id":"plan-reading-expert","title":"Como ler um plano de execução","category":"Desempenho","summary":"Um plano de execução mostra as estimativas do otimizador e os operadores físicos que ele escolheu; o gargalo se esconde no desvio entre as contagens de linhas estimadas e reais.","points":["Diferencie os métodos de acesso: Full/Table Scan é para leituras amplas em tabelas grandes, Index Seek/Range Scan para predicados seletivos, Index Full Scan para leituras ordenadas; Rows Removed by Filter ou a divisão entre predicate/access mostra onde a seletividade se perde.","Adeque o método de join à carga de trabalho: Nested Loop é ideal para um conjunto externo pequeno + conjunto interno indexado, Hash Join para equi-joins grandes, Merge Join para dois conjuntos já ordenados; uma escolha errada geralmente resulta de uma estimativa de cardinalidade ruim.","Procure erros de estimativa de cardinalidade: compare as linhas estimadas e reais com EXPLAIN ANALYZE (PG), DBMS_XPLAN ALLSTATS LAST (Oracle) ou SET STATISTICS PROFILE (MSSQL); um desvio acima de 10x sugere que a escolha do plano pode estar fundamentalmente errada.","Leia o plano pelo custo real: encontre o operador que consome mais tempo/leituras lógicas (logical reads, buffers); a unidade de 'custo' do otimizador é uma estimativa, não o gargalo real.","Capture os avisos de spill/espaço temp: um operador Hash/Sort que não cabe na memória e transborda para o disco (PG 'Sort Method: external merge', no MSSQL Sort/Hash Warning com SpillToTempDb no plano) indica work_mem/área de sort insuficiente.","Leia a árvore de operadores de dentro para fora e de baixo para cima: os nós internos executam primeiro e as linhas fluem para cima; calcule o custo total por operador multiplicando loops pelo actual time."],"level":"expert"},{"id":"parameter-sniffing-deep","title":"Parameter sniffing e bind peeking","category":"Desempenho","summary":"O otimizador constrói e armazena em cache um plano com base no valor do parâmetro da primeira chamada; quando valores posteriores com distribuição diferente herdam esse plano, o desempenho pode mudar drasticamente.","points":["Reconheça o sintoma: a mesma consulta é rápida com alguns parâmetros e muito lenta com outros; isso mostra que o plano em cache foi compilado para um 'primeiro' valor atípico.","O risco é alto em colunas com distribuição assimétrica; os histogramas tornam o otimizador sensível ao valor, enquanto um único plano em cache o mantém insensível ao valor, e essa tensão é a origem do problema.","No MSSQL, OPTION (RECOMPILE) constrói um plano a cada execução, OPTIMIZE FOR UNKNOWN escolhe um plano equilibrado com base na densidade média e OPTIMIZE FOR (@p = value) fixa um valor típico.","No Oracle, o adaptive cursor sharing e os cursores bind-aware produzem planos diferentes para valores assimétricos; no PG, a escolha entre plano custom e genérico é controlada com plan_cache_mode.","Para uma correção permanente, separe os planos por valor: projete divisão de instruções, índices filtrados/parciais ou um caminho de acesso dedicado para valores muito atípicos.","Em OLTP, RECOMPILE em excesso acrescenta custo de CPU e de compilação (hard parse); meça e mantenha o equilíbrio nas consultas executadas com frequência."],"level":"expert"},{"id":"plan-stability","title":"Estabilidade de planos: baselines, hints e plan guides","category":"Desempenho","summary":"Mecanismos de persistência específicos de cada engine são usados para congelar planos verificados de consultas críticas e evitar regressões de plano inesperadas em mudanças de estatísticas/versão.","points":["No Oracle, fixe os planos aprovados com SQL Plan Baselines (SPM); novos planos são apenas coletados como candidatos até serem 'aceitos' e são verificados de forma controlada com evolve.","No MSSQL, detecte regressões de plano com o Query Store e force o plano reconhecidamente bom com 'Force Plan'; o Automatic Plan Correction pode automatizar isso.","O PostgreSQL não tem congelamento de planos nativo; a estabilidade vem da extensão pg_hint_plan ou de reescritas de consultas, extended statistics e design de índices.","Use hints como último recurso, com justificativa e comentários; um hint pressupõe o schema físico e a distribuição dos dados, e se torna prejudicial quando eles mudam.","Audite periodicamente o inventário de baselines/planos forçados; planos fixados podem perder otimalidade com o crescimento dos dados, então não caia na armadilha do 'estável, mas lento'.","Capture os planos das consultas críticas antes de um upgrade de versão; prepare baselines como rede de segurança contra mudanças de comportamento do otimizador."],"level":"expert"},{"id":"latch-mutex-contention","title":"Contenção de latch, mutex e spinlock","category":"Desempenho","summary":"Latches/mutexes são locks leves que protegem estruturas em memória; sob alta concorrência, a contenção neles queima CPU em loops de spinlock e impede o escalonamento.","points":["Diferencie locks de latches: locks protegem dados lógicos (linha/tabela) durante a transação, latches protegem estruturas físicas de memória (buffers, hash chains) por microssegundos; seus métodos de diagnóstico são diferentes.","No Oracle, a contenção do latch 'cache buffers chains' geralmente aponta para um hot block; uma tabela pequena lida com frequência ou a borda de um índice monotonicamente crescente (right-hand index) é uma causa comum.","Inserts com chaves sequencialmente crescentes (identity/sequence) causam contenção na última página/bloco (hot page, PAGELATCH); distribua-os com hash partitioning, um reverse-key index ou uma chave aleatória.","No MSSQL, monitore as estatísticas de spinlock e as esperas PAGELATCH_*; para contenção de alocação no tempdb, use vários arquivos de dados e uma configuração adequada do tempdb.","A contenção de spinlock aparece como CPU alta com throughput baixo; a correção é reduzir a contenção no nível do código/arquitetura, e adicionar hardware muitas vezes piora a situação.","A consciência de NUMA e a limitação do número de conexões (pooling) reduzem a contenção de latches; paralelismo excessivo pode aumentar a pressão sobre os latches."],"level":"expert"},{"id":"wait-event-methodology","title":"Metodologia de análise de wait events","category":"Desempenho","summary":"Gerencie o desempenho medindo onde o sistema passa seu tempo esperando, e não adivinhando; a análise de esperas top-down é o método científico que restringe o gargalo de forma sistemática.","points":["Divida o DB time em seus componentes: separe o tempo gasto em CPU do tempo de espera; comece pelo maior componente e não se desvie para micro-otimizações.","Encontre o principal wait event com ASH/AWR e 'Top Wait Events' no Oracle, pg_stat_activity + pg_wait_sampling no PG e sys.dm_os_wait_stats e Query Store no MSSQL.","Interprete a wait class: esperas de I/O apontam para storage/planos, esperas de lock para o design de concorrência, esperas de latch para hot spots, e esperas de rede/commit para problemas de configuração.","Desça até o nível de sessão/consulta: parta do total de esperas, vá para o SQL que mais contribui e depois para o plano desse SQL para isolar a causa (drill-down).","Vincule a medição à janela da carga de trabalho: tire a diferença (delta) dos contadores cumulativos entre dois pontos; os totais enganam, o que importa são as taxas e os intervalos de tempo.","Filtre do ruído as esperas idle/benignas; nem toda espera é um problema, o que importa são as esperas de foreground que contribuem para o tempo de resposta do usuário."],"level":"expert"},{"id":"plan-regression-detection","title":"Detecção de regressões de plano de execução","category":"Desempenho","summary":"Uma consulta que fica lenta de repente geralmente é causada por uma mudança de plano, e não de código; detectar regressões de forma proativa é mais barato que apagar incêndios de forma reativa.","points":["Mantenha e compare o histórico de planos: acompanhe as mudanças de plano e as tendências de duração/recursos para o mesmo sql_id/query_hash com o Query Store do MSSQL e o AWR/SQL Monitor do Oracle.","Identifique o gatilho da regressão: atualizações de estatísticas, crescimento do volume de dados, upgrades de versão, alterações de parâmetros ou índices removidos são as causas mais comuns.","Configure alertas automáticos: dispare um alerta quando o plan hash mudar e a duração média/leituras lógicas excederem um limite; acompanhe métricas por execução, não cumulativas.","Prepare um caminho de rollback rápido: fixe temporariamente o plano reconhecidamente bom com Force Plan (MSSQL) ou uma SQL Plan Baseline (Oracle) e corrija a causa raiz depois.","Para regressões causadas por estatísticas, examine as estatísticas bloqueadas/atuais e a atualidade dos histogramas; a coleta automática de estatísticas pode estar agendada em horários críticos.","Execute testes de regressão antes de um upgrade: reproduza uma carga representativa no otimizador antigo e no novo e relate as diferenças de plano (uma abordagem semelhante ao SPA do Oracle)."],"level":"expert"},{"id":"mvcc-vacuum-internals","title":"MVCC e internals de vacuum/undo","category":"Internals","summary":"O MVCC evita bloqueios entre leitores e escritores mantendo versões antigas das linhas; como e onde essas versões são mantidas (undo vs dentro da tabela) determina a estratégia de manutenção.","points":["No PostgreSQL, as versões antigas permanecem na própria tabela como dead tuples; o VACUUM as limpa, caso contrário ocorrem bloat e crescimento dos índices.","O Oracle e o MySQL/InnoDB mantêm as versões antigas em segmentos de undo/rollback; se uma leitura de longa duração esgotar o undo, aparecem erros como 'ORA-01555 snapshot too old'.","Ajuste o autovacuum à carga de trabalho: reduza o scale factor e o cost delay em tabelas com muitos updates/deletes; dê configurações por tabela às tabelas mais agressivas.","Mantenha o visibility map saudável; os index-only scans e o rastreamento de tuplas congeladas dependem dele, e o desempenho se degrada se ele for negligenciado.","Monitore o risco de transaction ID wraparound: acompanhe a métrica datfrozenxid/age no PG e evite que o vacuum agressivo/anti-wraparound entre em ação durante o horário comercial.","Incentive os updates HOT (Heap-Only Tuple): updates que não alteram uma coluna indexada são feitos no próprio lugar, sem aumentar o índice; um fillfactor adequado favorece isso."],"level":"expert"},{"id":"wal-redo-log-mechanics","title":"Mecânica de WAL/redo/log de transações","category":"Internals","summary":"A durabilidade é obtida gravando a alteração no log antes que as páginas de dados sejam gravadas em disco; a taxa e o tamanho do fluxo de log determinam tanto a durabilidade quanto o desempenho de escrita.","points":["Entenda o princípio write-ahead: para que um commit retorne, basta que os registros de log relacionados estejam em storage durável; as páginas de dados sujas são gravadas depois, de forma preguiçosa.","Ajuste o group commit e o comportamento de log flush: equilibre a frequência de fsync com os requisitos de durabilidade da carga de trabalho usando commit_delay/synchronous_commit no PG e o comportamento do log writer no Oracle.","Monitore a taxa de geração de log (geração de WAL/redo); um aumento repentino aponta para atualizações em massa, full-page images após um checkpoint (full_page_writes/FPI) ou manutenção de índices, e aumenta o atraso do DR.","O log é fonte não só para a recuperação, mas também para replicação e CDC; a replicação lógica e o WAL shipping se alimentam desse fluxo, então projete a política de arquivamento/limpeza de acordo.","Separe o disco de log do disco de dados e coloque-o em storage de baixa latência; as gravações de log são sequenciais e sensíveis à latência, e o throughput de commits depende diretamente delas.","Proteja-se contra o crescimento descontrolado do log: no MSSQL use o recovery model correto e backups de log regulares; no PG garanta que o arquivamento/replication slots não fiquem atrasados."],"level":"expert"},{"id":"buffer-pool-management","title":"Gerenciamento e eviction do buffer/shared pool","category":"Internals","summary":"O buffer pool reduz o I/O de disco mantendo os dados quentes em memória; o algoritmo que decide qual página é removida e quando governa o hit ratio e a estabilidade.","points":["Não use o buffer cache hit ratio como única meta; mesmo uma proporção alta pode esconder a latência das leituras físicas, então observe também o I/O absoluto e o tempo de espera.","Entenda o algoritmo de eviction: contra o LRU puro sendo poluído por scans sequenciais, o PG usa clock-sweep, o Oracle uma variante de touch-count/LRU e o InnoDB um LRU com inserção no ponto médio (midpoint insertion).","Evite que scans grandes e pontuais expulsem os dados quentes do pool (cache pollution); proteja-os com buffer pools separados ou estratégias de acesso amigáveis a scans.","Gerencie a proporção de páginas sujas e a pressão de escrita: páginas sujas demais causam picos de I/O no checkpoint, escrita agressiva demais gera I/O desnecessário; meça o equilíbrio.","Dimensione a memória para o working set; o objetivo é cobrir o conjunto acessado ativamente, não o total de dados, e o superdimensionamento traz retornos decrescentes.","No shared pool do Oracle, monitore a contenção no library/dictionary cache e os hard parses frequentes; usar bind variables em vez de SQL com literais reduz a pressão no shared pool."],"level":"expert"},{"id":"checkpoint-tuning","title":"Tuning de checkpoint","category":"Internals","summary":"Um checkpoint reduz o tempo de recuperação gravando as páginas sujas em disco; checkpoints frequentes demais criam picos de I/O e raros demais criam recuperações longas, e esse trade-off precisa ser ajustado.","points":["Equilibre o tempo de recuperação com o I/O em tempo de execução: checkpoints raros significam menos carga de escrita, mas crash recovery mais longo; checkpoints frequentes, o contrário.","No PG, distribua os checkpoints no tempo com checkpoint_timeout e max_wal_size; suavize o pico de I/O espalhando as gravações ao longo do intervalo com checkpoint_completion_target.","O indirect checkpoint do MSSQL (target recovery time) oferece escrita contínua em segundo plano; torna a latência previsível ao evitar grandes ondas repentinas de checkpoint.","Correlacione a frequência de checkpoints com a taxa de geração de log/WAL; em períodos de escrita intensa, monitore se é o gatilho por tamanho, e não o por tempo, que está sendo acionado.","full_page_writes (PG) grava em log a página inteira na primeira alteração após um checkpoint; se os checkpoints forem frequentes demais o volume de WAL explode, aumentando o custo de DR e de disco.","Capture os sintomas de 'checkpoint sink': aumento da latência de escrita e esperas de fsync durante os checkpoints; revise a fila e a distribuição do storage."],"level":"expert"},{"id":"statistics-strategy","title":"Estratégia de coleta de estatísticas","category":"Internals","summary":"A qualidade das decisões do otimizador depende da atualidade e da resolução das estatísticas; a taxa de amostragem, os histogramas e as extended statistics determinam as estimativas de cardinalidade.","points":["Escolha a taxa de amostragem com base no tamanho e na assimetria dos dados: uma amostra pequena demais produz estimativas erradas em distribuições assimétricas, uma grande demais gera custo de coleta desnecessário.","Modele a assimetria com histogramas: default_statistics_target no PG, histogramas FREQUENCY/HYBRID no Oracle e os histogramas de estatísticas do MSSQL expõem ao otimizador os valores frequentes e desbalanceados.","Capture a correlação entre colunas com extended statistics: CREATE STATISTICS (ndistinct/dependencies) no PG e extended stats no Oracle corrigem erros de estimativa em colunas interdependentes.","Desacople os horários de coleta da carga de trabalho: evite que o job automático de estatísticas/gather rode em horários críticos e cause I/O e instabilidade de planos.","Gerencie o risco de estatísticas desatualizadas em tabelas que crescem rápido; atualizações automáticas baseadas em limites podem atrasar, então adicione coleta manual/agendada para as tabelas críticas.","Saiba que mudanças nas estatísticas podem causar regressões de plano; em ambientes críticos, bloqueie as estatísticas (locked stats) ou publique-as de forma controlada com pending publish."],"level":"expert"},{"id":"partition-pruning-join","title":"Partition pruning e partition-wise joins","category":"Escala/Arquitetura","summary":"O particionamento não apenas divide uma tabela; o ganho real é que as consultas nunca leem partições irrelevantes (pruning) e os joins rodam em paralelo por partição.","points":["Escolha a chave de partição com base no filtro mais frequente e seletivo; o pruning só funciona quando o predicado da consulta inclui a chave de partição, caso contrário todas as partições são lidas.","Diferencie pruning estático e dinâmico: predicados constantes eliminam partições em tempo de compilação, valores de bind/join em tempo de execução (runtime pruning); verifique o plano de acordo.","Para partition-wise joins, particione as duas tabelas pela mesma chave com um esquema compatível; o otimizador reduz um join grande a pequenos joins partição por partição e os paraleliza.","Equilibre o número e a granularidade das partições: partições demais significam custo de metadados e de planejamento, poucas demais significam pruning fraco; dimensione-as conforme o padrão de acesso.","Combine o gerenciamento do ciclo de vida com o particionamento: faça DETACH/DROP ou arquive as partições antigas; isso oferece limpeza instantânea e com pouco log em vez de DELETE.","Lembre-se de que funções/conversões de tipo ou expressões que escondem a chave quebram o pruning; verifique o número de partições lidas com EXPLAIN."],"level":"expert"},{"id":"shard-key-selection","title":"Escolha da shard key e hot spots","category":"Escala/Arquitetura","summary":"A shard key determina o destino de um sistema distribuído; uma escolha ruim concentra a carga em um único nó (hot shard), impede o escalonamento e torna caras as consultas cross-shard.","points":["Escolha uma chave de alta cardinalidade que distribua a carga uniformemente; uma chave de baixa cardinalidade ou temporal/monotonicamente crescente concentra a carga em um único shard e cria um hot spot.","Projete a chave para que as consultas mais frequentes sejam resolvidas em um único shard; consultas cross-shard (scatter-gather) multiplicam a latência e o custo de coordenação.","O hash sharding equilibra a carga, mas espalha as consultas por faixa; o range sharding é bom para consultas por faixa, mas aumenta o risco de hot spot; escolha com base no padrão de acesso.","Minimize a redistribuição ao adicionar/remover nós com consistent hashing; um hash por módulo fixo move quase todos os dados quando o número de nós muda.","Projete o plano de resharding desde o início; alterar a chave depois é caro e arriscado, então modele o cenário de crescimento antecipadamente.","Ao dividir por tenant/cliente, prepare um shard dedicado ou uma estratégia de subparticionamento (split) para que um tenant gigante (whale) não encha um único shard."],"level":"expert"},{"id":"read-write-splitting","title":"Separação de leitura e escrita e roteamento para réplicas","category":"Escala/Arquitetura","summary":"Rotear leituras para réplicas alivia o primário de escrita; mas, como o replication lag pode quebrar as garantias de consistência, o roteamento deve ser feito deliberadamente.","points":["Ao distribuir a carga de leitura para as réplicas, monitore o replication lag continuamente; uma réplica desatualizada pode mostrar dados antigos aos usuários.","Roteie para o primário os fluxos que exigem read-your-writes (o usuário que escreveu lendo imediatamente) ou garanta uma réplica atualizada com causal reads/tokens.","Faça o roteamento na camada de infraestrutura, não na aplicação: distribua de forma transparente com um proxy/router (ProxySQL para MySQL; para PG, Pgpool-II ou HAProxy com endpoints separados de leitura/escrita, já que o PgBouncer não separa leituras e escritas; no MSSQL, read-only routing via application intent).","Remova uma réplica do pool quando o limite de atraso for excedido; enviar leituras a uma réplica com atraso alto gera inconsistência de dados sob a ilusão de 'escalonamento'.","Isole em uma réplica dedicada as leituras pesadas e tolerantes a atraso, como analytics/relatórios; proteja as réplicas OLTP dessa carga.","Teste se o roteamento de leituras se atualiza automaticamente em um cenário de failover; um router que não conhece o novo primário causa split-brain ou indisponibilidade."],"level":"expert"},{"id":"connection-pool-sizing","title":"Matemática de dimensionamento do pool de conexões","category":"Escala/Arquitetura","summary":"O tamanho do pool é determinado por cálculo com base na lei de Little e no número de núcleos, e não por intuição; conexões demais reduzem o throughput por contenção e troca de contexto.","points":["Aplique a lei de Little: concorrência necessária ≈ taxa de requisições (throughput) × tempo médio de processamento; derive a concorrência alvo de valores medidos, não de suposições.","Um pool pequeno muitas vezes é mais rápido: quando as conexões ativas excedem o paralelismo físico de núcleos/disco, a troca de contexto da CPU e a contenção de latches reduzem o throughput.","Como ponto de partida aproximado, use um pool principal com um número de conexões próximo ao número de núcleos (ex.: poucas conexões reais por trás do PgBouncer) e ajuste medindo sob carga.","Planeje o pool do lado da aplicação junto com o max_connections do banco de dados; N instâncias da aplicação × tamanho do pool não devem exceder o limite do banco.","Em engines com alto custo de processo por conexão, como o PG, use PgBouncer/transaction pooling; toda conexão custa memória e escalonamento.","Monitore a saturação do pool, o tempo de espera na fila e os timeouts; uma fila em crescimento constante sinaliza um gargalo ou subdimensionamento, então não aumente o pool às cegas."],"level":"expert"},{"id":"lock-escalation-deadlock","title":"Lock escalation e padrões de prevenção de deadlocks","category":"Confiabilidade","summary":"Muitos row locks podem escalar para um table lock e acabar com a concorrência; um deadlock é o resultado evitável de uma ordem de locks inconsistente.","points":["Divida as grandes operações em massa que disparam lock escalation (lotes/chunks); bloquear milhões de linhas em uma única transação causa escalation e bloqueios.","O padrão básico para prevenir deadlocks é a ordem de locks consistente: todos os caminhos de código devem bloquear os recursos na mesma ordem (ex.: pela ordem da chave primária).","Mantenha as transações curtas e faça uma única unidade atômica de trabalho; transações com interação do usuário, chamadas remotas ou cálculos longos mantêm locks por tempo desnecessário.","Escolha o nível de isolamento deliberadamente: isolamento desnecessariamente alto causa locks em excesso, desnecessariamente baixo causa anomalias; em engines MVCC as leituras já evitam a maioria dos locks.","Colete os grafos/traces de deadlock (deadlock graph no MSSQL, log_lock_waits no PG, trace no Oracle); registre a vítima e rastreie os padrões recorrentes até a causa raiz.","Implemente lógica de retry: repita de forma idempotente a transação vítima do deadlock; é uma rede de segurança para a contenção inevitável pelo design."],"level":"expert"},{"id":"long-transaction-bloat","title":"Transações longas e gerenciamento de bloat/undo","category":"Confiabilidade","summary":"Uma transação longa deixada aberta bloqueia a limpeza de versões antigas em engines MVCC, iniciando uma cadeia de bloat, pressão de undo e colapso de desempenho.","points":["Monitore e alerte sobre transações de longa duração/abertas: idle in transaction no PG e consultas longas que mantêm undo ativo no Oracle param a limpeza (vacuum/recuperação de undo).","No PG, uma única transação longa impede que o VACUUM remova dead tuples; tabelas e índices incham, e uma sessão 'zumbi' pode deixar todo o banco de dados lento.","Encerre automaticamente as transações travadas com idle_in_transaction_session_timeout e statement_timeout; crie uma linha de defesa contra vazamentos da aplicação.","No Oracle/InnoDB, uma leitura longa esgota o undo e produz 'snapshot too old'; dimensione o espaço/retenção de undo para a consulta mais longa da carga de trabalho.","Divida os jobs em lote com intervalos de commit curtos; uma única transação gigante acumula undo/WAL e prolonga perigosamente o tempo de rollback.","Meça e recupere o bloat existente: meça o bloat com pgstattuple e devolva o espaço e a eficiência dos índices com VACUUM FULL/pg_repack ou uma reorganização online."],"level":"expert"},{"id":"dr-game-day","title":"Exercícios de DR (game day) e validação de RPO/RTO","category":"Confiabilidade","summary":"Um plano de backup e failover não testado é uma suposição; a capacidade de DR só é comprovada medindo RPO/RTO em exercícios realistas.","points":["Derive o RPO e o RTO dos requisitos de negócio e meça-os na prática: o atraso de backup/replicação determina o RPO, o tempo de recuperação + validação determina o RTO; compare a meta com a realidade.","Restaure os backups de forma regular e automática: um backup que nunca foi restaurado é um backup de Schrodinger; sem teste de restore, a afirmação de que existe backup não está verificada.","Planeje exercícios de game day em um ambiente próximo ao de produção com cenários de falha realistas (perda do primário, queda de região, corrupção de dados).","Execute os procedimentos de failover e failback de ponta a ponta; inclua o roteamento de DNS/conexões, a reconexão da aplicação e a promoção da réplica.","Comprove a capacidade de recuperação point-in-time (PITR): teste se você consegue voltar a um momento específico com arquivos de log + backups full em um cenário de corrupção lógica.","Produza a partir de cada exercício o RTO/RPO medido, as surpresas e os itens de ação; atualize o runbook e verifique a melhoria no exercício seguinte."],"level":"expert"},{"id":"observability-slo","title":"Observabilidade e SLOs/golden signals","category":"Confiabilidade","summary":"Para gerenciar o banco de dados pelo impacto no negócio, vincule os golden signals (latência, tráfego, erros, saturação) a SLOs e priorize com um error budget.","points":["Monitore os quatro golden signals: latência, tráfego (throughput), taxa de erros (errors) e saturação; eles resumem a saúde sem entrar na causa raiz.","Meça a latência com percentis (p95/p99), não com médias; a média esconde a latência de cauda e a pior experiência do usuário.","Defina SLOs e um error budget; alerte sobre sintomas (violações de SLO), e não sobre cada oscilação de métrica de baixo nível, para evitar a fadiga de alertas.","Aplique o método USE (Utilization, Saturation, Errors) aos recursos: observe separadamente a saturação de CPU, memória, I/O de disco e pool de conexões.","Correlacione o monitoramento entre as camadas: veja a cadeia consulta -> wait event -> saturação de recursos -> métrica de negócio em um único eixo de tempo.","Configure métricas + logs + traces em conjunto; as métricas sozinhas respondem 'o quê', os logs/traces respondem 'por quê', e sem eles o MTTR aumenta."],"level":"expert"},{"id":"least-privilege-roles","title":"Menor privilégio e design de roles","category":"Segurança","summary":"Fazer com que cada conta tenha apenas os privilégios mínimos necessários para seu trabalho reduz o raio de impacto de uma violação; as roles oferecem uma abstração gerenciável em vez de conceder privilégios diretamente.","points":["Conceda privilégios a roles, não a usuários; projete as roles por função (leitor, escritor, DDL, operações) e atribua os usuários às roles, evitando grants diretos.","Dê às contas de aplicação apenas os privilégios de objetos e operações necessários; DDL, SUPERUSER/DBA e privilégios amplos de schema não devem existir em uma conta de aplicação de produção.","Personalize e audite o acesso de administradores humanos: use identidades individuais + acesso elevado sob demanda (JIT/break-glass) em vez de uma conta de administrador compartilhada.","Revogue os privilégios amplos de PUBLIC/padrão; configure default privileges e controles no nível do schema para evitar que direitos padrão vazem para novos objetos.","Revise regularmente as contas privilegiadas (recertificação de acessos); limpe periodicamente as contas não utilizadas, as de funcionários desligados e as com privilégios em excesso.","Aplique a segregação de funções; a mesma pessoa não deve poder alterar a produção e também apagar a trilha de auditoria, então proteja a gravação da auditoria com um privilégio separado."],"level":"expert"},{"id":"encryption-decision","title":"Decisões de criptografia: at-rest, in-transit, TDE","category":"Segurança","summary":"A criptografia é escolhida com base no modelo de ameaças; cada camada protege contra um ataque diferente, e o gerenciamento de chaves muitas vezes é mais crítico que o algoritmo de criptografia.","points":["Esclareça a ameaça: at-rest (discos/backups roubados), in-transit (escuta na rede) e no nível da aplicação (não exposto a ninguém, incluindo os DBAs) são proteções diferentes; decida de qual você precisa.","Para in-transit, exija TLS nas conexões cliente-servidor; não desabilite a validação de certificados, pois isso deixa você exposto a ataques man-in-the-middle (MITM).","Para at-rest, compare o TDE com as opções de criptografia do sistema de arquivos/disco; o TDE protege datafiles e backups, mas não os dados em memória nem o acesso autorizado do DBA.","Para os campos mais sensíveis, use criptografia no nível da aplicação/coluna ou uma abordagem client-side como o Always Encrypted, para que nem o DBA consiga ver o texto puro.","Leve a sério o gerenciamento de chaves: armazene as chaves em um KMS/HSM separado dos dados e planeje a rotação e o controle de acesso; se a chave vazar, a criptografia não vale nada.","Meça o impacto funcional e de desempenho: a indexação/busca é restrita em colunas criptografadas e o TDE acrescenta custo de CPU; tome a decisão como um trade-off medido."],"level":"expert"},{"id":"audit-strategy","title":"Estratégia de auditoria","category":"Segurança","summary":"A trilha de auditoria fornece evidências de eventos de segurança e de requisitos de compliance; o que é registrado, para onde vai a trilha e por quanto tempo é mantida definem o equilíbrio entre ruído e evidência.","points":["Derive o que auditar das ameaças e do compliance: priorize operações privilegiadas, logins/falhas de login, alterações de schema (DDL) e acesso a dados sensíveis.","Não caia na armadilha de registrar tudo; auditoria em excesso degrada o desempenho e afoga o sinal no ruído, então foque nos eventos críticos de forma seletiva e intencional.","Grave a trilha de auditoria em um destino separado e seguro que o DBA de produção não possa modificar (um coletor de logs externo/SIEM); evite a adulteração da trilha por meio da segregação de funções.","Use os recursos do engine: ajuste o nível de detalhe às suas necessidades com Oracle Unified/Fine-Grained Audit, MSSQL SQL Audit e pgAudit no PG.","Defina a retenção de acordo com os requisitos de compliance (KVKK/GDPR/PCI-DSS etc.) e automatize a política de arquivamento/limpeza; preserve a integridade da trilha.","Não se limite a coletar a trilha; revise-a regularmente e vincule-a a alertas: a auditoria só gera valor quando sinaliza anomalias e as transforma em ação, e não como um arquivo morto."],"level":"expert"}]},"guide/best-practices-4.json":{"topics":[{"id":"oracle-rac-cache-fusion","title":"Oracle RAC: Cache Fusion e o interconnect","category":"Oracle","summary":"No RAC, várias instâncias compartilham o mesmo banco de dados; o Cache Fusion mantém a coerência enviando blocos entre os nós pelo interconnect em vez de pelo disco.","points":["Quando uma instância precisa de um bloco que está no buffer cache de outra instância, o Cache Fusion o transfere de RAM para RAM pelo interconnect privado; não o grava em disco para lê-lo de volta (disk ping).","O Global Cache Service (processos GCS/LMS) gerencia a propriedade e o modo dos blocos (shared/exclusive), enquanto o Global Enqueue Service (GES) gerencia locks e enqueues.","Todo bloco tem um nó master; a localização dos blocos é rastreada no Global Resource Directory e pode ser remasterizada com DRM (Dynamic Resource Mastering) com base na intensidade de acesso.","O interconnect exige uma rede dedicada de baixa latência; use Jumbo Frames (MTU 9000) e, se necessário, RDMA/RoCE ou InfiniBand, e nunca o compartilhe com a rede pública.","Os wait events 'gc buffer busy' e 'gc cr/current block busy' indicam contenção em hot blocks; aumentar o CACHE das sequences, usar reverse key indexes ou distribuir a carga com particionamento pode ajudar.","Se a estatística gc blocks lost continuar aumentando, há perda de pacotes no interconnect; revise a NIC, o buffer do switch e os tamanhos de socket buffer (rmem/wmem)."],"level":"expert"},{"id":"oracle-rac-node-eviction","title":"Oracle RAC: node eviction e split-brain","category":"Oracle","summary":"O Clusterware remove do cluster um nó que não responde para evitar split-brain; ele decide com base no network heartbeat, no disk heartbeat e na maioria dos voting disks.","points":["O CSSD monitora dois heartbeats separados: o network heartbeat pelo interconnect (misscount, padrão de 30 s) e o disk heartbeat pelos voting disks (disktimeout, padrão de 200 s).","Em um split-brain, o subcluster sobrevivente (cohort) é determinado pela maioria dos voting disks; por isso o número de voting disks deve ser ímpar (3 ou 5) e eles devem ficar em failure groups separados.","A eviction geralmente é feita por reinicialização do nó ou por fencing sem reboot (reiniciando apenas o stack); o objetivo é impedir que o nó com falha continue gravando no storage compartilhado.","Causas comuns de eviction: perda do interconnect, CSSD sem CPU sob carga intensa, latência de I/O nos voting disks e problemas de acesso ao OCR/voting disk.","Para a análise de causa raiz, revise o ocssd.log, os traces do CSSD, o alert log e as mensagens do SO junto com os dados do CHM/oclumon (Cluster Health Monitor)."],"level":"expert"},{"id":"oracle-asm-redundancy-rebalance","title":"Oracle ASM: redundância de disk group e rebalance","category":"Oracle","summary":"O ASM protege os dados distribuindo-os (striping) entre os discos de um disk group e espelhando-os por failure group; ele rebalanceia os extents automaticamente quando discos são adicionados ou removidos.","points":["Níveis de redundância: EXTERNAL (sem espelhamento, a proteção fica a cargo do storage array), NORMAL (2 cópias, tolera a perda de 1 disco), HIGH (3 cópias, tolera 2 perdas simultâneas).","O ASM espelha failure groups, não discos; o extent primário fica em um failure group e suas cópias espelhadas em failure groups diferentes, então nenhum dado é perdido mesmo se um failure group inteiro falhar.","Adicionar ou remover um disco dispara um rebalance que redistribui os extents; ASM_POWER_LIMIT (0-1024) define o equilíbrio entre velocidade e consumo de recursos.","O tamanho da AU (Allocation Unit) é definido quando o disk group é criado; para bancos de dados grandes uma AU de 4 MB melhora a eficiência de I/O.","Os voting disks e o OCR podem ser armazenados em um disk group com redundância normal/high; um quorum failure group é usado apenas para voting disks e não contém extents de dados."],"level":"expert"},{"id":"oracle-data-guard-modes","title":"Oracle Data Guard: tipos de standby e modos de proteção","category":"Oracle","summary":"O Data Guard oferece recuperação de desastres enviando o redo para um standby; a escolha entre standby físico/lógico e os três modos de proteção definem o equilíbrio entre perda de dados e disponibilidade.","points":["Um standby físico é uma cópia idêntica bloco a bloco do primário (Redo Apply/MRP); com o Active Data Guard pode ser consultado em modo somente leitura enquanto aberto. Um standby lógico converte o redo em SQL e o aplica (SQL Apply) e pode conter estruturas/índices diferentes.","Maximum Performance (padrão): o redo é enviado de forma assíncrona (ASYNC) e o primário não espera confirmação; impacto zero no desempenho, mas um pequeno risco de perda de dados.","Maximum Availability: o redo é enviado de forma síncrona (SYNC/AFFIRM); se o standby estiver inacessível, o primário não para, mas passa ao comportamento MAX PERFORMANCE e ressincroniza quando o standby volta.","Maximum Protection: o primário não faz commit até que pelo menos um standby confirme; garante perda zero de dados, mas o primário é desligado se todos os standbys forem perdidos.","O Fast-Start Failover (FSFO) usa um processo observer para fazer failover automaticamente quando o primário falha; RPO=0 é buscado com FastStartFailoverThreshold e transporte síncrono.","Monitore o apply lag no standby com v$dataguard_stats e as métricas 'apply lag'/'transport lag'; o real-time apply aplica o redo antes de ele ser arquivado."],"level":"expert"},{"id":"oracle-exadata-offload","title":"Oracle Exadata: Smart Scan e storage indexes","category":"Oracle","summary":"No Exadata, as storage cells assumem parte do processamento das consultas (offload) e retornam ao nó do banco apenas os dados relevantes; Smart Scan, storage indexes e HCC reduzem drasticamente o I/O.","points":["Em consultas com full scan, o Smart Scan faz a filtragem de predicados e a projeção de colunas na storage cell; apenas as linhas/colunas necessárias, e não blocos, são retornadas ao nó do banco, o que reduz o tráfego no interconnect.","O Smart Scan só funciona com direct path reads; não entra em ação para blocos lidos do buffer cache nem para certas operações; meça o ganho com as estatísticas 'cell physical IO bytes eligible for predicate offload' e 'cell physical IO interconnect bytes returned by smart scan' ('cell physical IO bytes saved by storage index' mostra apenas a economia do storage index).","Um storage index mantém em memória os valores mín./máx. das colunas para cada região de armazenamento de 1 MB; se o predicado da consulta ficar fora do intervalo, essa região é ignorada sem ser lida (funciona como um índice negativo).","Storage indexes não são persistentes; ficam em memória e são reconstruídos quando a cell reinicia. Dados fisicamente ordenados (clustering) aumentam a taxa de descarte.","O HCC (Hybrid Columnar Compression) comprime os dados por coluna dentro de Compression Units; QUERY LOW/HIGH é para dados muito consultados, enquanto ARCHIVE LOW/HIGH é para dados de arquivo raramente acessados e oferece compressão muito alta com alto custo de CPU."],"level":"expert"},{"id":"oracle-awr-ash-analysis","title":"Análise de desempenho com Oracle AWR e ASH","category":"Oracle","summary":"O AWR coleta periodicamente snapshots de desempenho, enquanto o ASH amostra as sessões ativas a cada segundo; juntos respondem 'para onde foi o tempo' em termos de wait events.","points":["Por padrão, o AWR tira um snapshot a cada 60 minutos e os mantém por 8 dias; um relatório AWR entre dois snapshots mostra quais SQLs e wait events consumiram DB Time (requer a licença do Diagnostics Pack).","Sempre comece a análise por 'Top 10 Foreground Events by Total Wait Time' e DB Time; observe ali o equilíbrio entre CPU, I/O e concorrência em vez de se perder em estatísticas isoladas.","O ASH amostra v$active_session_history uma vez por segundo e captura problemas curtos e repentinos (picos); expõe tempestades momentâneas de lock/latch que o AWR não pega, por SQL_ID e sessão bloqueadora.","Average Active Sessions (AAS = DB Time / tempo decorrido) é um resumo em um único número da carga do sistema; AAS acima do número de núcleos de CPU indica saturação.","Para tuning de SQL, pegue o SQL_ID mais caro da seção 'SQL ordered by Elapsed Time/Gets' do AWR, confirme com o ASH em qual etapa esse SQL espera e depois examine o plano linha a linha com um relatório SQL Monitor."],"level":"expert"},{"id":"oracle-scn-read-consistency","title":"Oracle SCN e consistência de leitura","category":"Oracle","summary":"O System Change Number (SCN) é o relógio lógico do banco; o Oracle isola leitores de escritores construindo uma imagem consistente (read consistency) a partir do undo, de acordo com o SCN em que a consulta começou.","points":["O SCN cresce monotonicamente a cada commit e é registrado no redo/undo, no control file e nos cabeçalhos de bloco; se o SCN da última alteração de um bloco for maior que o SCN da consulta, o bloco é 'revertido'.","Para a consistência de leitura, o Oracle gera uma cópia CR (Consistent Read) do bloco atual e a reverte até o SCN de início da consulta usando o undo; assim, 'leitores não bloqueiam escritores e escritores não bloqueiam leitores'.","Se o undo for insuficiente ou undo_retention for excedido, uma consulta longa recebe 'ORA-01555 snapshot too old'; a solução é aumentar o undo tablespace, ajustar a retenção ou encurtar a consulta.","A consistência no nível de instrução usa um SCN separado para cada instrução SQL; uma transação SERIALIZABLE ou somente leitura mantém o único SCN do início da transação para todas as instruções.","No RAC, o SCN é mantido sincronizado entre todas as instâncias (Lamport ou broadcast-on-commit); o avanço do SCN é coordenado entre os nós para garantir a consistência global."],"level":"expert"},{"id":"postgres-patroni-failover","title":"PostgreSQL: failover automático com Patroni","category":"PostgreSQL","summary":"O Patroni oferece eleição de líder e failover automático mantendo o estado do cluster PostgreSQL em um repositório de consenso distribuído (DCS); evita split-brain com um watchdog.","points":["O estado do cluster e o lock de líder ficam em um DCS como etcd/Consul/ZooKeeper; o líder renova periodicamente um lock com TTL e, se não conseguir renová-lo, o lock expira e uma nova eleição de líder começa.","No failover, o Patroni escolhe a réplica mais atualizada (a de maior LSN); o novo líder é promovido e as demais réplicas se reconectam a ele (reinitialize/rewind).","O watchdog (softdog) é uma rede de segurança em nível de hardware que reinicia a máquina quando o antigo líder perde contato com o DCS, impedindo que dois nós sejam líderes ao mesmo tempo (split-brain).","maximum_lag_on_failover impede que uma réplica muito atrasada vire líder e cause perda de dados; synchronous_mode pode buscar RPO=0, mas a latência de escrita aumenta.","Os clientes não devem se conectar diretamente a um nó, mas via HAProxy usando o health check REST do Patroni, ou por um VIP; assim o tráfego é roteado automaticamente para o novo líder quando o líder muda.","A maioria (quórum) do DCS é obrigatória; use um cluster etcd de 3 ou 5 membros. Se o DCS estiver inacessível, o Patroni age com cautela e pode rebaixar o líder atual para somente leitura."],"level":"expert"},{"id":"postgres-logical-replication-upgrade","title":"PostgreSQL: upgrade de versão principal sem downtime com replicação lógica","category":"PostgreSQL","summary":"Como a replicação lógica pode transportar alterações de linhas entre versões, ela permite upgrades de versão principal com downtime quase zero; as versões antiga e nova rodam em paralelo por um tempo.","points":["A replicação lógica decodifica logicamente as alterações do WAL (INSERT/UPDATE/DELETE); ao contrário da replicação física, funciona entre versões principais diferentes e plataformas diferentes.","Fluxo: crie um schema vazio na nova versão, defina uma PUBLICATION na versão antiga e uma SUBSCRIPTION na nova; as tabelas são copiadas primeiro (sincronização inicial) e depois as alterações ao vivo começam a fluir.","Toda tabela precisa de uma REPLICA IDENTITY; em tabelas sem chave primária, replicar UPDATE/DELETE exige REPLICA IDENTITY FULL, caso contrário ocorre erro.","Alterações de DDL não são replicadas automaticamente e os valores atuais das sequences não são transportados; no cutover, avance as sequences manualmente na nova versão, caso contrário ocorrerão chaves conflitantes.","No cutover, pare brevemente a aplicação que escreve na versão antiga e, quando o atraso chegar a zero (verifique com pg_stat_replication), aponte a aplicação para a nova versão; se necessário, mantenha uma subscription reversa pronta para um rollback rápido.","Limitações: large objects e algumas DDLs não são replicados; é preciso configurar wal_level=logical e valores suficientes de max_replication_slots/max_wal_senders."],"level":"expert"},{"id":"postgres-pgvector-similarity","title":"PostgreSQL: busca por similaridade com pgvector","category":"PostgreSQL","summary":"O pgvector armazena embeddings vetoriais e faz busca aproximada de vizinhos mais próximos (ANN); os índices HNSW e IVFFlat definem o equilíbrio entre precisão, velocidade e memória.","points":["Escolha o operador de distância conforme o caso de uso: <-> L2 (euclidiana), <=> cosseno, <#> produto interno; o índice precisa usar a mesma classe de operador da consulta, caso contrário não é usado.","O HNSW constrói um grafo multicamada; oferece alto recall e consultas rápidas, mas precisa de mais memória e é lento para construir. m (número de conexões) e ef_construction ajustam a qualidade da construção, e ef_search ajusta a precisão no momento da consulta.","O IVFFlat divide os vetores em lists clusters e varre apenas probes clusters por consulta; usa menos memória, mas o índice deve ser criado DEPOIS da carga dos dados (clusters não fazem sentido em uma tabela vazia).","No IVFFlat, comece com lists ≈ linhas/1000 até 1M de linhas e ≈ sqrt(linhas) acima de 1M; aumentar probes eleva o recall, mas deixa a consulta mais lenta, então ajuste esse equilíbrio medindo.","O ANN retorna resultados aproximados; se for exigida exatidão de 100%, é preciso uma varredura exata sem o índice. Em buscas filtradas (WHERE), o recall do índice pode cair; se necessário, considere iterative scan ou um índice parcial.","As dimensões dos vetores e o número de linhas determinam a necessidade de memória; mantenha maintenance_work_mem grande o suficiente durante a construção, caso contrário a construção do HNSW transborda para o disco e fica muito lenta."],"level":"expert"},{"id":"postgres-citus-distributed","title":"PostgreSQL: escalabilidade distribuída com Citus","category":"PostgreSQL","summary":"O Citus escala o PostgreSQL horizontalmente dividindo as tabelas em shards por uma coluna de distribuição e espalhando-os pelos nós worker; a escolha da coluna de distribuição determina o desempenho.","points":["O nó coordinator recebe a consulta e a roteia para os shards relevantes com base na coluna de distribuição; os nós worker armazenam os shards e os processam em paralelo. Os shards são tabelas PostgreSQL comuns (divididas por faixa de hash).","A coluna de distribuição deve ser o filtro comum da maioria das consultas e JOINs (ex.: tenant_id); linhas com o mesmo valor caem no mesmo shard, então JOINs e chaves estrangeiras permanecem locais no mesmo nó (colocation).","A colocation é crítica: tabelas que são unidas entre si rodam sem redistribuição de dados entre nós (repartition) se forem distribuídas com a mesma coluna de distribuição e o mesmo número de shards.","Torne reference tables as tabelas pequenas que são frequentemente unidas com todos os shards; elas são copiadas integralmente para cada worker e eliminam o custo de rede em JOINs distribuídos.","Consultas que não incluem a coluna de distribuição se espalham por todos os shards e são caras; em SaaS multi-tenant, filtrar por tenant_id reduz a consulta a um único shard (router execution)."],"level":"expert"},{"id":"postgres-timescaledb-hypertable","title":"PostgreSQL: hypertables e continuous aggregates do TimescaleDB","category":"PostgreSQL","summary":"O TimescaleDB escala dados de séries temporais com hypertables, que os dividem automaticamente em chunks por intervalo de tempo, e com continuous aggregates pré-calculados.","points":["Uma hypertable parece uma única tabela por fora, mas por trás é dividida em chunks pela coluna de tempo (e opcionalmente de espaço); as consultas tocam apenas os chunks do intervalo de tempo relevante (chunk exclusion).","Defina chunk_time_interval de modo que os chunks mais ativos caibam em memória (shared_buffers); pequeno demais causa overhead excessivo de chunks/planejamento, grande demais causa exclusão fraca.","Um continuous aggregate é uma materialized view atualizada de forma incremental; é mantido atualizado em segundo plano por uma refresh policy que recalcula apenas os time buckets que mudaram.","Com real-time aggregation, um continuous aggregate combina os dados antigos materializados com os dados mais recentes da tabela bruta para retornar resultados atualizados no momento da consulta.","Chunks antigos podem ser bastante reduzidos com compressão colunar; uma retention policy remove automaticamente chunks mais antigos que uma certa idade com drop_chunks (muito mais barato que DELETE linha a linha)."],"level":"expert"},{"id":"postgres-vacuum-xid-wraparound","title":"PostgreSQL: VACUUM e XID wraparound","category":"PostgreSQL","summary":"O MVCC deixa versões mortas de linhas para trás; o VACUUM as limpa e marca linhas como 'frozen', evitando a perda de dados causada pelo wraparound do ID de transação (XID) de 32 bits.","points":["O PostgreSQL usa XIDs de 32 bits, que são circulares; cada versão de linha é marcada com xmin. Se linhas suficientemente antigas não forem congeladas, no XID wraparound transações do 'passado' parecem estar no 'futuro' e linhas podem de repente ficar invisíveis.","O autovacuum faz dois trabalhos: limpeza regular (dead tuples, bloat) e congelamento; para tabelas que se aproximam de autovacuum_freeze_max_age, um vacuum obrigatório 'anti-wraparound' é disparado mesmo com o autovacuum desativado.","Avisos são registrados no log conforme o wraparound se aproxima; se o limite ficar muito perto, o banco recusa novas escritas e passa a somente leitura para evitar perda de dados, e a solução é rodar um VACUUM agressivo (FREEZE).","Monitore o XID não congelado mais antigo com pg_database.datfrozenxid e age(); transações abertas por muito tempo (idle in transaction) e replication slots não usados bloqueiam o avanço do VACUUM, aumentando o bloat e o risco de wraparound.","Sob alta carga de escrita, o autovacuum ficar para trás gera bloat; aumente autovacuum_vacuum_cost_limit, reduza o naptime e aplique configurações de autovacuum específicas por tabela às tabelas grandes/quentes.","Em geral, o VACUUM não devolve espaço ao sistema operacional; ele o marca para reutilização. A redução física exige VACUUM FULL (bloqueia a tabela) ou pg_repack (online)."],"level":"expert"},{"id":"mysql-innodb-cluster","title":"MySQL: Group Replication e InnoDB Cluster","category":"MySQL","summary":"O InnoDB Cluster é um cluster de maioria (quórum) baseado em Group Replication que oferece alta disponibilidade apresentando à aplicação um único ponto de conexão via MySQL Router.","points":["O Group Replication propaga as transações para o grupo por uma camada de comunicação de grupo baseada em Paxos; uma transação só faz commit depois que a maioria do grupo (quórum) concorda, o que fornece failover automático e consistência.","O modo single-primary (padrão) permite escritas em apenas um nó, e o grupo elege automaticamente um novo primário quando o primário falha; no modo multi-primary todos os nós aceitam escritas, mas o tratamento de conflitos (certification) fica mais complexo.","O MySQL Router lê os metadados do cluster e oferece à aplicação duas portas: escritas vão para o primário atual (6446), leituras para as réplicas (6447); no failover, o roteamento é atualizado sem alterar a conexão da aplicação.","A perda da maioria (ex.: 2 de 3 nós fora) bloqueia o grupo; para evitar split-brain, o cluster não aceita novas escritas, e a recuperação é feita manualmente com group_replication_force_members.","O Group Replication exige binlog baseado em linhas (formato ROW), GTID e InnoDB; uma chave primária em cada tabela é obrigatória, caso contrário o nó não consegue entrar no cluster.","Um nó que entra no grupo primeiro se sincroniza via transferência de estado a partir de um doador existente (distributed recovery: clone plugin ou binlog) e depois passa para o fluxo ao vivo."],"level":"expert"},{"id":"mysql-semisync-replication","title":"MySQL: replicação semi-síncrona","category":"MySQL","summary":"A replicação semi-síncrona reduz a perda de dados fazendo o primário esperar, antes de confirmar um commit, até que pelo menos uma réplica tenha recebido a transação em seu relay log.","points":["Na replicação assíncrona, o primário confirma o commit sem esperar a réplica; se o primário cair, as transações ainda não enviadas são perdidas. O semi-sync espera uma confirmação de recebimento de pelo menos N réplicas (rpl_semi_sync_source_wait_for_replica_count).","AFTER_SYNC (padrão, recomendado): o primário primeiro recebe a confirmação da réplica e depois retorna o commit ao cliente; isso garante que toda transação que o cliente vê como 'bem-sucedida' existe em pelo menos uma réplica.","No modo AFTER_COMMIT, o primário faz commit localmente primeiro e depois espera a réplica; se a réplica atrasar, outras sessões podem ver dados que ainda não foram replicados (semelhante a um phantom read).","Se rpl_semi_sync_source_timeout for excedido, o primário volta automaticamente ao modo assíncrono e não para; retorna ao semi-sync quando a réplica volta, então a 'garantia' é condicional.","O semi-sync garante 'recebido', não 'aplicado na réplica'; para RPO=0 estrito, o Group Replication ou uma camada externa de consenso é mais adequado."],"level":"expert"},{"id":"mysql-undo-purge","title":"MySQL InnoDB: undo tablespaces e purge","category":"MySQL","summary":"O InnoDB mantém versões antigas das linhas no undo log para o MVCC; as threads de purge limpam os registros de undo e as versões mortas de que nenhum leitor precisa mais.","points":["Toda alteração produz um registro de undo log para rollback e leituras consistentes; uma transação longa mantém read views antigas vivas, bloqueando o avanço do purge e fazendo o undo crescer (o history list length aumenta).","Se o history list length (SHOW ENGINE INNODB STATUS) não para de crescer, o purge não está acompanhando; a causa principal costuma ser transações abertas por muito tempo ou leituras antigas mantidas ativas (ex.: mysqldump --single-transaction).","innodb_purge_threads controla o paralelismo do purge, e innodb_max_purge_lag adiciona atraso artificial ao DML quando o purge fica muito para trás, impedindo que a carga sobrecarregue o purge.","No MySQL 8, o undo fica em undo tablespaces separados e arquivos de undo que cresceram podem ser reduzidos com truncamento automático (innodb_undo_log_truncate); em versões antigas o undo ficava no system tablespace e nunca diminuía.","Um undo inchado obriga as leituras consistentes a percorrer cadeias de versões mais longas (I/O e CPU); transações curtas e disciplina de autocommit minimizam a pressão sobre o undo."],"level":"expert"},{"id":"mysql-buffer-pool-lru","title":"MySQL InnoDB: instâncias do buffer pool e LRU","category":"MySQL","summary":"O buffer pool do InnoDB mantém páginas de dados e de índice em memória; o algoritmo LRU com inserção no ponto médio impede que table scans expulsem dados quentes da memória.","points":["Em um servidor de banco dedicado, o buffer pool costuma ser definido em ~70-80% da RAM (innodb_buffer_pool_size; menos em um servidor compartilhado); o objetivo é manter em memória o working set acessado com frequência e minimizar o I/O de disco.","A lista LRU é dividida nas sublistas 'young' (quente) e 'old' (fria); uma página recém-lida não é inserida no início da lista, mas no início da região old (ponto médio, ~37%), de modo que um scan pontual não expulsa as páginas quentes.","Uma página na região old só é promovida para young se for acessada novamente depois de decorrido innodb_old_blocks_time; isso impede que grandes full scans poluam o buffer pool.","innodb_buffer_pool_instances divide o pool em várias instâncias independentes; como cada instância tem seu próprio mutex, a contenção no mutex do buffer pool diminui sob alta concorrência (relevante para pools grandes).","Monitore a taxa de acerto do buffer pool e o equilíbrio entre páginas livres e sujas; um grande número de páginas sujas e flush agressivo podem causar uma 'checkpoint storm', e innodb_io_capacity define a taxa de flush conforme o armazenamento."],"level":"expert"},{"id":"sqlserver-always-on-ag","title":"SQL Server: Always On Availability Groups","category":"SQL Server","summary":"Um Availability Group replica um grupo de bancos para réplicas síncronas/assíncronas; no WSFC oferece failover automático, réplicas legíveis e read-only routing.","points":["Com uma réplica synchronous-commit, o primário espera que o secundário grave (harden) o registro de log antes do commit; isso fornece RPO=0, mas se a réplica atrasar aumenta a latência de commit no primário.","Uma réplica asynchronous-commit não faz o primário esperar; é adequada para sites remotos de recuperação de desastres (DR), mas o failover pode perder alguns dados (RPO>0) e só o failover manual forçado (FORCE_FAILOVER_ALLOW_DATA_LOSS) é suportado.","O failover automático só ocorre entre um par de réplicas em modo synchronous-commit e 'automatic failover', enquanto o quórum do WSFC for mantido; as verificações de saúde são feitas com sp_server_diagnostics e database health detection.","Uma réplica secundária legível tira do primário a carga de relatórios; graças ao read-only routing, clientes que se conectam com ApplicationIntent=ReadOnly são roteados automaticamente pelo listener para uma réplica legível.","Consultas em uma réplica legível usam automaticamente snapshot isolation; para isso, uma tag de versão de 14 bytes é adicionada às linhas modificadas no primário e o version store do tempdb no secundário é carregado; além disso, se a aplicação do redo atrasar, os dados na réplica podem ficar desatualizados.","O listener do AG apresenta aos clientes um único ponto de conexão com um nome de rede virtual + IP; no failover o listener passa para o novo primário e a aplicação continua funcionando sem mudar sua connection string."],"level":"expert"},{"id":"sqlserver-columnstore","title":"SQL Server: índices columnstore e batch mode","category":"SQL Server","summary":"Um índice columnstore armazena os dados por coluna com alta compressão; o processamento em batch mode e a segment elimination trazem grandes ganhos de velocidade em consultas analíticas.","points":["Os dados são divididos em segmentos de coluna dentro de rowgroups (~1 milhão de linhas) e cada segmento é comprimido; apenas as colunas de que a consulta precisa são lidas, o que reduz bastante o I/O.","Cada segmento guarda metadados de mín./máx.; se o predicado da consulta estiver fora do intervalo de valores do segmento, ele é ignorado sem ser lido (segment elimination), por isso carregar os dados em ordem é muito importante.","O batch mode processa as linhas em grupos de ~900 em vez de linha a linha, aumentando o trabalho feito por ciclo de CPU; é muitas vezes mais rápido que o row mode para agregações e joins (a partir do SQL 2019+, o batch mode também é possível em rowstore).","Um clustered columnstore é ideal para grandes tabelas fato analíticas/de DW; para cargas mistas OLTP + análise, é possível montar real-time operational analytics (HTAP) com um nonclustered columnstore sobre uma tabela rowstore.","Linhas quentes (ainda não comprimidas) ficam por linha no deltastore e são comprimidas pelo tuple mover quando ele enche; muitas cargas pequenas causam fragmentação, por isso o bulk loading deve ser preferido."],"level":"expert"},{"id":"sqlserver-inmemory-oltp","title":"SQL Server: In-Memory OLTP (Hekaton)","category":"SQL Server","summary":"O In-Memory OLTP elimina gargalos em cargas OLTP de alta concorrência processando tabelas memory-optimized com estruturas sem lock/latch e procedures compiladas nativamente.","points":["Tabelas memory-optimized ficam inteiramente em memória e todas as versões de linhas vivem em memória; a concorrência é tratada com MVCC otimista sem locks, eliminando a contenção clássica de latch e lock.","Para a durabilidade, as alterações ainda são gravadas no log e descarregadas em checkpoint files (data/delta); tabelas SCHEMA_ONLY não são registradas no log e são esvaziadas no restart (ideal, por exemplo, para dados transitórios de staging/sessão).","Uma stored procedure compilada nativamente compila o T-SQL em código de máquina (DLL), eliminando o overhead de interpretação; ela só acessa tabelas memory-optimized e suporta um subconjunto limitado do T-SQL.","Como a concorrência é otimista, os conflitos são detectados em tempo de execução; um conflito write-write reverte a transação com um erro (exigindo nova tentativa), então a aplicação precisa ter lógica de retry.","Cenários mais adequados: taxas de insert muito altas (ex.: ingestão de IoT/telemetria), tabelas quentes com gargalos de lock/latch e tabelas temporárias que usam o tempdb; todos os dados precisam caber em memória e a pressão de memória deve ser monitorada de perto."],"level":"expert"},{"id":"sqlserver-query-store","title":"SQL Server: gerenciamento de planos com Query Store","category":"SQL Server","summary":"O Query Store persiste os textos das consultas, os planos de execução e as estatísticas de execução; permite detectar regressões de plano e forçar um plano específico.","points":["O Query Store guarda, dentro do banco, todos os planos que cada consulta usou ao longo do tempo, com métricas de duração/CPU/leituras por plano; responde com dados históricos 'por que esta consulta era rápida ontem e está lenta hoje'.","Regressões de plano (um plano recém-compilado pior que o antigo) são encontradas com os relatórios 'Regressed Queries' e 'Top Resource Consumers'; a estabilidade é restaurada forçando o plano bom conhecido com sys.sp_query_store_force_plan.","Com os Query Store hints do SQL Server 2022, hints (ex.: RECOMPILE, MAXDOP) podem ser aplicados sem forçar um plano nem alterar o texto da consulta; isso é poderoso para ajustar consultas de aplicações de terceiros.","A correção automática de planos (automatic tuning, FORCE_LAST_GOOD_PLAN) detecta regressões, força automaticamente o plano bom anterior e o desfaz se não houver melhora; ative-a em produção com supervisão.","Defina corretamente o modo de captura (ALL/AUTO/CUSTOM) e o tamanho do armazenamento; AUTO filtra consultas raras/insignificantes para reduzir overhead e espaço, e um Query Store cheio passa para o modo somente leitura e para de coletar dados."],"level":"expert"},{"id":"mongodb-sharding-deep","title":"MongoDB: sharding, chunks e o balancer","category":"MongoDB","summary":"O MongoDB divide os dados em chunks pela shard key e os distribui entre os shards; o balancer equilibra os chunks, e a escolha da shard key determina a distribuição e o roteamento das consultas.","points":["Os dados são divididos em chunks por faixas da shard key e os chunks são distribuídos entre os shards; o roteador mongos olha a shard key e envia a consulta apenas ao shard relevante (targeted), caso contrário faz broadcast para todos os shards (scatter-gather).","Uma boa shard key tem alta cardinalidade, baixa frequência e não é monotonicamente crescente; uma chave monotonicamente crescente (ex.: timestamp/ObjectId) concentra todas as novas escritas em um único shard (hotspot), e o hashed sharding as espalha.","Quando o número de chunks fica desequilibrado entre os shards, o balancer migra chunks em segundo plano; a consistência entre origem e destino é preservada durante a migração, mas há custo de I/O e ela pode ser agendada em uma janela de manutenção.","Um jumbo chunk é um chunk que excede o tamanho máximo e não pode ser dividido porque a shard key tem baixa cardinalidade; não pode ser migrado e cria desequilíbrio, e a solução é uma shard key mais seletiva (composta).","O zone sharding (tag-aware) fixa determinadas faixas da shard key em determinados shards; é usado para direcionar a localização dos dados por geografia ou hardware (ex.: dados da UE em um shard na região da UE).","Embora as versões modernas tragam balanceamento por tamanho e desfragmentação automática em vez de contagem de chunks, o princípio é o mesmo: para consultas targeted, a shard key precisa estar presente em toda leitura/escrita."],"level":"expert"},{"id":"mongodb-oplog-election","title":"MongoDB: oplog do replica set e eleições","category":"MongoDB","summary":"Em um replica set, o primário registra as operações de escrita no oplog e os secundários as aplicam; quando o primário falha, um novo primário é escolhido por uma eleição semelhante ao Raft.","points":["O oplog é uma capped collection que registra cada alteração no primário de forma idempotente (que pode ser reaplicada com segurança); os secundários acompanham (tail) e aplicam o oplog para se manter sincronizados.","O tamanho do oplog determina a janela de replicação; se um secundário ficar offline por mais tempo que o oplog cobre, ele fica 'stale' e exige uma ressincronização completa (initial sync), por isso o oplog deve ser dimensionado para a carga.","Quando o primário falha, os secundários votam usando um protocolo semelhante ao Raft; o candidato que obtém a maioria dos votos vira primário, por isso mantém-se um número ímpar de votos (com um arbiter, se necessário) para preservar a maioria.","writeConcern 'majority' garante que uma escrita chegou à maioria dos nós, então ela não é revertida no failover (proteção contra rollback); w:1 é mais rápido, mas a escrita pode ser perdida se o primário falhar.","readConcern e read preference controlam a atualidade das leituras; ler dos secundários distribui a carga, mas pode retornar dados desatualizados por causa do lag de replicação, enquanto 'majority'/'linearizable' dão garantias mais fortes.","Se o antigo primário ficar na minoria após uma partição de rede, ele desce para secundário; ao voltar ao novo primário, move suas escritas sem commit majoritário para um arquivo de rollback (o write concern majority evita isso)."],"level":"expert"},{"id":"mongodb-wiredtiger-checkpoint","title":"MongoDB: checkpoints e journal do WiredTiger","category":"MongoDB","summary":"O WiredTiger garante a durabilidade com checkpoints periódicos e um journal write-ahead; oferece alto throughput com concorrência no nível de documento e compressão.","points":["Por padrão, o WiredTiger faz um checkpoint a cada 60 segundos aproximadamente, gravando em disco um snapshot consistente da memória; entre checkpoints, a durabilidade é preservada registrando cada escrita no journal (WAL).","Sem o journal, uma queda perde as escritas feitas após o último checkpoint; com o journal, a recuperação carrega o último checkpoint e reaplica as operações seguintes a partir do journal.","O controle de concorrência no nível de documento permite que documentos diferentes da mesma coleção sejam atualizados ao mesmo tempo; snapshots MVCC fornecem leituras consistentes.","O cache do WiredTiger (por padrão ~50% da RAM) guarda os dados e índices acessados com frequência; se o working set não couber no cache, o eviction e o I/O de disco aumentam, e a saturação do cache degrada muito o desempenho.","A compressão de armazenamento usa snappy por padrão (equilíbrio entre velocidade e taxa); zstd/zlib dão taxas maiores, mas exigem mais CPU. Os índices são reduzidos ainda mais com prefix compression."],"level":"expert"},{"id":"redis-cluster-hashslot","title":"Redis Cluster: hash slots e resharding","category":"Redis","summary":"O Redis Cluster escala horizontalmente dividindo o espaço de chaves em 16384 hash slots e distribuindo-os entre os nós; os clientes encontram o nó certo por meio de redirecionamentos MOVED/ASK.","points":["Cada chave é mapeada para um slot via CRC16(key) mod 16384; cada master é dono de determinadas faixas de slots, então o cluster distribui os dados sem um roteador central.","Se um cliente vai ao nó errado, o nó responde com MOVED indicando o dono permanente do slot e o cliente atualiza seu mapa de slots. Durante o resharding, um redirecionamento ASK temporário é usado para o slot em migração.","O resharding move slots (e as chaves neles) ao vivo de um nó para outro; a migração é feita chave a chave e o cluster continua atendendo durante todo o processo.","Operações com várias chaves (MSET, transações, Lua) só funcionam com chaves no mesmo slot; hash tags ({...}) são usadas para agrupar chaves relacionadas no mesmo slot, ex.: user:{123}:name e user:{123}:email.","Para alta disponibilidade, dê a cada master pelo menos uma réplica; quando um master falha, sua réplica é promovida. O cluster decide pela maioria dos masters, e as escritas param se a maioria for perdida.","Se algum slot não estiver atribuído ou não tiver master, o cluster rejeita todas as escritas (quando cluster-require-full-coverage está ativo); todos os 16384 slots precisam estar atribuídos."],"level":"expert"},{"id":"redis-replication-psync","title":"Redis: replicação e PSYNC","category":"Redis","summary":"Na replicação assíncrona do Redis, o master transfere um snapshot dos dados para a réplica e depois transmite os comandos seguintes; o PSYNC faz uma ressincronização parcial após desconexões curtas.","points":["Na sincronização inicial, o master gera um snapshot RDB e o envia à réplica (full resync); enquanto isso, guarda as escritas que chegam em um replication backlog buffer e as transmite depois do RDB.","O PSYNC acompanha o replication offset da réplica e o replication ID do master; após uma desconexão curta, se os dados perdidos ainda estiverem no backlog buffer, só a parte faltante é enviada (partial resync), evitando um full resync caro.","repl-backlog-size determina por quanto tempo uma desconexão pode ser tolerada; com altas taxas de escrita, um backlog pequeno força um full resync nas desconexões, o que significa geração de RDB no master e custo de rede.","A replicação é assíncrona: o master confirma uma escrita sem esperar as réplicas, então se o master cair de repente as escritas mais recentes podem ser perdidas; o comando WAIT pode ser usado para esperar até que um certo número de réplicas a tenha recebido, mas não é uma garantia síncrona de verdade.","Com a diskless replication (repl-diskless-sync), o master pode transmitir o RDB direto para o socket sem gravá-lo em disco; isso acelera a sincronização inicial em ambientes com discos lentos, mas rede rápida."],"level":"expert"},{"id":"redis-memory-fragmentation","title":"Redis: fragmentação de memória e jemalloc","category":"Redis","summary":"O Redis usa jemalloc por padrão; alocações e liberações de tamanho variável causam fragmentação de memória com o tempo, fazendo o RSS parecer maior que os dados realmente usados.","points":["mem_fragmentation_ratio = used_memory_rss / used_memory; perto de 1 é o ideal, bem acima de 1 (ex.: >1.5) indica fragmentação, e abaixo de 1 indica que dados estão indo para o swap em disco (ruim).","A fragmentação surge quando chaves de tamanhos diferentes são criadas e apagadas o tempo todo, deixando lacunas inutilizáveis nas arenas do jemalloc; alterações frequentes em valores grandes pioram o quadro.","A desfragmentação ativa (activedefrag yes) compacta os blocos de memória em tempo de execução com a ajuda do jemalloc para reduzir a fragmentação; seus limites (active-defrag-ignore-bytes, -threshold-lower/upper) são ajustados para limitar o overhead.","Defina corretamente maxmemory e maxmemory-policy; como o RSS real alocado pelo jemalloc pode exceder maxmemory, mantenha maxmemory abaixo da RAM para evitar um OOM do sistema operacional.","Se used_memory estiver baixo, mas o RSS continuar alto, um restart (ou um nó reiniciado via failover) costuma zerar a fragmentação de forma duradoura; o active defrag reduz a necessidade de restarts na maioria dos casos."],"level":"expert"},{"id":"elasticsearch-shard-sizing","title":"Elasticsearch: dimensionamento de shards","category":"Elasticsearch","summary":"Cada shard é um índice Lucene e tem um custo fixo de recursos; shards pequenos demais em excesso (oversharding) ou shards grandes demais degradam o desempenho e a estabilidade.","points":["Regra prática: mantenha um shard na faixa de 10-50 GB; shards muito grandes deixam a recuperação e o rebalanceamento lentos, enquanto shards muito pequenos (oversharding) sobrecarregam desnecessariamente o cluster state e o heap.","Cada shard, e principalmente cada campo mapeado, consome heap. A antiga regra de \"~20 shards por GB de heap\" não vale mais a partir da 8.3 (o overhead de heap por shard caiu muito); a orientação atual é reservar ~1 KB de heap por campo mapeado por índice nos data nodes, mais o overhead, e manter os shards por nó abaixo de cluster.max_shards_per_node (padrão 1000). Shards demais ainda aumentam o cluster state e o overhead de coordenação.","A latência das consultas está ligada ao número de shards: uma consulta se espalha por todos os shards relevantes e os resultados são mesclados; mais shards que o necessário deixam lentas até consultas pequenas por causa do overhead de coordenação.","Para dados de séries temporais/logs, use índices baseados em tempo (data streams) em vez de um único índice gigante; isso torna barato mover/apagar dados antigos por índice (ILM) e mantém os shards gerenciáveis.","O número de shards primários é fixado na criação do índice e não pode ser alterado depois (só via reindex/split/shrink); por isso planeje-o corretamente desde o início com base nas estimativas de crescimento, enquanto o número de réplicas pode ser ajustado dinamicamente."],"level":"expert"},{"id":"elasticsearch-ilm-tiers","title":"Elasticsearch: ILM e camadas hot-warm-cold-frozen","category":"Elasticsearch","summary":"O Index Lifecycle Management gerencia dados de séries temporais de forma econômica, movendo automaticamente os índices entre camadas de custo/desempenho conforme a fase do ciclo de vida.","points":["Uma política ILM move um índice pelas fases: hot (escritas ativas + consultas frequentes, SSD rápido), warm (escritas encerradas, consultas ocasionais), cold (consultas raras, hardware mais barato), frozen (muito raro, servido do object storage via searchable snapshots).","O rollover abre um novo índice quando o índice hot atinge um certo tamanho/idade/número de documentos; assim um único índice não cresce para sempre e cada fase é gerenciada por índice.","A camada frozen mantém os dados no object storage (S3/blob) via searchable snapshots e os traz parcialmente para a memória só quando necessário; reduz muito o custo de disco, mas a latência das consultas aumenta.","Ao passar para warm/cold, o armazenamento e o heap são otimizados com force merge, shrink e menos réplicas; como os dados não mudam mais nessas fases, os segmentos podem ser mesclados em um único segmento.","Mapeie as camadas de dados para papéis de nó (data_hot/data_warm/data_cold/data_frozen); o ILM usa shard allocation filters para colocar o índice nos nós com o hardware certo."],"level":"expert"},{"id":"elasticsearch-segment-merge","title":"Elasticsearch: merge de segmentos e force merge","category":"Elasticsearch","summary":"O Lucene cria novos segmentos imutáveis a cada refresh; o merge em segundo plano combina e remove segmentos, enquanto o force merge é uma operação manual que deve ser usada com cuidado.","points":["Cada refresh (padrão 1 s) gera um novo segmento, e as exclusões são marcadas como 'tombstones' no segmento; muitos segmentos pequenos deixam as leituras lentas, por isso o merge em segundo plano os combina.","Documentos excluídos/atualizados só são removidos fisicamente do disco durante um merge; sob carga pesada de updates, 'deleted docs' se acumulam nos segmentos e o uso de disco/memória incha.","Em índices que não recebem mais escritas (somente leitura), um force merge para 1 segmento melhora a velocidade das consultas e a eficiência do disco; é uma etapa típica da fase warm do ILM.","NUNCA rode force merge em um índice que recebe escritas ativas; o segmento muito grande que ele gera não entra no ciclo normal de merge, as exclusões seguintes não podem ser limpas, e ele sufoca o I/O e o heap por muito tempo.","Aumentar temporariamente o refresh_interval durante cargas em massa (ex.: -1 ou 30s) gera menos segmentos e maiores, reduzindo a carga de merge e melhorando o throughput de escrita."],"level":"expert"},{"id":"elasticsearch-node-roles","title":"Elasticsearch: papéis de nó e topologia do cluster","category":"Elasticsearch","summary":"Os nós do Elasticsearch assumem papéis como master, data, coordinating e ingest; separar os papéis em clusters grandes traz estabilidade e escalabilidade.","points":["Os nós master-eligible gerenciam o cluster state (índices, posicionamento dos shards, mappings); para eleições estáveis, use um número ímpar (geralmente 3) de nós master dedicados e conte com um quórum (maioria) para evitar split-brain.","Os data nodes hospedam os shards e cuidam da indexação e do I/O das consultas; são os que mais consomem CPU/RAM/disco e podem ser divididos em camadas de dados (hot/warm/cold/frozen).","Um nó coordinating-only não tem outros papéis e distribui as requisições para os shards relevantes e mescla os resultados (scatter-gather); protege os data nodes assumindo a mesclagem pesada de buscas/agregações e atua como balanceador de carga.","Um nó ingest processa os dados por pipelines (transformação, enriquecimento) antes da indexação; mover pipelines de ingestão pesados para nós ingest dedicados protege o desempenho de consulta dos data nodes.","Nunca faça os nós master dividirem carga pesada de consultas/dados; um master lento sob carga atrasa as atualizações do cluster state e causa instabilidade em todo o cluster (alocação de shards atrasada, eleições)."],"level":"expert"}]},"guide/glossary.json":{"terms":[{"term":"ACID","full":"Atomicity, Consistency, Isolation, Durability (Atomicidade, Consistência, Isolamento, Durabilidade)","definition":"As quatro propriedades básicas que tornam as transações confiáveis: Atomicidade (tudo ou nada), Consistência (as regras são preservadas), Isolamento (transações concorrentes não corrompem umas às outras) e Durabilidade (dados com commit não se perdem). É a garantia transacional dos bancos relacionais.","tags":["transaction","transaction","acid","consistency","consistency"]},{"term":"BASE","full":"Basically Available, Soft state, Eventually consistent (basicamente disponível, estado flexível, eventualmente consistente)","definition":"Uma abordagem de consistência relaxada, alternativa ao ACID, preferida em sistemas distribuídos e NoSQL. O sistema prioriza estar sempre disponível e aceita que os dados fiquem consistentes com o tempo (consistência eventual). Troca a consistência estrita por escalabilidade.","tags":["base","distributed","distributed","eventual-consistency","nosql"]},{"term":"MVCC","full":"Multi-Version Concurrency Control (controle de concorrência multiversão)","definition":"Um método de concorrência que mantém várias versões da mesma linha para que leitores e escritores trabalhem sem bloquear uns aos outros. Cada transação vê seu próprio snapshot dos dados, então leituras não bloqueiam escritas e escritas não bloqueiam leituras. Usado em sistemas como PostgreSQL e Oracle.","tags":["concurrency","concurrency","lock","mvcc","snapshot"]},{"term":"WAL","full":"Write-Ahead Log","definition":"O princípio de que um registro de log é gravado de forma durável em disco ANTES de a alteração ser gravada nos arquivos de dados. A recuperação após falhas e a durabilidade são garantidas por ele. Chama-se WAL no PostgreSQL e transaction log no SQL Server.","tags":["wal","log","recovery","recovery","durability"]},{"term":"Redo Log","full":"","definition":"O log que registra as alterações feitas no banco e é usado para reaplicar (redo) o trabalho perdido em uma queda. Durante a recuperação, aplica para frente (roll forward) as alterações que tiveram commit, mas ainda não foram gravadas em disco. O redo log do Oracle corresponde ao conceito geral de WAL.","tags":["redo","log","recovery","recovery","oracle"]},{"term":"Undo / Rollback Segment","full":"","definition":"A área que armazena a imagem anterior dos dados alterados por uma transação. Tem dois propósitos: desfazer uma alteração com rollback e servir a versão antiga aos leitores no MVCC. Chama-se undo/rollback segment no Oracle e undo/version store em outros sistemas.","tags":["undo","rollback","rollback","mvcc","segment"]},{"term":"Buffer Pool / Buffer Cache","full":"","definition":"O cache em memória onde ficam as páginas de dados e de índice usadas com frequência. Como leituras de disco são caras, o desempenho do banco depende muito da taxa de acerto aqui (cache hit ratio). Chama-se buffer pool no MySQL InnoDB e buffer cache no SQL Server.","tags":["buffer-pool","buffer-cache","cache","cache","memory"]},{"term":"Página suja (Dirty Page)","full":"","definition":"Uma página de dados alterada em memória, mas ainda não gravada em disco. A durabilidade é protegida pelo WAL; a página em si continua suja até que o checkpoint ou o background writer a grave em disco. Páginas sujas demais alongam o tempo de recuperação.","tags":["dirty-page","dirty-page","memory","checkpoint","io"]},{"term":"LSN","full":"Log Sequence Number","definition":"Um número de sequência único e sempre crescente atribuído a cada registro no WAL/transaction log. É usado para determinar até qual registro de log uma página está atualizada e de onde a recuperação deve continuar. Também acompanha o progresso na replicação.","tags":["lsn","log","sequence-number","recovery","replication"]},{"term":"SCN","full":"System Change Number","definition":"No Oracle, um timestamp lógico monotonicamente crescente atribuído a cada ponto de commit no banco. É usado para a consistência de leitura, o MVCC e a ordenação de eventos durante a recuperação. Pode ser visto como o equivalente do LSN no Oracle.","tags":["scn","oracle","timestamp","read-consistency","commit"]},{"term":"Nível de isolamento (Isolation Level)","full":"Nível de isolamento (Isolation Level)","definition":"A configuração que determina até que ponto transações concorrentes podem ver as alterações umas das outras. Os níveis são Read Uncommitted, Read Committed, Repeatable Read e Serializable; a consistência aumenta e a concorrência diminui conforme o nível sobe. Controla as anomalias dirty/non-repeatable/phantom read.","tags":["isolation","isolation-level","transaction","concurrency","concurrency"]},{"term":"Dirty Read","full":"","definition":"Uma transação ler uma alteração que outra transação ainda não confirmou com commit (e pode reverter). Como o dado lido pode ser inválido, é uma anomalia de consistência. Só é possível no nível de isolamento Read Uncommitted.","tags":["dirty-read","anomaly","isolation","transaction","consistency"]},{"term":"Non-repeatable Read","full":"","definition":"Ver um valor diferente ao ler a mesma linha duas vezes na mesma transação, porque outra transação fez commit no meio. Pode ocorrer em Read Committed; é evitado em Repeatable Read e acima.","tags":["non-repeatable-read","anomaly","isolation","transaction","non-repeatable"]},{"term":"Phantom Read","full":"","definition":"O conjunto de linhas mudar quando uma consulta é executada de novo com a mesma condição na mesma transação, por causa de um insert/delete intermediário (surgem novas linhas 'fantasma'). Pelo padrão SQL é evitado em Serializable; o PostgreSQL também o evita em Repeatable Read.","tags":["phantom-read","phantom","anomaly","serializable","isolation"]},{"term":"Deadlock","full":"","definition":"Uma situação em que duas ou mais transações esperam cada uma por um lock mantido pela outra, de modo que nenhuma consegue avançar. O banco a detecta e quebra o ciclo, geralmente escolhendo a transação mais barata como 'vítima' e fazendo rollback dela. Adquirir os locks sempre na mesma ordem reduz o risco.","tags":["deadlock","deadlock","lock","lock","concurrency"]},{"term":"Lock Escalation","full":"","definition":"Quando uma transação mantém muitos locks de linha/página, o banco os converte em um único lock mais grosso (por exemplo, um lock de tabela). Reduz a memória de gerenciamento de locks, mas diminui a concorrência e pode aumentar o bloqueio. Visto principalmente no SQL Server.","tags":["lock-escalation","lock","lock","concurrency","sql-server"]},{"term":"Latch","full":"","definition":"Um lock de concorrência leve e de baixo custo usado para proteger estruturas em memória (por exemplo, páginas do buffer pool) por um tempo muito curto. Ao contrário dos locks de transação, protege a estrutura física de memória e não os dados lógicos, e é mantido apenas por muito pouco tempo.","tags":["latch","lock","memory","concurrency","internal"]},{"term":"Índice B-Tree","full":"Balanced Tree Index (índice de árvore balanceada)","definition":"O tipo de índice mais comum, que mantém os dados em uma estrutura de árvore ordenada e balanceada. É eficiente para consultas de igualdade e de intervalo, ordenação e buscas por prefixo. É o tipo de índice padrão na maioria dos bancos.","tags":["btree","index","index","search","range"]},{"term":"Índice Hash","full":"","definition":"Um tipo de índice que localiza uma chave passando-a por uma função hash. É muito rápido apenas para buscas de igualdade exata (=); não pode ser usado para consultas de intervalo nem para ordenação. Disponível, por exemplo, no PostgreSQL e nas tabelas Memory do MySQL.","tags":["hash-index","index","index","equality","search"]},{"term":"Índice Bitmap","full":"","definition":"Um índice que mantém arrays de bits para cada valor distinto, adequado a colunas de baixa cardinalidade (poucos valores distintos). Permite combinar várias condições rapidamente com AND/OR; eficaz em cargas de data warehouse/OLAP, mas ineficiente sob escritas pesadas.","tags":["bitmap-index","index","index","olap","cardinality"]},{"term":"Índice de cobertura (Covering Index)","full":"","definition":"Um índice que contém todas as colunas de que uma consulta precisa; a consulta é atendida só pelo índice, sem acessar a tabela (heap/clustered). Isso melhora o desempenho ao eliminar buscas de linha caras. Pode ser criado com colunas INCLUDE.","tags":["covering-index","index","index","performance","lookup"]},{"term":"Índice clusterizado (Clustered Index)","full":"","definition":"Um índice que mantém as linhas da tabela fisicamente ordenadas pela chave do índice; a própria tabela é armazenada nessa ordem. Uma tabela só pode ter um. É rápido para consultas de intervalo; no InnoDB a chave primária é sempre clusterizada.","tags":["clustered-index","index","index","physical","primary-key"]},{"term":"Cardinalidade","full":"","definition":"O número de valores distintos em uma coluna. Alta cardinalidade (ex.: e-mail) significa muitos valores diferentes; baixa cardinalidade (ex.: gênero), poucos. É uma medida crítica para o otimizador ao escolher índices e estimar o custo do plano.","tags":["cardinality","cardinality","statistics","optimizer","distinct"]},{"term":"Seletividade","full":"","definition":"Indica que fração pequena do total de linhas uma condição de filtro retorna. Alta seletividade (poucas linhas) torna o uso de índice atraente; com baixa seletividade (muitas linhas), um full scan pode ser mais barato. O otimizador a usa ao escolher um plano.","tags":["selectivity","selectivity","optimizer","index","statistics"]},{"term":"Plano de execução","full":"","definition":"O roteiro que mostra as etapas (tipo de varredura, método de join, ordenação etc.) que o otimizador escolheu para executar uma consulta. Examiná-lo com EXPLAIN/EXPLAIN ANALYZE revela a causa raiz de problemas de desempenho. Comparar custos estimados e reais é importante.","tags":["execution-plan","query-plan","explain","optimizer","performance"]},{"term":"Otimizador baseado em custo","full":"CBO","definition":"O otimizador de consultas que estima o custo dos possíveis planos de execução a partir das estatísticas e escolhe o mais barato. Estatísticas atualizadas são essenciais para decisões corretas; estatísticas desatualizadas levam a planos ruins. É a abordagem padrão nos bancos modernos.","tags":["cbo","optimizer","cost","statistics","query-plan"]},{"term":"Estatísticas","full":"Estatísticas","definition":"Metadados coletados para uma tabela/índice para que o otimizador possa estimar contagens de linhas, cardinalidade e distribuição de valores. Estatísticas atuais significam bons planos de consulta; quando desatualizadas, devem ser renovadas com ANALYZE/UPDATE STATISTICS. Estão entre as causas mais comuns de mau desempenho.","tags":["statistics","statistics","optimizer","analyze","query-plan"]},{"term":"Histograma","full":"","definition":"Uma estrutura de estatísticas que resume a distribuição dos valores de uma coluna dividindo-os em faixas (buckets). Permite ao otimizador estimar contagens de linhas com mais precisão, principalmente em distribuições assimétricas. É um componente das estatísticas.","tags":["histogram","statistics","statistics","optimizer","distribution"]},{"term":"Partição","full":"","definition":"Uma técnica que divide fisicamente uma tabela grande em partes menores (por exemplo, por data ou faixa) enquanto ela continua sendo logicamente uma única tabela. As consultas varrem apenas a parte relevante (partition pruning), e a manutenção e o arquivamento ficam mais fáceis. A diferença para o sharding: fica no mesmo servidor/instância.","tags":["partition","partitioning","scaling","pruning","big-data"]},{"term":"Sharding","full":"","definition":"Um método de distribuir dados horizontalmente entre vários servidores/bancos separados de acordo com uma shard key. Permite escalar horizontalmente além dos limites de uma única máquina, mas complica o gerenciamento de consultas e transações. A diferença para o particionamento: os dados ficam espalhados por nós diferentes.","tags":["sharding","scaling","distributed","distributed","horizontal-scaling"]},{"term":"Replicação (síncrona/assíncrona)","full":"","definition":"Copiar dados de um nó primário para uma ou mais cópias (réplicas). Na replicação síncrona, o commit espera a confirmação da réplica (sem perda de dados, latência maior); na assíncrona, não espera (rápida, mas pode haver perda de dados se a réplica estiver atrasada). Usada para HA e escalabilidade de leitura.","tags":["replication","replication","synchronous","asynchronous","ha"]},{"term":"Replicação lógica vs. física","full":"","definition":"A replicação física cria uma cópia exata no nível de bloco de disco/WAL (mesma versão, banco inteiro). A replicação lógica transfere as alterações no nível de linha/SQL; permite replicar tabelas seletivamente e transferir entre versões e schemas diferentes. A replicação lógica é preferida em cenários de CDC e upgrade.","tags":["logical-replication","physical-replication","replication","cdc","wal"]},{"term":"Failover","full":"","definition":"Transferir o serviço, automática ou manualmente, para um nó standby quando o nó primário falha. Minimiza o downtime; o RPO determina quantos dados podem ser perdidos e o RTO, quanto tempo leva a recuperação. Entra em ação em falhas não planejadas.","tags":["failover","ha","high-availability","standby","rpo"]},{"term":"Switchover","full":"","definition":"Uma troca planejada e controlada dos papéis de primário e standby (por exemplo, para manutenção). A diferença para o failover: é uma operação planejada, não uma falha, e geralmente é feita sem perda de dados.","tags":["switchover","planned","ha","maintenance","standby"]},{"term":"RPO","full":"Recovery Point Objective","definition":"A quantidade máxima aceitável de perda de dados após um desastre (expressa em tempo). Por exemplo, com um RPO de 5 minutos, tolera-se no máximo 5 minutos de perda de dados. A frequência de backup e o tipo de replicação são escolhidos para atender a essa meta.","tags":["rpo","data-loss","dr","disaster-recovery","backup"]},{"term":"RTO","full":"Recovery Time Objective","definition":"O tempo máximo previsto para o sistema voltar a operar após uma interrupção. Por exemplo, com um RTO de 1 hora, o serviço precisa voltar em no máximo 1 hora. A arquitetura de HA/DR e o nível de automação são projetados em torno dessa meta.","tags":["rto","recovery-time","dr","disaster-recovery","ha"]},{"term":"HA","full":"High Availability (alta disponibilidade)","definition":"O objetivo de projeto de manter um sistema atendendo sem interrupção, ou com muito pouca, apesar das falhas. É alcançado com redundância, failover automático e health checks. Geralmente é expresso como percentual de uptime (ex.: 99.99%).","tags":["ha","high-availability","high-availability","failover","redundancy"]},{"term":"DR","full":"Disaster Recovery (recuperação de desastres)","definition":"Os planos e processos para restaurar sistemas e dados, geralmente em uma região geograficamente separada, após grandes desastres como incêndio, inundação ou uma interrupção em toda uma região. É medido pelas metas de RPO e RTO. HA foca nas falhas do dia a dia; DR, nos grandes desastres.","tags":["dr","disaster-recovery","disaster-recovery","rpo","rto"]},{"term":"Quórum","full":"","definition":"A maioria mínima de nós (geralmente N/2 + 1) necessária para que uma decisão (por exemplo, eleição de líder ou confirmação de escrita) seja válida em um sistema distribuído. É usado para evitar split-brain e preservar a consistência. Por isso os tamanhos de cluster costumam ser ímpares.","tags":["quorum","majority","distributed","distributed","split-brain"]},{"term":"Split-Brain","full":"","definition":"Uma situação em que, após uma partição de rede, as duas metades de um cluster acreditam ser o primário e continuam escrevendo de forma independente; isso gera dados conflitantes e corrupção. É evitado com mecanismos de quórum e fencing. É um dos cenários de falha mais perigosos em clusters de HA.","tags":["split-brain","distributed","quorum","ha","consistency"]},{"term":"TDE","full":"Transparent Data Encryption","definition":"Um método de criptografia, transparente para a aplicação, que mantém os arquivos do banco (dados e log) criptografados em disco. Protege os dados mesmo se discos ou arquivos de backup forem roubados (data at rest). Não protege os dados na rede (in transit); para isso é preciso TLS.","tags":["tde","encryption","encryption","security","security"]},{"term":"RBAC","full":"Role-Based Access Control (controle de acesso baseado em papéis)","definition":"Um modelo de controle de acesso em que os privilégios são atribuídos a papéis (roles), e não diretamente aos usuários, e os usuários se tornam membros dos papéis. Simplifica o gerenciamento de privilégios e facilita aplicar o princípio do menor privilégio. Mantém a administração escalável conforme cresce o número de usuários.","tags":["rbac","role","privilege","security","security"]},{"term":"Pool de conexões (Connection Pool)","full":"","definition":"Um pool que cria conexões antecipadamente e as reutiliza, em vez de abrir e fechar repetidamente as conexões da aplicação com o banco. Reduz o custo de estabelecer conexões, limita o consumo de recursos e controla a carga. Protege o banco evitando conexões em excesso.","tags":["connection-pool","connection-pool","performance","resource","application"]},{"term":"Prepared Statement","full":"","definition":"Uma construção em que uma instrução SQL é analisada e planejada uma vez e depois executada repetidamente com valores de parâmetro diferentes. Melhora o desempenho pela reutilização do plano e oferece segurança contra SQL injection. É usada junto com bind variables.","tags":["prepared-statement","bind","security","sql-injection","performance"]},{"term":"Bind Variable","full":"","definition":"Um parâmetro passado por um placeholder em vez de embutir o valor no texto do SQL. Aproveita bem o plan cache ao evitar que a mesma consulta seja replanejada para valores diferentes, e impede SQL injection. É crítica para consultas cujos valores literais mudam com frequência.","tags":["bind-variable","parameter","prepared-statement","plan-cache","security"]},{"term":"Parameter Sniffing","full":"","definition":"O otimizador gerar e guardar em cache o plano de uma consulta preparada/parametrizada com base no valor de parâmetro da primeira execução. Se esse valor for atípico, um plano com mau desempenho para valores diferentes posteriores pode se fixar. As soluções incluem recompilação do plano (recompile) e hints do otimizador.","tags":["parameter-sniffing","plan-cache","optimizer","performance","sql-server"]},{"term":"VACUUM / Bloat","full":"","definition":"Por causa do MVCC, versões mortas de linhas excluídas/atualizadas se acumulam na tabela; esse inchaço se chama bloat. O VACUUM recupera o espaço dessas linhas mortas e atualiza as estatísticas (PostgreSQL). Se não for executado regularmente, o disco incha e o desempenho cai.","tags":["vacuum","bloat","bloated","mvcc","postgresql"]},{"term":"Compactação (Compaction)","full":"","definition":"Em armazenamentos baseados em LSM-tree (ex.: Cassandra, RocksDB), o processo de mesclar muitos arquivos de dados pequenos e eliminar registros mortos/obsoletos. Melhora o desempenho de leitura e recupera espaço em disco. É o equivalente do VACUUM no mundo LSM.","tags":["compaction","lsm-tree","merge","cassandra","rocksdb"]},{"term":"Oplog","full":"Operations Log","definition":"No MongoDB, uma coleção especial de tamanho fixo (capped) em que todas as operações de escrita aplicadas ao primário são registradas em ordem. Os membros do replica set leem dela para se manter sincronizados com o primário. É a base do CDC e da replicação.","tags":["oplog","mongodb","replication","cdc","log"]},{"term":"Binlog","full":"Binary Log","definition":"No MySQL, o log binário que registra todas as operações (ou alterações de linhas) que modificam dados. É usado para replicação, recuperação point-in-time e CDC. Pode ser mantido no formato row, statement ou mixed.","tags":["binlog","mysql","replication","cdc","recovery"]},{"term":"CDC","full":"Change Data Capture","definition":"Uma técnica que captura as alterações de insert/update/delete em um banco e as transmite para outros sistemas (data warehouse, mecanismo de busca, fila de mensagens). Geralmente roda com baixo overhead lendo o log de transações (binlog, WAL, oplog). É a base da integração de dados em tempo real.","tags":["cdc","change-data-capture","data-streaming","binlog","integration"]},{"term":"Materialized View","full":"","definition":"Uma view que armazena fisicamente em disco o resultado de uma consulta; ao contrário de uma view comum, não é recalculada a cada consulta. Acelera agregações e joins caros, mas seus dados ficam desatualizados e precisam ser atualizados com refresh. Comum em OLAP/relatórios.","tags":["materialized-view","view","cache","olap","reporting"]},{"term":"Chave estrangeira (Foreign Key)","full":"","definition":"Uma restrição de integridade referencial que permite que uma coluna de uma tabela referencie a chave primária/candidata de outra tabela. Impede referências a linhas inexistentes e preserva os relacionamentos. Regras como ON DELETE/UPDATE CASCADE definem o comportamento das linhas dependentes.","tags":["foreign-key","foreign-key","integrity","relationship","constraint"]},{"term":"Normalização","full":"Normalização","definition":"O processo de dividir os dados em tabelas relacionadas para reduzir a redundância e o risco de inconsistência (formas normais como 1NF, 2NF, 3NF). Evita anomalias de atualização e é preferido em sistemas OLTP. Em troca, as consultas podem exigir mais joins.","tags":["normalization","normalization","design","oltp","redundancy"]},{"term":"Desnormalização","full":"Desnormalização","definition":"Uma técnica que duplica dados deliberadamente para reduzir o número de joins e melhorar o desempenho de leitura. Acelera as consultas, mas introduz duplicação de dados e complexidade nas atualizações. Preferida em relatórios/OLAP e cargas com muita leitura.","tags":["denormalization","denormalization","performance","olap","read"]},{"term":"OLTP","full":"Online Transaction Processing","definition":"Um tipo de sistema que processa um grande número de transações curtas, frequentes e concorrentes (insert/update/delete, leituras de uma linha); ex.: bancos, e-commerce. Exige baixa latência e alta concorrência e geralmente é projetado normalizado. É a contraparte operacional do OLAP.","tags":["oltp","transaction","transaction","operational","normalization"]},{"term":"OLAP","full":"Online Analytical Processing","definition":"Um tipo de sistema que executa consultas complexas de agregação e análise sobre grandes conjuntos de dados; ex.: relatórios, business intelligence. Rodam poucas consultas, mas pesadas, e geralmente é projetado desnormalizado e colunar. É a contraparte analítica do OLTP.","tags":["olap","analytics","reporting","data-warehouse","columnar"]},{"term":"ETL","full":"Extract, Transform, Load","definition":"O processo de extrair dados das fontes (Extract), transformá-los conforme as regras de negócio (Transform) e carregá-los no sistema de destino, geralmente um data warehouse (Load). A variante em que a transformação é feita no destino após a carga se chama ELT. É a abordagem clássica de integração de dados.","tags":["etl","data-integration","data-warehouse","elt","transformation"]},{"term":"Dados quentes/frios (Hot/Cold Data)","full":"","definition":"Dados atuais e acessados com frequência são chamados de 'quentes'; dados antigos/de arquivo raramente acessados, de 'frios'. Dados quentes ficam em armazenamento rápido/caro e os frios em armazenamento barato/lento (data tiering). É uma estratégia para equilibrar custo e desempenho.","tags":["hot-data","cold-data","hot-cold","archive","tiering"]},{"term":"Fragmentação de índice","full":"","definition":"Com o tempo, inserts/deletes/updates fazem a ordem lógica das páginas de índice se afastar da ordem física e o preenchimento das páginas cair. Isso gera I/O desnecessário e desperdício de espaço, degradando o desempenho. É corrigida com REBUILD ou REORGANIZE.","tags":["index-fragmentation","fragmentation","index","maintenance","performance"]},{"term":"Two-Phase Commit","full":"2PC","definition":"Um protocolo que fornece commit atômico para uma transação distribuída que abrange vários bancos/recursos. Funciona em duas fases: primeiro o coordenador pergunta a todos os participantes se estão prontos (prepare); se todos concordarem, faz commit, e se um recusar, todos fazem rollback. É lento e sensível a falhas do coordenador.","tags":["two-phase-commit","2pc","distributed","distributed","atomic"]}]},"guide/glossary-2.json":{"terms":[{"term":"LSM Tree","full":"Log-Structured Merge Tree","definition":"Uma estrutura de armazenamento que primeiro acumula as escritas em uma estrutura em memória (memtable) e as descarrega em disco como blocos ordenados. Transforma escritas aleatórias em escritas sequenciais para alto throughput de escrita; as leituras varrem vários níveis. É a base de RocksDB, Cassandra e LevelDB.","tags":["storage","storage engine","lsm","write"]},{"term":"B+ Tree","full":"","definition":"Uma estrutura de árvore balanceada em que todos os dados ficam nos nós folha e os nós internos contêm apenas chaves de roteamento. Folhas encadeadas aceleram varreduras de intervalo. É a estrutura mais comum para índices de bancos relacionais.","tags":["index","index structure","storage","storage engine","btree"]},{"term":"Bloom Filter","full":"","definition":"Uma estrutura de dados probabilística que verifica com pouca memória se um elemento está em um conjunto. Responde \"definitivamente não\" ou \"provavelmente sim\"; falsos positivos são possíveis, mas falsos negativos não. Usada em engines baseadas em LSM para evitar leituras de disco desnecessárias.","tags":["storage","storage engine","probabilistic","filter","performance"]},{"term":"Consistent Hashing","full":"","definition":"Um método de distribuição que garante que apenas uma pequena fração das chaves se mova quando nós são adicionados ou removidos. Chaves e nós são posicionados em um anel virtual. Usado para distribuição de dados em caches distribuídos e sistemas NoSQL.","tags":["distributed systems","distributed","hashing","sharding","scaling"]},{"term":"Vector Clock","full":"","definition":"Uma estrutura que mantém um contador por nó para acompanhar a ordem causal dos eventos em sistemas distribuídos. Determina se duas atualizações descendem uma da outra ou são concorrentes (conflitantes). Usada na detecção de conflitos e na consistência eventual.","tags":["distributed systems","distributed","clock","causality","consistency"]},{"term":"Gossip Protocol","full":"","definition":"Um método de comunicação em que cada nó espalha periodicamente seu estado para alguns pares escolhidos aleatoriamente, de modo que a informação chega a todo o cluster como uma epidemia. Não exige coordenador central, é escalável e tolerante a falhas. Usado para gerenciamento de membros no Cassandra e no Consul.","tags":["distributed systems","distributed","gossip","cluster","membership"]},{"term":"Raft","full":"","definition":"Um algoritmo de consenso projetado para ser mais fácil de entender que o Paxos. Elege um líder, anexa todas as escritas a um log replicado por meio do líder e as torna duráveis com a confirmação da maioria. Usado pelo etcd e pelo Consul.","tags":["distributed systems","distributed","consensus","raft","replication"]},{"term":"Paxos","full":"","definition":"O algoritmo de consenso clássico que garante que uma maioria concorde com um único valor em uma rede não confiável. É correto, mas considerado complexo de implementar; forma a base teórica de muitos sistemas distribuídos. Usado em sistemas como o Google Chubby.","tags":["distributed systems","distributed","consensus","paxos","agreement"]},{"term":"Eleição de líder (Leader Election)","full":"","definition":"O processo de selecionar um único nó (o líder) para coordenar uma tarefa específica em um cluster distribuído. Se o líder atual falhar, um novo líder é eleito automaticamente. Geralmente exige aprovação da maioria (quórum) para evitar split-brain.","tags":["distributed systems","distributed","leader","election","coordination"]},{"term":"Quorum Write/Read","full":"","definition":"O número mínimo de nós necessário para que uma leitura ou escrita seja considerada válida. Quando W + R > N, é garantido alcançar o dado mais recente. Permite ajustar o equilíbrio entre consistência e disponibilidade.","tags":["distributed systems","distributed","quorum","consistency","replication"]},{"term":"WAL Shipping","full":"Write-Ahead Log Shipping","definition":"Enviar os registros de WAL gerados pelo servidor primário para servidores standby e reaplicá-los lá. Assim o standby mantém uma cópia quase atual do banco primário. É a base da streaming replication do PostgreSQL.","tags":["replication","replication","wal","high-availability","standby"]},{"term":"Log Shipping","full":"","definition":"Um método simples de replicação que copia backups do log de transações para um servidor standby em intervalos regulares e os restaura. Seu atraso é maior que o do streaming, mas é fácil de configurar. Muito usado para recuperação de desastres no SQL Server.","tags":["replication","replication","log","backup","standby"]},{"term":"Snapshot Isolation","full":"","definition":"Um nível de isolamento em que cada transação vê um snapshot consistente dos dados do momento em que começou. Leitores não bloqueiam escritores; porém, está sujeito a algumas anomalias como write skew. Implementado junto com o MVCC.","tags":["isolation level","isolation","mvcc","snapshot","concurrency"]},{"term":"Serializable Snapshot Isolation (SSI)","full":"Serializable Snapshot Isolation","definition":"Um método que fornece serializabilidade real sobre o snapshot isolation, rastreando dependências perigosas de leitura-escrita. Quando um conflito é detectado, uma das transações é revertida. Usado no nível SERIALIZABLE do PostgreSQL.","tags":["isolation level","isolation","serializable","ssi","concurrency"]},{"term":"Gap Lock","full":"","definition":"Um lock no intervalo entre registros de índice (uma faixa que ainda não existe) que impede a inserção de novas linhas nessa faixa. Usado para evitar phantom reads. Entra em ação no nível REPEATABLE READ do InnoDB.","tags":["locking","lock","innodb","phantom","concurrency"]},{"term":"Next-Key Lock","full":"","definition":"A combinação de um lock em um registro de índice com um lock no intervalo anterior a ele (gap lock). Impede inserts fantasmas protegendo tanto a linha existente quanto a faixa. É o comportamento padrão de lock de linha do InnoDB.","tags":["locking","lock","innodb","gap","concurrency"]},{"term":"Lock otimista (Optimistic Locking)","full":"","definition":"Um método que supõe que conflitos são raros e trabalha sem obter locks, verificando apenas no commit se os dados mudaram. Geralmente implementado com número de versão ou timestamp. Se um conflito for encontrado, a operação é repetida.","tags":["locking","lock","optimistic","concurrency","concurrency"]},{"term":"Lock pessimista (Pessimistic Locking)","full":"","definition":"Um método que supõe que haverá conflitos e obtém um lock imediatamente ao ler ou modificar os dados. Outras transações esperam até o lock ser liberado. Protege a integridade dos dados em ambientes de alta contenção, mas reduz a concorrência.","tags":["locking","lock","pessimistic","concurrency","concurrency"]},{"term":"Idempotência","full":"","definition":"A propriedade de que executar uma operação uma ou várias vezes produz o mesmo resultado. Permite novas tentativas seguras após erros de rede. Em sistemas distribuídos, evita que requisições duplicadas causem efeitos colaterais.","tags":["distributed systems","distributed","idempotent","retry","reliability"]},{"term":"Circuit Breaker","full":"","definition":"Um padrão de projeto que protege o sistema cortando temporariamente as chamadas a um serviço que falha repetidamente. Enquanto o circuito está \"aberto\", as requisições são rejeitadas rapidamente, e uma chamada de teste é feita depois de um tempo. Evita falhas em cascata.","tags":["distributed systems","distributed","fault tolerance","resilience","pattern"]},{"term":"Saga Pattern","full":"","definition":"Um padrão que gerencia transações longas que abrangem vários serviços, tornando cada etapa uma transação local e usando transações de compensação em caso de falha. Fornece consistência eventual em vez de ACID em um ambiente distribuído. Comum em arquiteturas de microsserviços.","tags":["distributed systems","distributed","saga","microservices","pattern"]},{"term":"Outbox Pattern","full":"","definition":"Um padrão que grava a mensagem em uma tabela \"outbox\" na mesma transação para tornar atômicas a atualização do banco e a publicação da mensagem. Um processo separado lê essa tabela e publica a mensagem. Isso evita inconsistência entre os dados e a publicação de eventos.","tags":["distributed systems","distributed","outbox","messaging","pattern"]},{"term":"Fan-out","full":"","definition":"Distribuir uma única operação para muitas suboperações ou destinos; por exemplo, gravar uma postagem nos feeds de milhares de seguidores. Pode ser feito no momento da escrita (write fan-out) ou da leitura (read fan-out). Uma decisão de projeto importante na escalabilidade.","tags":["distributed systems","distributed","scaling","fanout","architecture"]},{"term":"Hotspot","full":"","definition":"Concentração excessiva de carga em um nó, partição ou chave específica. Esse ponto vira um gargalo e limita o desempenho de todo o sistema. Uma shard keying mal escolhida é uma causa comum.","tags":["distributed systems","distributed","hotspot","performance","sharding"]},{"term":"Skew (desequilíbrio de dados)","full":"","definition":"Distribuição desigual de dados ou carga entre partições. Algumas partições transbordam enquanto outras ficam vazias, e a eficiência paralela cai. Equilibrado pela escolha da chave ou por salting.","tags":["distributed systems","distributed","skew","imbalance","sharding"]},{"term":"Índice parcial (Partial Index)","full":"","definition":"Um índice que cobre apenas as linhas da tabela que satisfazem uma condição WHERE. Reduz o tamanho do índice, barateia a manutenção e acelera o subconjunto consultado com frequência. Usado, por exemplo, para indexar apenas as linhas ativas.","tags":["index","index type","postgresql","partial","performance"]},{"term":"Índice de expressão (Expression Index)","full":"","definition":"Um índice criado sobre o resultado de uma expressão ou função em vez de uma coluna. Por exemplo, criado sobre LOWER(email), acelera buscas que ignoram maiúsculas/minúsculas. A consulta precisa usar a mesma expressão.","tags":["index","index type","expression","function","performance"]},{"term":"Índice GIN","full":"Generalized Inverted Index","definition":"Um tipo de índice invertido que indexa vários componentes dentro de um valor. Ideal quando um campo contém muitas chaves, como arrays, JSONB e busca full-text. Usado no PostgreSQL.","tags":["index","index type","postgresql","gin","jsonb"]},{"term":"Índice GiST","full":"Generalized Search Tree","definition":"Uma estrutura de índice extensível baseada em árvore; estratégias de busca personalizadas podem ser definidas para diferentes tipos de dados. Muito adequada para consultas geoespaciais (geometria), de intervalos e de vizinho mais próximo. É a base do PostGIS.","tags":["index","index type","postgresql","gist","geospatial"]},{"term":"TOAST","full":"The Oversized-Attribute Storage Technique (técnica de armazenamento de atributos grandes)","definition":"A técnica do PostgreSQL para comprimir valores grandes de campos que não cabem em uma página e armazená-los em uma área separada. Valores grandes de texto e JSONB são divididos de forma transparente. Preserva o desempenho mantendo a tabela principal compacta.","tags":["storage","storage engine","postgresql","toast","large-values"]},{"term":"Index-Only Scan","full":"","definition":"Uma varredura que produz o resultado só a partir do índice, sem ler a tabela, porque todos os dados necessários estão no índice. Reduz bastante o acesso ao disco. No PostgreSQL funciona em conjunto com o visibility map.","tags":["index","index scan","scan","performance","postgresql"]},{"term":"HTAP","full":"Hybrid Transactional/Analytical Processing (processamento transacional/analítico híbrido)","definition":"Uma abordagem que executa cargas transacionais (OLTP) e analíticas (OLAP) juntas em um único sistema. Elimina o atraso de mover os dados para um armazenamento separado para análise (ETL). Geralmente combina armazenamento por linhas e por colunas.","tags":["analytics","oltp","olap","htap","architecture"]},{"term":"Shard keying (Sharding Key)","full":"","definition":"A coluna ou colunas que determinam em qual shard uma linha cai. Uma chave bem escolhida distribui a carga de maneira uniforme e evita hotspots. Uma escolha ruim leva a desequilíbrio de dados e consultas cross-shard caras.","tags":["distributed systems","distributed","sharding","key","scaling"]},{"term":"Rebalanceamento","full":"","definition":"Redistribuir os dados entre as partições quando nós são adicionados ou removidos ou quando a carga fica desequilibrada. O objetivo é igualar a carga e usar os recursos com eficiência. Gera custo de rede e I/O enquanto roda.","tags":["distributed systems","distributed","rebalancing","scaling","sharding"]},{"term":"Fencing","full":"","definition":"Um mecanismo que evita corrupção de dados impedindo que um nó obsoleto ou isolado escreva em um recurso compartilhado. Geralmente usa-se um \"fencing token\" crescente para que requisições obsoletas sejam rejeitadas. Limita o impacto do split-brain.","tags":["distributed systems","distributed","fencing","safety","split-brain"]},{"term":"Watermark","full":"","definition":"Em sistemas de stream processing, um marcador de progresso que indica que todos os eventos até um certo tempo são considerados recebidos. Usado para tratar eventos que chegam atrasados e decidir quando fechar cálculos de janela.","tags":["stream processing","streaming","watermark","event time","event"]},{"term":"Tombstone","full":"","definition":"Um marcador especial gravado para indicar que um registro foi excluído. Em sistemas LSM e distribuídos, em que os dados não são excluídos fisicamente de imediato, garante que a exclusão se propague para todas as réplicas. A limpeza real acontece durante a compaction.","tags":["storage","storage engine","lsm","tombstone","delete"]},{"term":"Compaction (LSM)","full":"","definition":"Mesclar e regravar os arquivos ordenados (SSTables) em disco nas LSM trees. Melhora o desempenho de leitura e o uso de disco eliminando versões antigas e tombstones. Roda em segundo plano e gera carga de escrita.","tags":["storage","storage engine","lsm","compaction","maintenance"]},{"term":"Read Repair","full":"","definition":"Uma técnica que, quando uma inconsistência entre réplicas é detectada durante uma leitura, a corrige gravando o valor mais recente nos nós atrasados. O sistema se torna consistente por meio do tráfego normal de leitura. Usada em sistemas como o Cassandra.","tags":["distributed systems","distributed","repair","consistency","replication"]},{"term":"Hinted Handoff","full":"","definition":"Armazenar uma escrita como \"hint\" em outro nó enquanto o nó de destino está temporariamente inacessível e entregá-la quando o nó voltar. Garante que as escritas não se percam em falhas transitórias. Apoia a consistência eventual.","tags":["distributed systems","distributed","handoff","availability","replication"]},{"term":"Consistência eventual","full":"","definition":"Um modelo de consistência fraca que garante que todas as réplicas acabarão convergindo para o mesmo valor se as novas atualizações pararem. Permite inconsistências de curta duração, mas oferece alta disponibilidade e baixa latência. É o padrão em muitos sistemas NoSQL.","tags":["distributed systems","distributed","consistency","eventual","nosql"]},{"term":"Consistência forte","full":"","definition":"Um modelo de consistência em que todos os leitores veem imediatamente o valor mais recente assim que uma escrita termina. É intuitivo de usar, mas, como exige coordenação, seu custo em latência e disponibilidade é alto. Preferido em sistemas financeiros.","tags":["distributed systems","distributed","consistency","strong","strong consistency"]},{"term":"Linearizabilidade","full":"","definition":"O nível de consistência mais forte, que garante que cada operação pareça ocorrer em um único instante entre seu início e seu fim, e que todas as operações se encaixem em uma única ordem de tempo real. O sistema se comporta como se fosse uma única cópia. É caro de implementar.","tags":["distributed systems","distributed","consistency","linearizability","strong consistency"]},{"term":"Two-Phase Locking (2PL)","full":"Two-Phase Locking","definition":"Uma regra de lock em duas fases em que uma transação primeiro só adquire locks (fase de crescimento) e depois só libera locks (fase de encolhimento). Essa disciplina garante a serializabilidade. Na forma estrita (Strict 2PL), os locks são mantidos até o commit.","tags":["locking","lock","2pl","serializable","concurrency"]},{"term":"Detecção de deadlock","full":"","definition":"Um mecanismo que detecta um deadlock, em que duas ou mais transações esperam umas pelas outras por locks que mantêm. Geralmente é encontrado procurando um ciclo no wait-for graph, e uma transação é escolhida como vítima e revertida. O sistema então volta a fluir.","tags":["locking","lock","deadlock","deadlock detection","concurrency"]}]},"guide/glossary-3.json":{"terms":[{"term":"Write Amplification","full":"Write Amplification","definition":"Uma única escrita lógica causar muito mais escritas físicas na camada de armazenamento (compaction LSM, regravação de páginas, WAL, apagamento de blocos de SSD). Valores altos desgastam os discos e reduzem o throughput de escrita.","tags":["storage","lsm","performance","ssd"]},{"term":"Read Amplification","full":"Read Amplification","definition":"Uma única leitura lógica exigir, na prática, várias leituras físicas/internas. Procurar uma chave em muitos níveis de uma LSM tree é o exemplo típico; bloom filters e compaction a reduzem.","tags":["storage","lsm","performance"]},{"term":"LSM-tree","full":"Log-Structured Merge Tree","definition":"Uma estrutura de dados que primeiro absorve as escritas em uma estrutura em memória (memtable), as descarrega em disco como blocos ordenados (SSTables) e as mescla em segundo plano (compaction). Ideal para cargas com muita escrita; usada pelo RocksDB e pelo Cassandra.","tags":["storage","lsm","write-heavy"]},{"term":"B+tree","full":"B+ Tree","definition":"A estrutura clássica dos índices de bancos relacionais. Todos os dados ficam nos nós folha e as folhas são encadeadas em uma lista ligada; oferece desempenho de leitura equilibrado para consultas pontuais e de intervalo.","tags":["index","btree","storage"]},{"term":"Fill Factor","full":"Fill Factor","definition":"A proporção que especifica quanto uma página de índice/tabela é preenchida inicialmente. Deixar espaço livre reduz page splits em futuros updates/inserts; fillfactor no PG, fill factor no MSSQL.","tags":["index","storage","tuning"]},{"term":"HOT Update","full":"Heap-Only Tuple Update","definition":"No PostgreSQL, um update que não altera nenhuma coluna indexada cria a nova versão da linha na mesma página e não atualiza os índices. Reduz o bloat de índice e diminui o custo do update.","tags":["postgres","mvcc","update","performance"]},{"term":"Bloat","full":"Table/Index Bloat","definition":"Uma tabela/índice ocupar mais espaço do que o necessário em engines MVCC por causa de versões mortas de linhas não limpas ou páginas vazias. Aumenta o custo das varreduras; o espaço é recuperado com VACUUM/reorg.","tags":["mvcc","postgres","maintenance","bloat"]},{"term":"Autovacuum","full":"Automatic VACUUM","definition":"O processo em segundo plano do PostgreSQL que faz automaticamente a limpeza de dead tuples, a coleta de estatísticas e o congelamento de IDs de transação. É ajustado à carga por parâmetros de limite e de custo.","tags":["postgres","vacuum","maintenance"]},{"term":"Freeze / Wraparound","full":"Transaction ID Freeze / Wraparound","definition":"No PostgreSQL, marcar linhas antigas como 'frozen' para evitar que os IDs de transação de 32 bits deem a volta (wraparound). Se negligenciado, o banco para de aceitar escritas para evitar perda de dados.","tags":["postgres","mvcc","vacuum","wraparound"]},{"term":"Checkpoint","full":"Checkpoint","definition":"O evento em que as páginas sujas em memória são gravadas em disco e o ponto a partir do qual a recuperação começará é registrado. Encurta o tempo de recuperação após falhas; sua frequência é um equilíbrio entre picos de I/O e tempo de recuperação.","tags":["recovery","wal","internals","checkpoint"]},{"term":"Fuzzy Checkpoint","full":"Fuzzy Checkpoint","definition":"Um tipo de checkpoint que grava as páginas sujas continuamente em segundo plano, distribuídas no tempo, sem parar o sistema. Mantém os tempos de resposta previsíveis evitando surtos repentinos de I/O (checkpoint spikes).","tags":["recovery","checkpoint","internals"]},{"term":"Redo","full":"Redo Log / Roll Forward","definition":"O registro mantido para reaplicar (roll forward) as alterações feitas por uma transação durante a recuperação. Restaura as alterações com commit que não tinham chegado ao disco antes de uma queda.","tags":["recovery","oracle","wal","redo"]},{"term":"Undo","full":"Undo Log / Rollback","definition":"O registro mantido para reverter uma transação e fornecer versões antigas das linhas para o MVCC. No Oracle/InnoDB, as versões antigas são lidas dos undo segments.","tags":["mvcc","oracle","innodb","undo","rollback"]},{"term":"Snapshot MVCC","full":"Snapshot MVCC","definition":"A visão lógica de um instante que determina quais versões de linha são visíveis para que uma transação tenha uma leitura consistente. É tirado no início da transação ou da instrução (conforme o nível de isolamento).","tags":["mvcc","concurrency","isolation","snapshot"]},{"term":"Anomalia de isolamento","full":"Anomalias de isolamento","definition":"Inconsistências produzidas por transações concorrentes com isolamento insuficiente: dirty read (ler dados sem commit), non-repeatable read (a mesma linha mudar), phantom (surgirem novas linhas) e write skew (escritas aparentemente independentes violarem juntas uma regra).","tags":["isolation","concurrency","anomaly","acid"]},{"term":"2PL","full":"Two-Phase Locking","definition":"Um protocolo que garante a serializabilidade com locks: uma transação primeiro só adquire locks (fase de crescimento) e, a partir de certo ponto, só os libera (fase de encolhimento). O Strict 2PL mantém os locks até o commit.","tags":["concurrency","locking","serializable","2pl"]},{"term":"MVTO","full":"Multi-Version Timestamp Ordering","definition":"Um método de controle de concorrência que atribui timestamps às transações e ordena as leituras/escritas sobre dados multiversão de acordo com eles. Resolve conflitos com timestamps em vez de locks.","tags":["concurrency","mvcc","timestamp","protocol"]},{"term":"Mutex","full":"Mutual Exclusion (exclusão mútua)","definition":"Uma primitiva de exclusão mútua que garante que apenas uma thread acesse um recurso por vez. Nos bancos, desempenha um papel semelhante ao latch na proteção de estruturas de memória compartilhada.","tags":["concurrency","internals","mutex"]},{"term":"Spinlock","full":"Spinlock","definition":"Um lock de duração muito curta que faz a thread ficar em loop (busy-wait) em vez de dormir até o lock ser liberado. Barato para seções críticas muito curtas; sob contenção, queima CPU.","tags":["concurrency","internals","spinlock","cpu"]},{"term":"Buffer Pool","full":"Buffer Pool / Buffer Cache","definition":"Um cache que reduz o I/O de disco mantendo em memória as páginas de dados acessadas com frequência. O algoritmo de eviction (LRU, clock-sweep) decide qual página sai; seu tamanho é definido conforme o working set.","tags":["memory","cache","internals","buffer"]},{"term":"Working Set","full":"Working Set","definition":"O conjunto de dados que uma carga acessa ativamente em uma determinada janela de tempo. Quando o buffer pool é grande o suficiente para conter esse conjunto, o I/O físico é minimizado; é diferente do tamanho total dos dados.","tags":["memory","cache","sizing","performance"]},{"term":"Skew","full":"Data Skew","definition":"Uma situação em que os valores não estão distribuídos uniformemente e alguns ocorrem com muito mais frequência. É a principal causa de estimativas de cardinalidade erradas, problemas de parameter sniffing e hotspots de sharding; é tratado com histogramas.","tags":["statistics","distribution","skew","performance"]},{"term":"Plan Cache","full":"Plan Cache","definition":"A área de memória em que os planos de execução compilados são guardados para reutilização. Evita o custo do hard parse, mas traz riscos de parameter sniffing e planos obsoletos; plan cache no MSSQL, library cache no Oracle.","tags":["optimizer","plan-cache","parsing"]},{"term":"Hard/Soft Parse","full":"Hard Parse / Soft Parse","definition":"Hard parse: o SQL é analisado, otimizado e um plano é gerado do zero (caro). Soft parse: um plano existente é encontrado no cache e reutilizado (barato). Bind variables aumentam a proporção de soft parses.","tags":["parsing","oracle","performance","plan-cache"]},{"term":"Connection Storming","full":"Connection Storm","definition":"Um grande número de novas conexões ao banco sendo abertas ao mesmo tempo em um curto intervalo. Sobrecarrega o banco com o custo de estabelecer conexões e com pressão de memória; geralmente vem do esgotamento do pool ou de uma onda de reconexões.","tags":["connections","pooling","overload"]},{"term":"Thundering Herd","full":"Thundering Herd Problem","definition":"Muitos clientes atingindo o mesmo recurso ao mesmo tempo após um evento (expiração de cache, liberação de um lock, retorno de um serviço). Mitigado com backpressure, jitter e padrões single-flight.","tags":["concurrency","cache","overload","resilience"]},{"term":"Backpressure","full":"Backpressure","definition":"Um sistema desacelerar ou rejeitar o produtor em vez de aceitar uma carga que não consegue suportar (limites de fila, rate limits). Permite uma degradação controlada em vez de colapsar sob sobrecarga.","tags":["resilience","flow-control","overload"]},{"term":"Lease","full":"Lease","definition":"Um direito de liderança/recurso concedido a um nó por um período fixo, que perde a validade automaticamente quando expira. Por ter prazo, impede que um nó travado continue líder para sempre.","tags":["distributed","leader-election","lease"]},{"term":"Read-Your-Writes","full":"Read-Your-Writes Consistency","definition":"Consistência de sessão que garante que um usuário sempre veja a própria alteração já na leitura seguinte. Ao rotear para réplicas com atraso, é obtida com roteamento/tokens especiais.","tags":["distributed","consistency","session","replication"]},{"term":"Consistência causal","full":"Consistência causal","definition":"Um modelo de consistência mais forte que o eventual, que garante que operações com relação causal sejam vistas na mesma ordem em todos os nós. Operações sem relação (concorrentes) podem ser vistas em ordens diferentes.","tags":["distributed","consistency","causal"]},{"term":"CAP","full":"Consistency, Availability, Partition tolerance (consistência, disponibilidade, tolerância a partições)","definition":"O teorema que afirma que, durante uma partição de rede, um sistema distribuído só pode escolher entre consistência e disponibilidade. Sem partição, esse trade-off não é obrigatório.","tags":["distributed","cap","consistency","theory"]},{"term":"PACELC","full":"PACELC Theorem","definition":"Um modelo que estende o CAP: sob partição (P), a escolha é entre Availability e Consistency; senão (E), entre Latency e Consistency. Também cobre o trade-off entre latência e consistência na operação normal.","tags":["distributed","cap","pacelc","latency","theory"]},{"term":"Partição quente (Hot Partition)","full":"Hot Partition / Hot Spot","definition":"Carga se acumulando de forma desproporcional em uma única partição/shard. Vem de uma shard key de baixa cardinalidade, baseada em tempo ou monotonicamente crescente; vira gargalo nesse nó e impede a escalabilidade.","tags":["distributed","sharding","hot-spot","skew"]},{"term":"Columnstore","full":"Column-Oriented Storage","definition":"Um formato em que os dados são armazenados por coluna, e não por linha. Consultas analíticas leem só as colunas necessárias, com alta compressão e execução vetorizada; ideal para OLAP.","tags":["olap","columnar","analytics","compression"]},{"term":"Execução vetorizada","full":"Execução vetorizada","definition":"Operadores de consulta trabalhando sobre um bloco (batch) de valores de coluna por vez, em vez de linha a linha. Aumenta muito o throughput de consultas analíticas aproveitando melhor os caches da CPU e o SIMD.","tags":["olap","execution","performance","columnar"]},{"term":"Zone Map / Min-Max","full":"Zone Map / Min-Max Index","definition":"Metadados leves que armazenam o valor mínimo e máximo da coluna para cada bloco de dados. Reduz o custo de varredura pulando, sem ler, os blocos que não podem atender ao predicado da consulta (block skipping).","tags":["olap","index","pruning","columnar"]},{"term":"Replicação lógica","full":"Replicação lógica","definition":"Replicação que publica e assina alterações no nível de linha (eventos lógicos) em vez de blocos físicos. Permite tabelas seletivas e cenários entre versões e bidirecionais; no PG é fornecida por publication/subscription.","tags":["replication","postgres","logical","cdc"]},{"term":"GTID","full":"Global Transaction Identifier","definition":"Um identificador globalmente único atribuído a cada transação na replicação do MySQL. Ao acompanhar a posição da réplica pelo ID da transação em vez de arquivo/offset, torna o failover e a reconfiguração seguros e simples.","tags":["mysql","replication","gtid","failover"]},{"term":"High Water Mark","full":"High Water Mark","definition":"O limite de bloco mais alto já usado em um segmento/tabela. No Oracle, um full table scan lê até esse limite; como ele não baixa após exclusões em massa, pode levar à varredura de blocos vazios e a bloat.","tags":["oracle","storage","internals","scan"]}]},"playbooks/playbooks.json":{"schemaVersion":1,"playbooks":[{"id":"db-slow","title":"O banco está lento","icon":"🐢","symptom":"Lentidão em toda a aplicação; as consultas demoram muito mais que o normal e os usuários estão reclamando.","steps":[{"title":"Primeiro, esclareça o que exatamente está lento","detail":"Está tudo lento ou uma consulta/tela específica? Quando começou, e coincide com um deploy/patch/crescimento de dados? Afeta o sistema todo ou um único banco? Isso restringe a busca a um eixo: CPU, I/O, lock ou mudança de plano."},{"title":"Veja as sessões ativas e os wait events","detail":"O que está rodando e o que está esperando agora? Um wait event dominante (I/O, lock, log) aponta o gargalo.","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":"Verifique bloqueios","detail":"A causa mais comum de lentidão é uma sessão bloqueando outras. Encontre a sessão bloqueadora e identifique o início da cadeia.","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":"Levante as consultas mais caras","detail":"Encontre as 10 consultas que mais consomem recursos. Geralmente 90% do problema vem de um punhado de consultas.","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":"Examine o plano da consulta suspeita","detail":"Obtenha o EXPLAIN da consulta lenta. Procure full table scans, índices ausentes, ordem de join ruim ou estatísticas desatualizadas. Se o plano mudou de repente, considere coletar estatísticas.","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":"Verifique os recursos do sistema","detail":"No nível do SO, verifique CPU, espera de I/O (iowait), memória e uso de disco. Verifique o cache hit ratio; se estiver baixo, pode haver um gargalo de memória. O problema pode estar fora do banco (disco cheio, VM vizinha barulhenta)."},{"title":"Decida: correção rápida ou definitiva","detail":"Para alívio imediato: mate a consulta descontrolada, crie o índice ausente, colete estatísticas. Para uma correção definitiva: redesenhe a consulta/índice, corrija as configurações de memória, garanta a estabilidade do plano (baseline/hint)."}],"related":["active-sessions","blocking-sessions","top-slow-queries","explain-plan","cache-hit-ratio"]},{"id":"disk-full","title":"Disco / tablespace cheio","icon":"💽","symptom":"Erros 'unable to extend', 'disk full', 'log file full'; as escritas estão parando.","steps":[{"title":"Não entre em pânico; primeiro descubra o que está cheio","detail":"É um datafile, o log de transações, a área de archive/redo, o temp ou o disco do SO? Limpar o lugar errado não ajuda. Verifique o disco com df -h no nível do SO e as views de espaço dentro do banco."},{"title":"Meça o uso","detail":"Qual tablespace/arquivo/diretório está cheio, e em que percentual?","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":"Encontre os maiores consumidores","detail":"Identifique as maiores tabelas/segmentos, os maiores arquivos de log/archive e backups antigos desnecessários. Na maioria das vezes, a culpa é de uma única tabela descontrolada ou de logs arquivados acumulados.","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":"Recupere espaço com segurança (rápido)","detail":"Para logs/archives: faça o backup e depois remova logs arquivados/backups antigos (Oracle: RMAN delete archivelog; MSSQL: faça um backup de log e reduza o log com shrink). No Redis: maxmemory-policy e eviction. NUNCA apague manualmente um datafile em uso; NUNCA apague logs arquivados sem backup."},{"title":"Aumente a capacidade de forma permanente","detail":"Adicione espaço ao datafile ou ative o autoextend (Oracle: ALTER DATABASE DATAFILE ... AUTOEXTEND ON MAXSIZE), aumente o disco, adicione um tablespace. Corrija a causa raiz: rotação de logs, job de limpeza de archives, política de retenção."},{"title":"Evite a recorrência","detail":"Configure alertas de uso de disco (limites de 80%/90%), automatize a limpeza de archives/logs e defina claramente a política de retenção. Evite precisar abrir este playbook de novo."}],"related":["free-space","largest-tables","database-size","reclaim-space","last-backup-status"]},{"id":"blocking","title":"Crise de bloqueios e locks","icon":"🔒","symptom":"Consultas travam, 'lock wait timeout', muitas sessões esperando, mas a CPU está baixa.","steps":[{"title":"Encontre o início da cadeia de bloqueio (root blocker)","detail":"Descubra quem bloqueia quem; o verdadeiro culpado é a sessão que não espera por nada, mas faz as outras esperarem. Concentre-se na sessão no topo da cadeia.","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":"Entenda o que o root blocker está fazendo","detail":"É uma transação aberta sem commit? A aplicação a deixou 'idle in transaction'? É um batch longo? Entenda o que é antes de matá-la às cegas — ela pode estar quase terminando.","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":"Decida: esperar, resolver pela aplicação ou matar","detail":"Se estiver quase terminando, espere. Se a aplicação puder fazer commit/rollback, acione isso. Caso contrário, se o negócio estiver parado, encerre o root blocker. Antes de matar, considere o impacto (tempo de rollback, dados)."},{"title":"Encerre o root blocker se necessário","detail":"Mate apenas a sessão no início da cadeia; as sessões abaixo dela são liberadas automaticamente.","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":"Corrija a causa raiz","detail":"Um índice ausente pode causar locks amplos; a aplicação pode manter transações abertas por tempo demais; o nível de isolamento pode estar errado. Crie índices, encurte as transações, defina um timeout para 'idle in transaction' e escolha um nível de isolamento adequado."}],"related":["blocking-sessions","kill-session","open-transactions"]},{"id":"connection-storm","title":"Connection storm (conexões demais)","icon":"🌊","symptom":"'too many connections', 'ORA-00018', 'remaining connection slots reserved' — novas conexões estão sendo rejeitadas.","steps":[{"title":"Meça o estado atual","detail":"Quantas conexões existem, qual é o limite, e quantas estão ativas vs. ociosas?","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":"Identifique a origem: quem/de onde","detail":"Qual aplicação/host/usuário está abrindo as conexões? Geralmente o pool de um único servidor de aplicação estourou ou há um vazamento de conexões (um monte de sessões 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":"Ganhe fôlego imediatamente","detail":"Limpe as conexões ociosas há muito tempo/idle in transaction. Se necessário, derrube em massa as conexões da aplicação problemática. Use o slot reservado para login de administrador (PG superuser_reserved_connections)."},{"title":"A correção certa: pooling de conexões","detail":"Aumentar max_connections sem limite consome memória e só adia o problema. A correção certa é um pool de conexões no lado da aplicação (HikariCP, PgBouncer, ProxySQL) com um tamanho de pool razoável. O tamanho do pool costuma ficar em torno de (núcleos*2 + número de discos) — veja a calculadora em Ferramentas > Connection Pool."},{"title":"Evite vazamentos e recorrência","detail":"Garanta que a aplicação feche as conexões (finally/using). Defina idle_in_transaction_session_timeout e wait_timeout. Configure um alerta para o número de conexões."}],"related":["connection-count","kill-session","open-transactions"]},{"id":"replication-lag","title":"Lag de replicação / replicação parada","icon":"🔁","symptom":"O standby/réplica está ficando para trás ou parou completamente; as réplicas de leitura mostram dados desatualizados.","steps":[{"title":"Qual o tamanho do atraso, e ele está crescendo ou estável","detail":"Qual é o atraso em segundos/bytes? É uma defasagem estável ou cresce continuamente? Se cresce, a réplica não acompanha a aplicação; se está estável, houve uma parada momentânea.","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":"A replicação está rodando, há erros","detail":"Qual é o estado das threads IO/SQL, do processo de aplicação, a conexão caiu? Se houver um erro (ex.: linha conflitante, tabela ausente), a aplicação parou; leia a mensagem de erro.","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":"Encontre o gargalo","detail":"Por que não consegue acompanhar? Aplicação em thread única mais uma carga pesada de escrita (PG/MySQL aplicam majoritariamente em série), um gargalo de I/O no standby, a rede, ou uma consulta longa bloqueando a aplicação (PG hot_standby_feedback / recovery conflict)?"},{"title":"Feche o atraso","detail":"Acelere a aplicação: ative a aplicação paralela (MySQL replica_parallel_workers — slave_parallel_workers antes da 8.0.26; o PG não tem, mas há configurações de recovery), melhore o I/O do standby, resolva a consulta que bloqueia a aplicação. Se parou com erro: corrija o erro (resolva a linha conflitante manualmente) e retome a replicação."},{"title":"Reconstrua se estiver quebrada","detail":"Se a réplica estiver muito atrasada/quebrada, ressincronizar é o mais limpo: reconstrua o standby a partir de um backup recente (PG pg_basebackup, MySQL clone/xtrabackup, Oracle RMAN duplicate). Crítico: descubra a causa antes de reconstruir, ou vai acontecer de novo."}],"related":["replication-status","list-replicas","promote-failover"]},{"id":"high-cpu","title":"CPU alta","icon":"🔥","symptom":"CPU do servidor acima de 90%; o sistema inteiro está lento e o load average está alto.","steps":[{"title":"Confirme que é o banco que está consumindo a CPU","detail":"Use top/mpstat no nível do SO para confirmar que o processo que consome CPU é realmente o banco. Às vezes o consumidor é um processo vizinho ou um backup/antivírus. Se o iowait estiver alto, o problema é o disco, não a CPU."},{"title":"Encontre as consultas que mais usam CPU","detail":"Levante as principais consultas ordenadas por tempo de CPU. Geralmente poucas consultas (plano ruim, full scan, índice ausente) queimam a 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":"Verifique se há problema de plano/índice","detail":"Obtenha o plano da consulta problemática. Full table scans, explosões de nested loop, spills de hash join ou planos ruins causados por parameter sniffing/estatísticas desatualizadas queimam CPU. Crie um índice ou colete estatísticas."},{"title":"Alivie imediatamente","detail":"Mate a consulta descontrolada e, se necessário, limite-a com Resource Manager/Resource Governor. Para uma carga que começou de repente, revise o último deploy/mudança de parâmetro."},{"title":"Corrija de forma definitiva","detail":"Corrija a consulta/índice, garanta a estabilidade do plano e agende o job de coleta de estatísticas. Se a CPU estiver constantemente em 100%, pode ser preciso escalar (adicionar CPU, distribuir leituras para réplicas de leitura)."}],"related":["top-slow-queries","explain-plan","active-sessions","update-statistics"]},{"id":"memory-pressure","title":"Pressão de memória / OOM","icon":"🧠","symptom":"O OOM killer mata o processo, 'out of memory', cache hit ratio baixo, swap excessivo, Redis 'OOM command not allowed'.","steps":[{"title":"Quem está consumindo memória","detail":"É a memória alocada pelo banco (buffer pool/SGA), a memória por sessão (PGA/sort/work_mem) ou o SO como um todo? Verifique free/vmstat no nível do SO e as views de memória dentro do banco.","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":"Separe configuração de carga","detail":"O total das configurações de memória excede a RAM física (over-commit)? Calcule shared_buffers + (work_mem * concorrência). Ou é uma carga momentânea (um sort/hash enorme, muitas conexões)?"},{"title":"Específico do Redis: eviction e fragmentação","detail":"Se used_memory atingiu maxmemory, verifique maxmemory-policy (com noeviction, as escritas são rejeitadas). Se mem_fragmentation_ratio estiver alto, use MEMORY PURGE / activedefrag. Encontre chaves grandes com --bigkeys.","engines":{"redis":"CONFIG GET maxmemory-policy\nMEMORY DOCTOR\nredis-cli --bigkeys"}},{"title":"Alivie imediatamente","detail":"Mate a consulta/sessão descontrolada que está comendo memória, reduza temporariamente a memória de sessão como work_mem, derrube conexões desnecessárias. Se o sistema estiver fazendo swap, sair do swap é a prioridade."},{"title":"Dimensione corretamente","detail":"Distribua a RAM corretamente com a calculadora em Ferramentas > Memória/Buffer Pool. Regra geral: em um servidor dedicado, buffer pool/SGA ~70-80% da RAM; a memória total de sessões multiplicada pela concorrência não deve exceder a RAM. Adicione RAM se necessário."}],"related":["cache-hit-ratio","show-config-param","reclaim-space"]},{"id":"log-growth","title":"Crescimento excessivo do log de transações / undo","icon":"📈","symptom":"O arquivo de log de transações ou a área de undo/redo está crescendo rápido; 'log full', 'ORA-01555 snapshot too old', 'unable to extend undo'.","steps":[{"title":"Encontre a transação aberta que faz o log crescer","detail":"O log/undo não pode ser liberado até que a transação ativa mais antiga termine. Uma única transação longa aberta pode estar segurando o log inteiro.","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":"Entenda a causa raiz específica da engine","detail":"MSSQL: no recovery model FULL, o log cresce indefinidamente se não forem feitos backups de log. Oracle: ORA-01555 = retenção/tamanho de undo insuficiente + uma consulta longa. PG: se um replication slot não avança, o WAL se acumula; uma transação longa bloqueia o VACUUM."},{"title":"A ação certa para o log do MSSQL","detail":"Faça um backup de log (BACKUP LOG) — isso torna o log reutilizável. Se o recovery model realmente deveria ser SIMPLE, altere-o. Depois, se necessário (e só se necessário), reduza o log com shrink.","engines":{"mssql":"BACKUP LOG [DB] TO DISK='C:\\backup\\DB_log.trn';\n-- Then, if needed: DBCC SHRINKFILE (N'DB_log', 512);"}},{"title":"Verificação de WAL / replication slot no PG","detail":"Um replication slot que não avança (inativo) causa acúmulo de WAL. Antes de removê-lo, verifique o dono do slot (slot_type, database, plugin): pode ser um standby temporariamente desconectado ou um assinante lógico/CDC (ex.: Debezium). Se o slot for removido, o standby ligado a ele precisa ser reconstruído e o lado assinante/CDC precisa ser ressincronizado. Remova-o apenas se realmente não estiver em uso; para proteção duradoura, defina um limite superior com 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":"Ajuste undo/retenção e evite a recorrência","detail":"Oracle: aumente o tablespace UNDO, defina undo_retention de acordo com as consultas longas (ou RETENTION GUARANTEE). Evite transações longas abertas na aplicação. Monitore se o job de backup de log está rodando."}],"related":["open-transactions","reclaim-space","last-backup-status"]},{"id":"deadlocks","title":"Análise de deadlock","icon":"♻️","symptom":"'deadlock detected', 'ORA-00060', 'chosen as deadlock victim' — transações bloqueiam umas às outras e uma é abortada.","steps":[{"title":"Deadlocks são normais, mas não devem ser frequentes","detail":"O banco detecta o deadlock e o resolve escolhendo uma vítima — isso é intencional. O objetivo é reduzir a frequência. A aplicação deve repetir a transação vítima. Primeiro capture o deadlock graph."},{"title":"Obtenha o deadlock graph/detalhes","detail":"Quais duas (ou mais) sessões, quais recursos e quais modos de lock entraram em conflito?","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":"Resolva o padrão de conflito","detail":"A causa mais comum: duas transações acessando recursos em ordem OPOSTA. Acesse os recursos na MESMA ordem em todos os caminhos de código. A segunda causa mais comum: locks de intervalo amplos por falta de índice — crie o índice necessário."},{"title":"Reduza a duração e o escopo dos locks","detail":"Mantenha as transações curtas (não inclua interação com o usuário dentro de uma transação). Escolha um nível de isolamento adequado. Quando necessário, obtenha os locks de linha cedo (SELECT ... FOR UPDATE com ordenação determinística)."},{"title":"Retry na aplicação é obrigatório","detail":"Deadlocks não podem ser eliminados por completo; implemente retry automático (exponential backoff) para a transação vítima. Isso evita que o usuário veja um erro."}],"related":["blocking-sessions","open-transactions","list-indexes"]},{"id":"db-down","title":"O banco não abre / inacessível","icon":"🚨","symptom":"Não é possível conectar ao serviço, 'connection refused', a instância não sobe, o listener não responde.","steps":[{"title":"Onde quebra: rede, serviço ou instância","detail":"O servidor está acessível (ping/ssh)? O processo/serviço do banco está rodando (ps/systemctl/services.msc)? A porta está escutando (ss -ltnp / telnet host porta)? Isso situa o problema em uma camada: rede / serviço / instância do banco."},{"title":"Verifique o serviço e o listener","detail":"Se o processo do banco não estiver no ar, tente iniciá-lo; se estiver no ar, mas as conexões falharem, veja o listener/porta e a camada de autenticação.","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":"Leia os logs — a resposta está lá","detail":"Se o banco não abre, o motivo está escrito no log: alert log (Oracle), postgresql.log / inicialização, error log do mysqld, ERRORLOG do SQL Server, log do redis. Disco cheio, arquivo corrompido, permissões, conflito de porta, arquivo ausente — tudo aparece aqui."},{"title":"Trate as causas comuns: disco, permissões, porta, corrupção","detail":"O disco está 100% cheio (a causa mais comum)? As permissões do diretório de dados estão quebradas? A porta está ocupada por outro processo? É preciso recovery (após uma queda)? Um control file/redo log está corrompido? Ataque cada um com base na mensagem do log."},{"title":"Recupere e registre o incidente","detail":"O crash recovery geralmente termina sozinho; tenha paciência. Se houver corrupção, recupere a partir de backup/PITR (veja o playbook de Corrupção). Depois, escreva uma análise de causa raiz (RCA): o que aconteceu, por que, e como evitar a recorrência."}],"related":["version-uptime","connect-cli","last-backup-status"]},{"id":"corruption","title":"Corrupção de dados","icon":"🧯","symptom":"'ORA-01578', 'page corruption', 'checksum mismatch', 'MISCONF', erros de consistência de I/O durante leituras.","steps":[{"title":"Mantenha a calma e contenha o alastramento","detail":"Uma intervenção em pânico piora as coisas. Primeiro determine o escopo e, se possível, pare as escritas no objeto afetado. Se for algo de hardware (disco/controladora), verifique também os logs do SO/hardware — consertar o banco não conserta o disco."},{"title":"Determine o escopo: quanto está corrompido","detail":"É um único bloco/página/objeto ou algo generalizado? Execute uma verificação de integridade.","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":"Prioridade: recuperação a partir de backup","detail":"Com corrupção, o caminho mais seguro é restaurar a partir de um backup bom. Se a recuperação no nível de bloco/página for suportada, recupere apenas a parte corrompida (Oracle RMAN BLOCKRECOVER, MSSQL page restore). Ferramentas de reparo (DBCC REPAIR_ALLOW_DATA_LOSS, innodb_force_recovery) CAUSAM PERDA DE DADOS — são o último recurso."},{"title":"Verifique a integridade","detail":"Após a recuperação, execute a verificação de novo (DBCC CHECKDB / RMAN VALIDATE / CHECK TABLE) e confirme que volta limpa. Verifique também a consistência dos dados no lado da aplicação (contagens de linhas, totais críticos)."},{"title":"Causa raiz: geralmente hardware","detail":"A corrupção geralmente vem de falha de disco/memória/controladora. Teste/substitua o hardware, ative checksums (data_checksums, PAGE_VERIFY CHECKSUM) e reforce a rotina de backup + verificação. Agende DBCC CHECKDB / RMAN VALIDATE regularmente."}],"related":["last-backup-status","restore-dump","db-down"]},{"id":"long-running-query","title":"Consulta / job de longa duração","icon":"⏱️","symptom":"Uma única consulta/job está rodando há horas sem terminar; consome recursos ou afeta outros.","steps":[{"title":"Capture a consulta e sua duração","detail":"Qual consulta, há quanto tempo está rodando, qual usuário/aplicação?","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":"Está avançando ou travada","detail":"Está realmente rodando ou esperando um lock? Veja os indicadores de progresso (Oracle v$session_longops, views pg_stat_progress_* do PG). Se estiver esperando, passe para o playbook de Bloqueios.","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":"Decida: esperar ou cancelar","detail":"Se estiver avançando e for terminar logo, espere (o custo de rollback do cancelamento pode fazer demorar ainda mais). Se estiver travada, rodando de forma errada ou afetando a produção, encerre-a. Considere o tempo de rollback antes de cancelar."},{"title":"Encerre se necessário","detail":"Prefira cancelar só a consulta (mantendo a sessão); se não funcionar, mate a sessão.","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":"Corrija de forma definitiva","detail":"Otimize a consulta (índice, plano, paginação/batches), mova jobs pesados para fora do horário de pico e, se necessário, execute-os em partes. Para relatórios recorrentes, considere uma materialized view / réplica de leitura."}],"related":["active-sessions","kill-session","explain-plan","top-slow-queries"]},{"id":"xid-wraparound","title":"Crise de XID wraparound / autovacuum no Postgres","icon":"🧬","symptom":"'database is not accepting commands to avoid wraparound data loss'; o autovacuum não consegue acompanhar, o datfrozenxid está envelhecendo.","steps":[{"title":"Entenda a urgência","detail":"Os IDs de transação do PostgreSQL são de 32 bits; quando se aproximam do esgotamento, o servidor PARA AS ESCRITAS para evitar perda de dados. É uma situação crítica e sensível ao tempo. A boa notícia: tem solução; exige disciplina, não pânico."},{"title":"Meça o quão perto você está","detail":"Levante a idade do XID não congelado mais antigo de cada banco; a proximidade de autovacuum_freeze_max_age (padrão 200M) mostra o perigo.","engines":{"postgres":"SELECT datname, age(datfrozenxid) AS xid_age\nFROM pg_database ORDER BY xid_age DESC;"}},{"title":"Encontre as tabelas mais antigas","detail":"O problema geralmente vem de algumas tabelas grandes/muito escritas; concentre-se nos valores de relfrozenxid mais antigos.","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":"Remova o que está bloqueando o VACUUM","detail":"Transações longas abertas, replication slots abandonados e prepared transactions bloqueiam a limpeza (freeze). Encontre-os e resolva — caso contrário o VACUUM não avança, por mais tempo que rode.","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":"Execute um FREEZE agressivo","detail":"Quando os bloqueadores sumirem, force o congelamento começando pelas tabelas mais antigas. Mesmo que o servidor tenha parado de atribuir novos IDs de transação, não passe para o modo single-user (postgres --single): a documentação atual do PostgreSQL diz que ele não é mais necessário e deve ser evitado. Conectar como superusuário no modo normal e executar VACUUM é suficiente; no PG14+, o mecanismo failsafe do VACUUM entra em ação conforme o wraparound se aproxima.","engines":{"postgres":"VACUUM (FREEZE, VERBOSE) oldest_table;\n-- Entire database: vacuumdb --all --freeze --jobs=4"}},{"title":"Definitivo: reforce e monitore o autovacuum","detail":"Aumente autovacuum_vacuum_cost_limit, reduza autovacuum_naptime e defina parâmetros de armazenamento específicos nas tabelas muito escritas. Configure um alerta para age(datfrozenxid); nunca mais passe por esta crise."}],"related":["open-transactions","reclaim-space"]},{"id":"tempdb-contention","title":"Contenção no tempdb (SQL Server)","icon":"🌀","symptom":"Esperas PAGELATCH_UP/EX, contenção nas páginas de alocação do tempdb (PFS/GAM/SGAM), lentidão geral.","steps":[{"title":"Confirme a contenção","detail":"Esperas PAGELATCH em páginas de sistema do tempdb (como 2:1:1) indicam contenção de alocação.","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":"Detalhe o uso do tempdb","detail":"Quem está usando quanto do tempdb? Objetos internos (spills de sort/hash), o version store ou objetos de usuário?","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":"Corrija a configuração dos arquivos","detail":"Use vários arquivos de dados de tamanho IGUAL para o tempdb, em número igual ao de núcleos de CPU (até 8). O SQL 2016+ recomenda isso na instalação; em versões antigas, use os trace flags 1117/1118. Coloque os arquivos em disco rápido (NVMe local)."},{"title":"Encontre a consulta descontrolada","detail":"Consultas com grandes spills de sort/hash estouram o tempdb. Mire nas que têm memory grants insuficientes ou planos ruins; reduza os spills com índices/planos.","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":"Equivalentes em outros bancos","detail":"A mesma 'contenção de espaço temporário' é o tablespace TEMP no Oracle (v$tempseg_usage / v$sort_usage) e temp_files e estouro de work_mem no PostgreSQL. A correção de raiz é sempre a mesma: corrija a consulta que faz spill e acelere o espaço temporário."}],"related":["free-space","top-slow-queries","reclaim-space"]},{"id":"cert-expiry","title":"TLS / certificado expirado","icon":"🔐","symptom":"'certificate has expired', 'SSL handshake failed', os clientes de repente não conseguem se conectar (sem mudança de código).","steps":[{"title":"Onde quebra: servidor, cliente ou CA?","detail":"Foi o certificado do servidor que expirou, um certificado de cliente ou uma CA da cadeia? O sintoma costuma ser 'funcionava ontem, hoje não funciona, nenhum código mudou'."},{"title":"Verifique a expiração","detail":"Leia a data de expiração do certificado direto do servidor (um método rápido e independente do banco).","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":"Instale e carregue o novo certificado","detail":"Substitua o certificado e, na maioria dos casos, recarregue o serviço sem reiniciá-lo.","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":"Verifique","detail":"Confirme com o comando openssl acima que o handshake TLS funciona com o novo certificado e que a expiração foi estendida; conecte de ponta a ponta com um cliente."},{"title":"Definitivo: nunca mais","detail":"Configure um alerta 30 dias antes da expiração do certificado; use renovação automática (ACME/Let's Encrypt, HashiCorp Vault, cert-manager). Automatize o reload após a renovação."}],"related":["connect-cli"]},{"id":"upgrade-rollback","title":"Upgrade de versão / rollback de patch","icon":"⏪","symptom":"Problemas após um upgrade/patch: regressão de desempenho, incompatibilidade com a aplicação ou o banco não abrindo.","steps":[{"title":"Pare primeiro: você tem um plano de retorno?","detail":"Se você não fez um backup completo + (se possível) um snapshot do storage ANTES do upgrade em produção, o caminho mais seguro é corrigir para frente. Na maioria dos bancos, voltar atrás significa restaurar de backup. Este passo deveria ter sido planejado ANTES do upgrade."},{"title":"Classifique o problema","detail":"É uma regressão de plano do otimizador (consultas ficaram lentas), uma incompatibilidade de aplicação/driver ou uma falha de abertura/corrupção? O caminho da solução varia muito conforme o caso."},{"title":"Caminho de rollback por banco","detail":"Oracle: rollback do patch com datapatch, ou Flashback Database (se você criou um guaranteed restore point). PostgreSQL: rollback após pg_upgrade = binários antigos + backup do diretório de dados antigo. MySQL: DOWNGRADE in-place geralmente NÃO É SUPORTADO — restaure de backup. SQL Server: não há downgrade — restaure o backup anterior ao upgrade. Em todos os casos: o snapshot/backup é o seu seguro."},{"title":"Se for regressão de plano: corrija sem rollback","detail":"Geralmente não é preciso reverter a versão inteira; só os planos mudaram.","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":"Definitivo: na próxima vez","detail":"Teste o upgrade primeiro em staging com uma carga real, aplique upgrades canary/rolling, crie um guaranteed restore point / snapshot e documente o procedimento de retorno."}],"related":["last-backup-status","restore-dump","version-uptime"]},{"id":"es-red-cluster","title":"Cluster Elasticsearch red/yellow e shards não atribuídos","icon":"🟥","symptom":"_cluster/health 'red' ou 'yellow'; shards não atribuídos; leituras/escritas restritas ou dados inacessíveis.","steps":[{"title":"Cor e causa","detail":"yellow = shards de réplica não atribuídos (os dados estão presentes, a durabilidade está reduzida). red = falta pelo menos um shard PRIMÁRIO (esses dados estão inacessíveis). Primeiro determine qual dos dois e por quê.","engines":{"elasticsearch":"GET _cluster/health?level=indices\nGET _cluster/allocation/explain"}},{"title":"Liste os shards não atribuídos e o motivo","detail":"A coluna unassigned.reason dá a causa raiz (NODE_LEFT, ALLOCATION_FAILED, DISK etc.).","engines":{"elasticsearch":"GET _cat/shards?v&h=index,shard,prirep,state,unassigned.reason&s=state"}},{"title":"Trate as causas comuns","detail":"1) Disk watermark → acima de low, o nó não recebe novos shards; em flood_stage, os índices ficam somente leitura. 2) Um nó caiu / saiu. 3) A alocação ficou desativada. 4) Número de réplicas > número de nós elegíveis."},{"title":"Corrija","detail":"Desbloqueie conforme a causa que se aplicar.","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":"Se continuar red e o primário estiver realmente perdido","detail":"Restaure o índice afetado a partir de um snapshot ou reindexe-o a partir dos dados de origem (_reindex). Definitivo: alertas de disk watermark, um número adequado de réplicas (≥1) e monitoramento da saúde dos nós."}],"related":["replication-status","list-replicas","free-space"]},{"id":"time-skew","title":"Clock skew / problema de NTP","icon":"⏱️","symptom":"Diferenças de relógio entre os nós do cluster; inconsistências de replicação/eleição, 'certificate not yet valid', saltos de tempo nos logs.","steps":[{"title":"Reconheça o sintoma","detail":"O clock skew é traiçoeiro: eleições oscilando no Mongo/Redis Sentinel, erros TLS 'not yet valid/expired', erros de Kerberos, timestamps voltando no tempo nos logs. Em sistemas distribuídos, é a raiz da maioria das esquisitices 'inexplicáveis'."},{"title":"Meça a diferença","detail":"Em cada nó, compare a fonte de tempo e o offset: `timedatectl`, `chronyc tracking` (ou `ntpq -p`) e `date -u` entre os nós. Quantos ms/s de diferença há?"},{"title":"Corrija o NTP/chrony","detail":"O chronyd/ntpd está rodando, alcança suas fontes de tempo, está sincronizado? Inicie o serviço e corrija a fonte; para offsets grandes, ajuste com cuidado (um salto repentino pode afetar alguns bancos)."},{"title":"Verifique o componente afetado","detail":"Depois de corrigir o relógio, verifique: a eleição do replica set do MongoDB está estável, o Redis Sentinel/Cluster está saudável, os handshakes TLS funcionam, as métricas de lag de replicação se normalizaram?"},{"title":"Definitivo","detail":"Torne o NTP obrigatório em todos os nós e monitore o offset (alerta: >100ms). Em máquinas virtuais, defina a configuração de sincronização de tempo host-guest; de preferência, use uma única hierarquia de fontes de tempo confiável."}],"related":["replication-status"]}]},"playbooks/hadr.json":{"schemaVersion":1,"playbooks":[{"id":"hadr-oracle-dataguard","title":"Configuração do Oracle Data Guard (physical standby)","icon":"🛡️","symptom":"Objetivo: configurar recuperação de desastres e alta disponibilidade para o Oracle com um physical standby (Data Guard); poder mudar para o standby se o primário falhar.","steps":[{"title":"Coloque o primário em modo FORCE LOGGING e ARCHIVELOG","detail":"Para o standby permanecer consistente com o primário, todas as alterações precisam ser gravadas no redo. O FORCE LOGGING registra até as operações NOLOGGING. Para o modo ARCHIVELOG, o banco é levantado no estado MOUNT.","engines":{"oracle":"ALTER DATABASE FORCE LOGGING;\n-- For ARCHIVELOG:\nSHUTDOWN IMMEDIATE;\nSTARTUP MOUNT;\nALTER DATABASE ARCHIVELOG;\nALTER DATABASE OPEN;"}},{"title":"Adicione os standby redo log files","detail":"Os standby redo logs (SRL) devem ter um grupo a mais que os online redo logs e o mesmo tamanho. São criados tanto no primário quanto no standby; são necessários para o real-time apply. No exemplo, se o online redo tem 200M, os SRLs também têm 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":"Defina log_archive_dest e os parâmetros relacionados","detail":"No primário, defina dest_2 para enviar o redo ao standby. Configure DB_UNIQUE_NAME, LOG_ARCHIVE_CONFIG (o db_unique_name dos dois lados), FAL_SERVER e STANDBY_FILE_MANAGEMENT=AUTO. Assim os arquivos são criados automaticamente no standby.","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":"Crie o standby com RMAN DUPLICATE FOR STANDBY","detail":"Depois que o password file e o listener estático/tnsnames estiverem configurados no servidor standby, o RMAN se conecta ao primário e ao standby (AUXILIARY). FROM ACTIVE DATABASE copia pela rede sem backup; DORECOVER aplica o 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":"Inicie o redo apply (MRP) e verifique","detail":"Inicie o managed recovery com o standby no estado MOUNT; use USING CURRENT LOGFILE para o real-time apply. Verifique com v$managed_standby que o processo de aplicação (MRP0) está rodando.","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":"Ative o Data Guard Broker","detail":"O broker centraliza a configuração e reduz failover/switchover a um único comando. Defina DG_BROKER_START=TRUE nas duas instâncias e depois crie e ative a configuração com o dgmgrl. No 12c+, o broker gerencia o transporte de redo: se LOG_ARCHIVE_DEST_2 foi definido manualmente, ADD DATABASE falha com ORA-16698; limpe-o antes com 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":"Monitore a defasagem de sincronização e conclua os testes","detail":"A diferença de sequence entre primário e standby deve ser monitorada continuamente; uma defasagem crescente indica gargalo de rede/aplicação. O dgmgrl SHOW CONFIGURATION deve mostrar 'SUCCESS'. Opcionalmente, teste uma troca de papéis com um switchover.","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":"Configuração do SQL Server Always On Availability Group","icon":"🔁","symptom":"Objetivo: configurar failover automático e uma réplica secundária legível para o SQL Server com um Always On Availability Group (AG).","steps":[{"title":"Configure um Windows Server Failover Cluster (WSFC)","detail":"O Always On depende de um WSFC subjacente. Instale o recurso Failover Clustering em todos os nós e configure a rede e a testemunha (witness). Crie o cluster com 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":"Ative o Always On em cada instância","detail":"Ative o recurso Always On Availability Groups com o SQL Server Configuration Manager ou PowerShell. Depois reinicie o serviço do SQL Server. Isso vincula a participação no cluster à instância.","engines":{"mssql":"-- PowerShell:\nEnable-SqlAlwaysOn -ServerInstance node1\\SQL01 -Force\nEnable-SqlAlwaysOn -ServerInstance node2\\SQL01 -Force"}},{"title":"Faça backup do banco e restaure-o no secundário WITH NORECOVERY","detail":"O banco a ser adicionado ao AG precisa estar no recovery model FULL. Faça um backup completo e um de log no primário; restaure-os no secundário WITH NORECOVERY (para que continue recebendo redo). Isso é seeding manual; a alternativa é o automatic seeding.","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":"Crie os endpoints e defina o Availability Group","detail":"Crie um endpoint HADR na porta 5022 para o tráfego de redo entre os nós. O modo síncrono (SYNCHRONOUS_COMMIT) oferece failover automático sem perda de dados; o assíncrono (ASYNCHRONOUS_COMMIT) tem atraso, mas é performático para DR remoto.","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":"Junte o secundário ao AG e junte o banco","detail":"Faça o JOIN do AG na instância secundária e depois adicione o banco restaurado ao AG. Esta etapa é necessária se foi usado seeding manual; com automatic seeding, é tratada no primário via SET(SEEDING_MODE).","engines":{"mssql":"-- On the secondary:\nALTER AVAILABILITY GROUP appag JOIN;\nALTER DATABASE app SET HADR AVAILABILITY GROUP = appag;"}},{"title":"Crie o Availability Group Listener","detail":"O listener é o nome e o IP virtuais aos quais as aplicações se conectam; após um failover, as conexões são redirecionadas automaticamente para o novo primário. Use esse nome e MultiSubnetFailover=True na connection string da aplicação.","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":"Teste o failover e verifique o estado de sincronização","detail":"Quando a sincronização estiver 'HEALTHY', teste uma troca de papéis com um failover planejado. Para failover automático, o modo deve ser síncrono e FAILOVER_MODE=AUTOMATIC. Monitore o estado com 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":"Streaming replication do PostgreSQL + failover automático","icon":"🐘","symptom":"Objetivo: configurar um hot standby para o PostgreSQL com streaming replication e adicionar Patroni/repmgr para failover automático.","steps":[{"title":"Defina os parâmetros de WAL e de conexão no primário","detail":"Para a streaming replication, wal_level precisa ser pelo menos 'replica'. max_wal_senders precisa cobrir o número de réplicas + conexões de backup, e a remoção precoce do WAL deve ser evitada com wal_keep_size ou um replication slot. As alterações exigem restart.","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":"Defina o papel de replicação e o acesso no pg_hba","detail":"Crie um papel com o atributo REPLICATION para o standby se conectar. Adicione ao pg_hba.conf uma linha que permita acesso ao banco 'replication' a partir do IP do standby e recarregue com 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":"Crie um replication slot persistente no primário","detail":"Um replication slot físico impede que o primário remova o WAL necessário mesmo quando o standby fica para trás; gerenciar por slot é mais seguro que wal_keep_size. Usaremos o nome do slot na configuração do standby.","engines":{"postgres":"SELECT pg_create_physical_replication_slot('standby1_slot');\nSELECT slot_name, active, restart_lsn FROM pg_replication_slots;"}},{"title":"Faça um base backup no servidor standby com pg_basebackup","detail":"Com o diretório de dados do standby vazio, faça uma cópia completa a partir do primário. A opção -R grava automaticamente o arquivo standby.signal e o primary_conninfo; -C também pode criar o slot. O nome do slot é passado com -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":"Verifique primary_conninfo e hot_standby e inicie o standby","detail":"Confira o primary_conninfo (host, usuário, slot) no postgresql.auto.conf gravado pelo -R; a presença do arquivo standby.signal determina o modo standby. Com hot_standby=on, o standby aceita consultas somente leitura. Inicie o serviço.","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":"Monitore o lag de replicação a partir do primário","detail":"No primário, pg_stat_replication mostra o LSN enviado/reaplicado e o atraso de cada standby. Os atrasos write/flush/replay devem ficar pequenos; sync_state é 'sync' se for usada uma réplica síncrona.","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":"Adicione Patroni ou repmgr para failover automático","detail":"A streaming replication pura exige um promote manual. O failover automático exige um gerenciador de cluster: Patroni (eleição de líder no etcd/Consul + promote automático) ou repmgr (monitoramento/failover com repmgrd). No lado da aplicação, ofereça um único endpoint com HAProxy/pgBouncer. Se for necessário um promote manual: pg_ctl promote. Antes de promover, garanta que o primário antigo esteja realmente parado e que as aplicações não consigam escrever nele (risco de split-brain). Reintegrar o primário antigo como standby do novo primário exige pg_rewind; para isso, wal_log_hints = on ou data checksums precisam estar ativos.","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":"Configuração do MySQL InnoDB Cluster (Group Replication)","icon":"🐬","symptom":"Objetivo: configurar alta disponibilidade com failover automático para o MySQL usando InnoDB Cluster (Group Replication + MySQL Shell + MySQL Router).","steps":[{"title":"Atenda aos pré-requisitos","detail":"O InnoDB Cluster exige MySQL 8.0+, um server_id único, modo GTID e o storage engine InnoDB em todos os nós. Todas as instâncias precisam se alcançar pela rede, e as tabelas precisam ter chave primária. Prepare um usuário clusterAdmin para a administração.","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":"Configure cada instância com o MySQL Shell","detail":"No mysqlsh, dba.configureInstance() deixa cada nó apto para o Group Replication; corrige parâmetros ausentes e pede restart se necessário. Repita em todos os nós.","engines":{"mysql":"-- mysqlsh:\ndba.configureInstance('icadmin@node1:3306')\ndba.configureInstance('icadmin@node2:3306')\ndba.configureInstance('icadmin@node3:3306')"}},{"title":"Crie o cluster (nó seed)","detail":"Conecte-se a um nó e inicie o cluster com dba.createCluster(); esse nó vira o primeiro primário. Um objeto cluster é retornado e usado nas adições seguintes.","engines":{"mysql":"-- mysqlsh, while connected to node1:\nvar cluster = dba.createCluster('appCluster')"}},{"title":"Adicione as outras instâncias ao cluster","detail":"Adicione os nós secundários com cluster.addInstance(). Escolha clone (clone físico, rápido para um nó novo) ou incremental (via GTID) como recoveryMethod. Pelo menos 3 nós fornecem uma maioria ímpar e failover automático.","engines":{"mysql":"-- mysqlsh:\ncluster.addInstance('icadmin@node2:3306', {recoveryMethod: 'clone'})\ncluster.addInstance('icadmin@node3:3306', {recoveryMethod: 'clone'})"}},{"title":"Faça o bootstrap do MySQL Router","detail":"O MySQL Router faz o roteamento entre a aplicação e o cluster; expõe as portas de leitura/escrita (6446) e somente leitura (6447) e redireciona o tráfego automaticamente quando o primário muda. O bootstrap gera a configuração a partir dos metadados do cluster.","engines":{"mysql":"mysqlrouter --bootstrap icadmin@node1:3306 --user=mysqlrouter --directory /etc/mysqlrouter\n# Then: mysqlrouter -c /etc/mysqlrouter/mysqlrouter.conf &"}},{"title":"Verifique o status do cluster e o failover","detail":"cluster.status() mostra o papel de cada nó (R/W primário, R/O secundário) e o estado (ONLINE). clusterName e a topologia devem estar saudáveis. Teste o failover desligando o primário e observando a eleição automática de um novo primário.","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":"Configuração de replica set + sharding no MongoDB","icon":"🍃","symptom":"Objetivo: configurar um replica set com failover automático para o MongoDB e estendê-lo para um cluster com sharding para escalabilidade horizontal.","steps":[{"title":"Inicie os processos mongod com o mesmo nome de replSet","detail":"Inicie cada membro do replica set com o mesmo nome em --replSet e um --bind_ip acessível. Em produção, recomenda-se autenticação interna com keyFile ou TLS. Busque um número ímpar de membros votantes para uma maioria clara.","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":"Inicie o replica set","detail":"Conecte-se a um membro com o mongosh, chame rs.initiate() e defina todos os membros. Isso dispara a primeira eleição e um primário é escolhido. Verifique os papéis PRIMARY/SECONDARY com rs.status().","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":"Adicione membros, defina prioridades e um arbiter se necessário","detail":"Adicione membros depois com rs.add(). A priority determina qual membro tende a virar primário (0 = nunca vira primário). Um arbiter só vota e não guarda dados; é usado como desempate com um número par de nós de dados, mas um membro real é preferível pela segurança dos dados. Em topologias com arbiter (principalmente PSA), o write concern majority não pode ser atendido quando um nó de dados cai e as escritas ficam esperando; no 5.0+, pode ser preciso definir explicitamente o write concern padrão do cluster com setDefaultRWConcern antes de adicionar um arbiter.","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":"Configure o replica set do config server para o sharding","detail":"Os metadados do cluster com sharding ficam em um replica set de config server (--configsvr). Ele mesmo é iniciado como replica set; recomenda-se 3 membros para alta disponibilidade.","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":"Inicie os replica sets dos shards e o roteador mongos","detail":"Cada shard é seu próprio replica set iniciado com --shardsvr (a durabilidade dos dados vem da replicação dentro do shard). O roteador mongos é iniciado apontando para os config servers; as aplicações se conectam ao 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":"Adicione os shards e faça o sharding da coleção","detail":"Conecte-se ao mongos e adicione cada replica set de shard com sh.addShard(). Ative o sharding no banco e distribua a coleção por uma shard key com sh.shardCollection(). A escolha da chave é crítica: deve ter alta cardinalidade e distribuição uniforme. Monitore a distribuição dos chunks com 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":"Alta disponibilidade com Redis Sentinel + Cluster","icon":"⚡","symptom":"Objetivo: configurar uma implantação master-réplica com failover automático para o Redis usando Sentinel; passar para o modo Redis Cluster se for necessária escalabilidade horizontal.","steps":[{"title":"Configure o master e as réplicas","detail":"Rode um master e pelo menos duas réplicas. As réplicas seguem o master com REPLICAOF ('replicaof <host> <port>' também pode ser escrito no redis.conf). Ative AOF ou RDB para persistência; recomenda-se autenticação com 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":"Configure o Sentinel com monitor e quórum","detail":"Defina o master a monitorar e o quórum no sentinel.conf de cada nó Sentinel. O quorum é o número mínimo de Sentinels necessário para considerar o master 'down'. Em produção, recomendam-se 3 Sentinels em 3 servidores separados (contra split-brain).","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":"Inicie os processos Sentinel","detail":"Inicie o Sentinel em cada nó. Os Sentinels descobrem automaticamente uns aos outros e as réplicas; gravam a configuração no arquivo em tempo de execução. Por isso o sentinel.conf precisa ser gravável.","engines":{"redis":"redis-sentinel /etc/redis/sentinel.conf\n# or:\nredis-server /etc/redis/sentinel.conf --sentinel"}},{"title":"Consulte o status pelo Sentinel e teste o failover","detail":"Consulte o master atual e as réplicas com os comandos SENTINEL. As aplicações devem descobrir o master atual perguntando ao Sentinel com 'get-master-addr-by-name'. Verifique a troca automática com um failover planejado.","engines":{"redis":"SENTINEL master mymaster\nSENTINEL get-master-addr-by-name mymaster\nSENTINEL replicas mymaster\n# planned switchover:\nSENTINEL failover mymaster"}},{"title":"Alternativa: particione os dados com Redis Cluster","detail":"Se a memória/throughput de um único master não bastar, use o Redis Cluster: os dados são divididos em 16384 hash slots e distribuídos entre vários masters; cada master tem sua própria réplica. A aplicação precisa usar um cliente cluster-aware. Configure com 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":"Verifique o estado do cluster","detail":"Depois de criar o cluster, verifique se todos os slots estão atribuídos e os nós conectados. cluster_state deve ser 'ok' e todos os 16384 slots devem aparecer atribuídos. Monitore a distribuição de nós e slots com os comandos 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":"Resiliência do Elasticsearch: réplica + snapshot + CCR","icon":"🔎","symptom":"Objetivo: dar resiliência ao Elasticsearch com shards de réplica, nós master/data dedicados, backups por snapshot (SLM) e cross-cluster replication (CCR).","steps":[{"title":"Separe os papéis: nós master e data dedicados","detail":"Para a estabilidade do cluster, os nós master-eligible votantes (de preferência 3, uma maioria ímpar) são separados da carga de dados. Atribua os papéis com node.roles no elasticsearch.yml e defina os seed hosts para o discovery. 3 masters evitam split-brain.","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":"Defina o número de réplicas do índice","detail":"number_of_replicas é o número de cópias mantidas para cada shard primário; deve ser pelo menos 1 para que os dados continuem disponíveis quando um data node for perdido. Pode ser alterado dinamicamente em um índice ativo; o número de réplicas deve ser menor que o número de data nodes.","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":"Defina um repositório de snapshots","detail":"Os backups são feitos em um repositório: um sistema de arquivos compartilhado (fs) ou os plugins S3/GCS/Azure. Para poder recuperar os dados mesmo se o cluster for apagado, o repositório precisa estar em armazenamento durável fora do cluster.","engines":{"elasticsearch":"PUT /_snapshot/backup_repo\n{\n  \"type\": \"fs\",\n  \"settings\": { \"location\": \"/mnt/es_backups\", \"compress\": true }\n}"}},{"title":"Agende snapshots automáticos com SLM","detail":"O Snapshot Lifecycle Management (SLM) tira snapshots regulares e aplica uma política de retenção. Uma expressão cron define a frequência, quais índices entram e quantos snapshots são mantidos.","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":"Verifique o snapshot e o restore","detail":"Dispare a política SLM manualmente para verificar se funciona; o estado do snapshot deve ser SUCCESS. Faça testes de restore regularmente, porque backup não testado não é backup.","engines":{"elasticsearch":"POST /_slm/policy/daily_backup/_execute\nGET /_snapshot/backup_repo/_all\n# restore:\nPOST /_snapshot/backup_repo/<snapshot_name>/_restore"}},{"title":"Configure DR remoto com Cross-Cluster Replication (CCR)","detail":"Para recuperação de desastres entre regiões, um segundo cluster (follower) segue os índices do cluster primário remoto (leader). Primeiro defina o remote cluster e depois vincule o índice follower ao leader; as alterações no leader fluem automaticamente. CCR é um recurso Platinum (comercial).","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":"Hardening de segurança: bancos SQL (Oracle, PostgreSQL, MySQL, SQL Server)","icon":"🔒","symptom":"Objetivo: fazer o hardening de bancos relacionais no estilo CIS — contas padrão, política de senhas forte, menor privilégio, restrição de rede, TLS, auditoria e criptografia (TDE).","steps":[{"title":"Remova ou bloqueie contas padrão/desnecessárias, remova schemas de exemplo","detail":"Contas padrão e schemas de exemplo que vêm com a instalação são uma superfície de ataque bem conhecida. Bloqueie ou remova os não usados; renomeie as contas de nível superior/de serviço.","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":"Imponha uma política de senhas forte e expiração","detail":"Senhas fracas ou que nunca mudam são o ponto de entrada mais comum. Imponha limites de tentativas de login, complexidade e validade das senhas; armazene as senhas com um hash forte.","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":"Menor privilégio: revogue privilégios PUBLIC/amplos, conceda privilégios por papel","detail":"Privilégios amplos concedidos a todos (PUBLIC) facilitam o movimento lateral. Revogue-os, crie papéis e conceda apenas o necessário.","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":"Restrinja a rede/o acesso — só clientes conhecidos podem conectar","detail":"Evite que o banco escute abertamente para o mundo. Restrinja o endereço de escuta, aplique regras de acesso por host/IP e limite a porta com um firewall.","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":"Imponha TLS/conexões criptografadas","detail":"O tráfego de rede está exposto a sniffing passivo. Configure um certificado de servidor e exija que os clientes se conectem com criptografia.","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":"Ative a auditoria — torne visível quem fez o quê","detail":"Uma trilha de auditoria é essencial para monitorar acessos privilegiados e atividades suspeitas. Registre logins, mudanças de privilégios e acessos a objetos sensíveis.","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":"Aplique criptografia de dados (at rest / TDE)","detail":"Se um disco, backup ou arquivo for roubado, os dados precisam ser ilegíveis. Ative a criptografia de dados em repouso (TDE) no nível de coluna/tablespace/banco.","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":"Mantenha os patches em dia e desative recursos desnecessários","detail":"Vulnerabilidades conhecidas são o risco mais explorado. Aplique patches de segurança regularmente; desative protocolos, plugins e recursos não usados (reduza a superfície de ataque).","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":"Hardening de segurança: MongoDB / Redis / Elasticsearch","icon":"🛡️","symptom":"Objetivo: fazer o hardening de armazenamentos NoSQL/de dados no estilo CIS — autenticação, restrição de rede, bloqueio de comandos perigosos, TLS, papéis de menor privilégio e auditoria.","steps":[{"title":"ATIVE a autenticação — corte o acesso não autenticado","detail":"Esses produtos muitas vezes vêm com a autenticação DESATIVADA por padrão e são comprometidos quando ficam expostos à internet. Ative a autenticação e crie um usuário administrador.","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":"Restrinja a rede — abra apenas as interfaces e portas necessárias","detail":"Evite que o serviço escute para o mundo todo em 0.0.0.0. Fixe o endereço de bind em uma interface interna/loopback e ative o protected mode.","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":"Restrinja comandos perigosos","detail":"Um único comando pode apagar todos os dados. Renomeie ou remova comandos destrutivos/administrativos, ou bloqueie alvos com curinga.","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":"Ative TLS/conexões criptografadas","detail":"Credenciais e dados não devem trafegar sem criptografia por uma rede aberta. Ative TLS para o tráfego de clientes e entre nós.","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":"Conceda roles de menor privilégio — evite roles amplas","detail":"Dê a cada usuário apenas o acesso que sua função exige. Em vez de papéis amplos/administrativos, use papéis granulares limitados a bancos, padrões de chave ou índices específicos.","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":"Ative auditoria/logging — monitore acessos e alterações","detail":"Tentativas de acesso não autorizado e operações administrativas precisam ser registradas. Ative o audit log e envie-o para um local central.","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":"Bancos gerenciados na nuvem (RDS/Aurora/Cloud SQL/Atlas/Azure SQL)","icon":"☁️","symptom":"Objetivo: conhecer as principais diferenças entre bancos gerenciados na nuvem e instalações autogerenciadas; entender como funcionam na nuvem backup, parâmetros, failover, monitoramento, upgrades e conectividade.","steps":[{"title":"Mudança de mentalidade: você acessa um serviço, não um servidor","detail":"Em bancos gerenciados você NÃO tem acesso de shell ao SO, ao sistema de arquivos nem ao processo do banco; não pode entrar por SSH, editar arquivos de configuração à mão nem virar superusuário. Você tem apenas a API/console de gerenciamento do provedor e uma conexão SQL normal. AWS RDS/Aurora: o gerenciamento é no nível do recurso (instância/cluster), o servidor fica oculto. GCP Cloud SQL: apenas API da instância, sem SO. MongoDB Atlas: cluster totalmente gerenciado, sem acesso ao mongod. Azure SQL Database: PaaS, nem o servidor nem o SO são visíveis por baixo (a Managed Instance dá um pouco mais de controle). Por isso a maioria dos reflexos do mundo autogerenciado, como 'olhar o arquivo', 'matar o processo' ou 'rodar uma ferramenta do SO', não se aplica."},{"title":"Backup: snapshots automáticos + recuperação point-in-time (PITR)","detail":"Você não agenda backups; o provedor os faz automaticamente. A recuperação geralmente é 'restaurar para um ponto específico no tempo' (PITR) ou criar uma nova instância a partir de um snapshot; a instância existente não é sobrescrita. AWS RDS/Aurora: backups automáticos + janela de retenção; um restore PITR com precisão de segundos abre como nova instância/cluster; snapshots manuais também são possíveis. GCP Cloud SQL: backups automáticos + PITR via binary logs; o restore vai para uma nova instância. MongoDB Atlas: cloud backup contínuo + PITR (M10+); restore a partir de snapshots. Azure SQL: backups automáticos nativos, retenção de 1-35 dias, PITR para qualquer ponto e restore de bancos excluídos. Regra comum: verifique a configuração de backup (janela, período de retenção) e faça testes de restore regulares."},{"title":"Parâmetros: parameter groups / flags, não um arquivo de configuração","detail":"Em vez de editar postgresql.conf ou my.cnf à mão, você usa a abstração de parâmetros do provedor; alguns parâmetros são bloqueados e alguns exigem restart (estáticos). AWS RDS/Aurora: definidos via DB parameter group (e cluster parameter group); parâmetros dinâmicos se aplicam na hora, os estáticos no reboot. GCP Cloud SQL: as 'database flags' são definidas pelo console/gcloud. MongoDB Atlas: 'Additional Settings' limitadas + tamanho do oplog etc.; a maioria dos parâmetros internos é gerenciada. Azure SQL: a maioria das configurações de nível de servidor é gerenciada; o comportamento muda via SCOPED CONFIGURATION e a escolha do service tier. Antes de aplicar, verifique se o parâmetro é dinâmico ou estático."},{"title":"Alta disponibilidade / failover: Multi-AZ e réplicas gerenciados","detail":"Você não monta o failover; marca uma opção e deixa com o provedor. O standby e o failover automático são gerenciados, e as conexões são redirecionadas ao novo primário por um endpoint estável. AWS RDS: Multi-AZ (standby síncrono, failover automático); Aurora: storage com várias cópias + failover automático, o cluster endpoint aponta para o writer. GCP Cloud SQL: configuração de HA (regional, standby em uma zona secundária) com um clique; réplicas de leitura são adicionadas à parte. MongoDB Atlas: replica set nativo, implantação multirregião/multicloud disponível, failover automático. Azure SQL: HA nativa (réplicas locais no Business Critical), opção zone-redundant e active geo-replication / failover groups entre regiões. A aplicação deve sempre se conectar ao endpoint, nunca a um IP fixo."},{"title":"Monitoramento: o serviço de métricas e logs do provedor","detail":"Como você não pode rodar ferramentas do SO (top, iostat), monitora pela plataforma de métricas do provedor; métricas de CPU, número de conexões, IOPS, lag de replicação e armazenamento ficam lá. AWS: métricas do CloudWatch + Enhanced Monitoring + Performance Insights (análise por consulta). GCP Cloud SQL: Cloud Monitoring (antigo Stackdriver) + Query Insights. MongoDB Atlas: métricas/gráficos nativos do Atlas + Performance Advisor + painel em tempo real. Azure SQL: Azure Monitor + SQL Analytics + Query Performance Insight. Sempre configure alarmes de limite (uso de armazenamento, CPU, limite de conexões, atraso de réplica)."},{"title":"Upgrades de versão e manutenção: pelo console, em uma janela de manutenção","detail":"Em vez de atualizar binários à mão, você escolhe uma versão de destino; patches de versão minor são em geral automáticos, enquanto upgrades de versão principal são planejados e geralmente envolvem downtime/um failover de HA. AWS RDS/Aurora: seleção da versão do engine + opção de upgrade minor automático + upgrades principais de baixo risco com Blue/Green Deployments. GCP Cloud SQL: janela de manutenção + upgrade de versão principal self-service. MongoDB Atlas: upgrade de versão com um clique, downtime quase zero de forma rolling. Azure SQL: recebe patches automaticamente da plataforma (a noção de versão é em grande parte abstraída); o comportamento é controlado pelo compatibility level. Sempre teste primeiro em uma cópia de teste/staging e agende a janela de manutenção fora do horário comercial."},{"title":"Conectividade e segurança: endpoint + IAM/TLS","detail":"As conexões sempre passam pelo endpoint DNS fornecido pelo provedor e são criptografadas (TLS); o acesso de rede e a identidade podem ser ligados ao sistema de identidade da nuvem. AWS RDS/Aurora: endpoint de instância/cluster + Security Group para a rede + autenticação IAM de banco opcional + TLS (certificado rds-ca). GCP Cloud SQL: IP público + Authorized Networks ou IP privado/VPC, Cloud SQL Auth Proxy, autenticação IAM de banco, TLS. MongoDB Atlas: connection string SRV (mongodb+srv://), IP access list + private endpoint/peering, SCRAM ou IAM/X.509, TLS obrigatório. Azure SQL: endpoint FQDN do servidor + firewall/Private Link + autenticação Microsoft Entra ID (antigo Azure AD) + TLS obrigatório. Regra: use o endpoint, não um IP fixo, na connection string, imponha TLS e conecte com uma identidade IAM da nuvem sempre que possível."}],"related":["last-backup-status","promote-failover","connect-cli"]}]},"playbooks/automation.json":{"schemaVersion":1,"playbooks":[{"id":"auto-ansible","title":"Automação de bancos com Ansible","icon":"🤖","symptom":"Objetivo: tornar repetíveis e idempotentes (rodar o mesmo playbook de novo não quebra o sistema) as tarefas de instalação, configuração, usuários e backup de bancos com Ansible.","steps":[{"title":"Defina o inventário e os grupos","detail":"Agrupe os servidores no inventário por papel no banco; coloque servidores primários, réplicas e de backup em grupos separados. Use um inventário estático INI/YAML ou um inventário dinâmico para a nuvem (aws_ec2, gcp_compute). Coloque as variáveis de grupo em group_vars/ e as específicas de host em 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":"Instale a collection certa (community.postgresql / community.mysql / community.mongodb)","detail":"O Ansible core agora distribui os módulos de banco em collections separadas; instale a collection do seu engine via requirements.yml. Use community.postgresql (postgresql_db, postgresql_user, postgresql_privs) para PostgreSQL, community.mysql (mysql_db, mysql_user) para MySQL/MariaDB e community.mongodb para MongoDB. O cliente Python correspondente (psycopg2, PyMySQL, pymongo) precisa estar instalado no host de destino.","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":"Criptografe os segredos com Ansible Vault","detail":"Não deixe senhas de banco, segredos de replicação e credenciais de superusuário em texto puro; mantenha-os em um arquivo de variáveis criptografado com ansible-vault. Descriptografe em tempo de execução com --ask-vault-pass ou --vault-password-file. Assim os segredos podem ficar com segurança no Git e o playbook continua idempotente.","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":"Monte a estrutura de roles (roles/postgres, roles/mysql)","detail":"Crie uma role por engine e divida a lógica nas subpastas tasks/, defaults/, templates/ e handlers/. Essa estrutura melhora a reutilização: defaults/main.yml para valores padrão, templates/ para templates de configuração jinja2, handlers/ para a lógica 'reiniciar só se algo mudou'. Você pode criar o esqueleto da role com 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":"Escreva as tarefas de instalação e configuração de forma idempotente","detail":"Instale o pacote, inicialize o diretório de dados e gere postgresql.conf/my.cnf a partir de um template; reinicie o serviço via handler quando a configuração mudar. Os módulos são idempotentes: um pacote já instalado não é reinstalado, e o handler não é disparado se o arquivo não mudou. Gere o template de configuração com o módulo template e ligue-o ao handler com '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":"Defina as tarefas de banco e de usuários","detail":"Crie o banco, os usuários e os privilégios com módulos; pegue a senha de uma variável do Vault. Os módulos community.postgresql são idempotentes: se o usuário/banco existir, não o recriam, aplicam só a diferença. Conceda privilégios à parte com postgresql_privs; no MySQL usa-se o campo priv do mysql_user.","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":"Adicione a tarefa de backup e o agendamento","detail":"Implante o script de backup a partir de um template e agende-o com ansible.builtin.cron; assim o job de backup também é gerenciado como código. Transforme em variáveis o diretório de destino do backup, o período de retenção e o agendamento. O módulo cron é idempotente e identifica a entrada pelo 'name', então rodar de novo não a duplica.","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":"Provisionamento de bancos com Terraform (IaC)","icon":"🏗️","symptom":"Objetivo: definir a infraestrutura do banco (instância, parameter group, rede) como código (Infrastructure as Code) com Terraform; montar o fluxo plan/apply, o remote state e o gerenciamento de drift.","steps":[{"title":"Escolha e configure o provider (aws / google / azurerm)","detail":"Defina o provider da nuvem em que você roda e fixe sua versão. Trave o provider hashicorp/aws para AWS, hashicorp/google para GCP e hashicorp/azurerm para Azure no bloco required_providers. Fixar a versão garante um comportamento consistente em toda a equipe.","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":"Configure o remote state e o locking","detail":"Não mantenha o arquivo de state localmente; use um backend remoto para trabalho em equipe e segurança. As escolhas comuns são o backend S3 + uma tabela de lock no DynamoDB na AWS, o backend gcs no GCP e o backend azurerm (Storage Account) no Azure. O remote state evita applies simultâneos por meio do locking e faz do state a única fonte da verdade. Como senhas podem ficar no state em texto puro, mantenha o backend criptografado e com acesso restrito.","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":"Defina o recurso do banco","detail":"Escreva o recurso principal para o seu engine e nuvem: aws_db_instance na AWS (ou aws_rds_cluster para Aurora), google_sql_database_instance no GCP, azurerm_mssql_database no Azure (para SQL Server, sob um azurerm_mssql_server). Especifique aqui engine, versão, classe, armazenamento e janela de backup.","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":"Escreva o parameter group como código","detail":"Defina as configurações do banco (max_connections, work_mem, conjunto de caracteres) com um recurso de parâmetros, não manualmente no console. Use aws_db_parameter_group na AWS, settings.database_flags dentro de google_sql_database_instance no GCP e o recurso de configuração do servidor no Azure. Assim as configurações ficam versionadas e reproduzíveis.","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":"Passe segredos por variáveis e um secrets manager","detail":"Não coloque a senha fixa em um arquivo .tf; defina-a como variável sensível (variable ... sensitive = true) e forneça o valor por uma variável de ambiente TF_VAR_, um secrets manager (AWS Secrets Manager, Vault) ou um segredo de CI. Lembre-se: o valor é gravado no arquivo de state, então o remote state precisa ser criptografado. A abordagem mais limpa é nunca passar a senha ao Terraform e lê-la de um recurso de secrets manager.","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":"Execute o fluxo plan e apply","detail":"Primeiro prepare o provider/backend com terraform init, veja o que vai mudar com terraform plan, aprove e aplique com terraform apply. Não aplique sem revisar a saída do plan; o fluxo seguro em CI é postar o 'plan' como comentário no PR e aplicar após aprovação humana. Identifique mudanças destrutivas (ex.: recriação da instância) pelo marcador -/+ na saída do plan.","engines":{"postgres":"terraform init\nterraform plan -out=plan.tfplan\nterraform apply plan.tfplan"}},{"title":"Detecte e corrija o drift","detail":"Se alguém fizer uma alteração manual no console, a infraestrutura real e o state divergem (drift). Diferenças que aparecem no terraform plan 'quando nada deveria ter mudado' revelam o drift; a diferença é lida com terraform refresh/plan. Ou leve a alteração de volta para o código, ou traga a infraestrutura de volta ao código com apply. Proíba alterações manuais como regra; o código deve ser a única fonte da verdade.","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":"Bancos no Kubernetes (operator)","icon":"☸️","symptom":"Objetivo: rodar o banco no Kubernetes com um operator; em vez de um StatefulSet puro, usar o failover automático, o armazenamento persistente e os recursos de backup que o operator oferece.","steps":[{"title":"Por que um operator: só um StatefulSet não basta","detail":"Um StatefulSet simples dá pods com identidades estáveis e PVCs, mas não a lógica de failover, configuração de replicação, backup e upgrades. Um operator empacota esse conhecimento operacional específico do banco como um controller + custom resource (CRD). Você escreve um CR chamado 'Cluster', e o operator gerencia o StatefulSet, o Service, o Secret e os jobs de backup por trás dele. Em produção, rodar bancos com um operator é geralmente o preferido.","engines":{"postgres":"# operators for PostgreSQL:\n#  - CloudNativePG (CNPG)\n#  - Zalando postgres-operator\n#  - Crunchy PGO"}},{"title":"Escolha e instale o operator","detail":"Escolha um operator para o seu engine: CloudNativePG ou Zalando postgres-operator para PostgreSQL; os operators da Percona (Percona Operator for MySQL / for MongoDB) são comuns para MySQL e MongoDB. Instale o operator com Helm ou um manifesto bundle; esta etapa adiciona os CRDs e o pod do controller ao cluster.","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":"Planeje o armazenamento (StorageClass / PVC)","detail":"O estado do banco fica nos PVCs; especifique no CR a StorageClass a usar. Escolha uma StorageClass que ofereça block storage de baixa latência, de preferência SSD com desempenho próximo ao local; sistemas de arquivos de rede (NFS) não são recomendados para a maioria dos bancos. Defina corretamente desde o início o tamanho do PVC e a possibilidade de expansão (allowVolumeExpansion), porque reduzir é difícil.","engines":{"postgres":"spec:\n  storage:\n    storageClass: fast-ssd\n    size: 50Gi"}},{"title":"Aplique o CR Cluster (réplicas e failover automático)","detail":"Especifique no CR o número de instâncias/réplicas; o operator configura a replicação síncrona/assíncrona e, se o primário falhar, faz failover automático promovendo uma réplica. A aplicação deve se conectar ao Service '-rw' (read-write) criado pelo operator; esse serviço sempre aponta para o primário atual. Por isso o destino da conexão não muda durante o failover.","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":"Grave os backups no S3 via CR","detail":"Os operators também gerenciam os backups de forma declarativa: você define no CR o destino principal do backup (object storage/S3) e o arquivamento do WAL. No CloudNativePG, os detalhes do S3 são informados com spec.backup.barmanObjectStore (obsoleto desde a 1.26; em novas implantações use o Barman Cloud Plugin e seu recurso ObjectStore); o arquivamento contínuo do WAL + base backups permitem a recuperação point-in-time. Referencie as credenciais a partir de um Secret do Kubernetes.","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":"CRs de backup agendado e de restore","detail":"Crie um CR Backup para um backup avulso e um CR ScheduledBackup para os agendados; faça base backups regulares com uma expressão cron. Os restores também são declarativos: você inicializa um novo Cluster a partir de um backup existente no object store com 'bootstrap.recovery'. Faça exercícios de restore regularmente; fazer backup não basta, teste a recuperação.","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 de migração de schema (Flyway/Liquibase)","icon":"🧬","symptom":"Objetivo: gerenciar as alterações de schema do banco com arquivos de migração versionados; aplicá-las de forma automática, mas controlada, no CI/CD com Flyway ou Liquibase.","steps":[{"title":"Crie arquivos de migração versionados (Vxxx__nome.sql)","detail":"Escreva cada alteração de schema em um arquivo nomeado com número de versão crescente; a convenção do Flyway é V<versão>__<descrição>.sql (ex.: V1__initial_schemas.sql, V2__orders_table.sql). Esses arquivos ficam no Git e são aplicados em ordem de versão. As migrações aplicadas são registradas em uma tabela de controle (flyway_schema_history no Flyway), então cada migração roda exatamente uma vez.","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":"Preserve a imutabilidade com checksums","detail":"O Flyway/Liquibase guardam o checksum de cada migração aplicada. Se você editar depois um arquivo já aplicado, o checksum não confere mais e a ferramenta falha. Regra: NUNCA edite uma migração aplicada; faça a correção com um novo arquivo de versão. Isso garante que todos os ambientes (dev/staging/prod) compartilhem o mesmo histórico.","engines":{"postgres":"# repair on checksum mismatch (use with care):\nflyway repair\n# the right way: add the change in a new Vx file"}},{"title":"Faça o baseline de um banco existente","detail":"Use baseline ao ligar a ferramenta de migração a um banco já populado e sem histórico; ele trata o estado atual como 'versão inicial' e não tenta recriar os objetos existentes. As migrações após baselineVersion são aplicadas. Em um ambiente criado do zero não é preciso baseline; as migrações rodam a partir da V1.","engines":{"postgres":"flyway baseline -baselineVersion=1 -baselineDescription=\"existing schema\""}},{"title":"Migre automaticamente no pipeline de CI","detail":"Rode a ferramenta de migração em uma etapa de CI para aplicar as alterações automaticamente nos bancos de teste e staging; o comando migrate roda apenas os arquivos novos (não aplicados) e é idempotente. Aplicar a migração primeiro em um banco temporário/efêmero e validá-la pega SQL quebrado antes de chegar à produção. O schema precisa ser migrado ANTES do deploy do código da aplicação (com alterações retrocompatíveis).","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":"Adicione uma etapa de aprovação manual para produção","detail":"Teste/staging são automáticos, mas faça o migrate em produção exigir aprovação manual; adicione uma etapa de 'approval gate' (aprovação manual) no CI/CD. Antes da aprovação, mostre quais migrações vão rodar com 'flyway info' ou 'liquibase status'. Sempre faça um backup recente antes de aplicar em produção para poder voltar atrás se algo der errado.","engines":{"postgres":"# what will run before approval?\nflyway info\n# liquibase equivalent:\nliquibase status --verbose"}},{"title":"Defina a reversibilidade e uma estratégia de rollback","detail":"O Flyway Community não tem undo automático; adote o princípio de migração somente para frente: em vez de desfazer um erro, escreva uma nova migração que o corrija. Changesets do Liquibase podem definir um bloco de rollback e ser revertidos com 'liquibase rollback'. A estratégia mais robusta: mantenha as alterações pequenas e retrocompatíveis, faça backup antes de operações arriscadas (remoção de colunas) e prepare um plano de rollback por escrito.","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":"Backups automatizados (pgBackRest/Barman/Xtrabackup/cron)","icon":"💾","symptom":"Objetivo: automatizar os backups do banco; montar uma cadeia de recuperação confiável com full + incremental + arquivamento de WAL/binlog agendados, retenção, verificação e uma cópia offsite.","steps":[{"title":"Escolha a ferramenta de backup certa","detail":"Escolha uma ferramenta para o seu engine: pgBackRest ou Barman para PostgreSQL (backup físico + arquivo de WAL + PITR); Percona XtraBackup (backup físico online) para MySQL/MariaDB, ou mysqldump/mydumper (lógico) para conjuntos de dados pequenos. Ferramentas físicas dão backups rápidos e consistentes + recuperação point-in-time em bancos grandes; dumps lógicos são portáveis, mas lentos com muitos dados.","engines":{"postgres":"# pgBackRest or Barman","mysql":"# physical: xtrabackup\n# logical: mysqldump / mydumper"}},{"title":"Monte a cadeia full + incremental + arquivamento contínuo","detail":"Configure a recuperação point-in-time com backups full semanais/diários, backups incrementais/diferenciais entre eles e arquivamento contínuo de WAL (PostgreSQL) ou binlog (MySQL). O pgBackRest gerencia os tipos de backup full/diff/incremental e o arquivo de WAL; no PostgreSQL você aponta o archive_command para o pgBackRest. Backups incrementais + arquivo permitem voltar a qualquer ponto no tempo.","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":"Agende os backups com cron/timer","detail":"Execute os comandos de backup regularmente com cron ou um timer do systemd: por exemplo, um backup full na noite de domingo e incrementais nas outras noites. Agende fora do horário comercial e garanta que os jobs full e incr não se sobreponham. Grave os logs de saída em algum lugar e gere um alerta em caso de falha.","engines":{"postgres":"# crontab\n0 1 * * 0 pgbackrest --stanza=appdb --type=full backup\n0 1 * * 1-6 pgbackrest --stanza=appdb --type=incr backup"}},{"title":"Defina uma política de retenção","detail":"Não acumule backups para sempre; defina quantos backups full e quantos dias de arquivos manter, e deixe a ferramenta expirar os antigos automaticamente. No pgBackRest isso é gerenciado com repo1-retention-full e as configurações de retenção de arquivo; no Barman, com retention_policy. A retenção precisa estar de acordo com seus objetivos de recuperação (quantos dias para trás você precisa voltar).","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":"Copie os backups para fora (offsite) / para o S3","detail":"Os backups não devem ficar na mesma máquina/região que o banco; copie-os para outro local ou object storage (S3, GCS). O pgBackRest pode gravar direto em armazenamento compatível com S3; caso contrário, sincronize com um destino offsite usando rsync/rclone. Em um desastre (perda do disco/região local), só a cópia offsite vai salvar você.","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":"Verifique o backup","detail":"Um backup existir não significa que ele possa ser restaurado; verifique a integridade regularmente. No pgBackRest, o comando 'verify' e as verificações de consistência do arquivo, e no XtraBackup uma etapa de prepare (--prepare) bem-sucedida, mostram que o backup está íntegro. Execute a verificação automaticamente após cada backup e gere um alarme em caso de falha.","engines":{"postgres":"pgbackrest --stanza=appdb verify","mysql":"# make the backup consistent (verification)\nxtrabackup --prepare --target-dir=/backup/full"}},{"title":"Faça exercícios de restore regulares","detail":"A etapa mais crítica: periodicamente, restaure DE VERDADE o backup em um servidor separado e verifique se o banco abre e se os dados estão consistentes. Esse exercício permite medir seu tempo de recuperação (RTO) e encontrar falhas no procedimento fora de um incidente. Backup não testado não é backup.","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 e deploy blue-green / sem downtime","icon":"🟦","symptom":"Objetivo: implantar alterações de schema e de aplicação sem downtime; chegar perto do zero downtime com migrações expand-contract, ambientes blue-green, feature flags e rollback automático.","steps":[{"title":"GitOps: faça do Git a única fonte da verdade","detail":"Defina no Git a infraestrutura, as migrações de schema e a versão da aplicação; o deploy é disparado por um merge no repositório (GitOps). Um reconciliador (Argo CD/Flux ou CI/CD) aplica o estado desejado ao ambiente real. Assim cada alteração é auditável, repetível e pode ser revertida para um commit anterior quando necessário.","engines":{"postgres":"# repo/\n#   migrations/  (Vxxx__*.sql)\n#   k8s/         (Deployment, Service)\n#   flags/       (feature flag config)"}},{"title":"Altere o schema de forma retrocompatível (expand-contract)","detail":"Para zero downtime, não altere o schema em um único passo que quebra compatibilidade; divida em duas fases. EXPAND: adicione a nova estrutura (nova coluna/tabela) de modo que o código antigo e o novo possam rodar ao mesmo tempo (coluna nullable, com default, escrita dupla). DEPOIS que a aplicação passar para a nova estrutura, CONTRACT: remova a coluna/tabela antiga que não é mais usada em uma migração separada. Assim as versões antiga e nova da aplicação rodam lado a lado sem problemas durante o deploy.","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":"Coloque comportamentos arriscados atrás de uma feature flag","detail":"Execute o novo caminho de código (como ler a nova coluna) condicionalmente atrás de uma feature flag; ative a flag quando o schema estiver pronto e desative-a sem mexer no deploy se algo der errado. Uma flag separa a implantação do código (deploy) da ativação do recurso (release). A fase expand é implantada, mas a mudança de comportamento é ativada de forma controlada e pode ser revertida rapidamente.","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":"Monte o ambiente blue-green","detail":"Mantenha dois ambientes idênticos: 'blue' (produção) e 'green' (nova versão). Implante a nova versão da aplicação no green e valide-a antes que receba tráfego real; quando estiver pronta, mude o roteador/tráfego para o green. Ponto-chave: o banco geralmente é COMPARTILHADO, então o schema precisa ser compatível com as duas versões (o expand-contract garante isso). Mesmo que o destino da conexão mude no cutover, a compatibilidade do schema significa zero downtime.","engines":{"postgres":"# traffic is switched to green (new version)\n# shared DB: schema must be compatible with both blue and green"}},{"title":"Valide o deploy com monitoramento (canary/observação)","detail":"Antes de transferir todo o tráfego, monitore métricas como taxa de erros, latência, contagens de erros/locks do banco e lag de replicação; opcionalmente, envie uma pequena porcentagem do tráfego (canary) para o green e observe. Se os indicadores de saúde estiverem bons, aumente o tráfego gradualmente; se estiverem ruins, não prossiga. O monitoramento é a entrada para a decisão de rollback automático.","engines":{"postgres":"-- live health queries\nSELECT count(*) FROM pg_stat_activity WHERE wait_event_type='Lock';\nSELECT * FROM pg_stat_replication;"}},{"title":"Prepare o rollback automático","detail":"Se as métricas ultrapassarem o limite, o deploy precisa voltar atrás automaticamente: no blue-green, mude rapidamente o tráfego de volta para o blue (a versão antiga). O rollback da aplicação é instantâneo porque o blue continua rodando. Do lado do schema, o rollback geralmente NÃO É NECESSÁRIO: graças ao expand-contract, o novo schema também é compatível com o código antigo, então reverter a aplicação basta. Por isso as alterações de schema devem ser independentes do deploy da aplicação e sempre retrocompatíveis.","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":"Instalação"},{"id":"ha","title":"Alta disponibilidade & replicação"},{"id":"backup","title":"Backup & recuperação"},{"id":"ops","title":"Operação diária & incidentes"},{"id":"pooling","title":"Conexão & balanceamento de carga"},{"id":"patch","title":"Patches & atualizações menores"},{"id":"upgrade","title":"Upgrade major & migração"},{"id":"monitoring","title":"Monitoramento & gestão"},{"id":"security","title":"Segurança & hardening"}],"guides":[{"id":"pg-install","file":"install/guides/pg-install.json","group":"PostgreSQL","engineId":"postgres","category":"install","title":"Instalação do PostgreSQL em servidor único (pronta para produção)","summary":"Instalação do PostgreSQL pronta para produção em um único servidor a partir do repositório PGDG: diretório de dados separado, data checksums, parâmetros calculados a partir de RAM/CPU, acesso seguro (peer + scram-sha-256","level":"Iniciante","duration":"30–45 min","topology":"1 servidor","tags":["postgresql","postgres","instalação","install","pgdg","initdb","tuning","rhel","ubuntu"],"order":1,"steps":23,"scenarios":[]},{"id":"pg-streaming","file":"install/guides/pg-streaming.json","group":"PostgreSQL","engineId":"postgres","category":"ha","title":"PostgreSQL streaming replication (primary + standby)","summary":"Adiciona um ou mais hot standbys a um primary já instalado com pg_basebackup (usuário de replicação, pg_hba, replication slot, modo assíncrono ou síncrono ANY/FIRST, monitoramento de atraso) e gera os runbooks de operaçã","level":"Intermediário","duration":"45–90 min","topology":"1 primary + 1..N standbys","tags":["postgresql","streaming replication","replicação","standby","hot standby","pg_basebackup","replication slot","synchronous","replicação síncrona","failover","switchover","pg_promote","pg_rewind","ha","cascading","delayed standby","recovery_min_apply_delay","limpeza de slots","pg_wal cheio","synchronous_standby_names","reconstruir standby"],"order":2,"steps":24,"scenarios":[{"k":"mode","v":"install","l":"Instalação: adicionar standbys ao primary","m":"Adicionar / reconstruir standby configurar streaming replication adicionar standby hot standby pg_basebackup read replica réplica de leitura physical replication replicação física standby.signal primary_conninfo Um ou mais hot standbys são adicionados a um primary já instalado com pg_basebackup (slot, síncrono/assíncrono, monitoramento). O primary continua aberto; a cópia inicial gera carga de dis"},{"k":"mode","v":"switchover","l":"Switchover planejado (troca de papéis, sem perda de dados)","m":"Troca de papéis switchover planned switchover troca de papéis inversão planejada de papéis manutenção do primary tornar o standby primary pg_promote pg_ctl promote Manutenção planejada: o primary é desligado de forma limpa, o primeiro standby é promovido e o antigo primary volta como standby. Sem perda de dados; a interrupção de escrita costuma ser menor que 1 minuto."},{"k":"mode","v":"failover","l":"Failover manual (o primary caiu, promover o standby)","m":"Troca de papéis could not connect to the primary server Connection refused primary down primary caiu primary inacessível failover manual failover promote standby pg_promote split-brain could not receive data from WAL stream servidor primary perdido O primary caiu ou está inacessível: o antigo primary é isolado (fencing) e o standby mais atualizado é promovido manualmente. No modo assíncrono as últ"},{"k":"mode","v":"rejoin","l":"Reintegrar o antigo primary como standby com pg_rewind","m":"Troca de papéis 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 reintegrar antigo primary rejoin old primary Após o failover, o antigo primary é ressincronizado com o novo primary via pg_rewind e volta como standby; é muito mais rápido que uma cópia completa."},{"k":"mode","v":"cascade","l":"Adicionar um novo standby alimentado por outro standby (cascading)","m":"Adicionar / reconstruir standby cascading replication cascade standby replicação em cascata standby a partir de standby data center remoto DR standby O novo standby recebe o WAL do primeiro standby em vez do primary: em um data center remoto ou com muitos standbys, isso reduz a carga de rede/envio de WAL do primary. O primary não é afetado."},{"k":"mode","v":"delayed","l":"Configurar um standby com atraso (delayed)","m":"Adicionar / reconstruir standby recovery_min_apply_delay delayed standby standby com atraso apagado por engano desfazer DROP TABLE accidental delete pg_wal_replay_pause Standby que aplica o WAL horas depois (`recovery_min_apply_delay`): para recuperar dados apagados por engano sem restaurar backup. Não é candidato a failover."},{"k":"mode","v":"rebuild","l":"Reconstruir um standby do zero","m":"Adicionar / reconstruir 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 reconstruir standby standby corrompido re-clone standby could not start WAL streaming wal_removed standby ficou para trás O standby ficou para trás, seu WAL foi removido ou está corrompido: o diretóri"},{"k":"mode","v":"slotclean","l":"pg_wal crescendo, disco enchendo (limpeza de slots não usados)","m":"Manutenção e solução de problemas No space left on device could not write to file \"pg_wal pg_wal cheio pg_wal crescendo inchaço de WAL disco cheio replication slot inactive max_slot_wal_keep_size diretório pg_wal grande WAL disk full A causa do acúmulo de WAL é identificada (slot inativo, falha de arquivamento, wal_keep_size); o replication slot não usado é removido e o espaço de WAL é recuperado."},{"k":"mode","v":"syncchg","l":"Adicionar / remover standby síncrono (synchronous_standby_names)","m":"Manutenção e solução de problemas canceling wait for synchronous replication synchronous_standby_names COMMIT pendente commit hangs sync standby standby síncrono sync_state potential synchronous_commit Reescreve a lista síncrona conforme o modo do formulário (ANY/FIRST, k) ou volta para assíncrono; aplicado com reload, sem restart. Uma configuração errada pode deixar commits pendentes; por isso é "}]},{"id":"pg-patroni","file":"install/guides/pg-patroni.json","group":"PostgreSQL","engineId":"postgres","category":"ha","title":"Cluster com failover automático usando Patroni + etcd + HAProxy","summary":"Instala e opera um cluster PostgreSQL com failover automático: em cada node o PostgreSQL é gerenciado pelo Patroni, a eleição do leader acontece em um etcd de 3 (ou 5) membros e as aplicações se conectam às portas de esc","level":"Avançado","duration":"2–3 horas","topology":"3 nodes PostgreSQL + etcd (compartilhados ou separados) + HAProxy (+ VIP)","tags":["postgresql","patroni","etcd","haproxy","keepalived","vip","failover automático","auto failover","switchover","ha","alta disponibilidade","cluster","cluster postgres","patronictl","dcs","reinit","pg_rewind","edit-config","pause","resume","etcdctl member","quórum","failsafe","adicionar node","remover node","patroni upgrade","desligar cluster"],"order":3,"steps":40,"scenarios":[{"k":"mode","v":"install","l":"Instalação: novo cluster Patroni","m":"Instalação instalação do patroni patroni install instalação do etcd haproxy failover automático automatic failover alta disponibilidade alta disponibilidade cluster HA Monta do zero um cluster etcd + Patroni + HAProxy (+ VIP). Os servidores não devem ter um cluster PostgreSQL: o Patroni executa o initdb (o pg-install não é aplicado)."},{"k":"mode","v":"ops","l":"Runbook de operação: switchover, teste de failover, modo de manutenção, alteração de parâmetro","m":"Verificação e simulação teste de failover failover test simulação DR drill runbook Executa em sequência as operações básicas em um cluster recém-instalado: status, switchover, teste de failover (o leader é parado, breve interrupção de escrita), modo de manutenção, alteração de parâmetro. Execute em uma janela de manutenção."},{"k":"mode","v":"health","l":"O cluster está saudável? (verificação de saúde)","m":"Verificação e simulação patronictl list Pending restart Maintenance mode: on start failed patroni health status do cluster replica lag atraso timeline diferente Somente leitura: papéis, atraso, timeline, REST API, saúde do etcd, slots, restart pendente e modo de manutenção."},{"k":"mode","v":"switchover","l":"Switchover planejado (mover o leader para outro node)","m":"Troca de papel candidate name does not match with sync_standby Switchover failed does not exist in cluster or is tagged as nofailover switchover trocar leader troca de papel manutenção planejada Antes da manutenção, o papel de leader passa de forma controlada para uma réplica; alguns segundos de interrupção de escrita, sem perda de dados."},{"k":"mode","v":"rejoin","l":"Houve failover e o leader antigo não volta ao cluster (pg_rewind / reinit)","m":"Troca de papel 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 antigo após failover pg_rewind: fatal could not find common ancestor timeline history mismatch Quando o leader antigo que caiu volta, ele deve entrar como réplica; se o pg_rewind "},{"k":"mode","v":"reinit","l":"Reconstruir uma réplica do zero (reinit)","m":"Manutenção de membro requested WAL segment has already been removed could not receive data from WAL stream invalid record length invalid page patronictl reinit réplica corrompida réplica atrasada rebuild replica replica start failed creating replica A réplica está corrompida, muito atrasada ou perdeu WAL: o diretório de dados é apagado e reconstruído a partir do leader (ou de um backup). O leader "},{"k":"mode","v":"addmember","l":"Adicionar um novo node ao cluster","m":"Manutenção de membro adicionar node add member nova réplica scale out expandir cluster Adicione o novo node ao final da lista no formulário: o software é instalado, o pg_hba e o HAProxy são atualizados nos nodes existentes e o node entra como réplica."},{"k":"mode","v":"rmmember","l":"Remover um node do cluster","m":"Manutenção de membro remover node remove member decommission desativar servidor remover réplica Um node que é réplica é removido definitivamente: o Patroni é parado, o registro no DCS e o slot são limpos e o node é retirado do HAProxy."},{"k":"mode","v":"editcfg","l":"Alterar uma configuração do PostgreSQL ou do Patroni (edit-config)","m":"Configuração e manutenção edit-config Pending restart configuração do postgresql.conf perdida ALTER SYSTEM alterar parâmetro max_connections shared_buffers change parameter work_mem parâmetro perdido configuração não aplicada A configuração é gravada no DCS e aplicada a todos os nodes; para configurações que exigem restart, `restart --pending` (réplicas primeiro)."},{"k":"mode","v":"pause","l":"Suspender o failover automático para manutenção (pause / resume)","m":"Configuração e manutenção Maintenance mode: on patronictl pause patronictl resume maintenance mode modo de manutenção desativar failover automático Em pause, o Patroni não mexe no PostgreSQL e não faz failover; para manutenção de rede/etcd ou intervenção manual. Ao terminar, resume."},{"k":"mode","v":"upgrade","l":"Atualizar o software do Patroni (rolling)","m":"Configuração e manutenção patroni upgrade atualização do patroni versão do patroni dnf update patroni apt upgrade patroni patroni 3 to 4 O cluster entra em pause e o Patroni é atualizado e reiniciado node a node; o PostgreSQL não para e não há failover."},{"k":"mode","v":"stopstart","l":"Parar / iniciar o cluster inteiro (ordem correta)","m":"Configuração e manutenção desligar cluster iniciar cluster shutdown order desligamento completo desligamento planejado manutenção de data center queda de energia Desligamento completo planejado (manutenção de storage ou de data center): primeiro as réplicas, depois o leader e por último o etcd; a inicialização segue a ordem inversa."},{"k":"mode","v":"etcdmember","l":"Substituir ou adicionar um membro do 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 membro etcd unhealthy O membro do etcd com falha é removido e um novo servidor é adicionado (ou o número de membros é aumentado); a lista de hosts etcd do Patroni é atualizada."},{"k":"mode","v":"dcsloss","l":"Quórum do etcd perdido: o leader ficou somente leitura","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 quórum failsafe etcd quorum lost sem leader no leader Sem quórum no etcd, o Patroni coloca o leader em somente leitura e também não há failover. O etcd é recuperado ou reconstruído a partir de um único membro."}]},{"id":"pg-pgbouncer","file":"install/guides/pg-pgbouncer.json","group":"PostgreSQL","engineId":"postgres","category":"pooling","title":"Pool de conexões com PgBouncer","summary":"Instalação do PgBouncer a partir do repositório PGDG: modo de pool transaction ou session, autenticação scram-sha-256 via auth_query (função SECURITY DEFINER) ou userlist.txt, tamanhos de pool calculados a partir do max_","level":"Intermediário","duration":"30–45 min","topology":"PgBouncer no servidor do banco ou em servidor separado; com Patroni, na frente do HAProxy/VIP","tags":["postgresql","pgbouncer","connection pool","pool de conexões","pooling","transaction pooling","auth_query","userlist","scram-sha-256","so_reuseport","max_client_conn","default_pool_size","patroni","haproxy","vip","failover"],"order":4,"steps":15,"scenarios":[]},{"id":"pg-pgbackrest","file":"install/guides/pg-pgbackrest.json","group":"PostgreSQL","engineId":"postgres","category":"backup","title":"Backup e PITR com pgBackRest","summary":"Backup full / diferencial / incremental com pgBackRest, arquivamento contínuo de WAL e recuperação para um ponto no tempo (PITR). Para servidor único, streaming replication (primary + standbys) ou cluster Patroni; o repo","level":"Intermediário","duration":"45–90 min","topology":"1 servidor, primary + standbys ou cluster Patroni; servidor de backup opcional","tags":["postgresql","pgbackrest","cópia de segurança","backup","restore","pitr","wal","archive","s3","minio","criptografia","retention","recuperação","patroni","streaming","standby","cron","backup-standby","systemd timer","delta restore","db-include","target-action","restore point","xid","lsn","clone","clonar","desastre","disaster recovery","verify","expire","type=standby","simulação"],"order":10,"steps":28,"scenarios":[{"k":"purpose","v":"kur","l":"Instalação do pgBackRest + primeiro backup + restore de teste","m":"Instalação stanza-create archive_command archive-push instalação do pgbackrest pgbackrest install configurar backup backup setup plano de backup full diff incr backup agendado ERROR: [087] archive_mode must be enabled configurar arquivamento de WAL primeiro backup O pgBackRest ainda não existe: software, repositório, arquivamento de WAL, primeiro backup, agendamento e um restore de teste."},{"k":"purpose","v":"geri","l":"Em um desastre: restore no local (até o estado mais recente ou até um ponto no tempo)","m":"Restore (mesmo servidor) recovery_target_time recovery_target_xid recovery_target_lsn pg_create_restore_point PITR point in time recovery recuperação para um ponto no tempo excluído por engano DROP TABLE DELETE without WHERE UPDATE without WHERE TRUNCATE restore point restore to time recuperar dados Leve o banco de dados, no próprio servidor, a um instante presente no backup e no archive: o último"},{"k":"purpose","v":"delta","l":"Há arquivos corrompidos ou excluídos no diretório de dados (reparar com delta restore)","m":"Restore (mesmo servidor) 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 bloco corrompido data corruption block corruption arquivo de dados excluído ERROR:  could not read block PANIC:  could not open file PANIC:  coul"},{"k":"purpose","v":"dbinc","l":"Recuperar apenas um banco de dados (--db-include)","m":"Restore (mesmo servidor) db-include DROP DATABASE banco de dados único single database restore banco de dados excluído recuperar tabela table restore restore de uma tabela O cluster continua no ar: o banco de dados é restaurado em uma instância temporária (diretório e porta separados), exportado com pg_dump e carregado no servidor de produção com um novo nome. Use este cartão também para uma única"},{"k":"purpose","v":"clone","l":"Restaurar o backup em outro servidor (clone / teste / relatórios)","m":"Novo servidor: clone, desastre, standby repo1-cipher-pass clone clonar ambiente de teste atualizar ambiente de teste refresh test staging restore em novo servidor servidor de relatórios repositório criptografado O servidor de produção não é tocado. O backup é aberto em um novo servidor; o arquivamento de WAL é desativado para que o clone não grave no repositório de produção. Em repositório criptog"},{"k":"purpose","v":"dr","l":"O servidor foi totalmente perdido: abrir o backup em um novo servidor e colocá-lo no lugar","m":"Novo servidor: clone, desastre, standby PANIC: could not locate a valid checkpoint record desastre disaster recovery DR perda de servidor falha de disco server lost diretório de dados perdido novo primary repositório criptografado could not open file \"global/pg_control\" servidor não sobe PostgreSQL não inicia Perda de disco ou servidor: o novo servidor é aberto a partir do backup e se torna o novo"},{"k":"purpose","v":"standby","l":"Criar um novo standby a partir do backup (--type=standby)","m":"Novo servidor: clone, desastre, standby type=standby criar standby adicionar réplica standby a partir do backup standby rebuild em vez de pg_basebackup add standby Novo standby sem sobrecarregar o primary com a cópia: os arquivos vêm do backup, e o WAL que falta é completado a partir do archive e via streaming. O primary continua no ar."},{"k":"purpose","v":"verify","l":"Os backups estão realmente íntegros? (info / check / verify e simulação de restore)","m":"Verificação e manutenção ERROR: [082] ERROR: [028] ERROR: [056] pgbackrest verify pgbackrest check pgbackrest info verificação de backup backup verification restore test simulação quando foi o último backup verify command o backup está íntegro restore drill verificação mensal Verificações somente leitura e uma simulação de restore em diretório separado, sem tocar no servidor de produção. Também é "},{"k":"purpose","v":"retention","l":"Alterar o período de retenção e limpar backups antigos (expire)","m":"Verificação e manutenção No space left on device WARN: option 'repo1-retention-full' is not set repo1-retention-full expire retention retenção repositório cheio disco de backup cheio excluir backups antigos repo cheio bucket cheio disco de backup lotado Altera os parâmetros repo1-retention-full/diff, mostra primeiro com --dry-run o que será excluído e depois executa o expire. Um backup excluído nã"}]},{"id":"pg-pitr-basebackup","file":"install/guides/pg-pitr-basebackup.json","group":"PostgreSQL","engineId":"postgres","category":"backup","title":"Backup e PITR com pg_basebackup + arquivo de WAL (sem pgBackRest)","summary":"Backup físico com as ferramentas do próprio PostgreSQL, sem software adicional: arquivamento contínuo de WAL com archive_command, base backup noturno com pg_basebackup, retenção com pg_archivecleanup. Recuperação para um","level":"Intermediário","duration":"45–90 min","topology":"1 servidor; com streaming ou Patroni o diretório de arquivo é compartilhado por todos os nodes (NFS)","tags":["postgresql","pg_basebackup","archive_command","restore_command","pitr","point in time recovery","recovery.signal","recovery_target_time","pg_archivecleanup","arquivo de wal","timeline","base backup","backup","restauração","pg_verifybackup","cron","teste de restore"],"order":12,"steps":14,"scenarios":[{"k":"op","v":"kur","l":"Configurar o arquivamento de WAL e o base backup noturno","m":"Configuração archive_mode archive_command archive_timeout pg_stat_archiver wal_level arquivo de WAL WAL archiving continuous archiving arquivamento contínuo pg_basebackup cron base backup backup noturno nightly backup configurar arquivamento de wal Configuração inicial: arquivamento contínuo de WAL com archive_command, script do pg_basebackup, agendamento em /etc/cron.d, retenção e limpeza de WAL."},{"k":"op","v":"pitr","l":"Recuperar até um ponto específico (PITR: tempo, xid, LSN, restore point)","m":"Restauração 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 apagado por engano accidental delete recuperar até um ponto n"},{"k":"op","v":"drill","l":"Teste de restore (em diretório separado, sem tocar em produção)","m":"Verificação e manutenção backup successfully verified pg_verifybackup pg_amcheck restore test restore drill teste de restore verificação de backup backup verify RTO o backup restaura Para comprovar que o backup realmente restaura (recomendado uma vez por mês): o último base backup é verificado (pg_verifybackup), extraído em um diretório separado e iniciado em outra porta com o arquivo de WAL; o te"},{"k":"op","v":"cleanup","l":"Limpar base backups antigos e o arquivo de WAL","m":"Verificação e manutenção No space left on device could not write to file archive command failed pg_archivecleanup disco do arquivo cheio arquivo de wal cheio disk full apagar backups antigos retenção de backup retention pg_wal crescendo archive_status .ready O disco do arquivo ou do backup está enchendo, ou a retenção mudou: os base backups antigos são apagados e o pg_archivecleanup remove o WAL a"}]},{"id":"pg-logical-repl","file":"install/guides/pg-logical-repl.json","group":"PostgreSQL","engineId":"postgres","category":"ha","title":"Logical replication do PostgreSQL (publication / subscription)","summary":"Logical replication em nível de tabela entre dois clusters PostgreSQL: wal_level=logical, verificação de replica identity, publication e subscription, sincronização inicial, monitoramento, tratamento de conflitos e sincr","level":"Avançado","duration":"45–90 min (+ tempo da cópia inicial)","topology":"2 servidores: publisher + subscriber; o publisher pode ser um servidor único, um ambiente de streaming replication ou um cluster Patroni","tags":["postgresql","logical replication","replicação lógica","publication","subscription","cdc","migração de dados","migration","upgrade","conflict","replica identity","sequence","patroni","failover slot","permanent slots","sync_replication_slots"],"order":15,"steps":25,"scenarios":[{"k":"purpose","v":"sync","l":"Replicação contínua (relatórios, integração, cópia parcial)","m":"logical replication publication subscription CREATE SUBSCRIPTION replicação de tabelas replicação parcial As tabelas escolhidas fluem continuamente para outro cluster (servidor de relatórios, alimentação de data warehouse, integração entre serviços). O subscriber continua gravável."},{"k":"purpose","v":"migrate","l":"Migração: novo servidor / nova major version + cutover","m":"upgrade sem downtime near zero downtime cutover migração de servidor logical upgrade Mudar para um novo servidor ou uma nova major version com segundos de downtime: cópia inicial e sincronização contínua, depois um breve congelamento de escritas e o cutover."}]},{"id":"pg-dump-restore","file":"install/guides/pg-dump-restore.json","group":"PostgreSQL","engineId":"postgres","category":"backup","title":"Backup lógico e restauração no PostgreSQL (pg_dump / pg_restore)","summary":"Backup lógico e restauração com pg_dump, pg_dumpall e pg_restore em nível de tabela, schema, banco de dados ou cluster inteiro; somente estrutura (DDL) ou somente dados, migração para outro servidor/versão, restauração d","level":"Intermediário","duration":"20–90 min (conforme o tamanho dos dados)","topology":"1 servidor, streaming replication (primary + standby) ou um cluster Patroni; origem + destino na migração, mais um servidor de backup no backup agendado remoto","tags":["postgresql","postgres","pg_dump","pg_restore","pg_dumpall","backup lógico","logical backup","export","import","dump","restore","restaurar dump","migração de banco de dados","migration","upgrade","globals","systemd timer","cron","pgpass","backup","patroni","streaming replication","replica","standby","haproxy","hot standby","pg_wrapper","cron.d","flock"],"order":15,"steps":9,"scenarios":[{"k":"mode","v":"tables","l":"Export / import de tabela(s)","m":"Export / import pg_dump -t exportar tabela importar tabela table export backup de uma tabela no matching tables were found A estrutura e os dados das tabelas escolhidas (incluindo índices, constraints e triggers) são exportados e carregados em outro banco de dados."},{"k":"mode","v":"schema","l":"Export / import de um schema","m":"Export / import pg_dump -n exportar schema schema export no matching schemas were found Todos os objetos do schema (tabelas, views, funções, sequences) são exportados."},{"k":"mode","v":"db","l":"Backup / restore de um banco de dados","m":"Export / import pg_dump pg_restore dump de banco de dados database backup database restore errors ignored on restore Um banco de dados inteiro (estrutura + dados) vai para um único dump e é restaurado no mesmo ou em outro banco de dados. As roles (globals) não estão incluídas."},{"k":"mode","v":"cluster","l":"Cluster inteiro (roles + tablespaces + todos os bancos de dados)","m":"Export / import pg_dumpall pg_dumpall -g globals backup do cluster inteiro backup de roles Globals com pg_dumpall -g, um pg_dump separado para cada banco de dados; a restauração é ensaiada em um cluster de teste temporário."},{"k":"mode","v":"ddl","l":"Somente a estrutura do schema (DDL)","m":"Estrutura e dados separados pg_dump -s --schema-only DDL export somente estrutura Definições de tabelas, índices, views e funções sem dados; para revisão, controle de versão ou montagem de um ambiente vazio."},{"k":"mode","v":"data","l":"Somente dados","m":"Estrutura e dados separados pg_dump -a --data-only somente dados --disable-triggers circular foreign-key constraints Apenas as linhas (COPY) são transferidas, com a estrutura já pronta no destino."},{"k":"mode","v":"migrate","l":"Migrar para outro servidor / versão","m":"Migração e recuperação migração de servidor migration dump restore upgrade aborting because of server version mismatch migrar para nova versão No servidor de destino, o pg_dump da nova versão conecta-se à origem pela rede; os dados são transferidos por pipe ou por arquivo."},{"k":"mode","v":"partial","l":"Restaurar uma única tabela / objeto a partir de um dump","m":"Migração e recuperação restaurar uma tabela pg_restore -L pg_restore --list DROP TABLE tabela apagada linhas apagadas apagado por engano table restore A partir de um dump custom/directory existente, apenas uma tabela com seus índices, constraints e dados é restaurada usando um arquivo de lista (-L)."},{"k":"mode","v":"sched","l":"Backup agendado (systemd timer / cron)","m":"Backup agendado pg_dump cron systemd timer backup agendado scheduled backup backup diário retenção de backup Backup diário de globals + banco de dados, verificação de legibilidade, retenção, log e notificação de falha."}]},{"id":"pg-minor-update","file":"install/guides/pg-minor-update.json","group":"PostgreSQL","engineId":"postgres","category":"patch","title":"Atualização de versão minor do PostgreSQL (patch)","summary":"Atualização minor dentro da mesma versão principal (ex.: 17.4 → 17.x): revisão das release notes, backup e preservação dos RPM/deb atuais para rollback. Em servidor único, com uma interrupção curta; em um cluster com str","level":"Intermediário","duration":"20–60 min","topology":"1 servidor, primary + standbys ou um cluster Patroni","tags":["postgresql","minor","patch","atualização","update","upgrade","rolling","switchover","dnf","apt","downgrade","rollback","extension","patroni","patronictl","failover"],"order":20,"steps":17,"scenarios":[{"k":"purpose","v":"upd","l":"Atualização minor","m":"minor update atualização de versão minor patch CVE atualização de segurança dnf upgrade postgresql apt upgrade postgresql Migrar para uma versão minor mais nova dentro da mesma versão principal (ex.: 17.4 → 17.6): correções de segurança e de bugs. Interrupção curta em servidor único, rolling em cluster."},{"k":"purpose","v":"rb","l":"Rollback: voltar à versão minor anterior (downgrade)","m":"downgrade reverter rollback voltar à versão anterior undefined symbol Um bug ou regressão apareceu na nova versão minor: faça o rollback com os RPM/deb salvos da versão anterior. O diretório de dados não muda."}]},{"id":"pg-major-upgrade","file":"install/guides/pg-major-upgrade.json","group":"PostgreSQL","engineId":"postgres","category":"upgrade","title":"PostgreSQL major upgrade (pg_upgrade / logical replication)","summary":"Upgrade de versão principal (ex.: 16 → 17): escolha do método (pg_upgrade --link / --copy / --clone ou migração quase sem downtime com logical replication), pg_upgrade --check, compatibilidade das extensões, migração da ","level":"Avançado","duration":"1–3 horas (+ conforme o tamanho dos dados)","topology":"In-place no mesmo servidor (pg_upgrade; servidor único, primary + standbys ou cluster Patroni) ou para um novo servidor (logical)","tags":["postgresql","major","upgrade","atualização de versão","pg_upgrade","pg_upgradecluster","link","clone","logical replication","migração","migration","rsync","rollback","patroni","patronictl remove","replica","streaming replication"],"order":30,"steps":24,"scenarios":[{"k":"purpose","v":"upg","l":"Major upgrade","m":"major upgrade pg_upgrade pg_upgradecluster upgrade de versão versão principal upgrade postgresql 17 upgrade postgresql 18 Upgrade de versão principal (ex.: 16 → 17): pré-verificações, backup, pg_upgrade ou logical replication, verificação e limpeza."},{"k":"purpose","v":"rb","l":"Rollback (upgrade falhou / foi abandonado)","m":"desfazer upgrade rollback pg_control.old database files are incompatible with server upgrade falhou O upgrade parou no meio ou a nova versão apresentou problemas: voltar para a versão antiga. Com --link, se o novo cluster já foi iniciado, só é possível voltar pelo backup."}]},{"id":"pg-security","file":"install/guides/pg-security.json","group":"PostgreSQL","engineId":"postgres","category":"security","title":"Hardening de segurança do PostgreSQL (auditoria de estado, rede, TLS, autenticação, privilégios, audit, criptografia)","summary":"Este não é um guia de instalação: ele encontra e fecha as brechas de segurança de um servidor PostgreSQL em execução. Primeiro a Auditoria de estado, somente leitura, lista as brechas por severidade e indica para qual ca","level":"Intermediário","duration":"5 min (auditoria) – 3 horas (hardening completo)","topology":"Um único servidor PostgreSQL + servidor de aplicação (verificação do cliente); ambientes com replica/Patroni nas notas","tags":["postgresql","postgres","segurança","security","hardening","endurecimento","cis benchmark","pg_hba","tls","ssl","sslmode","verify-full","scram-sha-256","md5","pgaudit","audit","auditoria","public schema","privilégios","role","luks","pgcrypto","criptografia","encryption","firewall"],"order":40,"steps":3,"scenarios":[{"k":"scenario","v":"scan","l":"Auditoria de estado: quais são minhas brechas? (somente leitura)","m":"Comece aqui auditoria de segurança security audit hardening check CIS brecha de segurança vulnerabilidade vulnerability achado de pentest relatório de auditoria consulta de auditoria verificação CIS varredura de segurança security scan A primeira varredura a executar: pg_hba, endereço de escuta, TLS, senhas md5, superusuários, privilégios de PUBLIC, audit, permissões de arquivos e firewall; não al"},{"k":"scenario","v":"all","l":"Hardening completo (todas as áreas em sequência)","m":"Comece aqui hardening endurecimento segurança completa full hardening aplicar CIS benchmark STIG Servidor recém-instalado ou que nunca passou por hardening: todas as áreas são aplicadas em uma ordem segura; o PostgreSQL é reiniciado uma ou duas vezes (é necessária uma janela de manutenção)."},{"k":"scenario","v":"net","l":"Rede e conexões: quem pode se conectar de onde? (listen, firewall, pg_hba)","m":"Rede e identidade pg_hba.conf 0.0.0.0/0 trust listen_addresses firewall no pg_hba.conf entry pg_hba.conf rejects connection porta 5432 aberta FATAL: no pg_hba.conf entry for host 28000 Connection refused listen_addresses = * host all all 0.0.0.0/0 acesso externo restringir acesso O PostgreSQL escuta em todas as interfaces, o pg_hba tem 0.0.0.0/0 ou trust, a porta está aberta para todos. Alterar li"},{"k":"scenario","v":"tls","l":"Criptografar as conexões (TLS, sslmode=verify-full)","m":"Rede e identidade ssl tls sslmode verify-full hostssl certificate verify failed SSL off sem criptografia server.crt certificado expirado 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 certificado autoassinado cadeia de certificados certificate chain hostnossl ssl = off ou os cl"},{"k":"scenario","v":"auth","l":"Autenticação e senhas (scram-sha-256, login remoto do postgres)","m":"Rede e identidade md5 scram-sha-256 password_encryption password authentication failed authentication method 10 not supported login remoto postgres política de senhas password policy 28P01 FATAL: password authentication failed for user SCRAM authentication requires libpq version 10 or above pass-the-hash VALID UNTIL validade da senha Método md5/password, senhas com hash md5, o usuário postgres con"},{"k":"scenario","v":"priv","l":"Privilégio mínimo: roles, PUBLIC e a conta da aplicação","m":"Privilégios e trilha de auditoria public schema PUBLIC GRANT REVOKE superuser least privilege privilégio mínimo permission denied for schema desenho de roles DEFAULT PRIVILEGES 42501 permission denied for table must be owner of table pg_read_server_files pg_execute_server_program SECURITY DEFINER REASSIGN OWNED relatório de privilégios A conta da aplicação é dona das tabelas ou é superusuário, qua"},{"k":"scenario","v":"audit","l":"Audit: quem fez o quê? (pgaudit, log centralizado)","m":"Privilégios e trilha de auditoria pgaudit audit trilha de auditoria audit log AUDIT: SESSION log_connections syslog SIEM LGPD PCI shared_preload_libraries could not access file \"pgaudit\" pgaudit must be loaded via shared_preload_libraries log_statement quem fez o quê who changed O auditor ou a equipe de segurança exige o registro das alterações de DDL e de roles; instalação do pgaudit e envio do l"},{"k":"scenario","v":"tde","l":"Criptografar os dados em disco (LUKS / pgcrypto)","m":"Dados e backups TDE transparent data encryption criptografia de disco encryption at rest LUKS dm-crypt pgcrypto pg_tde cryptsetup luksFormat pgp_sym_encrypt criptografia em repouso É exigida proteção contra roubo do disco ou do backup. O PostgreSQL não tem TDE nativo: LUKS no nível do disco (downtime para a migração) ou pgcrypto no nível da coluna."},{"k":"scenario","v":"backup","l":"Segurança dos backups (backup criptografado, permissões)","m":"Dados e backups criptografia de backup backup encryption repo-cipher-type pgbackrest cipher gpg .pgpass permissões de backup cipher: none repo-cipher-pass backup sem criptografia unencrypted backup Os arquivos de backup não estão criptografados ou ficam em um diretório que todos podem ler; criptografia do repositório do pgBackRest ou pg_dump + GPG, .pgpass e permissões de diretório. Sem downtime."},{"k":"scenario","v":"os","l":"Lado do sistema operacional (conta de serviço, permissões, core dump, SELinux)","m":"Servidor e versão SELinux permissive chmod 700 data directory has invalid permissions core dump conta postgres sudo avc: denied LimitCORE core dumped passwd -l A conta postgres tem senha utilizável, as permissões do diretório de dados estão frouxas, o SELinux está Permissive/Disabled. A configuração de core dump passa a valer na próxima reinicialização."},{"k":"scenario","v":"patch","l":"Patches e versão: estou em uma versão suportada?","m":"Servidor e versão EOL end of life fim do suporte versão minor CVE patch de segurança security release out of support server_version calendário de patches minor update pgsql-announce Verifica a versão, a data de fim do suporte e as atualizações minor pendentes; remete ao guia de patch para aplicá-las. Somente leitura."}]},{"id":"mysql-install","file":"install/guides/mysql-install.json","group":"MySQL","engineId":"mysql","category":"install","title":"Instalação do MySQL em servidor único (pronta para produção)","summary":"Instala do zero, a partir do repositório oficial, um único servidor MySQL 8.4 LTS (ou 8.0) pronto para produção: diretórios separados para dados, binlog e logs, my.cnf calculado conforme RAM/CPU/tipo de disco, GTID e per","level":"Iniciante","duration":"30–45 min","topology":"1 servidor","tags":["mysql","instalação","instalar","8.4","lts","innodb","my.cnf","tuning","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":"Replicação GTID do MySQL (async / semi-sync)","summary":"Monta, a partir de servidores MySQL já instalados, uma replicação baseada em GTID com 1 source + N replicas: usuário de replicação, transferência dos dados existentes com o clone plugin ou mysqldump, SOURCE_AUTO_POSITION","level":"Intermediário","duration":"45–90 min","topology":"1 source + 1..5 replicas","tags":["mysql","replicação","replication","gtid","semi-sync","semisync","replica","source","clone","failover","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":"Monta um InnoDB Cluster single-primary a partir de 3 (ou 5–9) servidores MySQL já instalados no mesmo data center: dba.configureInstance, createCluster e addInstance com clone pela AdminAPI do MySQL Shell; bootstrap do M","level":"Avançado","duration":"90–120 min","topology":"3–9 nós MySQL + 1 servidor Router","tags":["mysql","innodb cluster","group replication","mysql shell","mysqlsh","adminapi","mysql router","alta disponibilidade","failover","quorum","clone","single-primary"],"order":3,"steps":39,"scenarios":[]},{"id":"mysql-xtrabackup","file":"install/guides/mysql-xtrabackup.json","group":"MySQL","engineId":"mysql","category":"backup","title":"Backup, restore e PITR com Percona XtraBackup","summary":"Backup físico com Percona XtraBackup: instalação da versão compatível do XtraBackup, usuário de backup com auth_socket, script de backup full + incremental com compressão/criptografia, agendamento com systemd timer ou cr","level":"Intermediário","duration":"45–90 min","topology":"1 servidor (standalone, source, replica ou secondary de InnoDB Cluster); área de backup em disco local ou NFS","tags":["mysql","xtrabackup","percona","backup","backup","restore","incremental","pitr","binlog","recuperação","zstd","criptografia","replica","slave-info","safe-slave-backup","innodb cluster","cron","systemd timer","flock"],"order":4,"steps":26,"scenarios":[{"k":"scenario","v":"setup","l":"Configurar o backup, agendar e testar o restore (fluxo completo)","m":"Instalação e ensaio instalação xtrabackup script de backup backup script systemd timer cron ensaio de restore backup xtrabackup backup físico physical backup hot backup incremental backup full backup percona-xtrabackup Instalação do XtraBackup, usuário de backup, script de backup full + incremental, agendamento e um ensaio de restore (incluindo PITR). Escolha esta opção se estiver configurando pel"},{"k":"scenario","v":"r_full","l":"Restore completo: voltar ao último backup full","m":"Restore restore restaurar copy-back datadir perdido InnoDB: corruption MY-011971 MY-012592 Database page corruption mysqld não inicia full restore ERROR 2002 Can't connect to local MySQL server through socket MY-012574 Unable to lock ./ibdata1 datadir apagado falha de disco disk failure perda de dados O diretório de dados foi perdido/corrompido ou o servidor não inicia; basta voltar ao backup full"},{"k":"scenario","v":"r_inc","l":"Restore com a cadeia full + incremental (até o último incremental)","m":"Restore incremental restore apply-log-only incremental-dir to_lsn from_lsn This incremental backup seems not to be proper for the target cadeia incremental incremental chain xtrabackup_checkpoints applying incremental Você quer voltar ao momento do último backup incremental (ou de um incremental escolhido); os incrementais são aplicados em ordem sobre o full com `--apply-log-only`. O MySQL fica pa"},{"k":"scenario","v":"r_pitr","l":"Recuperar para um ponto no tempo (PITR): antes de um DELETE / DROP errado","m":"Ponto no tempo PITR point in time apagado por engano DROP TABLE DELETE errado TRUNCATE mysqlbinlog stop-datetime stop-position exclude-gtids binlog replay UPDATE errado DELETE sem WHERE accidental delete accidental drop DROP DATABASE desfazer undo delete recuperação com binlog Dados apagados ou corrompidos por engano: o último backup é restaurado e os binlogs são aplicados até imediatamente antes "},{"k":"scenario","v":"r_table","l":"Restaurar uma única tabela (--export + IMPORT TABLESPACE)","m":"Ponto no tempo tabela única 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 restaurar uma tabela table restore arquivo ibd Você precisa apenas da versão de uma tabela que está no backup; sem restaurar o servidor inteiro, a tabela é"},{"k":"scenario","v":"r_replica","l":"Criar uma nova replica a partir de backup","m":"Migração e clone nova replica criar replica xtrabackup_binlog_info xtrabackup_slave_info gtid_purged slave-info replication from backup 1236 criar replica a partir de backup seed replica Could not find first log file name in binary log index file purged required binary logs 1236 reconstruir replica Você quer preparar uma replica nova (ou a ser reconstruída) a partir de um backup XtraBackup existen"},{"k":"scenario","v":"r_other","l":"Restaurar o backup em outro servidor (migração, teste, clone)","m":"Migração e clone outro servidor servidor de teste restore test migração migration clone clone to test rsync server_uuid carregar em ambiente de teste verificação de backup restore drill abrir backup migração de servidor Você quer abrir um backup de produção em um servidor de teste/desenvolvimento, migrar um servidor ou verificar em um servidor separado que o backup realmente restaura. O servidor d"}]},{"id":"mysql-upgrade","file":"install/guides/mysql-upgrade.json","group":"MySQL","engineId":"mysql","category":"upgrade","title":"Upgrade do MySQL 8.0 → 8.4 LTS (in-place)","summary":"Faz o upgrade de um MySQL 8.0 instalado para o 8.4 LTS no mesmo servidor (in-place): servidor único, source + réplicas (primeiro as réplicas, por último o source) ou InnoDB Cluster (Router → Shell → metadata → secondarie","level":"Intermediário","duration":"60–120 min (conforme o volume de dados)","topology":"1 servidor, source + réplicas ou InnoDB Cluster (3+ membros + servidores do MySQL Router)","tags":["mysql","upgrade","8.0","8.4","lts","atualização de versão","checkForServerUpgrade","mysql_native_password","authentication_policy","rollback","retorno à versão anterior","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":"Operação diária e cenários de falha da replicação MySQL (8.0 / 8.4)","summary":"Runbook de operação diária e recuperação de falhas para uma topologia source + replica já instalada (async / semi-sync, GTID ou posição do binlog): verificação de saúde e de atraso, switchover planejado, failover, reinte","level":"Avançado","duration":"5 min (verificação) – 2 horas (reconstrução)","topology":"1 source + 1..5 replicas (async / semi-sync)","tags":["mysql","replicação","replication","gtid","errant gtid","errant transaction","switchover","failover","replica","source","super_read_only","semi-sync","show replica status","seconds_behind_source","atraso de replicação","lag","1062","1032","1236","duplicate entry","can't find record","gtid_next","sql_replica_skip_counter","source_delay","replica atrasada","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":"Verificação de status e de atraso (a replicação está saudável?)","m":"Monitoramento e verificação SHOW REPLICA STATUS SHOW SLAVE STATUS Seconds_Behind_Source Seconds_Behind_Master Replica_IO_Running Slave_IO_Running Replica_SQL_Running: No atraso de replicação replication lag replica lag Rpl_semi_sync_source_status 1045 2003 2026 Error connecting to source status da replicação Replica_IO_Running: No Replica_IO_Running: Connecting Slave_IO_Running: No Slave_SQL_Runni"},{"k":"scenario","v":"switchover","l":"Switchover planejado (passar o papel de source para uma replica)","m":"Troca de papel switchover switchover planejado troca de papel role change promote replica trocar source manutenção manutenção planejada graceful takeover graceful-master-takeover substituir source trocar primary change primary novo source O source e as replicas estão saudáveis; você está passando o papel de source para uma replica de forma planejada, para manutenção, troca de hardware ou upgrade. "},{"k":"scenario","v":"failover","l":"Source perdido: failover para a replica mais adiantada","m":"Troca de papel failover source caiu source down master down primary down Error connecting to source Can't connect to MySQL server 2003 2013 Lost connection replica mais adiantada most advanced replica Replica_IO_Running: Connecting Slave_IO_Running: Connecting 2005 Unknown MySQL server host error reconnecting to source source inacessível source desligado primary caiu servidor caiu server crashed O"},{"k":"scenario","v":"rejoin","l":"Reintegrar o source antigo como replica após o failover","m":"Troca de papel source antigo old source old master rejoin reintegrar errant split brain 1236 primary antigo old primary master antigo voltou split-brain Replica has more GTIDs than the source has Slave has more GTIDs than the master has reintegração reintegrate O failover foi feito e o servidor do source antigo voltou. Primeiro ele é fechado para gravação e seus binlogs são copiados; em seguida é "},{"k":"scenario","v":"rebuild","l":"Reconstruir uma replica do zero (clone / XtraBackup / mysqldump)","m":"Recuperação 1236 Cannot replicate because the source purged required binary logs purged required binary logs reconstruir rebuild replica reseed clone instance nova replica divergência de dados 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"},{"k":"scenario","v":"errant","l":"Errant GTID: a replica tem transações que o source não tem","m":"Recuperação errant gtid errant transaction gtid_subtract extra gtid gtid a mais Having extra GTID events incompatible GTID set 1236 GTID_SUBTRACT diferença no gtid_executed gravado na replica write on replica super_read_only desativado Replica has more GTIDs than the source has Há transações gravadas diretamente na replica (com super_read_only desativado) ou herdadas de um source antigo; num failo"},{"k":"scenario","v":"sqlerr","l":"Replicação parada: 1062 Duplicate entry / 1032 Can't find record","m":"Recuperação 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-01"},{"k":"scenario","v":"delayed","l":"Replica atrasada (SOURCE_DELAY): configurar ou recuperar dados apagados","m":"Operação diária SOURCE_DELAY MASTER_DELAY delayed replica replica atrasada apagado por engano DROP TABLE DELETE errado SQL_Delay SQL_BEFORE_GTIDS SQL_Remaining_Delay DELETE acidental DELETE sem WHERE accidental delete accidental drop dropped table tabela apagada recuperação de dados UNTIL SQL_BEFORE_GTIDS Você quer manter uma replica deliberadamente N segundos atrás (definir / remover o atraso) ou"},{"k":"scenario","v":"repoint","l":"Mover uma replica para outro source (encadeamento / reconexão)","m":"Operação diária repoint change source replicação encadeada chained replication intermediate replica intermediária relay replica CHANGE MASTER TO CHANGE REPLICATION SOURCE TO cascading replication replicação em cascata conectar replica a outro source alterar SOURCE_HOST alterar MASTER_HOST log_replica_updates Você quer ligar uma replica abaixo de outra replica (cadeia / replica intermediária) ou de"},{"k":"scenario","v":"binlog","l":"Limpeza e retenção de binlogs (disco enchendo)","m":"Operação diária PURGE BINARY LOGS PURGE MASTER LOGS binlog_expire_logs_seconds expire_logs_days disco cheio de binlog No space left on device errno 28 limpeza de 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 crescendo binlog_expire_logs_auto_purge binlog_transaction_compression Os binlogs estã"}]},{"id":"mysql-ic-ops","file":"install/guides/mysql-ic-ops.json","group":"MySQL","engineId":"mysql","category":"ops","title":"Operação diária e cenários de falha do MySQL InnoDB Cluster (MySQL Shell 8.4)","summary":"Não é instalação: runbook por cenários para a operação diária e a recuperação de falhas de um InnoDB Cluster já em funcionamento (Group Replication + MySQL Router, implantado com a AdminAPI do MySQL Shell). Escolha um ca","level":"Avançado","duration":"5 min (verificação) – 1 hora (inclusão de membro)","topology":"3–9 nós MySQL (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","split brain","expelTimeout","memberWeight","autoRejoinTries","exitStateAction","consistency","clone","MISSING","UNREACHABLE","RECOVERING","ERROR","runbook","8.4"],"order":13,"steps":5,"scenarios":[{"k":"scenario","v":"health","l":"Status e verificação de saúde do cluster (está tudo bem?)","m":"Monitoramento e verificações cluster.status status() OK_PARTIAL OK_NO_TOLERANCE OK_NO_TOLERANCE_PARTIAL instanceErrors replicationLag flow control RECOVERING applier queue status do cluster Cluster is ONLINE and can tolerate can tolerate up to ONE failure verificação de saúde health check fila crescendo replication_group_members group_replication_member_stats estado do cluster Somente leitura: `cl"},{"k":"scenario","v":"add","l":"Adicionar um novo membro (addInstance: clone / incremental)","m":"Membros addInstance adicionar membro adicionar nó 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 aumentar capacidade aumentar tolerância a falhas OK_NO_TOLERANCE Você quer adicionar um novo nó MySQL ao cluster, aumentar a tolerância a falhas (3 → 5) ou trazer de volta um nó q"},{"k":"scenario","v":"remove","l":"Remover um membro (removeInstance, com force se necessário)","m":"Membros removeInstance remover membro remover nó remove instance force MISSING decommission Cluster.removeInstance is not reachable and cannot be safely removed excluir nó reduzir cluster desativação de servidor Você quer remover um nó do cluster de forma permanente (devolução de hardware, redução) ou o nó foi perdido e precisa ser apagado dos metadados (`force`). Remover um secondary não causa do"},{"k":"scenario","v":"rejoin","l":"Reintegrar um membro que caiu (MISSING / ERROR / OFFLINE)","m":"Falha e recuperação rejoinInstance MISSING ERROR OFFLINE UNREACHABLE expelled expulso do grupo 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 membro caiu membro OFFLINE m"},{"k":"scenario","v":"reboot","l":"O cluster inteiro parou: reiniciá-lo (rebootClusterFromCompleteOutage)","m":"Falha e recuperação rebootClusterFromCompleteOutage complete outage interrupção total todos os nós caíram falta de energia 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 metada"},{"k":"scenario","v":"quorum","l":"Perda da maioria (NO_QUORUM): forçar o quorum com os membros restantes","m":"Falha e recuperação NO_QUORUM forceQuorumUsingPartitionOf quorum perda da maioria split-brain split brain UNREACHABLE majority partition 3100 Cluster has no quorum cannot process write transactions split-brain! Instance is not part of the majority group gravações travadas writes hang forceQuorum A maioria dos membros sumiu ao mesmo tempo (ex.: 2 de 3) e os restantes pararam de aceitar gravações co"},{"k":"scenario","v":"switch","l":"Troca planejada de primary (setPrimaryInstance)","m":"Papéis e roteamento setPrimaryInstance trocar primary switchover transferir primary The appointed primary member has a version that is greater group_replication_set_as_primary Cluster.setPrimaryInstance runningTransactionsTimeout troca planejada de primary mover primary planned switchover Você quer passar o papel de primary, de forma planejada, para um secondary específico por manutenção (patch do"},{"k":"scenario","v":"router","l":"Adicionar o Router ou fazer novo bootstrap","m":"Papéis e roteamento 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 não conecta instalação do Router V"},{"k":"scenario","v":"options","l":"Alterar as opções do cluster (consistency, expelTimeout, memberWeight…)","m":"Configuração 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 membro expulso com frequência prioridade de failover Você"},{"k":"scenario","v":"rescan","l":"Sincronizar os metadados com o grupo real (rescan)","m":"Configuração 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 metadados inconsistentes metadados dessincronizados `cluster.status()` menciona um membro que não está nos metadados ou um registro antigo que não está mais no g"}]},{"id":"mysql-logical-backup","file":"install/guides/mysql-logical-backup.json","group":"MySQL","engineId":"mysql","category":"backup","title":"Backup lógico e restauração no MySQL (mysqldump, MySQL Shell)","summary":"Backup e restauração lógicos com mysqldump ou MySQL Shell (util.dumpInstance / dumpSchemas / dumpTables + util.loadDump): uma tabela, um schema ou a instance inteira; somente estrutura ou somente dados; migração para out","level":"Intermediário","duration":"20–90 min (conforme o volume de dados)","topology":"1 servidor (+ um servidor de destino na migração e na restauração da instance)","tags":["mysql","mysqldump","mysql shell","mysqlsh","dumpInstance","dumpSchemas","dumpTables","loadDump","backup lógico","logical backup","export","import","restauração","restore","migração","migration","login-path","mysql_config_editor","systemd timer","cron","backup","replica","dump-replica","source-data","innodb cluster","cron","systemd timer","flock","login-path"],"order":15,"steps":8,"scenarios":[{"k":"mode","v":"table","l":"Export / import de tabela(s)","m":"Backup e restauração backup de tabela table export copiar tabela copy table mysqldump tabela Fazer backup de uma ou mais tabelas, copiá-las para outro schema/servidor ou restaurá-las. A origem continua no ar; não são obtidos locks em tabelas InnoDB."},{"k":"mode","v":"schema","l":"Fazer backup / restaurar um schema (banco de dados)","m":"Backup e restauração backup de schema backup de banco de dados database backup dumpSchemas mysqldump database Fazer backup de um banco de dados (schema) inteiro ou carregá-lo em outro schema/servidor. A origem continua no ar; no destino, as tabelas com o mesmo nome são removidas e recriadas."},{"k":"mode","v":"instance","l":"Instance inteira (usuários + todos os schemas)","m":"Backup e restauração todos os bancos de dados all databases dumpInstance migrar usuários full logical backup O backup é feito neste servidor e a restauração é feita em um servidor vazio: usuários, privilégios e todos os schemas. Para reconstruir um servidor ou mudar de versão/plataforma."},{"k":"mode","v":"ddl","l":"Somente estrutura (DDL)","m":"Estrutura e dados separados somente estrutura schema only no-data ddlOnly CREATE TABLE export Definições de tabelas, views, triggers, procedures e events; sem dados. Para comparar schemas, montar um ambiente vazio ou colocar a estrutura sob controle de versão."},{"k":"mode","v":"data","l":"Somente dados","m":"Estrutura e dados separados somente dados data only no-create-info dataOnly transferência de dados Somente as linhas são transferidas, com a estrutura já pronta no destino (ex.: atualizar dados de teste). Triggers no destino podem disparar durante a carga; o guia verifica isso."},{"k":"mode","v":"migrate","l":"Migração para outro servidor","m":"Migração migração migration troca de servidor migrar para novo servidor 8.0 to 8.4 migration dump and load migrar para HeatWave O trabalho é feito no servidor de destino; a conexão com a origem é feita pela rede, com login-path. No momento do corte, a aplicação para de gravar; a indisponibilidade dura o tempo do dump + carga. Para trocar de servidor, sistema operacional ou versão."},{"k":"mode","v":"extract","l":"Extrair uma única tabela de um dump completo","m":"Recuperação restaurar uma tabela extrair tabela do dump extract table from dump desfazer DROP TABLE linhas apagadas ERROR 1146 Table doesn't exist Você tem um dump completo e precisa de apenas uma tabela (linhas apagadas, tabela removida com DROP). Ela é extraída para um schema separado sem mexer no schema original, ou a tabela removida é recolocada."},{"k":"mode","v":"sched","l":"Backup agendado (systemd timer / cron)","m":"Backup agendado backup agendado scheduled backup cron mysqldump systemd timer backup automático backup noturno Backup lógico automático todos os dias em horário definido: usuário de backup separado, login-path, script, systemd timer ou cron, período de retenção e notificação de erro. A origem continua no ar."}]},{"id":"mysql-security","file":"install/guides/mysql-security.json","group":"MySQL","engineId":"mysql","category":"security","title":"Hardening de segurança do MySQL (auditoria de estado, rede, TLS, autenticação, privilégios, audit, criptografia)","summary":"Não é um guia de instalação: encontra e fecha as brechas de um servidor MySQL 8.4 / 8.0 em execução. Primeiro a Auditoria de estado, somente leitura, lista as brechas por ordem de gravidade e indica para qual cartão cada","level":"Intermediário","duration":"5 min (auditoria) – 3 horas (hardening completo)","topology":"Um servidor MySQL + servidor de aplicação (verificação no cliente); replica/InnoDB Cluster nas notas","tags":["mysql","segurança","security","hardening","endurecimento","cis benchmark","tls","ssl","require_secure_transport","verify_identity","caching_sha2_password","mysql_native_password","validate_password","audit_log","audit","percona","tde","keyring","innodb encryption","root","usuário anônimo","privilégio","role","login-path"],"order":40,"steps":2,"scenarios":[{"k":"scenario","v":"scan","l":"Auditoria de estado: quais são minhas brechas? (somente leitura)","m":"Início auditoria de segurança security audit hardening check CIS brecha vulnerabilidade vulnerability achado de pentest mysql_secure_installation consulta de auditoria varredura de segurança security scan CRÍTICO A primeira varredura a executar: contas anônimas/sem senha/root remoto, acesso de qualquer lugar (%), plugin de autenticação fraco, privilégios globais, TLS, audit, criptografia, permissõ"},{"k":"scenario","v":"all","l":"Hardening completo (tudo em sequência)","m":"Início hardening endurecimento segurança completa full hardening aplicar CIS benchmark STIG Servidor recém-instalado ou nunca endurecido: todas as áreas são aplicadas em ordem segura; o MySQL é reiniciado algumas vezes (é necessária janela de manutenção)."},{"k":"scenario","v":"net","l":"Rede e conexão: quem pode se conectar de onde? (bind_address, firewall, restrição de host)","m":"Rede e identidade 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 acesso externo restrição de acesso O MySQL escuta em todas as interfaces, as contas têm host '%', a porta está aberta para todos. Mudar o bind_address exige reinicialização."},{"k":"scenario","v":"tls","l":"Criptografar a conexão (TLS, require_secure_transport, VERIFY_IDENTITY)","m":"Rede e identidade ssl tls require_secure_transport ssl-mode VERIFY_IDENTITY VERIFY_CA ERROR 3159 Connections using insecure transport are prohibited server-cert.pem validade do certificado ERROR 2026 SSL connection error certificate verify failed ERROR 3888 cadeia de certificados certificate chain Está em uso o certificado autoassinado gerado automaticamente, conexões sem criptografia são aceitas "},{"k":"scenario","v":"auth","l":"Autenticação e senha (caching_sha2, política de senhas, root)","m":"Rede e identidade mysql_native_password caching_sha2_password validate_password password_history FAILED_LOGIN_ATTEMPTS root remoto anonymous user usuário anônimo 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 Contas mysql_native_password, sem polític"},{"k":"scenario","v":"priv","l":"Privilégio mínimo: roles e conta de aplicação sem DDL","m":"Privilégios e rastreio GRANT REVOKE ALL PRIVILEGES SUPER FILE least privilege privilégio mínimo CREATE ROLE ERROR 1142 command denied ERROR 3530 ERROR 1227 you need (at least one of) the SUPER privilege DEFAULT ROLE relatório de privilégios Privilégios CREATE/ALTER/DROP ou *.* na conta da aplicação, contas com FILE/SUPER; roles de leitura/escrita/DDL e relatório de privilégios. Sem interrupção."},{"k":"scenario","v":"audit","l":"Audit: quem fez o quê?","m":"Privilégios e rastreio audit audit_log audit_log_filter trilha de auditoria general_log Enterprise Audit Percona audit SIEM LGPD PCI audit_log_filter_set_filter ERROR 1126 licença MySQL Enterprise quem fez o quê O auditor pede registro de sessões e consultas. O MySQL Community não tem audit embutido: Enterprise Audit, Audit Log Filter do Percona Server ou opções limitadas para o Community. **Licen"},{"k":"scenario","v":"tde","l":"Criptografar os dados em disco (InnoDB tablespace encryption, keyring)","m":"Dados e backup 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 master key Criptografia de tabelas, redo, undo e binlog contra roubo do disco ou de uma cópia de backup; uma reinicialização para instalar o keyring comp"},{"k":"scenario","v":"backup","l":"Segurança dos backups (backup criptografado, login-path, permissões)","m":"Dados e backup criptografia de backup backup encryption mysqldump gpg xtrabackup --encrypt login-path mysql_config_editor senha no .my.cnf xbcrypt --encrypt-key-file backup sem criptografia unencrypted backup Backups sem criptografia ou em diretório legível por todos, senha em texto puro no script; mysqldump + GPG ou XtraBackup --encrypt, conta de backup e login-path."},{"k":"scenario","v":"os","l":"Lado do sistema operacional (conta de serviço, permissões, core dump, SELinux)","m":"Servidor e versão SELinux permissive secure_file_priv local_infile core dump conta mysql .mysql_history ERROR 1290 secure-file-priv option ERROR 3948 Loading local data is disabled avc: denied Diretório de dados ou arquivos de certificado acessíveis a outros, secure_file_priv vazio, local_infile ativado, SELinux desativado. Algumas configurações valem após a reinicialização."},{"k":"scenario","v":"patch","l":"Patch e versão: estou em uma versão suportada?","m":"Servidor e versão EOL end of life fim do suporte MySQL 8.0 EOL CPU Critical Patch Update CVE patch de segurança calendário de patches MySQL 8.0 end of life 8.4 LTS Versão, fim do suporte (o 8.0 terminou em abril de 2026) e atualizações pendentes; para aplicar, leva ao guia de upgrade. Somente leitura."}]},{"id":"mssql-linux-install","file":"install/guides/mssql-linux-install.json","group":"SQL Server","engineId":"mssql","category":"install","title":"Instalação do SQL Server no Linux (RHEL / Ubuntu, pronta para produção)","summary":"Instala o SQL Server 2022 ou 2025 a partir do repositório da Microsoft em um único servidor Linux (família RHEL ou Ubuntu): escolha da edição, definição segura da senha do sa, mssql-tools18 (sqlcmd/bcp), diretórios separ","level":"Iniciante","duration":"40–60 min","topology":"1 servidor","tags":["sql server","mssql","linux","instalação","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":"Instalação do SQL Server 2022 no Windows (unattended, pronta para produção)","summary":"Instala o SQL Server 2022 em um único Windows Server de forma silenciosa (unattended) com ConfigurationFile.ini: um INI gerado a partir das suas escolhas (recursos, instância, contas de serviço/gMSA, collation, diretório","level":"Intermediário","duration":"45–75 min","topology":"1 Windows Server","tags":["sql server","mssql","windows","instalação","install","unattended","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 Availability Group (Windows, WSFC)","summary":"Cria um Always On Availability Group em servidores Windows com SQL Server 2022 instalado: Windows Server Failover Cluster (WSFC) e testemunha de quorum (file share / cloud witness), habilitação do Always On, endpoints de","level":"Avançado","duration":"90–150 min","topology":"2–9 nodes Windows (WSFC) + testemunha (witness)","tags":["sql server","mssql","always on","grupo de disponibilidade","ag","wsfc","cluster de failover","listener","testemunha","automatic seeding","hadr","windows","alta disponibilidade"],"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 Availability Group (Linux, Pacemaker)","summary":"Monta um Always On AG gerenciado pelo Pacemaker a partir de três servidores Linux (RHEL 9 ou Ubuntu 22.04) com SQL Server 2022 instalado: mssql-server-ha, hadr.hadrenabled, endpoints de espelhamento autenticados por cert","level":"Avançado","duration":"120–180 min","topology":"3 nodes Linux: 3 réplicas síncronas ou 2 síncronas + uma réplica configuration-only","tags":["sql server","mssql","always on","grupo de disponibilidade","ag","linux","pacemaker","corosync","pcs","stonith","fencing","mssql-server-ha","ocf:mssql:ag","cluster_type external","configuration only","listener","ip virtual","rhel","ubuntu","alta disponibilidade"],"order":4,"steps":30,"scenarios":[]},{"id":"mssql-cu-patch","file":"install/guides/mssql-cu-patch.json","group":"SQL Server","engineId":"mssql","category":"patch","title":"Aplicar um Cumulative Update (CU) do SQL Server","summary":"Aplica um Cumulative Update (CU) dentro da mesma versão principal a uma instância SQL Server 2022/2025 já instalada: com dnf/apt no Linux e, no Windows, como instalação silenciosa (/quiet) com o arquivo de instalação do ","level":"Intermediário","duration":"30–90 min","topology":"1 servidor ou um AG (2+ réplicas)","tags":["sql server","mssql","cu","cumulative update","patch","atualização","rolling","availability group","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":"Operação do SQL Server Always On AG (Windows e Linux)","summary":"Não é uma instalação: operação diária e cenários de falha de um Always On Availability Group já instalado: verificação de saúde, diagnóstico de atraso e crescimento do log, failover planejado, failover forçado (FORCE_FAI","level":"Avançado","duration":"15–90 min (conforme o cenário)","topology":"AG com 2–9 réplicas (Windows WSFC ou 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":"Verificação de saúde do AG (consultas do dashboard)","m":"Monitoramento e diagnóstico NOT SYNCHRONIZING NOT_HEALTHY DISCONNECTED RESOLVING PARTIALLY_HEALTHY saúde do AG availability group health sys.dm_hadr dashboard estado da réplica Msg 35206 connection timeout AG dashboard Show Dashboard Está tudo certo? Estado das réplicas / bancos de dados, prontidão para failover, o cluster e as últimas mudanças de papel. Não altera nada."},{"k":"op","v":"lag","l":"Secondary ficando para trás / arquivo de log crescendo (diagnóstico de atraso)","m":"Monitoramento e diagnóstico 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 atraso redo blocked log crescendo A fila de send/redo está crescendo, os dados no secondary estão desatualizados, o log no primary está prestes a encher (log_reuse_wait = AVAILABILITY_REPLICA) ou os commits estão lentos"},{"k":"op","v":"failover","l":"Failover planejado (switchover, sem perda de dados)","m":"Mudança de papel planned failover manual failover switchover ALTER AVAILABILITY GROUP FAILOVER pcs resource move Msg 41142 41142 Msg 19407 trocar papel mover primary Failover Cluster Manager Move failover de manutenção Move o primary para um secondary síncrono e SYNCHRONIZED para manutenção, patch ou teste; alguns segundos de indisponibilidade, sem perda de dados."},{"k":"op","v":"forced","l":"Primary perdido: failover forçado (FORCE_FAILOVER_ALLOW_DATA_LOSS)","m":"Mudança de papel FORCE_FAILOVER_ALLOW_DATA_LOSS forced failover failover forçado quorum lost perda de quorum FixQuorum forcequorum disaster recovery DR Msg 41131 Msg 35250 perda de site primary down Msg 47104 ForceQuorum Cluster is running in ForceQuorum state RESOLVING_NORMAL primary caiu perda de dados O primary (ou todo o site / o quorum do cluster) foi perdido e não é possível esperar: um seco"},{"k":"op","v":"suspend","l":"Suspender / retomar a movimentação de dados (SUSPEND / RESUME)","m":"Manutenção SUSPENDED SET HADR SUSPEND SET HADR RESUME is_suspended suspend_reason data movement movimentação de dados suspensa Msg 35264 35264 Msg 35265 SUSPEND_FROM_REDO SUSPEND_FROM_USER SUSPEND_FROM_PARTNER suspenso suspender banco de dados Interromper temporariamente o envio de dados para um secondary (manutenção de rede, operação em lote) ou retomar um banco de dados que ficou suspenso (SUSPE"},{"k":"op","v":"mode","l":"Alterar o modo síncrono / assíncrono","m":"Manutenção SYNCHRONOUS_COMMIT ASYNCHRONOUS_COMMIT availability mode REQUIRED_SYNCHRONIZED_SECONDARIES_TO_COMMIT required_synchronized_secondaries_to_commit síncrono assíncrono Msg 35211 35211 Msg 35212 35212 FAILOVER_MODE Mudar uma réplica entre SYNCHRONOUS_COMMIT ↔ ASYNCHRONOUS_COMMIT (site remoto, rede lenta, teste de DR) e configurar a proteção de commit (REQUIRED_SYNCHRONIZED_SECONDARIES_TO_CO"},{"k":"op","v":"adddb","l":"Adicionar um banco de dados ao AG (automatic seeding ou backup/restore)","m":"Alteração ADD DATABASE automatic seeding SET HADR AVAILABILITY GROUP Msg 35250 Msg 1478 1478 seeding failed adicionar banco de dados Msg 1475 1475 might contain bulk logged changes manual seeding Colocar um banco de dados novo ou existente no AG: automatic seeding para bancos pequenos/médios, a partir de backup para bancos grandes ou em rede lenta."},{"k":"op","v":"addrep","l":"Adicionar uma réplica (node)","m":"Alteração ADD REPLICA Add-ClusterNode pcs cluster node add nova réplica adicionar réplica Msg 41158 41158 Failed to join local availability replica JOIN Adicionar um novo secondary ao AG: o node entra no cluster, o endpoint é preparado, ADD REPLICA + JOIN, e os bancos de dados chegam por seeding."},{"k":"op","v":"removerep","l":"Remover uma réplica (node)","m":"Alteração REMOVE REPLICA Remove-ClusterNode pcs cluster node remove remover réplica decommission Msg 35223 35223 remover node Remover do AG e do cluster um secondary que será desativado definitivamente ou reinstalado."},{"k":"op","v":"routing","l":"Roteamento de leitura (read-only routing)","m":"Conectividade read-only routing READ_ONLY_ROUTING_URL READ_ONLY_ROUTING_LIST ApplicationIntent=ReadOnly readable secondary secondary legível Msg 978 978 Msg 976 976 not accessible for queries Msg 10786 ApplicationIntent Direcionar as conexões ApplicationIntent=ReadOnly, pelo listener, para secondaries legíveis (tirar a carga de relatórios do primary)."},{"k":"op","v":"listener","l":"Criar ou alterar o listener (IP, porta)","m":"Conectividade listener ADD LISTENER MODIFY LISTENER MultiSubnetFailover RegisterAllProvidersIP Msg 19471 19471 Msg 41009 virtualip Msg 19456 19456 HostRecordTTL porta do listener registro DNS Criar o listener se não existir, alterar a porta dele ou (Windows) adicionar um IP para uma segunda sub-rede."}]},{"id":"mssql-backup","file":"install/guides/mssql-backup.json","group":"SQL Server","engineId":"mssql","category":"backup","title":"Estratégia de backup, automação e restore no SQL Server","summary":"Configura os backups de uma instância do SQL Server já instalada (Linux ou Windows; instância única, FCI ou réplicas de AG) e faz a recuperação a partir do backup. Backup: escolha do recovery model, full semanal + differ","level":"Intermediário","duration":"30–90 min","topology":"1 servidor, Failover Cluster Instance ou réplicas de Always On AG (restore em outro servidor: origem + destino)","tags":["sql server","mssql","backup","cópia de segurança","backup do banco","restore","restauração","pitr","stopat","point in time","differential","transaction log","copy_only","compression","checksum","encryption","criptografia","sql server agent","job","ola hallengren","maintenance solution","retenção","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","restore do master","single user","restore do msdb","restore do model","stopatmark","tail-log","no_truncate","recovery_pending","suspect","cadeia de log","lsn"],"order":15,"steps":11,"scenarios":[{"k":"mode","v":"strategy","l":"Montar a estratégia de backup (backups agendados + retenção)","m":"Backup plano de backup backup strategy arquivo de log crescendo LOG_BACKUP Msg 9002 transaction log is full sql agent job Msg 3013 3013 BACKUP DATABASE is terminating abnormally backup não está rodando job de backup Servidor novo ou banco de dados sem backup regular: configuram-se os jobs de full / differential / log, a retenção e o monitoramento."},{"k":"mode","v":"oneoff","l":"Fazer um backup avulso (ex.: COPY_ONLY antes de uma mudança)","m":"Backup copy_only backup avulso backup antes da mudança backup manual Msg 4214 4214 Msg 4208 4208 BACKUP LOG is not allowed while the recovery model is SIMPLE Um único backup antes de uma mudança, patch ou upgrade, ou para copiar para um ambiente de teste; COPY_ONLY não quebra a cadeia."},{"k":"mode","v":"verify","l":"Verificar os backups (histórico, VERIFYONLY, restore de teste)","m":"Ensaio e verificação VERIFYONLY HEADERONLY FILELISTONLY restore de teste backup corrompido Msg 3241 Msg 3183 Msg 3203 Para provar que os backups realmente podem ser restaurados: histórico de backup, VERIFYONLY, HEADERONLY / FILELISTONLY e restore de teste em um banco temporário + CHECKDB."},{"k":"mode","v":"chain","l":"A cadeia de backup está íntegra? (lacuna de LSN, arquivo ausente)","m":"Ensaio e verificação Msg 4305 4305 too recent to apply LSN cadeia de log cadeia quebrada broken log chain Msg 3136 last_log_backup_lsn cadeia de backup Antes de um restore ou em auditoria periódica: monta a cadeia a partir do histórico do msdb; encontra lacunas de LSN, arquivos que não estão no disco e backups intercalados. Não altera nada."},{"k":"mode","v":"restore","l":"Restaurar o banco de dados a partir do backup (cadeia, STOPAT / STOPATMARK, MOVE / REPLACE, outro servidor)","m":"Restauração e volta no tempo STOPAT STOPATMARK STOPBEFOREMARK point in time PITR apagado por engano desfazer 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 Dados foram apagados ou atualizados por engano, é preciso uma cópia do banco ou ele será mo"},{"k":"mode","v":"damaged","l":"O banco de dados não abre: arquivo de dados ausente ou corrompido (tail-log + restore)","m":"Perda / corrupção 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 apagado arquivo de dados ausente database cannot be opened Msg 823 NO_TRUNCATE CONTINUE_AFTER_ERROR EMERGENCY O banco está em RECOVERY_PENDING ou SUSPECT, o .mdf/.ndf não pode ser lido, mas a instância está no ar: primeiro faz-se o tail-lo"},{"k":"mode","v":"page","l":"Algumas páginas corrompidas (Msg 823 / 824): page restore","m":"Perda / corrupção Msg 824 824 Msg 823 823 Msg 829 829 suspect_pages torn page incorrect checksum página corrompida page corruption page restore CHECKDB found Msg 8928 Msg 8939 Msg 8976 repair_allow_data_loss Consultas ou o CHECKDB dão erro em páginas específicas (msdb.dbo.suspect_pages): apenas as páginas corrompidas são restauradas do backup. No Enterprise/Developer o banco continua aberto; no St"},{"k":"mode","v":"master","l":"Restaurar o banco master (modo de usuário único)","m":"Bancos do sistema master Msg 3108 3108 single user mode single-user modo de usuário único -m Msg 3417 3417 Msg 17113 Msg 18461 master corrompido force-setup REBUILDDATABASE master corrompido ou perda de logins / linked servers / configurações do servidor: a instância é iniciada em modo de usuário único (-m), o master é restaurado e o SQL Server se desliga sozinho. Exige downtime; se a instância nã"},{"k":"mode","v":"sysdb","l":"Restaurar o banco msdb ou model","m":"Bancos do sistema msdb model Msg 3168 3168 jobs sumiram msdb suspect Msg 1807 msdb corrompido model corrompido Jobs, histórico de backup, Database Mail (msdb) ou o modelo para novos bancos (model) corrompidos / perdidos: restaura-se com REPLACE a partir de um backup feito no mesmo build; o Agent para por pouco tempo."},{"k":"mode","v":"orphan","l":"Usuários não conseguem conectar após o restore (orphaned user, mapeamento de logins)","m":"Migração e acesso Msg 18456 18456 Login failed for user orphaned user orphan usuário órfão sp_help_revlogin sp_change_users_login Msg 15023 15023 Msg 916 Msg 4060 mapeamento de login SID O banco foi movido ou restaurado em outro servidor e a aplicação recebe 'Login failed': os logins são transferidos da origem com SID e hash de senha, e os usuários restantes são vinculados aos logins. O banco cont"},{"k":"mode","v":"enc","l":"Backup criptografado não abre (sem certificado, Msg 33111)","m":"Migração e acesso Msg 33111 33111 Cannot find server certificate with thumbprint backup criptografado encrypted backup certificado certificate TDE Msg 15581 15581 master key O backup (ou o backup de um banco com TDE) está criptografado com certificado e o certificado não existe neste servidor: localiza-se o thumbprint, carrega-se o certificado com a private key e verifica-se o backup. Os bancos ex"}]},{"id":"mssql-bcp-export","file":"install/guides/mssql-bcp-export.json","group":"SQL Server","engineId":"mssql","category":"backup","title":"Exportação/importação por tabela no SQL Server (bcp, sqlpackage)","summary":"Não é backup, e sim movimentação lógica de dados: exportar tabelas com o bcp e carregá-las em outro banco de dados (formato nativo ou de caracteres, arquivo de formato, batch, TABLOCK, coluna de identidade, UTF-8), grava","level":"Intermediário","duration":"20–60 min","topology":"1 servidor (os comandos são executados no SQL Server ou em um servidor de gerenciamento)","tags":["sql server","mssql","bcp","bulk copy","exportar","importar","queryout","arquivo de formato","nativo","csv","utf-8","sqlpackage","bacpac","dacpac","extract","publish","azure sql","migração","migration","copiar tabela"],"order":16,"steps":8,"scenarios":[{"k":"op","v":"table","l":"Mover tabelas: bcp out → bcp in","m":"Migração de dados bcp bcp out bcp in bulk copy copiar tabela mover tabela Unexpected EOF encountered in BCP data-file Unable to open BCP host data-file Copiar uma ou várias tabelas para outro banco de dados SQL Server; as tabelas devem existir previamente no destino."},{"k":"op","v":"query","l":"Gravar o resultado de uma consulta em arquivo: bcp queryout (CSV/texto)","m":"Exportação queryout csv exportar csv resultado da consulta em arquivo export to file Gravar o resultado de uma consulta em um arquivo CSV/texto a ser entregue a outro sistema (Excel, ETL, relatório)."},{"k":"op","v":"bacpac","l":"Esquema + dados: sqlpackage Export / Import (.bacpac)","m":"Migração de dados bacpac sqlpackage SqlPackage Export SqlPackage Import migração para Azure SQL Database SQL71564 SQL71501 Mover esquema e dados em um único arquivo; especialmente para migração para o Azure SQL Database ou bancos de dados pequenos/médios."},{"k":"op","v":"dacpac","l":"Somente esquema: sqlpackage Extract / Script / Publish (.dacpac)","m":"Esquema dacpac Extract Publish comparação de esquema schema compare BlockOnPossibleDataLoss The schema update is terminating because data loss might occur Extrair apenas o esquema, compará-lo com o destino e gerar um script de alterações ou implantar o esquema vazio em um novo ambiente."}]},{"id":"mssql-security","file":"install/guides/mssql-security.json","group":"SQL Server","engineId":"mssql","category":"security","title":"Hardening de segurança do SQL Server (Linux e Windows: avaliação, rede, TLS, autenticação, permissões, audit, TDE)","summary":"Não é um guia de instalação: encontra e fecha as brechas de uma instância SQL Server 2019 / 2022 / 2025 em execução (Linux ou Windows). Primeiro a Avaliação de segurança, somente leitura, lista as brechas por gravidade e","level":"Intermediário","duration":"5 min (avaliação) – 3 horas (hardening completo)","topology":"Uma instância SQL Server (Linux ou Windows) + servidor de aplicação; Always On AG nas notas","tags":["sql server","mssql","segurança","security","hardening","endurecimento de segurança","cis benchmark","stig","force encryption","tls","certificado","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":"Avaliação de segurança: quais são minhas brechas? (somente leitura)","m":"Início avaliação de segurança security audit hardening check CIS STIG brecha de segurança vulnerabilidade vulnerability achado de pentest SQL Vulnerability Assessment consulta de avaliação verificação de segurança security scan CRÍTICO A varredura a rodar primeiro: sa, política de senha, senhas vazias, membros de sysadmin, permissões de public/guest, xp_cmdshell, conexões sem criptografia, audit, "},{"k":"scenario","v":"all","l":"Hardening completo (tudo em sequência)","m":"Início hardening endurecimento de segurança segurança completa full hardening aplicar CIS benchmark STIG Instância recém-instalada ou nunca endurecida: todas as áreas são aplicadas em ordem segura; o SQL Server é reiniciado uma ou duas vezes (requer janela de manutenção)."},{"k":"scenario","v":"net","l":"Rede e conexão: quem pode se conectar de onde? (escuta, firewall, Browser)","m":"Rede e identidade 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 acesso externo restringir acesso O SQL Server escuta em todas as interfaces, a 1433 está aberta para todos, o SQL Browser roda sem necessidade. Mudar o endereço de escuta exige"},{"k":"scenario","v":"tls","l":"Criptografar as conexões (Force Encryption, certificado, validação no cliente)","m":"Rede e identidade Force Encryption TrustServerCertificate Encrypt=Mandatory certificate chain was issued by an authority that is not trusted SSL Provider error 0x80090325 tlscert validade do certificado TDS 8.0 strict The target principal name is incorrect certificate verify failed Encrypt=Strict Force Strict Encryption Unable to load user-specified certificate cadeia de certificados certificate c"},{"k":"scenario","v":"auth","l":"Autenticação e senha (sa, CHECK_POLICY, autenticação do Windows)","m":"Rede e identidade sa CHECK_POLICY CHECK_EXPIRATION mixed mode Login failed for user Error 18456 Error 18486 account is locked out política de senha 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 habilitado, sem política de senha nos logins SQL, senhas vazias/fracas; conta pessoal"},{"k":"scenario","v":"priv","l":"Privilégio mínimo e superfície de ataque (roles, public, guest, xp_cmdshell)","m":"Permissões e rastreabilidade db_owner sysadmin public guest xp_cmdshell TRUSTWORTHY CONTROL SERVER least privilege privilégio mínimo Msg 262 Msg 229 permission was denied Msg 15247 Msg 916 db_ddladmin EXECUTE AS relatório de permissões Usuário de aplicação db_owner ou sysadmin, permissões extras em public/guest, xp_cmdshell/TRUSTWORTHY habilitados; desenho de roles e relatório de permissões. Sem d"},{"k":"scenario","v":"audit","l":"Audit: quem fez o quê? (Server Audit, Database Audit Specification)","m":"Permissões e rastreabilidade SQL Server Audit server audit audit specification fn_get_audit_file C2 audit login auditing trilha de auditoria SIEM LGPD PCI sqlaudit Server Audit Specification Database Audit Specification Msg 33072 quem fez o quê O auditor quer o registro de logins, alterações de permissão e de schema; Server Audit em arquivo (ou no log de eventos do Windows), envio a um sistema cen"},{"k":"scenario","v":"tde","l":"Criptografar os dados em disco (TDE)","m":"Dados e backup 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 backup do certificado TDE contra a abertura do disco, do arquivo de dados ou do backup em outro servidor: DMK, certificado, DEK. Feito online; o backup do certificado é O"},{"k":"scenario","v":"backup","l":"Segurança dos backups (backup criptografado, certificado, permissões)","m":"Dados e backup backup encryption criptografia de backup WITH ENCRYPTION BACKUP CERTIFICATE permissões de backup Msg 33111 Msg 15151 RESTORE VERIFYONLY key_algorithm Msg 15240 Backups sem criptografia, diretório de backup aberto a todos, senha em texto puro no script; BACKUP … WITH ENCRYPTION, backup do certificado e permissões do diretório. Sem downtime. A criptografia de backup existe no Standard"},{"k":"scenario","v":"os","l":"Lado do sistema operacional (conta de serviço, permissões de arquivo, SELinux)","m":"Servidor e versão service account conta de serviço do sql server LocalSystem gMSA virtual account icacls SELinux usuário mssql NT Service\\MSSQLSERVER mssql-server-selinux unconfined_service_t Configuration Manager Log On O serviço roda como LocalSystem ou com conta de administrador, os diretórios de dados/backup estão abertos a todos, o SELinux está desativado; trocar a conta de serviço exige rein"},{"k":"scenario","v":"patch","l":"Patch e versão: estou em versão suportada e no último CU?","m":"Servidor e versão CU cumulative update GDR EOL end of support fora de suporte CVE atualização de segurança ProductUpdateLevel ProductUpdateReference Latest updates calendário de patches Versão, nível de CU e fim do suporte (o 2016 terminou em julho de 2026); remete ao guia de CU patch para aplicar. Somente leitura."}]},{"id":"mongo-replset","file":"install/guides/mongo-replset.json","group":"MongoDB","engineId":"mongodb","category":"ha","title":"Instalação de replica set MongoDB (3 membros, keyfile e autorização)","summary":"Monta do zero um replica set MongoDB 8.0 (ou 7.0) de três membros: repositório oficial, diretório de dados em XFS, cache do WiredTiger dimensionado pela RAM, autenticação entre membros com keyfile, autorização, usuários ","level":"Intermediário","duration":"60–90 min","topology":"3 servidores (1 primary + 2 secondaries), número ímpar de membros com dados","tags":["mongodb","mongo","replica set","replset","rs.initiate","keyfile","failover","stepdown","write concern","wiredtiger","alta disponibilidade","ha","rhel","ubuntu"],"order":1,"steps":36,"scenarios":[]},{"id":"mongo-sharded","file":"install/guides/mongo-sharded.json","group":"MongoDB","engineId":"mongodb","category":"ha","title":"Instalação de sharded cluster MongoDB (config servers + shards + mongos)","summary":"Sharded cluster montado quando os dados ou a carga de escrita excedem um único replica set: config server replica set de três membros, dois ou três shard replica sets e dois roteadores mongos; autenticação interna com ke","level":"Avançado","duration":"2–3 horas","topology":"3 config servers + 2×3 membros de shard + 2 mongos (no mínimo 11 servidores; menos para teste)","tags":["mongodb","sharding","sharded cluster","mongos","config server","shard key","addShard","balancer","hashed","escalabilidade","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 e sharded cluster","summary":"Atualiza um replica set ou sharded cluster MongoDB 7.0 em execução para 8.0 sem downtime (rolling): verificações prévias (versão, FCV, estado dos membros, compatibilidade de drivers), backup, primeiro os secondaries, dep","level":"Avançado","duration":"60–120 min (independente do tamanho dos dados; alguns minutos por membro)","topology":"Replica set (3+ membros) ou sharded cluster (config servers + shards + mongos)","tags":["mongodb","upgrade","atualização de versão","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":"Backup e restore do MongoDB (mongodump, mongorestore, snapshot)","summary":"Configura a rotina de backup de um MongoDB já instalado e descreve, cenário por cenário, a recuperação a partir do backup. Backup: mongodump de uma única collection, de um banco de dados ou de todo o deployment (--archiv","level":"Intermediário","duration":"45–90 min","topology":"Servidor de backup ou um membro + replica set / instância única / sharded cluster (mongos)","tags":["mongodb","mongo","backup","backup","restore","restauração","mongodump","mongorestore","oplog","oplogReplay","nsFrom","nsTo","mongoexport","mongoimport","fsyncLock","lvm snapshot","systemd timer","cron","retention","balancer","activeWindow","config server","cron","systemd timer","flock","oplog","cenários de restore","point in time recovery","pitr","oplogLimit","nsInclude","dryRun","sharded restore","clone","collection excluída","excluído por engano"],"order":15,"steps":20,"scenarios":[{"k":"scenario","v":"setup","l":"Configurar o backup: mongodump, agendamento e restore de teste","m":"Backup mongodump configurar backup 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 backup Usuário de backup, arquivo de credenciais, mongodump manual e agendado, restore de teste com renomeação; snapshot e mongoexport opcionais. Se for a primeira configuração, comece por"},{"k":"scenario","v":"r_dry","l":"O backup pode mesmo ser restaurado? (--dryRun e ensaio em instância temporária)","m":"Ensaio e verificação dryRun --dryRun restore test ensaio de restore verificação de backup backup verify gzip: invalid compressed data unexpected EOF archive is corrupt arquivo corrompido gzip -t o backup abre Sem tocar nos dados de produção: integridade do arquivo, namespaces e oplog contidos nele e, opcionalmente, restore completo em um mongod temporário com contagem de documentos."},{"k":"scenario","v":"r_full","l":"Restaurar todos os dados do backup (restore completo, --drop)","m":"Restore full restore restore completo restauração completa --drop mongorestore --drop perda de dados data loss ransomware resgate todos os dados excluídos dropDatabase no oplog file to replay oplogReplay applyOps not authorized … applyOps admin.tempusers Os dados foram perdidos ou corrompidos em grande parte e o deployment voltará ao instante em que o backup foi feito. As gravações posteriores ao "},{"k":"scenario","v":"r_ns","l":"Restaurar um único banco de dados ou collection (--nsInclude, com novo nome ou no lugar)","m":"Restore --nsInclude --nsFrom --nsTo collection única single collection restore collection excluída collection dropped drop collection documentos excluídos deleted documents deleteMany namespace restore E11000 duplicate key error $merge orders_restored restaurar um banco de dados Uma collection/banco de dados foi excluído ou corrompido, o restante está íntegro: só esse namespace vem do backup; os d"},{"k":"scenario","v":"r_pitr","l":"Voltar a um instante específico: backup + oplog (drop acidental, update/delete incorreto)","m":"Retorno no tempo point in time PITR retorno no tempo --oplogReplay --oplogLimit oplog replay oplog.rs excluído por engano accidental drop update incorreto wrong update antes do drop Timestamp oplog sobrescrito rollback to time voltar a um horário específico A operação incorreta ocorreu depois do backup e as gravações até aquele instante também são necessárias: o último backup completo é restaurado"},{"k":"scenario","v":"r_other","l":"Restaurar o backup em outro cluster / servidor (clone, ambiente de teste, migração)","m":"Migração e clone clone clone restore em outro servidor restore to another cluster migration migração ambiente de teste refresh nsExclude admin.system.users Invalid feature compatibility version cannot use --oplogReplay with excludes specified cópia para ambiente de teste O deployment de origem não é tocado: o backup é restaurado em outro replica set ou instância (cópia para teste/relatórios, migra"},{"k":"scenario","v":"r_shard","l":"Restaurar um sharded cluster: limites do mongodump e o método correto","m":"Migração e clone sharded restore sharded cluster restore mongos restore shard key shardCollection config server restore balancer inconsistent backup inconsistente PBM Percona Backup Ops Manager --oplog mode only supported on full dumps backup via mongos A estrutura do backup é um sharded cluster: restore lógico via mongos (recriação das shard keys, balancer) ou reconstrução física de todo o cluste"}]},{"id":"mongo-ops","file":"install/guides/mongo-ops.json","group":"MongoDB","engineId":"mongodb","category":"ops","title":"Operação diária e cenários de falha do MongoDB (replica set e sharded cluster)","summary":"Não é uma instalação: runbook por cenários para administrar no dia a dia um replica set e um sharded cluster MongoDB já instalados e recuperá-los quando quebram. Verificação de saúde, adição/remoção de membros, membro pr","level":"Avançado","duration":"5 min (verificação) – várias horas (initial sync, drain, reshard)","topology":"Replica set (3+ membros) ou sharded cluster (config server + replica sets dos shards + 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","operação","falha"],"order":20,"steps":3,"scenarios":[{"k":"scenario","v":"health","l":"Verificação de saúde: membros, atraso, janela do oplog (no sharded, shards e balancer)","m":"Monitoramento e verificação rs.status rs.status() replication lag atraso replLag printSecondaryReplicationInfo sh.status health saúde NotYetInitialized RECOVERING STARTUP2 UNKNOWN (not reachable/healthy) DOWN ReplicaSetNoPrimary Server selection timed out lastHeartbeatMessage Somente leitura: estados dos membros, atraso de replicação, janela do oplog, configuração; no sharded cluster, lista de sha"},{"k":"scenario","v":"add","l":"Adicionar um novo membro ao replica set (initial sync)","m":"Gerenciamento de membros rs.add adicionar membro add member initial sync novo secondary newlyAdded STARTUP2 scale out rs.add() Quorum check failed Found two member configurations with same host field votes: 0 Um novo servidor foi preparado (mesma versão, keyfile, replSetName); ele é adicionado com priority 0 / votes 0 e recebe voto e priority quando o initial sync termina e ele fica SECONDARY. Sem"},{"k":"scenario","v":"remove","l":"Remover o membro do replica set","m":"Gerenciamento de membros rs.remove remover membro remove member decommission remover servidor REMOVED Our replica set config is invalid or we are not a member of it rs.remove() O servidor está sendo desativado ou foi perdido de forma definitiva: o membro é removido da configuração e verifica-se que os votos restantes ainda formam maioria. Se for o primary, faça stepDown antes."},{"k":"scenario","v":"member_cfg","l":"Alterar o papel do membro: priority, hidden, delayed (com atraso)","m":"Gerenciamento de membros priority hidden delayed secondaryDelaySecs slaveDelay membro oculto membro com atraso votes rs.reconfig priority must be 0 when hidden=true only one voting member can be added or removed at a time rs.reconfig() Alterar a prioridade de um membro para se tornar primary, torná-lo um membro oculto (hidden) para relatórios/backup ou um membro com atraso (delayed) como proteção "},{"k":"scenario","v":"arbiter","l":"Substituir o arbiter por um membro com dados (PSA → PSS)","m":"Gerenciamento de membros arbiter arbiterOnly PSA rs.addArb majority write concern cache pressure w: majority aguardando Rejecting reconfig where the new config has a PSA topology implicit default write concern majority commit point Replica set com primary + secondary + arbiter: quando um membro com dados cai, as escritas majority e a pressão no cache viram problema. Um novo membro com dados é adic"},{"k":"scenario","v":"resync","l":"Ressincronizar um membro atrasado ou corrompido (resync)","m":"Falha e recuperação too stale too stale to catch up RS102 resync ressincronizar initial sync RECOVERING WiredTiger error WT_PANIC arquivo de dados corrompido data corruption OplogStartMissing maintenance mode InitialSyncFailure fassert checksum mismatch O membro está preso em RECOVERING e informa 'too stale to catch up', ou os arquivos de dados estão corrompidos: o diretório de dados do membro é e"},{"k":"scenario","v":"force","l":"Perda da maioria: reconfigurar à força com os membros restantes (force reconfig)","m":"Falha e recuperação force reconfig force: true no primary sem primary perda da maioria majority lost NotWritablePrimary not master no replset config split brain DR site perda de site ReplicaSetNoPrimary Server selection timed out rs.reconfig force A maioria dos membros foi perdida de forma definitiva (perda de site/servidor) e os restantes não conseguem eleger um primary: rs.reconfig(cfg, {force: "},{"k":"scenario","v":"stepdown","l":"Troca planejada do primary (rs.stepDown, tornar um membro específico primary)","m":"Manutenção stepDown rs.stepDown replSetStepDown trocar primary switchover manutenção maintenance rs.freeze No electable secondaries caught up InterruptedDueToReplStateChange PrimarySteppedDown troca de primary Haverá manutenção/patch no servidor primary: o primary se retira e um secondary sincronizado se torna primary. A aplicação pode receber erros de escrita por alguns segundos."},{"k":"scenario","v":"oplog","l":"Alterar o tamanho do oplog (replSetResizeOplog)","m":"Manutenção oplog oplog window janela do oplog replSetResizeOplog oplogSizeMB oplogMinRetentionHours too stale oplog overflow rs.printReplicationInfo getReplicationInfo log length start to end A janela do oplog é curta: os secondaries ficam 'too stale' após manutenção, o backup não consegue capturar o oplog ou ela não basta para recuperação point-in-time. O oplog é aumentado em cada membro, sem dow"},{"k":"scenario","v":"fcv","l":"Verificar e concluir a Feature Compatibility Version (FCV)","m":"Manutenção FCV featureCompatibilityVersion setFeatureCompatibilityVersion Invalid feature compatibility version IncompatibleServerVersion após upgrade UPGRADE PROBLEM requires confirm: true getParameter featureCompatibilityVersion Após o upgrade, a FCV ficou na versão antiga ou há diferença de versão entre os membros: a versão do binário e a FCV de todos os membros são verificadas e a FCV é elevad"},{"k":"scenario","v":"addshard","l":"Adicionar um shard ao cluster (sh.addShard)","m":"Sharded cluster addShard sh.addShard adicionar shard add shard scale out novo shard shardAdded is not running with --shardsvr in use by another shard A capacidade não é suficiente: um novo replica set de shard (shardsvr) foi montado e é adicionado ao cluster; o balancer move os chunks gradualmente."},{"k":"scenario","v":"rmshard","l":"Remover um shard (removeShard: drain e movePrimary)","m":"Sharded cluster removeShard remove shard remover shard drain draining movePrimary dbsToMove jumboChunks moveCollection collectionsToMove ShardNotFound draining started successfully Um shard está sendo desativado: seus chunks são esvaziados para os outros shards (drain), os bancos de dados dos quais ele é o primary shard são movidos (movePrimary) e depois ele é removido do cluster."},{"k":"scenario","v":"balancer","l":"Balancer: janela de horário, parar / iniciar, desativar por collection","m":"Sharded cluster balancer activeWindow stopBalancer startBalancer sh.stopBalancer disableBalancing janela do balancer chunk migration moveChunk isBalancerRunning getBalancerState Balancer timed out As migrações de chunks geram carga no horário de pico, as migrações precisam parar para manutenção/backup ou uma única collection não deve ser balanceada."},{"k":"scenario","v":"chunks","l":"Distribuição desbalanceada ou jumbo chunk (diagnóstico e solução)","m":"Sharded cluster jumbo jumbo chunk chunk too big ChunkTooBig desbalanceado imbalance hot shard balancerCollectionStatus clearJumboFlag moveChunk failed getShardDistribution low cardinality splitFind Cannot split on the boundary jumboChunks Um shard está muito mais cheio que os outros, o balancer não move chunks, há chunks marcados como 'jumbo' ou o moveChunk falha: a distribuição, os jumbo chunks e"},{"k":"scenario","v":"reshard","l":"Alterar a shard key (reshardCollection)","m":"Sharded cluster reshardCollection reshard alterar shard key change shard key refineCollectionShardKey abortReshardCollection commitReshardCollection forceRedistribution ReshardCollectionInProgress ReshardCollectionAborted unshardCollection A shard key atual gera shard quente, jumbo chunks ou consultas scatter-gather: a collection é redistribuída online com a nova shard key (5.0+). No final, as esc"},{"k":"mcfg","v":"priority","l":"Alterar a priority (preferência para se tornar primary)","m":"Altera a prioridade do membro para se tornar primary (ex.: preferir o membro do data center principal, definir 0 para o membro de DR). Pode ocorrer uma eleição; pode haver uma breve interrupção de escrita."},{"k":"mcfg","v":"hidden","l":"Membro oculto (hidden): invisível para a aplicação, para backup/relatórios","m":"O membro fica invisível para as aplicações (nenhuma leitura é direcionada a ele); fica reservado para relatórios, analytics ou backup. Passa a ter priority 0 e não pode se tornar primary."},{"k":"mcfg","v":"delayed","l":"Membro com atraso (delayed): proteção contra exclusões acidentais","m":"O membro aplica o oplog com o atraso definido; dados excluídos por engano permanecem nele durante esse período. Ele passa a ser hidden, priority 0 e votes 0."},{"k":"mcfg","v":"normal","l":"Voltar ao normal (priority 1, visível, sem atraso, com voto)","m":"Desfaz o papel anterior: priority 1, visível, sem atraso, com voto."},{"k":"bal_op","v":"window","l":"Definir uma janela de horário (activeWindow)","m":"As migrações ocorrem apenas em determinados horários (ex.: à noite); sem carga durante o dia."},{"k":"bal_op","v":"unwindow","l":"Remover a janela de horário (funcionar a qualquer hora)","m":"A janela de horário é removida; o balancer migra a qualquer hora quando necessário (ex.: para rebalancear rapidamente após adicionar um novo shard)."},{"k":"bal_op","v":"stop","l":"Parar o balancer (manutenção/backup)","m":"Antes de backup, upgrade ou manutenção: a migração em andamento termina e nenhuma nova começa. Ao terminar o trabalho, inicie-o novamente sem falta."},{"k":"bal_op","v":"start","l":"Iniciar o balancer","m":"Ativa o balancer parado; o balanceamento continua de onde parou."},{"k":"bal_op","v":"coll_off","l":"Desativar o balanceamento de uma única collection","m":"Apenas os chunks de uma collection deixam de ser migrados (posicionamento intencional, collection problemática). As outras continuam sendo balanceadas."},{"k":"bal_op","v":"coll_on","l":"Ativar o balanceamento de uma única collection","m":"Reativa o balanceamento que foi desativado para a collection."}]},{"id":"mongo-security","file":"install/guides/mongo-security.json","group":"MongoDB","engineId":"mongodb","category":"security","title":"Hardening de segurança do MongoDB (autorização, TLS, roles, audit)","summary":"Runbook por cenários para aplicar hardening a um MongoDB em execução (servidor único, replica set ou sharded cluster) sem downtime: auditoria de segurança somente leitura, autorização rolling com keyFile + transitionToAu","level":"Avançado","duration":"10 min (auditoria) – 2 horas (hardening completo)","topology":"Servidor único, replica set com 3+ membros ou sharded cluster","tags":["segurança mongodb","mongodb security","hardening","endurecimento de segurança","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":"Auditoria do estado de segurança (somente leitura)","m":"Auditoria auditoria de segurança security audit security checklist CIS MongoDB hardening endurecimento de segurança Access control is not enabled for the database auth desabilitado bindIp 0.0.0.0 exposed mongodb mongodb exposto na internet ransom ransomware getCmdLineOpts security checklist MongoDB relatório de auditoria Não altera nada. Acesso sem autenticação, endereços em escuta, TLS, mecanismo"},{"k":"op","v":"all","l":"Hardening completo (tudo em ordem)","m":"Auditoria hardening completo full hardening CIS benchmark projeto de segurança achado de pentest achados de auditoria Auditoria → internal auth + authorization (sem downtime com transitionToAuth) → usuários com privilégio mínimo → SCRAM-SHA-256 → bindIp/firewall → TLS (allowTLS → preferTLS → requireTLS) → audit (Enterprise/Percona) → auditoria final. Em replica set é feito de forma rolling; cada p"},{"k":"op","v":"auth","l":"Autorização desabilitada: habilitar authorization (keyFile, sem downtime)","m":"Identidade e acesso Access control is not enabled for the database Read and write access to data and configuration is unrestricted authorization disabled authorization: enabled auth desabilitado no authentication transitionToAuth keyFile internal authentication autenticação entre membros acesso sem autenticação permissions on /etc/mongod.keyfile are too open Authentication failed __system localhos"},{"k":"op","v":"users","l":"Usuários com privilégio mínimo e custom roles (aplicação, backup, monitoramento)","m":"Identidade e acesso least privilege privilégio mínimo custom role createRole usuário root aplicação conecta como root not authorized on Unauthorized command find requires authentication requires authentication readWrite clusterMonitor role backup createUser grantRolesToUser monitor_user backup_user As aplicações se conectam com root ou com uma conta de administrador compartilhada. É criada uma cus"},{"k":"op","v":"scram","l":"Desabilitar SCRAM-SHA-1, somente SCRAM-SHA-256","m":"Identidade e acesso 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 As credenciais de usuários antigos estão armazenadas com SHA-1, ou a auditoria encontrou SCRAM-SHA-1 habilitado. Os usuários são migrados"},{"k":"op","v":"bind","l":"Restringir o acesso de rede (bindIp 0.0.0.0, firewall)","m":"Rede e criptografia bindIp 0.0.0.0 bindIpAll bind_ip_all 0.0.0.0:27017 porta 27017 aberta shodan exposto na internet firewall javascriptEnabled noscripting net.bindIp ufw allow 27017 firewall-cmd 27017 O mongod escuta em todas as interfaces (0.0.0.0, `bindIpAll`) ou a porta está aberta para todos. O bindIp é reduzido a localhost + IP interno do servidor, e o firewall libera apenas os membros e a r"},{"k":"op","v":"tls","l":"Criptografar conexões: TLS (allowTLS → preferTLS → requireTLS)","m":"Rede e criptografia TLS SSL net.tls.mode requireTLS preferTLS allowTLS conexão sem criptografia 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 O tráfego entre "},{"k":"op","v":"auditlog","l":"Habilitar o audit log (Enterprise / Percona)","m":"Rastreabilidade e proteção de dados audit log auditLog registro de auditoria quem apagou who dropped Unrecognized option: auditLog unrecognised option '--auditDestination' LGPD PCI DSS registro de log É preciso registrar quem fez login e quando, as alterações de usuários/roles e as operações de drop. No MongoDB Enterprise e no Percona Server for MongoDB isso é habilitado com `auditLog`; o Communit"},{"k":"op","v":"ear","l":"Encryption at rest (criptografar os dados em disco)","m":"Rastreabilidade e proteção de dados encryption at rest criptografia de disco enableEncryption encryptionKeyFile KMIP Vault LUKS dm-crypt criptografia de dados Unrecognized option: security.enableEncryption Unable to retrieve key Unable to use encryption at rest cryptsetup luksFormat Se o disco ou um backup for roubado, os dados não podem ser lidos. No Enterprise/Percona, a criptografia do WiredTig"}]},{"id":"redis-sentinel","file":"install/guides/redis-sentinel.json","group":"Redis","engineId":"redis","category":"ha","title":"Alta disponibilidade com Redis Sentinel (master + replicas + 3 Sentinels)","summary":"Monta do zero uma instalação de alta disponibilidade com três servidores Redis 7.2 / 8.2 ou Valkey: um master, duas replicas e um Sentinel em cada servidor. maxmemory calculado pela RAM, persistência (RDB/AOF), senha, pa","level":"Intermediário","duration":"45–60 min","topology":"3 servidores: em cada um, Redis (1 master + 2 replicas) e Sentinel","tags":["redis","valkey","sentinel","replica","replicação","failover","quorum","alta disponibilidade","ha","cache","rhel","ubuntu"],"order":1,"steps":27,"scenarios":[]},{"id":"redis-cluster","file":"install/guides/redis-cluster.json","group":"Redis","engineId":"redis","category":"ha","title":"Instalação do Redis Cluster (3 masters + 3 replicas)","summary":"Monta um Redis Cluster do zero (Redis 7.2 / 8.2 ou Valkey): os 16384 hash slots são distribuídos entre três (ou mais) masters, e cada master tem uma replica em outro servidor. A disposição com uma instância por servidor ","level":"Intermediário","duration":"45–60 min","topology":"6 instâncias: 6 servidores × 1 ou 3 servidores × 2","tags":["redis","valkey","cluster","redis cluster","sharding","hash slot","reshard","failover","replica","escalabilidade","rhel","ubuntu"],"order":2,"steps":33,"scenarios":[]},{"id":"redis-backup","file":"install/guides/redis-backup.json","group":"Redis","engineId":"redis","category":"backup","title":"Backup e restore do Redis (RDB, AOF, replica e cluster)","summary":"Configura uma rotina de backup para um Redis ou Valkey já instalado (instância única, master/replica com Sentinel ou Redis Cluster) e descreve como restaurar a partir do backup. Passo a passo: backups RDB (regra save, BG","level":"Intermediário","duration":"30–60 min","topology":"Servidor de instância única, replica ou Redis Cluster (Redis 7.2 / 8.x, Valkey)","tags":["redis","valkey","backup","backup","restore","restauração","rdb","dump.rdb","bgsave","lastsave","aof","appendonly","bgrewriteaof","appendonlydir","redis cluster","systemd timer","cron","retenção","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: operação diária e cenários de falha (Cluster e Sentinel)","summary":"Não é instalação: runbook por cenários para administrar no dia a dia um Redis Cluster já instalado ou uma estrutura master/replica com Sentinel e recuperá-la quando quebrar (Redis 7.2, Redis 8 e Valkey). Cluster: verific","level":"Avançado","duration":"5 min (verificação) – 1 hora (reshard)","topology":"Redis Cluster (3+ masters + replicas) ou Sentinel (1 master + replicas + 3 Sentinels)","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","operação","falha"],"order":20,"steps":3,"scenarios":[{"k":"scenario","v":"c_health","l":"Verificação de saúde do cluster (--cluster check, CLUSTER INFO / NODES)","m":"Redis Cluster: monitoramento 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 saúde do cluster cluster health cluster_state Somente leitura: todos os slots estão cobertos, os "},{"k":"scenario","v":"c_add","l":"Adicionar node ao cluster (master ou replica)","m":"Redis Cluster: gerenciamento de nodes add-node --cluster add-node adicionar node add node scale out --cluster-slave --cluster-replica cluster-master-id novo master nova replica Node is not empty. Either the node already knows other nodes New node added correctly aumentar capacidade A nova instância (cluster-enabled yes, vazia) está pronta: entra no cluster como master e recebe slots, ou vira repli"},{"k":"scenario","v":"c_remove","l":"Remover node do cluster (esvaziar slots + del-node)","m":"Redis Cluster: gerenciamento de nodes del-node --cluster del-node remover node remove node scale in esvaziar slots cluster-weight Node … is not empty is not empty! Reshard data away and try again CLUSTER RESET SOFT aposentar node Um master ou replica vai ser aposentado: os slots do master são movidos para os outros masters e depois o node é removido do cluster. Sem interrupção; durante a migração "},{"k":"scenario","v":"c_reshard","l":"Redistribuir os slots (rebalance / reshard)","m":"Redis Cluster: gerenciamento de nodes rebalance reshard --cluster rebalance --cluster reshard distribuição de slots desbalanceado 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 mover slots Os slots ou a memória estão desbalanceados entre"},{"k":"scenario","v":"c_failover","l":"Failover manual: promover a replica a master (CLUSTER FAILOVER, FORCE, TAKEOVER)","m":"Redis Cluster: falhas e manutenção CLUSTER FAILOVER failover FORCE TAKEOVER manual failover manutenção do master promover replica a master Manual failover timed out ERR Master is down or failed, please use CLUSTER FAILOVER FORCE ERR You should send CLUSTER FAILOVER to a replica trocar master Haverá manutenção no servidor do master (planejada, sem perda de dados), ou o master está inacessível e o f"},{"k":"scenario","v":"c_replace","l":"Substituir master / node com defeito (FORGET, nova replica, --cluster fix)","m":"Redis Cluster: falhas e manutenção CLUSTER FORGET --cluster fix node perdido failed node fail noaddr slots not covered CLUSTERDOWN replace node master com defeito handshake ERR Can't forget my master! CLUSTERDOWN Hash slot not served servidor perdido falha de disco O servidor de um node foi perdido de vez: se a replica dele virou master, o node antigo é esquecido e uma nova replica é adicionada no"},{"k":"scenario","v":"s_health","l":"Estado do Sentinel: master, replicas, Sentinels, quorum","m":"Sentinel SENTINEL MASTERS SENTINEL master get-master-addr-by-name CKQUORUM +sdown +odown -odown +switch-master NOQUORUM NOGOODSLAVE estado do sentinel +tilt -failover-abort-not-elected s_down o_down master_link_status:down sentinel health Somente leitura: o endereço do master visto pelos Sentinels, as replicas, os outros Sentinels, CKQUORUM e os últimos eventos de failover. Em uma estrutura com Se"},{"k":"scenario","v":"s_failover","l":"Failover manual com o Sentinel (SENTINEL FAILOVER)","m":"Sentinel SENTINEL FAILOVER sentinel failover switch-master failover planejado INPROG NOGOODSLAVE -failover-abort-no-good-slave NOGOODSLAVE No suitable replica to promote manutenção do sentinel Haverá manutenção no servidor do master: o Sentinel promove a replica mais adequada a master e redireciona as outras replicas e os clientes para o novo master. Interrupção de 1–2 s; com o master em execução,"},{"k":"scenario","v":"s_replace","l":"Adicionar / remover / substituir node no ambiente Sentinel (SENTINEL RESET)","m":"Sentinel SENTINEL RESET sentinel reset replicaof nova replica novo sentinel adicionar sentinel remover sentinel replica antiga ainda aparece num-other-sentinels known-replica known-sentinel sentinel antigo ainda aparece Uma replica ou um Sentinel foi removido de vez ou adicionado: a nova replica se conecta com REPLICAOF e os registros antigos dos Sentinels são limpos com SENTINEL RESET."},{"k":"scenario","v":"s_quorum","l":"Alterar o quorum e as configurações do Sentinel (SENTINEL SET)","m":"Sentinel SENTINEL SET quorum down-after-milliseconds failover-timeout parallel-syncs CKQUORUM NOQUORUM failover tarde demais failover desnecessário O número de Sentinels mudou ou o failover dispara tarde demais/cedo demais: quorum, down-after-milliseconds, failover-timeout e parallel-syncs são alterados em todos os Sentinels."},{"k":"scenario","v":"memory","l":"Pressão de memória: diagnóstico de uso, fragmentação e eviction","m":"Memória e chaves OOM command not allowed when used memory > 'maxmemory' OOM maxmemory used_memory evicted_keys eviction maxmemory-policy MEMORY DOCTOR mem_fragmentation_ratio fragmentação activedefrag client-output-buffer-limit memória cheia Out of memory: Killed process oom-killer used_memory_rss mem_clients_normal omem used_memory se aproximou de maxmemory, erro 'OOM command not allowed', evicti"},{"k":"scenario","v":"bigkeys","l":"Encontrar chaves grandes e quentes (--bigkeys, --memkeys, --hotkeys)","m":"Memória e chaves --bigkeys --memkeys --hotkeys big key chave grande hot key chave quente MEMORY USAGE UNLINK slowlog latency SCAN HGETALL KEYS * --keystats pico de latência latency spike A memória ou a CPU de um único node está mais alta que a dos outros, há picos de latência, o DEL demora: as maiores chaves e as mais acessadas são encontradas e limpas com segurança (UNLINK)."},{"k":"add_role","v":"master","l":"Master (recebe slots: rebalance após adicionar)","m":"Entra como master vazio e depois recebe slots com rebalance. Aumenta a capacidade; para o novo master também deve ser adicionada uma replica."},{"k":"add_role","v":"replica","l":"Replica (cópia de um master)","m":"Vira cópia de um master: assume se o master cair. Passa pela rede um volume de dados igual à memória do master (sincronização completa)."},{"k":"rs_mode","v":"rebalance","l":"Rebalance: distribuir os slots igualmente entre os masters (incluindo masters vazios)","m":"Todos os masters recebem partes iguais (inclusive o novo master sem slots). Primeiro é mostrada uma simulação. É a operação mais comum depois de adicionar um novo master."},{"k":"rs_mode","v":"move","l":"Reshard: mover um número definido de slots de um master para outro","m":"Um número definido de slots é movido de um master para outro: para aliviar um master quente/grande ou esvaziar um master aos poucos."},{"k":"fo_mode","v":"default","l":"Planejado (padrão): sincroniza com o master e assume, sem perda de dados","m":"O master deve estar em execução."},{"k":"fo_mode","v":"force","l":"FORCE: o master está inacessível, assume sem esperar a sincronização","m":"As últimas escritas do master podem ser perdidas; a maioria dos masters ainda vota."},{"k":"fo_mode","v":"takeover","l":"TAKEOVER: a maioria dos masters também não está disponível, assume sem votação","m":"Último recurso: risco de split brain e de conflito de epoch."},{"k":"srep_op","v":"add_replica","l":"Adicionar nova replica","m":"O Redis do novo servidor se conecta ao master atual; os Sentinels o descobrem sozinhos."},{"k":"srep_op","v":"rm_replica","l":"Remover a replica de vez","m":"A replica é desligada e seu registro é limpo em todos os Sentinels."},{"k":"srep_op","v":"add_sentinel","l":"Adicionar novo Sentinel","m":"Um Sentinel é adicionado no novo servidor (o total de Sentinels deve continuar ímpar: 3 → 5)."},{"k":"srep_op","v":"rm_sentinel","l":"Remover o Sentinel de vez","m":"O Sentinel é desligado e seu registro é limpo nos outros; depois o quorum é revisto."}]},{"id":"redis-security","file":"install/guides/redis-security.json","group":"Redis","engineId":"redis","category":"security","title":"Hardening de segurança do Redis / Valkey (ACL, TLS, comandos perigosos)","summary":"Não é instalação nem operação diária: runbook por cenários para endurecer, sem indisponibilidade, um Redis ou Valkey em execução (servidor único, replica + Sentinel ou Cluster). Auditoria de segurança somente leitura, us","level":"Avançado","duration":"5 min (auditoria) – 90 min (hardening completo)","topology":"Servidor único, master + replica + Sentinel ou Redis Cluster","tags":["segurança redis","redis security","valkey","hardening","endurecimento","ACL","ACL SETUSER","aclfile","requirepass","masterauth","protected-mode","bind","rename-command","enable-protected-configs","TLS","tls-replication","senha do sentinel","CIS"],"order":20,"steps":7,"scenarios":[{"k":"op","v":"audit","l":"Auditoria do estado de segurança (somente leitura)","m":"Auditoria auditoria de segurança redis redis security audit CIS Redis hardening endurecimento redis exposto exposed redis unauthorized redis redis sem senha -NOAUTH crackit redis cryptominer kinsing NOAUTH Authentication required verificação de segurança redis redis pentest Não altera nada. Acesso sem senha, usuário default, endereços em escuta, protected-mode, comandos perigosos, TLS, senha do Se"},{"k":"op","v":"all","l":"Hardening completo (tudo em sequência)","m":"Auditoria hardening completo full hardening projeto de segurança redis achado de pentest Auditoria → usuários ACL (administrador, aplicação, replicação, Sentinel) e desativação do usuário default → bind/protected-mode/firewall → comandos perigosos e protected configs → TLS → permissões de arquivos → auditoria final. Em replica/Sentinel é rolling; passos arriscados pedem confirmação."},{"k":"op","v":"acl","l":"Usuários ACL e desativação do usuário default (Redis 6+)","m":"Identidade e privilégios ACL ACL SETUSER aclfile default user usuário default NOPERM WRONGPASS invalid username-password pair -NOAUTH Authentication required user default on nopass masteruser least privilege menor privilégio 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 senha por usuário ACL SAVE Todos se cone"},{"k":"op","v":"auth","l":"Redis sem senha: requirepass / masterauth (medida rápida)","m":"Identidade e privilégios requirepass masterauth auth-pass redis sem senha 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 definir senha Não há senha nenhuma e não há tempo para migrar para ACL. Uma senha comum a todos os nodes (`requ"},{"k":"op","v":"net","l":"Restringir o acesso de rede (bind 0.0.0.0, protected-mode, firewall)","m":"Rede e criptografia bind 0.0.0.0 protected-mode no DENIED Redis is running in protected mode 0.0.0.0:6379 porta 6379 aberta shodan firewall 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 O Redis escuta em todas as interfaces ou está com `protected-mode no`. O bind é reduzido"},{"k":"op","v":"cmds","l":"Comandos perigosos e abuso de CONFIG (FLUSHALL, CONFIG, DEBUG, MODULE)","m":"Rede e criptografia 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 módulo malicioso abuso de SLAVEOF Contr"},{"k":"op","v":"tls","l":"Criptografar as conexões: TLS (cliente, replicação, Sentinel, cluster bus)","m":"Rede e criptografia TLS SSL tls-port tls-replication tls-cluster tls-auth-clients conexão sem criptografia 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 conexão criptografada encryption in transit O tráfego não é criptografado. A porta TLS é aberta em funcionamento ao lad"},{"k":"op","v":"perms","l":"Permissões de arquivos e usuário de execução","m":"Rastros e arquivos permissão redis.conf world readable chmod dump.rdb appendonly rodando como root running as root permissões de arquivos Permission denied 640 User=redis redis root O redis.conf (contém senhas), o arquivo ACL, os arquivos RDB/AOF e de log podem ser lidos por outros usuários, ou o Redis roda como root. As permissões passam a 640/750 e o dono passa a ser o usuário do serviço."}]},{"id":"es-cluster","file":"install/guides/es-cluster.json","group":"Elasticsearch","engineId":"elasticsearch","category":"install","title":"Instalação de cluster Elasticsearch (3+ nodes, TLS, Kibana)","summary":"Cria do zero um cluster Elasticsearch 8.x / 9.x com 3 ou mais nodes: repositório da Elastic, heap dimensionado conforme a RAM, memory lock, vm.max_map_count, segurança automática no primeiro node (TLS + senha do elastic)","level":"Intermediário","duration":"60–90 min","topology":"3+ nodes Elasticsearch (+ servidor Kibana opcional)","tags":["elasticsearch","elastic","kibana","cluster","cluster elasticsearch","instalação","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":"Rolling upgrade do Elasticsearch (minor 8.x ou 8.19 → 9.x)","summary":"Não é uma instalação: leva um cluster Elasticsearch em execução para uma nova versão sem interrupção, atualizando os nodes um a um (minor dentro da 8.x ou versão principal 8.19 → 9.x). Verificações prévias (versão, saúde","level":"Avançado","duration":"15–30 min por node","topology":"Cluster existente com 3+ nodes (+ Kibana)","tags":["elasticsearch","upgrade","rolling upgrade","minor","major","9.x","8.19","kibana","upgrade assistant","deprecation","snapshot","rollback","rolling upgrade","node roles","master-eligible","deprecation api","versionlock"],"order":2,"steps":34,"scenarios":[{"k":"path","v":"minor","l":"Dentro da mesma versão principal (ex.: 8.18 → 8.19, 9.1 → 9.2)","m":"Dentro da mesma versão principal (8.18 → 8.19, 9.1 → 9.2): o repositório não muda, mas a verificação de deprecation é feita do mesmo jeito. Pular minors intermediárias é suportado."},{"k":"path","v":"major","l":"Versão principal: 8.19.x → 9.x","m":"O cluster de origem deve ter sido atualizado antes para a 8.19.x (último patch). As verificações prévias incluem os passos do Upgrade Assistant / deprecation API e da system feature migration."}]},{"id":"es-snapshot","file":"install/guides/es-snapshot.json","group":"Elasticsearch","engineId":"elasticsearch","category":"backup","title":"Snapshot e restauração no Elasticsearch (repository fs / S3, SLM)","summary":"Configura o esquema de snapshots (backups) de um cluster Elasticsearch 8.x / 9.x já instalado e descreve a recuperação: repository em sistema de arquivos compartilhado (NFS + path.repo) ou S3 (keystore), ativação por rol","level":"Intermediário","duration":"45–90 min","topology":"Cluster Elasticsearch 8.x / 9.x (1–N nodes) + diretório compartilhado (NFS) ou armazenamento de objetos compatível com S3","tags":["elasticsearch","snapshot","restauração","backup","cópia de segurança","restaurar","repository","path.repo","nfs","s3","keystore","slm","snapshot lifecycle","retenção","rename_pattern","feature_states","repository somente leitura","migração","slm","snapshot lifecycle","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":"Operação diária e cenários de falha do Elasticsearch (8.x / 9.x)","summary":"Não é uma instalação: runbook por cenários para administrar no dia a dia um cluster Elasticsearch 8.x / 9.x instalado e recuperá-lo quando quebrar. Saúde e allocation explain, solução de shards não alocados (disco, filte","level":"Avançado","duration":"5 min (verificação) – horas (reindex, esvaziamento de node)","topology":"Cluster Elasticsearch 8.x / 9.x (1–N nodes), com TLS e autenticação ativos","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","operação","falha"],"order":20,"steps":6,"scenarios":[{"k":"scenario","v":"health","l":"Saúde do cluster: status, nodes, shards não alocados, disco","m":"Monitoramento e diagnóstico red yellow _cluster/health _cat/shards UNASSIGNED allocation explain _cluster/allocation/explain status red status yellow saúde do cluster pending tasks master_not_discovered_exception NoNodeAvailableException circuit_breaking_exception heap verificação de saúde do cluster Somente leitura: green/yellow/red, lista de nodes, shards não alocados (UNASSIGNED) e o motivo (al"},{"k":"scenario","v":"unassigned","l":"Resolver shard não alocado (UNASSIGNED) (conforme o explain)","m":"Monitoramento e diagnóstico 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 REPLI"},{"k":"scenario","v":"watermark","l":"Ver / alterar o disk watermark","m":"Disco e bloqueios watermark disk.watermark low disk watermark high disk watermark flood stage disk watermark disco cheio disk full cluster.routing.allocation.disk cluster.routing.allocation.disk.watermark.high disk usage exceeded limite de disco Shards estão sendo movidos ou não são alocados por causa da ocupação do disco; os limites de watermark (low / high / flood_stage) serão alterados de forma"},{"k":"scenario","v":"readonly","l":"Índice ficou somente leitura: remover o bloqueio read_only_allow_delete","m":"Disco e bloqueios 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 somente leitura read-only blocked by: [FORBIDDEN/12/index read-only / allow delete (api)] index read-only escrita recusada As escritas são recusadas com 'FORBIDDEN/12/index r"},{"k":"scenario","v":"add_node","l":"Adicionar node ao cluster (enrollment token)","m":"Gerenciamento de nodes adicionar node 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 aumentar capacidade novo node É preciso mais capacidade: o Elasticsearch foi instalado em um novo servidor, que entra no cluster com enr"},{"k":"scenario","v":"remove_node","l":"Remover node com segurança (exclude, esvaziar, desligar)","m":"Gerenciamento de nodes remover node remove node decommission cluster.routing.allocation.exclude._name exclude voting_config_exclusions relocating esvaziar voting configuration aposentar node troca de servidor Um node vai ser aposentado ou ter o hardware trocado: com allocation exclude os shards são movidos para os outros nodes, confirma-se que ele esvaziou, se for master-eligible recebe voting exc"},{"k":"scenario","v":"reindex","l":"Reindex: novo índice para mudança de mapping/configuração e migração sem interrupção com alias","m":"Gerenciamento de índices _reindex reindex alterar mapping mapper_parsing_exception illegal_argument_exception: mapper alias _aliases migração sem interrupção zero downtime task version_conflict_engine_exception cannot be changed from type mapper [ alterar analyzer O tipo de um campo do mapping, o analyzer ou o número de shards vai mudar: cria-se um novo índice, os dados são copiados com _reindex e"},{"k":"scenario","v":"ilm","l":"Configurar / resolver problemas de index lifecycle (ILM) e rollover","m":"Gerenciamento de índices 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 índice não é apagado índice de log crescendo Índices de log/séries temporais crescem ou não são apagados: configura-se a política ILM (rollove"},{"k":"scenario","v":"resize","l":"Corrigir o número de shards: _shrink (reduzir) / _split (aumentar)","m":"Gerenciamento de índices _shrink _split shrink split número de shards number_of_shards too many shards excesso de shards 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 O número de shards do índice foi mal escolhido: shards muito pequenos (oversharding) são unidos com _shrink, shards muito gr"},{"k":"scenario","v":"snaprestore","l":"Restaurar um único índice de snapshot com novo nome","m":"Gerenciamento de índices snapshot restore _restore restore de um único índice rename_pattern rename_replacement índice apagado deleted index index_not_found_exception cannot restore index because an open index with same name already exists snapshot_missing_exception apagado por engano recuperar índice Um índice foi apagado ou corrompido: do snapshot repository restaura-se apenas esse índice, com n"},{"k":"un_fix","v":"retry","l":"Limite de tentativas excedido: tentar de novo (_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'. Antes, corrige-se o erro real (disco, mapping, memória)."},{"k":"un_fix","v":"replicas","l":"Número de replicas maior que o de nodes: reduzir as replicas","m":"same_shard a copy of this shard is already allocated to this node explain: same_shard (não se coloca cópia no mesmo node); em cluster de um node, replica 0."},{"k":"un_fix","v":"filter","l":"Allocation filtering / exclude está impedindo: remover o filtro","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…]' ou exclude do cluster)."},{"k":"un_fix","v":"disk","l":"Disk watermark está impedindo","m":"disk_threshold the node is above the low watermark the node is above the high watermark explain: disk_threshold decider. Direciona ao cenário de watermark."},{"k":"un_fix","v":"stale","l":"Último recurso: alocar primary a partir da cópia antiga (stale)","m":"no_valid_shard_copy all the copies of its data in the cluster are stale or corrupt allocate_stale_primary A cópia atual da primary foi perdida e só existe uma cópia antiga: as últimas escritas dessa cópia se perdem."},{"k":"un_fix","v":"empty","l":"Último recurso de todos: alocar primary vazia (todos os dados do shard se perdem)","m":"no_valid_shard_copy there are no copies of its data in the cluster allocate_empty_primary Não existe nenhuma cópia; se o índice não puder ser restaurado de snapshot."},{"k":"wm_op","v":"show","l":"Apenas mostrar (uso de disco e limites atuais)","m":"Somente leitura: disco por node e limites em vigor."},{"k":"wm_op","v":"set","l":"Alterar os limites","m":"Elevar os limites temporariamente (ex.: em disco grande, `50gb` de espaço livre em vez de porcentagem). Quando o problema for resolvido, volte ao padrão."},{"k":"wm_op","v":"reset","l":"Voltar ao padrão (85% / 90% / 95%)","m":"Apaga os limites alterados antes e volta ao padrão (85% / 90% / 95%)."},{"k":"ilm_op","v":"setup","l":"Nova política + template + índice inicial (write alias)","m":"São criados a política (rollover + exclusão), o index template e o índice inicial (`-000001`, alias de escrita). Para um novo fluxo de logs."},{"k":"ilm_op","v":"debug","l":"Por que os índices existentes não avançam? (explain, retry)","m":"Os índices não fazem rollover ou não são apagados: `_ilm/explain` mostra o passo com erro; corrigido o motivo, faz-se retry."},{"k":"ilm_op","v":"rollover","l":"Fazer rollover manual","m":"Um novo índice de escrita é aberto sem esperar a condição (após mudança de mapping ou para um índice inchado)."},{"k":"rs_kind","v":"shrink","l":"_shrink: reduzir o número de shards (o destino deve ser divisor do atual)","m":""},{"k":"rs_kind","v":"split","l":"_split: aumentar o número de shards (o destino deve ser múltiplo do atual)","m":""}]},{"id":"es-security","file":"install/guides/es-security.json","group":"Elasticsearch","engineId":"elasticsearch","category":"security","title":"Hardening de segurança do Elasticsearch (security, TLS, roles, audit)","summary":"Não é um guia de instalação nem de operação diária: é um runbook por cenários para fazer o hardening de um cluster Elasticsearch em execução. Auditoria de segurança somente leitura, habilitação da security desativada jun","level":"Avançado","duration":"10 min (auditoria) – 2 horas (hardening completo)","topology":"Cluster Elasticsearch com 1–12 nodes (+ Kibana)","tags":["elasticsearch segurança","elasticsearch security","hardening","endurecimento de segurança","xpack.security","TLS","elasticsearch-certutil","elasticsearch-users","API key","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":"Auditoria do estado de segurança (somente leitura)","m":"Auditoria auditoria de segurança elasticsearch elasticsearch security audit CIS Elasticsearch hardening endurecimento de segurança elasticsearch exposto exposed elasticsearch xpack.security.enabled missing authentication credentials for REST request security_exception verificação de segurança elasticsearch elasticsearch pentest RISCO Não altera nada. Se a security está habilitada, acesso sem auten"},{"k":"op","v":"all","l":"Hardening completo (tudo em sequência)","m":"Auditoria hardening completo full hardening projeto de segurança elastic achado de pentest Auditoria → security + TLS de transport/HTTP (se desativada; restart completo do cluster) → usuários/roles/API keys, desativação do anonymous, retirada do elastic do uso diário → rede e filtragem de IP → audit logging (se a licença permitir) → acesso ao repositório de snapshot → conexão do Kibana → auditoria"},{"k":"op","v":"enable","l":"Security desativada: habilitar a security e o TLS de transport","m":"Identidade e criptografia xpack.security.enabled: false security disabled acesso sem autenticação Elasticsearch built-in security features are not enabled Transport SSL must be enabled if security is enabled invalid configuration for xpack.security.transport.ssl upgrade 7.x segurança Security is disabled xpack.security.transport.ssl sem autenticação Cluster com `xpack.security.enabled: false`, ou "},{"k":"op","v":"httptls","l":"Migrar o tráfego HTTP (REST) para TLS","m":"Identidade e criptografia 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 senha em texto claro na rede A security está habilitada, mas a porta 9200 usa HTTP sem criptografia: as senhas podem ser lidas na rede. Os certificados HTTP "},{"k":"op","v":"users","l":"Usuários, roles, API keys; acesso do elastic e anonymous","m":"Identidade e criptografia usuário elastic elastic superuser superuser role mapping API key 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 expiração de api key api key sem expiração break-glass As aplicações se cone"},{"k":"op","v":"auditlog","l":"Habilitar o audit logging","m":"Rastros e acesso audit log xpack.security.audit.enabled audit logging _audit.json trilha de auditoria quem apagou LGPD PCI DSS xpack.security.audit.logfile.events.include log de acesso Quem acessou qual índice, tentativas de login malsucedidas, negações de autorização e alterações de configurações de segurança precisam ser registradas. `xpack.security.audit.enabled` (estático, restart rolling) — e"},{"k":"op","v":"net","l":"Acesso de rede e filtragem de IP","m":"Rastros e acesso network.host 0.0.0.0 0.0.0.0:9200 porta 9200 aberta 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 público 9200/9300 escutam em todas as interfaces ou estão abertas para qualquer um. O `network.host` é restrito ao IP interno e, com o firewall e a filtragem de IP do Elasticsearch, apenas os nodes,"},{"k":"op","v":"snapshot","l":"Proteger o acesso ao repositório de snapshot","m":"Rastros e acesso snapshot repo path.repo repository_exception s3.client access_key readonly repository segurança de snapshot snapshot_operator Object Lock segurança de backup O diretório de snapshot pode ser lido por todos, o privilégio de gerenciar o repositório é amplo ou as chaves de acesso à nuvem estão no elasticsearch.yml. Permissões do diretório, role de operador de snapshot, keystore e reg"},{"k":"op","v":"kibana","l":"Proteger a conexão do Kibana","m":"Rastros e acesso kibana_system elasticsearch.username: elastic kibana.yml senha 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 O Kibana se conecta com o usuário `elastic` ou sem criptogr"}]},{"id":"mon-prometheus-grafana","file":"install/guides/mon-prometheus-grafana.json","group":"Monitoramento","engineId":null,"category":"monitoring","title":"Monitoramento de bancos de dados com Prometheus + Grafana","summary":"Instala um servidor de monitoramento central (Prometheus, Alertmanager, Grafana) e adiciona aos servidores monitorados o node_exporter e os exporters de banco que você selecionar: PostgreSQL, MySQL, Oracle, SQL Server, M","level":"Intermediário","duration":"60–120 min","topology":"1 servidor de monitoramento + servidores monitorados","tags":["prometheus","grafana","alertmanager","node_exporter","postgres_exporter","mysqld_exporter","oracledb_exporter","sql_exporter","mongodb_exporter","redis_exporter","elasticsearch_exporter","monitoramento de banco de dados","monitoring","alerta","dashboard"],"order":1,"steps":44,"scenarios":[]},{"id":"ora19-install","file":"install/guides/ora19-install.json","group":"Oracle","engineId":"oracle","category":"install","title":"Instalação do Oracle Database 19c single instance (EE / SE2)","summary":"Instala do zero o Oracle Database 19c em um único servidor, sobre Oracle Linux / RHEL 7.9, 8 ou 9: preparação do sistema operacional (preinstall RPM ou manual), diretórios OFA, instalação silenciosa (silent) do software ","level":"Intermediário","duration":"90–150 min","topology":"1 servidor","tags":["oracle","19c","instalação","install","runInstaller","dbca","netca","silent","release update","applyRU","opatch","cdb","pdb","hugepages","rman","oracle linux","rhel","asm","ol7","multipath","oracle restart"],"order":1,"steps":38,"scenarios":[]},{"id":"ora23-install","file":"install/guides/ora23-install.json","group":"Oracle","engineId":"oracle","category":"install","title":"Instalar o Oracle AI Database 26ai / 23ai (Linux)","summary":"Instala o Oracle AI Database 26ai (a versão que substitui o 23ai, número de versão 23.26.x) em um único servidor; você escolhe um de três caminhos oficiais: instalação OFA a partir do gold image ZIP para produção (runIns","level":"Intermediário","duration":"45–120 min","topology":"1 servidor","tags":["oracle","26ai","23ai","ai database","instalação","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":"Preparação do storage para Oracle: multipath, nomes de dispositivo persistentes, discos ASM","summary":"Aplicado uma vez, antes da instalação do Oracle Grid Infrastructure, do Oracle Restart ou do banco de dados: os LUNs da SAN são identificados pelo WWID, os aliases do DM-Multipath são configurados quando necessário e os ","level":"Intermediário","duration":"30–90 min","topology":"1 servidor, ou 2–8 nodes no RAC + discos SAN/iSCSI/VM","tags":["oracle","asm","multipath","device-mapper-multipath","dm-multipath","multipath.conf","wwid","udev","regra udev","asmlib","oracleasm","afd","asm filter driver","lvm","xfs","fstab","san","lun","preparação de storage","storage","disco","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 (servidor único)","summary":"Instalação do Oracle Restart (Grid Infrastructure 19c standalone, HA_CONFIG) e do ASM em um único servidor: usuário grid e grupos do ASM, nomes de disco persistentes (udev, ASMLib ou ASM Filter Driver; discos de caminho ","level":"Avançado","duration":"90–150 min","topology":"1 servidor + discos ASM não compartilhados","tags":["oracle","19c","grid infrastructure","oracle restart","asm","gridSetup","HA_CONFIG","udev","asmlib","oracleasm","afd","asm filter driver","srvctl","asmcmd","instalação","multipath","ol7"],"order":3,"steps":30,"scenarios":[]},{"id":"ora19-patch-ru","file":"install/guides/ora19-patch-ru.json","group":"Oracle","engineId":"oracle","category":"patch","title":"Aplicação de Release Update (RU) no Oracle Database 19c","summary":"Release Update trimestral em um banco de dados 19c de instância única ou Oracle Restart (Grid Infrastructure + ASM): atualização do OPatch, verificações prévias de conflito e de espaço, backup do ORACLE_HOME e guaranteed","level":"Intermediário","duration":"60–120 min (downtime: in-place 30–60 min, out-of-place 10–20 min)","topology":"1 servidor (instância única ou Oracle Restart); para RAC, o guia de rolling patch","tags":["oracle","19c","patch","release update","ru","opatch","opatchauto","datapatch","ojvm","out-of-place","rollback","restore point","oracle restart","rac","rolling","standby-first","data guard","standby","1265700.1"],"order":10,"steps":25,"scenarios":[]},{"id":"ora19-rac","file":"install/guides/ora19-rac.json","group":"Oracle","engineId":"oracle","category":"ha","title":"Instalação do Oracle RAC 19c (Grid Infrastructure + ASM + banco de dados RAC)","summary":"Instala do zero o Oracle Grid Infrastructure 19c (Flex ASM, SCAN) e um banco de dados Oracle RAC 19c em dois ou mais nodes: plano de rede e DNS, preparação dos discos compartilhados (udev ou ASMLib; com multipath ou cami","level":"Avançado","duration":"4–6 horas","topology":"2–8 nodes + disco compartilhado (SAN/iSCSI) + SCAN no DNS","tags":["oracle","rac","19c","grid infrastructure","clusterware","asm","scan","gridsetup","dbca","srvctl","crsctl","cluster","ha","udev","asmlib","multipath","ol7","scan","ocr","voting disk"],"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 rolling (opatchauto)","summary":"Aplica a Release Update trimestral do GI a um cluster RAC 19c de 2–8 nós em execução, sem downtime (rolling): atualização do OPatch, verificação de conflitos com opatchauto analyze, backup do OCR e ponto de retorno, apli","level":"Avançado","duration":"45–90 min por nó","topology":"RAC 19c existente de 2–8 nós","tags":["oracle","rac","19c","patch","release update","ru","opatchauto","opatch","datapatch","rolling","grid infrastructure","rollback","scan","serviço","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":"Operação diária e cenários de falha do Oracle RAC","summary":"Operação diária e resposta a falhas de um cluster Oracle RAC (Grid Infrastructure 19c) já instalado e em funcionamento: verificação de saúde, diagnóstico de node eviction, colocação de um node em manutenção, parada e par","level":"Avançado","duration":"15 min – 3 horas (conforme o cenário)","topology":"RAC existente com 2–8 nodes (Grid Infrastructure 19c; diferenças do 23ai/26ai nas notas)","tags":["oracle","rac","grid infrastructure","clusterware","crsctl","srvctl","olsnodes","cluvfy","addnode","adicionar node","remover node","delete node","ocr","olr","voting disk","votedisk","ocrconfig","ocrcheck","scan","vip","oifcfg","interconnect","eviction","ocssd","misscount","service","relocate","application continuity","taf","fan","operação diária","falha"],"order":12,"steps":10,"scenarios":[{"k":"scenario","v":"health","l":"Verificação de saúde do cluster (diária / antes de manutenção)","m":"Verificação e diagnóstico crsctl check cluster crsctl stat res -t cluvfy recurso OFFLINE CRS-4535 CRS-4530 CRS-4639 health check verificação de saúde INTERMEDIATE CRS-4537 CRS-2765 CRS-2878 CRS-4700 CRS-4701 crsctl check crs estado do cluster cluster status recurso parado resource offline orachk tfactl verificação antes de manutenção Não altera nada: são verificados a stack do Clusterware, os recu"},{"k":"scenario","v":"eviction","l":"Um node foi removido do cluster ou reiniciou sozinho (diagnóstico de eviction)","m":"Verificação e diagnóstico 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 node expulso 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 node reiniciou servidor reiniciou sozinho rebootless restart instance"},{"k":"scenario","v":"stopnode","l":"Parar um node para manutenção e trazê-lo de volta","m":"Iniciar / parar crsctl stop crs crsctl start crs manutenção de node OS patch reboot CRS-4133 CRS-4123 drain_timeout srvctl stop instance CRS-2673 CRS-2677 CRS-2675 crsctl disable crs crsctl enable crs modo de manutenção maintenance kernel update atualização de kernel firmware Escolha se for feito patch do sistema operacional, de kernel ou manutenção de hardware em um node. Os outros nodes continua"},{"k":"scenario","v":"stopall","l":"Parar e iniciar o cluster inteiro de forma planejada","m":"Iniciar / parar crsctl stop cluster -all crsctl start cluster -all desligamento total cluster shutdown parada planejada srvctl stop database CRS-2677 CRS-4133 CRS-4123 crsctl stop crs crsctl start crs manutenção de SAN manutenção de data center datacenter maintenance power off desligar todos os servidores Escolha quando todos os nodes precisam ser desligados ao mesmo tempo, como em uma manutenção "},{"k":"scenario","v":"addnode","l":"Adicionar um novo node ao cluster","m":"Adicionar / remover node addnode.sh addNode gridSetup.sh -addNode adicionar node 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 adicionar novo servidor expansão do cluster Escolha se um novo servidor vai entrar no cluster (aumento de capacidade, renovação de hardware). Sem downtime: verifica"},{"k":"scenario","v":"delnode","l":"Remover um node do cluster","m":"Adicionar / remover node crsctl delete node deinstall -local dbca -deleteInstance remover node delete node remove node cluvfy stage -post nodedel crsctl unpin css CRS-4658 CRS-4661 runInstaller -updateNodeList srvctl remove instance decommission remover servidor do cluster desmontar servidor antigo Escolha se um servidor vai sair do cluster de forma definitiva (devolução, falha de hardware). A ins"},{"k":"scenario","v":"service","l":"Adicionar, alterar, mover ou remover um serviço","m":"Serviço e rede srvctl add service srvctl modify service srvctl relocate service srvctl remove service ORA-12514 PRCD-1026 preferred available TAF Application Continuity TAC FAN mover serviço PRKO-2017 PRCR-1090 ORA-12514: TNS:listener does not currently know of service srvctl start service srvctl status service failback serviço não voltou drain_timeout adicionar serviço create service Escolha para"},{"k":"scenario","v":"net","l":"Alteração de SCAN, VIP, porta do listener ou interconnect","m":"Serviço e rede srvctl modify scan srvctl modify scan_listener srvctl modify nodeapps srvctl modify listener oifcfg setif oifcfg delif oifcfg getif alteração de IP SCAN IP alteração de VIP interconnect private network ORA-12545 listener port PRCS-1034 PRKO-2310 PRCR-1079 oifcfg HAIP 169.254 alteração de porta alteração de SCAN VIP change remote_listener ASMNET1LSNR_ASM Escolha se o nome/IPs do SCAN"},{"k":"scenario","v":"ocr_backup","l":"Fazer backup de OCR e OLR e verificar os backups","m":"OCR, OLR e voting ocrconfig -manualbackup ocrconfig -showbackup ocrconfig -local -manualbackup backup do OLR backup do OCR OCR backup ocrcheck ocrdump PROT- ocrconfig -copy ocrconfig -showbackuploc OLR backup onde fica o backup do OCR backup manual do OCR Sem downtime: backup manual do OCR, backup do OLR em cada node e cópia dos backups para fora dos discos do cluster. Escolha antes de qualquer op"},{"k":"scenario","v":"ocr_restore","l":"OCR corrompido ou disk group CRS perdido: restaurar a partir do backup","m":"OCR, OLR e voting PROT-602 PROC-26 CRS-4535 CRS-4000 CRS-1606 ocrconfig -restore crsctl start crs -excl -nocrs OCR corruption OCR corrompido disk group CRS perdido voting disk perdido ORA-15017 ORA-15063 PROT-35 PROT-19 ORA-15018 ORA-15033 ocrdump OCR restore CRSD não inicia Logical corruption check failed Escolha se o `ocrcheck` indicar corrupção, se o CRSD não subir (erros PROT-/PROC-) ou se o d"},{"k":"scenario","v":"olr_restore","l":"O Clusterware não sobe em um node: OLR corrompido","m":"OCR, OLR e voting ocrcheck -local ocrconfig -local -restore OLR corrompido OLR corrupt ohasd não inicia CRS-4124 CRS-4639 PROCL- CRS-4123 ohasd.trc olr.loc ocrconfig -local -showbackup Local registry integrity check failed OHASD não inicia um node não sobe Escolha se, com os outros nodes em funcionamento, `crsctl start crs` não consegue subir o OHASD em apenas um node e `ocrcheck -local` retorna e"},{"k":"scenario","v":"ocrvote_move","l":"Mover os arquivos de OCR e voting para outro disk group","m":"OCR, OLR e voting crsctl replace votedisk crsctl query css votedisk ocrconfig -add ocrconfig -delete mover voting disk votedisk mover OCR storage migration ORA-15274 ocrconfig -backuploc asmcmd spmove asmcmd pwmove mover disk group CRS mover arquivo de voting OCR move troca de storage Sem downtime: ocrconfig -add/-delete e crsctl replace votedisk. Escolha na troca de storage (SAN), ao aumentar a r"}]},{"id":"ora-asm-ops","file":"install/guides/ora-asm-ops.json","group":"Oracle","engineId":"oracle","category":"ops","title":"Oracle ASM: operação diária e cenários de falha","summary":"Operação diária dos disk groups ASM em um Oracle Restart ou RAC já instalado e o que fazer na hora da falha: verificação de capacidade (usable_file_mb), monitoramento de rebalance, adição/substituição/remoção de discos, ","level":"Avançado","duration":"10 min – algumas horas (conforme a duração do rebalance)","topology":"Oracle Restart (servidor único) ou RAC de 2–8 nodes, Grid Infrastructure 19c (diferenças do 23ai/26ai nas notas)","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","operação diária","falha"],"order":13,"steps":4,"scenarios":[{"k":"op","v":"capacity","l":"Verificação de capacidade e saúde dos disk groups","m":"Verificação e monitoramento usable_file_mb required_mirror_free_mb asmcmd lsdg disk group cheio ocupação do ASM free_mb capacidade ORA-15041 ORA-01653 ORA-17502 ORA-15041: diskgroup space exhausted diskgroup space exhausted disk group full ASM disk group full usable_file_mb negativo negative usable_file_mb ASM sem espaço asmcmd du Não altera nada: o disk group encheu, quanto espaço resta (a leitur"},{"k":"op","v":"rebal","l":"Monitorar, acelerar ou desacelerar um rebalance","m":"Verificação e monitoramento v$asm_operation gv$asm_operation rebalance REBALANCE POWER asm_power_limit asmcmd lsop est_minutes resync compact rebalance lento rebalance slow rebalance travado rebalance hung ERRS ARB0 quando o rebalance termina Progresso e tempo restante de um rebalance/resync em andamento (v$asm_operation, est_minutes) e alteração do POWER. O banco continua aberto; só muda a carga "},{"k":"op","v":"add","l":"Adicionar um novo disco ao disk group","m":"Operações de disco ADD DISK ALTER DISKGROUP ADD DISK adicionar disco liberar espaço aumentar capacidade ORA-15041 ORA-15031 ORA-15033 ORA-15014 ORA-15410 ORA-15032 ORA-15075 ORA-17502 add disk novo LUN new LUN aumentar disk group extend diskgroup O disk group está ficando sem espaço ou precisa crescer: prepare o novo LUN em todos os nodes (multipath/udev/ASMLib/AFD), adicione com ADD DISK e acompa"},{"k":"op","v":"replace","l":"Substituir um disco por um novo (REPLACE DISK)","m":"Operações de disco REPLACE DISK substituição de disco replace disk ORA-15145 storage migration renovação de disco ORA-15221 ORA-15033 replace failed disk substituir disco com falha disk replacement migração de storage storage migration ASM Substitui por um novo, em uma única operação, um disco com falha (offline) ou a ser renovado; apenas os dados desse disco são copiados (12.1+, NORMAL/HIGH). Com"},{"k":"op","v":"drop","l":"Remover um disco do disk group","m":"Operações de disco DROP DISK remover disco UNDROP DISKS FORMER ORA-15041 ORA-15067 devolver LUN drop disk DROPPING desconectar disco remove disk from diskgroup devolução de LUN Para devolver um LUN ou retirá-lo do storage: com DROP DISK os dados são movidos para os discos restantes; o disco não é desconectado antes de o rebalance terminar e o disco ficar FORMER. O banco continua aberto."},{"k":"op","v":"failed","l":"Um disco está offline ou com falha (redundância NORMAL/HIGH)","m":"Operações de disco 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 disco ficou offline SYNCING disco não pode ser lido I/O error ASM Em um disk group NORMAL/HIGH um disc"},{"k":"op","v":"create","l":"Criar um novo disk group","m":"Gerenciamento de disk groups CREATE DISKGROUP criar disk group au_size compatible.asm compatible.rdbms failgroup ORA-15018 ORA-15221 ORA-15072 ORA-15031 ORA-15033 create diskgroup new disk group novo disk group Para criar um novo disk group de dados, de FRA ou de aplicação: redundância, tamanho de AU, atributos compatible.asm/rdbms; no RAC, mount em todos os nodes e recurso do Clusterware. Os disk"},{"k":"op","v":"mount","l":"Fazer mount ou dismount de um disk group","m":"Gerenciamento de disk groups srvctl start diskgroup srvctl stop diskgroup ALTER DISKGROUP MOUNT DISMOUNT ORA-15027 ORA-15017 disk group não monta v$asm_client ORA-15063 ORA-15040 ORA-15130 ORA-15032 ORA-15042 PRCR-1065 CRS-2674 MOUNT FORCE diskgroup dismounted disk group não abre insufficient number of disks Para fechar um disk group de forma planejada (dismount) ou abrir um disk group fechado ou "},{"k":"op","v":"spbackup","l":"Backup do spfile do ASM, do arquivo de senhas e dos metadados","m":"Configuração asmcmd spbackup asmcmd spget asmcmd pwget asmcmd pwcopy md_backup md_restore backup do spfile do ASM orapwASM asmcmd spcopy GPnP profile profile.xml ASM password file backup ASM metadata backup backup do ASM Sem downtime: o spfile do ASM, o arquivo de senhas, a estrutura dos disk groups (md_backup) e, no RAC, o perfil GPnP são copiados para fora do ASM, para que a configuração do ASM "},{"k":"op","v":"dstring","l":"Alterar a string de descoberta de discos do ASM (asm_diskstring)","m":"Configuração asm_diskstring asmcmd dsset asmcmd dsget discovery string string de descoberta ORA-15014 kfod ORA-15020 discovered duplicate ASM disk afd_dsset asm_diskstring change disco não encontrado Para alterar o padrão de caminho em que o ASM procura discos (ex.: migração para multipath, novo diretório udev, ASMLib/AFD): primeiro testa com kfod, depois asmcmd dsset. Todos os discos existentes ("}]},{"id":"ora-autoupgrade","file":"install/guides/ora-autoupgrade.json","group":"Oracle","engineId":"oracle","category":"upgrade","title":"Upgrade de 19c → Oracle AI Database 26ai (23ai): AutoUpgrade","summary":"Use este guia para um upgrade de release principal (19c → 26ai); para um RU trimestral dentro da mesma release, use o guia \"Aplicar um Release Update (RU) no Oracle Database 19c\". Com o AutoUpgrade, a ferramenta recomend","level":"Avançado","duration":"2–4 horas (downtime: 30–90 min, conforme o tamanho do banco e os componentes)","topology":"1 servidor, Oracle Restart ou RAC (home 26ai em todos os nodes)","tags":["oracle","upgrade","autoupgrade","19c","26ai","23ai","noncdb","pdb","target_cdb","restore point","restoration","timezone","compatible","rollback","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 (com Broker; instância única, Oracle Restart, RAC)","summary":"Cria um physical standby para um banco de dados primary 19c em execução com RMAN DUPLICATE … FROM ACTIVE DATABASE e o adiciona ao Data Guard Broker. O resultado é um standby que recebe e aplica o redo em tempo real, uma ","level":"Avançado","duration":"2–4 horas (conforme o tamanho dos dados)","topology":"Primary (instância única / Oracle Restart / RAC com 2–8 nós) + physical standby (instância única / Oracle Restart / RAC) + observer opcional","tags":["oracle","data guard","dataguard","standby","physical standby","dgmgrl","broker","rman duplicate","switchover","failover","fast-start failover","observer","19c","dr","rac","oracle restart","srvctl","standby redo log","apply instance"],"order":20,"steps":43,"scenarios":[]},{"id":"ora-datapump","file":"install/guides/ora-datapump.json","group":"Oracle","engineId":"oracle","category":"backup","title":"Oracle Data Pump: export / import, migração, refresh de schema e transportable","summary":"Export e import com expdp/impdp no nível de tabela, schema, tablespace ou full, migração entre dois bancos de dados (arquivo de dump + scp + checksum ou NETWORK_LINK) e extração de DDL a partir de um dump (SQLFILE). Incl","level":"Intermediário","duration":"30–90 min (conforme o volume de dados)","topology":"1 banco de dados (instância única, Oracle Restart ou RAC); origem + destino em uma migração","tags":["oracle","data pump","datapump","expdp","impdp","export","import","dump","parfile","remap_schema","network_link","sqlfile","table_exists_action","flashback_time","migração de dados","migration","logical backup","backup lógico","rac","scan","cluster","acfs","cron","wallet","agendamento","refresh","refresh de schema","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":"Export: gerar um arquivo de dump a partir do banco de dados","m":"Exportação / importação expdp export gerar dump backup lógico logical backup ORA-39001 ORA-39000 ORA-39070 ORA-31633 ORA-01555 ORA-39095 ORA-39094 ORA-00439 LRM-00123 UDE-00002 ORA-39127 Uma tabela, um schema, um tablespace ou o banco de dados inteiro é gravado em um arquivo de dump (expdp). O banco de dados permanece aberto e a aplicação continua funcionando. É uma cópia lógica: não substitui um "},{"k":"op","v":"import","l":"Import: carregar um arquivo de dump no banco de dados","m":"Exportação / importação impdp import carregar dump 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 Um arquivo de dump gerado anteriormente é carregado com impdp; nomes de schema, tablespace e tabela podem ser remapeados. O destino permane"},{"k":"op","v":"move","l":"Migração: transferir dados do banco de origem para o destino","m":"Migração e refresh migração de dados migration NETWORK_LINK database link scp checksum ORA-31679 ORA-02085 ORA-39183 Export → cópia de arquivos → import, ou diretamente com NETWORK_LINK, sem arquivo de dump. Escolha este cartão se o schema ainda não existir no destino (carga inicial); se o mesmo schema já existir no destino e for substituído pela cópia de produção, escolha o cartão \"Refresh de sch"},{"k":"op","v":"sqlfile","l":"Extrair somente o DDL de um arquivo de dump (SQLFILE)","m":"Exportação / importação SQLFILE extrair DDL conteúdo do dump o que há no dump metadata DBMS_METADATA Nada é carregado; os comandos CREATE dos objetos são gravados em um arquivo .sql. O banco de dados não é alterado."},{"k":"op","v":"refresh","l":"Refresh de schema de produção para teste","m":"Migração e refresh refresh refresh de schema atualizar teste prod to test produção para teste refresh de UAT DROP USER CASCADE ORA-01940 ORA-02380 ORA-01917 ORA-31684 ORA-00031 TABLE_EXISTS_ACTION=REPLACE Um schema que já existe em teste/UAT é substituído pela versão atual de produção: backup do schema de destino, encerramento das sessões, DROP USER … CASCADE ou TABLE_EXISTS_ACTION=REPLACE, preser"},{"k":"op","v":"tts","l":"Mover um tablespace copiando datafiles (transportable tablespace)","m":"Transportable (cópia de datafiles) 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 Tablespaces grandes (centenas de GB ou mais) são movidos copiando datafiles, e não linha a linha; mesma plataforma ou plataforma/endian diferente (RMAN CON"},{"k":"op","v":"fulltts","l":"Mover o banco de dados inteiro: full transportable (11g/12c → 19c, non-CDB → PDB)","m":"Transportable (cópia de datafiles) full transportable TRANSPORTABLE=ALWAYS FULL=Y VERSION=12 11g to 19c de 11g para 19c non-CDB to PDB migrar para PDB migration upgrade by migration ORA-39123 ORA-01647 ORA-29349 ORA-39127 Com FULL=Y TRANSPORTABLE=ALWAYS, os tablespaces de usuário são movidos para uma nova PDB como datafiles e todo o resto (usuários, PL/SQL, privilégios) como metadados; VERSION=12 "},{"k":"op","v":"jobfix","l":"Job do Data Pump interrompido / suspenso: monitorar, retomar, encerrar","m":"Monitoramento e falhas ATTACH START_JOB CONTINUE_CLIENT KILL_JOB STOP_JOB dba_datapump_jobs orphan master table NOT RUNNING IDLING suspenso resumable ORA-39171 ORA-31626 ORA-31633 ORA-39002 ORA-31634 ORA-39097 ORA-39126 Um job do expdp/impdp está suspenso (resumable wait), parado ou interrompido; você quer se conectar a ele com ATTACH e retomá-lo, encerrá-lo com KILL_JOB ou limpar uma master table"}]},{"id":"ora-dataguard-ops","file":"install/guides/ora-dataguard-ops.json","group":"Oracle","engineId":"oracle","category":"ops","title":"Oracle Data Guard: operação diária e cenários de falha (19c / 23ai)","summary":"Runbook de operação diária e recuperação de falhas para uma configuração Data Guard (physical standby) já existente; para a instalação, use o guia de instalação do Data Guard. Se não tiver certeza do que fazer, comece po","level":"Avançado","duration":"5 min (verificação) – 4 horas (recriação)","topology":"Primary (instância única / Oracle Restart / RAC) + physical standby (instância única / Oracle Restart / RAC) + observer opcional","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":"Verificação de status e atraso (está tudo em ordem?)","m":"Monitoramento e verificação ORA-16809 ORA-16810 ORA-16853 ORA-16855 ORA-16857 ORA-16766 ORA-16825 apply lag transport lag atraso lag SHOW CONFIGURATION WARNING status do Data Guard ORA-16854 ORA-16856 ORA-16191 ORA-16198 ORA-03135 ORA-16714 ORA-16792 ORA-16047 standby atrasado transport lag alto verificação de saúde do Data Guard health check Somente leitura: configuração, transport/apply lag, gap"},{"k":"scenario","v":"switchover","l":"Switchover planejado (trocar os papéis)","m":"Transição de papéis switchover troca de papéis role transition teste de DR ORA-16475 ORA-16470 ORA-16467 Ready for Switchover ORA-16541 ORA-16516 switchover_status TO STANDBY SESSIONS ACTIVE switchback reverter os papéis manutenção planejada troca de site Primary e standby estão saudáveis e você quer trocar os papéis de forma planejada (manutenção, teste de DR, retorno dos papéis); não há perda de"},{"k":"scenario","v":"failover","l":"Primary perdido: failover para o standby","m":"Falha e recuperação failover primary caiu primary down perda de site disaster ORA-16472 ORA-01034 ORA-12541 FAILOVER TO ACTIVATE PHYSICAL STANDBY ORA-12514 ORA-12170 ORA-03113 ORA-16625 ORA-16778 primary inacessível perda de data center FAILOVER TO IMMEDIATE emergência O primary está inacessível e não vai voltar (perda de servidor, storage ou site); o standby passa a ser o primary. Irreversível: e"},{"k":"scenario","v":"reinstate","l":"Após o failover, trazer o primary antigo de volta como standby (reinstate)","m":"Falha e recuperação reinstate ORA-16661 ORA-16795 ORA-38729 ORA-16653 needs to be reinstated primary antigo flashback ORA-16649 split-brain primary antigo não abre FastStartFailoverAutoReinstate REINSTATE DATABASE standby_became_primary_scn Houve failover e o servidor do primary antigo voltou; se o Flashback Database estiver habilitado, ele vira standby do novo primary sem recriação. O novo primar"},{"k":"scenario","v":"gap","l":"Gap de archive log: o standby está aguardando archive logs ausentes","m":"Falha e recuperação archive gap gap de archive log 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 archive log ausente missing archive log ORA-16089 `v$archive_gap` retorna linhas ou o alert log mostra mensagens de FAL/gap; o apply travou em uma sequence. Os bancos continuam abertos. Se o"},{"k":"scenario","v":"rollfwd","l":"Standby muito atrasado ou sem archive logs: roll forward (RECOVER FROM SERVICE)","m":"Falha e recuperação roll forward roll forward do standby RECOVER STANDBY DATABASE FROM SERVICE nologging ORA-01578 ORA-26040 standby atrasado resync ressincronizar ORA-10567 BACKUP INCREMENTAL FROM SCN standby dias atrasado NONLOGGED BLOCK incremental roll forward Os archive logs do gap não existem em lugar nenhum, operações NOLOGGING corromperam o standby ou o standby está dias atrasado; o standb"},{"k":"scenario","v":"rebuild","l":"Recriar o standby do zero","m":"Falha e recuperação rebuild recriar standby re-create standby ORA-16795 DUPLICATE standby perdido control file perdido ORA-00205 ORA-01157 arquivos do standby apagados DROP DATABASE perda de disco do standby Não é possível fazer reinstate (sem flashback) nem roll forward, ou os arquivos/control file do standby foram perdidos; o standby é removido e criado novamente com DUPLICATE. O primary continu"},{"k":"scenario","v":"snapshot","l":"Converter para snapshot standby / reverter (cópia gravável para testes)","m":"Testes e leitura snapshot standby CONVERT TO SNAPSHOT STANDBY ambiente de teste read write standby ORA-16000 ORA-38784 ORA-16433 CONVERT TO PHYSICAL STANDBY SNAPSHOT STANDBY guaranteed restore point abrir standby para teste Você quer abrir o standby temporariamente em leitura e gravação para testes e depois descartar as alterações e voltar a physical standby; o primary não é afetado e o redo conti"},{"k":"scenario","v":"apply","l":"Parar / iniciar o Redo Apply, trocar a instância de apply, abrir em read-only","m":"Operação diária 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 parado MRP não está rodando Você quer parar ou reiniciar o MRP para manutenção, mover o apply para outra instância em um standby RAC ou abrir o standby par"},{"k":"scenario","v":"prot","l":"Modo de proteção, Fast-Start Failover e observer","m":"Operação diária 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 modo de proteção Você quer alternar entre MaxPerformance / MaxAvailability / MaxProtection, habilitar ou desabilitar o FSFO ou gerenciar o observer."},{"k":"scenario","v":"files","l":"Adicionar datafile, redo log e standby redo log / arquivo UNNAMED","m":"Operação diária standby_file_management UNNAMED ORA-01111 ORA-01110 ORA-01157 ORA-01274 adicionar datafile add datafile adicionar redo log standby redo log SRL ORA-16789 db_file_name_convert ADD STANDBY LOGFILE ORA-01136 datafile adicionado standby Um datafile ou redo log será adicionado ao primary, surgiu um arquivo UNNAMED no standby (ORA-01111/ORA-01274) ou faltam standby redo logs."},{"k":"scenario","v":"backup","l":"Fazer backup RMAN a partir do standby","m":"Operação diária rman standby backup backup a partir do standby archivelog deletion policy RMAN-08137 recovery catalog offload backup RMAN-06820 BACKED UP 1 TIMES CONFIGURE DB_UNIQUE_NAME backup no standby Você quer executar o backup RMAN no standby para tirar a carga de backup do primary e ajustar a política de exclusão de archive logs de acordo."}]},{"id":"ora-backup-strategy","file":"install/guides/ora-backup-strategy.json","group":"Oracle","engineId":"oracle","category":"backup","title":"Estratégia de backup e automação no Oracle (RMAN + Data Pump)","summary":"Estabelece um esquema de backup permanente e automatizado para um banco de dados já instalado (a recuperação após uma falha está em um guia separado: \"Restore e recovery com RMAN\"): level 0 semanal + level 1 diário (ou f","level":"Intermediário","duration":"60–120 min (sem contar o primeiro level 0)","topology":"1 servidor (instância única ou Oracle Restart) ou RAC (2–8 nodes)","tags":["oracle","rman","backup","cópia de segurança","estratégia","level 0","level 1","incremental","archivelog","fra","retenção","block change tracking","data pump","expdp","crontab","cron","systemd timer","dbms_scheduler","automação","wallet","mkstore","rac","oracle restart","snapshot controlfile","asm","/etc/cron.d","ol7","recovery catalog","create catalog","register database","teste de restore","simulado de restore","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":"Restore e recovery com RMAN","summary":"Conduz passo a passo o retorno correto com RMAN no momento da falha: 19 cenários — perda de datafile, SYSTEM/UNDO, tempfile, blocos corrompidos, online redo log, controlfile e spfile; restore completo, restore para outro","level":"Avançado","duration":"30 min – algumas horas (depende do tamanho do banco de dados)","topology":"1 servidor (instância única ou Oracle Restart) ou RAC; origem + destino no cenário de novo host","tags":["oracle","rman","restore","recovery","recuperação do banco de dados","pitr","point in time","resetlogs","recover table","controlfile","spfile","autobackup","datafile","preview","validate","dbid","novo servidor","disaster recovery","rac","oracle restart","cluster_database","srvctl","asm","block corruption","bloco corrompido","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":"Ensaio: RESTORE … PREVIEW / VALIDATE (não altera nada)","m":"Ensaio e registros de backup RESTORE PREVIEW RESTORE VALIDATE ensaio de restore teste de restore meu backup funciona backup test restore drill simulado de recuperação RMAN VALIDATE o backup está íntegro Nada está quebrado; você quer ver, sem gravar dados, se os backups realmente bastam para uma recuperação (o banco de dados continua aberto). Também é o primeiro passo do teste mensal de restore e d"},{"k":"scenario","v":"catalog","l":"Backups movidos para outro diretório / RMAN não encontra o backup (CATALOG)","m":"Ensaio e registros de backup CATALOG START WITH RMAN-06023 RMAN-06025 RMAN-06026 ORA-19505 ORA-27037 EXPIRED backup movido backup moved no backup found CROSSCHECK NFS mudou backup não encontrado As backup pieces existem, mas o RMAN não as conhece (foram movidas, o NFS mudou, vieram de outro servidor): você recebe RMAN-06023/06025. O banco de dados continua aberto."},{"k":"scenario","v":"arch","l":"Restaurar apenas os archive logs (RESTORE ARCHIVELOG)","m":"Ensaio e registros de backup RESTORE ARCHIVELOG ORA-00308 restaurar archive logs archive log restore archive gap LogMiner SET ARCHIVELOG DESTINATION Você precisa em disco dos archive logs de um intervalo de sequence específico para LogMiner, um gap no standby ou recovery manual; o banco de dados continua aberto e nenhum arquivo é sobrescrito."},{"k":"scenario","v":"datafile","l":"Perda/corrupção de um único datafile ou tablespace (o banco de dados continua aberto)","m":"Perda / corrupção ORA-01157 ORA-01110 ORA-01116 ORA-27041 ORA-00376 ORA-01113 datafile perdido datafile excluído missing datafile lost datafile tablespace perdido ORA-27037 ORA-01135 ORA-01115 ORA-01114 datafile corrompido O banco de dados está aberto, apenas um datafile ou tablespace não pode ser lido (ORA-01157/01110/01116); todo o resto funciona. Se o arquivo pertence a SYSTEM/UNDO, escolha o c"},{"k":"scenario","v":"block","l":"Há blocos corrompidos (ORA-01578, block media recovery)","m":"Perda / corrupção ORA-01578 ORA-26040 ORA-01110 bloco corrompido block corruption corrupt block v$database_block_corruption RECOVER CORRUPTION LIST block media recovery nologging ORA-19566 Marked Corrupt Corrupt block relative dba DBVERIFY Uma consulta retorna ORA-01578/ORA-26040, o backup para com ORA-19566 ou o VALIDATE encontrou blocos corrompidos; o restante do arquivo está íntegro. O banco de"},{"k":"scenario","v":"sysdf","l":"Perda de datafile do SYSTEM ou do UNDO (o banco de dados não abre)","m":"Perda / corrupção ORA-01157 ORA-01110 ORA-01116 ORA-01147 ORA-00376 ORA-01541 SYSTEM datafile UNDO datafile undo tablespace perdida system tablespace lost banco de dados não abre ORA-01113 system01.dbf undotbs O arquivo perdido ou corrompido pertence à tablespace SYSTEM ou UNDO: não pode ser colocado offline, o banco de dados (ou apenas aquele PDB, se for um arquivo de PDB) é fechado e restaurado "},{"k":"scenario","v":"temp","l":"Tempfile perdido ou corrompido (tablespace TEMP)","m":"Perda / corrupção ORA-01157 ORA-01187 ORA-25153 ORA-01116 ORA-01122 ORA-01110 tempfile temp tablespace tablespace temporária TEMP perdida temp01.dbf dba_temp_files Operações de sort/hash retornam ORA-01157/ORA-01187/ORA-25153 e o arquivo é um tempfile (o número na mensagem de erro é maior que o valor de `db_files`, por exemplo `data file 201`). Não é necessário restore; um novo tempfile é adiciona"},{"k":"scenario","v":"redo","l":"Online redo log perdido ou corrompido","m":"Perda / corrupção ORA-00313 ORA-00312 ORA-00327 ORA-00366 ORA-00367 ORA-00353 ORA-00354 ORA-00316 ORA-01624 redo log perdido online redo lost redo log CLEAR LOGFILE ORA-00314 ORA-00320 ORA-00321 ORA-00340 ORA-00350 ORA-00470 CLEAR UNARCHIVED No alert log aparece ORA-00313/00312 (não pode ser aberto) ou ORA-00327/00366/00367 (corrompido). Se um membro foi perdido ou o grupo está INACTIVE, o banco d"},{"k":"scenario","v":"controlfile","l":"Todas as cópias do controlfile perdidas","m":"Perda / corrupção ORA-00205 ORA-00202 ORA-00210 ORA-27037 controlfile perdido control file lost RESTORE CONTROLFILE autobackup ORA-00206 ORA-00214 ORA-00221 ORA-00227 controlfile corrompido Na fase MOUNT a instância não encontra ou não consegue ler o controlfile (ORA-00205/00202/00210); datafiles e redo estão íntegros. Se uma das cópias estiver íntegra, não é necessário restore (a etapa de diagnós"},{"k":"scenario","v":"spfile","l":"spfile perdido","m":"Perda / corrupção ORA-01078 LRM-00109 ORA-01565 spfile perdido spfile perdido parameter file RESTORE SPFILE CRS-5017 PRCR-1079 spfile excluído O spfile foi excluído ou corrompido; a instância não sobe (ORA-01078/LRM-00109) ou está no ar, mas o arquivo não existe. Os datafiles não são tocados e não há perda de dados; se a instância ainda está no ar, também não há indisponibilidade."},{"k":"scenario","v":"full","l":"Restore completo no mesmo servidor (datafiles perdidos; controlfile e redo íntegros)","m":"Perda / corrupção todos os datafiles perdidos all datafiles lost full restore RESTORE DATABASE falha de disco storage failure disco perdido LUN perdida datafiles excluídos Todos ou quase todos os datafiles se foram, o controlfile e os online redo logs estão íntegros; o banco de dados é fechado e não há perda de dados. Se o disco/diretório antigo dos arquivos não pode mais ser usado, escolha o cart"},{"k":"scenario","v":"relocate","l":"Disco perdido: restaurar o banco de dados para outro diretório / ASM (SET NEWNAME)","m":"Perda / corrupção SET NEWNAME SWITCH DATAFILE ALL restore para outro diretório restore para ASM new location disco trocado mount point perdido relocate ORA-15001 ORA-15040 disk group dismounted O disco ou disk group onde estão os datafiles não pode ser usado; controlfile e redo estão íntegros. Os arquivos são restaurados em um novo diretório ou disk group ASM, o banco de dados é fechado e não há p"},{"k":"scenario","v":"pitr","l":"Voltar a um horário / SCN (PITR, RESETLOGS)","m":"Point-in-time e reversão PITR point in time recovery voltar no tempo voltar a um SCN DELETE errado UPDATE errado TRUNCATE erro lógico logical error UNTIL TIME dados excluídos DROP USER UNTIL SCN RESETLOGS DELETE/UPDATE/TRUNCATE errado ou versão defeituosa da aplicação: leva o banco de dados (ou apenas o PDB) a um momento do passado; todas as alterações posteriores a esse momento se perdem (RESETLO"},{"k":"scenario","v":"flashback","l":"Retroceder com Flashback Database (restore point / SCN / horário)","m":"Point-in-time e reversão FLASHBACK DATABASE FLASHBACK PLUGGABLE DATABASE restore point guaranteed restore point retroceder reverter upgrade voltar após teste FLASHBACK_ON FLASHBACK TO RESTORE POINT O flashback está ativado ou existe um guaranteed restore point, e nenhum arquivo foi perdido: o banco é retrocedido em minutos sem restore (Enterprise Edition). RESETLOGS é necessário. Está ativado? `SE"},{"k":"scenario","v":"tspitr","l":"Voltar uma tablespace a um momento do passado (TSPITR)","m":"Point-in-time e reversão TSPITR tablespace point in time RECOVER TABLESPACE AUXILIARY DESTINATION DBMS_TTS recuperar tablespace ORA-29308 A operação errada afetou apenas objetos de uma tablespace; o restante do banco de dados deve permanecer no presente (Enterprise Edition). A tablespace fica offline durante a operação e todos os objetos nela voltam ao momento de destino; se apenas uma ou duas tab"},{"k":"scenario","v":"table","l":"Recuperar uma única tabela (RECOVER TABLE, 12c+ Enterprise Edition)","m":"Point-in-time e reversão RECOVER TABLE tabela excluída DROP TABLE recuperar tabela table recovery ORA-00942 REMAP TABLE ORA-38305 FLASHBACK TABLE recyclebin PURGE Uma única tabela foi excluída ou danificada por engano; o restante do banco de dados deve ficar como está (12c+ Enterprise Edition). Se sofreu DROP sem PURGE, veja primeiro a recyclebin: `FLASHBACK TABLE … TO BEFORE DROP` leva segundos ("},{"k":"scenario","v":"pdbdrop","l":"Trazer de volta um PDB descartado (DROP PLUGGABLE DATABASE)","m":"Point-in-time e reversão DROP PLUGGABLE DATABASE PDB excluído dropped PDB RMAN-06813 ORA-65011 ORA-65179 KEEP DATAFILES recuperar PDB unplug DBMS_PDB.RECOVER Um PDB foi removido com `DROP PLUGGABLE DATABASE`. Se os arquivos ainda existem, ele é plugado de novo com o XML; se foram excluídos, é trazido do backup (21c+ com um único comando, 19c por meio de um CDB auxiliar). O CDB continua aberto."},{"k":"scenario","v":"newhost","l":"Restore para outro servidor (novo host, a partir do autobackup do controlfile)","m":"Outro servidor e standby novo servidor outro servidor perda do servidor disaster recovery DR new host clone clone ambiente de teste servidor queimou server lost restore to another host O servidor se perdeu por completo ou será montado um ambiente de cópia/teste: o backup é restaurado em outro servidor (somente instância única, file system). A recuperação vai até o último archive log com backup; o "},{"k":"scenario","v":"fromsvc","l":"Data Guard: obter o arquivo do standby/primary pela rede (FROM SERVICE)","m":"Outro servidor e standby RESTORE FROM SERVICE FROM SERVICE RECOVER STANDBY DATABASE restore a partir do standby Data Guard standby atrasado archive gap standby controlfile ORA-01110 v$archive_gap apply lag Há Data Guard: você obtém o datafile perdido do primary a partir do standby, ou o standby atrasado ou o controlfile perdido do standby a partir do primary, sem usar backup pieces (12c+)."}]},{"id":"ora-goldengate","file":"install/guides/ora-goldengate.json","group":"Oracle","engineId":"oracle","category":"ha","title":"Oracle GoldenGate Microservices: replicação unidirecional Oracle → Oracle","summary":"Replica continuamente (com lag de segundos) um schema de PDB para outro banco de dados usando GoldenGate 21c ou 23ai/26ai Microservices. Ao final, Integrated Extract e Distribution Path rodam na origem e um Parallel Repl","level":"Avançado","duration":"3–5 horas","topology":"Servidor do banco de origem (deployment OGG de origem) + servidor do banco de destino (deployment OGG de destino); no RAC, GoldenGate no node 1 (ou como recurso de cluster com XAG)","tags":["oracle","goldengate","ogg","microservices","replicação","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: operação diária e cenários de falha (Microservices 21c / 23ai)","summary":"Runbook de operação diária e recuperação de falhas para uma replicação GoldenGate Microservices já instalada (para a instalação, use o guia de instalação do GoldenGate). Se não tiver certeza do que fazer, comece por 'Ver","level":"Avançado","duration":"5 min (verificação) – 2 horas (upgrade, inclusão de tabela)","topology":"Servidor de origem (deployment de origem, Integrated Extract, Distribution Path) + servidor de destino (deployment de destino, 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":"Verificação de saúde e de lag (está tudo certo?)","m":"Monitoramento e verificações INFO ALL lag atraso STATS heartbeat GG_LAG Service Manager ggserr.log OGG-01027 OGG-01738 Long Running Transaction STOPPED RUNNING Distribution Path DISTPATH Receiver INFO DISTPATH replicação atrasada replication lag Somente leitura: Service Manager e os microservices, INFO ALL, lag, STATS, lag do heartbeat, status do capture no banco de dados e ggserr.log; nada é alte"},{"k":"scenario","v":"ext_abend","l":"Extract ABENDED (parou com erro)","m":"Falha (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 parou capture ABORTED O Extract na origem está ABENDED ou reinicia continuamente: a causa (conexão, archived log ausente, log mining, privilégios, disco) "},{"k":"scenario","v":"rep_abend","l":"Replicat ABENDED (não consegue aplicar no destino)","m":"Falha (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 parou ORA-01400 ORA-12899 value too large O Replicat no destino não conseguiu aplicar uma transação: a tabela, a operação e o erro são identi"},{"k":"scenario","v":"add_table","l":"Adicionar uma tabela com dados à replicação (carga inicial + AFTERCSN)","m":"Gerenciamento de tabelas adicionar tabela add table ADD TRANDATA ADD SCHEMATRANDATA AFTERCSN ATCSN initial load carga inicial flashback_scn MAPEXCLUDE nova tabela Adiciona uma tabela existente que já contém dados a uma replicação em execução, sem indisponibilidade: ADD TRANDATA, expdp/impdp em um SCN consistente e um Replicat separado que aplica apenas as alterações desta tabela posteriores a esse"},{"k":"scenario","v":"remove_table","l":"Remover uma tabela da replicação","m":"Gerenciamento de tabelas remover tabela remove table TABLEEXCLUDE MAPEXCLUDE DELETE TRANDATA exclude A tabela deixará de ser replicada: TABLEEXCLUDE no Extract (ou remoção da linha TABLE), MAPEXCLUDE no Replicat e, se necessário, DELETE TRANDATA. Os processos são reiniciados rapidamente."},{"k":"scenario","v":"resync","l":"Ressincronizar uma única tabela (resync)","m":"Gerenciamento de tabelas resync ressincronizar out of sync diferença de dados divergência Veridata OGG-01004 ORA-01403 ORA-00001 row count contagem de linhas diferente Os dados de uma tabela no destino divergiram da origem (alteração manual, erro ignorado, carga inicial incompleta): a tabela é recarregada da origem em um SCN consistente e um Replicat temporário aplica as alterações posteriores a e"},{"k":"scenario","v":"purge","l":"Arquivos de trail enchendo o disco: limpeza (Purge Trail)","m":"Manutenção trail purge PURGEOLDEXTRACTS Purge Trail disco cheio No space left on device limpeza de trail var/lib/data diretório de trail cheio ENOSPC O diretório de trails está crescendo ou o disco está prestes a encher: verifica-se quais arquivos estão sendo lidos, uma tarefa Purge Trail (equivalente ao PURGEOLDEXTRACTS do Classic) é definida com USECHECKPOINTS; em emergência, os arquivos já lido"},{"k":"scenario","v":"reposition","l":"Reposicionar o Extract em um SCN específico","m":"Manutenção reposition ALTER EXTRACT SCN BEGIN SCN ETROLLOVER iniciar a partir do SCN perda de trail first_scn retroceder Existe um SCN a partir do qual você quer que o Extract recomece (perda de trail, ponto de início errado, retrocesso no destino): ele é iniciado em um novo arquivo de trail com ALTER EXTRACT … SCN e ETROLLOVER. Os mesmos dados podem chegar ao destino uma segunda vez."},{"k":"scenario","v":"upgrade","l":"Upgrade de versão / patch do GoldenGate (Microservices)","m":"Manutenção upgrade patch atualização de versão OPatch out-of-place oggHome Service Manager upgrade bundle patch 21c 23ai 26ai release update GoldenGate patch Service Manager PATCH Migração para uma nova versão ou patch do GoldenGate: out-of-place (instalar um novo home e mover o Service Manager e os deployments para o novo home via REST) ou in-place com OPatch. Extract/Replicat param por pouco tem"},{"k":"scenario","v":"dg_role","l":"Manter o Extract em execução após switchover/failover do Data Guard na origem","m":"Troca de função Data Guard switchover failover role transition HANDLEDLFAILOVER ORA-01033 ORA-16000 ORA-01109 novo primary standby FSFO ORA-12514 troca de função Extract novo primary FAILOVERTARGETDESTID Houve um switchover ou failover no banco de dados de origem; o Extract precisa se conectar ao novo primary e continuar a partir do seu checkpoint: verificam-se a conexão (credential alias/serviço)"}]},{"id":"ora-security","file":"install/guides/ora-security.json","group":"Oracle","engineId":"oracle","category":"security","title":"Hardening de segurança do Oracle Database (auditoria, rede, TLS, autenticação, privilégios, Unified Auditing, TDE)","summary":"Não é um guia de instalação: encontra e corrige as vulnerabilidades de um banco de dados Oracle 19c / 23ai (26ai) em execução (instância única, Oracle Restart ou RAC; CDB/PDB). Primeiro, a Verificação de estado, somente ","level":"Avançado","duration":"5 min (verificação) – 4 horas (hardening completo)","topology":"Instância única / Oracle Restart / RAC (2–8 nós), CDB + PDB; servidor de aplicação (validação do cliente)","tags":["oracle","segurança","security","hardening","endurecimento","cis benchmark","stig","tcps","wallet","orapki","sqlnet.ora","native network encryption","TCP.VALIDNODE_CHECKING","ALLOWED_LOGON_VERSION_SERVER","profile","ORA12C_STRONG_VERIFY_FUNCTION","unified auditing","AUDSYS","DBMS_AUDIT_MGMT","TDE","keystore","ADMINISTER KEY MANAGEMENT","UTL_FILE","PUBLIC","senha padrão"],"order":40,"steps":2,"scenarios":[{"k":"scenario","v":"scan","l":"Verificação de estado: quais são as minhas vulnerabilidades? (somente leitura)","m":"Início auditoria de segurança security audit hardening check CIS STIG DBSAT vulnerabilidade falha de segurança vulnerability achado de pentest dba_users_with_defpwd consulta de auditoria varredura de segurança security scan CRÍTICO A primeira varredura a executar: contas abertas e com senha padrão, verificadores de senha antigos, profile, privilégios DBA/ANY, packages PL/SQL UTL_* abertos para PUB"},{"k":"scenario","v":"all","l":"Hardening completo (tudo em sequência)","m":"Início hardening endurecimento segurança completa full hardening aplicar CIS benchmark STIG Banco de dados recém-instalado ou nunca endurecido: todas as áreas são aplicadas em uma ordem segura; o listener e o banco de dados são reiniciados uma ou duas vezes (requer janela de manutenção)."},{"k":"scenario","v":"net","l":"Rede e conexão: quem pode se conectar e de onde? (listener, TCP.VALIDNODE_CHECKING, firewall)","m":"Rede e identidade TCP.VALIDNODE_CHECKING TCP.INVITED_NODES listener 1521 5500 ORA-12537 TNS-12537 ORA-12541 ADMIN_RESTRICTIONS firewall TNS-12546 ORA-12170 invited nodes listener.log acesso externo restrição de acesso O listener está aberto em todos os endereços, não há invited nodes definidos e as portas 1521/5500 estão abertas para todos. O listener é reiniciado (as sessões abertas não são afeta"},{"k":"scenario","v":"tls","l":"Criptografar a conexão (wallet TCPS ou native network encryption)","m":"Rede e identidade TCPS SSL TLS wallet orapki SQLNET.ENCRYPTION_SERVER ORA-28860 ORA-29024 ORA-28759 ORA-29106 ORA-12696 ORA-12660 SSL_SERVER_DN_MATCH validade do certificado ORA-29003 ORA-29002 TNS-12560 cadeia de certificados TLS certificate chain native network encryption O tráfego de rede não é criptografado; TLS (TCPS, wallet, certificado, SSL_SERVER_DN_MATCH no cliente) ou native encryption s"},{"k":"scenario","v":"auth","l":"Autenticação e senha (verificador 12C, profile, contas padrão)","m":"Rede e identidade ALLOWED_LOGON_VERSION_SERVER ORA-28040 ORA-01017 ORA-28000 ORA-28001 ORA-28003 ORA-28007 password_versions 10G PROFILE ORA12C_STRONG_VERIFY_FUNCTION senha padrão default password SCOTT ORA-65066 ORA-00988 password_versions 10G profile de senha password policy FAILED_LOGIN_ATTEMPTS Verificadores de senha 10G/11G, nenhum profile de senha, contas de exemplo ou com senha padrão abert"},{"k":"scenario","v":"priv","l":"Privilégio mínimo: roles, PUBLIC e conta da aplicação","m":"Privilégios e rastreabilidade PUBLIC UTL_FILE UTL_TCP UTL_HTTP UTL_SMTP DBA role RESOURCE ANY privilege least privilege privilégio mínimo ORA-01031 ORA-00942 schema-only account PLS-00201 ORA-04021 GRANT ANY UNLIMITED TABLESPACE relatório de privilégios Privilégios DBA/RESOURCE/ANY na conta da aplicação, UTL_FILE/UTL_TCP/UTL_HTTP abertos para PUBLIC; owner do schema, roles de leitura/escrita e rel"},{"k":"scenario","v":"audit","l":"Auditoria: quem fez o quê? (Unified Auditing, limpeza do AUDSYS)","m":"Privilégios e rastreabilidade unified auditing AUDIT POLICY AUDSYS DBMS_AUDIT_MGMT UNIFIED_AUDIT_TRAIL ORA_LOGON_FAILURES ORA_SECURECONFIG UNIFIED_AUDIT_SYSTEMLOG SYSAUX cheio trilha de auditoria SIEM ORA-46267 unified audit policy quem fez o quê who changed O auditor quer registros de logon, de alterações de contas e de schemas; políticas de unified audit, limpeza do AUDSYS conforme o período de "},{"k":"scenario","v":"tde","l":"Criptografar os dados em disco (TDE)","m":"Dados e backup TDE transparent data encryption keystore 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 contra a leitura de datafiles, backups ou cópias de disco: WALLET_ROOT, keystore, master key, criptografia de tablespace (online). Requer a licen"},{"k":"scenario","v":"backup","l":"Segurança dos backups (criptografia RMAN, automação sem senha, permissões)","m":"Dados e backup RMAN encryption CONFIGURE ENCRYPTION ORA-19913 expdp ENCRYPTION secure external password store mkstore SEPS permissões de backup ORA-19914 licença Advanced Security backup sem criptografia unencrypted backup ENCRYPTION_PWD_PROMPT Backups RMAN/Data Pump sem criptografia, senhas em texto claro nos scripts, diretório de backup aberto para todos; RMAN encryption, ENCRYPTION_PWD_PROMPT, "},{"k":"scenario","v":"os","l":"Lado do sistema operacional (conta oracle, permissões de arquivos, core dump, SELinux)","m":"Servidor e versão SELinux orapw conta oracle permissões de arquivos core dump permissões do ORACLE_HOME sudo avc: denied passwd -l oracle setuid 6751 limits.d A senha da conta oracle está ativa, as permissões do arquivo de senhas/network admin/wallet estão frouxas, o SELinux está desativado. O limite de core dump passa a valer em uma nova sessão/após a reinicialização."},{"k":"scenario","v":"patch","l":"Patch e versão: estou na última RU?","m":"Servidor e versão RU release update CPU Critical Patch Update opatch lspatches datapatch dba_registry_sqlpatch CVE fim do suporte opatch Doc ID 742060.1 calendário de patches RU instalada, estado do datapatch e calendário de suporte; para a aplicação, remete ao guia de patch de RU. Somente leitura."}]},{"id":"ora-oem","file":"install/guides/ora-oem.json","group":"Oracle","engineId":"oracle","category":"monitoring","title":"Instalação do Oracle Enterprise Manager Cloud Control 13c Release 5 (13.5)","summary":"Instala o Oracle Enterprise Manager Cloud Control 13.5: um banco de dados 19c existente é preparado como Management Repository (parâmetros da documentação, reset das configurações do optimizer), o OMS é instalado em modo","level":"Avançado","duration":"3–5 horas","topology":"Servidor OMS + servidor do banco de dados do repository (+ servidores de destino a monitorar)","tags":["oracle","enterprise manager","oem","em13c","13.5","cloud control","oms","agent","emctl","emcli","monitoring","monitoramento","rac","cluster","discover_db","data guard","exportconfig"],"order":40,"steps":32,"scenarios":[]}]}}