mysql查询优化

-->Title: 淺議 SQL Server 执行计划
-->Author: wufeng4552
-->Date :2009-10-20 15:08:24

前言 :

最近溫習了執行計劃方面的部份知識 , 為了加深印象與方便初學者 , 特做了如下整理 .

不對地方 歡迎提出並 指正 .

查看执行计划的方式 :

(1) 菜單方式 :

(1.1) 显示实际执行计划

(1.2) 显示预估的执行计划

以上兩種均位於位于 查询 下拉菜单中 , 两者的不同之处在于当实际运行一个查询时 , 当前的服务器上的运算也会被考虑进去。大多数情况下 , 两种方式产生的执行计划产生的结果是相似的 .

(2) 命令方式

SET SHOWPLAN_TEXT ON

这条命令被执行后 , 所有在当前这个查询分析器会话中执行的查询都不会运行 , 而是会显示一个基于文本的执行计划

注意 : 执行某条用到临时表的查询时,必须在执行查询先运行 SET STATISTICS PROFILE ON 语句 :

go

if not object_id ( 'tempdb..#t' ) is null

  drop table #t

Go

Create table #t( [ 日期 ] Datetime , [ 姓名 ] nvarchar ( 2))

Insert #t

select '2009-10-01' , N' 张三 ' union all

select '2009-10-01' , N' 李四 ' union all

select '2009-10-02' , N' 赵六 '

Go

SET STATISTICS PROFILE ON

go

select * from #T

SET STATISTICS PROFILE OFF

結果如圖 1

1

為了討論方便 下面以 Northwind 庫中表 [Order Details] 為例 ( 我已經將主鍵刪除 )

use Northwind

go

SET SHOWPLAN_TEXT ON

go

select ProductID, sum ( Quantity) Quantity from [Order Details]

group by ProductID order by ProductID

go

SET SHOWPLAN_TEXT OFF

/*

StmtText

|--Sort(ORDER BY:([Northwind].[dbo].[Order Details].[ProductID] ASC))

     |--Hash Match(Aggregate, HASH:([Northwind].[dbo].[Order Details].[ProductID]) DEFINE:([Expr1004]=SUM([Northwind].[dbo].[Order Details].[Quantity])))

        |--Table Scan(OBJECT:([Northwind].[dbo].[Order Details]))

*/

use Northwind

go

---- 建一个聚集索引

CREATE CLUSTERED INDEX INDEX_ProductID on [Order Details]( ProductID)

go

SET SHOWPLAN_TEXT ON

go

select ProductID, sum ( Quantity) Quantity from [Order Details]

group by ProductID order by ProductID

go

SET SHOWPLAN_TEXT OFF

/*

StmtText

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

  |--Stream Aggregate(GROUP BY:([Northwind].[dbo].[Order Details].[ProductID]) DEFINE:([Expr1004]=SUM([Northwind].[dbo].[Order Details].[Quantity])))

       |--Clustered Index Scan(OBJECT:([Northwind].[dbo].[Order Details].[INDEX_ProductID]), ORDERED FORWARD)

(2 個資料列受到影響 )

*/

如果在执行计划中看到如下所示的任何一项 , 从性能方面来说 , 下面所示的每一项都是不理想的。

Index or table scans(索引或者表扫描): 可能意味着需要更好的或者额外的索引。

Bookmark Lookups(书签查找): 考虑修改当前的聚集索引,使用复盖索引,限制 SELECT 语句中的字段数量。

Filter(过滤): WHERE 从句中移除用到的任何函数,不要在 SQL 语句中包含视图,可能需要额外的索引。

Sort(排序): 数据是否真的需要排序?可否使用索引来避免排序?在客户端排序是否会更加有效率?

以上事項 避免得越多, 查询性能就会越快.

注意 : 如果有在存储过程中或者其它 T-SQL 批处理代码中用到了临时表,就不能在查询分析器或 Management Studio 使用 显示预估的执行计划 选项来评估查询。必须实际运行这个存储过程或者批处理代码。这是因为使用 显示预估的执行计划 选项来运行一个查询时,它并没有实际被运行,临时表也没有创建。由于临时表没有被创建,参考到临时表的代码就会失败,导致预估的执行计划不能成创建成功。从另一方面来说,如果使用的是表变量而不是临时表,则可以使用 显示预估的执行计划 选项 .

use Northwind

go

select a.* from [orders] a, [Order Details] b

where a. OrderID= b. OrderID

2

查看执行计划时记住如下几点:

