`
juji1010
  • 浏览: 114875 次
社区版块
存档分类
最新评论

SQL中使用WITH AS提高性能

 
阅读更多
摘要:本文结合笔者实际的工作情况,说明了如何使用with as改写存储过程,从而大幅提高SQL的运行时间。本文首先交代了案例的起因,随后简单介绍了WITH AS的含义,最后基于实际工作,使用了一个测试用例来说明如何使用WITH AS。

1. 案例起因
    公司门店应用程序每天都要出一份报表,用来统计所有商品当天的期初库存数量、入库数量、出库数量
及当天的期末库存数量。运行半年以后,这份报表运行越来越慢,到现在,每次运行该报表显示当天数据时需要近20秒的时间。于是开发人员找到我,希望我看看,是不是可以使该报表运行的时间更短。
该报表就是一段SQL语句,主要由三部分组成,第一部分是计算每个商品的期初数量,第二部分是计算每个商品的当天发生(包括入库和出库的)数量,第三部分是计算每个商品的期末数量,也就是当天的余额。每个部分使用UNION ALL连接起来。
我看到该报表,第一个感觉就是这段SQL里的每个部分都要对表进行扫描,明显成本过高。应该可以使用WITH AS进行改写。

2. WITH AS的含义
    WITH AS短语,也叫做子查询部分(subquery factoring),可以让你做很多事情,定义一个SQL片断,该SQL片断会被整个SQL语句所用到。有的时候,是为了让SQL语句的可读性更高些,也有可能是在UNION ALL的不同部分,作为提供数据的部分。
特别对于UNION ALL比较有用。因为UNION ALL的每个部分可能相同,但是如果每个部分都去执行一遍的话,则成本太高,所以可以使用WITH AS短语,则只要执行一遍即可。如果WITH AS短语所定义的表名被调用两次以上,则优化器会自动将WITH AS短语所获取的数据放入一个TEMP表里,如果只是被调用一次,则不会。而提示materialize则是强制将WITH AS短语里的数据放入一个全局临时表里。很多查询通过这种方法都可以提高速度。
3. 案例说明
  首先介绍该SQL所涉及到的主要的表的结构。该表表名为fin,用来存放每天每个商品的发生数以及该商
品的余额数。其表结构为如下所示(这里我只选取了与我们要讨论的SQL相关的部分表字段)。
SQL> desc fin
名称 是否为空? 类型
----------------------------------------- -------- ----------------------------
。。。。。。
DAY DATE
SKU VARCHAR2(8)
INQTY NUMBER(16,6)
OUTQTY NUMBER(16,6)
LASTQTY NUMBER(16,6)
。。。。。。。。

简单解释一下各个字段的含义:
1) DAY:发生的日期。
2) SKU:发生交易的商品代码。
3) INQTY:商品入库数量。
4) OUTQTY:商品出库数量。
5) LASTQTY:商品的余额数量。

该表中含有的记录数量为:
SQL> SELECT count(*) FROM fin;

COUNT(*)
----------
4729319
原来的SQL如下所示(比如查询2003年7月14日这天的记录。当然,我对该SQL做了些修改,去掉了与本文讨论无关的部分,比如显示商品名称之类的部分等):
SELECT
sku,
sum(initqty) as initqty,
sum(inqty) as inqty,sum(outqty) as outqty,
sum(lastqty) as lastqty
FROM (
SELECT sku,lastqty as initqty,0 as inqty,0 as outqty,0 as lastqty
FROM fin
WHERE day=to_date('20030713','yyyymmdd')
UNION ALL
SELECT sku,0 as initqty,inqty,outqty,0 as lastqty
FROM fin
WHERE day>=to_date('20030714','yyyymmdd') and day<=to_date('20030714','yyyymmdd')
UNION ALL
SELECT sku,0 as initqty,0 as inqty,0 as outqty,lastqty
FROM fin
WHERE day=to_date('20030714','yyyymmdd')
)
GROUP BY sku;

我们来看该SQL所花费的时间为:
SQL> set timing on
SQL> /
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
SKU INITQTY INQTY OUTQTY LASTQTY
-------- ---------- ---------- ---------- ----------
00106162 0 0 12 60
00106467 0 20 10 60
已选择956行。

已用时间: 00: 00: 19.08

然后,我们来对该SQL进行改写一番,如下所示:
WITH result AS (
SELECT /*+ materialize */ day,sku,inqty,outqty,lastqty
FROM fin
WHERE day>=to_date('20030713','yyyymmdd') AND day<=to_date('20030714','yyyymmdd'))
SELECT
sku,
sum(initqty) as initqty,
sum(inqty) as inqty,
sum(outqty) as outqty,
sum(lastqty) as lastqty
FROM (
SELECT sku,lastqty as initqty,0 as inqty,0 as outqty,0 as lastqty
FROM result
WHERE day=to_date('20030713','yyyymmdd')
UNION ALL
SELECT sku,0 as initqty,inqty,outqty,0 as lastqty
FROM result
WHERE day=to_date('20030714','yyyymmdd')
UNION ALL
SELECT sku,0 as initqty,0 as inqty,0 as outqty,lastqty
FROM result
WHERE day=to_date('20030714','yyyymmdd')
)
GROUP BY sku;

我们来看修改后的SQL所花费的时间为:
SQL> set timing on
SQL> /
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
SKU INITQTY INQTY OUTQTY LASTQTY
-------- ---------- ---------- ---------- ----------
00106162 0 0 12 60
00106467 0 20 10 60
已选择956行。

已用时间: 00: 00: 06.06

从这里可以看到,通过WITH AS可以从20秒降低到6秒,几乎提高了65%的性能。


分享到:
评论

相关推荐

    经典SQL语句大全

    在SQLServer中分组时:不能以text,ntext,image类型的字段作为分组依据 在selecte统计函数中的字段,不能和普通的字段放在一起; 13、对数据库进行操作: 分离数据库: sp_detach_db; 附加数据库:sp_attach_db 后...

    微软内部资料-SQL性能优化2

    Although 2 GB of address space may seem like a large amount of memory, application such as SQL Server could leverage more memory if it were available. The boot.ini option /3GB was created for those ...

    微软内部资料-SQL性能优化3

     Differentiate locks, latches, and other SQL Server internal “locking” mechanism such as spinlocks and other synchronization objects. Recommended Reading  Chapter 14 “Locking”, Inside SQL ...

    Microsoft SQL Server 2005 Express Edition SP3

    如果已在安装过程中使用了默认的命名实例,则将实例指定为“SQLExpress”。 [顶部] 2.3 管理 SQL Server Express 的工具 有关连接到 SQL Server Express 数据库并进行管理的信息,请参阅 Microsoft 知识库文章 ...

    微软内部资料-SQL性能优化5

    Just as the organization of a telephone directory makes it easy for a person to search, SQL Server quickly searches a table with a clustered index. Because a clustered index determines the sequence ...

    PL/SQL Developer 6.05注册版-1

    这样,如果需要编译所有工程条目或者将工程从某个位置或数据库移动到其他位置时,所需工程条目的查找就变得比较简单, &lt;br&gt;To-Do条目——您可以在任何SQL或PL/SQL源文件中使用To-Do条目快速记录该文件中那些需要...

    sql2005全文检索.doc

    为了提升全文索引过程的效率,Microsoft SQL Server 2005 改进了全文收集机制的体系结构,从而大大增强了性能。 Microsoft Full-Text Engine for SQL Server (MSFTESQL) 服务是一个全文索引和搜索引擎。MSFTESQL ...

    PL/SQL Developer 7.1.5 注册版-3

    这样,如果需要编译所有工程条目或者将工程从某个位置或数据库移动到其他位置时,所需工程条目的查找就变得比较简单, &lt;br&gt;To-Do条目——您可以在任何SQL或PL/SQL源文件中使用To-Do条目快速记录该文件中那些需要...

    SQL培训第一期

    存储过程是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中。用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。 1.9.2 准备 create table t_user ( username varchar2(20), ...

    PL/SQL Developer 7.1.5 注册版

    这样,如果需要编译所有工程条目或者将工程从某个位置或数据库移动到其他位置时,所需工程条目的查找就变得比较简单, &lt;br&gt;To-Do条目——您可以在任何SQL或PL/SQL源文件中使用To-Do条目快速记录该文件中那些需要...

    2009达内SQL学习笔记

    ORDER BY子句中使用的列将是为显示所选择的列,但是实际上并不一定要这样,用非检索的列排序数据是完全合法的。 为了按多个列排序,列名之间用逗号分开。 2、支持按相对列位置进行排序。 输入 SELECT prod_id,...

    sql经典语句一部分

    在SQLServer中分组时:不能以text,ntext,image类型的字段作为分组依据 在selecte统计函数中的字段,不能和普通的字段放在一起; 13、对数据库进行操作: 分离数据库: sp_detach_db; 附加数据库:sp_attach_db 后...

    数据库操作语句大全(sql)

    在SQLServer中分组时:不能以text,ntext,image类型的字段作为分组依据 在selecte统计函数中的字段,不能和普通的字段放在一起; 13、对数据库进行操作: 分离数据库: sp_detach_db; 附加数据库:sp_attach_db ...

    存储过程的安全及性能优化

     尽量避免使用游标,游标效率很差,如果使用游标就不要在游标的循环中使用表连接操作  注意where语句的写法,应该根据索引的顺序、范围的顺序、范围的大小来确定条件子句的前后顺序,尽量让字段顺序与索引顺序...

    数据库原理编程与性能第2版 中文版附答案

     elizabeth o'neil is a professor of computer science at the university of massachusetts at boston.she serves as a comsult-ant to sybase iqin concor, massachusetts,and has worked with a number of ...

    使用SqlServer CTE递归查询处理树、图和层次结构

    使用CTE能改善代码可读性,且不损害其性能。 递归CTE是SQL SERVER 2005中重要的增强之一。一般我们在处理树,图和层次结构的问题时需要用到递归查询。 CTE的语法如下 WITH CTE AS ( SELECT EmpId, ReportTo, ...

    qsv - 通过 SQL 查询 CSV 的高性能 CLI 工具

    QSV通过 SQL 查询 CSV 的高性能 CLI 工具安装克隆存储库后,您可以使用cargo install --path .在本地安装二进制文件cargo install --path .特征用途/特点目的是使用 CSV 作为数据源支持所有 SQLite 语法,包括:连接...

    SQL处理多级分类,查询结果呈树形结构

    如果用SQL下面的CTE递归处理的话,一次性就能把结果给查询出来,而且性能很不错 比用程序处理(数据量很大的情况),临时表性能更好,更方便 代码如下: with area as( select *,id px,cast(id as nvarchar(4000)) ...

    Mastering The Faster Web with PHP, MySQL, and JavaScript 1st pdf

    Grasp modern SQL techniques to optimize complex SQL queries Identify and simplify overly complex JavaScript code Explore and implement UI design principles that effectively enhance the performance ...

Global site tag (gtag.js) - Google Analytics