我正在尝试优化以下T-SQL查询:
SELECT Person.*
FROM Person
WHERE ZipCode LIKE '123%'
AND City = 'Washington'
AND NumberOfHomes in (1, 2, 3)
AND
(
EXISTS
(
SELECT * FROM House
WHERE Person.ID = House.PersonID
AND House.Type = 'TOWNHOUSE'
AND House.Size = 'Medium'
)
OR
EXISTS
(
SELECT * FROM Color
WHERE Person.ID = Color.PersonID
AND Color.Foreground IN ('Green', 'Blue', 'Purple')
)
)
我非常感谢您在优化查询时的任何响应。
特别是,有没有办法只使用一个没有任何内部SELECT语句的SELECT语句将查询转换为更有效的查询?
谢谢!
答案 0 :(得分:4)
这是查询:
SELECT p.*
FROM Person p
WHERE p.ZipCode LIKE '123%' AND p.City = 'Washington' AND p.NumberOfHomes in (1, 2, 3) AND
(EXISTS (SELECT *
FROM House h
WHERE p.ID = h.PersonID AND h.Type = 'TOWNHOUSE' AND h.Size = 'Medium'
) OR
EXISTS (SELECT *
FROM Color c
WHERE p.ID = c.PersonID AND c.Foreground IN ('Green', 'Blue', 'Purple')
)
);
如果不重写查询,可以使用索引对其进行优化。我建议:
Person(City, ZipCode, NumberOfHomes, Id);
House(PersonId, Type, Size);
Color(PersonID, Foreground)
问题。您确定身份s in the
众议院and
颜色tables really match back to
Person.Id ? Normally, they would have a column called something like
PersonId`。
答案 1 :(得分:0)
左连接和检查null将比进行存在检查更快。此外,如果NumberofHomes是一个整数,则BETWEEN
与IN
相同。
SELECT p.*
FROM Person p
LEFT JOIN House h
ON p.ID = h.PersonID
AND h.Type = 'TOWNHOUSE'
AND h.Size = 'Medium'
LEFT JOIN Color c
ON p.ID = c.PersonID
AND c.Foreground IN ('Green', 'Blue', 'Purple')
WHERE p.ZipCode LIKE '123%'
AND p.City = 'Washington'
AND p.NumberOfHomes BETWEEN 1 AND 3
AND (h.PersonID is not null or c.PersonID is not null)
或者你可以尝试这样的事情......
select t.*
from (
select personid from house
where type = 'townhouse' and size = 'medium'
union
select personid from color
where foreground in ('green','blue','purple')
) pid
cross apply (
select *
from person p
where p.id = pid.personid
and p.zipcode like '123%'
and p.city = 'washington'
and p.numberofhomes between 1 and 3
) t
where t.id is not null
优化这些盲人真的很难。根据您的数据分布,上述查询可能会给您带来更好的结果。
答案 2 :(得分:0)
请试试这个:
SELECT p.*
FROM Person p
WHERE Substring(Ltrim(Rtrim(p.ZipCode)),1,3) = '123' AND p.City = 'Washington'AND
(p.NumberOfHomes=1 or p.NumberOfHomes=2 or p.NumberOfHomes=3))
AND
(
EXISTS
(
SELECT 1 FROM House h
WHERE p.ID = h.PersonID
AND h.Type = 'TOWNHOUSE'
AND h.Size = 'Medium'
)
OR
EXISTS
(
SELECT 1 FROM Color c
WHERE p.ID = c.PersonID
AND (c.Foreground ='Green' or c.Foreground='Blue' or c.Foreground='Purple')
)
);
这也会更好:
SELECT
p.*
FROM Person p
Left join House h
On (p.Id=h.PersonID)
Left join Color c
On (p.id=c.PersonID)
WHERE Substring(Ltrim(Rtrim(p.ZipCode)),1,3) = '123' AND p.City = 'Washington'AND
(p.NumberOfHomes=1 or p.NumberOfHomes=2 or p.NumberOfHomes=3)) and Isnull(h.Type,'') = 'TOWNHOUSE' AND Isnull(h.Size,'') = 'Medium' AND
(Isnull(c.Foreground,'') ='Green' or Isnull(c.Foreground,'')='Blue' or Isnull(c.Foreground,'')='Purple') and
(h.PersonID is not null or c.PersonID is not null);
答案 3 :(得分:-1)
通常优化并具有多个不同的select语句是不同的主题,因为查询优化器(SQL Server)通常会采用您的sql语句并以它认为最合适的方式运行它。
说是,有几种不同的方法可以将你的语句组合成一个sql语句,这是一个例子。这将保留您的人员表并从符合您标准的House或Color表中获取匹配。
<!-- language:SQL-->
SELECT *
FROM Person Left Outer Join House ON Person.ID = House.PersonID Left Outer Join Color ON
Person.ID= Color.PersonID
WHERE (ZipCode LIKE '123%'
AND City = 'Washington'
AND Person.NumberofHomes in (1, 2, 3) )
AND (
House.Type = 'TOWNHOUSE'
AND House.Size = 'Medium'
)
OR(
Color.Foreground IN ('Green', 'Blue', 'Purple')
)
我建议您重新考虑您的模型。例如,具有颜色的PersonID是非常可疑的,因为具有numberofhomes(例如,可以通过House表上具有该人的id的计数来计算)。还有一些其他可疑的规范化属性。不是你问题的一部分,但我认为你可能想要考虑它。