簡體   English   中英

SQL Server-在多個表上查詢時創建索引?

[英]SQL Server - Create Index on query over multiple tables?

我在優化特定的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. 我還能做些什么來改善我的表現?

這不是一個完整的答案 ,而是有關現有語法的注釋中您的問題的答案。
代替:

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 
    )

用這個:

WHERE   EXISTS ( 
        SELECT  1
        FROM    [Scanresultebay] t1
                INNER JOIN [ProductEbay] ON [ProductEbay].id = t1.ProductEbayId 
                INNER JOIN [Category] ON [Category].Id = ProductEbay.CategoryID 
        WHERE   [ProductEbay].categoryid = @categoryid  
        AND [ProductEbay].expired is null 
        AND [Scanresultebay].productebayid = t1.productebayid
    )

請注意,我已經將[Scanresultebay].productebayid從主查詢的where子句移到內部查詢的where子句中。 Exists將計算為true括號返回結果中查詢,否則false

另外,最后一個in運算符應替換為= ,因為select SELECT max(Id)將僅返回單個值。

我將嘗試將此查詢重寫為類似的內容(這僅是使用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是加入的關鍵。 上面的查詢(調整后)可以添加到上面的第一個查詢中,並加入最終查詢中。

我缺少用於格式和語法檢查的好工具,因此請原諒上面的任何錯誤。

您應該為每個外鍵創建索引。

如果where子句包含單個表的多個字段,則還應該在這些組合上創建索引。

編輯:

詳細說明:

  1. 索引是全局的。 不特定於查詢。
  2. 100個類別非常小。 您有很多加入(所有都是必要的)
  3. 創建索引將極大地提高性能!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM