Added a few lines of code and now query is taking 5x as long to run. Executions plans are almost identical - sql

I have a query that has been in production a long time and takes an average of 4 seconds to run. I added the code below which is a declaration of a table and then an insert into that table. then the select query joins to that and returns 1 field from it in the select statement. Now the query takes up to 25 seconds to run.
DECLARE #tmpStageLoc TABLE
(
LP VARCHAR(20) ,
stgloc VARCHAR(20)
)
INSERT INTO #tmpStageLoc
EXEC dbo.spGetStageLoc #ActLP = #LP;
--Try to get data from DW tables first.
INSERT INTO [COMMON_INFORMATION].[dbo].[ProcTmpData]
( SPID ,
DataSetName ,
IntValue1 , --JRB004
ChValue1 , --JRB001
String1 ,
InsDate
)
SELECT DISTINCT
##SPID ,
#datasetname ,
ls.ToDC ,
col.Cust_No --JRB001
,
REPLACE(#LOADNUM, ' ', '') + --JRB007
'~' + 'N/A'
+ --JRB005 Wave number no longer printed on label
'~' + CASE WHEN la.stage_loc IS NULL THEN ''
ELSE la.stage_loc + '-' + ISNULL(la.misc_info,
'')
END + '~' + fa.OrderControlNo + '~' + col.Cust_No
+ '~' + SUBSTRING(cst.name, 1, 20) + '~'
+ SUBSTRING(cst.name, 21, 5) + '~' + LEFT(cst.address1
+ ', '
+ CASE
WHEN cst.address2 IS NULL
THEN ''
ELSE ( cst.address2
+ ', ' )
END + cst.city
+ ', '
+ cst.state, 45)
+ '~' + ls.StopNO + '~' + ls.LoadNo + '~' + e.first_name
+ ' ' + e.last_name + --JRB009
'~' + --JRB009
CASE WHEN cst.plt_usage IS NULL --JRB009
THEN '' --JRB009
ELSE --JRB009
'# ' + LEFT(cst.plt_usage, 20) --JRB009
END + '~' + ISNULL(STG.STGLOC, '') + '~' --JRB009
,
#RUNDTE
FROM dbo.tblFactAction AS fa
LEFT OUTER JOIN COMMON_INFORMATION.dbo.LoadStop AS ls ON LEFT(fa.OrderControlNo,
8) = ls.ExtOrderNo
AND ls.LatestLoadFlg = 1 --JRB008
LEFT OUTER JOIN dbo.RP_LaneAssign AS la ON ls.LoadNo = la.carrier_move_id
OR ls.ExtOrderNo = la.order_num
LEFT OUTER JOIN dbo.Cust_Order_Lookup AS col ON fa.OrderControlNo = col.Order_Control_no
LEFT OUTER JOIN COMMON_INFORMATION.dbo.Partners AS cst ON col.Cust_No = cst.partner_shipto
LEFT OUTER JOIN COMMON_INFORMATION.dbo.Employee AS e ON fa.EmployeeID = CAST(e.emp_no AS VARCHAR(40))
LEFT OUTER JOIN #tmpStageLoc STG ON fa.actlp = STG.LP
WHERE fa.ActLP = #LOADNUM
AND fa.AssignTypeID IN ( 'PB01', 'PF01' )
I have looked at the execution plans in SQL Sentry Plan Explorer and they look almost identical. I am using the free version of the software. I am at a loss at why the query takes so long to run. just an FYI when I execute the stored procedure that is being called it runs instantly.
Any ideas on how I can figure out why the query now runs for so long?

Related

some weird signs appearing on SQL SERVER Query output

i have written a SELECT Query on SQL SERVER 2014 . I have got the desired output . but an apostrophe symbol(') appearing on 'TaskAction' field data(at the end of each data). here it is my script:
SELECT
WOtask.PK,
WOPK,
TaskNo,
TaskAction =
CASE
WHEN WOTask.AssetPK IS NOT NULL THEN '<b>' + Asset.AssetName + ' [' + Asset.AssetID + ']</b> ' + CASE
WHEN Asset.Vicinity IS NOT NULL AND
Asset.Vicinity <> '''' THEN RTRIM(Asset.Vicinity) + ': '
ELSE ''''
END + WOtask.TaskAction + CASE
WHEN CONVERT(varchar, ValueLow) IS NOT NULL AND
CONVERT(varchar, ValueHi) IS NOT NULL AND
Spec = 1 THEN ' (Range: '' + CONVERT(VARCHAR,CONVERT(FLOAT,ISNULL(ValueLow,0))) + '' - '' + CONVERT(VARCHAR,CONVERT(FLOAT,ISNULL(ValueHi,0))) + )'
ELSE ''''
END
ELSE WOtask.TaskAction + CASE
WHEN CONVERT(varchar, ValueLow) IS NOT NULL AND
CONVERT(varchar, ValueHi) IS NOT NULL AND
Spec = 1 THEN ' (Range: '' + CONVERT(VARCHAR,CONVERT(FLOAT,ISNULL(ValueLow,0))) + '' - '' + CONVERT(VARCHAR,CONVERT(FLOAT,ISNULL(ValueHi,0))) + )'
ELSE ''''
END
END,
Rate,
Measurement,
Initials,
Fail,
Complete,
Header,
LineStyle,
WOtask.Comments,
WOtask.NotApplicable,
WOTask.Photo1,
WOTask.Photo2
FROM WOtask WITH (NOLOCK)
LEFT OUTER JOIN Asset WITH (NOLOCK)
ON Asset.AssetPK = WOTask.AssetPK
LEFT OUTER JOIN AssetSpecification
ON AssetSpecification.PK = WOTask.AssetSpecificationPK
WHERE (WOPK IN (SELECT
WOPK
FROM WO WITH (NOLOCK)
LEFT OUTER JOIN Asset WITH (NOLOCK)
ON Asset.AssetPK = WO.AssetPK
LEFT OUTER JOIN AssetHierarchy WITH (NOLOCK)
ON AssetHierarchy.AssetPK = WO.AssetPK
WHERE WO.WOPK = 10109)
)
ORDER BY WOPK, TaskNo
now please check my output and error
please help to solve this issue. Thanks in Advance.
As noted in comments, use ELSE '' instead of ELSE ''''. The reason is that within a pair of single quotes, then '' tells SQL to escape a single quote into your output.
For instance, to show the output User's, you would need SELECT 'User''s'.

select same columns twice in MS SQL

Have a select Statement like
select
SouceField_A
+ 'DeliminiterCharacter'
+ SouceField_A
+ 'DeliminiterCharacter'
+ SourceField_B
+ 'DeliminiterCharacter'
...
Problem is that in real life I do not have a simple Field, but have CASE WHEN ... END. This makes it error prone and difficult to Keep both places up to date when Change is required.
For this I wonder if there is an easy way to put it into variable etc.
Below is part of query to Show
select
ISNULL ( Oracle_Update , 'create' ) + '~' +
#Email + '~' +
#ItemNo + '~' +
'' + '~' +
'D' + '~' +
ISNULL ( Item_Desc_DE , '' ) + '~' +
REPLACE(REPLACE(ISNULL ( Item_Specification_DE , '' ), CHAR(13), ''), CHAR (10), ' $#') + '~' +
ISNULL ( Item_Copy_From, '' ) + '~' +
-- master template
CASE WHEN Oracle_Update like 'update' OR item_copy_from is not NULL
THEN
''
ELSE ISNULL ( Item_Template , 'MAG Assembly' )
END + '~' +
CASE WHEN Oracle_Update like 'update' OR item_copy_from is not NULL
THEN
''
ELSE ISNULL
Just use a nested query:
select
SouceField_A
+ 'DeliminiterCharacter'
+ SouceField_A
+ 'DeliminiterCharacter'
+ SourceField_B
+ 'DeliminiterCharacter'
FROM (
SELECT CASE ... ) AS t
You can used a derived table, where this table is defined in the FROM clause. I've given the long code the column aliases SourceField_A and SourceField_B. The derived table is aliased dT. For clarity, the SELECT clause can use the alias in front of the column name. For example, dT.SourceField_A
SELECT dT.SourceField_A
+ 'DeliminiterCharacter'
+ dT.SourceField_A
+ 'DeliminiterCharacter'
+ dT.SourceField_B
+ 'DeliminiterCharacter'
FROM (
ISNULL ( Oracle_Update , 'create' ) + '~' +
#Email + '~' +
#ItemNo + '~' +
'' + '~' +
'D' + '~' +
ISNULL ( Item_Desc_DE , '' ) + '~' +
REPLACE(REPLACE(ISNULL ( Item_Specification_DE , '' ), CHAR(13), ''), CHAR (10), ' $#') + '~' +
ISNULL ( Item_Copy_From, '' ) + '~' +
-- master template
CASE WHEN Oracle_Update like 'update' OR item_copy_from is not NULL
THEN
''
ELSE ISNULL ( Item_Template , 'MAG Assembly' )
END + '~' +
CASE WHEN Oracle_Update like 'update' OR item_copy_from is not NULL
THEN
''
ELSE ISNULL
...
AS SourceField_A
,...
AS SourceField_B
) AS dT

How to reduce execution time of SQL Select Query

TitemName and TshotName is the problem here
SELECT DISTINCT
tJobs.* ,
tCustomer.Name AS Customer_name ,
(SELECT tEmployee.First + ' ' + tEmployee.Last
FROM tEmployee
WHERE tEmployee.EmployeeID = tJobs.AccountExecutiveID) AS AccountExecutive,
(SELECT tEmployee.First + ' ' + tEmployee.Last
FROM tEmployee
WHERE tEmployee.EmployeeID = tJobs.AccountManagerID) AS AccountManager,
dbo.RetrunUserFavourite(tJobs.JobNumber, 33369, 'Employee') AS Favorites,
(SELECT COUNT(*)
FROM tShots
WHERE tShots.JobNumber = tJobs.JobNumber) AS shotcount,
SUBSTRING((SELECT ', ' + SKU + ', ' + Source + ', ' + ModelNumber
+ ', ' + Description
FROM tItems
WHERE tItems.CustomerID = tCustomer.CustomerID
FOR XML PATH('')), 3, 200000) titemName,
SUBSTRING((SELECT ', ' + ArtDirection + ', '
+ REPLACE(CONVERT(VARCHAR(5), AdDate, 110), '-',
'/')
FROM tShots
WHERE tShots.JobNumber = tJobs.JobNumber
FOR XML PATH('')), 3, 200000) TshotName
FROM
tJobs
INNER JOIN
tCustomer ON tCustomer.CustomerID = tJobs.CustomerID
WHERE
tCustomer.CustomerID = 68666
I strongly agree with M Ali's comments. Two points I would make. The first is not with regard to performance. But, instead of substring() use:
STUFF((SELECT ', ' + SKU + ', ' + Source + ', ' + ModelNumber+ ', ' + Description
FROM tItems
WHERE tItems.CustomerID = tCustomer.CustomerID
FOR XML PATH('')
), 1, 1, '') as titemName
That way, you don't need strange, meaningless numbers floating around the code.
Second, you may need indexes. Based on the highlighted performance problems, I would suggest:
tItems(CustomerID)
and:
tshots(JobNumber, ArtDirection, AdDate)
You have awful lot of string manipulation going on is your query, anyway a slightly improved version of your query would look something like...
Select DISTINCT
tJobs.*
, tCustomer.Name AS Customer_name
, AE.First + ' ' + AE.Last AS AccountExecutive
, AM.First + ' ' + AM.Last AS AccountManager
, dbo.RetrunUserFavourite(tJobs.JobNumber,33369,'Employee')AS Favorites
, TS.shotcount
, SUBSTRING(( SELECT ', ' + SKU + ', ' + Source + ', ' + ModelNumber+ ', ' + Description
FROM tItems
where tItems.CustomerID=tCustomer.CustomerID
FOR XML PATH('')), 3, 200000)titemName
, SUBSTRING(( SELECT ', ' + ArtDirection +', '+REPLACE(CONVERT(VARCHAR(5),AdDate,110), '-','/')
FROM tShots
where tShots.JobNumber=tJobs.JobNumber
FOR XML PATH('')), 3, 200000)TshotName
From tJobs
inner join tCustomer on tCustomer.CustomerID = tJobs.CustomerID
Left join tEmployee AE ON AE.EmployeeID = tJobs.AccountExecutiveID
Left join tEmployee AM ON AM.EmployeeID = tJobs.AccountManagerID
Left join (
SELECT JobNumber , Count(*) shotcount
FROM tShots
GROUP BY JobNumber
) TS ON TS.JobNumber = tJobs.JobNumber
WHERE tCustomer.CustomerID = 68666
A Couple of Pointers:
Having sub-queries in your select statement makes it very inefficient, because the sub-query is executed for each row returned by the outer query, a more sensible way of doing it would be to use joins.
You Also have a call to a User-Defined Scalar function dbo.RetrunUserFavourite() in your select , these scalar UDFs are also performance killers, again the same execution logic is applied here, they are also executed for each row returned by the outer query, a more sensible way would be to put the function logic/code inside a CTE and join your query to that CTE.
These comma delimited lists that you are creating on the fly for last two columns will be slow, maybe an Inline-Table-Valued function can give better performance here.

CASE statement: Inconsistent conversion fail error - varchar to int

SELECT
CASE
WHEN Employees.first_name IS NULL
OR Employees.first_name = 'x' THEN Employees.last_name
WHEN Employees.credentials IS NULL THEN Employees.last_name + ', ' + Employees.first_name
ELSE Employees.last_name + ', ' + Employees.first_name + ' - ' + Employees.credentials
END,
Employees.num3,
Employees.address1 + ' ' + Employees.city + ', ' + Employees.state + ' ' + Employees.zip,
Employees.work_phone,
CASE
WHEN Clients.age <= 18 THEN 'Youth'
ELSE 'Adult'
END,
Clients.client_id,
Clients.last_name + ', ' + Clients.first_name,
ClientVisit.cptcode,
ClientVisit.visittype,
ClientVisit.rev_timeout,
ClientVisit.timein,
ClientVisit.duration,
SUM(CASE
WHEN ClientVisit.cptcode = 90791 THEN 200
WHEN ClientVisit.comb_units = 1 THEN 85.67
ELSE ClientVisit.comb_units * 21.4175
END),
DATEDIFF(d, ClientVisit.rev_timeout, ClientVisit.signature_datetime)
FROM dbo.ClientVisit
INNER JOIN dbo.Employees
ON (
ClientVisit.by_emp_id = Employees.emp_id
)
INNER JOIN dbo.Programs
ON (
ClientVisit.program_id = Programs.program_id
)
INNER JOIN dbo.Clients
ON (
Clients.client_id = ClientVisit.client_id
)
WHERE (
ClientVisit.rev_timeout BETWEEN '20160401 11:40:00.000' AND '20160415 11:40:16.000'
AND Programs.program_desc IN ('Off Panel')
AND ClientVisit.non_billable = 0
AND ClientVisit.cptcode NOT IN ('00000', '0124', '100', '1001', '101', '102', '103', '80100', '9079', '99999')
AND Employees.num3 IS NOT NULL
)
GROUP BY
CASE
WHEN Clients.age <= 18 THEN 'Youth'
ELSE 'Adult'
END,
CASE
WHEN Employees.first_name IS NULL
OR Employees.first_name = 'x' THEN Employees.last_name
WHEN Employees.credentials IS NULL THEN Employees.last_name + ', ' + Employees.first_name
ELSE Employees.last_name + ', ' + Employees.first_name + ' - ' + Employees.credentials
END,
DATEDIFF(d, ClientVisit.rev_timeout, ClientVisit.signature_datetime),
ClientVisit.cptcode,
Clients.last_name + ', ' + Clients.first_name,
Clients.client_id,
Employees.address1 + ' ' + Employees.city + ', ' + Employees.state + ' ' + Employees.zip,
Employees.work_phone,
ClientVisit.duration,
ClientVisit.visittype,
ClientVisit.rev_timeout,
ClientVisit.timein,
Employees.num3
Gives me the Error:
Conversion failed when converting the varchar value 'H2019' to data
type int.
I'm unable to locate specifically where this conversion is taking place and what could be a possible fix.
EDIT: Located problem in cptcode column which has alphanumeric entries. However, changing date ranges in WHERE clause gives results for some dates and not for others.
when you use
"ClientVisit"."cptcode" = 90791
the data type of 90791 will be integer. If you replace it with
"ClientVisit"."cptcode" = '90791'
both sides of the equation will be characters. You can also do something like:
"ClientVisit"."cptcode" = CAST(90791 AS VARCHAR(20))
The reasons for your problem is that SQL Server will do an implicit conversion. In this case to integer as Integer has a higher Data Type Precedence than (n)(var)char data types.
Of course I do not know your data but I guess there are data ranges where there is only numeric values for cptcode. So your code will work for them but not if you hit something like e.g. H006
Hope that helps ;-)
Comment out all the colums in the select segment and start ucommenting them one by one while executing the select each time. When you uncomment the problematic line, you'll find the source of the error.
BTW: I'm guessing the problem is in "ClientVisit"."cptcode" = 90791.

Conversion failed when converting the nvarchar value '29449,29446,29450,29534' to data type int

I am create a stored procedure in SQL and I get the following error when I execute the query:
Conversion failed when converting the nvarchar value '11021,78542,12456,24521' to data type int.
Any idea why?
SELECT
A.Art_ID, A.Title
FROM
Art A
INNER JOIN
Iss I ON A.Iss_ID = I.Iss_ID
INNER JOIN
Sections S ON A.Section_ID = S.Section_ID
INNER JOIN
iPadSec IPS ON A.Sec_ID = IPS.Sec_ID
WHERE
A.Art_ID IN (SELECT CAST(Art_IDs AS int) /***error happens here***/
FROM Book_Art b
WHERE Sub_ID = 68)
AND I.Iss > dateadd(month, -13, getdate())
AND A.Active = 1
AND IPS.Active = 1
AND A.PDate <= getdate()
ORDER BY
PDate DESC, Art_ID DESC;
You cannot do what you want using in. First, it is a really bad idea to store ids in lists in strings. You should be using a junction table.
That said, sometimes this is necessary. You can rewrite this line of code as:
EXISTS (SELECT 1 /***error happens here***/
FROM Book_Art b
WHERE Sub_ID = 68 AND
',' + Art_IDs + ',' LIKE '%,' + cast(A.Art_ID as varchar(255)) + ',%'
)
However, the performance would generally be on the lousy side and there is little prospect of speeding this up without fixing the data structure. Use a junction table instead of a string to store lists.
Adding this line works for me.
declare #ids varchar(1000)
select #ids = art_ids from book_art where sub_id = #Sub_ID
EXECUTE ( 'SELECT A.Art_ID, A.Title'
+ ' FROM Art A'
+ ' INNER JOIN Iss I ON A.Iss_ID = I.Iss_ID'
+ ' INNER JOIN Sections S ON A.Section_ID = S.Section_ID'
+ ' INNER JOIN iPadSec IPS ON A.Sec_ID = IPS.Sec_ID'
+ ' WHERE A.Art_ID IN (' + #ids + ')'
+ ' AND I.Iss > dateadd(month, -13, getdate())'
+ ' AND A.Active = 1'
+ ' AND IPS.Active = 1'
+ ' AND A.PDate <= getdate()'
+ ' ORDER BY PDate DESC,'
+ ' Art_ID DESC;'
)
END
Thank you all for your help :)