惊呆:where 1=1 可能严重影响性能,差了10多倍,快去排查你的 sql

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 老架构师尼恩在读者交流群中分享了关于MySQL中“where 1=1”条件的性能影响及其解决方案。该条件在动态SQL中常用,但可能在无真实条件时导致全表扫描,严重影响性能。尼恩建议通过其他条件或SQL子句命中索引,或使用MyBatis的`<where>`标签来避免性能问题。他还提供了详细的执行计划分析和优化建议,帮助大家在面试中展示深厚的技术功底,赢得面试官的青睐。更多内容可参考《尼恩Java面试宝典PDF》。

尼恩说在前面

在40岁老架构师 尼恩的读者交流群(50+)中,最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团、蚂蚁、得物的面试资格,遇到很多很重要的相关面试题:

MySQL中“where 1=1” 条件 影响性能么,为什么?

听说 MySQL中“where 1=1” 条件,部分场景会严重 影响性能,是哪些场景呢, 该怎么解决?

最近有小伙伴面试网易,都问到了这个面试题。 小伙伴没有系统的去梳理和总结,所以支支吾吾的说了几句,面试官不满意,面试挂了。

所以,尼恩给大家做一下系统化、体系化的梳理,使得大家内力猛增,可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提”。

当然,这道面试题,以及参考答案,也会收入咱们的 《尼恩Java面试宝典PDF》V175版本,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。

《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请到文末公号【技术自由圈】获取

MySQL中“where 1=1”的性能影响深究

“where 1=1” 这个条件, 非常常见,也非常好用。

但是, 隐藏在背后一个巨大的 性能问题。 通过此文, 老架构师尼恩给大家来一一揭秘, 帮助大家内力猛增。

“where 1=1”在动态 SQL 中的应用

WHERE 1 = 1在动态 SQL 场景中经常被使用,很多开发者喜欢在构建动态SQL查询时使用它,因为它可以方便地添加额外的查询条件。

在动态构建 SQL 查询语句时,添加WHERE 1 = 1可以方便地在其后添加其他条件,“1=1” 常被用作where 的 一个条件占位符。

image.png

有了 1 = 1,当我们可以动态地添加多个查询条件,不同担心“AND”或“OR”关键字的拼接问题。

例如,在一个 Java 程序中动态构建 SQL 查询:

String sql = "SELECT * FROM table_name WHERE 1 = 1";
if (condition1) {
   
    sql += " AND column1 = value1";
}
if (condition2) {
   
    sql += " AND column2 > value2";
}

image.png

“where 1=1”会导致严重的性能问题

虽然 “where 1=1” 使用的时候很方便,但是 存在严重的 性能隐患。

然而,这种做法存在风险,在部分罕见场景,就可能导致意外的全表扫描,影响查询性能。

什么罕见场景呢? 就是where没有一个真正的条件,只剩下1=1,就可能导致意外的全表扫描。

image.png

所以在使用动态 SQL 时,需要谨慎处理这种情况,确保在必要的时候添加合适的筛选条件来避免不必要的全表扫描。

性能影响测试

where 1=1到底会不会影响性能?我们可以先看一个具体的例子:

尼恩使用的mysql 版本比较老 是5.7,可以使用如下指令查看 MySQL版本:

SELECT VERSION();

image.png

场景:基于一张拥有 50W 条数据的test_user 表,根据height (带索引的列)进行查询,

使用存储过程,插入50W条测试数据, 具体请参见尼恩的前面文章

美团面试:mysql 索引失效?怎么解决?(重点知识,建议收藏,读10遍+)

所创建的test_user 中包含:idid_cardageuser_nameheight、address字段。

test_user 的结构如下:

CREATE TABLE `test_user` (
`id` int NOT NULL AUTO_INCREMENT, 
`id_card` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL, 
`age` int DEFAULT '0', 
`user_name` varchar(30) COLLATE utf8mb4_bin DEFAULT NULL,
`height` int DEFAULT '0',  
`address` varchar(30) COLLATE utf8mb4_bin DEFAULT NULL,  
PRIMARY KEY (`id`), 
KEY `idx_id_card_age_user_name` (`id_card`,`age`,`user_name`), 
KEY `idx_height` (`height`))
ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin

