首先我们先明确一下sql语句的执行顺序,如下有前至后执行:

(1)from  (2) on   (3) join  (4) where  (5)group by  (6) avg,sum...  (7)having  (8) select  (9) distinct  (10) order by

1、独立子查询

独立子查询:顾名思义:就是子查询和外层查询不存在任何联系,是独立于外层查询的:
下面就看一个例子:
有一张订单表 Sales.Order 和一张 客户表
Sales.Customer
下面的sql 语句是为了查询出Sales.Customer里 custid(用户id)不在
Sales.Order 的custid

select custid
from [Sales.Customers]
where custid not in
(
select custid
from [Sales.Orders]
)

2、相关子查询

顾名思义:就是子查询里面的条件依赖于外层查询的数据
下面我再来举一个例子:
业务要求:查询出每个客户的订单的数量:

select distinct custid,
(
select COUNT(*)
from [Sales.Orders]
--相关子查询:依赖于外层查询结果;;是外层和内层相互结合的操作
where [Sales.Orders].custid=[Sales.Customers].custid
) as orderNum
from [Sales.Customers]

查询的结果:

所以我们不难看出:相关子查询比独立子查询实现的功能强大的多

但是复杂度也会有提升,相当于笛卡尔积

3、案例演示

一个我之前开发时候写过的错误案例

SELECT
DISTINCT m.id AS PolicyId,
m.PolicyNo,
m.PolicyType,
m.PolicyStartTime,
m.PolicyEndTime,
m.BelogOrganizationName,
CASE
( SELECT count( 0 ) FROM policy_people AS b WHERE b.ProposalNo = m.ProposalNo AND b.Relation = 2 )
WHEN 1 THEN
( SELECT GROUP_CONCAT( b.`Name` ) FROM policy_people AS b WHERE b.ProposalNo = m.ProposalNo AND b.Relation = 2 ) ELSE
concat(
( SELECT b.NAME FROM policy_people AS b WHERE b.ProposalNo = m.ProposalNo AND b.Relation = 2 LIMIT 1 ),",",(SELECT b.NAME FROM policy_people AS b WHERE b.ProposalNo = m.ProposalNo AND b.Relation = 2 LIMIT 1,1 ),'等'
)
END AS InsuredPeople,
( SELECT count( 0 ) FROM report WHERE report.ProposalNo = m.ProposalNo ) AS CompenCount
FROM
policy_people AS p
INNER JOIN policy_index AS m ON p.ProposalNo = m.ProposalNo
WHERE
p.Relation = 1
AND p.CertificateNo = "57016086-6

注意这个语句中的子查询,CASE嵌套了一层子查询,之后还用后面的逻辑继续执行子查询。再加上使用了distinct ,很容易造成选出过多的数据,执行过多的无效子查询,最后被distinct筛选掉。

暴力测试数据量上w之后,上面的语句执行时间长达几十秒。

优化之后的修改,首先时使用group by代替了distinct,因为sql执行顺序的问题。distinct的级别很低,会造成先去选取数据,然后再去distinct,所以尽量去用group by而不是distinct

然后将子查询中过多的逻辑放到逻辑层去解决,而不是再sql中强行使用。

优化后的sql

SELECT
m.ProposalNo,
ANY_VALUE ( m.PolicyNo ) AS PolicyNo,
ANY_VALUE ( m.PolicyType ) AS PolicyType,
ANY_VALUE ( m.PolicyStartTime ) AS PolicyStartTime,
ANY_VALUE ( m.PolicyEndTime ) AS PolicyEndTime,
ANY_VALUE ( m.BelogOrganizationName ) AS BelogOrganizationName,
d.InsuredPeople,
d.InsuredPeolpleCount,
( SELECT count( 0 ) FROM report WHERE report.ProposalNo = p.ProposalNo ) AS CompenCount
FROM
policy_people AS p
INNER JOIN policy_index AS m ON p.ProposalNo = m.ProposalNo
INNER JOIN
(SELECT GROUP_CONCAT( b.NAME ) AS InsuredPeople,count( 1 ) AS InsuredPeolpleCount,b.ProposalNo FROM policy_people AS b WHERE b.Relation = 2 GROUP BY b.ProposalNo ) AS d
ON p.ProposalNo = d.ProposalNo
WHERE
p.Relation = 1
AND p.CertificateNo = ? certificateNo
AND m.PolicyStartTime >? YEAR
GROUP BY
p.ProposalNo
LIMIT ? pagebegin,? pageend

使用了三表联查,减少了子查询,效率大幅提升,目前已经可以满足几十万级别的数据量,等项目运作一段时间后,再继续考虑是否进一步优化。

