Stored Procedure takes 30 seconds but Report takes 10 minutes - sql-server-2005

I am using SQL Server 2005 and I have been trying to fix this for a while now. I have tried the parameter sniffing and with recompile but neither have worked.
When executing the stored procedure, it takes 30 seconds and the report takes around 10 minutes. I'm not going to post the whole stored procedure because it is 300 lines, but I'll post the first bit of it. I am lost, and so are my coworkers as to why this is so slow.
ALTER PROCEDURE [dbo].[sp_PermitAllData]
#datey datetime
with recompile
AS
BEGIN
Set NoCount On
Declare #date datetime
Set #date = #datey
--Permit11
select
MDate,
isnull(NumbBreaker, 0) NumbBreaker,
isnull(Steel20T, 0) Steel20T,
isnull(Steel9T, 0) Steel9T,
isnull(Ductile, 0) Ductile,
isnull(IMF,0) IMF,
isnull((select sum(NumbBreaker) from Permit p
where MDate>= dateadd(month,-11,Permit.MDate) and MDate<= dateadd(month,-1,Permit.MDate)),0) NumbBreaker11,
isnull((select sum(Steel20T) from Permit p
where MDate>= dateadd(month,-11,Permit.MDate) and MDate<=dateadd(month,-1,Permit.MDate) and MDate>='10/1/2008'),0) Steel20T11,
isnull((select sum(Steel9T) from Permit p where MDate>= dateadd(month,-11,Permit.MDate) and MDate<= dateadd(month,-1,Permit.MDate)and MDate>='10/1/2008'),0) Steel9T11,
isnull((select sum(Ductile) from Permit p where MDate>= dateadd(month,-11,Permit.MDate) and MDate<= dateadd(month,-1,Permit.MDate)),0) Ductile11,
isnull((select sum(IMF) from Permit p where MDate>= dateadd(month,-11,Permit.MDate) and MDate<= dateadd(month,-1,Permit.MDate)),0) IMF11
Into #Permit11
from
Permit
where
MDate between dateadd(month,-2,#date) AND #date
--270
SELECT dateadd(month,datediff(month,0,fdate),0) Month,-1*SUM(fqty) 'A270',
(select -1*sum(fqty)
from M2MDATA01.dbo.intran t INNER JOIN
M2MDATA01.dbo.inmast m ON t.fpartno = m.fpartno INNER JOIN
M2MDATA01.dbo.jomast j ON t.ftojob = j.fjobno INNER JOIN
M2MDATA01.dbo.inmast m2 on j.fpartno=m2.fpartno and j.fpartrev=m2.frev and j.fac=m2.fac
--PEntries e ON j.fpartno = e.Sand
where dateadd(month,datediff(month,0,t.fdate),0) BETWEEN dateadd(month,-11,dateadd(month,datediff(month,0,intran.fdate),0)) and dateadd(month,-1,dateadd(month,datediff(month,0,intran.fdate),0)) AND
fdate>='6/1/2008' AND
t.ftype = 'I' AND
(m.fdescript in('TECHNISET 6435 PART 2 339749','TECHNISET F6000 PART 1 347944') OR m.fdescript LIKE 'ACTIVATOR%') AND
m2.fcusrchr2='270') 'A27011'
Into #270
FROM M2MDATA01.dbo.intran intran INNER JOIN
M2MDATA01.dbo.inmast inmast ON intran.fpartno = inmast.fpartno INNER JOIN
M2MDATA01.dbo.jomast jomast ON intran.ftojob = jomast.fjobno INNER JOIN
M2MDATA01.dbo.inmast m2 on jomast.fpartno=m2.fpartno and jomast.fpartrev=m2.frev and jomast.fac=m2.fac
-- PEntries ON jomast.fpartno = PEntries.Sand
WHERE dateadd(month,datediff(month,0,fdate),0) BETWEEN dateadd(month,-2,#date) and #date AND
intran.ftype = 'I' AND
(inmast.fdescript in('TECHNISET 6435 PART 2 339749','TECHNISET F6000 PART 1 347944') OR inmast.fdescript LIKE 'ACTIVATOR%') AND
m2.fcusrchr2='270'
GROUP BY dateadd(month,datediff(month,0,fdate),0), dateadd(month,-11,dateadd(month,datediff(month,0,intran.fdate),0)), dateadd(month,-1,dateadd(month,datediff(month,0,intran.fdate),0))
ORDER BY dateadd(month,datediff(month,0,fdate),0)

Related

Returning values from different rows in a stored procedure as different values

I have a stored procedure:
`SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [ebs].[DB_Task_ONEYCRPRaport]
--#startDate DATE,
--#endDate DATE
AS
BEGIN
SELECT DISTINCT
CAST(A.ExternalMerchantId as varchar) "Merchant_guid", -- ok
CAST(C.CreatedOn AS DATE) "Purchase_date", --ok
CAST(C.CreatedOn AS TIME) "Purchase_hour", --ok
C.ContractNo "Funding_reference",--ok
APP.OrderNo "External_reference", --ok
A.CustomerInternalId "Customer_external_code",--ok
CASE WHEN I.TotalAmountToPay = 0 THEN '-' ELSE '+' END "Total_amount_symbol",--ok
CASE WHEN I.TotalAmountToPay = 0 THEN I.TotalAmountToRecover ELSE I.TotalAmountToPay END "Total_amount"
from ebs.Account as A
JOIN ebs.FTOS_CB_Contract AS C ON A.Accountid = C.CustomerId
JOIN ebs.FTOS_CB_BankAccount AS BA ON BA.FTOS_CB_BankAccountid = C.MainBankAccountId
JOIN ebs.FTOS_CB_BankAccountOperation AS BAO ON BAO.BankAccountId = BA.FTOS_CB_BankAccountid
JOIN Ebs.FTOS_CMB_Currency AS CU ON CU.FTOS_CMB_Currencyid = C.CurrencyId
JOIN ebs.FTOS_TPM_Invoice AS I ON I.BankAccountId = BA.FTOS_CB_BankAccountid
JOIN ebs.FTOS_TPM_InvoiceDetail AS ID ON ID.InvoiceId = I.FTOS_TPM_Invoiceid
JOIN ebs.FTOS_BNKAP_Application AS APP ON APP.ContractId = ID.ContractId
JOIN ebs.FTOS_CB_Payment AS P ON I.FTOS_TPM_Invoiceid=P.InvoiceId
JOIN ebs.FTOS_BP_BankingProduct AS BP ON BP.FTOS_BP_BankingProductid=(SELECT CO.ProductId from ebs.FTOS_CB_Contract AS CO where CO.FTOS_CB_Contractid = ID.ContractId)
JOIN ebs.FTOS_TPM_PreInvoiceDetail AS PID ON PID.ContractId = C.FTOS_CB_Contractid
left JOIN ebs.FTOS_ONEY_ICE_Repayment as R ON P.PaymentNo = R.PaymentNo
left JOIN ebs.FTOS_ONEY_ICE_Repayment_Details AS RD ON RD.FTOS_ONEY_ICE_Repaymentid = R.FTOS_ONEY_ICE_Repaymentid -- detalii plati efectuate
left JOIN ebs.FTOS_ONEY_ICE_Libra_ReceivedPayments AS RP ON RP.FTOS_CB_Contractid = C.FTOS_CB_Contractid --and DATEPART(week, C.CreatedOn) = DATEPART(week, GETDATE()) take current week results
END`
I have another table where commissions are stored, the problem is I don't know how to select them in my stored procedure if they are on separate columns:
Here is the test query:
SELECT PID.*
FROM [ebs].[FTOS_TPM_PreInvoiceDetail] as PID
WHERE PID.Name = 'name'
Basically for this example I want those values 20 and 5 to be selected in my stored procedures as two different values, how can I achieve that?
I tried created another stored procedure, but I think is a very bad idea.

How to extract people who have NOT transacted since the last visit

I'm supposed to be reaching users who have NOT transacted since the configured days. I'm capturing users who HAVE transacted within X days. Not quite sure how I should get the user who have NOT transacted since the last the visit
CREATE PROCEDURE [ContentPush].[GetLastVisitDateTransaction]
#DaysSinceLastVisit INT,
#TenantID UNIQUEIDENTIFIER
AS
BEGIN
DECLARE #ReturnJson NVARCHAR(MAX)
SET #ReturnJson = (
SELECT DISTINCT [D].[UserID]
FROM [dbo].[UserInfo] D WITH(NOLOCK)
INNER JOIN [Txn].[Txn] T WITH (NOLOCK) ON [D].[UserID]=[T].[UserID]
INNER JOIN [Txn].[TxnPaymentResponse] TPR WITH(NOLOCK) ON [T].[TxnID] = [TPR].[TxnID]
WHERE
[TPR].[PaymentResponseType] = 'FINAL'
AND [TPR].[PaymentResultCode] = 'approved'
AND [T].[AppTenantID] = #TenantID
AND
(
[T].[TransactionDateTime]>= DATEADD(DD, - #DaysSinceLastVisit, GETUTCDATE())
)
AND D.IsActive = 1
FOR JSON PATH)
SELECT #ReturnJson
END
You can start from the users table, and use not exists to filter out those that had a transaction within the period.
SELECT [D].[UserID]
FROM [dbo].[UserInfo] D
WHERE NOT EXISTS (
SELECT 1
FROM [Txn].[Txn] T
INNER JOIN [Txn].[TxnPaymentResponse] TPR ON [T].[TxnID] = [TPR].[TxnID]
WHERE
[D].[UserID]=[T].[UserID]
AND [TPR].[PaymentResponseType] = 'FINAL'
AND [TPR].[PaymentResultCode] = 'approved'
AND [T].[AppTenantID] = #TenantID
AND [T].[TransactionDateTime]>= DATEADD(DD, - #DaysSinceLastVisit, GETUTCDATE())
AND D.IsActive = 1
)

SQL query running slowly - parameter sniffing

I have a simple query where I return a list of orders by date range. This query is used in a report which feeds it parameters(Site, From Date, and To Date).
ALTER PROCEDURE [dbo].[Z_N_ECOM_ORDER_STATUS_DATERANGE]
#Site VARCHAR(5),
#FromDate DATETIME,
#ToDate DATETIME
AS
BEGIN
SET NOCOUNT ON;
SELECT
o.Company_Code,
o.Division_Code,
o.Control_Number,
RTRIM(o.Customer_Purchase_Order_Number) AS Shopify_Num,
CASE
WHEN p.PickTicket_Number IS NULL
THEN i.PickTicket_Number
ELSE p.PickTicket_Number
END PickTicket_Number,
i.Invoice_Number,
o.Date_Entered,
CASE
WHEN ph.packslip IS NULL AND i.invoice_number IS NULL
AND P.pickticket_number IS NULL
THEN 'Cancelled'
WHEN ph.packslip IS NULL AND i.invoice_number IS NULL
AND DATEADD(minute, 90, o.date_entered) > CURRENT_TIMESTAMP
THEN 'Not Entered Yet'
WHEN ph.packslip IS NULL
THEN 'SHIPPED & UPLOADED'
ELSE RTRIM (z.status)
END Accellos_Status,
b.UPS_Tracking_Number Tracking_Number
FROM
[JMNYC-AMTDB].[AMTPLUS].[dbo].Orders o (nolock)
LEFT JOIN
[JMNYC-AMTDB].[AMTPLUS].[dbo].PickTickets p (nolock) ON o.Company_Code = p.Company_Code
AND o.Division_Code = p.Division_Code
AND o.Control_Number = p.Control_Number
LEFT JOIN
[JMNYC-AMTDB].[AMTPLUS].[dbo].Invoices i (nolock) ON o.Company_Code = i.Company_Code
AND o.Division_Code = i.Division_Code
AND o.Control_Number = i.Control_Number
LEFT JOIN
[JMNYC-AMTDB].[AMTPLUS].[dbo].box b (nolock) ON o.Company_Code = b.Company_Code
AND o.Division_Code = b.Division_Code
AND i.PickTicket_Number = b.PickTicket_Number
LEFT JOIN
pickhead ph (nolock) ON p.PickTicket_Number = ph.packslip
LEFT JOIN
Z_Status z (nolock) ON ph.PROCSTEP = z.procstep
WHERE
o.Company_Code = LEFT(#Site, 2)
AND o.Division_Code = RIGHT(#Site, 3)
AND o.Customer_Number = 'ecom2x'
AND o.Date_Entered BETWEEN #FromDate AND DATEADD(dayofyear, 1, #ToDate)
ORDER BY
o.date_entered DESC
END
The problem with this query is that it takes way too long and the problem lines are
WHERE
o.Company_Code = LEFT(#Site, 2)
AND o.Division_Code = RIGHT(#Site, 3)
The format of the variable site is something like '09001' or '03001' where the left side is the company and the right side is the division
Because when I run this query with hard-coded values, it runs pretty much instantaneously. When I use the parameters, it takes minutes.
So I looked it up and I discovered about parameter sniffing. So I added the following line after the begin statement.
DECLARE #LocalSite VARCHAR(5) = CAST(#Site AS VARCHAR(5))
However, it still runs extremely slow.
My new where statement would be
WHERE
o.Customer_Number = 'ecom2x'
AND o.Date_Entered BETWEEN #FromDate AND DATEADD(dayofyear, 1, #ToDate)
AND ((#LocalSite = '00000') OR (O.Company_Code = LEFT(#LocalSite, 2) AND O.Division_Code = RIGHT(#LocalSite, 3)))
order by o.date_entered desc*
I also want the user to have the functionality of selecting all sites which will make the site variable be '00000' and thus it shouldn't run the company/division code check. This current where statement makes the query run very slow.
Does anyone know what I am doing wrong?
Can you try to avoid using LEFT() and RIGHT() by declaring few variables and assigning values to those variables and then using them in the SELECT statement?
a hint OPTIMIZED FOR UNKNOWN to avoid parameter sniffing:
option (OPTIMIZE FOR (#p1 UNKNOWN, #p2 UNKNOWN))
Where p1 and p2 those two variables mentioned above
I also want the user to have the functionality of selecting all sites
which will make the site variable be '00000' and thus it shouldn't run
the company/division code check. This current where statement makes
the query run very slow.
This can be optimized by replacing current SELECT with IF statement that uses two SELECTs. If value is 00000 just avoid to check on company and division, else run the same select but with those extra checks
Another striking thing is querying linked server objects with further join to local tables. Consider to split this into a separate step, for instance by storing data in temporary table (not a table variable!) as intermediate result. Then temp table to be joined with local objects. This can improve accuracy of query plan because of better estimates.
Did you try taking left and right values of#site parameter in two different variables and using those variables in SP.
For eg.
Declare #compcode as varchar(2)
Declare #divcode as varchar(3)
Set #compcode=LEFT(#Site, 2)
Set #divcode=RIGHT(#Site, 3)
Your where condition
WHERE
o.Company_Code = #compcode
AND o.Division_Code = #divcode

Grouping and Pipe delimiter (Newbee) SQL Server 2008 R2

I created this script:
SELECT Distinct
rtrim(Insurances.EligibilityPayorNumber) as InsurancePayorCode
, rtrim(ContractFacilityProviders.NPI) as ProviderID
, rtrim(PatientInsuranceProfiles.Insurance1PolicyNumber) as SubscriberInsuranceID
, rtrim(PatientInsuranceProfiles.Insurance1PolicyGroupNumber) as SubscriberGroupNumber
, rtrim(PatientDemographics.firstname) as SubscriberFirstName
, rtrim(PatientDemographics.MiddleInitial) as SubscriberMiddleInitial
, rtrim(PatientDemographics.Lastname) as SubscriberLastName
, rtrim(PatientDemographics.sex) as Gender
, rtrim(PatientDemographics.DateofBirth) as DOB
, ScheduleEntry.ScheduleDate as DateofService
, PatientDemographics.AccountNumber as TrackingID
FROM ScheduleEntry
LEFT JOIN PatientDemographics
ON ScheduleEntry.PatientAccount = PatientDemographics.AccountNumber
LEFT JOIN Reasons
ON ScheduleEntry.ReasonCode = Reasons.ReasonCode
LEFT JOIN Providers
ON ScheduleEntry.ResourceCode = Providers.MedStarProviderIdentifier
LEFT JOIN Facilities
ON ScheduleEntry.FacilityCode = Facilities.MedStarFacilityIdentifier
LEFT JOIN [john-pc\sqlexpress].[Global].[dbo].[PatientStatuses] TAB2
on ScheduleEntry.PatientStatus = TAB2.PatientStatusCode
LEFT JOIN AddedResource
ON ScheduleEntry.ResourceCode = AddedResource.AddedResourceCode
LEFT JOIN Caregiver
ON ScheduleEntry.ResourceCode = Caregiver.CaregiverCode
LEFT JOIN ReasonScripts
ON ScheduleEntry.ReasonCode = ReasonScripts.Reasoncode
LEFT JOIN Scripts
on Reasonscripts.Scriptcode = Scripts.ScriptCode
LEFT JOIN PatientInsuranceProfiles
ON ScheduleEntry.PatientAccount = PatientInsuranceProfiles.PatientAccountNumber
LEFT JOIN Insurances
ON PatientInsuranceProfiles.Insurance1Mnemonic = Insurances.Mnemonic
LEFT JOIN ContractFacilityProviders
ON PatientDemographics.PrimaryPhysician = ContractFacilityProviders.ProviderIdentifier
WHERE ScheduleEntry.ScheduleDate >= getdate()
and ScheduleEntry.ScheduleDate <= getDate() +1
and PatientinsuranceProfiles.ActiveFlag = 1
and EligibilityPayorNumber > = 1
ORDER By SCHEDULEDATE
I would like to do a few things and can't figure out how:
The DOB of is returning a value of Nov 6 1939 12:00AM and I need it to be mmddyyyy.
I need to group by TrackingID which can be the same on multiple lines. The data would always be the same.
What can I add to the script so when I run it as a SQL it will save as pipe delimited?
For your DOB, this can be used in your SELECT. Note, it will be of type VARCHAR and no longer a datetime.
SELECT REPLACE(CONVERT(VARCHAR(10),PatientDemographics.DateofBirth,101),'/','') AS DOB
I notice your RTRIM and they could be necessary for your output, but this is just some free knowledge on SQL server and trailing spaces for comparisions:
https://support.microsoft.com/en-us/kb/316626
DECLARE #s1 varchar(10)
DECLARE #s2 varchar(10)
set #s1 = 'nospace'
set #s2 = '3spaces '
select len(#s1), len(#s2)

Slow TSQL query with nested selects

I have written a query, but appears to run quite slowly in our live environment.
The query contains nested select statements which I believe to slow down execution.
Does anyone have any tips of how I could re-write the query to improve the execution speed.
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '20140101'
SET #EndDate = '20140101'
SELECT a.applicationid,
a.ourreference,
(SELECT MAX(e.CreateDateTime) FROM tblEmail AS e WHERE( e.ApplicationID = a.ApplicationID) AND (ISNULL(e.StandardEmailID,0) <> 3)) AS 'LastEmail',
(SELECT MAX(l.CreateDateTime) FROM tblLetter AS l WHERE l.ApplicationID = a.ApplicationID AND l.ExternalDocumentTypeID IS NULL) AS 'LastInternalLetter',
(SELECT MAX(l.CreateDateTime) FROM tblLetter AS l WHERE l.ApplicationID = a.ApplicationID AND l.ExternalDocumentTypeID IS NOT NULL) AS 'LastExternalLetter'
INTO #Temp
FROM tblapplication AS a
WHERE (a.LogDate BETWEEN #StartDate AND #EndDate + '23:59:59')
AND (a.BusinessSourceID NOT IN (11, 16))
AND (a.ApplicationStatusID = 100)
SELECT *
FROM #Temp AS tem
WHERE ((LastEmail < LastExternalLetter) AND (LastInternalLetter < LastExternalLetter))
Cheers everyone
edit- Sorry I should say what the query is for. I am trying to see if our customers have sent us a letter and we haven't responded to them with a letter/email
select *
from
(
Select a.applicationId, a.ourreference,
max(e.CreateDateTime) LastEmail,
max(li.CreateDateTime) LastInternalLetter,
max(le.CreateDateTime) LastExternalLetter
from tblApplication a
left outer join tblEmail e on e.ApplicationID = a.ApplicationID
left outer join tblLetter li on li.ApplicationId = a.ApplicationId
left outer join tblLetter le on le.ApplicationId = a.ApplicationId
WHERE (a.LogDate BETWEEN #StartDate AND #EndDate + '23:59:59')
AND (a.BusinessSourceID NOT IN (11, 16))
AND (a.ApplicationStatusID = 100)
and (e.StandardEmailID <> 3 or e.StandardEmailId is null)
group by a.ApplicationId, a.OurReference
)x
WHERE ((LastEmail < LastExternalLetter) AND (LastInternalLetter < LastExternalLetter))
This gets rid of the temporary table. Remember, with SQL wherever you have a Table you can substitute a query (in Selects anyway). This should make it a bit more efficient, but you want to look at the Query Plans and see what's holding it up.
Cheers -