This query (I've simulated it to show you. Otherwise, it is longer with many more lists of columns, some more tables joined; and finally to sort by every column as required by the user) takes too long, and can timeout from the UI sometimes. I was trying to optimize the stored procedure to reduce loading time without affecting the retrieved lists. I was considering to select * from the temporary table and then Order from there. That could help somehow. I also considered using a dynamic sql without specifying the @sortidr (DESC/ASC), but the user should have the flexibility to order either way.
I was wondering if anyone can suggest better ways of optimizing it.
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
I'm not at a PC so I won't be able to add code until later but you have provided enough information for me to provide some good insight.
First - the optimizer will never be able to leverage an index to prevent a sort when you order by a CASE statement. That said, there are many reasons your query could be slow; you should remove that logic then test performance to understand if that's the culprit.
Based on the limited info I have my suggestion would be update your proc to: 1. Use dynamic SQL to build your temp table, as you have done, but without the CASE statement.
Now you have a temp table correctly indexed based on user supplied parameters.
Add a second dynamic SQL statement that does a SELECT * FROM #temp... You will again use @columnName and @sortOrder to build a SARGable ORDER BY (one which will leverage the index from Step #1.
Test with different parameters always looking at the Actual Execution plan to further tune your indexes.
Hope this helps. I'll add demo code a little later if you need.
Updated On 2/22/2019 to include examples:
Here's a stored proc that does what I'm describing (note the comments)--
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
You can test like this:
EXEC dbo.DynamicSortProc 'ColA', 'ASC';
EXEC dbo.DynamicSortProc 'ColA', 'DESC';
EXEC dbo.DynamicSortProc 'ColB', 'ASC';
EXEC dbo.DynamicSortProc 'ColB', 'DESC';
In each case they sort as expected and there is no sort in the output query.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.