最常见危险是未加where的多表join引发笛卡尔积,导致内存/cpu耗尽;须用explain检查rows、禁用1=1占位、优先物化视图;mysql max_execution_time仅对innodb的select生效;postgresql用statement_timeout+work_mem控超时与内存;limit是join慢查最快止血法,但需配合order by索引。

JOIN太多或没加WHERE条件,数据库直接卡死
这是最常见也最危险的情况:一个没加过滤条件的多表JOIN,尤其涉及大表,会触发笛卡尔积,瞬间吃光内存和CPU。MySQL可能直接拒绝新连接,PostgreSQL可能把work_mem耗尽后退化成磁盘排序。
- 上线前必须检查
EXPLAIN结果——重点看rows预估是否爆炸(比如上千万)、是否有Using join buffer或Using temporary - 禁止在WHERE里写
1=1或空条件来“占位”,这会让优化器放弃索引选择 - 如果业务真需要宽表关联,优先用物化视图或定时ETL生成汇总表,而不是实时JOIN
- 对用户可输入的查询接口,强制要求至少一个高选择性字段(如
user_id、order_no)作为必填过滤项
MySQL的max_execution_time不生效?看版本和存储引擎
max_execution_time只对SELECT语句生效,且仅在MySQL 5.7.8+、使用InnoDB引擎时才真正起作用。MyISAM不支持,而且它对子查询、UNION、存储过程内的查询也无效。
- 设置方式:
SET SESSION max_execution_time = 3000;(单位毫秒),不能设为0或负数 - 注意它只中断执行中的查询,不会回滚事务;若在事务里被杀,需应用层主动处理
ERROR 3024 (HY000): Query execution was interrupted - 更稳妥的做法是配合
wait_timeout和interactive_timeout限制空闲连接,避免慢查询堆积 - 云数据库(如阿里云RDS)可能屏蔽该变量,得改用代理层限流或SQL审计规则
PostgreSQL如何限制单个查询的内存和时间
PostgreSQL没有全局超时开关,但可以通过statement_timeout和work_mem组合控制资源滥用。
-
SET statement_timeout = '5s';是最直接的查询超时手段,超时抛出ERROR: canceling statement due to statement timeout -
work_mem决定排序/哈希操作能用多少内存,设太高会导致OOM,太低则频繁落盘——建议按并发数反推:总内存 × 0.25 ÷ 最大并发连接数 - 在
postgresql.conf里设log_min_duration_statement = 1000,把耗时超1秒的SQL全记下来,定期分析TOP SQL - 对报表类长查询,用
pg_stat_activity查backend_start和state_change差值,主动KILL掉异常长的active会话
JOIN性能救急:临时加索引不如先加LIMIT
当线上突然出现慢JOIN又不能立刻改表结构时,LIMIT是最快速的“止血”手段——它能让优化器提前终止扫描,大幅降低I/O和锁持有时间。
- 哪怕只是加
LIMIT 1000,也可能让查询从30秒降到0.2秒,因为优化器会选择走索引+范围扫描而非全表JOIN - 注意
LIMIT必须配合ORDER BY字段有索引,否则仍可能先排序再截断,白忙活 - 别信“加了索引就万事大吉”——复合索引字段顺序必须匹配JOIN和WHERE条件中列的使用顺序,
(a,b,c)无法加速WHERE b = ? AND c = ? - 临时方案不是长久之计:记录下这类查询的
query_id,后续必须补上覆盖索引或重构数据模型
真正难的不是加个超时参数,而是判断哪个JOIN本就不该存在——有些关联逻辑其实在应用层做hash join或分批拉取,比数据库硬扛更稳。










