优化SQL存储过程

时间:2009-05-06 19:47:42

标签: sql optimization stored-procedures select

在大型表上运行SELECT的存储过程超时。 where子句导致超时,因为我只选择另一个表中的城市。

AND city IN (SELECT DISTINCT city from tOH where clientId = @clientId)
AND state IN (SELECT DISTINCT state from tOH where clientId = @clientId)

*注意几乎总是只返回一个州

我正在尝试将城市放入一个表格,然后使用该表格来填充城市,但我收到的错误是@cities未被声明。

DECLARE @cities TABLE
(
city varchar(200)
);
INSERT INTO @cities (city) SELECT city FROM tOH WHERE clientId = @clientId GROUP BY city

然后我的where子句改为

AND city IN (SELECT city from @cities) 

有人能找到优化此存储过程的好方法吗?

----------------------------更新------------------ ------------------

连接速度太慢了。我认为具有临时表或表变量的解决方案将起作用。

12 个答案:

答案 0 :(得分:8)

不仅速度慢,而且不正确。

假设您的城市是“威斯康星州埃文斯维尔”,但您的tOH表只有“Evansville,IN”和“密尔沃基,威斯康星州”的条目。您目前单独检查城市和州的部分,因此您现有的查询将找到“Evansville”和“WI”的匹配项。它将允许这个城市,即使它真的不应该。

请改为:

INNER JOIN 
  ( 
    SELECT DISTINCT City AS tOHCity, State AS tOHState 
    FROM tOH 
    WHERE ClientID= @ClientID 
  ) cs ON cs.tOHCity = city AND cs.tOHState = state

请注意,子查询基于以下假设:原始帖子中的DISTINCT是必需的,因为每个客户端可能在该表中有多个相同的城市。如果不是这种情况,您可以直接加入tOH表。

将此与正确的索引相结合,你应该很好。

答案 1 :(得分:4)

我会在tOH表上尝试JOIN并通过clientid过滤整个查询。您也可以使用SELECT INTO将其放入临时表中。

答案 2 :(得分:4)

来自SQL Hacks:

  

当子查询不包含时   聚合函数,很有可能   不需要子查询 - 你需要一个   JOIN。

因此,您应该将第一个子查询(AND CITY IN)转换为JOIN。除非您向我们提供剩下的查询,否则我们无法准确地向您展示如何,但它的基础是将City添加为您在主查询中选择的表。

答案 3 :(得分:4)

我认为值得指出遭遇超时背后的原因。您的查询从原始表中选择每一条记录,然后对于它选择的每条记录,它必须为每条记录反复查询同一表中的DISTINCT城市列表。

答案 4 :(得分:1)

您可能希望查看在State列上放置索引,但是您应该对此进行一些基准测试。在插入新行时,您必须权衡索引的好处与成本。

您可能还想对City列执行相同的操作。

答案 5 :(得分:1)

使用EXISTS代替IN

AND EXISTS(SELECT 1 FROM tOH WHERE tOH.city=main.city AND clientId=@clientId)

您还需要确保在两个表格中对该城市编制索引。

答案 6 :(得分:1)

你可能已经尝试过了,但我的第一反应是使用你的城市填充临时表。这可能是你正在做的事情,我只是不熟悉语法,但我一直在使用:

Create Table #Cities(City varchar(200))

然后你将在你的例子中填写临时表和查询(INSERT INTO ...和AND city IN(从#Cities中选择城市))

答案 7 :(得分:1)

我假设关于tOH的DISTINCT的原因是城市名称可能存在于多个州,同样,由于每个州都有多个城市,因此州有多次出现。

如果每个城市和州的组合是一个独特的事件,那么放弃DISTINCT并做类似以下的事情会更合适和更具成本效益:

select mytable.* 
from mytable m
inner join tOH t on  t.clientid = @clientId 
    and t.city = m.city and t.state = m.state

答案 8 :(得分:0)

select ....
from ....
    inner join tOH ON ...city=tOH.city and ...state=tOH.state
where ... and tOH.clientId = @clientId

答案 9 :(得分:0)

在回答你为什么@cities作为表变量可能不起作用的问题时,你还没有展示sp的其余部分,但我会在某处构建动态SQL并执行它。那个woudl超出了以前存在的表变量的范围。

答案 10 :(得分:0)

您可以使用原始查询(不加入联接),进行下一次更正:

  1. 通过clientID,city,state
  2. 在TOH上创建索引
  3. 删除DISTINCT关键字 - 这允许优化器有效地使用该索引

答案 11 :(得分:0)

将您的IN过滤器更改为存在。所以而不是:

AND city IN (SELECT DISTINCT city from tOH where clientId = @clientId)
AND state IN (SELECT DISTINCT state from tOH where clientId = @clientId)

将其更改为:

AND EXISTS ( 
      SELECT 0 FROM tOH t WHERE 
      ClientID = @clientId 
      and t.City = parent.ctiy 
      and t.state = parent.state 
)

我已经完成了性能测试,并且总是发现EXISTS的执行速度比IN快。此外,由于你使用同一张桌子进行了两次,所以你获得了双击。

如果可能,您还应该在tOH中为城市和州编制索引。索引是一种参考,因此请确保您了解添加它们的含义。