我有一个请求 - 显示所有学生并为所有参加过“文学”课程的人指明成绩,格式为:全名,成绩:
SELECT T1.FIO, T2.ItogovayaOcenka
FROM ( SELECT DISTINCT ( SELECT Chelovek.FIO
FROM Chelovek
WHERE Chelovek.NumerPassporta = ObuchayushchijsyaNumerPassporta) FIO
FROM Ocenka) T1
LEFT JOIN ( SELECT ( SELECT Chelovek.FIO
FROM Chelovek
WHERE Chelovek.NumerPassporta = ObuchayushchijsyaNumerPassporta ) FIO,
ItogovayaOcenka
FROM Ocenka
WHERE ZHurnal_OcenokKursNazvanie='Литература') T2 ON T2.FIO=T1.FIO;
下面是它的物理计划:
现在,不添加索引,我将查询更改为这个(优化查询):
WITH
T1 AS ( SELECT DISTINCT ( SELECT Chelovek.FIO
FROM Chelovek
WHERE Chelovek.NumerPassporta = ObuchayushchijsyaNumerPassporta) FIO
FROM Ocenka ),
T2 as ( SELECT ( SELECT Chelovek.FIO
FROM Chelovek
WHERE Chelovek.NumerPassporta = ObuchayushchijsyaNumerPassporta) FIO ,
ItogovayaOcenka
FROM Ocenka
WHERE ZHurnal_OcenokKursNazvanie='Литература'),
JOINED AS ( SELECT T1.FIO, T2.ItogovayaOcenka
FROM T1
LEFT JOIN T2 ON T2.FIO=T1.FIO)
SELECT * FROM JOINED;
但是通过 DATEDIFF 的时间测量指标显示第一个(非优化查询)表现更好。而他的物理位面并没有改变:

优化第一个查询的最佳方法是什么?
Chelovek 表定义如下:
CREATE TABLE Chelovek
(
NumerPassporta NVARCHAR(200) PRIMARY KEY NOT NULL CHECK (NumerPassporta!=''),
FIO NVARCHAR(200) UNIQUE NOT NULL CHECK(FIO !='')
);
评价表:
CREATE TABLE Ocenka
(
Id INT IDENTITY ,--PRIMARY KEY,
PromezhutochnyeOcenka1 INT NOT NULL CHECK (PromezhutochnyeOcenka1>0),--ПромежуточныеОценки
PromezhutochnyeOcenka2 INT NOT NULL CHECK (PromezhutochnyeOcenka2>0),--ПромежуточныеОценки
PromezhutochnyeOcenka3 INT NOT NULL CHECK (PromezhutochnyeOcenka3>0),--ПромежуточныеОценки
ItogovayaOcenka int NOT NULL CHECK (ItogovayaOcenka>0),
ZHurnal_OcenokKursNazvanie NVARCHAR(200) NOT NULL CHECK (ZHurnal_OcenokKursNazvanie!=''),
CONSTRAINT FOREIGN_KursNazvanie FOREIGN KEY (ZHurnal_OcenokKursNazvanie) REFERENCES ZHurnal_Ocenok(KursNazvanie),
ObuchayushchijsyaNumerPassporta NVARCHAR(200) NOT NULL CHECK (ObuchayushchijsyaNumerPassporta!=''),
--FOREIGN KEY (ObuchayushchijsyaNumerPassporta) REFERENCES Obuchayushchijsya(NumerPassporta)
CONSTRAINT PRIMARY_KEY_Id PRIMARY KEY(Id)
);
这些表填充在一个循环中:
Declare @_NumPass varchar(11)
Set @_NumPass = ''
Declare @_FIO varchar(80)
Set @_FIO = ''
Declare @_PromezhutochnyeOcenka1 int
Set @_PromezhutochnyeOcenka1 = 0
Declare @_PromezhutochnyeOcenka2 int
Set @_PromezhutochnyeOcenka2 = 0
Declare @_PromezhutochnyeOcenka3 int
Set @_PromezhutochnyeOcenka3 = 0
Declare @_ItogovayaOcenka int
Set @_ItogovayaOcenka = 0
Declare @_ZHurnal_OcenokKursNazvanie varchar(80)
Set @_ZHurnal_OcenokKursNazvanie = ''
Declare @RandNumForSubject int
Set @RandNumForSubject=0
Declare @top int
Set @top = 1000000
Declare @cnt int
Set @cnt = 0
While @cnt < @top
Begin
set @_NumPass = convert(varchar(36),newid())
set @_FIO = convert(varchar(36),newid())
set @RandNumForSubject = ABS(CHECKSUM(NEWID())) % 7+1
IF @RandNumForSubject = 1
BEGIN
set @_ZHurnal_OcenokKursNazvanie='Matematica'
END;
IF @RandNumForSubject = 2
BEGIN
set @_ZHurnal_OcenokKursNazvanie='История'
END;
IF @RandNumForSubject = 3
BEGIN
set @_ZHurnal_OcenokKursNazvanie='Литература'
END;
IF @RandNumForSubject = 4
BEGIN
set @_ZHurnal_OcenokKursNazvanie='География'
END;
IF @RandNumForSubject = 5
BEGIN
set @_ZHurnal_OcenokKursNazvanie='Базовая'+'информатика'
END;
IF @RandNumForSubject = 6
BEGIN
set @_ZHurnal_OcenokKursNazvanie='Биология'
END;
IF @RandNumForSubject = 7
BEGIN
set @_ZHurnal_OcenokKursNazvanie='Химия'
END;
set @_PromezhutochnyeOcenka1 = ABS(CHECKSUM(NEWID())) % 5+1
set @_PromezhutochnyeOcenka2 = ABS(CHECKSUM(NEWID())) % 5+1
set @_PromezhutochnyeOcenka3 = ABS(CHECKSUM(NEWID())) % 5+1
set @_ItogovayaOcenka = (@_PromezhutochnyeOcenka1+@_PromezhutochnyeOcenka2+@_PromezhutochnyeOcenka3)/3
Insert Into Chelovek values (@_NumPass,@_FIO)
Insert Into Ocenka values (@_PromezhutochnyeOcenka1,@_PromezhutochnyeOcenka2,@_PromezhutochnyeOcenka3,@_ItogovayaOcenka,@_ZHurnal_OcenokKursNazvanie,@_NumPass)
Set @cnt = @cnt + 1
End
在任务“您需要显示所有学生并为所有参加过该课程的人指明“文学”课程的成绩,格式为:全名,成绩”,查询看起来要简单得多。您需要带走所有学生并为该科目的成绩进行左连接。或多或少是这样的:
计划:
优化 - 添加 ZHurnal_OcenokKursNazvanie 搜索的索引和 ItogovayaOcenka、ObuchayushchijsyaNumerPassporta 的选择 - SSMS 建议:
计划: