left join 改写标量子查询

数据库环境:SQL SERVER 2005

  有一博彩的赔率是1:20,它有2张业务表:smuchs(投注表),lottery(开奖表)。

smuchs表有3个字段,分别是sno(投注号码)、smuch(投注金额),stime(投注时间),

lottery表有2个字段,分别是lno(开奖号码)、stime(开奖时间)。smuchs表和lottery表的数据如下:

     

  要求:根据每天的投注情况和开奖号码,统计指定日期的投注金额、中奖应支付金额、盈亏金额。

  1.建表,导入模拟数据

CREATE TABLE smuchs (sno INT,smuch INT,stime DATETIME)
INSERT into smuchs values(23,100,‘2015-09-01 09:10:11‘);
INSERT into smuchs values(02,2,‘2015-09-01 12:23:28‘);
INSERT into smuchs values(18,4,‘2015-09-01 14:02:34‘);
INSERT into smuchs values(32,60,‘2015-09-01 14:10:58‘);
INSERT into smuchs values(10,26,‘2015-09-02 10:57:24‘);
INSERT into smuchs values(27,12,‘2015-09-02 15:42:34‘);
INSERT into smuchs values(03,14,‘2015-09-02 16:12:58‘);
INSERT into smuchs values(19,18,‘2015-09-03 17:23:24‘);
INSERT into smuchs values(14,30,‘2015-09-03 17:25:12‘);
INSERT into smuchs values(02,90,‘2015-09-01 18:02:34‘);
CREATE TABLE lottery(lno INT,ltime DATETIME)
INSERT INTO lottery VALUES(18,‘2015-09-01 21:00:00‘)
INSERT INTO lottery VALUES(09,‘2015-09-02 21:00:00‘)
INSERT INTO lottery VALUES(14,‘2015-09-03 21:00:00‘)

  2.标量实现

SELECT  stime ,
        smuch ,
        ISNULL(lmuch, 0) AS lmuch ,
        smuch - ISNULL(lmuch, 0) slmuch
FROM    ( SELECT    CONVERT(VARCHAR(10), sh.stime, 121) AS stime ,
                    SUM(sh.smuch) AS smuch ,
                    20
                    * ( SELECT  SUM(smuch)
                        FROM    smuchs
                                INNER JOIN lottery ON lottery.lno = smuchs.sno
                                                      AND CONVERT(VARCHAR(10), lottery.ltime, 121) = CONVERT(VARCHAR(10), smuchs.stime, 121)
                                                      AND CONVERT(VARCHAR(10), sh.stime, 121) = CONVERT(VARCHAR(10), smuchs.stime, 121)
                      ) AS lmuch
          FROM      smuchs sh
          GROUP BY  CONVERT(VARCHAR(10), sh.stime, 121)
        ) t

  

  这是某网友的实现方法,我们可以看到,smuchs表被扫描了4次,lottery表被访问了3次。通过

查看执行计划,发现外部表和子查询部分走的是嵌套循环。如果数据很多,这个SQL的查询速度会比较慢。

  3.left join实现

/*合计每个号码的投注金额*/
WITH    x0
          AS ( SELECT   sh.sno ,
                        SUM(sh.smuch) AS smuch ,
                        CONVERT(VARCHAR(10), sh.stime, 121) AS stime
               FROM     smuchs sh
               GROUP BY sno ,
                        CONVERT(VARCHAR(10), sh.stime, 121)
             ),
        x1
          AS ( SELECT   sh.sno ,
                        sh.smuch ,
                        sh.stime ,
                        ly.lno
               FROM     x0 sh
                        LEFT JOIN lottery ly ON ly.lno = sh.sno
                                                AND CONVERT(VARCHAR(10), ly.ltime, 121) = sh.stime
             ),
        x2
          AS ( SELECT   stime ,
                        SUM(smuch) AS smuch ,--统计所有投注金额
                        20 * SUM(CASE WHEN lno IS NOT NULL THEN smuch
                                 END) AS lmuch--统计中奖应付金额
               FROM     x1
               GROUP BY stime
             )
    SELECT  stime ,
            smuch ,
            ISNULL(lmuch, 0) AS lmuch ,
            smuch - ISNULL(lmuch, 0) slmuch
    FROM    x2

  通过left join改写,lottery表和smuchs表均只被扫描1次。

  统计的结果如图:

