【问题标题】:Improve Performance of SQL query joining 14 tables提高连接 14 个表的 SQL 查询的性能
【发布时间】:2014-03-07 17:11:16
【问题描述】:

我正在尝试加入 14 个表,其中我需要使用左联接加入其中的几个表。 现有数据大约 7000 条记录,执行以下查询大约需要 10 秒。如果记录超过百万条,恐怕会怎样。请帮助我提高以下查询的性能。

CREATE proc [dbo].[GetTodaysActualInvoiceItemSoldHistory]                          
@fromdate datetime,        
@todate datetime        
as                          

Begin                    

select SDID.InvoiceDate as [Sold Date],Cust.custCompanyName as [Sold To] ,   
case SQBD.TransferNo  when '0' then IVM.VendorName else SQBD.TransferNo end as [Purchase From],  
SQBD.BatchSellQty as SoldQty,SQID.SellPrice,  
SDID.InvoiceNo as [Sales Invoice No],INV.PRInvoiceNo as [PO Invoice No],INV.PRInvoiceDate as [PO Invoice Date],   
SQID.ItemDesc as [Item Description],SQID.NetPrice,SDHM.DeliveryHeaderMasterName as   DeliveryHeaderName,    
SQID.ItemCode as [Item Code],           
SQBD.BatchNo,SQBD.ExpiryDate,SQID.Amount,   
SQID.Dept_ID as Dept_ID,              
Dept_Name as [Department],SQID.Catg_ID as Catg_ID,                                    
Category_Name as [Category],SQID.Brand_ID as Brand_ID,               
BrandName as BrandName, SQID.Manf_Id as Manf_Id,                             
Manf.ManfName as [Manufacturer],              
STM.TaxName, SQID.Tax_ID as Tax_ID,              
INV.VendorID as VendorID,              
SQBD.ItemID,SQM.Isdeleted,  
SDHM.DeliveryHeaderMasterID,Cust.CustomerMasterID        
 from  SD_QuotationMaster SQM                  
inner join  SD_InvoiceDetails SDID on SQM.QuoteID = SDID.QuoteID                
inner join  SD_QuoteItemDetails SQID on SDID.QuoteID = SQID.QuoteID               
inner join  SD_QuoteBatchDetails SQBD on SDID.QuoteID = SQBD.QuoteID and SQID.ItemID=SQBD.ItemID              
inner join  INV_ProductInvoice INV on SQBD.InvoiceID=INV.ProductInvoiceID              
inner jOIN  INV_VendorMaster IVM ON INV.VendorID = IVM.VendorID       
inner jOIN  Sys_TaxMaster STM ON SQID.Tax_ID = STM.Tax_ID                 
inner join Cust_CustomerMaster Cust on SQM.CustomerMasterID = Cust.CustomerMasterID    
left jOIN  INV_DeptartmentMaster Dept ON SQID.Dept_ID = Dept.Dept_ID                                       
left jOIN  INV_BrandMaster BRD ON SQID.Brand_ID = BRD.Brand_ID                                       
left jOIN  INV_ManufacturerMaster  Manf ON SQID.Manf_Id = Manf.Manf_Id                
left join INV_CategoryMaster CAT ON SQID.Catg_ID = CAT.Catg_ID                                                              
left join SLRB_DeliveryCustomerMaster SDCM on SQM.CustomerMasterID=SDCM.CustomerMasterID and SQM.DeliveryHeaderMasterID=SDCM.DeliveryHeaderMasterID                                       
left join SLRB_DeliveryHeaderMaster SDHM on SDCM.DeliveryHeaderMasterID=SDHM.DeliveryHeaderMasterID                               
where (SQM.IsDeleted=0)  and SQBD.BatchSellQty > 0          

and SDID.InvoiceDate between @fromdate and @todate                
order by ItemDesc                     

End 

只有下表包含更多的数据,而其他表的记录少于 20

InvoiceDetails, QuoteMaster, QuoteItemDetails, QuoteBatchDetails ProductInvoice

下面是执行计划的链接

http://jmp.sh/CSZc2x2

谢谢。

【问题讨论】:

标签: sql sql-server sql-server-2005


【解决方案1】:

让我们从一个明显的错误开始:

(isnull(SQBD.BatchSellQty,0) > 0)

那个是不可索引的,所以它不应该发生。说真的,在大多数情况下,BatchSellQty 不应该是未知的(可为空的),或者您最好正确处理 null。该字段应该被索引,我不确定我是否希望使用 isNull - 可能有大量批次。另请注意,过滤索引(条件 >0)可能在这里起作用。

其次,检查您是否拥有所有正确的索引以及执行计划是否合理。

因此,您必须使用大量数据进行测试。索引统计数据可能会有所不同。检查时间花在哪里 - 它可能是 tempdb,在这种情况下,您确实需要良好的 tempdb IO 速度....并且它与输入端无关。

【讨论】:

  • NULL永远不会大于0,所以根本不需要使用is null,应该是一个简单的“SQBD.BatchSellQty > 0”
  • 我现在更改了程序。删除了所有列的 isnull 条件。但对于 8000 条记录,仍然需要大约 8 秒。
  • @user2859242 好吧,你很高兴没有做我要求的任何其他事情。检查 tempdb 加载并发布执行的查询计划。
  • 嗨,Tom.. 我实际上是在尝试对几列进行索引。所以没有检查 tempdb 加载。我已经保存了执行计划。请告诉我如何在此处上传附件。
  • @user2859242 很简单——一点也不。把它放在互联网上的某个地方(很多地方),然后用链接编辑你的帖子。
【解决方案2】:

您可以尝试使用query hints 来帮助SQL Server 优化器构建最佳查询执行计划。例如,您可以使用FORCE ORDER 语句强制连接表的顺序。如果您按照在每个步骤中以最小结果大小连接的顺序对表进行排序,则查询将执行得更快(可能需要尝试)。示例:

We need to A join B join C
If A join B = 2000 records x 1000 records = ~400 records (we suspect this result)
And A join C = 2000 records x 10 records = ~3 records (and this)
And B join C = 1000 records x 10 records = 10 000 records (and this)

在这种情况下,最佳顺序将是

A join C join B = ~3 records x 1000 records = ~3000 records

【讨论】:

  • 提示应该是最后的手段。如果收集到了必要的统计信息并且存在匹配索引,则要智取优化器并不容易。
  • 你是绝对正确的,但在这种情况下我没有看到任何其他方式(如果期望外键的索引没有被删除:))。
  • 表和 Zeolot 没有外键,就 Force 顺序而言,就加入而言,一切都很完美。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多