查看表结构和表的总数据,如下图:

下面,通过执行两条 SQL查询语句(一条带有 1=1):

explain format=json SELECT * FROM test_user WHERE 1 = 1   LIMIT 10,10

explain format=json   SELECT * FROM test_user WHERE 1 = 1  and  height=120  LIMIT 10,10

场景1:后面不带真实查询条件的where 1=1的执行成本

对 不带 真实查询条件 的where 1=1的sql,通过explain 查看执行计划 和 执行成本。

代码如下:


explain format=json SELECT * FROM test_user WHERE 1 = 1   LIMIT 10,10

执行结果如下:

{
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "100134.80"
    },
    "table": {
      "table_name": "test_user",
      "access_type": "ALL",
      "rows_examined_per_scan": 489294,
      "rows_produced_per_join": 489294,
      "filtered": "100.00",
      "cost_info": {
        "read_cost": "2276.00",
        "eval_cost": "97858.80",
        "prefix_cost": "100134.80",
        "data_read_per_join": "160M"
      },
      "used_columns": [
        "id",
        "id_card",
        "age",
        "user_name",
        "height",
        "address"
      ]
    }
  }
}

image.png

以下是对这个 JSON 格式的执行计划输出的解释:

一、整体结构

  1. "query_block": 代表整个查询的执行计划块,包含了关于这个查询的各种信息。

二、查询标识符和 执行成本

  1. "select_id": 1:查询的唯一标识符为 1。

  2. "cost_info"

"query_cost": "100134.80": 查询的预估总成本为 100134.80。

这个成本是数据库优化器根据多种因素估算出来的,包括读取数据的成本、评估条件的成本等。

一般来说,成本越低,查询的执行效率可能越高。

关于 sql 语句执行成本的详细介绍, 请参考尼恩的前面的深度文章:

美团面试:Mysql如何选择最优 执行计划,为什么?

三、表相关信息

  1. "table_name": "test_user": 查询涉及的表名为 test_user

  2. "access_type": "ALL":

访问表的方式为全表扫描(ALL)。

这意味着数据库在执行这个查询时没有使用索引,而是扫描了整个表来获取数据。

全表扫描通常在没有合适的索引可用或者优化器认为全表扫描比使用索引更高效的情况下发生。

  1. "rows_examined_per_scan": 489294:

每次扫描检查的行数为 489294。

这表示在执行查询过程中,数据库预计需要检查这么多行的数据。

  1. "rows_produced_per_join": 489294: 每次连接产生的行数为 489294。

如果查询涉及多个表的连接,这个值表示从这个表中产生的行数,用于连接操作。在这个例子中,可能没有连接操作,所以这个值与 rows_examined_per_scan 相同。

  1. "filtered": "100.00": 过滤后的行数比例为 100%。

过滤后,所有满足条件的行数占总检查行数的比例为 100%。这意味着经过筛选条件(在这个例子中,WHERE 1 = 1实际上没有进行有效的筛选)

  1. "cost_info" :

    • "read_cost": "2276.00": 读取数据的成本为 2276.00。
    • "eval_cost": "97858.80": 评估条件的成本为 97858.80。在这个例子中,由于 WHERE 1 = 1 没有实际的评估工作,这个成本可能主要来自其他方面,如读取数据后的处理。
    • "prefix_cost": "100134.80": 前缀成本为 100134.80,通常是指查询的总成本减去某些特定操作的成本。
    • "data_read_per_join": "160M": 每次连接读取的数据量为 160M(可能是 160 兆字节)。
  2. "used_columns": ["id", "id_card", "age", "user_name", "height", "address"]:

查询使用的列包括 idid_cardageuser_nameheightaddress

这意味着查询将从表中读取这些列的数据。

综上所述,这个执行计划表明查询使用了全表扫描的方式来获取数据,成本较高。

image.png

可能需要考虑创建合适的索引或者优化查询语句来提高查询性能。