(1)     非 常复杂的执行计划会被分成多个部分,它们分别列出在屏幕上。每个部分分别代表查询优化器为了得到最终结果而必须执行的单个处理或步骤。执行计划的每个步骤 经常会被拆分成一个个更小的子步骤。不幸的是,它们是从右至左显示在屏幕上的。这意味着你必须滚动到图形执行计划的最右边去查看每个步骤是从哪儿开始的

(2)     每个步骤与子步骤间通过箭头连接,藉此显示查询执行的路径。

(3)     最后,查询的所有部分在屏幕顶部的左边汇总到一起 , 如果将鼠标移动到连接步骤或子步骤的箭头上,就可以看到一个弹出式窗口,上面显示有多少笔记录从一个步骤或子步骤移动到另一个步骤或子步骤 ( 如圖3) 如果将鼠标移动到任何执行计划任何步骤或者子步骤的上面,就会显示一个弹出式窗口,上面显示该步骤或子步骤的更加详细的信息 如圖2 彈出窗口

mysql查询优化_第1张图片

3

(4)     图形执行计划上连接每个图标的箭头粗细不同 ( 如圖3) 。箭头的粗细表示每个图标之间移动的数据行数量以及数据行大小移动所需的相对本。箭头越粗,相对成本就越高。可以使用这个指示器来快速测量一个查询。你可能会特别关注粗箭头以了解它如何影响到查询的效能。例如,粗线头应该在图形执行计划的右边,而非左边。如果看到它们在左边,就意味着太多的数据行被返回,这个执行计划也不是最佳的执行计划 .

(5)     执行计划的每个部分都被分配了一个成本百分比(如圖2,3)它表示这个部分耗用了整个执行计划的多少资源。当对一个执行计划进行分析的时候,应该将精力集中于有着高成本百分比的那些部分。这样就可以在有限的时间里找到可能性最大的问题,从而回报了你在时间上的投资 .

(6)     你可能会注意到一个执行计划的某些部分被执行了不止一次。 作为执行计划分析的一部分,应该将你的一些时间集中在任何执行了超过一次的那些部分上,看看是否有什么方式减少它们执行的次数。执行的次数越少,查询的速度就越快。

(7)     I/O与CPU成本 。查询优化器使用这些数字来做出最佳选择。它们可用来参考的一个意义是,较小的 I/O CPU 成本比较大的 I/O CPU 成本使用更少的服务器资源 .

use Northwind

go

-- 刪除聚集索引

DROP INDEX [Order Details]. INDEX_ProductID

--CREATE CLUSTERED INDEX INDEX_ProductID ON [Order Details](ProductID)

SET STATISTICS IO ON

select * from [Order Details] where ProductID= 42

SET STATISTICS IO OFF

資料表 'Order Details' 。掃描計數 1 ,邏輯讀取 11 ,實體讀取 0 ,讀取前讀取 0 LOB 邏輯讀取 0 LOB 實體讀取 0 LOB 讀取前讀取 0

use Northwind

go

-- 刪除聚集索引

--DROP INDEX [Order Details].INDEX_ProductID

-- 建立聚集索引

CREATE CLUSTERED INDEX INDEX_ProductID ON [Order Details]( ProductID)

go

SET STATISTICS IO ON

select * from [Order Details] where ProductID= 42

SET STATISTICS IO OFF

資料表 'Order Details' 。掃描計數 1 ,邏輯讀取 2 ,實體讀取 0 ,讀取前讀取 0 LOB 邏輯讀取 0 LOB 實體讀取 0 LOB 讀取前讀取 0

以上可以看出邏輯讀相差很大 , 由此可以 通过 SET STATISTICS IO ON 来查看逻辑读,完成同一功能的不同 SQL 语句,逻辑读越小查询速度越快

(8) 将鼠标移到图形执行计划上的表名 ( 以及它的图标 ) 上面,就会弹出一个窗口,从它上面可以看到一些信息。这些信息让你知道是否有用到索引来从表中获取数据,以及它是如何使用的。这些信息包括:

