【发布时间】:2011-09-22 00:52:25
【问题描述】:
我需要帮助来提高以下 SQL 查询的性能。此应用程序的数据库设计基于 OLD 大型机实体设计。查询所做的只是根据一些搜索条件返回一个客户列表:
-
@Advisers:只返回被该顾问捕获的客户。 -
@outlets:忽略这个 -
@searchtext: (firstname, surname, suburb, policy number) 任意组合
我正在做的是创建一个临时表,然后查询所有涉及的表,创建我自己的数据集,然后将该数据集插入到一个易于理解的表中 (@clients)
此查询需要 20 秒 执行,目前只返回 7 行!
所有表计数的屏幕截图可以在这里找到:Table Record Count
我可以从哪里开始优化此查询?
ALTER PROCEDURE [dbo].[spOP_SearchDashboard]
@advisers varchar(1000),
@outlets varchar(1000),
@searchText varchar(1000)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Set the prefixes to search for (firstname, surname, suburb, policy number)
DECLARE @splitSearchText varchar(1000)
SET @splitSearchText = REPLACE(@searchText, ' ', ',')
DECLARE @AdvisersListing TABLE
(
adviser varchar(200)
)
DECLARE @SearchParts TABLE
(
prefix varchar(200)
)
DECLARE @OutletListing TABLE
(
outlet varchar(200)
)
INSERT INTO @AdvisersListing(adviser)
SELECT part as adviser FROM SplitString (@advisers, ',')
INSERT INTO @SearchParts(prefix)
SELECT part as prefix FROM SplitString (@splitSearchText, ',')
INSERT INTO @OutletListing(outlet)
SELECT part as outlet FROM SplitString (@outlets, ',')
DECLARE @Clients TABLE
(
source varchar(2),
adviserId bigint,
integratedId varchar(50),
rfClientId bigint,
ifClientId uniqueidentifier,
title varchar(30),
firstname varchar(100),
surname varchar(100),
address1 varchar(500),
address2 varchar(500),
suburb varchar(100),
state varchar(100),
postcode varchar(100),
policyNumber varchar(100),
lastAccess datetime,
deleted bit
)
INSERT INTO @Clients
SELECT
source, adviserId, integratedId, rfClientId, ifClientId, title,
firstname, surname, address1, address2, suburb, state, postcode,
policyNumber, max(lastAccess) as lastAccess, deleted
FROM
(SELECT DISTINCT
'RF' as Source,
advRel.SourceEntityId as adviserId,
cast(pe.entityId as varchar(50)) AS IntegratedID,
pe.entityId AS rfClientId,
cast(ifClient.Id as uniqueidentifier) as ifClientID,
ISNULL(p.title, '') AS title,
ISNULL(p.firstname, '') AS firstname,
ISNULL(p.surname, '') AS surname,
ISNULL(ct.address1, '') AS address1,
ISNULL(ct.address2, '') AS address2,
ISNULL(ct.suburb, '') AS suburb,
ISNULL(ct.state, '') AS state,
ISNULL(ct.postcode, '') AS postcode,
ISNULL(contract.policyNumber,'') AS policyNumber,
coalesce(pp.LastAccess, d_portfolio.dateCreated, pd.dateCreated) AS lastAccess,
ISNULL(client.deleted, 0) as deleted
FROM
tbOP_Entity pe
INNER JOIN tbOP_EntityRelationship advRel ON pe.EntityId = advRel.TargetEntityId
AND advRel.RelationshipId = 39
LEFT OUTER JOIN tbOP_Data pd ON pe.EntityId = pd.entityId
LEFT OUTER JOIN tbOP__Person p ON pd.DataId = p.DataId
LEFT OUTER JOIN tbOP_EntityRelationship ctr ON pe.EntityId = ctr.SourceEntityId
AND ctr.RelationshipId = 79
LEFT OUTER JOIN tbOP_Data ctd ON ctr.TargetEntityId = ctd.entityId
LEFT OUTER JOIN tbOP__Contact ct ON ctd.DataId = ct.DataId
LEFT OUTER JOIN tbOP_EntityRelationship ppr ON pe.EntityId = ppr.SourceEntityId
AND ppr.RelationshipID = 113
LEFT OUTER JOIN tbOP_Data ppd ON ppr.TargetEntityId = ppd.EntityId
LEFT OUTER JOIN tbOP__Portfolio pp ON ppd.DataId = pp.DataId
LEFT OUTER JOIN tbOP_EntityRelationship er_policy ON ppd.EntityId = er_policy.SourceEntityId
AND er_policy.RelationshipId = 3
LEFT OUTER JOIN tbOP_EntityRelationship er_contract ON er_policy.TargetEntityId = er_contract.SourceEntityId AND er_contract.RelationshipId = 119
LEFT OUTER JOIN tbOP_Data d_contract ON er_contract.TargetEntityId = d_contract.EntityId
LEFT OUTER JOIN tbOP__Contract contract ON d_contract.DataId = contract.DataId
LEFT JOIN tbOP_Data d_portfolio ON ppd.EntityId = d_portfolio.EntityId
LEFT JOIN tbOP__Portfolio pt ON d_portfolio.DataId = pt.DataId
LEFT JOIN tbIF_Clients ifClient on pe.entityId = ifClient.RFClientId
LEFT JOIN tbOP__Client client on client.DataId = pd.DataId
where
p.surname <> ''
AND (advRel.SourceEntityId IN (select adviser from @AdvisersListing)
OR
pp.outlet COLLATE SQL_Latin1_General_CP1_CI_AS in (select outlet from @OutletListing)
)
) as RFClients
group by
source, adviserId, integratedId, rfClientId, ifClientId, title,
firstname, surname, address1, address2, suburb, state, postcode,
policyNumber, deleted
SELECT * FROM @Clients --THIS ONLY RETURNS 10 RECORDS WITH MY CURRENT DATASET
END
【问题讨论】:
-
万岁!截图。不幸的是,这是错误的:实际的执行计划是什么样的? SQL Management Studio 提供了哪些提示?
-
我认为这种性能只是这种数据模型的现实,您使用元数据来创建关联而不是真实的关系。
-
SQL执行计划PDF可以在这里下载:docs.google.com/…
-
如果您只是立即从中选择所有内容,为什么还要使用临时表?
-
JohnFX:我没有粘贴整个查询,我删除了查询的其余部分以简化查找问题。其余的查询只需要 1s 执行,而上面的查询则需要 20s。临时表的原因很简单,有另一个查询将记录插入临时表,来自另一个数据库。所以它基本上是从两个数据库中收集客户。