read_cost、 eval_cost、prefix_cost 三个成本的关系

  1. read_cost(读取数据成本)

    定义:read_cost 主要是指从存储介质(如磁盘或内存)中读取数据所产生的成本。在数据库操作中,数据存储在磁盘上的文件或者内存中的缓存区域。当执行查询时,需要将相关的数据块读取到内存中进行处理,这个过程就会产生 read_cost。

    影响因素:

    • 数据量:要读取的数据量越大,read_cost 就越高。例如,对于一个全表扫描的查询,需要读取整个表的数据,read_cost 会比只读取少量满足条件的数据行高很多。
    • 存储介质性能:磁盘的 I/O 速度会直接影响 read_cost。如果是机械硬盘,其 I/O 速度相对较慢,read_cost 会比较高;而固态硬盘(SSD)的 I/O 速度快,read_cost 会相应降低。另外,内存读取速度比磁盘快很多,所以如果数据已经在内存缓存中,read_cost 会比从磁盘读取低。
    • 数据分布和存储格式:数据在磁盘上的分布情况以及存储格式也会影响 read_cost。例如,数据是否按照某种顺序存储(如按照索引顺序),如果是,可能会减少磁盘寻道时间,从而降低 read_cost。

    • 示例:在一个查询中,假设需要读取一个包含 100 万行数据的表,每行数据大小为 1KB,从磁盘读取数据块的单位成本为 1(这是一个抽象的成本单位),如果是全表扫描,read_cost 可能就会很高,约为 100 万(行数) 1KB(每行大小) 1(单位成本)。

  2. eval_cost(评估条件成本)

    定义:eval_cost 是指对查询条件进行评估所产生的成本。在 SQL 查询中,WHERE 子句用于筛选数据,数据库需要对每一行数据的条件进行判断,这个判断操作就会产生 eval_cost。

    影响因素:

    • 条件复杂度:如果查询条件很复杂,包含多个逻辑运算符(如 AND、OR)、函数(如 SUM、AVG)或者嵌套的子查询,eval_cost 会增加。例如,一个 WHERE 子句中有多个复杂的函数调用和嵌套子查询,数据库需要执行更多的计算和比较操作来评估条件,从而增加 eval_cost。
    • 数据类型和索引使用:数据类型也会影响 eval_cost。例如,比较整数类型的条件可能比比较文本类型的条件更快。如果能够利用索引来帮助评估条件,eval_cost 可能会降低。例如,对于一个有索引的列,数据库可以通过索引快速定位满足条件的行,减少了对每一行数据的详细评估,从而降低 eval_cost。

    • 示例:对于一个查询条件为 WHERE age > 30 AND salary < 5000 的查询,数据库需要对每一行数据的 age 和 salary 列进行比较操作。如果表中有 10 万行数据,每次比较操作的成本假设为 0.01(抽象成本单位),那么 eval_cost 大约为 10 万(行数) 2(两个条件) 0.01(单位成本)。

  3. prefix_cost(前缀成本)

    定义:prefix_cost 是查询的一种累积成本估算,它通常是查询总成本减去某些特定操作的成本。具体来说,它考虑了在执行查询过程中的多个步骤的成本累积,包括读取数据、评估条件以及其他可能的操作(如排序、分组等),但可能会排除一些后续的特定操作成本,以便于在执行计划比较等场景中进行更灵活的成本分析。

    与其他成本的关系:prefix_cost 是 read_cost 和 eval_cost 等成本的综合体现,并且还可能包含其他相关操作的成本。它的计算方式和具体包含的内容可能因数据库系统的优化器实现而有所不同。一般来说,它可以帮助用户和优化器快速判断一个查询执行计划在主要操作阶段的成本情况。

image.png

示例:假设一个查询的总成本为 100,其中排序操作成本为 10,那么 prefix_cost 可能就是 90,它反映了在不考虑排序操作的情况下,读取数据和评估条件等主要操作的成本。在执行计划选择过程中,数据库优化器可能会比较不同执行计划的 prefix_cost,选择成本较低的计划作为主要的候选方案,然后再考虑其他操作(如排序)的成本来最终确定执行计划。

场景2:后面 带有真实查询条件 的where 1=1的执行成本

对 带有真实查询条件 的where 1=1的sql,通过explain 查看执行计划 和 执行成本。

代码如下:



explain format=json   SELECT * FROM test_user WHERE 1 = 1  and  height=120  LIMIT 10,10

