今天公司开了个会,具体的是一个技术交流会,主要针对的sql优化这方面的,还真是让学到了不少:主要有下面这些
左连接(left join on / left outer join on)
left join 是left outer join的简写,它的全称是左外连接,是外连接中的一种。
左(外)连接,左表(a_table)的记录将会全部表示出来,而右表(b_table)只会显示符合搜索条件的记录。右表记录不足的地方均为NULL
1.用左表的第一行分别和右表的所有行进行联接, 如果有匹配的行,则一起输出,如果右表有多行匹配,则结果集输出多行,如果没有匹配行,则结果集中只输出一行,该输出行左边为左表第一行内容,右边全部输出null
2.然后再用左表第二行和右边所有行进行联接,如果有匹配的行,则一起输出,如果右表有多行匹配,则结果集输出多行, 如果没有匹配行,则结果集中只输出一行,该输出行左边为左表第二行内容,右边全部输出null
3.以此类推,直至左边所有行连接完毕
4.因为右边很可能出现有多行和左边的某一行匹配,所以左联接产生的结果集的行数很可能大于left join左边表的记录的总数
SELECT agencies.*, FROM authentication_user au LEFT JOIN agencies_agencyuser ag ON ag.UserId = au.Id LEFT JOIN agencies_agency agencies ON agencies.Id = ag.AgencyId WHERE au.Email = '[email protected]' //结果: 2019-08-06 11:22:26.497 1BCE1865-970C-4E60-9CE9-63D2D6941F01 0 北大西洋教育 0 9B075BFC-4475-45A5-B6B3-878C3BBED701 2019-08-06 11:22:26.497
可以理解为在在左表+包含的为左连接的即绿色+黄色的模块,即为左连接的结果
右连接(right join/right outer join)
right join是right outer join的简写,它的全称是右外连接,是外连接中的一种。
与左(外)连接相反,右(外)连接,左表(a_table)只会显示符合搜索条件的记录,而右表(b_table)的记录将会全部表示出来。左表记录不足的地方均为NULL
SELECT agencies.* FROM authentication_user au RIGHT JOIN agencies_agencyuser ag ON ag.UserId = au.Id right JOIN agencies_agency agencies ON agencies.Id = ag.AgencyId WHERE au.Email = '[email protected]' //结果: 2019-08-06 11:22:26.497 1BCE1865-970C-4E60-9CE9-63D2D6941F01 0 北大西洋教育 0 9B075BFC-4475-45A5-B6B3-878C3BBED701 2019-08-06 11:22:26.497
这样的结果和左连接的结果一样。
内连接(inner join on)
说明:组合两个表中的记录,返回关联字段相符的记录,也就是返回两个表的交集(阴影)部分。
Innerjoin:即内连接,同时将两表作为参考对象,根据ON后给出的两表的条件将两表连接起来。结果则是两表同时满足ON后的条件的部分才会列出。
select * from a_table a inner join b_table bon a.a_id = b.b_id;
-
JOIN: 如果表中有至少一个匹配,则返回行
-
LEFT JOIN: 即使右表中没有匹配,也从左表返回所有的行
-
RIGHT JOIN: 即使左表中没有匹配,也从右表返回所有的行
-
FULL JOIN: 只要其中一个表中存在匹配,就返回行
//右连接 SELECT column_name(s) FROM table_name1 RIGHT JOIN table_name2 ON table_name1.column_name=table_name2.column_name //左连接 SELECT column_name(s) FROM table_name1 LEFT JOIN table_name2 ON table_name1.column_name=table_name2.column_name // 内连接 SELECT column_name(s) FROM table_name1 INNER JOIN table_name2 ON table_name1.column_name=table_name2.column_name //SELECT INTO 语句从一个表中选取数据,然后把数据插入另一个表中。 //SELECT INTO 语句常用于创建表的备份复件或者用于对记录进行存档。 SELECT Persons.LastName,Orders.OrderNo INTO Persons_Order_Backup FROM Persons INNER JOIN Orders ON Persons.Id_P=Orders.Id_P
SQL SELECT DISTINCT 语句
在表中,可能会包含重复值。这并不成问题,不过,有时您也许希望仅仅列出不同(distinct)的值。
关键词 DISTINCT 用于返回唯一不同的值。
SELECT DISTINCT 列名称 FROM 表名称
优化
优化思路:
-
•去掉不必要的关联
-
•规避or:使用notexists(not exists的执行逻辑,什么情况下适用not exists)
-
•规避distinct:使用exists(exists的执行逻辑是什么?什么情况下适合使用exists)
-
•必要的索引,根据需要建立组合索引
•优化后的确认
-
•结果一致性确认
-
•查看解释计划
-
•执行脚本,比较修改前后脚本第二次执行的时间
-
•改写后执行时间有可能变长,原因:
-
•跟哪些字段建立索引有关系
-
•跟组合索引的字段顺序有关系
-
•跟数据分布有关系,一般来讲,如果过滤条件的筛选小于30%,是不走索引的
使用绑定变量形式不使用拼接sql
绑定变量形式: PreparedStatement pstmt = con.prepareStatement("UPDATE employees SET salay = ? WHERE id = ?"); pstmt.setBigDecimal(1, 15.00); pstmt.setInt(2, 110592); //result statmement: UPDATE employees SET salay = 15.00 WHERE id = 110592 pstmt.executeQuery(); //其实使用 mybatis 我们在不知不觉中就使用量绑定变量的方式执行 sql。这涉及 mybatis 中 ‘#’ 和 ‘$ ‘的区别。mybatis 在对 sql 语句进行预编译之前,会对 sql 进行动态解析,解析为一个 BoundSql 对象,也是在此处对动态 SQL 进行处理的。在动态 SQL 解析阶段, #{ } 和 ${ } 会有不同的表现。比如同一条 sql select * from dual where t = #{test} // #{} 在动态解析的时候, 会解析成一个参数标记符。就是解析之后的语句是: select * from dual where t = ? //这就和 jdbc 绑定变量的方式一样了。而 select * from dual where t = ${test} //${}在动态解析的时候,会将我们传入的参数当做String字符串填充到我们的语句中,就会变成下面的语句 select * from dual where t = '参数' //预编译之前的 SQL 语句已经不包含变量了,完全已经是常量数据了。相当于我们普通没有变量的sql了。 //综上所得, ${ } 变量的替换阶段是在动态 SQL 解析阶段,而 #{ }变量的替换是在 DBMS 中。
什么时候不用绑定变量:
-
a.如果你用数据仓库,一条大查询一跑几个小时,根本没必要做绑定变量,因为解析的消耗微乎其微。
-
b. 变量对优化器产生执行计划有很重要的影响的时候:绑定变量被使用时,查询优化器会忽略其具体值,因此其预估的准确性远不如使用字面量值真实,尤其是在表存在数据倾斜(表上的数据非均匀分布)的列上会提供错误的执行计划。从而使得非高效的执行计划被使用。
使用join,in,还是exists
-
in的使用场景:结果集很小,最好小于百条内
-
join:多对一或者一对一时,可以使用
-
exists:在表数据量较大,选择性较低,关联关系属于一对多时适合用该语法,exits的子查询不返回任何的数据,只是产生逻辑上的真与假,"true","false"
在使用时,select sname,from student where exists (select * from sc where sno=student.sno and cno='1'),这里使用了exists字句,若内层的查询结果为空,则外层的where字句返回真值,否则为假,这里引出子查询用了*因为exists的子查询只返回真与假给出列无实际意义。
union与union all的两点区别是什么
UNION 操作符用于合并两个或多个 SELECT 语句的结果集。
请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。
默认地,UNION 操作符选取不同的值。如果允许重复的值,请使用 UNION ALL。
UNION ALL 命令和 UNION 命令几乎是等效的,不过 UNION ALL 命令会列出所有的值,并且允许重复
有了以上的这些的规范相信在以后的开发中会少走一些弯路,这是其中的一则后序如果有会继续更新。