SQL夯实基础(四):子查询及sql优化案例的更多相关文章

  1. SQL Server 基础:子查询

    1.子查询的概念:子查询就是嵌套在主查询中的查询.子查询可以嵌套在主查询中所有位置,包括SELECT.FROM.WHERE.GROUP BY.HAVING.ORDER BY.2.子查询的分类:2.1按 ...

  2. SQL夯实基础(九)MySQL联接查询算法

    书接上文<SQL夯实基础(八):联接运算符算法归类>. 这里先解释下EXPLAIN 结果中,第一行出现的表就是驱动表(Important!). 对驱动表可以直接排序,对非驱动表(的字段排序 ...

  3. 优化有标量子查询的SQL

    数据库环境:SQL SERVER 2008R2 今天在数据库中抓出一条比较耗费资源的SQL,只返回904条数据,居然跑了40多分钟.SQL及对应的数据量如下图: SELECT saft04.cur_y ...

  4. 在论坛中出现的比较难的sql问题:40(子查询 销售和历史库存)

    原文:在论坛中出现的比较难的sql问题:40(子查询 销售和历史库存) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所以,觉得有 ...

  5. 在论坛中出现的比较难的sql问题:7(子查询 判断某个字段的值是否连续)

    原文:在论坛中出现的比较难的sql问题:7(子查询 判断某个字段的值是否连续) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所以 ...

  6. MySQL之多表查询一 介绍 二 多表连接查询 三 符合条件连接查询 四 子查询 五 综合练习

    MySQL之多表查询 阅读目录 一 介绍 二 多表连接查询 三 符合条件连接查询 四 子查询 五 综合练习 一 介绍 本节主题 多表连接查询 复合条件连接查询 子查询 首先说一下,我们写项目一般都会建 ...

  7. mysql in 子查询 效率慢 优化(转)

    mysql in 子查询 效率慢 优化(转) 现在的CMS系统.博客系统.BBS等都喜欢使用标签tag作交叉链接,因此我也尝鲜用了下.但用了后发现我想查询某个tag的文章列表时速度很慢,达到5秒之久! ...

  8. MySQL的一次优化记录 (IN子查询和索引优化)

    这两天实习项目遇到一个网页加载巨慢的问题(10多秒),然后定位到是一个MySQL查询特别慢的语句引起的: SELECT * FROM ( SELECT DISTINCT t.vc_date, t.c_ ...

  9. 记一次mysql多表查询(left jion)优化案例

    一次mysql多表查询(left jion)优化案例 在新上线的供需模块中,发现某一个查询按钮点击后,出不来结果,找到该按钮对应sql手动执行,发现需要20-30秒才能出结果,所以服务端程序判断超时, ...

随机推荐

  1. c# 内部类使用接口IComparer实现排序

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  2. I.MX6Q(TQIMX6Q/TQE9)学习笔记——U-Boot移植

    其实Freescale的BSP移植文档已经将u-boot的移植步骤讲述的非常详细了,但为了以后方便查阅,还是按照自己的理解记录在这里. 获取源码 根据前一篇文章搭建好LTIB环境后就可以非常方便的导出 ...

  3. [NOI2008]奥运物流

    题目 洛谷 BZOJ 做法 单环有向图毒瘤题 不考虑环和改变后继:\(\sum\limits{i=1}^n C_i\cdot K^{dep(i)}\) 考虑环无穷等比求极m:\(R(1)=\sum\l ...

  4. 20145230《java学习笔记》第七周学习总结

    20145230 <Java程序设计>第7周学习总结 教材学习内容 Lambda语法概览 我们在许多地方都会有按字符串长度排序的需求,如果在同一个方法内,我们可以使用一个byName局部变 ...

  5. 20145240 《Java程序设计》第五周学习总结

    20145240 <Java程序设计>第五周学习总结 教材学习内容总结 语法与继承结构 8.1.1使用try.catch java中所有的错误都会被打包为对象,并提供了特有的语句进行处理. ...

  6. jprofile查看hprof文件[转]

    用jprofile打开hprof文件,查看内存泄露情况,有几个常用的功能说明一下: 工具下载:到官网下载jprofile7.0.1 64位的.再申请一个注册号,注册号的申请好像是一个邮件只能用一次. ...

  7. SEM竞价数据基本分析方法

    今天我们从账户数据表现来看一看怎样通过数据分析,判断账户出现的问题及解决思路.也欢迎大家提出意见,共同讨论进步. 首先我们从关键词报告来分析数据: 以上图数据为例.(设定该行业CPC均价为8) 先说下 ...

  8. struts2中常用配置

    1.Post提交乱码问题,如果编码采用的是utf-8,那么默认不需要自己处理,因为其默认的常量配置文件就是处理UTF-8的 这个常量值只处理POST提交,get如果乱码还得自己写拦截器处理,一般只要页 ...

  9. Luogu-3222 [HNOI2012]射箭

    几何题,二次函数,化一下式子吧 设二次函数\(y=ax^2+bx\),对于一个线段\((x,y1)\),\((x,y2)\),与他相交的条件是\(y1<=ax^2+bx<=y2\) 对于\ ...

  10. maven 内置属性有哪些?该如何使用?

    maven 共有6类内置属性: 内置属性(maven预定义,用户可以直接使用的) ${basedir}表示项目的根目录,既包含pom.xml文件的目录: ${version}表示项目版本: ${pro ...