sql优化的操作

今天公司开了个会,具体的是一个技术交流会,主要针对的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 命令会列出所有的值,并且允许重复

有了以上的这些的规范相信在以后的开发中会少走一些弯路,这是其中的一则后序如果有会继续更新。

猜你喜欢

转载自blog.csdn.net/qq_37256896/article/details/103171854