1

私はSQL最適化問題の工学的実践を行っていますが、これは典型的なケースであり、多くの人を助けるでしょう.

SQL サーバー 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]

次に、約 10,000 レコードをテーブルに挿入します。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 ツリー情報全体を保存できます。

3 番目に、問題のある 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 =@agentkey
     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 に属する子をフィルター処理します)。たとえば、level=3 の Sales Department の child-department のすべての人を取得するには、次のようにします。

パート 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 も遅いです。

テーブル構造体が存在することに基づいて最適化する方法を知りたいです。

あなたの、イヴァン

4

1 に答える 1

0

試す:

(i)このインデックスを に追加OLAPAgentDim:

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

(ii)からへMainDemoNameの変更。これは、 の列定義と一致します。#tnvarchar(max)nvarchar(100)OLAPAgentDim

(iii)パート A とパート B の間、つまりパート A の後とパート B の前に、このインデックスを次のように追加します#t

create clustered index IX on #t (MainDemoName)
于 2013-04-10T07:07:21.193 に答える