执行结果如下:

{
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "7252.80"
    },
    "table": {
      "table_name": "test_user",
      "access_type": "ref",
      "possible_keys": [
        "idx_height"
      ],
      "key": "idx_height",
      "used_key_parts": [
        "height"
      ],
      "key_length": "5",
      "ref": [
        "const"
      ],
      "rows_examined_per_scan": 6044,
      "rows_produced_per_join": 6044,
      "filtered": "100.00",
      "cost_info": {
        "read_cost": "6044.00",
        "eval_cost": "1208.80",
        "prefix_cost": "7252.80",
        "data_read_per_join": "1M"
      },
      "used_columns": [
        "id",
        "id_card",
        "age",
        "user_name",
        "height",
        "address"
      ]
    }
  }
}

以下是对这个 JSON 格式执行计划输出的详细解释:

一、整体结构

  1. "query_block": 代表整个查询的执行计划块,包含了关于这个查询的各种关键信息。

二、查询标识符和成本信息

  1. "select_id": 1:查询的唯一标识符为 1。

  2. "cost_info" :

    • "query_cost": "7252.80": 查询的预估总成本为 7252.80。这个成本是数据库优化器根据多种因素估算出来的,包括读取数据的成本、评估条件的成本等。相对较低的成本通常意味着执行计划较为高效。

image.png

三、表相关信息

  1. "table_name": "test_user": 查询涉及的表名为 test_user
  2. "access_type": "ref": 访问表的方式为 ref,表示通过非唯一索引进行查找。

在这个例子中,说明查询使用了索引进行查找,并且不是唯一索引。

  1. "possible_keys": ["idx_height"]:

可能使用的索引列表为 idx_height,这表明优化器考虑了这个索引,并最终选择了它。

  1. "key": "idx_height":

实际使用的索引是 idx_height,说明优化器认为使用这个索引可以提高查询性能。

  1. "used_key_parts": ["height"]: 使用的索引部分是 height 列,表明索引 idx_height 是基于 height 列创建的,并且在查询中只使用了这个索引的 height 部分。
  2. "key_length": "5": 索引的长度为 5,可能与存储 height 列的值所需的空间有关。
  3. "ref": ["const"]: 索引引用的值是常量,这里可能是查询条件中的某个具体值。
  4. "rows_examined_per_scan": 6044: 每次扫描检查的行数为 6044。这表示在执行查询过程中,需要检查的行数估计为 6044 行。相比全表扫描,这个行数较少,说明索引的使用有效地减少了需要检查的数据量。
  5. "rows_produced_per_join": 6044: 每次连接产生的行数为 6044。如果查询涉及多个表的连接,这个值表示从这个表中产生的行数,用于连接操作。在这个例子中,可能没有连接操作,所以这个值与 rows_examined_per_scan 相同。
  6. "filtered": "100.00": 过滤后的行数比例为 100%。这意味着经过筛选条件(可能与 height 列相关)过滤后,所有满足条件的行数占总检查行数的比例为 100%。
  7. "cost_info":
  • "read_cost": "6044.00": 读取数据的成本为 6044.00。
  • "eval_cost": "1208.80": 评估条件的成本为 1208.80。
  • "prefix_cost": "7252.80": 前缀成本为 7252.80,通常是指查询的总成本减去某些特定操作的成本。
  • "data_read_per_join": "1M": 每次连接读取的数据量为 1M(可能是 1 兆字节)。
  1. "used_columns": ["id", "id_card", "age", "user_name", "height", "address"]: 查询使用的列包括 idid_cardageuser_nameheightaddress。这意味着查询将从表中读取这些列的数据。

综上所述,这个执行计划表明查询使用了名为 idx_height 的索引进行查找,有效地减少了需要检查的行数和读取的数据量,从而降低了查询成本。

image.png

两条执行计划的对比

可以生成两条执行计划,一个是走索引(idx_height)的执行计划,另一个是全表扫描的执行计划,并且通过sql分析我们发现两者的cost值不一样的,cost的值如下所示:

执行方式 cost
where 1=1` 后面 有带真实条件 , 走索引 7252.80
where 1=1` 后面 没有带真实条件 , 没 走索引,全表扫描 100134.80

