简体   繁体   English

SQL Server T-SQL查询优化

[英]SQL Server T-SQL Query Optimization

I am trying to optimize the following T-SQL query: 我正在尝试优化以下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')
    )
)

I'd greatly appreciate any response in optimizing the query. 我非常感谢优化查询的任何响应。

In particular, is there a way to convert the query into a more efficient query using only a single SELECT statement without any of the inner SELECT statements? 特别是,有没有办法只使用一个没有任何内部SELECT语句的SELECT语句将查询转换为更有效的查询?

Thanks! 谢谢!

This is the query: 这是查询:

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')
              )
      );

Without rewriting the query, you can optimize this with indexes. 如果不重写查询,可以使用索引对其进行优化。 I would recommend: 我建议:

Person(City, ZipCode, NumberOfHomes, Id);
House(PersonId, Type, Size);
Color(PersonID, Foreground)

Question, though. 但问题是。 Are you sure that the id s in the House and Color tables really match back to Person.Id ? Normally, they would have a column called something like 你确定的ID s in theand颜色tables really match back to Person.Id ? Normally, they would have a column called something like ? Normally, they would have a column called something like PersonId`. ? Normally, they would have a column called something like PersonId` ? Normally, they would have a column called something like

Left join and checking for null will be quicker than doing existence checks. 左连接和检查null将比进行存在检查更快。 Also, if NumberofHomes is an integer, doing BETWEEN will be the same as IN . 此外,如果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)

OR you can try something like this... 或者你可以尝试这样的东西......

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

It's really difficult to optimize these blind. 优化这些盲人真的很难。 Depending on the distribution of your data, the above query may give you better results. 根据您的数据分布,上述查询可能会给您带来更好的结果。

Please try this: 请试试这个:

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')
)
);

Also this will work better: 这也会更好:

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);

Often optimizing and having several different select statements are different topics as the query optimizer (SQL Server) often will take your sql statement and run it the way it sees to be the most efficient way it sees fit. 通常优化和具有多个不同的select语句是不同的主题,因为查询优化器(SQL Server)通常会采用您的sql语句并以它认为最合适的方式运行它。

Saying that yes are several different ways you can take your statements and combine them into one sql statement here is an example. 说这是肯定的几种不同的方法,你可以把你的语句和它们组合成一个sql语句这里是一个例子。 This will preserve your person table and get matches from House OR Color tables that match your criteria. 这将保留您的人员表并从符合您条件的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')
    )

I would recommend that you reconsider your model. 我建议你重新考虑你的模型。 For example, having PersonID in color is very suspect as is having numberofhomes (that could be possibly calculated for example, from a count on the House table that has the person's id). 例如,具有颜色的PersonID是非常可疑的,因为具有numberofhomes(例如,可能可以通过House表上具有该人的id的计数来计算)。 There are some other questionable normalization attributes as well. 还有一些其他可疑的规范化属性。 Not part of your question but I thought you might want to consider it. 不是你问题的一部分,但我认为你可能想要考虑它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM