提高 SQL Server 中大表的 SELECT 查询性能

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

问: 如何提高查询的性能?

详情: 我有一张包含 200k 条记录的表

(Sales)
和一个函数
getView_sls(@TON_orNPS)

以下查询需要10-12秒

SELECT * FROM Sales 

以下查询需要32-34秒

SELECT * FROM getView_sls('TON')

以下是我的销售表结构:

USE [WaterfallDB]
GO

/****** Object:  Table [dbo].[Sales]    Script Date: 07/09/2013 11:39:17 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[Sales](
    [year] [varchar](4) NOT NULL,
    [nslschnl] [varchar](2) NULL,
    [distchnl] [varchar](2) NULL,
    [chl6] [varchar](20) NOT NULL,
    [sku] [varchar](15) NOT NULL,
    [ton01] [float] NULL,
    [ton02] [float] NULL,
    [ton03] [float] NULL,
    [ton04] [float] NULL,
[ton05] [float] NULL,
[ton06] [float] NULL,
[ton07] [float] NULL,
[ton08] [float] NULL,
[ton09] [float] NULL,
[ton10] [float] NULL,
[ton11] [float] NULL,
[ton12] [float] NULL,
[nps01] [float] NULL,
[nps02] [float] NULL,
[nps03] [float] NULL,
[nps04] [float] NULL,
[nps05] [float] NULL,
[nps06] [float] NULL,
[nps07] [float] NULL,
[nps08] [float] NULL,
[nps09] [float] NULL,
[nps10] [float] NULL,
[nps11] [float] NULL,
[nps12] [float] NULL,

  CONSTRAINT [PK_Sales] PRIMARY KEY CLUSTERED 
(
    [year] ASC,
    [chl6] ASC,
    [sku] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

以下是我的功能

USE [WaterfallDB]
GO
/****** Object:  UserDefinedFunction [dbo].[getView_sls]    Script Date: 07/09/2013 11:55:56 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[getView_sls] (@TON_or_NPS nvarchar(10))
RETURNS TABLE
AS
RETURN(

SELECT     
dbo.Sales.year, 
dbo.Sales.nslschnl, 
dbo.Sales.distchnl, 

SUBSTRING(dbo.Sales.chl6,12,7) AS chl6, 
BI.dbo.View_ch.chl5, 
BI.dbo.View_ch.chl4, 
BI.dbo.View_ch.chl3, 

dbo.Sales.sku,
ISNULL(BI.dbo.SKU.descr, ISNULL(dbo.Sales.SKU,'Undefined')) AS SKU_descr,
BI.dbo.SKU.bp,
BI.dbo.SKU.ccatg,

SUBSTRING(BI.dbo.SKU.phl5,0,3) AS phl1,
ISNULL(BI.dbo.phl1.descr, ISNULL(CAST(SUBSTRING(BI.dbo.SKU.phl5,0,3) AS VARCHAR(13)),'Uncategorized')) AS phl1_descr,
SUBSTRING(BI.dbo.SKU.phl5,0,4) AS phl2,
ISNULL(BI.dbo.phl2.descr, ISNULL(CAST(SUBSTRING(BI.dbo.SKU.phl5,0,4) AS VARCHAR(13)),'Uncategorized')) AS phl2_descr,
SUBSTRING(BI.dbo.SKU.phl5,0,6) AS phl3,
ISNULL(BI.dbo.phl3.descr, ISNULL(CAST(SUBSTRING(BI.dbo.SKU.phl5,0,6) AS VARCHAR(13)),'Uncategorized')) AS phl3_descr,
SUBSTRING(BI.dbo.SKU.phl5,0,10) AS phl4,
ISNULL(BI.dbo.phl4.descr, ISNULL(CAST(SUBSTRING(BI.dbo.SKU.phl5,0,10) AS VARCHAR(13)),'Uncategorized')) AS phl4_descr,
BI.dbo.SKU.phl5 AS phl5,
ISNULL(BI.dbo.phl5.descr, ISNULL(BI.dbo.SKU.phl5,'Uncategorized')) AS phl5_descr,

BI.dbo.SKU.crpbrd, 
ISNULL(BI.dbo.crpbrd.descr, ISNULL(BI.dbo.SKU.crpbrd,'Uncategorized')) AS crpbrd_descr,
BI.dbo.SKU.rngbrd, 
ISNULL(BI.dbo.rngbrd.descr, ISNULL(BI.dbo.SKU.rngbrd,'Uncategorized')) AS rngbrd_descr,
BI.dbo.SKU.brdden, 
ISNULL(BI.dbo.brdden.descr, ISNULL(BI.dbo.SKU.brdden,'Uncategorized')) AS brdden_descr,


CASE @TON_or_NPS WHEN 'TON' THEN dbo.Sales.ton01 / 1000 ELSE dbo.Sales.nps01 / 1000000 END AS ton01,
CASE @TON_or_NPS WHEN 'TON' THEN dbo.Sales.ton02 / 1000 ELSE dbo.Sales.nps02 / 1000000 END AS ton02,
CASE @TON_or_NPS WHEN 'TON' THEN dbo.Sales.ton03 / 1000 ELSE dbo.Sales.nps03 / 1000000 END AS ton03,
CASE @TON_or_NPS WHEN 'TON' THEN dbo.Sales.ton04 / 1000 ELSE dbo.Sales.nps04 / 1000000 END AS ton04,
CASE @TON_or_NPS WHEN 'TON' THEN dbo.Sales.ton05 / 1000 ELSE dbo.Sales.nps05 / 1000000 END AS ton05,
CASE @TON_or_NPS WHEN 'TON' THEN dbo.Sales.ton06 / 1000 ELSE dbo.Sales.nps06 / 1000000 END AS ton06,
CASE @TON_or_NPS WHEN 'TON' THEN dbo.Sales.ton07 / 1000 ELSE dbo.Sales.nps07 / 1000000 END AS ton07,
CASE @TON_or_NPS WHEN 'TON' THEN dbo.Sales.ton08 / 1000 ELSE dbo.Sales.nps08 / 1000000 END AS ton08,
CASE @TON_or_NPS WHEN 'TON' THEN dbo.Sales.ton09 / 1000 ELSE dbo.Sales.nps09 / 1000000 END AS ton09,
CASE @TON_or_NPS WHEN 'TON' THEN dbo.Sales.ton10 / 1000 ELSE dbo.Sales.nps10 / 1000000 END AS ton10,
CASE @TON_or_NPS WHEN 'TON' THEN dbo.Sales.ton11 / 1000 ELSE dbo.Sales.nps11 / 1000000 END AS ton11,
CASE @TON_or_NPS WHEN 'TON' THEN dbo.Sales.ton12 / 1000 ELSE dbo.Sales.nps12 / 1000000 END AS ton12

FROM                
dbo.Sales 
LEFT OUTER JOIN
  BI.dbo.SKU ON dbo.Sales.sku = BI.dbo.SKU.sku 

LEFT OUTER JOIN
  BI.dbo.View_ch ON dbo.Sales.distchnl = BI.dbo.View_ch.distchnl AND SUBSTRING(dbo.Sales.chl6,12,7) = BI.dbo.View_ch.chl6

LEFT OUTER JOIN
  BI.dbo.crpbrd ON BI.dbo.SKU.crpbrd = BI.dbo.crpbrd.crpbrd
LEFT OUTER JOIN
  BI.dbo.rngbrd ON BI.dbo.SKU.rngbrd = BI.dbo.rngbrd.rngbrd 
 LEFT OUTER JOIN
  BI.dbo.brdden ON BI.dbo.SKU.brdden = BI.dbo.brdden.brdden
LEFT OUTER JOIN
  BI.dbo.phl1 ON SUBSTRING(BI.dbo.SKU.phl5,0,3) = BI.dbo.phl1.phl1
LEFT OUTER JOIN
  BI.dbo.phl2 ON SUBSTRING(BI.dbo.SKU.phl5,0,4) = BI.dbo.phl2.phl2
LEFT OUTER JOIN
  BI.dbo.phl3 ON SUBSTRING(BI.dbo.SKU.phl5,0,6) = BI.dbo.phl3.phl3
LEFT OUTER JOIN
  BI.dbo.phl4 ON SUBSTRING(BI.dbo.SKU.phl5,0,10) = BI.dbo.phl4.phl4
LEFT OUTER JOIN
  BI.dbo.phl5 ON BI.dbo.SKU.phl5= BI.dbo.phl5.phl5  
)
sql performance t-sql sql-server-2005 query-performance
2个回答
0
投票

由于 200k 条记录并不算大,而且查询需要很长时间,因此您很可能丢失了一个重要的索引。在您经常选择的列上要么有聚集索引和标识列,要么有非聚集索引,即

year

还尝试显式地声明你的列名,

SELECT *
并不是真正需要的,你打算每次运行查询时带回200k行吗?

要创建非聚集索引,您可以执行以下操作:

CREATE NONCLUSTERED INDEX IX_SALES_Year 
    ON dbo.Sales (Year); 

您可能想要应用其中的一些并运行查询以查看哪一个最有效。我还建议查看数据库调整向导,这可能会为您提供更多指导。


0
投票

首先,如果这是我的表,我将创建一个数字主键而不是 varchar 复合聚集索引。请记住,非数字索引总是比数字列索引慢。

其次,尝试在查询中使用较多的列上创建非聚集索引,因此好的公式是根据需求在主数字索引和更多非聚集(数字或非数字)索引上创建索引。

第三,始终避免在连接中使用部分列值,这可以工作,但会极大地降低选择的性能。为此,您可以为这些值创建更多列并在更新或插入时保存。这将在更新或插入时花费几毫秒,但在选择完整列名称或加入这些列时可以节省很多时间。

这些东西在我 14 年的数据库工作中总是对我有帮助,包括 Teradata 和 SQL Server 中非常大的表。我希望这些技巧能够帮助您和其他人。

© www.soinside.com 2019 - 2024. All rights reserved.