in为什么慢

2023-05-16

IN为什么慢?
在应用程序中使用子查询后,SQL语句的查询性能变得非常糟糕。例如:

SELECT driver_id FROM driver where driver_id in (SELECT driver_id FROM driver where _create_date > ‘2016-07-25 00:00:00’);
独立子查询返回了符合条件的driver_id,这个问题是解决了,但是所用的时间需要6秒,可以通过EXPLAIN查看SQL语句的执行计划:

可以看到上面的SQL语句变成了相关子查询,通过EXPLAIN EXTENDED 和 SHOW WARNINGS命令,可以看到如下结果:

select northwind.driver.driver_id AS driver_id from northwind.driver where <in_optimizer>(northwind.driver.driver_id,(select 1 from northwind.driver where ((northwind.driver._create_date > ‘2016-07-25 00:00:00’) and ((northwind.driver.driver_id) = northwind.driver.driver_id))))
可以看出MySql优化器直接把IN子句转换成了EXISTS的相关子查询。下面这条相关IN子查询:

SELECT driver_id FROM driver where driver_id in (SELECT driver_id FROM user where user.uid = driver.driver_id);
查看SQL语句的执行计划:

就是相关子查询,通过EXPLAIN EXTENDED 和 SHOW WARNINGS命令,看到如下结果:

select northwind.driver.driver_id AS driver_id from northwind.driver where <in_optimizer>(northwind.driver.driver_id,(select 1 from northwind.user where ((northwind.user.uid = northwind.driver.driver_id) and ((northwind.driver.driver_id) = northwind.driver.driver_id))))
可以看出无论是独立子查询还是相关子查询,MySql 5.5之前的优化器都是将IN转换成EXISTS语句。如果子查询和外部查询分别返回M和N行,那么该子查询被扫描为O(N+N*M),而不是O(N+M)。这也就是为什么IN慢的原因。

IN和EXISTS哪个快?
网上百度到很多认为IN和EXISTS效率一样是错误的文章。

如果查询的两个表大小相当,那么用in和exists差别不大。
如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in:
例如:表A(小表),表B(大表)
1:
select * from A where cc in (select cc from B) 效率低,用到了A表上cc列的索引;
select * from A where exists(select cc from B where cc=A.cc) 效率高,用到了B表上cc列的索引。
相反的
2:
select * from B where cc in (select cc from A) 效率高,用到了B表上cc列的索引;
select * from B where exists(select cc from A where cc=B.cc) 效率低,用到了A表上cc列的索引。
总结上面的描述,个人认为其主要的原因在于对索引的使用。任何情况下,只要是大表的索引被使用,就可以使效率提高。

但是在编辑本文的时候,多次测试,却没能得到上面所总结的结果。下面是测试SQL语句,先是外表为大表,内表为小表。(示例一)

SELECT count(driver_id) FROM driver where driver_id in (SELECT uid FROM user);
SELECT count(driver_id) FROM driver where exists (SELECT 1 FROM user where uid = driver.driver_id);
执行结果是:

再是外表是小表,内表是大表。(示例二)

select count(uid) from user where uid in (SELECT driver_id FROM driver);
select count(uid) from user where exists (SELECT 1 FROM driver where driver.driver_id = user.uid);
执行结果是:

可以发现IN和EXISTS的执行效率,在任何情况下都正好是相同的。基于此,我们继续查看示例一两条SQL语句的执行计划,如下:

可以看到IN和EXISTS的执行计划是一样的,对此得出的结论两者的执行效率应该是一样的。

《MySql技术内幕:SQL编程》:书中描述的确实有很多DBA认为EXISTS比IN的执行效率更高,可能是当时优化器还不是很稳定和足够优秀,但是目前绝大数的情况下,IN和EXISTS都具有相同的执行计划。

如何提高效率?
上面示例二中的SQL语句执行时间约8秒,因为存在M*N的原因造成慢查询,但是还是可以进行优化,注意到慢的原因就是内部每次与外部比较时,都需要遍历一次表操作,可以采用另外一个方法,在嵌套一层子查询,避免多次遍历操作,语句如下:

SELECT count(driver_id) FROM driver where exists (SELECT uid FROM (SELECT uid from user) as b where b.uid = driver.driver_id);
执行效果如图:

可以发现优化减少了6s多的执行时间,下面是SQL的执行计划:

