SQL 服务器 - 优化查询
SQL Server - Optimize query
我需要使用现有的 SQL 服务器存储过程,但在我看来它根本没有优化,因为没有 where 子句需要 45 秒才能完成,而且数据量不大。
我知道任何试图帮助我的人都很难测试它,但至少给我一个改进它的想法或起点。
查询的是下一个:
DECLARE @PFK_ENTERPRISE int = 7,
@PFK_USER int = 14118,
@ID_REGION varchar(200) = '',
@FK_SITE int = 0,
@FK_MARKET int = null;
DECLARE @RETURN_TABLE TABLE
(
MARKET varchar(200),
NAMES varchar(200),
PK_IDS VARCHAR (25),
PFK_MARKET INT,
IS_ADHOC BIT
)
INSERT INTO @RETURN_TABLE (NAMES, PK_IDS, PFK_MARKET, IS_ADHOC, MARKET )
SELECT DISTINCT
CASE
WHEN CLIENT_LEGAL.LEGAL_NAME = CLIENT_ORIGIN.LEGAL_NAME
THEN CLIENT_LEGAL.LEGAL_NAME
ELSE CLIENT_ORIGIN.LEGAL_NAME + ' (' + CLIENT_LEGAL.LEGAL_NAME + ')'
END AS 'NAMES',
CONVERT(VARCHAR(10), MARKETS_CATALOGUES.PFK_CLIENT_LEGAL) + '/' + CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_CLIENT_ORIGIN) + '/' + CONVERT(VARCHAR(10), MARKETS_CATALOGUES.PFK_COMPANY) AS 'PK_IDS',
USER_ACCESS_CLIENTS.PFK_MARKET, 1 as "IS_ADHOC",
MARKET.NAME_DESCRIPTION
FROM
USER_ACCESS_CLIENTS
INNER JOIN
MARKETS_CATALOGUES ON USER_ACCESS_CLIENTS.PFK_ENTERPRISE = MARKETS_CATALOGUES.PFK_ENTERPRISE
AND USER_ACCESS_CLIENTS.PFK_MARKET = MARKETS_CATALOGUES.PFK_MARKET
AND USER_ACCESS_CLIENTS.PFK_CLIENT_LEGAL = MARKETS_CATALOGUES.PFK_CLIENT_LEGAL
AND USER_ACCESS_CLIENTS.PFK_CLIENT_ORIGIN = MARKETS_CATALOGUES.PFK_CLIENT_ORIGIN
AND USER_ACCESS_CLIENTS.PFK_COMPANY = MARKETS_CATALOGUES.PFK_COMPANY
INNER JOIN
CLIENTS AS CLIENT_LEGAL ON MARKETS_CATALOGUES.PFK_ENTERPRISE = CLIENT_LEGAL.PFK_ENTERPRISE
AND MARKETS_CATALOGUES.PFK_COMPANY = CLIENT_LEGAL.PFK_COMPANY
AND MARKETS_CATALOGUES.PFK_CLIENT_LEGAL = CLIENT_LEGAL.PK_CLIENT
INNER JOIN
CLIENTS AS CLIENT_ORIGIN ON MARKETS_CATALOGUES.PFK_ENTERPRISE = CLIENT_ORIGIN.PFK_ENTERPRISE
AND MARKETS_CATALOGUES.PFK_COMPANY = CLIENT_ORIGIN.PFK_COMPANY
AND MARKETS_CATALOGUES.PFK_CLIENT_ORIGIN = CLIENT_ORIGIN.PK_CLIENT
INNER JOIN
MARKET ON MARKETS_CATALOGUES.PFK_ENTERPRISE = market.PFK_ENTERPRISE
AND MARKETS_CATALOGUES.PFK_MARKET = market.PK_MARKET
INNER JOIN
CATALOGUES cat ON cat.PFK_ENTERPRISE = MARKETS_CATALOGUES.PFK_ENTERPRISE
AND cat.PK_CATALOGUE = MARKETS_CATALOGUES.PFK_CATALOGUE
AND market.FK_SITE = cat.FK_SITE
WHERE
USER_ACCESS_CLIENTS.PFK_ENTERPRISE = @PFK_ENTERPRISE
AND USER_ACCESS_CLIENTS.PFK_USER = @PFK_USER
AND MARKETS_CATALOGUES.FK_CATALOGUE_SETUP > 0
AND MARKETS_CATALOGUES.IS_ACTIVE = 1
AND (@FK_MARKET IS NULL OR @FK_MARKET = USER_ACCESS_CLIENTS.PFK_MARKET)
AND FK_TYPE_CATALOGUE = 6
INSERT INTO @RETURN_TABLE (NAMES, PK_IDS, PFK_MARKET, IS_ADHOC, MARKET)
SELECT DISTINCT
CASE WHEN CLIENT_LEGAL.LEGAL_NAME = CLIENT_ORIGIN.LEGAL_NAME THEN CLIENT_LEGAL.LEGAL_NAME ELSE CLIENT_ORIGIN.LEGAL_NAME + ' (' + CLIENT_LEGAL.LEGAL_NAME + ')' END AS 'NAMES',
CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_CLIENT_LEGAL) + '/' + CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_CLIENT_ORIGIN) + '/' + CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_COMPANY) AS 'PK_IDS',
USER_ACCESS_CLIENTS.PFK_MARKET, 0 as "IS_ADHOC",
MARKET.NAME_DESCRIPTION AS MARKET
FROM USER_ACCESS_CLIENTS
inner JOIN MARKETS_CATALOGUES
ON USER_ACCESS_CLIENTS.PFK_ENTERPRISE = MARKETS_CATALOGUES.PFK_ENTERPRISE AND
USER_ACCESS_CLIENTS.PFK_MARKET = MARKETS_CATALOGUES.PFK_MARKET AND
USER_ACCESS_CLIENTS.PFK_CLIENT_LEGAL = MARKETS_CATALOGUES.PFK_CLIENT_LEGAL AND
USER_ACCESS_CLIENTS.PFK_CLIENT_ORIGIN = MARKETS_CATALOGUES.PFK_CLIENT_ORIGIN AND
USER_ACCESS_CLIENTS.PFK_COMPANY = MARKETS_CATALOGUES.PFK_COMPANY
INNER JOIN CLIENTS AS CLIENT_LEGAL
ON MARKETS_CATALOGUES.PFK_ENTERPRISE = CLIENT_LEGAL.PFK_ENTERPRISE AND
MARKETS_CATALOGUES.PFK_COMPANY = CLIENT_LEGAL.PFK_COMPANY AND
MARKETS_CATALOGUES.PFK_CLIENT_LEGAL = CLIENT_LEGAL.PK_CLIENT
INNER JOIN CLIENTS AS CLIENT_ORIGIN ON MARKETS_CATALOGUES.PFK_ENTERPRISE = CLIENT_ORIGIN.PFK_ENTERPRISE AND
MARKETS_CATALOGUES.PFK_COMPANY = CLIENT_ORIGIN.PFK_COMPANY AND
MARKETS_CATALOGUES.PFK_CLIENT_ORIGIN = CLIENT_ORIGIN.PK_CLIENT
inner join MARKET on MARKETS_CATALOGUES.PFK_ENTERPRISE = market.PFK_ENTERPRISE
and MARKETS_CATALOGUES.PFK_MARKET = market.PK_MARKET
INNER JOIN CATALOGUES cat on cat.PFK_ENTERPRISE = MARKETS_CATALOGUES.PFK_ENTERPRISE and cat.PK_CATALOGUE = MARKETS_CATALOGUES.PFK_CATALOGUE
and market.FK_SITE = cat.FK_SITE
WHERE USER_ACCESS_CLIENTS.PFK_ENTERPRISE = @PFK_ENTERPRISE
AND USER_ACCESS_CLIENTS.PFK_USER = @PFK_USER
AND MARKETS_CATALOGUES.FK_CATALOGUE_SETUP > 0
AND MARKETS_CATALOGUES.IS_ACTIVE = 1
AND (@FK_MARKET IS NULL OR @FK_MARKET = USER_ACCESS_CLIENTS.PFK_MARKET)
AND FK_TYPE_CATALOGUE <> 6
and CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_CLIENT_LEGAL) + '/' + CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_CLIENT_ORIGIN) + '/' + CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_COMPANY) NOT IN (select PK_IDS from @RETURN_TABLE)
select *
from @RETURN_TABLE
group by PK_IDS
order by MARKET
并且显着减慢查询速度的行是:
and CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_CLIENT_LEGAL) + '/' + CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_CLIENT_ORIGIN) + '/' + CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_COMPANY) NOT IN (select PK_IDS from @RETURN_TABLE)
当然是因为 NOT IN (select PK_IDS from @RETURN_TABLE) 为 select每一行,但我没有找到避免该行的方法,因为评论它会在结果 temp table.
中创建重复的记录
这只是一个针对市场 231 的过滤示例,并且评论了我所说的“违规”行,因此您对返回的数据知之甚少。
adm Promotions ADM Promotions UK Limited 75/75/39 231 1
adm Promotions Branding Your POS Mexico, S.A. de C.V. / BYP (MX ) 107/107/39 231 1
adm Promotions Imagen Publicitaria Punto de Venta SA de CV (MX ) 111/111/39 231 1
adm Promotions ADM Promotions UK Limited 75/75/39 231 0
adm Promotions Branding Your POS Mexico, S.A. de C.V. / BYP (MX ) 107/107/39 231 0
adm Promotions Imagen Publicitaria Punto de Venta SA de CV (MX ) 111/111/39 231 0
因此,如您所见,有两条记录(AD_HOC 1 和 AD_HOC 0)重复记录具有相同的 PK_IDS,但我无法肯定 AD_HOC值为1或值为0的可以跳过
不知道你是否明白,希望大家帮帮忙。
尝试 1:
在结果 tmp table select 中执行下一步可以解决我的问题,我删除了“违规”行(这使得 acceptable 计时)和然后在结果中我只保留重复值中的第一个值,但 tsql 是底层的“seqnum”,其中说明不正确。
如何解决?
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY PK_IDS ORDER BY market) seqnum
FROM
@RETURN_TABLE
WHERE
seqnum = 1
对于您的 seqnum 问题,您需要使用 derived table 或 cte来封装查询,eg
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY PK_IDS ORDER BY market) seqnum
FROM @RETURN_TABLE
)t
WHERE seqnum = 1;
我需要使用现有的 SQL 服务器存储过程,但在我看来它根本没有优化,因为没有 where 子句需要 45 秒才能完成,而且数据量不大。
我知道任何试图帮助我的人都很难测试它,但至少给我一个改进它的想法或起点。
查询的是下一个:
DECLARE @PFK_ENTERPRISE int = 7,
@PFK_USER int = 14118,
@ID_REGION varchar(200) = '',
@FK_SITE int = 0,
@FK_MARKET int = null;
DECLARE @RETURN_TABLE TABLE
(
MARKET varchar(200),
NAMES varchar(200),
PK_IDS VARCHAR (25),
PFK_MARKET INT,
IS_ADHOC BIT
)
INSERT INTO @RETURN_TABLE (NAMES, PK_IDS, PFK_MARKET, IS_ADHOC, MARKET )
SELECT DISTINCT
CASE
WHEN CLIENT_LEGAL.LEGAL_NAME = CLIENT_ORIGIN.LEGAL_NAME
THEN CLIENT_LEGAL.LEGAL_NAME
ELSE CLIENT_ORIGIN.LEGAL_NAME + ' (' + CLIENT_LEGAL.LEGAL_NAME + ')'
END AS 'NAMES',
CONVERT(VARCHAR(10), MARKETS_CATALOGUES.PFK_CLIENT_LEGAL) + '/' + CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_CLIENT_ORIGIN) + '/' + CONVERT(VARCHAR(10), MARKETS_CATALOGUES.PFK_COMPANY) AS 'PK_IDS',
USER_ACCESS_CLIENTS.PFK_MARKET, 1 as "IS_ADHOC",
MARKET.NAME_DESCRIPTION
FROM
USER_ACCESS_CLIENTS
INNER JOIN
MARKETS_CATALOGUES ON USER_ACCESS_CLIENTS.PFK_ENTERPRISE = MARKETS_CATALOGUES.PFK_ENTERPRISE
AND USER_ACCESS_CLIENTS.PFK_MARKET = MARKETS_CATALOGUES.PFK_MARKET
AND USER_ACCESS_CLIENTS.PFK_CLIENT_LEGAL = MARKETS_CATALOGUES.PFK_CLIENT_LEGAL
AND USER_ACCESS_CLIENTS.PFK_CLIENT_ORIGIN = MARKETS_CATALOGUES.PFK_CLIENT_ORIGIN
AND USER_ACCESS_CLIENTS.PFK_COMPANY = MARKETS_CATALOGUES.PFK_COMPANY
INNER JOIN
CLIENTS AS CLIENT_LEGAL ON MARKETS_CATALOGUES.PFK_ENTERPRISE = CLIENT_LEGAL.PFK_ENTERPRISE
AND MARKETS_CATALOGUES.PFK_COMPANY = CLIENT_LEGAL.PFK_COMPANY
AND MARKETS_CATALOGUES.PFK_CLIENT_LEGAL = CLIENT_LEGAL.PK_CLIENT
INNER JOIN
CLIENTS AS CLIENT_ORIGIN ON MARKETS_CATALOGUES.PFK_ENTERPRISE = CLIENT_ORIGIN.PFK_ENTERPRISE
AND MARKETS_CATALOGUES.PFK_COMPANY = CLIENT_ORIGIN.PFK_COMPANY
AND MARKETS_CATALOGUES.PFK_CLIENT_ORIGIN = CLIENT_ORIGIN.PK_CLIENT
INNER JOIN
MARKET ON MARKETS_CATALOGUES.PFK_ENTERPRISE = market.PFK_ENTERPRISE
AND MARKETS_CATALOGUES.PFK_MARKET = market.PK_MARKET
INNER JOIN
CATALOGUES cat ON cat.PFK_ENTERPRISE = MARKETS_CATALOGUES.PFK_ENTERPRISE
AND cat.PK_CATALOGUE = MARKETS_CATALOGUES.PFK_CATALOGUE
AND market.FK_SITE = cat.FK_SITE
WHERE
USER_ACCESS_CLIENTS.PFK_ENTERPRISE = @PFK_ENTERPRISE
AND USER_ACCESS_CLIENTS.PFK_USER = @PFK_USER
AND MARKETS_CATALOGUES.FK_CATALOGUE_SETUP > 0
AND MARKETS_CATALOGUES.IS_ACTIVE = 1
AND (@FK_MARKET IS NULL OR @FK_MARKET = USER_ACCESS_CLIENTS.PFK_MARKET)
AND FK_TYPE_CATALOGUE = 6
INSERT INTO @RETURN_TABLE (NAMES, PK_IDS, PFK_MARKET, IS_ADHOC, MARKET)
SELECT DISTINCT
CASE WHEN CLIENT_LEGAL.LEGAL_NAME = CLIENT_ORIGIN.LEGAL_NAME THEN CLIENT_LEGAL.LEGAL_NAME ELSE CLIENT_ORIGIN.LEGAL_NAME + ' (' + CLIENT_LEGAL.LEGAL_NAME + ')' END AS 'NAMES',
CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_CLIENT_LEGAL) + '/' + CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_CLIENT_ORIGIN) + '/' + CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_COMPANY) AS 'PK_IDS',
USER_ACCESS_CLIENTS.PFK_MARKET, 0 as "IS_ADHOC",
MARKET.NAME_DESCRIPTION AS MARKET
FROM USER_ACCESS_CLIENTS
inner JOIN MARKETS_CATALOGUES
ON USER_ACCESS_CLIENTS.PFK_ENTERPRISE = MARKETS_CATALOGUES.PFK_ENTERPRISE AND
USER_ACCESS_CLIENTS.PFK_MARKET = MARKETS_CATALOGUES.PFK_MARKET AND
USER_ACCESS_CLIENTS.PFK_CLIENT_LEGAL = MARKETS_CATALOGUES.PFK_CLIENT_LEGAL AND
USER_ACCESS_CLIENTS.PFK_CLIENT_ORIGIN = MARKETS_CATALOGUES.PFK_CLIENT_ORIGIN AND
USER_ACCESS_CLIENTS.PFK_COMPANY = MARKETS_CATALOGUES.PFK_COMPANY
INNER JOIN CLIENTS AS CLIENT_LEGAL
ON MARKETS_CATALOGUES.PFK_ENTERPRISE = CLIENT_LEGAL.PFK_ENTERPRISE AND
MARKETS_CATALOGUES.PFK_COMPANY = CLIENT_LEGAL.PFK_COMPANY AND
MARKETS_CATALOGUES.PFK_CLIENT_LEGAL = CLIENT_LEGAL.PK_CLIENT
INNER JOIN CLIENTS AS CLIENT_ORIGIN ON MARKETS_CATALOGUES.PFK_ENTERPRISE = CLIENT_ORIGIN.PFK_ENTERPRISE AND
MARKETS_CATALOGUES.PFK_COMPANY = CLIENT_ORIGIN.PFK_COMPANY AND
MARKETS_CATALOGUES.PFK_CLIENT_ORIGIN = CLIENT_ORIGIN.PK_CLIENT
inner join MARKET on MARKETS_CATALOGUES.PFK_ENTERPRISE = market.PFK_ENTERPRISE
and MARKETS_CATALOGUES.PFK_MARKET = market.PK_MARKET
INNER JOIN CATALOGUES cat on cat.PFK_ENTERPRISE = MARKETS_CATALOGUES.PFK_ENTERPRISE and cat.PK_CATALOGUE = MARKETS_CATALOGUES.PFK_CATALOGUE
and market.FK_SITE = cat.FK_SITE
WHERE USER_ACCESS_CLIENTS.PFK_ENTERPRISE = @PFK_ENTERPRISE
AND USER_ACCESS_CLIENTS.PFK_USER = @PFK_USER
AND MARKETS_CATALOGUES.FK_CATALOGUE_SETUP > 0
AND MARKETS_CATALOGUES.IS_ACTIVE = 1
AND (@FK_MARKET IS NULL OR @FK_MARKET = USER_ACCESS_CLIENTS.PFK_MARKET)
AND FK_TYPE_CATALOGUE <> 6
and CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_CLIENT_LEGAL) + '/' + CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_CLIENT_ORIGIN) + '/' + CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_COMPANY) NOT IN (select PK_IDS from @RETURN_TABLE)
select *
from @RETURN_TABLE
group by PK_IDS
order by MARKET
并且显着减慢查询速度的行是:
and CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_CLIENT_LEGAL) + '/' + CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_CLIENT_ORIGIN) + '/' + CONVERT(VARCHAR(10),MARKETS_CATALOGUES.PFK_COMPANY) NOT IN (select PK_IDS from @RETURN_TABLE)
当然是因为 NOT IN (select PK_IDS from @RETURN_TABLE) 为 select每一行,但我没有找到避免该行的方法,因为评论它会在结果 temp table.
中创建重复的记录这只是一个针对市场 231 的过滤示例,并且评论了我所说的“违规”行,因此您对返回的数据知之甚少。
adm Promotions ADM Promotions UK Limited 75/75/39 231 1
adm Promotions Branding Your POS Mexico, S.A. de C.V. / BYP (MX ) 107/107/39 231 1
adm Promotions Imagen Publicitaria Punto de Venta SA de CV (MX ) 111/111/39 231 1
adm Promotions ADM Promotions UK Limited 75/75/39 231 0
adm Promotions Branding Your POS Mexico, S.A. de C.V. / BYP (MX ) 107/107/39 231 0
adm Promotions Imagen Publicitaria Punto de Venta SA de CV (MX ) 111/111/39 231 0
因此,如您所见,有两条记录(AD_HOC 1 和 AD_HOC 0)重复记录具有相同的 PK_IDS,但我无法肯定 AD_HOC值为1或值为0的可以跳过
不知道你是否明白,希望大家帮帮忙。
尝试 1:
在结果 tmp table select 中执行下一步可以解决我的问题,我删除了“违规”行(这使得 acceptable 计时)和然后在结果中我只保留重复值中的第一个值,但 tsql 是底层的“seqnum”,其中说明不正确。 如何解决?
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY PK_IDS ORDER BY market) seqnum
FROM
@RETURN_TABLE
WHERE
seqnum = 1
对于您的 seqnum 问题,您需要使用 derived table 或 cte来封装查询,eg
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY PK_IDS ORDER BY market) seqnum
FROM @RETURN_TABLE
)t
WHERE seqnum = 1;