在使用前一个视图的聚合结果的视图列中使用 IIF 时,SQL 查询变得太慢。请参阅下面的示例以了解清楚

问题描述 投票:0回答:1

亲爱的,我正在打电话给谁可以解决任何SQL查询性能问题

我正在生成一份库存报告,用于处理库存商品的位置,我想向用户显示一个标记“不再可用”,这意味着该位置不可用,因为它是从另一个商品中获取的。

主要是这部分代码完成的。使用以下条件:

IIF(ItemLocationsCount > 1 and ItemsInStock = 0 and StoreId <> MainStoreId, 'Not available any more', Store)

此情况仅针对具有多个位置且数量为 0 的商品(ItemsInStock 列)显示该标志

此聚合正在计算某个项目所占用的位置数量:

ItemsInStockByCurrentItemLocation as (
select   *
        ,(  select 
                count(*)
            from 
                ItemsInStock ItemsInStockLocationsCount
            where 
            ItemsInStock.StoreId = ItemsInStockLocationsCount.StoreId
            group by MainStoreId) ItemLocationsCount
            
from
    ItemsInStock

)

这是显示带有所需标志的整个数据的视图(运行太慢了 30 分钟):

,FilteredUnitifiedConsederingLocation as (
select  (select 
            IIF(ItemLocationsCount > 1 and ItemsInStock = 0 and StoreId <> MainStoreId, 'Not available any more', Store) 
         from 
            ItemsInStockByCurrentItemLocation ItemsInStockByCurrentItemLocationAvalability
         where 
            ItemsInStockByCurrentItemLocationAvalability.StoreId = ItemsInStockByCurrentItemLocation.StoreId and
            ItemsInStockByCurrentItemLocationAvalability.ItemId = ItemsInStockByCurrentItemLocation.ItemId) StoreAvalability,  
        ItemsInStockByCurrentItemLocation.*, 
        MainAndWorkFlowUnitified.Date_P, 
        MainAndWorkFlowUnitified.Date  
from ItemsInStockByCurrentItemLocation
    inner join MainAndWorkFlowUnitified
        on MainAndWorkFlowUnitified.StoreId = ItemsInStockByCurrentItemLocation.StoreId and
            MainAndWorkFlowUnitified.ItemId = ItemsInStockByCurrentItemLocation.ItemId
where 
    --(ItemLocationsCount = 1 or
    --(ItemLocationsCount > 1 and ItemsInStock <> 0))  and 
    (ItemsInStockByCurrentItemLocation.StorePath Like '%' + @StorePath + '%' 
        or (ItemsInStockByCurrentItemLocation.StorePath is null and MSId is not null))
    and ItemsInStockByCurrentItemLocation.ItemPath Like @ItemPath + '%' 
    and (ItemsInStockByCurrentItemLocation.Description is null or ItemsInStockByCurrentItemLocation.Description like '%' + @Description + '%' )
    and (Date_P is null or (Date >= @FromDate and Date <= @ToDate))
)

这是显示整个数据的视图,没有生成所需标志的部分(这运行得太快了 1 秒):

,FilteredUnitified as (
select  ItemsInStock.*, 
        MainAndWorkFlowUnitified.Date_P, 
        MainAndWorkFlowUnitified.Date  
from ItemsInStock
    inner join MainAndWorkFlowUnitified
        on MainAndWorkFlowUnitified.StoreId = ItemsInStock.StoreId and
            MainAndWorkFlowUnitified.ItemId = ItemsInStock.ItemId
where 
    (ItemsInStock.StorePath Like '%' + @StorePath + '%' 
        or (ItemsInStock.StorePath is null and MSId is not null))
    and ItemsInStock.ItemPath Like @ItemPath + '%' 
    and (ItemsInStock.Description is null or ItemsInStock.Description like '%' + @Description + '%' )
    and (Date_P is null or (Date >= @FromDate and Date <= @ToDate))
)