对比两条 SQL执行的结果,可以发现它们消耗的时间几乎相同,因此,看起来where 1=1 后面有没有带真实条件,对整体的性能 影响非常大 。
image.png

1=1 本质上被mysql 优化掉了

实际上: where 后面的1=1 条件,本质上被mysql 优化掉了

回顾一下:查询优化器、执行器的工作原理

MySQL 的查询优化器在生成执行计划之前会对查询语句进行分析。

image.png

  • 上图中 优化器 + 执行器 是哼哈二将:
  • 根据sql的结构生成不同的执行计划,然后选择一个最优的 plan 计划 , 是MySQL优化器 的主要任务。
  • 执行这个最优的执行计划 plan ,是 MySQL执行器 的主要任务。

执行器最终 执行的,是mysql 认为的,效率最高的执行计划, 执行sql并返回数据。

MySQL 优化器职责

  • 语法和语义解析

    当接收到一个 SQL 查询语句时,优化器首先会对语句进行语法和语义解析。

    它会识别出查询中的关键字(如 SELECT、FROM、WHERE、JOIN 等)、表名、列名、函数调用、操作符以及各种条件表达式等元素。这是理解查询意图的基础步骤。

    例如,对于查询语句 “SELECT * FROM users WHERE age> 18 AND gender = 'male'”,优化器会解析出这是一个从 “users” 表中选择所有列,并且筛选出年龄大于 18 岁且性别为男性的记录的查询。

  • 查询重写

    优化器会尝试对查询进行重写,以使其更高效或符合优化规则。

    这可能包括简化复杂的表达式、消除冗余的子句等操作。

    例如,对于一些包含嵌套子查询的复杂查询,优化器可能会将其转换为等价的连接操作,以提高查询性能。

    另外,如果查询中存在重复的条件或者可以通过逻辑推导简化的条件,优化器也会进行相应的处理。

  • 生成执行计划

    这是优化器的核心职责之一。

    它会根据解析后的查询和数据库的元数据(如表结构、索引信息、统计信息等)生成多个可能的执行计划。

    执行计划描述了数据库如何执行查询,包括访问哪些表、以何种顺序访问、是否使用索引、如何进行连接操作等细节。

    例如,对于一个涉及多表连接的查询,优化器可能会生成多种连接顺序不同的执行计划,如先连接表 A 和表 B,再连接表 C,或者先连接表 B 和表 C,再连接表 A 等不同的方案。

  • 成本估算和计划选择

    对于每个生成的执行计划,优化器会估算其执行成本。

    成本估算考虑多种因素,主要包括 I/O 成本(从磁盘读取数据的成本)和 CPU 成本(对数据进行处理的成本,如比较、排序、函数计算等)。

    优化器会根据表和索引的统计信息(如表的行数、索引的键值分布、列的基数等)来计算这些成本。

    然后,它会选择成本最低的执行计划作为最终的执行计划。

    例如,如果一个执行计划需要进行大量的全表扫描,I/O 成本较高,而另一个执行计划可以通过使用索引有效减少数据读取量,优化器会倾向于选择后者。

MySQL 执行器职责

  • 执行计划的执行

    一旦优化器确定了最终的执行计划,执行器就负责按照这个计划执行查询。

    它会根据执行计划中规定的步骤,逐个操作地处理查询。

    例如,如果执行计划要求先从某个表中读取数据,执行器就会向存储引擎发出相应的读取请求,获取数据行。

    如果执行计划包括连接操作,执行器会按照指定的连接算法(如嵌套循环连接、哈希连接等)对数据进行连接处理。

  • 数据读取和操作

    执行器负责从存储引擎读取数据,并根据查询的要求进行相应的操作。

    这包括读取表中的行数据、获取索引中的键值信息等。在读取数据的过程中,执行器会遵循存储引擎的接口和规则。

    例如,对于 InnoDB 存储引擎,执行器会通过 InnoDB 提供的接口来读取表空间文件(.ibd 文件)中的数据。同时,执行器会对读取的数据进行操作,如根据 WHERE 子句中的条件进行筛选,对选定的列进行投影操作(即选择查询中指定的列)等。

  • 事务管理(如果涉及)

    如果查询是在事务环境中进行的,执行器需要参与事务的管理。

    它会负责开启事务、提交事务或者回滚事务等操作,以确保数据的一致性和完整性。

    例如,在一个包含多个更新操作的事务查询中,执行器会按照事务的要求,先将更新操作记录到事务日志(如 InnoDB 的 redo 日志)中,在事务提交时确保所有的更新操作都持久化到磁盘,或者在事务回滚时撤销已经执行的部分更新操作。

  • 结果集生成和返回

    执行器会根据查询的要求生成最终的结果集。

    这可能包括对数据进行排序、分组、聚合等操作。

    例如,对于一个带有 ORDER BY 子句的查询,执行器会对读取的数据进行排序,然后将排序后的结果返回给客户端。

    在生成结果集的过程中,执行器会遵循 SQL 标准和数据库的特定规则,确保结果的准确性和完整性。

    最后,执行器将结果集返回给客户端应用程序,完成查询的执行过程。

