避免全表扫描

时间:2019-03-21 05:49:03

标签: sql sql-server tsql sql-server-2017

我对以下查询有疑问

UPDATE P 
set    P.price =  (select top 1 PV.price 
                   from  @port_values PV      
                   where PV.pv_id < P.pv_id 
                   and   PV.price is not NULL 
                   and   PV.id    = P.id 
                   order by  PV.pv_id desc) 
FROM   @port_values P 
WHERE  P.price is NULL

它正在做的是回顾历史以查找以前的任何先前的价格值,并将其应用于价格为NULL的地方。 pv_id按日期顺序排列并建立索引。以前是按日期排序的,但性能没有变化。

它以合理的性能工作,但是数据库变得越来越大,这一行代码有效地挂起了查询。对于较小的数据集也可以,但是在@port_values具有约40万行的情况下。显然,它正在执行迭代表扫描,并且根本没有效率。我尝试过将索引放在具有任何性能的列上。

像这样构造查询的最有效方法是什么?

3 个答案:

答案 0 :(得分:0)

由于您的环境不可用,我们无法提供确切的解决方案。但是请尝试下面的方法,让我知道它是否对性能有影响

方法1:

UPDATE P SET  P.price = PV.price
FROM @port_values P
INNER JOIN
(
    SELECT id, price FROM (
    SELECT ROW_NUMBER() OVER(PARTITION BY PV.id ORDER BY PV.pv_id ASC) AS SNO
    ,PV.id
    ,PV.price
    FROM @port_values PV
    WHERE PV.price is not NULL 
    )AS A
    WHERE SNO= 1
)PV ON P.id = PV.ID
WHERE P.price is NULL

方法2:

CREATE TABLE #TAB (ID INT PRIMARY KEY, price DECIMAL(18,2))

INSERT INTO #TAB
SELECT id, price FROM (
SELECT ROW_NUMBER() OVER(PARTITION BY PV.id ORDER BY PV.pv_id ASC) AS SNO
,PV.id
,PV.price
FROM @port_values PV
WHERE PV.price is not NULL 
)AS A
WHERE SNO= 1


UPDATE P SET  P.price = PV.price
FROM @port_values P 
INNER JOIN #TAB PV ON P.id = PV.ID
WHERE P.price is NULL

答案 1 :(得分:0)

请尝试此非标准sql性能是否更好

UPDATE P 
set    P.price =  s.price
FROM   @port_values P
    Outer apply(
        select top 1 PV.price
        from @port_values PV 
        where PV.pv_id < P.pv_id
        and PV.price is not NULL 
        and PV.id = P.id 
        and P.price is null
        order by  PV.pv_id desc ) s
WHERE  P.price is NULL

答案 2 :(得分:0)

使用可更新的CTE:

with toupdate as (
      select p.*,
             lag(p.price) over (partition by p.pv_id order by p.id) as prev_price
      from @port_values p
      where p.price is not null
     )
update toupdate
    set price = prev_price;

为了提高性能,您希望在(pv_id, id, price)上建立索引。在SQL Server的最新版本中,表变量允许使用这些变量。在旧版本中,请使用临时表,以便您可以添加索引。