2013-04-10 110 views
1

我有一個SQL優化問題的工程實踐,我認爲這是一個典型案例,並且會幫助很多人。SQL優化的典型性能案例

SQL SERVER 2005,

首先,創建主表。這是一個人信息表。

CREATE TABLE [dbo].[OLAPAgentDim](
    [RoleID] [varchar](50) NULL CONSTRAINT [DF_OLAPAgentDim_RoleID] DEFAULT ((1)), 
    [OLAPKey] [bigint] IDENTITY(1,1) NOT NULL, 
    [FatherKey] [bigint] NULL, 
    [FatherKeyValue] [nvarchar](100) NULL, 
    [System] [varchar](6) NULL, 
    [Level] [int] NULL, 
    [IfLeaf] [real] NULL, 
    [IfDel] [real] NULL CONSTRAINT [DF_OLAPAgentDim_IfDel] DEFAULT ((0)), 
    [SourceKey] [varchar](50) NULL, 
    [MainDemoName] [nvarchar](100) NULL, 
    [FastCode] [varchar](50) NULL, 
    [TagValue] [varchar](50) NULL, 
    [Script] [nvarchar](max) NULL, 
    [Birthday] [datetime] NULL, 
    [EarlyStartTime] [datetime] NULL, 
    [StartTime] [datetime] NULL, 
    [EndTime] [datetime] NULL, 
    [EditTime] [datetime] NULL, 
    [BecomesTime] [datetime] NULL, 
    [ContractTime] [datetime] NULL, 
    [ContractEndTime] [datetime] NULL, 
    [XMLIcon] [nvarchar](max) NULL, 
    [PassKey] [varchar](50) NULL CONSTRAINT [DF_OLAPAgentDim_PassKey] DEFAULT ('N3pkY3RHaeZXA9mGJdfm8A=='), 
    [Address] [nvarchar](100) NULL, 
    [HomeTel] [varchar](50) NULL, 
    [Mobile] [varchar](50) NULL, 
    [Email] [varchar](100) NULL, 
    [IDCard] [varchar](50) NULL, 
    [IDSecu] [varchar](50) NULL, 
    [IDEndowment] [varchar](50) NULL, 
    [IDAccumulation] [varchar](50) NULL, 
    [ContactPerson] [nvarchar](100) NULL, 
    [ContactPersonTel] [varchar](50) NULL, 
    [Others1] [varchar](50) NULL, 
    [SexKey] [varchar](2) NULL CONSTRAINT [DF_OLAPAgentDim_SexKey] DEFAULT ((1)), 
    [SexKeyValue] [nvarchar](100) NULL, 
    [MarrageKey] [varchar](2) NULL CONSTRAINT [DF_OLAPAgentDim_MarrageKey] DEFAULT ((1)), 
    [MarrageKeyValue] [nvarchar](100) NULL, 
    [Nation] [nvarchar](50) NULL, 
    [Race] [nvarchar](50) NULL, 
    [PartyMemberKey] [varchar](2) NULL CONSTRAINT [DF_OLAPAgentDim_PartyMemberKey] DEFAULT ((1)), 
    [PartyMemberKeyValue] [nvarchar](100) NULL, 
    [RegionKey] [bigint] NULL CONSTRAINT [DF_OLAPAgentDim_RegionKey] DEFAULT ((1)), 
    [RegionKeyValue] [nvarchar](100) NULL, 
    [LeaveResonKey] [bigint] NULL CONSTRAINT [DF_OLAPAgentDim_LeaveResonKey] DEFAULT ((1)), 
    [LeaveResonKeyValue] [nvarchar](100) NULL, 
    [RoleStr] [varchar](max) NULL, 
    [RoleStrValue] [nvarchar](max) NULL, 
    [LeaderKey] [bigint] NULL CONSTRAINT [DF_OLAPAgentDim_LeaderKey] DEFAULT ((1)), 
    [LeaderKeyValue] [nvarchar](100) NULL, 
    [FastCode2] [varchar](50) NULL, 
    [FastCode3] [varchar](50) NULL, 
    [FastCode4] [varchar](50) NULL, 
    [FastCode5] [varchar](50) NULL, 
    [OtherAddress] [nvarchar](100) NULL, 
    [ShowOrder] [int] NULL, 
    [RaceKey] [bigint] NULL DEFAULT ((1)), 
    [RaceKeyValue] [nvarchar](100) NULL, 
    [DepartLevelKey] [bigint] NULL DEFAULT ((1)), 
    [DepartLevelKeyValue] [nvarchar](100) NULL, 
    [forumname] [nvarchar](100) NULL, 
    [IfCloseKey] [bigint] NULL DEFAULT ((1)), 
    [IfCloseKeyValue] [nvarchar](100) NULL, 
    [InsureStartTime] [datetime] NULL, 
    [AccumulationStartTime] [datetime] NULL, 
    [Rate] [varchar](50) NULL, 
    [DirectLeaderKey] [bigint] NULL CONSTRAINT [DF_OLAPAgentDim_DirectLeaderKey] DEFAULT ((1)), 
    [DirectLeaderAttriKey] [bigint] NULL CONSTRAINT [DF_OLAPAgentDim_DirectLeaderAttriKey] DEFAULT ((1)), 
    [DirectLeaderKeyValue] [nvarchar](100) NULL, 
    [DirectLeaderSourceKey] [varchar](50) NULL, 
    [DirectLeaderPartName] [nvarchar](100) NULL, 
    [DirectLeaderPositionName] [nvarchar](100) NULL, 
    [NOTSync] [int] NULL, 
    [FatherPath] [nvarchar](max) NULL, 
    [SaleDiscount] [real] NULL, 
CONSTRAINT [PK_OLAPAgent Dim] PRIMARY KEY CLUSTERED 
(
    [OLAPKey] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

其次,向表中插入10000條記錄。我認爲10,000條記錄對於SQL SERVER來說不是一個很大的數字。事實上,你可以看到這是一張父親和兒童的維度表。 ifleaf = 0的記錄表示人員的部門結構節點,ifleaf = 1的記錄表示該人員。您可以使用FahterKey列定義父子關係。例如:

OLAPKey IfLeaf FatherKey DepartLevelKey MainDemoName 
    2  0  0   1   IBM Company 
    3  0  2   2   Sales Depart  
    4  0  2   2   Service Depart 
    5  0  3   3   Sales Team1 
    6  1  5   NULL  John Smith 
    7  1  4   NULL  Mary 
...... 

DepartLevelKey列表示離開節點的級別。 所以在這張表中,我們可以保存整個HR樹信息。

第三,我們看到了問題的SQL:

create table #t 
(
TableID int IDENTITY(1,1), 
OLAPKey bigint, 
MainDemoName nvarchar(max) 
) 

declare @t4 table 
(
TableID int IDENTITY(1,1), 
MainDemoName nvarchar(max), 
OLAPKeystr varchar(100) 
) 

declare @agentkey bigint 
set @agentkey ='2' 

    --Part A 
    --DepartLevelKey=2, to get @agentkey node's all level=2 department 

    ;WITH Result AS(
    SELECT OLAPKey,DepartLevelKey,maindemoname FROM OLAPAgentDim WHERE OLAPKey [email protected] 
    UNION ALL 
    SELECT a.OLAPKey,a.DepartLevelKey,a.maindemoname FROM OLAPAgentDim AS a,Result AS b WHERE a.FatherKey = b.OLAPKey 
    ) 

    insert #t select OLAPKey,maindemoname from Result where DepartLevelKey=4 

    --Part B 
    ;with One as 
    ( 
    select *,convert(varchar(50),OLAPKey) as Re from #t 
    ) 
    insert @t4 select maindemoname,stuff((select ','+Re from One where One.maindemoname=#t.maindemoname for xml path('')),1,1,'') as Two 
    from #t 
    group by maindemoname 
    drop table #t 

的SQL上述分爲A部分和B部分 部分A SQL得到根節點下的所有兒童(和過濾那些屬於指定的DepartLevelKey)。例如,讓銷售部門的所有人員的級別= 3。

B部分SQL更改的行與列,例如:

Change: 
TableID OLAPKey MainDemoName 
    1  6  Sales Team1 
    2  10 Sales Team1 
    3  12 Sales Team1 
to: 
TableID MainDemoName OLAPKeystr 
    1  Sales Team1 6,10,12 

因此我們得到的每個目標部門的人,作進一步處理(這裏被遺漏)。

問題: A部分非常慢,花費約5分鐘。 B部分也很慢。

我不知道如何根據表結構存在優化它。

你的, 伊萬

+3

1)什麼是您的SQL計劃說。 2)你爲什麼打擾臨時表? – 2013-04-10 04:53:15

+1

您應該注意不要引起不必要的類型轉換;如果你有'聲明@agentkey bigint' - 那麼***爲什麼***在地球上將你的值設置爲**字符串**'set @agentkey ='2'' ?????這是一個數字 - 只需將其設置爲數字值即可!'set @agentkey = 2'如果你的查詢中有這樣的*隱式類型轉換,那麼這些都是真正的性能殺手... – 2013-04-10 04:55:59

+0

聯盟往往非常緩慢。你爲什麼不離開外連接? – 2013-04-10 05:52:52

回答

0

嘗試:

(ⅰ)添加這個索引來OLAPAgentDim

create index IX_OLAPAgentDim_FatherKey on OLAPAgentDim (FatherKey) include (DepartLevelKey, MainDemoName) 

(ⅱ)nvarchar(max)#t更改MainDemoNamenvarchar(100)。這與OLAPAgentDim中的列定義匹配。

(III) A部分和B部分之間,即,後部分和B部分之前,添加該指數#t

create clustered index IX on #t (MainDemoName)