MySQL 优化器对于1=1条件的优化工作

优化器最终选择最优或者执行效率最高的执行计划, 交给执行器去执行sql并返回数据。

MySQL 优化器的语义解析阶段

优化器的主要目标是找到一个高效的执行计划,以最小化查询的成本(包括 I/O 成本和 CPU 成本)。

优化器的语义解析阶段, 会解析 SQL 语句的语法和语义,提取表名、列名、条件表达式等信息。

对于WHERE 1 = 1这样的条件,优化器会判断它是一个恒为真的表达式。

当它发现WHERE 1 = 1这个条件不会对结果集进行实质性的筛选,并且不会影响索引的使用或其他优化策略时,就会尝试忽略这个条件。

MySQL 有一系列内置的优化规则。其中一条规则可能是识别并忽略没有实际筛选效果的常量条件。对于WHERE 1 = 1,它符合这种没有实际筛选作用的情况,因此可以根据规则被优化掉。

MySQL 优化器的成本估算和计划选择

在评估成本时,它会考虑多种因素,如是否使用索引、表的连接方式、数据量等。

在生成多个可能的执行计划时,优化器会计算每个计划的成本。

对于包含WHERE 1 = 1的查询,优化器会在计算成本的过程中发现这个条件不会对数据的读取量、比较操作的复杂度等成本因素产生实质性的增加。

例如,在计算 I/O 成本时,因为WHERE 1 = 1不会减少或增加需要从磁盘读取的数据页数量,所以在选择执行计划时,会倾向于选择那些不含有WHERE 1 = 1这个条件的更高效的计划。

所以,无论在 优化器的语义解析阶段,还是在 优化器的成本估算和计划选择, 都会把 1=1 这个条件忽略。

where 1=1的被优化后的结果

如果查询语句中除了WHERE 1 = 1之外,没有其他真正有筛选作用的条件,并且没有指定`Order by等使用索引的子句,数据库优化器可能会认为没有足够的信息来使用索引进行高效的查询,从而选择全表扫描的方式来获取数据。

例如,对于查询SELECT * FROM test_user WHERE 1 = 1,如果没有其他限制条件,数据库可能会扫描整个表来获取所有行。

但是,如果 后面指定`Order by ,就会命中索引,而不走全表扫描。

 SELECT * FROM test_user WHERE 1 = 1  order by  height   LIMIT 10,10

where 1=1 与索引使用的关系

如果查询中有其他条件、或者其他子句(如order)可以使用索引,并且WHERE 1 = 1不会干扰索引的使用,优化器会优先考虑索引相关的优化策略。

例如,对于查询SELECT * FROM table WHERE 1 = 1 AND column_name = 'value',如果column_name列有索引,优化器会重点关注如何利用这个索引来高效地找到满足column_name = 'value'的行,而WHERE 1 = 1则被视为不影响索引使用的额外条件,在生成执行计划时可能被忽略。

如果没有其他的条件、其他的字句 命中索引,那么对不起, 就只能是性能退化, 退化到 全表扫描。

如何避免 where 1=1 导致的性能严重退化?

where 1=1 条件 本质是被优化了的,所以 如果没有其他条件命中索引、或者其他sql子句命中索引, 那么sql就会退化到 全表扫描。

