Parameter Sniffing Not working - sql

I am using MSSQL. I have a stored procedure which works fine for couple of days and later on it becomes slow. I came to know that Parameter Sniffing will work for it. How ever after implementing it it became slow for ever. I also tried to Recompiling job. I faced the same slowness issue immediately.
Can some one please help me with this ?
Below is the structure of my Stored Procedure.
#START_VALUE int=null,
#END_VALUE int=null
#UID NVARCHAR(MAX)=null,
AS
BEGIN
SELECT
dbo.TABLE1.ID,
ROW_NUMBER() OVER (ORDER BY TABLE1.UPDATED_ON desc) AS RN,
CONVERT(VARCHAR(10), dbo.TABLE1.DATE, 101) AS TDATE,
CATEGORY = (
SELECT TOP 1 COLUMN1
FROM TABLE5 CT1
WHERE TABLE1.CATEGORY = CT1.CATEGORY_ID
),
TYPETEXT = (
SELECT TOP 1 COLUMN1
FROM TABLE6 CT1
WHERE TABLE1.TYPE = CT1.TYPE_ID
),
IMAGE = STUFF(( SELECT DISTINCT ',' + CAST(pm.C1 AS varchar(12))
FROM TABLE2 pm
WHERE pm.ID = TABLE1.ID AND pm.C1 IS NOT NULL AND pm.C1 <> ''
FOR XML PATH('')),
1, 1, '' ) INTO #tempRecords
FROM dbo.TABLE1
WHERE ((#UID is null OR dbo.TABLE1.ID = #UID )
ORDER BY TABLE1.UPDATED DESC
SELECT #count = COUNT(*) FROM #tempRecords;
SELECT *, CONVERT([int],#count) AS 'TOTAL_RECORDS'
FROM #tempRecords
WHERE #tempRecords.RN BETWEEN CONVERT([bigint], #START_VALUE) AND CONVERT([bigint], #END_VALUE)
END
GO

To make the query optimized for parameter sniffing, declare dummy variables and use them in your query, as opposed to using the original parameters as such.
CREATE PROCEDURE test_proc
#START_VALUE INT=NULL,
#END_VALUE INT=NULL,
#UID NVARCHAR(max)=NULL
as
BEGIN
DECLARE #START_VALUE_SNIFF INT=NULL,
#END_VALUE_SNIFF INT=NULL,
#UID_SNIFF NVARCHAR(max)=NULL
SET #START_VALUE_SNIFF = #START_VALUE
SET #END_VALUE_SNIFF = #END_VALUE
SET #UID_SNIFF = #UID
select * from
FROM dbo.TABLE1
WHERE ((#UID_SNIFF is null OR dbo.TABLE1.ID = #UID_SNIFF )
ORDER BY TABLE1.UPDATED DESC
END

Related

Sending same parameter twice in exec

I have a simple stored procedure like this:
[dbo].[getStatusList]
#Extended NVARCHAR(255) = 'Project Status',
#Exclude NVARCHAR(255) = '',
#All BIT = 0
AS
SET NOCOUNT ON
IF (#All = 0)
BEGIN
SELECT
[GeneralKey],
[Label]
FROM
[General]
WHERE
[Extended] = #Extended
AND [Label] <> #Exclude
ORDER BY
[OrderID];
END
ELSE
BEGIN
IF (#All = 1)
BEGIN
SELECT
0 AS [GeneralKey],
'Any' AS [Label],
0 AS [OrderID]
UNION ALL
SELECT
[GeneralKey],
[Label],
[OrderID]
FROM
[General]
WHERE
[Extended] = #Extended
AND [Label] <> #Exclude
ORDER BY
[OrderID];
END
END
That I want to do is exec this stored procedure sending twice #Extended parameter like:
exec getStatusList #Extended = 'title1' AND #Extended = 'title2'
It is not possible to do something like this on exec? To only way to solve this is to add another parameter to stored procedure?
Update
As comments below mentioned, I tried this:
CREATE OR ALTER PROCEDURE usp_Get_StatusListByDesignType
-- Add the parameters for the stored procedure here
#Extended NVARCHAR(MAX),
#Exclude NVARCHAR(255) = '',
#All BIT = 0
AS
SET NOCOUNT ON
IF (#All = 0)
BEGIN
DECLARE #Parameter1 VARCHAR(50)
DECLARE #Parameter2 VARCHAR(50)
;WITH CTE AS
(
SELECT
*,
ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) rn
FROM
STRING_SPLIT (#Extended,',')
)
SELECT
#Parameter1 = MAX(CASE WHEN rn = 1 THEN VALUE END),
#Parameter2 = MAX(CASE WHEN rn = 2 THEN VALUE END)
FROM
CTE
SELECT
[GeneralKey], [Label]
FROM
[General]
WHERE
[Extended] IN (SELECT #Parameter1, #Parameter2)
AND [Label] <> #Exclude
ORDER BY
[OrderID];
END
ELSE
BEGIN
IF (#All = 1)
BEGIN
SELECT
0 AS [GeneralKey],
'Any' AS [Label],
0 AS [OrderID]
UNION ALL
SELECT
[GeneralKey],
[Label],
[OrderID]
FROM
[General]
WHERE
[Extended] IN (SELECT #Parameter1, #Parameter2)
AND [Label] <> #Exclude
ORDER BY
[OrderID];
END
RETURN;
But I get this error:
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
You can let pass your parameter like para1Val1,para1Val2... connected with , comma.
then use STRING_SPLIT function to split it from , comma then get the parameter.
DECLARE #Extended varchar(max)='title1,titl2'
Here is a simple
DECLARE #Extended varchar(max)='title1,titl2'
select *,row_number() over(order by (select NULL)) rn
from STRING_SPLIT (#Extended,',')
Then you can set parameters in SP.
declare parameters variable, then use row_number make your parameter row number.
next step use condition aggregate function set the parameter in select clause.
declare #parameter1 varchar(50)
declare #parameter2 varchar(50)
;with cte as (
select *,row_number() over(order by (select NULL)) rn
from STRING_SPLIT (#Extended,',')
)
select #parameter1 = MAX(case when rn = 1 then value end),
#parameter2 = MAX(case when rn = 2 then value end)
from cte
sqlfiddle
This method :
exec getStatusList #Extended='title1' AND #Extended = 'title2'
it's not going to work at all as a parameter or a variable in general can only hold one value and nothing more. So, you can't do that unless you execute the store procedure twice and specify the parameters on each one of them. Or you may use loops to do it. But i'm not fan of loops and I always suggests to avoid them as much as possible.
The method that I see it fits your situation is a TVP with some modifications on the store procedure itself.
So, you'll pass the values in comma separate values in #Extended and from the store procedure you'll use IN() and NOT IN() instead of = and <> this will extend it to have more values to compare rather than one value.
Then you can use XML to split the values and turn them into rows.
So we will use this :
SELECT LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)')))
FROM (
SELECT CAST('<XMLRoot><RowData>' + REPLACE(#Extended,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) Extended
) D
CROSS APPLY Extended.nodes('/XMLRoot/RowData')m(n)
You can inject it directly into the store procedure with modifying the operators that I mentioned above, and it will work just fine. but for the code reuse, we will use it as TVP.
CREATE FUNCTION SplitToRows
(
#Extended VARCHAR(MAX)
)
RETURNS TABLE
AS
RETURN
(
SELECT LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))) Extended
FROM (
SELECT CAST('<XMLRoot><RowData>' + REPLACE(#Extended,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) Extended
) D
CROSS APPLY Extended.nodes('/XMLRoot/RowData')m(n)
)
Now, you can modify the store procedure to the following :
[dbo].[getStatusList]
#Extended NVARCHAR(255) = 'Project Status'
, #Exclude NVARCHAR(255) = ''
, #All BIT = 0
AS
SET NOCOUNT ON
IF(#All = 0)
BEGIN
SELECT
[GeneralKey]
, [Label]
FROM [General]
WHERE
[Extended] IN( SELECT * FROM dbo.SplitToRows(#Extended) )
AND [Label] NOT IN( SELECT * FROM dbo.SplitToRows(#Exclude) )
ORDER BY
[OrderID];
END
ELSE
BEGIN
IF(#All = 1)
BEGIN
SELECT
0 AS [GeneralKey]
, 'Any' AS [Label]
, 0 AS [OrderID]
UNION ALL
SELECT
[GeneralKey]
, [Label]
, [OrderID]
FROM [General]
WHERE
[Extended] IN( SELECT * FROM dbo.SplitToRows(#Extended) )
AND [Label] NOT IN( SELECT * FROM dbo.SplitToRows(#Exclude) )
ORDER BY
[OrderID];
END
END
Now, you can pass multiple separated values in #Extended and #Exclude at the same time like this :
#Extended = 'title1, title2, title3'
#Exclude = 'title5, title8'
so both parameters will use the same method.

Create View dynamically from SP in sql server 2012

sql server 2012
i have created a SP to create view dynamically with Parameter i supplied.
below is the code
i am not sure why i am getting the below error.
Msg 102, Level 15, State 1, Procedure uspCreateView, Line 10
Incorrect syntax near '#VIEWNM'.
Code:
CREATE PROCEDURE uspCreateView
#VIEWNM VARCHAR(50),
#COMP INT,
#TODT DATE = 9999-12-31
AS
EXEC ('
CREATE VIEW +'#VIEWNM'
AS
(
SELECT
COL1,
COL2,
COL3,
DATE,
SKU,
CASE WHEN IsRowCurrent = 1 THEN '#TODT' ELSE dateadd(MILLISECOND, -1000 - datepart(MILLISECOND, FMDT), FMDT) END AS TODT,
FROM MYTABLE mt
OUTER APPLY ( SELECT MAX(DATEADD(second, -1, FMDT)) TO_DATE
FROM MYTABLE mt2
WHERE mt2.COL1 = mt.COL1
AND mt2.COL2 = mt.COL2
AND mt2.FMDT > mt.FMDT
AND mt.COL3 = '#COMPID' ) oa
WHERE mt.COL3 = '#COMPID'
)
please help me to fix the below error.
Thanks
I am not sure, why you want to create views dynamically, ideally views should be created before hand only, and you will be required to fetch the data depending on the condition.
Still if you want to proceed, you should do it proper way to avoid any issues. I can see there are issues with your implementation. Ideally you should make it parameterized, like following sample query to avoid any SQL injection.
There are issues with your provided code also, I tried to fix some of these.
CREATE PROCEDURE uspCreateView
(
#VIEWNM VARCHAR(50),
#COMP INT,
#TODT DATE = '9999-12-31'
)
AS
BEGIN
DECLARE #Query NVARCHAR(MAX)
DECLARE #ParmDefinition nvarchar(MAX);
SET #Query = N'CREATE VIEW #VIEWNM_I AS ( SELECT COL1, COL2, COL3, DATE, SKU,
CASE WHEN IsRowCurrent = 1 THEN #TODT_I ELSE
dateadd(MILLISECOND, -1000 - datepart(MILLISECOND, FMDT)
, FMDT) END AS TODT, FROM MYTABLE mt OUTER APPLY (
SELECT MAX(DATEADD(second, -1, FMDT)) TO_DATE
FROM MYTABLE mt2
WHERE mt2.COL1 = mt.COL1
AND mt2.COL2 = mt.COL2
AND mt2.FMDT > mt.FMDT
AND mt.COL3 = #COMPID_I ) oa
WHERE mt.COL3 = #COMPID_I)'
SET #ParmDefinition = N'#VIEWNM VARCHAR(100),#TODT_I DATETIME,#COMP_I INT';
EXECUTE sp_executesql #Query,#ParmDefinition, #VIEWNM_I=#VIEWNM, #COMP_I=#COMP, #TODT_I=#TODT
END
Try this
Command(s) completed successfully.
CREATE PROCEDURE uspCreateView
#VIEWNM VARCHAR(50),
#COMP INT,
#TODT DATE = '9999-12-31'
AS
EXEC ('
CREATE VIEW '+#VIEWNM+'
AS
(
SELECT
COL1,
COL2,
COL3,
DATE,
SKU,
CASE WHEN IsRowCurrent = 1 THEN '+#TODT+' ELSE dateadd(MILLISECOND, -1000 - datepart(MILLISECOND, FMDT), FMDT) END AS TODT,
FROM MYTABLE mt
OUTER APPLY ( SELECT MAX(DATEADD(second, -1, FMDT)) TO_DATE
FROM MYTABLE mt2
WHERE mt2.COL1 = mt.COL1
AND mt2.COL2 = mt.COL2
AND mt2.FMDT > mt.FMDT
AND mt.COL3 = '+#COMP+' ) oa
WHERE mt.COL3 = '+#COMP+'
) ')
It should be
CREATE VIEW ' + #VIEWNM + ' AS...

Stored procedure becomes slow every couple of days

I am facing an issue on SQL Server in which my stored procedure becomes slow after couple of days.
Below is the sample of my stored procedure.
Could this be a caching issue on the server side? Can I increase the server's cache size to resolve the problem?
Normally the stored procedure returns data in one second.
#START_VALUE int=null,
#END_VALUE int=null
#UID NVARCHAR(MAX)=null,
AS
BEGIN
SELECT
dbo.TABLE1.ID,
ROW_NUMBER() OVER (ORDER BY TABLE1.UPDATED_ON desc) AS RN,
CONVERT(VARCHAR(10), dbo.TABLE1.DATE, 101) AS TDATE,
CATEGORY = (
SELECT TOP 1 COLUMN1
FROM TABLE5 CT1
WHERE TABLE1.CATEGORY = CT1.CATEGORY_ID
),
TYPETEXT = (
SELECT TOP 1 COLUMN1
FROM TABLE6 CT1
WHERE TABLE1.TYPE = CT1.TYPE_ID
),
IMAGE = STUFF(( SELECT DISTINCT ',' + CAST(pm.C1 AS varchar(12))
FROM TABLE2 pm
WHERE pm.ID = TABLE1.ID AND pm.C1 IS NOT NULL AND pm.C1 <> ''
FOR XML PATH('')),
1, 1, '' ) INTO #tempRecords
FROM dbo.TABLE1
WHERE ((#UID is null OR dbo.TABLE1.ID = #UID )
ORDER BY TABLE1.UPDATED DESC
SELECT #count = COUNT(*) FROM #tempRecords;
SELECT *, CONVERT([int],#count) AS 'TOTAL_RECORDS'
FROM #tempRecords
WHERE #tempRecords.RN BETWEEN CONVERT([bigint], #START_VALUE) AND CONVERT([bigint], #END_VALUE)
END
GO
'
A few performance tips:
1) #UID is null OR dbo.TABLE1.ID = #UID --> this is bad because you'll have one execution plan when UID is null and when it's not. Build a dynamic sql query and you'll get 2 execution plans.
2) Update stats in a maintenance plan.
3) Check index fragmentation.
4) Try to do the same thing without using a temp table.
5) Try to avoid castings.

SQl Server Performance

I have database with more than 30 tables and more than 270k records in one table (the most important table) and create view get data from this table and other tables,
When I run the code below on my machine it takes less than 4 sec to get data from the view.
select * from view
My problem is that,
When I run the same script of database on another machine and run the same query from the view it takes a very long time.
Code for view
SELECT
dbo.UserSite.UserId,
dbo.UserSite.Name,
dbo.Site.RootPageURL,
dbo.PDFDocument.DocumentId,
dbo.RunDocumentVerificationResult.Status,
dbo.UserSite.UserSiteId,
dbo.Systemcode.Value,
dbo.RunDocumentVerificationResult.PageNumber,
dbo.RunDocumentVerificationResult.TestNameID,
dbo.RunDocumentVerificationResult.VerificationResultID,
dbo.TaskRun.VerificationEndDate,
dbo.TaskRun.RunId,
dbo.RunDocument.IsTagged,
dbo.RunDocument.IsProtected,
dbo.RunDocument.IsCorrupted
FROM
dbo.UserSite
INNER JOIN dbo.Site ON dbo.UserSite.SiteId = dbo.Site.SiteId
INNER JOIN dbo.TaskUserSites ON dbo.UserSite.UserSiteId = dbo.TaskUserSites.UserSiteId
INNER JOIN dbo.Task ON dbo.TaskUserSites.TaskId = dbo.Task.TaskId
INNER JOIN dbo.TaskRun ON dbo.Task.TaskId = dbo.TaskRun.TaskId
INNER JOIN dbo.RunDocument ON dbo.TaskRun.RunId = dbo.RunDocument.RunId
INNER JOIN dbo.PDFDocument ON dbo.PDFDocument.DocumentId = dbo.RunDocument.DocumentId
INNER JOIN dbo.RunDocumentVerificationResult ON dbo.RunDocument.RunDocumentId = dbo.RunDocumentVerificationResult.RunDocumentID
INNER JOIN dbo.Systemcode ON dbo.RunDocumentVerificationResult.Status = dbo.Systemcode.ID
EstimatedTime
Procdure Code is
ALTER proc [dbo].[status]
as
begin
begin transaction
declare #usersiteid bigint
declare #runid bigint
declare #TestedFiles int
declare #TaggedFiles int
declare #UnTaggedFiles int
declare #PassedFiles int
declare #FaildFiles int
declare #Name varchar(500)
declare #VerificationEndDate datetime
declare #RootPageURL varchar (1024)
declare #status table ( Name varchar(1000) , Urlrootpage varchar(2000) ,Testedfile int , TaggedFiles int , Untaggedfile int ,passedfiles int , faildfiles int,VerificationEndDate datetime,rootpageurl varchar(1024) )
declare #domain table (name varchar(1000) , urlrootpage varchar (2000) )
if (1=2)
begin
select 'n' Name ,'r' Urlrootpage ,1 Testedfile ,1 TaggedFiles ,0 Untaggedfile ,0 passedfiles ,0 faildfiles,GETDATE() VerificationEndDate ,'r' rootpageurl where 1=2
end
create table #status ( Name varchar(1000) , Urlrootpage varchar(2000) ,Testedfile int , TaggedFiles int , Untaggedfile int ,passedfiles int , faildfiles int,VerificationEndDate datetime,rootpageurl varchar(1024) )
set #usersiteid = (select min (UserSiteId) from vw)
set #runid = (select max (runid) from vw where usersiteid = #usersiteid)
while #usersiteid is not null
begin
set #TestedFiles = (select (count ( distinct documentid )) from vw where UserSiteId=#usersiteid and runid=#runid )
set #TaggedFiles = (select (count ( distinct documentid )) from vw where istagged=1 and UserSiteId=#usersiteid and runid=#runid)
set #UnTaggedFiles =(select (count ( distinct documentid )) from vw where istagged=0 and UserSiteId=#usersiteid and runid=#runid)
set #PassedFiles =(select (count ( distinct documentid )) from vw where Status<>1 and DocumentId not in (select DocumentId from vw where status =1) and UserSiteId=#usersiteid and runid=#runid)
set #FaildFiles = ( select (count ( distinct documentid )) from vw where Status=1 and UserSiteId=#usersiteid and runid=#runid)
set #Name = (select distinct name from vw where UserSiteId=#usersiteid)
set #rootPageUrl = (select distinct RootPageURL from vw where UserSiteId=#usersiteid)
set #VerificationEndDate = (select max(distinct VerificationEndDate) from vw where UserSiteId=#usersiteid and RunId=#runid)
insert into #status ( Name, Urlrootpage , Testedfile , TaggedFiles , Untaggedfile ,passedfiles , faildfiles ,VerificationEndDate ) values
(#Name,#RootPageURL,#TestedFiles,#TaggedFiles ,#UnTaggedFiles,#PassedFiles,#FaildFiles,#VerificationEndDate)
set #usersiteid = (select min (UserSiteId) from vw where UserSiteId > #usersiteid)
set #runid = (select max (runid) from vw where usersiteid = #usersiteid)
end
insert into #domain select UserSite.Name , Site.RootPageURL from UserSite inner join Site on UserSite.SiteId=Site.SiteId where UserSiteId not in (select UserSiteId from vw)
insert into #status select name,urlrootpage,0,0,0,0,0,null,0 from #domain
select Name,Urlrootpage,Testedfile,TaggedFiles,Untaggedfile, passedfiles,faildfiles from #status
end
If (##Error <> 0) -- Check if any error
Begin
rollback transaction
End
else
commit transaction
return
I would do a little test to find out if it is actually, as suggested, the network bandwidth that causes your query to be slow, or, better said, to look like it's slow. Append a limit-statement to your query and run it, like LIMIT 10. So while the whole query will execute, only the 10 first rows will be sent, and if the network is your bottleneck, it should now be very fast. If it is still that slow, your machine's sql server probably has very little memory to use, so it can't fit the whole result in, and your local sql server is probably configured to use more memory, so it executes faster. In this case, giving your sql server more memory should fix the problem. This should be no problem at all, since, as already mentioned in the comments, your database is actually very small, so the currently used memory will be very small too.
If your network connection turns out to be the bottleneck, you need to decide if, and why, you need all the results to be sent at once. I can't really help you on that one, since I don't know what the application is supposed to do with the data. But probably you should either do some aggegration in the database, or only send a small part of the data over the network.

How to rectify this query in SQL Server 2005

I have the a query which is union of two queries, the resulting query is returning duplicate records, I don't want duplicate records. I tried using DISTINCT but still getting the same result, can anybody help me fix this query?
I also want to know whether this query is safe from SQL injection... I'll be pasting my query below:
ALTER PROCEDURE [dbo].[sp_GetTrashListWithSorting] --'6dbf9a01-c88f-414d-8dd9-696749258cef', '6dbf9a01-c88f-414d-8dd9-696749258cef','DateTime ASC','0','30'
(
#p_CreatedBy UNIQUEIDENTIFIER,
#p_ToReceipientID UNIQUEIDENTIFIER,
#p_SortExpression NVARCHAR(100),
#p_StartIndex INT,
#p_MaxRows INT
)
AS
SET NOCOUNT ON;
IF LEN(#p_SortExpression) = 0
SET #p_SortExpression ='DateTime DESC'
DECLARE #Sql NVARCHAR(4000)
SET #sql = 'SELECT ID, DateTime, Subject, CreatedBy, ToReceipientID, Status
FROM (SELECT ID,
DateTime,
Subject,
CreatedBy,
ToReceipientID,
Status,
ROW_NUMBER() OVER(ORDER BY '+ #p_SortExpression +') AS Indexing
FROM (SELECT ID,
DateTime,
Subject,
CreatedBy,
ToReceipientID,
SenderStatus AS Status
FROM ComposeMail
WHERE (CreatedBy = #p)
AND (SenderStatus = 7 OR SenderStatus = 8)
UNION
SELECT ID,
DateTime,
Subject,
CreatedBy,
ToReceipientID,
ReceiverStatus As Status
FROM ComposeMail
WHERE (ToReceipientID = #p1)
AND (ReceiverStatus = 7 OR ReceiverStatus = 8)) AS NewDataTable
) AS IndexTable
WHERE
Indexing > #p2 AND Indexing<= (#p2+#p3)'
DECLARE #paramDefinition NVARCHAR(500)
SET #paramDefinition = N'#p UNIQUEIDENTIFIER ,#p1 UNIQUEIDENTIFIER, #p2 INT, #p3 INT'
EXEC sp_executesql #sql, #paramDefinition,
#p = #p_CreatedBy,
#p1 = #p_ToReceipientID,
#p2 = #p_StartIndex ,
#p3 = #p_MaxRows
1) I re-wrote your SQL as:
WITH trash_list AS (
SELECT cm.id,
cm.datetime,
cm.subject,
cm.createdby,
cm.toreceipientid,
cm.senderstatus AS Status
FROM COMPOSEMAIL cm
WHERE cm.createdBy = #p
AND cm.enderStatus IN(7, 8)
UNION
SELECT cm.id,
cm.datetime,
cm.subject,
cm.createdby,
cm.toreceipientid,
cm.receiverstatus AS Status
FROM COMPOSEMAIL cm
WHERE cm.toreceipientid = #p1
AND cm.receiverstatus IN (7, 8))
SELECT t.id,
t.datetime,
t.subject,
t.createdby,
t.toreceipientid,
t.status
FROM (SELECT tl.id,
tl.datetime,
tl.subject,
tl.createdby,
tl.toreceipientid,
tl.status,
ROW_NUMBER() OVER(ORDER BY '+ #p_SortExpression +') AS Indexing
FROM trash_list tl
GROUP BY tl.id,
tl.datetime,
tl.subject,
tl.createdby,
tl.toreceipientid,
tl.status) t
WHERE t.indexing BETWEEN #p2 AND (#p2+#p3)
...but if you still get duplicates, review the logic in the SELECT/UNION in the WITH clause.
Get it to work as normal SQL before turning it into dynamic SQL.
2) The query is not safe from injection attacks because you aren't handling single quotes when users can provide text:
IF LEN(#p_SortExpression)=0
SET #p_SortExpression ='DateTime DESC'
...should be:
IF LEN(#p_SortExpression)=0
SET #p_SortExpression ='DateTime DESC'
ELSE
SET #p_SortExpression = REPLACE(#p_SortExpression, '''', '''''')
You do not need to queries and a union. Instead of these 2 lines (one per subquery)
WHERE (CreatedBy = #p)
WHERE (ToReceipientID = #p1)
do this (in one query)
WHERE CreatedBy IN (#p, #p1)
Like this:
SELECT
ID
, DateTime
, Subject
, CreatedBy
, ToReceipientID
, Status
FROM (
SELECT
ID
, DateTime
, Subject
, CreatedBy
, ToReceipientID
, SenderStatus AS Status
, ROW_NUMBER() OVER (ORDER BY ' + #p_SortExpression + ') AS Indexing
FROM ComposeMail
WHERE CreatedBy IN (#p, #p1)
AND (SenderStatus = 7
OR SenderStatus = 8)
) AS IndexTable
WHERE Indexing > #p2
AND Indexing <= (#p2 + #p3)
HOWEVER I am not sure I understand how you pass in values for #p or #p1