同样的还是相关子查询,但是减少了内部遍历查询的操作。所以可以通过预查询来减少遍历操作,而提高效率。

其实在实际编程中,很多开发人员选择不使用连接表查询,而是自己先把数据从一张表中取出,再到另一张表中执行WHEREIN操作,这原理和上面SQL语句实现的是一样的。

MySQL5.6对子查询的优化?
SEMI JOIN策略
优化器会识别出需要子查询的IN语句以便从区域表返回每个区域键的一个实例。这就导致了MySQL会以半连接的方式执行SELECT语句,所以全局表中每个区域只会有一个实例与记录相匹配。

半连接和常规连接之间存在两个非常重要的区别:

在半连接中,内表不会导致重复的结果。
此操作不会有内表中的字段添加到结果中去。
因此,半连接的结果常常是来自外表记录的一个子集。从有效性上看,半连接的优化在于有效的消除了来自内表的重复项,MySQL应用了四个不同的半连接执行策略用来去重。

Table Pullout优化
Convert the subquery to a join, or use table pullout and run the query as an inner join between subquery tables and outer tables. Table pullout pulls a table out from the subquery to the outer query.将子查询转变为一个连接,或是利用table pullout并将查询作为子查询表和外表之间的一个内连接来执行。Table pullout会为外部查询从子查询抽取出一个表。

有些时候,一个子查询可以被重写为JOIN,例如:

SELECT OrderID FROM Orders where EmployeeID IN (select EmployeeID from Employees where EmployeeID > 3);
如果知道OrderID是唯一的,即主键或者唯一索引,那么SQL语句会被重写为Join形式。

SELECT OrderID FROM Orders join Employees where Orders.EmployeeID = Employees.EmployeeID and Employees.EmployeeID > 3;
Table pullout的作用就是根据唯一索引将子查询重写为JOIN语句,在MySql 5.5中,上述的SQL语句执行计划:

如果通过EXPLAIN EXTENDED 和 SHOW WARNINGS命令,可以看到如下结果:

select northwind.Orders.OrderID AS OrderID from northwind.Orders where <in_optimizer>(northwind.Orders.EmployeeID,(<primary_index_lookup>((northwind.Orders.EmployeeID) in Employees on PRIMARY where ((northwind.Employees.EmployeeID > 3) and ((northwind.Orders.EmployeeID) = northwind.Employees.EmployeeID)))))
正是上面说的in为什么慢?

在MySql 5.6中,优化器会对SQL语句重写,得到的执行计划:

在MySql 5.6中,优化器没有将独立子查询重写为相关子查询,通过EXPLAIN EXTENDED 和 SHOW WARNINGS命令,得到优化器的执行方式为:

/* select#1 */ select northwind.orders.OrderID AS OrderID from northwind.employees join northwind.orders where ((northwind.orders.EmployeeID = northwind.employees.EmployeeID) and (northwind.employees.EmployeeID > 3))
很显然,优化器将上述子查询重写为JOIN语句,这就是Table Pullout优化。

Duplicate Weedout优化
Run the semi-join as if it was a join and remove duplicate records using a temporary table.执行半连接,就如同它是一个连接并利用临时表移除了重复的记录。

上面内部表查出的列是唯一的,因此优化器会将子查询重写为JOIN语句,以提高SQL执行的效率。Duplicate Weedout优化是指外部查询条件是列是唯一的,MySql优化器会先将子查询查出的结果进行去重。比如下面这条SQL语句:

SELECT ContactName FROM Customers where CustomerID in (select CustomerID from Orders where OrderID > 10000 and Customers.Country = Orders.ShipCountry);
因为CustomerID是主键,所以应该对子查询得到的结果进行去重。在MySql 5.6中的执行计划:

Extra选项提示的Start temporary表示创建一张去重的临时表,End temporary表示删除该临时表。而通过EXPLAIN EXTENDED 和 SHOW WARNINGS命令,得到优化器的执行方式为:

