我真的很喜欢这些类型的问题,因为您可以进行性能分析。
首先,让我们创建一个示例 [test] 数据库,其中包含一个包含一百万条随机记录的 [urls] 表。
请参阅下面的代码。
-- Switch databases
USE [master];
go
-- Create simple database
CREATE DATABASE [test];
go
-- Switch databases
USE [test];
go
-- Create simple table
CREATE TABLE [urls]
(
my_id INT IDENTITY(1, 1)
PRIMARY KEY ,
my_link VARCHAR(255) ,
my_status VARCHAR(15)
);
go
-- http://stackoverflow.com/questions/1393951/what-is-the-best-way-to-create-and-populate-a-numbers-table
-- Load table with 1M rows of data
;
WITH PASS0
AS ( SELECT 1 AS C
UNION ALL
SELECT 1
), --2 rows
PASS1
AS ( SELECT 1 AS C
FROM PASS0 AS A ,
PASS0 AS B
), --4 rows
PASS2
AS ( SELECT 1 AS C
FROM PASS1 AS A ,
PASS1 AS B
), --16 rows
PASS3
AS ( SELECT 1 AS C
FROM PASS2 AS A ,
PASS2 AS B
), --256 rows
PASS4
AS ( SELECT 1 AS C
FROM PASS3 AS A ,
PASS3 AS B
), --65536 rows
PASS5
AS ( SELECT 1 AS C
FROM PASS4 AS A ,
PASS4 AS B
), --4,294,967,296 rows
TALLY
AS ( SELECT ROW_NUMBER() OVER ( ORDER BY C ) AS Number
FROM PASS5
)
INSERT INTO urls
( my_link ,
my_status
)
SELECT
-- top 10 search engines + me
CASE ( Number % 11 )
WHEN 0 THEN 'www.ask.com'
WHEN 1 THEN 'www.bing.com'
WHEN 2 THEN 'www.duckduckgo.com'
WHEN 3 THEN 'www.dogpile.com'
WHEN 4 THEN 'www.webopedia.com'
WHEN 5 THEN 'www.clusty.com'
WHEN 6 THEN 'www.archive.org'
WHEN 7 THEN 'www.mahalo.com'
WHEN 8 THEN 'www.google.com'
WHEN 9 THEN 'www.yahoo.com'
ELSE 'www.craftydba.com'
END AS my_link ,
-- ratings scale
CASE ( Number % 5 )
WHEN 0 THEN 'poor'
WHEN 1 THEN 'fair'
WHEN 2 THEN 'good'
WHEN 3 THEN 'very good'
ELSE 'excellent'
END AS my_status
FROM TALLY AS T
WHERE Number <= 1000000
go
其次,在我们的测试环境中进行性能分析时,我们总是希望清除缓冲区和缓存。另外,我们要打开统计 I/O 和时间来比较结果。
请参阅下面的代码。
-- Show time & i/o
SET STATISTICS TIME ON
SET STATISTICS IO ON
GO
-- Remove clean buffers & clear plan cache
CHECKPOINT
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
GO
第三,我们要尝试第一个 TSQL 语句。查看执行计划并捕获统计信息。
-- Try 1
SELECT * FROM urls ORDER BY my_status
/*
Table 'urls'. Scan count 5, logical reads 4987, physical reads 1, read-ahead reads 4918, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 3166 ms, elapsed time = 8130 ms.
*/
第四,我们想试试第二条 TSQL 语句。不要忘记清除查询计划缓存和缓冲区。如果不这样做,则查询将花费不到 1 秒的时间,因为大部分信息都在内存中。查看执行计划并捕获统计信息。
-- Try 2
SELECT ROW_NUMBER() OVER (ORDER BY my_status) as my_rownum, * FROM urls
/*
Table 'urls'. Scan count 5, logical reads 4987, physical reads 1, read-ahead reads 4918, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 3276 ms, elapsed time = 8414 ms.
*/
最后但同样重要的是,这是有趣的部分,性能分析。
1 - 我们可以看到第二个计划是第一个计划的超集。所以这两个计划都会扫描聚集索引并对数据进行排序。并行性用于将结果放在一起。
2 - 第二个计划/查询需要计算行号。它分割数据并计算这个标量。因此,我们最终在计划中增加了两个运算符。
第一个计划在 8130 毫秒内运行,第二个计划在 8414 毫秒内运行,这并不奇怪。
始终查看查询计划。估计的和实际的。他们告诉您希望引擎计划做什么以及它实际做什么。
在这个例子中,两个不同的 TSQL 语句提出了几乎相同的计划。
真挚地
约翰
www.craftydba.com