如何防止 where 1=1 导致的性能退化?

方法一:通过其他的查询条件命中索引

比如,能够确保其他条件中,至少有一个条件 命中索引:

eg

SELECT * FROM test_user WHERE 1 = 1  and  height=120

方法二:如果没有通过其他的查询条件命中索引

如果没有通过其他的查询条件命中索引 , 通过其他的sql 子句命中索引, 比如order子句。

比如下面的用id 排序

explain   SELECT * FROM test_user WHERE 1 = 1  ORDER BY id  LIMIT 10,10;

image.png

方法三:使用<where>标签,去掉不必要的1=1

使用<where>标签,去掉不必要的1=1, 比如使用 Mybatis提供的<where>标签

<where>标签只有在至少一个 if条件有值的情况下才去生成 where子句,若 AND或 OR前没有有效语句,where元素会将它们去除,

也就是说,如果 Mybatis通过<where>标签动态生成的语句为 where AND name = '111',最终会被优化为where name = '111'

<where>标签使用示例如下:

<select id="" parameterType = "">
    SELECT * FROM user 
    <where>
        <if test="name != null and name != ''">
           AND name = #{name}
        </if>
        <if test="age != null">
           AND age = #{age}
        </if>
    </where>
</select>

<where>标签是在 MyBatis中引入的,所以,很多一开始就使用 MyBatis的用户对这个标签使用的比较多。

尼恩提示:方式三 只是去掉 不必要的 1=1 条件而已, 并没有解决根本问题。

根本问题是要通过 sql 的其他子句,比如 select 子句、order by 子句 命中索引, 从而避免全表扫描。

如果遇到 mysql 这块的很难的面试题,可以找尼恩 来交流。

尼恩架构团队的塔尖 sql 面试题

  • sql查询语句的执行流程:

网易面试:说说MySQL一条SQL语句的执行过程?

美团面试:Mysql 有几级缓存? 每一级缓存,具体是什么?

  • 索引

阿里面试:为什么要索引?什么是MySQL索引?底层结构是什么?

滴滴面试:单表可以存200亿数据吗?单表真的只能存2000W,为什么?

  • 索引下推 ?

贝壳面试:什么是回表?什么是 索引下推 ?

  • 索引失效

美团面试:mysql 索引失效?怎么解决?(重点知识,建议收藏,读10遍+)

  • MVCC

MVCC学习圣经:一文穿透MySQL MVCC,吊打面试官

  • binlog、redolog、undo log

美团面试:binlog、redolog、undo log底层原理是啥?分别实现ACID哪个特性?(尼恩图解,史上最全)

  • mysql 事务

阿里面试:事务ACID,底层是如何实现的?

京东面试:RR隔离mysql如何实现?什么情况RR不能解决幻读?

  • 分布式事务

分布式事务圣经:从入门到精通,架构师尼恩最新、最全详解 (50+图文4万字全面总结 )

阿里面试:秒杀的分布式事务, 是如何设计的?

  • mysql 调优

如何做mysql调优?绝命7招,让慢SQL调优100倍

美团面试:Mysql如何选择最优 执行计划,为什么?

说在最后:有问题找老架构取经‍

回到面试题:

  • MySQL中“where 1=1” 条件 影响性能么,为什么?

  • 听说 MySQL中“where 1=1” 条件,部分场景会严重 影响性能,是哪些场景呢, 该怎么解决?

只要按照上面的 尼恩团队梳理的 方案去作答, 你的答案不是 100分,而是 120分。 面试官一定是 心满意足, 五体投地。

按照尼恩的梳理,进行 深度回答,可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提”。

在面试之前,建议大家系统化的刷一波 5000页《尼恩Java面试宝典PDF》,里边有大量的大厂真题、面试难题、架构难题。

很多小伙伴刷完后, 吊打面试官, 大厂横着走。

在刷题过程中,如果有啥问题,大家可以来 找 40岁老架构师尼恩交流。

另外,如果没有面试机会, 可以找尼恩来改简历、做帮扶。前段时间,刚指导一个小伙 暴涨200%(涨2倍),29岁/7年/双非一本 , 从13K一次涨到 37K ,逆天改命

