WHERE 1=1本身不破坏索引,真正拖慢查询的是其常伴随的字符串拼接、缺失参数化、类型错配及NULL处理不当等问题,导致SQL注入、执行计划失效、隐式转换和全表扫描。

WHERE 1=1 本身不破坏索引,真正拖慢查询的是它常伴随的拼接方式和缺失的参数化
MySQL优化器会忽略1=1,但不会忽略你拼进去的脏数据
现代 MySQL(5.7+)和 PostgreSQL 都能识别并消除 1=1 这类恒真谓词,执行计划里通常看不到它。问题出在:你用 WHERE 1=1 开头后,往往直接字符串拼接用户输入,比如:"AND name = '" + userInput + "'"。这会导致:
- SQL注入风险让数据库不敢复用执行计划(即使没被攻破,预编译也失效)
- 拼出来的值未加引号或类型错配(如
AND age = 25vsAND age = '25'),触发隐式转换,使age列索引失效 - 拼接空字符串或 NULL 值时变成
AND status = ''或AND id = NULL,而NULL = NULL返回 UNKNOWN,条件永远不成立,优化器可能放弃索引走全表扫描
MyBatis等框架里写WHERE 1=1不如用<where>标签
手写 WHERE 1=1 是为绕过“第一个条件要不要加 WHERE”的判断逻辑,但框架早提供了更安全的替代方案:
-
<where>标签自动处理开头的 WHERE 和中间的 AND/OR,没有条件时整个<where>块被剔除,生成干净 SQL - 所有
#{}占位符默认参数化,避免类型错误和注入 - 不用手动拼字符串,也就杜绝了
"' OR 1=1 --"类攻击入口
对比示例:
SELECT * FROM users WHERE 1=1 AND name = 'admin' AND status = 1(手拼,危险)
vs
<select>SELECT * FROM users <where><if test="name != null">AND name = #{name}</if><if test="status != null">AND status = #{status}</if></where></select>(框架处理,安全)
存储过程中硬拼WHERE 1=1等于主动放弃参数化
在 MySQL 存储过程里用 CONCAT() 拼 WHERE 1=1 后跟用户变量,是典型反模式:
-
SET @sql = CONCAT('SELECT * FROM t WHERE 1=1 AND id = ', p_id);—— 如果p_id是 NULL 或含单引号,语句直接报错或被注入 - 必须改用
PREPARE ... EXECUTE+?占位符,且结构部分(表名、字段名)需白名单校验,不能拼进字符串 - 哪怕只拼一个值,也要先
IF p_id IS NOT NULL THEN SET @sql = CONCAT(@sql, ' AND id = ?');,再EXECUTE stmt USING p_id;
真正影响索引效率的从来不是 1=1 这三个字符,而是它背后暴露的“图省事不参数化”“不校验输入类型”“不区分结构与数据”的开发习惯。只要参数化到位、类型对齐、NULL 显式处理,WHERE 1=1 可以安全存在;但一旦开始拼字符串,它就成了性能和安全漏洞的同谋。

















