【发布时间】:2011-12-21 14:15:33
【问题描述】:
我在Microsoft T-SQL Performance Tuning whitepaper 中读到,相关子查询在大型表上的性能方面可能代价高昂:
...将此与第一个进行比较 扫描整个表并为每个表执行相关子查询的解决方案 排。在一张小桌子上,性能上的差异可以忽略不计。但在一张大桌子上 可能需要数小时的处理时间...
是否有一种通用方法可以将具有基于不同标准的多个聚合的查询作为相关子查询转换为使用JOINs 而不是相关子查询的单个查询?
考虑一个例子:
准备架构:
CREATE TABLE Student (
ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
Name NVARCHAR(255) NOT NULL
);
CREATE TABLE Grade (
ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
StudentID INT NOT NULL FOREIGN KEY REFERENCES Student(ID),
Score INT NOT NULL,
CONSTRAINT CK_Grade_Score CHECK (Score >= 0 AND Score <= 100)
);
INSERT INTO Student (Name) VALUES ('Steven');
INSERT INTO Student (Name) VALUES ('Timmy');
INSERT INTO Student (Name) VALUES ('Maria');
INSERT INTO Grade (StudentID, Score) VALUES (1, 90);
INSERT INTO Grade (StudentID, Score) VALUES (1, 81);
INSERT INTO Grade (StudentID, Score) VALUES (1, 82);
INSERT INTO Grade (StudentID, Score) VALUES (1, 82);
INSERT INTO Grade (StudentID, Score) VALUES (2, 99);
INSERT INTO Grade (StudentID, Score) VALUES (2, 63);
INSERT INTO Grade (StudentID, Score) VALUES (2, 97);
INSERT INTO Grade (StudentID, Score) VALUES (2, 90);
INSERT INTO Grade (StudentID, Score) VALUES (3, 66);
INSERT INTO Grade (StudentID, Score) VALUES (3, 61);
INSERT INTO Grade (StudentID, Score) VALUES (3, 60);
有问题的查询:
SELECT Name,
(SELECT AVG(Score) FROM Grade WHERE StudentID = Student.ID AND Score < 65) AS 'F',
(SELECT AVG(Score) FROM Grade WHERE StudentID = Student.ID AND Score >= 65 AND Score < 70) AS 'D',
(SELECT AVG(Score) FROM Grade WHERE StudentID = Student.ID AND Score >= 70 AND Score < 80) AS 'C',
(SELECT AVG(Score) FROM Grade WHERE StudentID = Student.ID AND Score >= 80 AND Score < 90) AS 'B',
(SELECT AVG(Score) FROM Grade WHERE StudentID = Student.ID AND Score >= 90 AND Score <= 100) AS 'A'
FROM Student
产生以下结果:
Name F D C B A
-----------------------------------------
Steven NULL NULL NULL 81 90
Timmy 63 NULL NULL NULL 95
Maria 60 66 NULL NULL NULL
我知道您可以在 COUNT() 中使用的技术,您可以在其中执行单个 SELECT 和 JOIN,然后使用 CASE 语句在主键行时选择性地向计数器添加 1在您的加入和您的条件为真之间。我正在寻找一种类似的技术,可以应用于不同类型的聚合(而不仅仅是COUNT)。
有没有一种有效的方法可以将此示例查询转换为使用JOIN 而不是多个子查询?
【问题讨论】:
标签: sql optimization aggregation correlated-subquery