(8.1)Table Scan(表扫描) : 如果看到这个信息,就说明数据表上没有聚集索引,或者查询优化器没有使用索引来查找。意即资料表的每一行都被检查到。如果资料表相对较小的话,表扫描可以 非常快速,有时甚至快过使用索引。因此,当看到有执行表扫描时,第一件要做的事就是看看数据表有多少数据行。如果不是太多的话,那么表扫描可能提供了最好 的总体效能。但如果数据表大的话,表扫描就极可能需要长时间来完成,查询效能就大受影响。在这种情况下,就需要仔细研究,为数据表增加一个适当的索引用于 这个查询。假设你发现某查询使用了表扫描,有一个合适的非聚集索引,但它没有用到。这意味着什么呢?为什么这个索引没有用到呢?如果需要获得的数据量相对 数据表大小来说非常大,或者数据选择性不高 ( 意味着同一个字段中重复的值很多 ) ,表扫描经常会比索引扫描快。例如,如果一个数据表有 10000 个数据行,查询返回 1000 行,如果这个表没有聚集索引的话,那么表扫描将比使用一个非聚集索引更快。或者如果数据表有 10000 个数据行,且同一个字段 (WHERE 条件句有用到这个字段 ) 上有 1000 笔重复的数据,表扫描也会比使用非聚集索引更快。查看图形执行计划上的数据表上的弹出式窗口时,请注意 预估的资料行数 (Estimated Row Count)” 。这个数字是查询优化器作出的多少个数据行会被返回的最佳推测。如果执行了表扫描且 预估的数据行数 数值很高的话,就意味着返回的记录数很多,查询优化器认为执行表扫描比使用可用的非聚集索引更快

(8.2)Index Seek(索引查找) :索引查找意味着查询优化器使用了数据表上的非聚集索引来查找数据。性能通常会很快,尤其是当只有少数的数据行被返回时

(8.3)Clustered Index Seek(聚集索引查找) :这指查询优化器使用了数据表上的聚集索引来查找数据,性能很快。实际上,这是 SQL Server 能做的最快的索引查找类型

(8.4)Clustered Index Scan(聚集索引扫描) : 聚集索引扫描与表扫描相似,不同的是聚集索引扫描是在一个建有聚集索引的数据表上执行的。和一般的表扫描一样,聚集索引扫描可能表明存在效能问题。一般来 说,有两种原因会引此聚集索引扫描的执行。第一个原因,相对于数据表上的整体数据行数目,可能需要获取太多的数据行。查看 预估的数据行数量 (Estimated Row Count)” 可以对此加以验证。第二个原因,可能是由于 WHERE 条 件句中用到的字段选择性不高。在任何情况下,与标准的表扫描不同,聚集索引扫描并不会总是去查找数据表中的所有数据,所以聚集索引扫描一般都会比标准的表 扫描要快。通常来说,要将聚集索引扫描改成聚集索引查找,你唯一能做的是重写查询语句,让语句限制性更多,从而返回更少的数据行

(9)绝大多数情况下,查询优化器会对连接进行分析,按最有效率的顺序,使用最有效率的连接类型来对数据表进行连接。 但 并不总是如此。在图形执行计划中你可以看到代表查询所使用到的各种不同连接类型的图标。此外,每个连接图标都有两个箭头指向它。指向连接图标的上面的箭头 代表该连接的外部表,下面的箭头则代表这个连接的内部表。箭头的另一头则指向被连接的数据表名。有时在多表连接的查询中,箭头的另一头指向的并不是一个数 据表,而是另一个连接。如果将鼠标移到指向外部连接与内部连接的箭头上,就可以看到一个弹出式窗口,告诉你有多少数据行被发送至这个连接来进行处理。外部 表应该总是比内部表含有更少的数据行。如果不是,则说明查询优化器所选择的连接顺序可能不正确

(10) 查看图形执行计划时,你可能会发现某个图标的文字用红色显示, 而非通常情况下的黑色。这意味着相关的表的一些统计数据遗失,统计数据是查询优化器生成一个好的执行计划所必须的 , 遗失的统计数据可以通过右键这个图标,并选择 创建遗失的统计资料 来创建。这时会弹出 创建遗失的统计数据 对话框,通过它可以很容易地创建遗失的统计数据。   当可以选择去更新遗失的统计资料时,应该总是这样做,因为这样极有可能让你正在分析的查询语句从中获得效能上的好处  

(11) 有时你会在图形执行计划上看到标识了”Assert”的图标。 这意味着查询优化器正在验证查询语句是否有违反引用完整性或者条件约束。如果没有,则没有问题。但如果有的话,查询优化器将无法为该查询建立执行计划,同时会产生一个错误  

(12) 你常常会在图形执行计划上看到标识成”书签查找(Bookmark Lookup )”的图标。 书签查找相当常见。书签查找的本质是告诉你查询处理器必须从数据表或者聚集索引中来查找它所需要的数据行,而不是从非聚集索引中直接读取。   打比方说,如果一个查询语句的 SELECT,JOIN 以及 WHERE 子句中的所有字段,都不存在于那个用来定位符合查询条件的数据行的非聚集索引中,那么查询优化器就不得不做额外的工作在数据表或聚集索引中查找那些满足这个查询语句的字段。另一种引起书签查找的原因是使用了 SELECT * 。由于在绝大多情况下它会返回比你实际所需更多的数据,所以应该永不使用 SELECT *.   从性能方面来说,书签查找是不理想的。因为它会请求额外的 I/O 开销在字段中查找以返回所需的数据行。   如果认为书签查找防碍了查询的性能,那么有四种选择可以用来避免它:可以建立 WHERE 子句会用到的聚集索引,利用索引交集的优势,建立覆盖的非聚集索引,或者 ( 如果是 SQL Server 2000/2005 企业版的话 ) 可以建立索引视图。如果这些都不可能,或者使用它们中的任何一个都会耗用比书签查找更多的资源,那么书签查找就是最佳的选择了。

(13) 有时查询优化器需要在tempdb数据库中建立临时工作表。 如果是这样的话,就意味着图形执行计划中有标识成 Index Spool, Row Count Spool 或者 Table Spool 的图标。   任何时候,使用到工作表一般都会防碍到性能,因为需要额外的 I/O 开 销来维护这个工作表。理想情况下应该不要用到工作表。不幸的是并不能总是避免用到工作表。有时当使用工作表比其它选择更有效率时,它的使用实际上会增强性 能。不论何种情况,图形执行计划中的工作表都应该引起你的警觉。应该仔细检查这样的查询语句,看看是否有办法重写查询来避免用到工作表。有可能没有办法。 但如果有的话,你就朝提升这个查询的性能方面前进了一步 .  

(14) 在图形执行计划上看到流聚合(Stream Aggregate )图标就意味着有对一个单一的输入进行了聚合。 当使用了 DISTINCT 子句,或者任何聚合函数时,如 AVG, COUNT, MAX, MIN, 或者 SUM 等,流聚合操作就相当常见。    

(15)查询分析器与Management Studio不是唯一的可以生成 、显示查询执行计划的工具。 SQL Server Profiler 也可以显示执行计划,但格式是文本形式的。使用 SQL Server Profiler 来显示执行计划的一个优势是,它能为实际运行的大量查询产生执行计划。如果使用查询分析器和 Management Studio ,则一次只能运行一个

(16)如果在查询中使用了OPTION FAST提示, 那就必须小心执行计划的结果可能不是你所期望的。这时你所看到的执行计划基于使用了 FAST 提示的结果,而不是整个查询语句的实际执行计划。 FAST 提示用来告知果询优化器尽可能快地返回指定行数的数据行,即便这样做会防碍查询的整体性能。使用这个提示的目的在于为使用者快速返回特定行数的记录,由此让他们产生速度非常快速的错觉。。当返回指定行数的数据行后,剩余的数据行按照它们通常的速度返回。   因此,如果使用了 FAST 提示,那么生成的执行计划只是基于那些 FAST 返回的数据行,而非查询要返回的所有数据行。如果想看所有数据行的执行计划,那么就必须移除这个 FAST 提示 .

 

 

 

 

 

 

MSSQL 优化之 ———— 探索 MSSQL 执行计划

 

作者: no_mIss   QQ:34813284

时间: 2006.11.07 23:30:00

环境:win2003 + mssql2005  

 

最近总想整理下对 MSSQL 的一些理解与感悟,却一直没有心思和时间写 ,晚上无事便写了一篇探索 MSSQL 执行计划,本文讲执行计划但不仅限于讲执行计划。  

网上的 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 呢?

现在去掉索引: DROP INDEX T_UserInfo. INDEX_Userid

现在打开 [ 显示语句执行情况的详细信息 ] SET SHOWPLAN_ALL  ON

然后再执行: SELECT * FROM T_UserInfo WHERE USERID LIKE 'ABCDE8%'

看结果栏:结果中有些具体参数,比如 IO 的消耗, CPU 的消耗。

在这里我们只看 StmtText:

SELECT * FROM T_UserInfo WHERE USERID LIKE 'ABCDE8%'

  | --Table Scan(OBJECT:([student].[dbo].[T_UserInfo]), WHERE:(like([T_UserInfo].[Userid], 'ABCDE8%', NULL)))

Ctrl+ L 看下此时的图行执行计划:

 

 

我再加上索引:

先关闭: SET SHOWPLAN_ALL OFF

再执行: CREATE CLUSTERED INDEX INDEX_Userid  ON T_UserInfo ( Userid )

再开启: SET SHOWPLAN_ALL ON

再执行: SELECT * FROM T_UserInfo WHERE USERID LIKE 'ABCDE8%'

查看 StmtText:

