【发布时间】:2020-02-04 21:57:44
【问题描述】:
有一个长时间运行的存储过程。第二个表(访问)仅用于 where 子句中使用的结果,同时从第一个表(批准)中检索记录。
下面是涉及到的两个表的DDL,以及存储过程的脚本。显然,因为它只是一个样本,它不会显示任何记录;因此,该样本数据没有观察到瓶颈。但是想象一下,游标中有许多 userr_id。 由于它正在调用另一个存储过程,因此还有额外的成本。有什么办法可以优化查询吗?
表的 DDL
CREATE TABLE [dbo].[Approvals](
userr_id [int] NOT NULL,
appro_id [int] NOT NULL,
app_units [decimal](9, 2) NOT NULL,
c_units [tinyint] NOT NULL,
usedunits [decimal](9, 2) NOT NULL,
deleted [bit] NOT NULL
)
INSERT INTO approvals
VALUES
(4262, 29, 36.00, 1, 0.00, 0),
(1717, 30, 24.00, 1, 0.00, 0),
(4743, 31, 76.00, 1, 0.00, 0),
(4460, 33, 36.00, 1, 0.00, 0),
(4488, 35, 36.00, 1, 0.00, 0),
(3871, 36, 24.00, 1, 0.00, 0),
(3561, 37, 12.00, 1, 3.00, 0),
(4828, 38, 36.00, 1, 0.00, 0),
(3828, 39, 24.00, 1, 0.00, 0),
(4101, 40, 24.00, 1, 0.00, 0)
CREATE TABLE [dbo].[Visit](
userr_id [int] NULL,
appro_id [int] NULL,
c_secondary [bit] NULL,
auth_exceeded [bit] NOT NULL,
tperiod [int] NOT NULL,
contratrate [decimal](9, 2) NOT NULL
)
INSERT INTO visit
VALUES
(5329, NULL, 0, 0, 419, 0.00),
(4262, NULL, 0, 0, 419, 0.00),
(5244, NULL, 0, 0, 419, 0.00),
(4205, NULL, 0, 0, 419, 0.00),
(4828, NULL, 0, 0, 419, 0.00),
(5531, NULL, 0,0, 419, 0.00),
(5558, NULL, 0, 0, 419, 0.00),
(4460, NULL, 0, 0, 419, 0.00),
(5547, NULL, 0, 0, 419, 0.00),
(5219, NULL, 0, 0, 419, 0.00)
存储过程:
CREATE PROCEDURE [dbo].[stored_procedure]
AS
DECLARE @userr_id Int, @cnt Int
SET @cnt = 0
DECLARE c CURSOR FOR
SELECT DISTINCT userr_id
FROM (SELECT userr_id, app_units, c_units, usedunits,
(SELECT count(*) FROM Visit WHERE c_secondary = 0 and appro_id = Approvals.appro_id and auth_exceeded = 0) AS count_notexceeded,
(SELECT count(*) FROM Visit WHERE c_secondary = 0 and appro_id = Approvals.appro_id ) AS count_all,
(SELECT SUM(tperiod) / 60.00 FROM Visit WHERE c_secondary = 0 and appro_id = Approvals.appro_id ) AS th_all,
(SELECT SUM(tperiod) / 60.00 FROM Visit WHERE c_secondary = 0 and appro_id = Approvals.appro_id and auth_exceeded = 0) AS th_notexceeded,
(SELECT SUM(contratrate) FROM Visit WHERE c_secondary = 0 and appro_id = Approvals.appro_id and auth_exceeded = 0) AS tr_notexceeded,
(SELECT SUM(contratrate) FROM Visit WHERE c_secondary = 0 and appro_id = Approvals.appro_id ) AS tr_all
FROM Approvals where deleted = 0) t
WHERE ((c_units = 0 and (count_all <> usedunits or count_notexceeded > app_units))
OR (c_units = 2 and (th_all <> usedunits or th_notexceeded > app_units))
OR (c_units = 3 and (tr_all <> usedunits or tr_notexceeded > app_units)))
OPEN c
FETCH NEXT FROM c INTO @userr_id
WHILE @@fetch_status = 0
BEGIN
SET @cnt = @cnt + 1
EXEC [_name_of_another_stored_procedure] @userr_id
FETCH NEXT FROM c INTO @userr_id
END
CLOSE c
DEALLOCATE c
谢谢。任何指南都非常受欢迎。
【问题讨论】:
-
为什么运行时间长?是打开光标吗?它是否正在运行其他存储过程?无论哪种情况,查询计划和等待统计信息是什么?
-
基本上就是打开光标。我已经单独尝试过了。我想,是因为它多次从访问表中选择,以便处理它以在 where 子句中使用。
标签: sql-server tsql stored-procedures cursor