【问题标题】:How to optimize the T-SQL query如何优化 T-SQL 查询
【发布时间】:2011-08-15 10:23:51
【问题描述】:

我正在编写一个 T-SQL 查询,我正在开发电子商务网站,因为我正在使用 4 个主要表:

  1. 产品类别
  2. 产品
  3. OrderLineItem
  4. 订购

我的管理部分有一页用于管理订单,现在我想按ProductCategory 过滤,即Order 包含Product(我的productIdOrderLineItem 表中)与选定的ProductCategory 相关,我通过以下查询执行此操作:

SELECT  
    O.OrderID,O.[OrderDate],O.[StatusID]                          
FROM [Order] O                              
INNER JOIN [Dyve_User] U ON U.[UserID] = O.[UserID]                               
INNER JOIN (SELECT OD.OrderID 
            FROM OrderLineItem OD
            LEFT OUTER JOIN [Product] P ON OD.ProductID = P.ProductID
            LEFT OUTER JOIN [ProductCategory] PC ON PC.CategoryID = P.CategoryID
            WHERE 
               (P.CategoryID = COALESCE(@CategoryID, P.CategoryID)                              
                OR P.CategoryID IN (SELECT CategoryID 
                                    FROM ProductCategory                              
                                    WHERE ParentID = COALESCE(@CategoryID, ParentID)
                                   )
               )                              
           ) AS T  ON O.OrderID = T.OrderID  

我的这个查询返回正确的结果,但是每次查询都会超时,谁能告诉我如何优化这个查询,这样就不会超时了?

以下是表格架构:

CREATE TABLE [dbo].[Order](
[OrderID] [int] IDENTITY(1,1) NOT NULL,
[OrderDate] [datetime] NULL,
[OrderTax] [money] NULL,
[OrderTotal] [money] NULL,
[ShippingCharge] [money] NULL,
[TrackingNumber] [varchar](50) NULL,
[TransactionStatusID] [int] NULL,
[UserID] [int] NULL,
[PromotionCode] [varchar](50) NULL
[ExpiryDate] [datetime] NULL,
[PaymentType] [tinyint] NULL
  CONSTRAINT [Order_PK] PRIMARY KEY CLUSTERED 
  (
[OrderID] ASC
 )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF,          ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
  ) ON [PRIMARY]

产品表:

CREATE TABLE [dbo].[Product](
[ProductID] [int] IDENTITY(1,1) NOT NULL,
[CategoryID] [int] NULL,
[ProductName] [nvarchar](600) NULL,
[ManufacturerID] [int] NULL,
[UnitPrice] [money] NULL,
[RetailPrice] [money] NULL,
[IsOnSale] [bit] NOT NULL,
[ExpiryDate] [datetime] NULL,
[IsElectrical] [bit] NULL,
[IsActive] [bit] NULL,
[ProductType] [int] NULL,
[AllowBackOrder] [bit] NULL
   CONSTRAINT [Product_PK] PRIMARY KEY CLUSTERED 
   (
[ProductID] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF,        ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
   ) ON [PRIMARY]

产品类别表:

CREATE TABLE [dbo].[ProductCategory](
[CategoryID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](100) NOT NULL,
[Description] [nvarchar](max) NULL,
[ParentID] [int] NULL,
[IsActive] [bit] NULL
    CONSTRAINT [ProductCategory_PK] PRIMARY KEY CLUSTERED 
   (
[CategoryID] ASC
   )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF,        ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
  ) ON [PRIMARY]

OrderLineItem 表:

CREATE TABLE [dbo].[OrderLineItem](
[OrderDetailID] [int] IDENTITY(1,1) NOT NULL,
[OrderID] [int] NOT NULL,
[ProductID] [int] NOT NULL
[TotalPrice] [money] NULL,
[Quantity] [int] NULL,
[Discount] [money] NULL,
[UnitPrice] [money] NULL,
[UserID] [int] NULL,
    CONSTRAINT [OrderLineItem_PK] PRIMARY KEY CLUSTERED 
      (
[OrderDetailID] ASC
   )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF,        ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
   ) ON [PRIMARY]

【问题讨论】:

  • 如果您只想查看特定类别的产品,为什么要在这里进行 LEFT JOIN? FROM OrderLineItem OD LEFT OUTER JOIN [ProductCategory] ​​PC ON PC.CategoryID = P.CategoryID WHERE (P.CategoryID = COALESCE(@CategoryID, P.CategoryID)

标签: asp.net sql-server tsql


【解决方案1】:

从以下几点开始:

  1. 在连接和位置列上定义索引。
  2. 从较小的表加入到较大的表中。

我建议阅读有关性能以及如何查找原因的内容 - 这是一篇关于该主题的好文章:part 1part 2

【讨论】:

  • 从小表加入大表是什么意思??
  • @Vijjendra - 从数据较少的表开始,然后加入更大的表。
【解决方案2】:

这未经测试,所以我不确定它是否仍然符合您对查询的预期。

它将获取具有OrderLineItemProductOrders 以及等于@CategoryIDCategoryID@CategoryID 的子类别。

SELECT O.OrderID,
       O.[OrderDate],
       O.[StatusID]
FROM   [Order] AS O
WHERE  O.OrderID IN (SELECT OD.OrderID
                     FROM   OrderLineItem AS OD
                            INNER JOIN Product AS P
                              ON OD.ProductID = P.ProductID
                            INNER JOIN (SELECT PC.CategoryID
                                        FROM   ProductCategory
                                        WHERE  ParentID = @CategoryID
                                        UNION ALL
                                        SELECT @CategoryID) AS C
                              ON P.CategoryID = C.CategoryID)

关于性能,您只需对其进行测试即可找到答案。

索引是个好东西,你应该确保你的外键列上有索引。

【讨论】:

  • 我已经尝试过这种方式,但得到相同的超时错误,请建议我任何其他方式
  • @Vijjendra - 如果您可以使用表结构 (DDL) 更新您的问题,包括任何索引、每个表包含多少行以及您希望通过此查询返回多少行,这可能会有所帮助.您是否尝试在 SSMS 中运行查询?
  • 我的订单表包含大约 15k 行,产品表大约 1.5k 类别表大约 50 和 OrderLineItem 包含大约 22k 行,我想返回 25 或 50 条记录。
  • @Vijjendra - 这并不多。我已经在具有 2GB 内存和 Intel Duo 1,20 GHz 的笔记本电脑上用这么多数据测试了这个查询。花了 300 毫秒。你的超时问题是另外一回事。您是否尝试在 SSMS 中运行查询?
【解决方案3】:

首先尝试延长超时时间以使其正常工作。比掠夺你的执行计划。将元素较少的表移到联接的左侧。

【讨论】:

  • 如何将元素较少的表格移动到联接的左侧?
  • 这是@Oded 评论的“从数据较少的表开始并加入更大的表”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-04
  • 2013-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多