我有以下sql查询只执行1秒钟:
select a.date, b.rate, c.type, a.value from
a inner join b on a.id = b.aid
c inner join b.id = c.bid
where a.name = 'xxx'
但我需要一个结果集来获得速率大于0的结果。所以当我将查询更改为此时需要7分钟才能执行:
select a.date, b.rate, c.type, a.value from
a inner join b on a.id = b.aid
c inner join b.id = c.bid
where a.name = 'xxx' and b.rate>0
为什么这会使查询时间从1秒增加到7分钟?由于b表很大,我甚至尝试使用CTE,但这也没有改善性能。我认为CTE会有较小的值来过滤,所以它应该更快但是没有帮助:
;with x as
(select a.date, b.rate, c.type, a.value from
a inner join b on a.id = b.aid
c inner join b.id = c.bid
where a.name = 'xxx')
select * from x where rate>0
我不能包含执行计划,因为除了查询之外我没有db的权限。
答案 0 :(得分:11)
我的猜测是,执行缓慢的计划是以不幸的方式进行rate>0
过滤,就像在循环连接内部扫描的一部分一样。
如果归结为它,一种解决方案是存储中间结果集并在单独的语句中对其进行过滤。
我建议您理解您无法对供应商的数据库进行更改,并且您基本上卡住了。这实际上是从优化器中取消了一些控制 - 你通常不想做的事情 - 并且还在创建临时表时增加了相对少量的开销。但它应该缓解这种情况的缓慢。如果可能的话,我会继续与您的供应商合作制定索引策略。
select a.date, b.rate, c.type, a.value
into #t
from a inner join b on a.id = b.aid
c inner join b.id = c.bid
where a.name = 'xxx'
select * from #t where rate>0
答案 1 :(得分:0)
答案 2 :(得分:0)
如果您试图通过使用CTE告诉服务器如何优化您的查询,我认为您在开玩笑。使用索引可以获得更好的结果。但在任何情况下,你似乎都有CTE部分。您想要求服务器首先执行CTE,然后评估外部查询。这样也许......
;with x as (Select a.id, a.date, a.value from a where a.name='xxx')
Select x.date, b.rate, c.type, x.value
From x
Inner join b on x.id=b.aid
Inner Join c on b.id=c.bid
where b.rate>0
或
;with x as (
Select b.id, b.rate, c.type
From b
Inner Join c on b.id=c.bid
where b.rate>0)
Select a.date, x.rate, x.type, a.value
From a
Inner join x on a.id=b.id
Where a.name='xxx'
答案 3 :(得分:0)
首先让我解释一下为什么你的计划不好。有一点是我现在能想到的。 当没有比率时。表a是第一个,基于sarg和索引说它估计有10000行。 这可能使用了合并连接。现在要与表b连接(截至现在假设有1到n的映射,并且在平均上,每行有2行形成a)。然后,连接后的估计行数是20000,然后它将与表C连接。现在基于表C的大小,它可以使用说Merge Join.Say实际行数为100<数千
但是,当你添加SARG费率> 0.然后优化器在A和B的连接之后没有估计20K行,而是估计6667行(当没有auto_create_statistics时,默认为> 0的30%)然后它可能选择了与表的嵌套循环连接C而不是合并连接。但是实际的行可能更多,因此嵌套的循环连接可能已经被用于100个数千,因此最终的嵌套循环连接可能需要花费很多时间。
总之,我想说的是,由于额外的sarg,优化器的估计不合理,因此计划不好。
你根本没有在这里创建索引。索引不是每个东西的解决方案,有太多的开销,特别是在你的情况下,较少的restrictiev查询运行得更好所以问题不是做有索引但它更多地与统计数据有关。检查以下
数据库的auto_create_statistics是打开还是关闭?或者表b是否有列速率的统计数据? 何时为这些表更新/创建统计数据? 如果不是首先为此列创建统计信息,我相信您的计划将是正常的。 如果您无法创建统计信息,请尝试强制执行相同的计划而不使用费率> 0 CTE并没有改善代码性能,因此可能存在重复性。这些都可以用来制作 代码更具可读性。
答案 4 :(得分:0)
通过强制合并联接,您也许可以沿着正确的路径发送优化器:
选择... 来自TableA 左合并加入TableB到...
答案 5 :(得分:-2)
部分b>0
彻底改变了它,因为服务器无法再使用聚簇索引和其他方法优化查询。当您添加b>0
时,会将此查询转换为范围查询,这将需要更多时间,因为它确实需要检查更多值。我认为已经有一些优化已经到位,例如像这样的查询的B树组织,但它不会那么多改进。