SQL Server - 在多个表上查询时创建索引?

时间:2015-08-24 07:13:56

标签: sql sql-server indices

我在优化特定的SQL查询方面遇到了很大的问题。它包含多个内部联接,并且为每个表添加索引根本不会提高性能。

我的查询:

declare @categoryid  int = 2;

SELECT  [Scanresultebay].Id
        , [Scanresultebay].Productebayid
        , [Scanresultebay].Price
        , [Scanresultebay].Stockamount
        , [Scanresultebay].Timestamp
        , [Category].Categoryname
        , (
            SELECT TOP 1 [Scanresultebay].price
            FROM    [Scanresultebay]
                    INNER JOIN [Productebay] ON [Productebay].id = .[Scanresultebay].productebayid
                    INNER JOIN [EbaySeller] on [EbaySeller].id = [ProductEbay].ebaysellerid
            WHERE   [dbo].[EbaySeller].id = 28
                    and [ProductEbay].categoryid = @categoryid
            ORDER BY [Scanresultebay].Id DESC
        ) AS 'OurPrice'
FROM    [Scanresultebay]
        INNER JOIN [Productebay] ON [Productebay].Id = [Scanresultebay].productebayid 
        INNER JOIN [Category] ON [Category].Id = [Productebay].categoryid 
WHERE   [Scanresultebay].productebayid in ( 
            SELECT  [Scanresultebay].productebayid
            FROM    [Scanresultebay]
                    INNER JOIN [ProductEbay] ON [ProductEbay].id = [ScanResultEbay].ProductEbayId 
                    INNER JOIN [Category] ON [Category].Id = ProductEbay.CategoryID 
            WHERE   [ProductEbay].categoryid = @categoryid  and [ProductEbay].expired is null 
            GROUP BY [Scanresultebay].ProductEbayId 
        )
        and [Scanresultebay].Id in (
            SELECT  max(Id)
            FROM    [Scanresultebay]
            WHERE   productebayid = [Scanresultebay].ProductEbayId 
                    and [Scanresultebay].Price <> 0 
            GROUP BY [Scanresultebay].[ProductEbayId]
        );

我的索引(正如SQL Server建议的那样):

CREATE NONCLUSTERED INDEX [ind_GetPrice]
ON [dbo].[ScanResultEbay] ([Id],[ProductEbayId]) include ([Stockamount], [Timestamp],  [Price])

我需要此查询才能在我网站的信息中心上显示信息。因此,我必须使用此查询遍历每个类别(总共100个)。这持续30-40秒,这当然太过分了。

创建视图是一个问题,因为我必须为子查询声明categoryid的参数,并且参数不能传递给视图。

所以我的问题:

  1. 我是否可以为此查询执行特定索引,因此速度更快(现在需要0.5秒)。
  2. 由于这些子查询,我的查询是否太长(或无效)?
  3. 我还能做些什么,以提高我的表现?

2 个答案:

答案 0 :(得分:2)

我会尝试将此查询重写为类似的内容(这只是使用CTE的概念证明):

declare @categoryid  int = 2;

with products_a as (
    select  [scanresultebay].productebayid
                from    [scanresultebay]
                        inner join [productebay] on [productebay].id = [scanresultebay].productebayid 
                        inner join [category] on [category].id = productebay.categoryid 
                where   [productebay].categoryid = @categoryid  and [productebay].expired is null 
                group by [scanresultebay].productebayid 
    ), -- 1st from where clause
    products_b as (
    select  max(id) id
                from    [scanresultebay]
                where   productebayid = [scanresultebay].productebayid 
                        and [scanresultebay].price <> 0 
                group by [scanresultebay].[productebayid]
    ), -- 2nd from where clause
    items as (
    select  [scanresultebay].id
            , [scanresultebay].productebayid
            , [scanresultebay].price
            , [scanresultebay].stockamount
            , [scanresultebay].timestamp
            , [category].categoryname
    from    [scanresultebay]
            inner join [productebay] on [productebay].id = [scanresultebay].productebayid 
            inner join [category] on [category].id = [productebay].categoryid 
    )
    select
        items.*
    from    
        items 
        join
            products_a
        on
            products_a.productebayid = items.productebayid
        join
            products_b
        on
            products_b.id = items.id
    ;

它消除了IN,并且通过拆分查询,可以更轻松地检查/优化部分查询。

我无法运行它,所以可能会出现小错误。

它不包含关于价格的部分 - 我没有抓住你使用的连接, 但我会使用类似的东西(作为上述查询的一部分):

select id,
[scanresultebay].productebayid,
price,
row_number() over (partition by [scanresultebay].productebayid order by [scanresultebay].id desc) nr -- top price is nr = 1 per each [scanresultebay].productebayid
from    [scanresultebay]
        inner join [productebay] on [productebay].id = .[scanresultebay].productebayid
        inner join [ebayseller] on [ebayseller].id = [productebay].ebaysellerid
where   [dbo].[ebayseller].id = 28
        and [productebay].categoryid = @categoryid

我认为[scanresultebay].productebayid是加入的关键。 上面的查询(调整后)可以添加到上面的第一个查询并加入 在最后的查询中。

我缺乏格式和语法检查的好工具,所以请原谅上面的任何错误。

答案 1 :(得分:0)

您应该为每个外键创建索引。

如果你的where子句包含单个表的多个字段,那么你也应该在这些组合上创建索引。

编辑:

详细说明:

  1. 索引是全球性的。不具体查询。
  2. 100个类别非常小。你有很多联接(都是必要的)
  3. 创建索引会大大提高性能!