这是在参数值上两者之间发生变化的视图:

ItemsInStocks as (
select 
        distinct
        ItemId,
        ParentGroup,
        Unit,
        Item, ItemPath, 
        StoreAvalability Store, 
        ItemLocationsCount,
        MainStorePath,
        --Store,
        StorePath, 
        ItemsInStock, 
        Description
        ,Code,
        Name,
        NameEn
from FilteredUnitifiedConsederingLocation where @ShowItemsWithUnavailableLocations = 1
union all
select
        distinct
        ItemId,
        ParentGroup,
        Unit,
        Item, ItemPath, 
        Store, 
        null ItemLocationsCount,
        MainStorePath,
        StorePath, 
        ItemsInStock, 
        Description
        ,Code,
        Name,
        NameEn
from FilteredUnitified where @ShowItemsWithUnavailableLocations = 0

我尝试不显示该行,而是放置一个标志。 (可以看相关代码注释)

--(ItemLocationsCount = 1 or
    --(ItemLocationsCount > 1 and ItemsInStock <> 0)) 

但同样的事情正在发生。视图仍然运行太慢

我查阅了知识库中的相关问题,发现有一个建议使用索引: 我认为所有必需的列都像 ItemId、StoreId 和 MainStoreId 一样被索引,因为它们是外键。请注意,如果需要对任何其他列进行索引以优化性能,请告诉我。

sql view
1个回答
0
投票

首先,您的查询应使用

table.column
alias.column
进行格式化,以便用户知道数据来自哪里,而不是猜测哪一列。例如,拥有
VeryLongTableName
会变得模糊,而
VeryLongTableName vltn
更容易通过别名
vltn
来表示。如果您只查询单个表,则没有必要。

我将从每个商店的商品预查询开始。谁在乎有多少,只要它存在,通过对 ItemsInStock > 0 应用 WHERE 子句,您就已经排除了那些不符合条件的产品。

我怀疑无论 MainStoreID 如何,StoreID 都是唯一的,否则数据库关系中的设计会更加可疑,因此出于冗余目的将其保留。但是,您还引用了 MSId 列。 MSId 是“MainStoreID”吗?如果是这样,请不要通过提供两个列名称上下文来混淆问题,或者至少像前面提到的那样通过别名进行澄清。

现在,进入你的WHERE子句,两边都带有通配符的LIKE不能利用任何索引进行优化,它必须扫描每条记录

ItemsAvailablePerStore as 
( 
select distinct 
        StoreID,
        ItemId
    from
        ItemsInStock
    where
        ItemsInStock > 0 
),

现在,我将使用您的主 ItemsInStock 表开始查询,左连接到仅具有现有数量的结果,然后从那里开始。与您的物品描述类似。进一步阅读这个问题,我真的很怀疑数据库的设计得有多好,但仍然愿意提供帮助。下次可以协助设计问题。

AllItems as
(
select
        IIS.*,
        case when ISA.StoreId is null 
            then 'Not available any more'
            else ' ' end StoreAvailability,
        MWF.Date_P,
        MWF.Date
    from
        ItemsInStock IIS
            LEFT JOIN ItemsAvailablePerStore IAPS
                on IIS.StoreId = IAPS.StoreID
                and IIS.ItemID = IAPS.ItemID
            JOIN MainAndWorkFlowUnitified MWF
                on IIS.StoreID = MWF.StoreId 
                and IIS.ItemID = MWF.ItemId 
    where 
        (       IIS.StorePath Like '%' + @StorePath + '%' 
            or ( IIS.StorePath is null and IIS.MainStoreId is not null)
        )
        and IIS.ItemPath Like @ItemPath + '%' 
        and (IIS.Description is null or IIS.Description like '%' + @Description + '%' )
        and (MWF.Date_P is null or ( MWF.Date >= @FromDate and MWF.Date <= @ToDate))
)
© www.soinside.com 2019 - 2024. All rights reserved.