/* select#1 / select northwind.customers.ContactName AS ContactName from northwind.customers semi join (northwind.orders) where ((northwind.customers.CustomerID = northwind.orders.CustomerID) and (northwind.customers.Country = northwind.orders.ShipCountry) and (northwind.orders.OrderID > 10000))
与Table Pullout优化不同的是,显示的是semi join而不是join,其中原因在于多了一些去重的工作,对于上述的执行计划,其扫描成本约为830+830
1=1660次。
而在MySql 5.5中的执行计划为:

可以看到,在MySql 5.5中还是将语句转化为相关子查询,扫描成本约为93+93*9=930次。

我们可以看到MySql 5.6优化以后比5.5的扫描成本反而大,其实这只是在两张表较小的的情况下的结果,如果表很大,优化的效果会非常明显。

Materialization优化
Materialize the subquery into a temporary table with an index and use the temporary table to perform a join. The index is used to remove duplicates. The index might also be used later for lookups when joining the temporary table with the outer tables; if not, the table is scanned.

上面的子查询是相关子查询,如果子查询是独立子查询,则优化器可以选择将独立子查询产生的结果填充到单独一张物化临时表中,如图:

根据JOIN的顺序,Materialization优化可分为:

Materialization scan:JOIN是将物化临时表和表进行关联。
Materialization lookup:JOIN是将表和物化临时表进行关联。
下面的子查询可以利用Materialization来进行优化:

SELECT OrderID FROM Orders where OrderID in (select OrderID from Order Details where UnitPrice < 50 );
SQL语句的执行计划:

可以看到,在进行JOIN时(也就是id为1的步骤),先扫描的表是Orders,然后是subquery2,因此这是Materialization lookup的优化。对于下面的SQL:

select * FROM driver where driver_id in (select uid from user);
SQL语句的执行计划:

先扫描的是subquery2,再是driver表,这就是Materialization scan的优化。

FirstMacth优化
When scanning the inner tables for row combinations and there are multiple instances of a given value group, choose one rather than returning them all. This “shortcuts” scanning and eliminates production of unnecessary rows.为了对记录进行合并而在扫描内表,并且对于给定值群组有多个实例时,选择其一而不是将它们全部返回。这为表扫描提供了一个早期退出机制而且还消除了不必要记录的产生。

半连接的最先匹配(FirstMatch)策略执行子查询的方式与MySQL稍早版本中的IN-TO-EXISTS是非常相似的。对于外表中的每条匹配记录,MySQL都会在内表中进行匹配检查。当发现存在匹配时,它会从外表返回记录。只有在未发现匹配的情况下,引擎才会回退去扫描整个内表。

LooseScan优化
Scan a subquery table using an index that enables a single value to be chosen from each subquery’s value group.利用索引来扫描一个子查询表可以从每个子查询的值群组中选出一个单一的值。

SEMI JOIN变量
Each of these strategies except Duplicate Weedout can be enabled or disabled using the optimizer_switch system variable. The semijoin flag controls whether semi-joins are used. If it is set to on, the firstmatch, loosescan, and materialization flags enable finer control over the permitted semi-join strategies. These flags are on by default.除Duplicate Weedout之外的每个策略可以用变量控制开关,semijoin控制semi-joins优化是否开启,如果设置开启,其他的策略也有独立的变量控制。所有的变量在5.6默认是打开的。

mysql> SELECT @@optimizer_switch\G;
*************************** 1. row ***************************
@@optimizer_switch: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on
1 row in set (0.00 sec)
EXPLAIN查看策略
Semi-joined tables show up in the outer select. EXPLAIN EXTENDED plus SHOW WARNINGS shows the rewritten query, which displays the semi-join structure. From this you can get an idea about which tables were pulled out of the semi-join. If a subquery was converted to a semi-join, you will see that the subquery predicate is gone and its tables and WHERE clause were merged into the outer query join list and WHERE clause.
Temporary table use for Duplicate Weedout is indicated by Start temporary and End temporary in the Extra column. Tables that were not pulled out and are in the range of EXPLAIN output rows covered by Start temporary and End temporary will have their rowid in the temporary table.
FirstMatch(tbl_name) in the Extra column(列) indicates join shortcutting.
LooseScan(m…n) in the Extra column indicates use of the LooseScan strategy. m and n are key part numbers.
As of MySQL 5.6.7, temporary table use for materialization is indicated by rows with a select_type value of MATERIALIZED and rows with a table value of .
Before MySQL 5.6.7, temporary table use for materialization is indicated in the Extra column by Materialize if a single table is used, or by Start materialize and End materialize if multiple tables are used. If Scan is present, no temporary table index is used for table reads. Otherwise, an index lookup is used.
上面介绍中FirstMacth优化、LooseScan优化的具体效果没有很好的例子去显示出来。有机会可以交流学习。

参考
有不对的地方希望大家多交流,谢谢。

《MySql技术内幕:SQL编程》

http://dev.mysql.com/doc/refman/5.6/en/subquery-optimization.html

http://tech.it168.com/a2013/0506/1479/000001479749.shtml

转载请注明出处。
作者:wuxiwei
出处:http://www.cnblogs.com/wxw16/p/6105624.html

转载于:https://www.cnblogs.com/wxw16/p/6105624.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

in为什么慢 的相关文章

  • 02 openEuler操作系统的安装

    文章目录 02 openEuler操作系统的安装2 1 openEuler操作系统的安装流程2 2 openEuler操作系统的安装详细步骤2 2 1 下载地址2 2 2 创建虚拟机2 2 2 1 方法一 xff1a 典型配置2 2 2 2
  • 06 openEuler XFCE 桌面环境的安装和使用

    06 openEuler XFCE 桌面环境的安装和使用 文章目录 06 openEuler XFCE 桌面环境的安装和使用6 1 XFCE简介6 2 XFCE安装方法6 2 1 更新软件源6 2 2 安装字库6 2 3 安装Xorg6 2
  • 21 openEuler 管理服务-改变运行级别

    文章目录 21 管理服务 改变运行级别21 1 Target和运行级别21 2 查看系统默认启动目标21 3 查看当前系统所有的启动目标21 4 改变默认目标21 5 改变当前目标21 6 切换到救援模式21 7 切换到紧急模式 21 管理
  • 字符串通配(动态规划java)

    1 牛客网题目 xff1a 题目描述 对于字符串A xff0c 其中绝对不含有字符 和 再给定字符串B xff0c 其中可以含有 或 xff0c 字符不能是B的首字符 xff0c 并且任意两个 字符不相邻 exp中的 代表任何一个字符 xf
  • 26 openEuler管理网络-使用ip命令配置网络

    文章目录 26 openEuler管理网络 使用ip命令配置网络26 1 配置IP地址26 1 1 配置静态地址26 1 2 配置多个地址 26 2 配置静态路由 26 openEuler管理网络 使用ip命令配置网络 说明 xff1a 使
  • 31 openEuler使用LVM管理硬盘-管理物理卷

    文章目录 31 openEuler使用LVM管理硬盘 管理物理卷31 1 创建物理卷31 2 查看物理卷31 3 修改物理卷属性31 4 删除物理卷 31 openEuler使用LVM管理硬盘 管理物理卷 31 1 创建物理卷 可在root
  • 41 openEuler搭建FTP服务器-传输文件

    文章目录 41 openEuler搭建FTP服务器 传输文件41 1 概述41 2 连接服务器41 3 下载文件41 4 上传文件41 5 删除文件41 6 断开服务器 41 openEuler搭建FTP服务器 传输文件 41 1 概述 这
  • 45 openEuler搭建Nginx服务器-Nginx概述和安装

    文章目录 45 openEuler搭建Nginx服务器 Nginx概述和安装45 1 概述45 2 安装 45 openEuler搭建Nginx服务器 Nginx概述和安装 45 1 概述 Nginx 是一款轻量级的 Web 服务器 反向代
  • 14 KVM虚拟机配置-配置虚拟设备(其它常用设备)

    文章目录 14 KVM虚拟机配置 配置虚拟设备 xff08 其它常用设备 xff09 14 1 概述14 2 元素介绍14 3 配置示例 14 KVM虚拟机配置 配置虚拟设备 xff08 其它常用设备 xff09 14 1 概述 除存储设备
  • 15 KVM虚拟机配置-体系架构相关配置

    文章目录 15 KVM虚拟机配置 体系架构相关配置15 1 概述15 2 元素介绍15 3 AArch64架构配置示例15 4 x86 64架构配置示例 15 KVM虚拟机配置 体系架构相关配置 15 1 概述 XML中还有一部分体系架构相
  • 16 KVM虚拟机配置-其他常见配置项

    文章目录 16 KVM虚拟机配置 其他常见配置项16 1 概述16 2 元素介绍16 3 配置示例 16 KVM虚拟机配置 其他常见配置项 16 1 概述 除系统资源和虚拟设备外 xff0c XML配置文件还需要配置一些其他元素 xff0c
  • windows查看默认编码类型

    xfeff xfeff 开始 cmd 运行chcp 你会得到一个数 例 xff1a 如936 xff0c 那就是GBK简体中文 ANSI代码页为1252 xff0c 日文代码页为932
  • 三、@PathVariable

    3 1 64 PathVariable 映射 URL 绑定的占位符 带占位符的 URL 是 Spring3 0 新增的功能 xff0c 该功能在SpringMVC 向 REST 目标挺进发展过程中具有里程碑的意义通过 64 PathVari
  • 走进CSDN

    走进CSDN 关注CSDN不久 xff0c 最近浏览的次数增多 xff0c CSDN的资讯刚开始基本上看的懂的不多 xff0c 专业名词扎堆的论坛 xff0c CSDN的氛围个人感觉挺好的 xff0c 一群俗称 程序员 的人聚集讨论问题 x
  • B端产品经理基本工作流程

    产品岗位必备素质 产品是一个门槛较低的岗位 xff0c 是一个看起来很容易 xff0c 做起来各个地方都是bug的岗位 产品需要更多的是软实力 xff0c 把握产品的方向 xff0c 目标用户是谁 xff0c 场景是什么 xff0c 达到怎
  • Mac实用的远程ssh连接工具( Royal TSX安装及使用)

    Mac实用的远程ssh连接工具 Royal TSX安装及使用 1 下载地址 https www royalapps com ts mac download 2 如何连接远程服务器 2 1 首先下载插件Terminal 2 2 然后创建新的D
  • 尝试VC控制外部程序

    这两天尝试VC控制外部程序呢 xff0c 慢慢完善 在参考了网络学习以后 xff0c 简单做了以下工作 xff1a 期间用了spy 43 43 器件 void CVCControlDlg OnStartreader 启动朗读女 TODO A
  • Windows Sever 2012 R2设置组策略对“不显示最后的登录名”选项已启用

    Windows Sever 2012 R2设置组策略对 不显示最后的登录名 选项已启用 作者 xff1a 我道梦 关注我的CSDN博客 xff0c 更多笔记知识还在更新 xff01 设置组策略启用 不显示最后的登录名 后 xff0c 系统将
  • Ubuntu22.04.1 & WIN11 双系统+双硬盘 grub启动项中无WIN11开机引导

    本机UEFI 43 GPT安装的双系统 xff0c 两块固态硬盘 xff0c 两个系统各自使用自己的硬盘分区 xff0c xff08 选择的全盘安装在新硬盘 xff0c 没有自定义分区 xff0c 所以安装的时候也没有提示与当前window

随机推荐

  • tightvnc,tightvnc软件介绍,详细介绍

    tightvnc一款用于windows操作系统的应用软件 xff0c 是一款远程控制软件 出门在外忘了带档案怎么办 xff1f FTP server 上头忘了开帐号怎么办 xff1f 这些麻烦的问题其实都可以靠 VNC 解决 tightvn
  • OpenCore-EFI-配置模版(持续更新)

    前言 随着OpenCore日臻完善 xff0c 将在以后会更多的用于黑苹果的安装 同时 xff0c 在各位大佬的大力支持与推广 xff0c 各种入门 xff0c 进阶教程的推出 xff0c OpenCore已经从神界降临到人间 逐渐为普通黑
  • OpenCore(OC)引导开机声音与图形界面设置

    关键字 xff1a OC xff1b OpenCore xff1b 引导 xff1b 开机声音 xff1b 图形界面 下面的设置基于OpenCore0 5 8 04 10编译版与1 22 0 0版OpenCore Configurator
  • The BMJ研究:现有的新冠病毒诊断AI模型,几乎毫无用处

    图片出处 xff1a unsplash 本文作者 xff1a 朱演瑞 新型冠状病毒对全球健康造成了严重的威胁 xff0c 为了减轻医疗保健系统的负担 xff0c 也给患者提供最佳的护理 xff0c 高效的诊断和疾病预后信息问题亟待解决 理论
  • 06-Docker-Centos 7.2 (Vmware最小化安装)之一篇搞定hyperledger/fabric的e2e_cli测试运行所遇到的ERROR总结

    bug产生原因分析如下 xff1a 1 系统过于单纯或复杂 xff08 即最小化安装与全部安装以及自行安装了很多软件 xff09 xff0c 很多命令和工具无法使用和执行或冲突 2 自己操作失误 xff0c 敲错代码 xff08 关键词和语
  • 秒懂Java之方法引用(method reference)详解

    版权申明 非商业目的注明出处可自由转载 出自 xff1a shusheng007 相关文章 xff1a 秒懂Java之深入理解Lambda表达式 文章目录 概述使用条件使用场景如何使用方法引用的类型调用类的静态方法调用传入的实例参数的方法调
  • 产品设计中关于思考力那些事

    这周的面试 xff0c 对我自己来说 xff0c 更像是一种迭代反思 从做什么怎么做 xff0c 到为什么做 xff0c 的一种强制思考 一方面是入行时间短 xff0c 另一方面是公司产品业务主导 xff0c 相对不需要产品去思考 xff0
  • 永不磨灭的设计模式(有这一篇真够了,拒绝标题党)

    版权申明 非商业目的注明出处可自由转载 出自 xff1a shusheng007 文章目录 概述定义分类创建型 xff08 creational xff09 结构型 xff08 structural xff09 行为型 xff08 beha
  • shusheng007编程手记

    版权申明 非商业目的注明出处可自由转载 出自 xff1a shusheng007 文章目录 概述工具篇IntelliJ IDEA在Idea中下载源码时 xff0c 报无法下载源码 Postman使用Postman发送Post请求服务端报得到
  • SpringBoot如何整合RabbitMQ

    版权申明 非商业目的注明出处可自由转载 出自 xff1a shusheng007 文章目录 概述rabbitmq简介SpringBoot整合安装rabbitmq初级用法高级用法配置交换器与队列发送消息消费消息测试 总结 概述 好久没有写博客
  • 秒懂SpringBoot之@Async如何自定义线程池

    版权申明 非商业目的注明出处可自由转载 出自 xff1a shusheng007 文章目录 概述异步初探线程池ThreadPoolExecutorThreadPoolTaskExecutor 验证线程池配置拒绝策略为AbortPolicy拒
  • 秒懂SpringBoot之参数验证全解析(@Validated与@Valid)

    版权申明 非商业目的注明出处可自由转载 出自 xff1a shusheng007 文章目录 概述实例SpringBoot 验证概述引入依赖使用相关注解标记使用 64 Valid标记统一处理异常 高级用法复杂对象参数验证基本类型参数验证Ser
  • 如何添加本地JAR文件到Maven项目中

    版权申明 非商业目的可自由转载 博文地址 xff1a 出自 xff1a shusheng007 相关文章 xff1a 秒懂Java序列化与反序列化 秒懂 Java注解类型 xff08 64 Annotation xff09 秒懂Java多线
  • 秒懂Java泛型

    版权申明 非商业目的可自由转载 博文地址 xff1a https blog csdn net ShuSheng0007 article details 80720406 出自 xff1a shusheng007 文章目录 概述什么是泛型为什
  • 实际项目中如何使用Git做分支管理

    版权申明 非商业目的注明出处可自由转载 出自 xff1a shusheng007 相关文章 Git日常开发常用命令汇总 文章目录 前言概述Git的基本使用方法使用Git管理项目的方式主分支支持分支总结图 总结 前言 记得刚工作的时候根本不知
  • 秒懂Java代理与动态代理模式

    版权申明 非商业目的可自由转载 博文地址 xff1a https blog csdn net shusheng0007 article details 80864854 出自 xff1a shusheng007 设计模式汇总篇 xff0c
  • 秒懂Java动态编程(Javassist研究)

    版权申明 非商业目的可自由转载 博文地址 xff1a https blog csdn net ShuSheng0007 article details 81269295 出自 xff1a shusheng007 概述什么是动态编程 反射动态
  • B端项目整体设计流程

    一 B端产品的能力图谱 1 逻辑思维与抽象能力 2 技术知识储备 3 复杂项目管理能力 xff1a 沟通能力 执行能力 团队协助能力 组织协调能力 4 业务与经营管理知识 二 B端产品设计流程 1 业务调研 a 明确调研目标 战略层 xff
  • Git日常开发常用命令汇总

    版权申明 非商业目的z注明出处可自由转载 博文地址 xff1a https blog csdn net ShuSheng0007 article details 89642945 出自 xff1a shusheng007 相关文章 实际项目
  • in为什么慢

    IN为什么慢 xff1f 在应用程序中使用子查询后 xff0c SQL语句的查询性能变得非常糟糕 例如 xff1a SELECT driver id FROM driver where driver id in SELECT driver