SQL优化案例—— RowNumber分页
将业务语句翻译成SQL语句不仅是一门技术,还是一门艺术。
下面拿我们程序开发工程师最常用的ROW_NUMBER()分页作为一个典型案例来说明。
先来看看我们最常见的分页的样子:
WITH CTE AS(
SELECT ROW_NUMBER() OVER ( ORDER BY (A.CreateTime ) AS OrderNo ,
Table_A.ID , --主键
Table_A.其它字段
FROM Table_A WITH ( NOLOCK )
WHERE RecID = 220051
)
SELECT * FROM CTE
WHERE OrderNo BETWEEN 1 AND 50;的确,这样的写法很符合我们的思维逻辑,并且我们在RecID上建立非聚集索引,那么它的效率看上去也是不错的。当然根据这条SQL,最佳索引实践应该是:
CREATE INDEX IX_Table_A_RecID_CreateTime_Inc
ON Table_A(RecID,CreateTime)
INCLUDE(Table_A.其它字段)但是,这真的是最佳的了吗?当SQL的Where条件变多,Table_A.其它字段变得越来越多,OVER()子句中的OrderBy字段越来越多或者变成Order By ColumnA/ColumnB这样的计算表达式,这条语句变得越来越不堪重负,最终性能问题凸现出来,另外,作为DBA,我们总是尽量维持索引的简单性、可重用度,而不想建立成为某个语句专用的索引。举例来说,在Include中,我们总不能把Table_A.其它字段中的所有字段都放进去吧,个数少还行,如果遇上几十个字段或者有大容量字符字段,维护成本将大大增加,那将是我们不愿意看到的。
这个时候就要求我们看看是否能对语句做出一些优化了。在上面的SQL中,我们看它的执行计划,我已经建立了索引,该索引并未Include SELECT列表中的其它字段:CREATE INDEX IX_Table_A_RecID_CreateTime_Inc
ON Table_A(RecID,CreateTime)
根据上图的执行计划,可以看到,WHERE条件走的是我刚刚建立的索引,下面的键查找与其并行,我们先不讨论该执行计划的具体细节,下面我们来设想几个问题:
在WHERE条件简单,并且索引合适,统计信息正确的前提下,SQL Server可以很容易获得那50行,并且回到聚集索引中找到属于它的其它字段的数据,这是SQL Server的智能编译的结果,也是我们希望看到的返回方式。
但是,在WHERE条件较为复杂,多个WHERE条件均为范围字段或者状态字段时,执行计划也许并没有我们想象的那么智能了,比如它可能采用这样的方式:
当SQL Server无法准确的取出你要的那些行时,那么它便会取回全部的行数后,再去聚集索引中找回属于它的其它字段的数据,当where条件可以返回几十万数据时,你可以想象它的效率有多低,它会仍然使用上文中类似的执行计划,这显然不是我们希望看到的。
我们想看到的是什么?
1、根据WHERE条件和排序规则,先取出那50条数据所属的主键。
SELECT ROW_NUMBER() OVER ( ORDER BY A.CreateTime ) AS OrderNo ,
Table_A.ID --主键
INTO #1
FROM Table_A WITH ( NOLOCK )
WHERE RecID = 220051
2、利用上个步骤中返回的主键,去原始表取回这50条记录的其它字段数据。
SELECT B.*,A.其它字段 FROM Table_A A WITH ( NOLOCK )
INNER JOIN #1 B ON A.ID=B.ID
WHERE B.OrderNo BETWEEN 1 AND 50;
那么,上面两个步骤合在一起:
WITH CTE AS(
SELECT ROW_NUMBER() OVER ( ORDER BY A.CreateTime ) AS OrderNo ,
Table_A.ID --主键
FROM Table_A WITH ( NOLOCK )
WHERE RecID = 220051
)
SELECT CTE.*,A.其它字段 FROM Table_A A WITH ( NOLOCK )
INNER JOIN CTE ON A.ID=CTE.ID
WHERE CTE.OrderNo BETWEEN 1 AND 50;
很好,现在我们再来看一下这个SQL的执行计划:
Binggo!这才是我们理想中的样子!
针对这个SQL,我们只需要建立一个合适的索引,而不用顾忌SELECT列表中那些烦人的其它列,因为他们回聚集索引取数据,也不过几百个IO而已(需要返回的行数*Index_Level)。它不需要再为过期的统计信息或者错误的执行计划而付出沉重的代价!
总结:SQL优化,是一门艺术。
SQL优化案例—— RowNumber分页的更多相关文章
- C# SQL优化 及 Linq 分页
每次写博客,第一句话都是这样的:程序员很苦逼,除了会写程序,还得会写博客!当然,希望将来的一天,某位老板看到此博客,给你的程序员职工加点薪资吧!因为程序员的世界除了苦逼就是沉默.我眼中的程序员大多都不 ...
- mysql的sql优化案例
前言 mysql的sql优化器比较弱,选择执行计划貌似很随机. 案例 一.表结构说明mysql> show create table table_order\G***************** ...
- SQL 优化案例 1
create or replace procedure SP_GET_NEWEST_CAPTCHA( v_ACCOUNT_ID in VARCHAR2, --接收短信的手机号 v_Tail_num i ...
- SQL 优化案例
create or replace procedure SP_GET_NEWEST_CAPTCHA( v_ACCOUNT_ID in VARCHAR2, --接收短信的手机号 v_Tail_num i ...
- SQL夯实基础(四):子查询及sql优化案例
首先我们先明确一下sql语句的执行顺序,如下有前至后执行: (1)from (2) on (3) join (4) where (5)group by (6) avg,sum... (7 ...
- [MySQL优化案例]系列 — 分页优化
通常,我们会采用ORDER BY LIMIT start, offset 的方式来进行分页查询.例如下面这个SQL: SELECT * FROM `t1` WHERE ftype=1 ORDER BY ...
- 数栈SQL优化案例:隐式转换
MySQL是当下最流行的关系型数据库之一,互联网高速发展的今天,MySQL数据库在电商.金融等诸多行业的生产系统中被广泛使用. 在实际的开发运维过程中,想必大家也常常会碰到慢SQL的困扰.一条性能不好 ...
- sqlserver sql优化案例及思路
始sql: SELECT TOP 100 PERCENT ZZ.CREW_NAME AS 机组, ZZ.CREW_ID, AA.年度时间, CC.当月时间, DD.连续七天时间 AS 最近七天 FRO ...
- 百倍性能的PL/SQL优化案例(r11笔记第13天)
我相信你是被百倍性能的字样吸引了,不过我所想侧重的是优化的思路,这个比优化技巧更重要,而结果嘛,其实我不希望说成是百倍提升,“”自黑“”一下. 有一个真实想法和大家讨论一下,就是一个SQL语句如果原本 ...
随机推荐
- Recurrent Neural Network系列1--RNN(循环神经网络)概述
作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! 本文翻译自 RECURRENT NEURAL NETWORKS T ...
- 深入理解DIP、IoC、DI以及IoC容器
摘要 面向对象设计(OOD)有助于我们开发出高性能.易扩展以及易复用的程序.其中,OOD有一个重要的思想那就是依赖倒置原则(DIP),并由此引申出IoC.DI以及Ioc容器等概念.通过本文我们将一起学 ...
- JS里面Data日期格式转换
var format = function(time, format){ var t = new Date(time); var tf = function(i){return (i ...
- 【SQLServer】记一次数据迁移-标识重复的简单处理
汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 今天在数据迁移的时候因为手贱遇到一个坑爹问题,发来大家乐乐,也传授新手点经验 迁移惯用就 ...
- WebForm获取GET或者POST参数到实体的转换,ADO.NET数据集自动转换实体
最近在修改维护以前的webform项目(维护别人开发的.....)整个aspx没有用到任何的控件,这个我也比较喜欢不用控件所以在提交信息的时候需要自己手动的去Request.QueryString[] ...
- c#多线程
一.使用线程的理由 1.可以使用线程将代码同其他代码隔离,提高应用程序的可靠性. 2.可以使用线程来简化编码. 3.可以使用线程来实现并发执行. 二.基本知识 1.进程与线程:进程作为操作系统执行程序 ...
- AFNetworking 3.0 源码解读 总结(干货)(下)
承接上一篇AFNetworking 3.0 源码解读 总结(干货)(上) 21.网络服务类型NSURLRequestNetworkServiceType 示例代码: typedef NS_ENUM(N ...
- Android—ListView条目背景为图片时,条目间距问题解决
ListView是android开发中使用最普遍的控件了,可有的listView条目的内容颇为丰富,甚至为了美观,背景用指定图片,如下图:
- Java 中获取类路径 classpath 的方法
System.out.println("++++++++++++++++++++++++"); String path = System.getProperty("jav ...
- Mysql 忘记root密码处理办法
一.更改my.cnf配置文件 1.用命令编辑/etc/my.cnf配置文件,即:vim /etc/my.cnf 或者 vi /etc/my.cnf 2.在[mysqld]下添加skip-grant-t ...