好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

SqlServer执行计划及Sql查询优化初探

网上的 SQL 优化的文章实在是很多,说实在的,我也曾经到处找这样的文章,什么不要使用 IN 了,什么 OR 了,什么 AND 了,很多很多,还有很多人拿出仅几 S 甚至几 MS 的时间差的例子来证明着什么 ( 有点可笑 ) ,让许多人不知道其是对还是错。而 SQL 优化又是每个要与数据库打交道的程序员的必修课,所以写了此文,与朋友们共勉。  

谈到优化就必然要涉及索引,就像要讲锁必然要说事务一样,所以你需要了解一下索引,仅仅是索引,就能讲半天了,所以索引我就不说了 ( 打很多字是很累的,况且我也知之甚少 ) ,可以去参考相关的文章,这个网上资料比较多了。  

今天来探索下 MSSQL 的执行计划,来让大家知道如何查看 MSSQL 的优化机制,以此来优化 SQL 查询。

 

--DROP TABLE T_UserInfo----------------------------------------------------

-- 建测试表

CREATE   TABLE  T_UserInfo

(

     Userid varchar ( 20 ),    UserName varchar ( 20 ),

     RegTime  datetime ,   Tel varchar ( 20 ),

)

-- 插入测试数据

DECLARE  @I  INT

DECLARE  @ENDID  INT

SELECT  @I  =  1

SELECT  @ENDID = 100    -- 在此处更改要插入的数据,重新插入之前要删掉所有数据

WHILE  @I  <=  @ENDID

BEGIN

     INSERT   INTO  T_UserInfo

     SELECT   'ABCDE' + CAST ( @I  AS  VARCHAR ( 20 ))+ 'EF' , ' 李 ' + CAST ( @I  AS  VARCHAR ( 20 )),

        GETDATE (), '876543' + CAST ( @I  AS  VARCHAR ( 20 ))

     SELECT  @I  =  @I  +  1

END

 

-- 相关 SQL 语句解释

---------------------------------------------------------------------------

-- 建聚集索引

CREATE   CLUSTERED   INDEX  INDEX_Userid    ON  T_UserInfo  ( Userid )

-- 建非聚集索引

CREATE   NONCLUSTERED   INDEX  INDEX_Userid    ON  T_UserInfo  ( Userid )

-- 删除索引

DROP   INDEX  T_UserInfo . INDEX_Userid

---------------------------------------------------------------------------

---------------------------------------------------------------------------

-- 显示有关由 Transact-SQL  语句生成的磁盘活动量的信息

SET   STATISTICS  IO  ON

-- 关闭有关由 Transact-SQL  语句生成的磁盘活动量的信息

SET   STATISTICS  IO  OFF

-- 显示 [ 返回有关语句执行情况的详细信息,并估计语句对资源的需求 ]

SET  SHOWPLAN_ALL    ON

-- 关闭 [ 返回有关语句执行情况的详细信息,并估计语句对资源的需求 ]

SET  SHOWPLAN_ALL    OFF

---------------------------------------------------------------------------

请记住: SET   STATISTICS  IO  和   SET  SHOWPLAN_ALL  是互斥的。

 

OK ,现在开始:

首先,我们插入 100 条数据

然后我写了一个查询语句:

SELECT   *   FROM  T_UserInfo  WHERE  USERID = 'ABCDE6EF'

选中以上语句,按 Ctrl + L ,如下图

 

 

这就是 MSSQL 的执行计划:表扫描:扫描表中的行

 

然后我们来看该语句对 IO 的读写:

执行 : SET   STATISTICS  IO  ON

此时再执行该 SQL : SELECT   *   FROM  T_UserInfo  WHERE  USERID = 'ABCDE6EF'

切换到消失栏显示如下:

表 'T_UserInfo' 。扫描计数 1 ,逻辑读 1  次,物理读 0  次,预读 0  次。

解释下其意思:

四个值分别为:

     执行的扫描次数 ;

     从数据缓存读取的页数 ;

      从磁盘读取的页数 ;

     为进行查询而放入缓存的页数

重要:如果对于一个 SQL 查询有多种写法,那么这四个值中的逻辑读 ( logical reads ) 决定了哪个是最优化的。

 

接下来我们为其建一个聚集索引

执行 CREATE   CLUSTERED   INDEX  INDEX_Userid    ON  T_UserInfo  ( Userid )

然后再执行 SELECT   *   FROM  T_UserInfo  WHERE  USERID = 'ABCDE6EF'

切换到消息栏如下显示:

表 'T_UserInfo' 。扫描计数 1 ,逻辑读 2  次,物理读 0  次,预读 0  次。

此时逻辑读由原来的 1 变成 2 ,

说明我们又加了一个索引页,现在我们查询时,逻辑读就是要读两页 (1 索引页 +1 数据页 ) ,此时的效率还不如不建索引。

 

此时再选中查询语句,然后再 Ctrl + L ,如下图 :

聚集索引查找:扫描聚集索引中特定范围的行

说明,此时用了索引。

 

OK , 到这里你应该已经知道初步知道 MSSQL 查询计划和如何查看对 IO 的读取消耗了吧!

 

 

接下来我们继续:

 

现在我再把测试数据改变成 1000 条

再执行 SET   STATISTICS  IO  ON , 再执行

SELECT   *   FROM  T_UserInfo  WHERE  USERID = 'ABCDE6EF'

在不加聚集索引的情况下:

表 'T_UserInfo' 。扫描计数 1 ,逻辑读 7  次,物理读 0  次,预读 0  次。

在加聚集索引的情况下: CREATE   CLUSTERED   INDEX  INDEX_Userid    ON  T_UserInfo  ( Userid )

表 'T_UserInfo' 。扫描计数 1 ,逻辑读 2  次,物理读 0  次,预读 0  次。

( 其实也就是说此时是读了一个索引页,一个数据页 )

如此,在数据量稍大时,索引的查询优势就显示出来了。

 

 

 

先小总结下 :

当你构建 SQL 语句时,按 Ctrl + L 就可以看到语句是如何执行,是用索引扫描还是表扫描?

通过 SET   STATISTICS  IO  ON   来查看逻辑读,完成同一功能的不同 SQL 语句,逻辑读

越小查询速度越快 ( 当然不要找那个只有几百条记录的例子来反我 ) 。

   

我们再继续深入:

OK ,现在我们再来看一次,我们换个 SQL 语句,来看下 MSSQL 如何来执行的此 SQL 呢?

现在去掉索引: 查看更多关于SqlServer执行计划及Sql查询优化初探的详细内容...

  阅读:41次