Analysis the execution plan of Sybase

There is a good article;

=============================================================================

--数据查询分析--
--1.        建立三张表:
/**************************************************************
--1.1. 学生(学号,学生姓名,性别,出生年月,班级号,入学时间,家庭住址)
--并在学生表中插入100000条记录(十万个学生,班级号为C1000--C1999)
CREATE TABLE 学生
(学号  char(8) not null,
学生姓名 varchar(30),
性别 char(1),
出生年月 datetime,
班级号 varchar(10),
入学时间 datetime,       
      家庭住址  nvarchar(100),
CONSTRAINT PK_学生 PRIMARY KEY (学号)
)
**************************************************************/
CREATE TABLE t_students
(
std_no         char(8) not null,
std_name       varchar(30)     ,
std_sex        char(1)         ,
std_birthday   datetime        ,
std_cls_no         varchar(10) ,
std_enter_date datetime        ,       
std_home_addr  nvarchar(100)   ,
CONSTRAINT PK_t_students PRIMARY KEY (std_no)
)
go
truncate table t_students
go
declare @rn integer
declare @std_name integer
declare @cls integer
select @rn=100000
while (@rn<200000)
begin
    select @std_name=ceiling(rand()*1000000)
    select @cls=ceiling((@rn-100000)/100+100)
    insert into t_students(std_no,std_name,std_sex,std_birthday,std_cls_no,std_enter_date,std_home_addr)
    values("S"||convert(char(6),@rn), convert(char(6),@std_name)||"NAME","0",
           convert(datetime,"May 01 1980 10:23PM","C"||convert(char(4),(@cls)),
           convert(datetime,"Apr 15 2001 10:23PM","HOME"||convert(char(6),@rn))
    select @rn=@rn+1
end
commit
go
--这时学生表上已经有一个nonclustered的索引 pk_t_students

--1.2. 学生2(学号,学生姓名,性别,出生年月,班级号,入学时间,家庭住址)
--并在学生2表中插入100条记录(一百个学生,班级号为C1000)
/**************************************************************
CREATE TABLE 学生小
(学号  char(8) not null,
学生姓名 varchar(30),
性别 char(1),
出生年月 datetime,
班级号 varchar(10),
入学时间 datetime,       
      家庭住址  nvarchar(100),
CONSTRAINT PK_学生小 PRIMARY KEY (学号)
)
**************************************************************/
CREATE TABLE t_students2
(
std_no         char(8) not null,
std_name       varchar(30)     ,
std_sex        char(1)         ,
std_birthday   datetime        ,
std_cls_no         varchar(10) ,
std_enter_date datetime        ,       
std_home_addr  nvarchar(100)   ,
CONSTRAINT PK_t_students2 PRIMARY KEY (std_no)
)
go
truncate table t_students2
go
declare @rn integer
declare @std_name integer
declare @cls integer
select @rn=100000
while (@rn<100100)
begin
    select @std_name=ceiling(rand()*1000000)
    select @cls=ceiling((@rn-100000)/100+100)
    insert into t_students2(std_no,std_name,std_sex,std_birthday,std_cls_no,std_enter_date,std_home_addr)
    values("S"||convert(char(6),@rn), convert(char(6),@std_name)||"NAME","0",
           convert(datetime,"May 01 1980 10:23PM","C"||convert(char(4),(@cls)),
           convert(datetime,"Apr 15 2001 10:23PM","HOME"||convert(char(6),@rn))
    select @rn=@rn+1
end
commit
go

--这时学生2表上已经有一个nonclustered的索引 pk_t_students2

/**************************************************************
--1.3.班级(班级号,班主任姓名,教室,系编号)
--并在班级表中插入1000条记录(一千个班级CLS1000--CLS1999)
CREATE TABLE 班级
(班级号  varchar(10) not null,
班主任姓名  varchar(30),
教室   varchar(30),
系编号   char(10),
CONSTRAINT PK_班级  PRIMARY KEY (班级号)
)
**************************************************************/
CREATE TABLE t_classes
(
cls_no  varchar(10) not null   ,
cls_director_name   varchar(30),
cls_room            varchar(30),
cls_fam_no          char(10)   ,
CONSTRAINT PK_t_classes  PRIMARY KEY (cls_no)
)
go
truncate table t_classes
go
declare @rn integer
select @rn=1000
while (@rn<2000)
begin
    insert into t_classes(cls_no,cls_director_name,cls_room,cls_fam_no)
    values("C"||convert(char(4),@rn), convert(char(4),@rn)||"DIRECTOR_NAME",
           "ROOM"||convert(char(4),@rn),"FAMILY"||convert(char(4),@rn))
    select @rn=@rn+1
end
commit
go



--2. 索引对查询的影响--
--2.0. 在学生表学生名上建立非聚集索引--
--drop index t_students.idx_t_students_1--
create nonclustered index idx_t_students_1 on t_students(std_name)
go

--集合函数count 返回非空的行数

--实验列表(表中有大量记录)--
--2.1. 查询表中的少量记录(约1%)   ,使用idx_t_students_1 noncluster索引  ,且不访问表数据块
--2.2. 查询表中的大量记录(约80%)  ,使用idx_t_students_1 noncluster索引  ,且不访问表数据块
--2.3. 查询表中的少量记录(约1%)   ,使用idx_t_students_1 noncluster索引  ,且访问表数据块
--2.4. 查询表中的少量记录(小于10%),使用idx_t_students_1 noncluster索引  ,且访问表数据块
--2.5. 查询表中的全部记录(约80%)  ,使用idx_t_students_1 noncluster索引  ,且访问表数据块(Sybase优化器消除了这种执行计划)
--2.6. 查询表中的少量记录(约1%)   ,不使用idx_t_students_1 noncluster索引,只访问表数据块
--2.7. 查询表中的全部记录(约80%)  ,不使用idx_t_students_1 noncluster索引,只访问表数据块

--实验清单--
--2.1. 查询表中的少量记录(约1%) ,使用idx_t_students_1 noncluster索引  ,且不访问表数据块
select count(a.std_name) from t_students a (index std_name) where a.std_name LIKE "10%"
/*
    STEP 1
        The type of query is SELECT.
        Evaluate Ungrouped COUNT AGGREGATE.


        FROM TABLE
            t_students
            a
        Nested iteration.
        Index : idx_t_students_1
        Forward scan.
        Positioning by key.
        Index contains all needed columns. Base table will not be read.
        Keys are:
            std_name  ASC
        Using I/O Size 2 Kbytes for index leaf pages.
        With LRU Buffer Replacement Strategy for index leaf pages.


    STEP 2
        The type of query is SELECT.


Table: t_students scan count 1, logical reads: (regular=16 apf=0 total=16), physical reads: (regular=0 apf=0 total=0), apf IOs used=0
-----------------------------------------------------------------------------------------      
  (A.) "Index : idx_t_students_1"表示使用了该索引
  (B.) "Index contains all needed columns. Base table will not be read."
        表示本查询结果集所需字段都包含在索引中,只需访问索引块,不需要再通过索引访问表数据块.
  (C.) "logical reads: (regular=16 apf=0 total=16)" 表示逻辑读为16
  (D.) "physical reads: (regular=0 apf=0 total=0)" 表示物理读为0,所需读的数据块都在内存中,无物理I/O
*/


--2.2. 查询表中的大量记录(约80%),使用idx_t_students_1 noncluster索引  ,且不访问表数据块
select count(a.std_name) from t_students a (index std_name) where a.std_name>="3"
/*
    STEP 1
        The type of query is SELECT.
        Evaluate Ungrouped COUNT AGGREGATE.


        FROM TABLE
            t_students
            a
        Nested iteration.
        Index : idx_t_students_1
        Forward scan.
        Positioning by key.
        Index contains all needed columns. Base table will not be read.
        Keys are:
            std_name  ASC
        Using I/O Size 2 Kbytes for index leaf pages.
        With LRU Buffer Replacement Strategy for index leaf pages.


    STEP 2
        The type of query is SELECT.


Table: t_students scan count 1, logical reads: (regular=857 apf=0 total=857), physical reads: (regular=0 apf=0 total=0), apf IOs used=0
-----------------------------------------------------------------------------------------
  (A.) 与2.1.(A.)相同
  (B.) 与2.1.(B.)相同
  (C.) "logical reads: (regular=857 apf=0 total=857)" 表示逻辑读为857
  (D.) 与2.1.(D.)相同
  
  (1.) 可见本SQL语句比2.1.的SQL慢.因为更多逻辑+物理读(857>16).
*/


--2.3. 查询表中的少量记录(约1%) ,使用idx_t_students_1 noncluster索引  ,且访问表数据块
select count(a.std_no||a.std_name) from t_students a (index std_name) where a.std_name LIKE "10%"
/*
        Nested iteration.
        Index : idx_t_students_1
        Forward scan.
        Positioning by key.
        Keys are:
            std_name  ASC
        Using I/O Size 2 Kbytes for index leaf pages.
        With LRU Buffer Replacement Strategy for index leaf pages.
        Using I/O Size 2 Kbytes for data pages.
        With LRU Buffer Replacement Strategy for data pages.


    STEP 2
        The type of query is SELECT.


Parse and Compile Time 0.
SQL Server cpu time: 0 ms.
Table: t_students scan count 1, logical reads: (regular=1207 apf=0 total=1207), physical reads: (regular=0 apf=0 total=0), apf IOs used=0
-----------------------------------------------------------------------------------------
  (A.) 与2.1.(A.)相同
  (B.) "Using I/O Size 2 Kbytes for index leaf pages."表示访问了索引数据块
  (C.) "Using I/O Size 2 Kbytes for data pages"表示也访问了表数据块
       因为结果集中只出现的std_no列不在idx_t_students_1(std_name)索引中,
       必须根据索引中的物理行地址,去访问行所在数据块,找出其中的std_no,并放入结果集中.
  (D.) "logical reads: (regular=1207 apf=0 total=1207)" 表示逻辑页读为1207
  (E.) 与2.1.(D.)相同
  
  (1.) 可见本SQL语句比2.1.的SQL慢.因为更多逻辑+物理读(1207>16).
  (2.) 可见本SQL语句比2.1.的SQL多了1207-16=1101的表数据块读取
  (3.) 可见本SQL语句比2.2.的SQL慢(1207>857).
*/

--2.4. 查询表中的全部记录(约7%),使用idx_t_students_1 noncluster索引  ,且访问表数据块
select count(a.std_no||a.std_name) from t_students a (index std_name) where a.std_name>="3" and a.std_name<="36"
/*
    STEP 1
        The type of query is SELECT.
        Evaluate Ungrouped COUNT AGGREGATE.


        FROM TABLE
            t_students
            a
        Nested iteration.
        Index : idx_t_students_1
        Forward scan.
        Positioning by key.
        Keys are:
            std_name  ASC
        Using I/O Size 2 Kbytes for index leaf pages.
        With MRU Buffer Replacement Strategy for index leaf pages.
        Using I/O Size 2 Kbytes for data pages.
        With MRU Buffer Replacement Strategy for data pages.


    STEP 2
        The type of query is SELECT.


Table: t_students scan count 1, logical reads: (regular=6736 apf=0 total=6736), physical reads: (regular=0 apf=0 total=0), apf IOs used=0
-----------------------------------------------------------------------------------------
  (A.) 与2.1.(A.)相同
  (B.) 与2.3.(B.)相同
  (C.) 与2.3.(C.)相同
  (D.) "logical reads: (regular=6736 apf=0 total=6736)" 表示逻辑页读为6736
  (E.) 与2.1.(D.)相同
  
  (1.) 可见本SQL语句比2.1.的SQL慢,因为更多逻辑+物理读(6736>16).
  (2.) 可见本SQL语句比2.2.的SQL慢,因为更多逻辑+物理读(6736>857).
  (3.) 可见本SQL语句比2.5.的SQL慢,因为更多逻辑+物理读(6736>3031)!!!!!!.
*/

--2.5. 查询表中的全部记录(约80%),使用idx_t_students_1 noncluster索引  ,且访问表数据块(Sybase优化器消除了这种执行计划)
select count(a.std_no||a.std_name) from t_students a (index std_name) where a.std_name>="3"
--2.6. 查询表中的少量记录(约1%) ,不使用idx_t_students_1 noncluster索引,只访问表数据块
--drop index t_students.idx_t_students_1
select count(a.std_name) from t_students a where a.std_name LIKE "10%"
--2.7. 查询表中的全部记录(约80%),不使用idx_t_students_1 noncluster索引,只访问表数据块
--drop index t_students.idx_t_students_1
select count(a.std_name) from t_students a where a.std_name>="3"
--2.5.,2.6,2.7三条SQL的执行计划完全一致--
/*
    STEP 1
        The type of query is SELECT.
        Evaluate Ungrouped COUNT AGGREGATE.


        FROM TABLE
            t_students
            a
        Nested iteration.
        Table Scan.
        Forward scan.
        Positioning at start of table.
        Using I/O Size 2 Kbytes for data pages.
        With MRU Buffer Replacement Strategy for data pages.


    STEP 2
        The type of query is SELECT.


Table: t_students scan count 1, logical reads: (regular=3031 apf=0 total=3031), physical reads: (regular=0 apf=0 total=0), apf IOs used=0
-----------------------------------------------------------------------------------------
  (A.) "Table Scan. "表示使用了全表扫描,而未使用指定的索引
  (B.) "Using I/O Size 2 Kbytes for data pages"表示访问了表数据块,当用全表扫描时,已毋需再去访问索引块.
  (C.) "logical reads: (regular=3031 apf=0 total=3031))" 表示逻辑读为3031,也是整个全表扫描所需的逻辑读
  (D.) 与2.1.(D.)相同
  
  (1.) 可见本SQL语句比2.2.的SQL慢. 因为更多逻辑+物理读(3031>857).
  (2.) 可见本SQL语句比2.3.的SQL慢. 因为更多逻辑+物理读(3031>1207).
  (3.) 可见本SQL语句比2.4.的SQL快. 因为更少逻辑+物理读(3031<6736)!!!!!!.
*/


--3. 表记录数对执行计划的影响--
--3.0. 在学生2表学生名上建立非聚集索引--
--drop index t_students2.idx_t_students2_1--
create nonclustered index idx_t_students2_1 on t_students2(std_name)
go

--集合函数count 返回非空的行数

--实验列表(表中有大量记录)--
--3.1. 查询表中的少量记录(约1%) ,使用idx_t_students_1 noncluster索引  ,且不访问表数据块
--3.2. 查询表中的大量记录(约80%),使用idx_t_students_1 noncluster索引  ,且不访问表数据块
--3.3. 查询表中的少量记录(约1%) ,使用idx_t_students_1 noncluster索引  ,且访问表数据块
--3.4. 查询表中的全部记录(约80%),使用idx_t_students_1 noncluster索引  ,且访问表数据块(Sybase优化器消除了这种执行计划)
--3.5. 查询表中的少量记录(约1%) ,不使用idx_t_students_1 noncluster索引,只访问表数据块
--3.6. 查询表中的全部记录(约80%),不使用idx_t_students_1 noncluster索引,只访问表数据块

--实验清单--
--3.1. 查询表中的少量记录(约1%) ,使用idx_t_students2_1 noncluster索引  ,且不访问表数据块
select count(a.std_name) from t_students2 a (index std_name) where a.std_name LIKE "1%"
/*
    STEP 1
        The type of query is SELECT.
        Evaluate Ungrouped COUNT AGGREGATE.


        FROM TABLE
            t_students2
            a
        Nested iteration.
        Index : idx_t_students2_1
        Forward scan.
        Positioning by key.
        Index contains all needed columns. Base table will not be read.
        Keys are:
            std_name  ASC
        Using I/O Size 2 Kbytes for index leaf pages.
        With LRU Buffer Replacement Strategy for index leaf pages.


    STEP 2
        The type of query is SELECT.


Table: t_students2 scan count 1, logical reads: (regular=2 apf=0 total=2), physical reads: (regular=0 apf=0 total=0), apf IOs used=0
-----------------------------------------------------------------------------------------      
  (A.) "Index : idx_t_students2_1"表示使用了该索引
  (B.) "Index contains all needed columns. Base table will not be read."
        表示本查询结果集所需字段都包含在索引中,不需要再通过索引访问表数据块.
  (C.) "logical reads: (regular=2 apf=0 total=2)" 表示逻辑读为2
  (D.) "physical reads: (regular=0 apf=0 total=0)" 表示物理读为0,所需读的数据块都在内存中,无物理I/O
  
  (1.) 可见本SQL语句比2.1.的SQL更快,因为更少逻辑+物理读(2<16).
*/


--3.2. 查询表中的大量记录(约80%),使用idx_t_students2_1 noncluster索引  ,且不访问表数据块
select count(a.std_name) from t_students2 a (index std_name) where a.std_name>="3"
/*
    STEP 1
        The type of query is SELECT.
        Evaluate Ungrouped COUNT AGGREGATE.


        FROM TABLE
            t_students2
            a
        Nested iteration.
        Index : idx_t_students2_1
        Forward scan.
        Positioning by key.
        Index contains all needed columns. Base table will not be read.
        Keys are:
            std_name  ASC
        Using I/O Size 2 Kbytes for index leaf pages.
        With LRU Buffer Replacement Strategy for index leaf pages.


    STEP 2
        The type of query is SELECT.


Table: t_students2 scan count 1, logical reads: (regular=3 apf=0 total=3), physical reads: (regular=0 apf=0 total=0), apf IOs used=0
-----------------------------------------------------------------------------------------
  (A.) 与3.1.(A.)相同
  (B.) 与3.1.(B.)相同
  (C.) "logical reads: (regular=3 apf=0 total=3)" 表示逻辑读为3
  (D.) 与3.1.(D.)相同
  
  (1.) 可见本SQL语句比2.2.的SQL块.因为更多逻辑+物理读(3<857).
*/


--3.3. 查询表中的少量记录(约1%) ,使用idx_t_students2_1 noncluster索引  ,且访问表数据块(Sybase优化器消除了这种执行计划)
select count(a.std_no||a.std_name) from t_students2 a (index std_name) where a.std_name LIKE "1%"
--3.4. 查询表中的全部记录(约80%),使用idx_t_students2_1 noncluster索引  ,且访问表数据块(Sybase优化器消除了这种执行计划)
select count(a.std_no||a.std_name) from t_students2 a (index std_name) where a.std_name>="3"
--3.5. 查询表中的少量记录(约1%) ,不使用idx_t_students2_1 noncluster索引,只访问表数据块
--drop index t_students2.idx_t_students2_1
select count(a.std_name) from t_students2 a where a.std_name LIKE "1%"
--3.6. 查询表中的全部记录(约80%),不使用idx_t_students2_1 noncluster索引,只访问表数据块
--drop index t_students2.idx_t_students2_1
select count(a.std_name) from t_students2 a where a.std_name>="3"
--3.3.,3.4.,3.5,3.6四条SQL的执行计划完全一致--
/*
    STEP 1
        The type of query is SELECT.
        Evaluate Ungrouped COUNT AGGREGATE.


        FROM TABLE
            t_students2
            a
        Nested iteration.
        Table Scan.
        Forward scan.
        Positioning at start of table.
        Using I/O Size 2 Kbytes for data pages.
        With LRU Buffer Replacement Strategy for data pages.


    STEP 2
        The type of query is SELECT.


Table: t_students2 scan count 1, logical reads: (regular=4 apf=0 total=4), physical reads: (regular=0 apf=0 total=0), apf IOs used=0
-----------------------------------------------------------------------------------------
  (A.) "Table Scan. "表示使用了全表扫描,而未使用指定的索引
  (B.) "Using I/O Size 2 Kbytes for data pages"表示访问了表数据块,当用全表扫描时,已毋需再去访问索引块.
  (C.) "logical reads: (regular=4 apf=0 total=4))" 表示逻辑读为4,也是整个全表扫描所需的逻辑读
  (D.) "physical reads: (regular=0 apf=0 total=0)" 表示物理读为0,所需读的数据块都在内存中,无物理I/O
  
  (1.) 可见本SQL语句比3.1.的SQL慢,但相差无几. 因为更多逻辑+物理读(4>2).
  (2.) 可见本SQL语句比3.2.的SQL慢,但相差无几. 因为更多逻辑+物理读(4<3).
  (3.) 可见本SQL语句比2.4.的SQL快. 因为更少的逻辑+物理读(4<3031).
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值