此查询(我模拟给您看了。否则,它会更长,包含更多的列列表,更多的表;最后要根据用户的需要按每列排序)花费的时间太长,并且有时会从UI超时。我正在尝试优化存储过程,以减少加载时间,而不影响检索到的列表。我正在考虑从临时表中选择*,然后从那里订购。这可能会有所帮助。我也考虑过使用动态sql而不指定@sortidr(DESC / ASC),但是用户应该可以灵活地选择两种方式。
我想知道是否有人可以提出更好的优化方法。
CREATE PROCEDURE get_lists
@employeeid int
@ColumnName varchar(100) = NULL,
@sortidr varchar(4) = NULL,
@start_date datetime = NULL
AS
CREATE #tempemp
(emp_id int, first_name varchar(20), last_name varchar(20), SSN int)
INSERT INTO #tempemp
SELECT team_action, rec_id, total_records, cfirst_name, efirst_name, has_desc, category_name
FROM
(SELECT COALESCE(lt.description, lt.action) AS team_action
,cl.rec_id
,total_records = count(*) Over()
,c.cfirst_name
,e.efirst_name
, has_desc = cld.changelog_id IS NOT NULL THEN 1 ELSE 0 END
, ct.category_name
FROM claimll cll
JOIN itemtype lt ON cll.clLog_id = lt.clLog_id
LEFT JOIN categgory ct ON ct.id=clc.cat_id
LEFT JOIN clients c ON ct.client_id = c.client_id
LEFT JOIN employees e ON cll.emp_id = e.emp_id
LEFT JOIN detail d ON d.change_id = cll.change_id
WHERE cll.change_date > @start_date
AND cll.emp_id = @employeeid OR cll.by_employeeid = @employeeid
) t
ORDER BY
CASE WHEN @sortidr = 'asc' AND @ColumnName='team_action' THEN team_action END,
CASE WHEN @sortidr = 'desc' AND @ColumnName = 'team_action' THEN team_action END DESC,
CASE WHEN @sortidr = 'asc' AND @ColumnName='rec_id' THEN rec_id END,
CASE WHEN @sortidr = 'desc' AND @ColumnName = 'rec_id' THEN rec_id END DESC,
CASE WHEN @sortidr = 'asc' AND @ColumnName='total_records' THEN total_records END,
CASE WHEN @sortidr = 'desc' AND @ColumnName = 'total_records' THEN total_records END DESC,
CASE WHEN @sortidr = 'asc' AND @ColumnName='cfirst_name' THEN cfirst_name END,
CASE WHEN @sortidr = 'desc' AND @ColumnName = 'cfirst_name' THEN cfirst_name END DESC,
CASE WHEN @ColumnName IS NULL THEN first_name END DESC
答案 0 :(得分:1)
我不在PC上,因此稍后我将无法添加代码,但是您为我提供了足够的信息,可以提供一些很好的见识。
首先-当您通过CASE语句进行排序时,优化器将永远无法利用索引来防止排序。就是说,您的查询可能很慢的原因很多;您应该删除该逻辑,然后测试性能以了解是否是罪魁祸首。
基于有限的信息,我建议将您的proc更新为: 1.与您一样,使用动态SQL构建临时表,但不使用CASE语句。
现在,您已经有一个基于用户提供的参数正确索引的临时表。
添加第二个执行SELECT * FROM #temp ...的动态SQL语句。您将再次使用@columnName和@sortOrder构建SARGable ORDER BY(一个将利用步骤1中的索引的语句)。
使用不同的参数进行测试,请始终查看“实际执行”计划以进一步调整索引。
希望这会有所帮助。如果需要的话,我会稍后添加演示代码。
已于2019/2/22更新,包括示例:
这是一个存储过程,执行我正在描述的操作(请注意注释)-
SET NOCOUNT ON;
USE tempdb
GO
IF OBJECT_ID('dbo.DynamicSortProc','P') IS NOT NULL DROP PROC dbo.DynamicSortProc;
GO
CREATE PROC dbo.DynamicSortProc @sortby NVARCHAR(100), @sortorder NVARCHAR(4)
AS
BEGIN
-- 1. Populate the temp table (sample data)
IF OBJECT_ID('##tmp','U') IS NOT NULL DROP TABLE ##tmp;
SELECT SomeId = IDENTITY(INT,1,1), ColA, ColB
INTO ##tmp
FROM (VALUES(1,3),(6,5),(2,8),(5,5),(2,6),(5,1)) AS f(ColA,ColB);
-- NOTE: On SQL 2014+ SELECT INTO is often faster than the standard create+insert
;
-- 2. Setup @sortby
SET @sortby = QUOTENAME(@sortby)+' '+CASE @sortorder WHEN 'DESC' THEN 'DESC' ELSE '' END;
-- 3. Set up the Dynamic SQL
DECLARE @createIndex NVARCHAR(4000) = 'CREATE CLUSTERED INDEX x ON ##tmp ('+@sortby+') ';
DECLARE @executeQuery NVARCHAR(4000) = 'SELECT t.* FROM ##tmp AS t ORDER BY '+@sortby;
-- 4. Execute the queries
EXEC sys.sp_executesql @createIndex;
EXEC sys.sp_executesql @executeQuery;
END
GO
您可以这样测试:
EXEC dbo.DynamicSortProc 'ColA', 'ASC';
EXEC dbo.DynamicSortProc 'ColA', 'DESC';
EXEC dbo.DynamicSortProc 'ColB', 'ASC';
EXEC dbo.DynamicSortProc 'ColB', 'DESC';
在每种情况下,它们均按预期进行排序,并且输出查询中没有排序。