我有一個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部分也很慢。
我不知道如何根據表結構存在優化它。
你的, 伊萬
1)什麼是您的SQL計劃說。 2)你爲什麼打擾臨時表? – 2013-04-10 04:53:15
您應該注意不要引起不必要的類型轉換;如果你有'聲明@agentkey bigint' - 那麼***爲什麼***在地球上將你的值設置爲**字符串**'set @agentkey ='2'' ?????這是一個數字 - 只需將其設置爲數字值即可!'set @agentkey = 2'如果你的查詢中有這樣的*隱式類型轉換,那麼這些都是真正的性能殺手... – 2013-04-10 04:55:59
聯盟往往非常緩慢。你爲什麼不離開外連接? – 2013-04-10 05:52:52