随笔 - 120, 文章 - 1, 评论 - 166, 阅读 - 19万
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

Query Hint FAST number_rows 改变SQL Server 执行计划

Posted on   nzperfect  阅读(1253)  评论(2编辑  收藏  举报

作者:nzperfect
本文地址:http://www.cnblogs.com/nzperfect/archive/2012/12/28/2837286.html

本文示例使用FASH nuber_rows改变SQL执行计划
准备测试数据:

复制代码
USE TEMPDB
GO
--
建立基本数据: --/////////////////// CREATE TABLE STUDENT (SNO VARCHAR(3) NOT NULL, SNAME VARCHAR(4) NOT NULL, SSEX VARCHAR(2) NOT NULL, SBIRTHDAY DATETIME, CLASS VARCHAR(5)) GO CREATE TABLE COURSE (CNO VARCHAR(5) NOT NULL, CNAME VARCHAR(10) NOT NULL, TNO VARCHAR(10) NOT NULL) GO CREATE TABLE SCORE (SNO VARCHAR(3) NOT NULL, CNO VARCHAR(5) NOT NULL, DEGREE NUMERIC(10, 1) NOT NULL) GO CREATE TABLE TEACHER (TNO VARCHAR(3) NOT NULL, TNAME VARCHAR(4) NOT NULL, TSEX VARCHAR(2) NOT NULL, TBIRTHDAY DATETIME NOT NULL, PROF VARCHAR(6), DEPART VARCHAR(10) NOT NULL) INSERT INTO STUDENT (SNO,SNAME,SSEX,SBIRTHDAY,CLASS) VALUES (108 ,'曾华' ,'' ,1977-09-01,95033); INSERT INTO STUDENT (SNO,SNAME,SSEX,SBIRTHDAY,CLASS) VALUES (105 ,'匡明' ,'' ,1975-10-02,95031); INSERT INTO STUDENT (SNO,SNAME,SSEX,SBIRTHDAY,CLASS) VALUES (107 ,'王丽' ,'' ,1976-01-23,95033); INSERT INTO STUDENT (SNO,SNAME,SSEX,SBIRTHDAY,CLASS) VALUES (101 ,'李军' ,'' ,1976-02-20,95033); INSERT INTO STUDENT (SNO,SNAME,SSEX,SBIRTHDAY,CLASS) VALUES (109 ,'王芳' ,'' ,1975-02-10,95031); INSERT INTO STUDENT (SNO,SNAME,SSEX,SBIRTHDAY,CLASS) VALUES (103 ,'陆君' ,'' ,1974-06-03,95031); GO INSERT INTO COURSE(CNO,CNAME,TNO)VALUES ('3-105' ,'计算机导论',825); INSERT INTO COURSE(CNO,CNAME,TNO)VALUES ('3-245' ,'操作系统' ,804); INSERT INTO COURSE(CNO,CNAME,TNO)VALUES ('6-166' ,'数据电路' ,856); INSERT INTO COURSE(CNO,CNAME,TNO)VALUES ('9-888' ,'高等数学' ,100); GO INSERT INTO SCORE(SNO,CNO,DEGREE)VALUES (103,'3-245',86); INSERT INTO SCORE(SNO,CNO,DEGREE)VALUES (105,'3-245',75); INSERT INTO SCORE(SNO,CNO,DEGREE)VALUES (109,'3-245',68); INSERT INTO SCORE(SNO,CNO,DEGREE)VALUES (103,'3-105',92); INSERT INTO SCORE(SNO,CNO,DEGREE)VALUES (105,'3-105',88); INSERT INTO SCORE(SNO,CNO,DEGREE)VALUES (109,'3-105',76); INSERT INTO SCORE(SNO,CNO,DEGREE)VALUES (101,'3-105',64); INSERT INTO SCORE(SNO,CNO,DEGREE)VALUES (107,'3-105',91); INSERT INTO SCORE(SNO,CNO,DEGREE)VALUES (108,'3-105',78); INSERT INTO SCORE(SNO,CNO,DEGREE)VALUES (101,'6-166',85); INSERT INTO SCORE(SNO,CNO,DEGREE)VALUES (107,'6-106',79); INSERT INTO SCORE(SNO,CNO,DEGREE)VALUES (108,'6-166',81); GO INSERT INTO TEACHER(TNO,TNAME,TSEX,TBIRTHDAY,PROF,DEPART) VALUES (804,'李诚','','1958-12-02','副教授','计算机系'); INSERT INTO TEACHER(TNO,TNAME,TSEX,TBIRTHDAY,PROF,DEPART) VALUES (856,'张旭','','1969-03-12','讲师', '电子工程系'); INSERT INTO TEACHER(TNO,TNAME,TSEX,TBIRTHDAY,PROF,DEPART)VALUES (825, '王萍','','1972-05-05','助教', '计算机系'); INSERT INTO TEACHER(TNO,TNAME,TSEX,TBIRTHDAY,PROF,DEPART) VALUES (831,'刘冰','','1977-08-14','助教', '电子工程系');
复制代码

加索引:

复制代码
CREATE UNIQUE CLUSTERED INDEX IX_1 ON COURSE(CNO)
CREATE NONCLUSTERED INDEX IX_2 ON COURSE(TNO,CNO)

CREATE UNIQUE CLUSTERED INDEX IX_1 ON SCORE(SNO,CNO)
CREATE NONCLUSTERED INDEX IX_2 ON SCORE(CNO)


CREATE UNIQUE CLUSTERED INDEX IX_1 ON TEACHER(TNO)
CREATE NONCLUSTERED INDEX IX_2 ON TEACHER(TNAME,TNO)
复制代码

 

查询语句写法一:

SELECT SC.*
FROM TEACHER TEA 
INNER JOIN COURSE CO ON TEA.TNO=CO.TNO 
INNER JOIN SCORE SC ON CO.CNO = SC.CNO
WHERE TEA.TNAME='张旭'

 

 查询语句写法二:

SELECT *
FROM SCORE SC
WHERE CNO IN ( 
    SELECT CNO
    FROM TEACHER TEA INNER JOIN COURSE CO
    ON TEA.TNO = CO.TNO
    WHERE TEA.TNAME='张旭'
) 

首先看下IO:

查询语句写法一:

Table 'SCORE'. Scan count 1, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'COURSE'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TEACHER'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
查询语句写法二:

Table 'TEACHER'. Scan count 0, logical reads 22, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'COURSE'. Scan count 0, logical reads 24, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'SCORE'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

从上面的IO可以看到写法二IO比写法一多一些逻辑读。

 

再比较一下执行计划:

写法一:

写法二:

上面这个写法二生成的执行计划看似不是我们想要的,我们的写法是:

SELECT *
FROM SCORE SC
WHERE CNO IN ( 
    SELECT CNO
    FROM TEACHER TEA INNER JOIN COURSE CO
    ON TEA.TNO = CO.TNO
    WHERE TEA.TNAME='张旭'
) 

按一般我们是这么想的:

step 1 : 先执行:

    SELECT CNO
    FROM TEACHER TEA INNER JOIN COURSE CO
    ON TEA.TNO = CO.TNO
    WHERE TEA.TNAME='张旭'

step 2 : 然后再执行:

SELECT *
FROM SCORE SC
WHERE CNO IN
(
    STEP 1 CNO结果
)

但实际上,但SQL执行计划并未按我们想的生成我们想要的执行计划,所以我打算想办法改变它,使用一个query hint : FAST number_rows

复制代码
SELECT *
FROM SCORE SC
WHERE CNO IN ( 
    SELECT CNO
    FROM TEACHER TEA INNER JOIN COURSE CO
    ON TEA.TNO = CO.TNO
    WHERE TEA.TNAME='张旭'
) 
OPTION(FAST 1)
复制代码

看看它的IO:

Table 'SCORE'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'COURSE'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TEACHER'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

看看它的执行计划:

这基本就是我们想要的了。

关于FAST hint,联机文档是这么解释的:

FAST number_rows

指定对查询进行优化,以便快速检索第一个 number_rows.。该值是非负整数。在返回第一个 number_rows 后,查询继续执行并生成完整的结果集。

其实也就是说FAST提示会将join优化为nested loop join ,而不用hash join,这样就能够快速的返回前几行/前几十行,尤其针对一个结果集会返回大量数据,但我们只需要显示前10行,那么如果hash join就不如nested loop join快了,当然,如果你要全部返回并显示,那么nested loop join就可能会比hash join还要慢了。

 

 

编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示