----------------------------------------------------------- ---- Create T_Pet table in tempdb. ----------------------------------------------------------- USE tempdb CREATE TABLE T_Pet ( animal VARCHAR(20), [name] VARCHAR(20), sex CHAR(1), age INT ) CREATE UNIQUE CLUSTERED INDEX T_PetonAnimal1_ClterIdx ON T_Pet (animal)
----------------------------------------------------------- ---- Insert data into data table. -----------------------------------------------------------
代码如下:
DECLARE @i int SET @i=0 WHILE(@i<1000000) BEGIN INSERT INTO T_Pet ( animal, [name], sex, age ) SELECT [dbo].random_string(11) animal, [dbo].random_string(11) [name], 'F' sex, cast(floor(rand()*5) as int) age SET @i=@i+1 END INSERT INTO T_Pet VALUES('Aardark', 'Hello', 'F', 1) INSERT INTO T_Pet VALUES('Cat', 'Kitty', 'F', 2) INSERT INTO T_Pet VALUES('Horse', 'Ma', 'F', 1) INSERT INTO T_Pet VALUES('Turtles', 'SiSi', 'F', 4) INSERT INTO T_Pet VALUES('Dog', 'Tomma', 'F', 2) INSERT INTO T_Pet VALUES('Donkey', 'YoYo', 'F', 3)
代码如下:
SET STATISTICS PROFILE ON SET STATISTICS TIME ON
SELECT animal, [name], sex, age FROM T_Pet WHERE animal = 'Ifcey'
SET STATISTICS PROFILE OFF SET STATISTICS TIME OFF
当我们执行完SQL查询计划时,把鼠标指针放到“聚集索引查找”上,这时会出现如下图信息,我们可以查看到一个重要的信息Logical Operation——Clustered Index Seek,SQL查询是直接根据聚集索引获取记录,查询速度最快。
图6查询计划
从下图查询结果,我们发现查询步骤只有2步,首先通过Clustered Index Seek快速地找到索引Ifcey,接着查询索引的叶节点(数据页)获取数据。
----------------------------------------------------------- ---- Create T_Pet table in tempdb with NONCLUSTERED INDEX. ----------------------------------------------------------- USE tempdb CREATE TABLE T_Pet ( animal VARCHAR(20), [name] VARCHAR(20), sex CHAR(1), age INT ) CREATE UNIQUE NONCLUSTERED INDEX T_PetonAnimal1_NonClterIdx ON T_Pet (animal)
代码如下:
SET STATISTICS PROFILE ON SET STATISTICS TIME ON
SELECT animal, [name], sex, age FROM T_Pet WHERE animal = 'Cat'
SET STATISTICS PROFILE OFF SET STATISTICS TIME OFF
如下图所示,我们发现查询计划的最右边有两个步骤:RID和索引查找。由于这两种查找方式相对于聚集索引查找要慢(Clustered Index Seek)。
----------------------------------------------------------- ---- Create T_Pet table in tempdb with NONCLUSTERED INDEX. ----------------------------------------------------------- USE tempdb CREATE TABLE T_Pet ( animal VARCHAR(20), [name] VARCHAR(20), sex CHAR(1), age INT ) CREATE UNIQUE NONCLUSTERED INDEX T_PetonAnimal1_NonClterIdx ON T_Pet (animal) CREATE UNIQUE CLUSTERED INDEX T_PetonAnimal1_ClterIdx ON T_Pet (animal) ----------------------------------------------------------- ---- Insert data into data table. ----------------------------------------------------------- DECLARE @i int SET @i=0 WHILE(@i<1000000) BEGIN INSERT INTO T_Pet ( animal, [name], sex, age ) SELECT [dbo].random_string(11) animal, [dbo].random_string(11) [name], 'F' sex, cast(floor(rand()*5) as int) age SET @i=@i+1 END INSERT INTO T_Pet VALUES('Aardark', 'Hello', 'F', 1) INSERT INTO T_Pet VALUES('Cat', 'Kitty', 'F', 2) INSERT INTO T_Pet VALUES('Horse', 'Ma', 'F', 1) INSERT INTO T_Pet VALUES('Turtles', 'SiSi', 'F', 4) INSERT INTO T_Pet VALUES('Dog', 'Tomma', 'F', 2) INSERT INTO T_Pet VALUES('Donkey', 'YoYo', 'F', 3)
SET STATISTICS PROFILE ON SET STATISTICS TIME ON SELECT animal, [name], sex, age FROM T_Pet WHERE animal = 'Cat' SET STATISTICS PROFILE OFF SET STATISTICS TIME OFF
employee_id NUMERIC NOT NULL, first_name VARCHAR(1000) NOT NULL, last_name VARCHAR(900) NOT NULL, date_of_birth DATETIME , phone_number VARCHAR(1000) NOT NULL, junk CHAR(1000) , --PK constraint defaults to clustered CONSTRAINT employees_pk PRIMARY KEY (employee_id) ); GO
----------------------------------------------------------- ---- Insert data into data table. ----------------------------------------------------------- CREATE VIEW rand_helper AS SELECT RND=RAND(); GO ---- Generates random string function. CREATE FUNCTION random_string (@maxlen int) RETURNS VARCHAR(255) AS BEGIN DECLARE @rv VARCHAR(255) DECLARE @loop int DECLARE @len int SET @len = (SELECT CAST(rnd * (@maxlen-3) AS INT) +3 FROM rand_helper) SET @rv = '' SET @loop = 0 WHILE @loop <@len BEGIN SET @rv = @rv + CHAR(CAST((SELECT rnd FROM rand_helper) * 26 AS INT )+97) IF @loop = 0 BEGIN SET @rv = UPPER(@rv) END SET @loop = @loop +1; END RETURN @rv END GO ---- Generates random date function. CREATE FUNCTION random_date (@mindaysago int, @maxdaysago int) RETURNS VARCHAR(255) AS BEGIN DECLARE @rv datetime SET @rv = (SELECT GetDate() - rnd * (@maxdaysago-@mindaysago) - @mindaysago FROM rand_helper) RETURN @rv END GO ---- Generates random int function. CREATE FUNCTION random_int (@min int, @max int) RETURNS INT AS BEGIN DECLARE @rv INT SET @rv = (SELECT rnd * (@max) + @min FROM rand_helper) RETURN @rv END GO ---- Inserts data into employees table. WITH generator (n) as ( select 1 union all select n + 1 from generator where N <30000 ) INSERT INTO employees (employee_id , first_name, last_name , date_of_birth, phone_number, junk) select n employee_id , [dbo].random_string(11) first_name , [dbo].random_string(11) last_name , [dbo].random_date(20*365, 60*365) dob , 'N/A' phone , 'junk' junk from generator OPTION (MAXRECURSION 30000) ----------------------------------------------------------- ---- Index Usefulness sample ----------------------------------------------------------- CREATE TABLE testIndex ( testIndex int identity(1,1) constraint PKtestIndex primary key, bitValue bit, filler char(2000) not null default (replicate('A',2000)) ) CREATE INDEX XtestIndex_bitValue on testIndex(bitValue) GO INSERT INTO testIndex(bitValue) VALUES (0) GO 20000 --runs current batch 20000 times. INSERT INTO testIndex(bitValue) VALUES (1) GO 10 --puts 10 rows into table with value 1 SELECT filler FROM testIndex WHERE bitValue = 1 UPDATE STATISTICS dbo.testIndex DBCC SHOW_STATISTICS('dbo.testIndex', 'XtestIndex_bitValue') WITH HISTOGRAM