SELECT * FROM T_UserInfo WHERE USERID LIKE 'ABCDE8%'

  | --Clustered Index Seek(OBJECT:([student].[dbo].[T_UserInfo].[INDEX_Userid]), SEEK:([T_UserInfo].[Userid] >= 'ABCDE8' AND [T_UserInfo].[Userid] < 'ABCDE9'),  WHERE:(like([T_UserInfo].[Userid], 'ABCDE8%', NULL)) ORDERED FORWARD)Ctrl+L 看下此时的图行执行计划:

Ctrl+ L 看下此时的图行执行计划:

 

 

 

在有索引的情况下,我们再写一个 SQL

SET SHOWPLAN_ALL ON

SELECT * FROM T_UserInfo WHERE LEFT( USERID, 4 )= 'ABCDE8%'

查看 StmtText:

SELECT * FROM T_UserInfo WHERE LEFT( USERID, 4 )= 'ABCDE8%'

  | --Clustered Index Scan(OBJECT:([student].[dbo].[T_UserInfo].[INDEX_Userid]), WHERE:(substring([T_UserInfo].[Userid], 1, 4)='ABCDE8%'))

Ctrl+L 看下此时的图行执行计划:

 

 

 

我们再分别看一下三种情况下对 IO 的操作

分别如下:

第一种情况:表 'T_UserInfo' 。扫描计数 1 ,逻辑读 7 次,物理读 0 次,预读 0 次。

第二种情况:表 'T_UserInfo' 。扫描计数 1 ,逻辑读 3 次,物理读 0 次,预读 0 次。

第三种情况:表 'T_UserInfo' 。扫描计数 1 ,逻辑读 8 次,物理读 0 次,预读 0 次。

这说明 :

第一次是表扫描,扫了 7 页,也就是全表扫描

第二次是索引扫描,扫了 1 页索引, 2 页数据页

第三次是索引扫描 + 表扫描,扫了 1 页索引, 7 页数据页

[图形界面也有对CPU和IO的消耗,也可以看出来哪个最优!] 

 

通过比较,嘿嘿,很容易的看出:第二种第三种写法在都有索引的情况下, like 有效的使用索引,而 left 则不能,这样一个最简单的优化的例子就出来了,哈哈。

 

  如果以上你都明白了,那么你可能已经对 SQL 的优化有初步新的想法了,网上一堆堆的 SQL 优化的文章真的是那样吗?你自己试试就知道了,而不必盲目去记那些东西,自己试试,看看 MSSQL 到底是怎么来执行就明白了。

在我举的例子中,用的是聚集索引扫描,字段是字母加数字,大家可以试试看纯数字的、字母的、汉字的等等,了解下 MMSQL 会如何改变 SQL 语句来利用索引。然后再试试非聚集索引是什么情况?用不用索引和什么有关?子查询 MSSQL 是如何执行? IN 用不用索引, LIKE 用不用索引?函数用不用索引? OR AND UNION ?子查询呢?在这里我不一一去试给大家看了,只要知道了如何去看 MSSQL 的执行计划(图形和文本 ) ,很多事情就很明朗了。

 

大总结:

实现同一查询功能的 SQL 写法可能会有多种,如果判断哪种最优化,如果仅仅是从时间上来测,会受很多外界因素的影响,而我们明白了 MSSQL 如何去执行,通过 IO 逻辑读、通过查看图示的查询计划、通过其优化后而执行的 SQL 语句,才是优化 SQL 的真正途径。

 

另外提醒下:数据量的多少有时会影响 MSSQL 对同一种查询写法语句的执行计划,这一点在非聚集索引上特别明显,还有就是在多 CPU 与单 CPU 下,在多用户并发情况下,同一写法的查询语句执行计划会有所不同,这个就需要大家有机会去试验了 ( 我也没有这方面的太多经验与大家分享 )

 

先写这些吧,由于我对 MSSQL 认识还很浅薄,如有不对的地方,还请指正。


-----查看运行时间

CHECKPOINT
GO
DBCC FREEPROCCACHE
GO
DBCC DROPCLEANBUFFERS
GO
DBCC FREESYSTEMCACHE('ALL') ;
GO
SET Statistics IO ON
GO
SET Statistics TIME ON
GO
declare @b datetime,@e datetime
set @b =getdate()
select * from tb
set @e =getdate()
select datediff(ms,@b,@e)
SET Statistics IO OFF
GO
SET Statistics TIME OFF
GO
DBCC DROPCLEANBUFFERS
從緩衝集區中移除所有的清除緩衝區
DBCC FREEPROCCACHE

你可能感兴趣的:(mysql查询优化)