狠狠卷,实现 “offer自由” 很容易的, 前段时间一个武汉的跟着尼恩卷了2年的小伙伴, 在极度严寒/痛苦被裁的环境下, offer拿到手软, 实现真正的 “offer自由” 。

nHwxrQQOA)

说在最后:有问题找老架构取经‍

回到面试题:

  • MySQL中“where 1=1” 条件 影响性能么,为什么?

  • 听说 MySQL中“where 1=1” 条件,部分场景会严重 影响性能,是哪些场景呢, 该怎么解决?

只要按照上面的 尼恩团队梳理的 方案去作答, 你的答案不是 100分,而是 120分。 面试官一定是 心满意足, 五体投地。

按照尼恩的梳理,进行 深度回答,可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提”。

在面试之前,建议大家系统化的刷一波 5000页《尼恩Java面试宝典PDF》,里边有大量的大厂真题、面试难题、架构难题。

很多小伙伴刷完后, 吊打面试官, 大厂横着走。

在刷题过程中,如果有啥问题,大家可以来 找 40岁老架构师尼恩交流。

另外,如果没有面试机会, 可以找尼恩来改简历、做帮扶。前段时间,刚指导一个小伙 暴涨200%(涨2倍),29岁/7年/双非一本 , 从13K一次涨到 37K ,逆天改命

狠狠卷,实现 “offer自由” 很容易的, 前段时间一个武汉的跟着尼恩卷了2年的小伙伴, 在极度严寒/痛苦被裁的环境下, offer拿到手软, 实现真正的 “offer自由” 。

尼恩技术圣经系列PDF

……完整版尼恩技术圣经PDF集群,请找尼恩领取

《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》PDF,请到下面公号【技术自由圈】取↓↓↓

相关文章
|
2月前
|
SQL 存储 关系型数据库
如何巧用索引优化SQL语句性能?
本文从索引角度探讨了如何优化MySQL中的SQL语句性能。首先介绍了如何通过查看执行时间和执行计划定位慢SQL,并详细解析了EXPLAIN命令的各个字段含义。接着讲解了索引优化的关键点,包括聚簇索引、索引覆盖、联合索引及最左前缀原则等。最后,通过具体示例展示了索引如何提升查询速度,并提供了三层B+树的存储容量计算方法。通过这些技巧,可以帮助开发者有效提升数据库查询效率。
141 2
|
26天前
|
SQL 存储 缓存
如何优化SQL查询性能?
【10月更文挑战第28天】如何优化SQL查询性能?
86 10
|
2月前
|
SQL 监控 数据库
慢SQL对数据库写入性能的影响及优化技巧
在数据库管理系统中,慢SQL(即执行缓慢的SQL语句)不仅会影响查询性能,还可能对数据库的写入性能产生显著的不利影响
|
2月前
|
SQL 关系型数据库 PostgreSQL
遇到SQL 子查询性能很差?其实可以这样优化
遇到SQL 子查询性能很差?其实可以这样优化
99 2
|
2月前
|
SQL Oracle 关系型数据库
Oracle SQL:了解执行计划和性能调优
Oracle SQL:了解执行计划和性能调优
60 1
|
2月前
|
SQL 存储 数据库
慢SQL对数据库写入性能的影响及优化技巧
在数据库管理系统中,慢SQL(即执行缓慢的SQL语句)不仅会影响查询性能,还可能对数据库的写入性能产生显著的不利影响
|
2月前
|
SQL 数据处理 数据库
SQL语句优化与查询结果优化:提升数据库性能的实战技巧
在数据库管理和应用中,SQL语句的编写和查询结果的优化是提升数据库性能的关键环节
|
2月前
|
SQL 存储 数据库
慢SQL对数据库写入性能的影响及优化策略
在数据库管理系统中,慢SQL(即执行缓慢的SQL语句)不仅会影响查询性能,还可能对数据库的写入性能产生不利影响
|
3月前
|
关系型数据库 MySQL 网络安全
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
|
5月前
|
SQL 存储 监控
SQL Server的并行实施如何优化?
【7月更文挑战第23天】SQL Server的并行实施如何优化?
118 13