(本文完)

时间: 2024-10-15 06:10:32

left join 改写标量子查询的相关文章

标量子查询

--标量子查询select e.empno, e.ename, e.sal, e.deptno,       (select d.dname from dept d where e.deptno = d.deptno)as dname  from emp e--插入一条数据insert into emp(empno,deptno) values(9999,null)--返回结果15条记录--改成left join(hash outer)select e.empno, e.ename, e.sal

优化有标量子查询的SQL

数据库环境:SQL SERVER 2008R2 今天在数据库中抓出一条比较耗费资源的SQL,只返回904条数据,居然跑了40多分钟.SQL及对应的数据量如下图: SELECT saft04.cur_year , LEFT(saft04.dept_id, 4) sdept_id , saft04.vdept_id , saft04.dept_id , saft04.fee_id , saft04.vitem_id , ISNULL(saft04.fee_amt, 0) AS saft04_fee_

Oracle sql优化之分析函数优化标量子查询

待优化语句如下 select a.code as code, a.m_code as m_code,a.stktype as f_stype,a.e_year as e_year, b.sname as sname,a.c_date as c_date,to_char(sysdate,'YYYYMMDD') as createtime, to_char(sysdate,'YYYYMMDD') as updatetime, (select sum(valuef2) from a t where t

oracle标量子查询

SQL> conn scott/scott Connected. SQL> create table a (id int,name varchar2(10)); Table created. SQL> create table b (id int,name varchar2(10)); Table created. SQL> insert into a values(1,'a1'); 1 row created. SQL> insert into a values(2,'a2

彻底搞懂oracle的标量子查询

oracle标量子查询和自定义函数有时用起来比较方便,而且开发人员也经常使用,数据量小还无所谓,数据量大,往往存在性能问题. 以下测试帮助大家彻底搞懂标量子查询. SQL> create table a (id int,name varchar2(10)); Table created. SQL> create table b (id int,name varchar2(10)); Table created. SQL> insert into a values (1,'a1'); 1

SQL Server的优化器会缓存标量子查询结果集吗

在这篇博客"ORACLE当中自定义函数性优化浅析"中,我们介绍了通过标量子查询缓存来优化函数性能: 标量子查询缓存(scalar subquery caching)会通过缓存结果减少SQL对函数(Function)的调用次数, ORACLE会在内存中构建一个哈希表来缓存标量子查询的结果. 那么SQL Server的优化器是否也会有类似这样的功能呢? 抱着这样的疑问,动手测试了一下,准备测试环境 CREATE TABLE TEST (    ID  INT );     DECLARE

mysql 标量子查询和非法子查询

#where或having后面:#标量子查询(单行子查询)#列子查询(多行子查询)#行子查询(多行多列) 特点:子查询放在小括号内,一般放在条件的右侧,标量子查询一般配备单行操作符使用单行操作符:<> >= <= < >列子查询:一般搭配着多行操作符使用多行操作符:in.any.some.all #标量子查询#案例:谁的工资比ABEL高的员工信息 SELECT * FROM employees WHERE salary>( SELECT salary FROM e

hive用left semi join替代in子查询的方式

执行如下hive sql: select * from trackinfo where ds=$date and session_id in (select session_id from rcmd_track_path where ds=$date and add_cart_flag>0 and product_id>0);</span> 提示报错如下: FAILED: ParseException line 2:39 cannot recognize input near 's

优化更新语句中的标量子查询

数据库环境:SQL SERVER 2008R2 今天看到开发写的一条更新语句,第一眼是觉得这个SQL的业务有问题,再细看子查询部分,才意识到这是开发人员使的“怪招”. 这个SQL能满足业务的需要,只是开发人员在写这个SQL的时候应该不会考虑到存在性能问题.具体SQL如下: UPDATE fapply_04 SET conf_y_fee_amt = ISNULL(conf_y_fee_amt, 0) + ISNULL(( SELECT SUM(fexp_03.opr_amt) FROM fexp_