I have some nested procedures which show low performance. In order to find bottle neck I inserted into t-sql code some debug marks for measure performance of chunks of code which I suspect in low performance. This debug marks look like:
select #start_point = GETDATE() -- start measuring point
---
open #session_license_fee_cur -- suspected chunk of code
---
select #end_point = GETDATE()-- end measuring point
select #duration = datediff(ms, #start_point, #end_point)
select #log_info_total = 'Opening cursor license_fee (bills_supp_create_license_fee) (#class_id = ' + cast(#class_id as nvarchar) + ')';
exec bills_supp_save_calculation_log #duration, #log_info_total, #house_id, #account_id, #log_level -- procedure for creating log (simple insert into log table pes_bl_bills_calculation_log_total)
After running the procedures I run query from pes_bl_bills_calculation_log_total table to find lowest performance code. It looks like this
set #session_license_fee_cur = cursor static for
select activity_id
, addendum_id
, service_id
, active_from
, active_to
from dbo.bills_supp_get_activate_license_fee_for_sessions_by_house(#active_from, #active_to, #house_id)
select #start_point = GETDATE()
---
open #session_license_fee_cur
---
select #end_point = GETDATE()
select #duration = datediff(ms, #start_point, #end_point)
select #log_info_total = 'Opening cursor license_fee (bills_supp_create_license_fee) (#class_id = ' + cast(#class_id as nvarchar) + ')';
exec bills_supp_save_calculation_log #duration, #log_info_total, #house_id, #account_id, #log_level
In other words open #session_license_fee_cur works very slowly (about 501980 ms).
I’m trying to run this chunk of code with given parameters in SQL Server Management Studio in order to look on query plan and try to optimize it. I run it like this
declare #active_from date = '01.03.2014'
declare #active_to date = '01.04.2014'
declare #house_id integer = 11927
select activity_id
, addendum_id
, service_id
, active_from
, active_to
from dbo.bills_supp_get_activate_license_fee_for_sessions_by_house(#active_from, #active_to, #house_id)
But it works very fast (returns 3000 records in about 0(zero) seconds).
What the difference in opening cursor in procedure
open #session_license_fee_cur
And running it in SQL Server Management Studio?
declare #active_from date = '01.03.2014'
declare #active_to date = '01.04.2014'
declare #house_id integer = 11927
select activity_id
, addendum_id
, service_id
, active_from
, active_to
from dbo.bills_supp_get_activate_license_fee_for_sessions_by_house(#active_from, #active_to, #house_id)
Where is my bottle neck?
Find Top 5 expensive Queries from a Read IO perspective
http://www.sqlservercentral.com/scripts/DMVs/102045/
Related
I have a Data Script, It executed about 3 minutes in a database, but when I try to execute that on another database (Different Servers) It takes more than 4 hours so I kill it.
when I get Server state the query is in wait (CXCONSUMER type) from first second. and Who_2 shows 25 Records with Cmd = OPEN CURSOR and 24 Status = suspended and 1 status = runnable.
How can I turn off parallelism in sql and run my script?
declare #PolicyId int, #ElhNo int, #Y int, #CapitalChangeZarib decimal(38, 10), #PrmChangeZarib decimal(38, 10)
declare PayPeriodCursor cursor local for
select Distinct CurrBNVer.PolicyId, CurrBNVer.ElhNo, CurrBNVer.Y, CurrBNVer.CapitalChangeZarib, CurrBNVer.PrmChangeZarib
from v_Table1 CurrBNVer
left join v_Table1 PreBNVer on CurrBNVer.PolicyId = PreBNVer.PolicyId and
CurrBNVer.ElhNo - 1 = PreBNVer.ElhNo
order by CurrBNVer.PolicyId, CurrBNVer.ElhNo
open PayPeriodCursor
fetch next from PayPeriodCursor into #PolicyId, #ElhNo, #Y, #CapitalChangeZarib, #PrmChangeZarib
while ##FETCH_STATUS = 0
begin
update Table2
set Filed1= 0.01 * #CapitalChangeZarib,
Filed2= 0.01 * #PrmChangeZarib
where PolicyId = #PolicyId and
ElhNo >= #ElhNo and
Year >= ISNULL(#Y, 0)
fetch next from PayPeriodCursor into #PolicyId, #ElhNo, #Y, #CapitalChangeZarib, #PrmChangeZarib
end
close PayPeriodCursor
deallocate PayPeriodCursor
go
Finaly I found what is the problem. I was using a view that includes a select * from table1
Somebody had been added a nullable column to table1 before I run my script. So I needed to Refresh the view before using that. But I didnt know about that adding field. So one of my important fields (used in my join) returned null for entire table(the field is not nullable but the view returns value of some other field instead). So it was only the join which took that long because of null values. All I did is refreshing the view and problem solved.
I'm currently creating stored procedures on the SQL server by using linked servers, "OPENQUERY" statements, and temporary tables. My goal is to have one source that will be consumed by multiple third party sources so that everyone is viewing the same data.
Where I'm running into my problem is that some instances need a specific where clause where others don't need this where clause. Is there a way to Declare this where clause equal to something that nullifies that where clause if it's blank but use the where clause if it's populated? I've tried making the parameter equal to "%", "%?%", etc. but nothing seems to work.
I would also like to point out that this is an Oracle Database that I'm pulling from on a Microsoft SQL Server. My code is below and the parameter #WINS is what I'm trying to nullify if left blank:
DECLARE #query_start DATETIME;
DECLARE #query_end DATETIME;
DECLARE #query_wins NVARCHAR(MAX);
SET #query_start = '7/1/2020';
SET #query_end = '7/15/2020';
SET #query_wins = 'F6666';
DECLARE #START_DATE NVARCHAR(MAX) = CONVERT(VARCHAR,#query_start,105)
DECLARE #END_DATE NVARCHAR(MAX) = CONVERT(VARCHAR,#query_end,105)
DECLARE #WINS NVARCHAR(MAX) = #query_wins
DECLARE #SqlCommand NVARCHAR(MAX) =
'
SELECT
*
FROM
OPENQUERY
(
PDB,
'' SELECT
T1.WELL_NUM
, D2.WELL_NAME
, T1.DAILY_RDG_DATE
, T1.GROSS_OIL_BBLS
, T1.GROSS_GAS_MCF
, T1.GROSS_WTR_BBLS
, T1.TUBING_PRESS
, T1.CASING_PRESS
, T1.GAS_LINE_PRESS
, T1.CHOKE,T1.CHOKE_SIZE AS CHOKE2
, T2.GAS_PROD_FORECAST
, T2.OIL_PROD_FORECAST
, T2.WTR_PROD_FORECAST
FROM
(PDB.T003031 T1
INNER JOIN WINS.DW_ANORM_ROWL#WINP_DBLINK.WORLD D2
ON T1.WELL_NUM = D2.WINS_NO
AND T1.CMPL_NUM = D2.CMPL_NO)
LEFT JOIN PDB.T000057 T2 ON T1.WELL_NUM = T2.WELL_NUM
AND T1.CMPL_NUM = T2.CMPL_NUM
AND T2.FORECAST_DATE=T1.DAILY_RDG_DATE
WHERE
D2.HOLE_DIRECTION = ''''HORIZONTAL''''
AND D2.ASSET_GROUP = ''''Powder River Basin''''
AND T1.DAILY_RDG_DATE > TO_DATE(''''' + CONVERT(VARCHAR,#START_DATE,105) + ''''',''''DD-MM-YYYY'''') - 2
AND T1.DAILY_RDG_DATE < TO_DATE(''''' + CONVERT(VARCHAR,#END_DATE,105) + ''''',''''DD-MM-YYYY'''')
AND D2.OPER_NON_OPER = ''''OPERATED''''
AND T1.WELL_NUM = ''''' + #WINS + '''''
''
)
'
PRINT #SqlCommand
DROP TABLE IF EXISTS #temp
CREATE TABLE #temp (
WELL_NUM NVARCHAR(MAX)
, WELL_NAME NVARCHAR(MAX)
, DAILY_RDG_DATE DATETIME
, GROSS_OIL_BBLS FLOAT
, GROSS_GAS_MCF FLOAT
, GROSS_WTR_BBLS FLOAT
, TUBING_PRESS FLOAT
, CASING_PRESS FLOAT
, GAS_LINE_PRESS FLOAT
, CHOKE1 FLOAT
, CHOKE2 FLOAT
, GAS_PROD_FORECAST FLOAT
, OIL_PROD_FORECAST FLOAT
, WTR_PROD_FORECAST FLOAT
)
PRINT #SqlCommand
INSERT INTO #temp
EXEC sp_ExecuteSQL #SqlCommand
SELECT
WELL_NUM
, WELL_NAME
, DAILY_RDG_DATE
, ISNULL(GROSS_OIL_BBLS,0) AS 'GROSS_OIL_BBLS'
, ISNULL(GROSS_GAS_MCF,0) AS 'GROSS_GAS_MCF'
, ISNULL(GROSS_WTR_BBLS,0) AS 'GROSS_WTR_BBLS'
, ISNULL(TUBING_PRESS,0) AS 'TUBING_PRESS'
, ISNULL(CASING_PRESS,0) AS 'CASING_PRESS'
, ISNULL(GAS_LINE_PRESS,0) AS 'GAS_LINE_PRESS'
, ISNULL(CHOKE1,0) AS 'CHOKE1'
, ISNULL(CHOKE2,0) AS 'CHOKE2'
, ISNULL(GAS_PROD_FORECAST,0) AS 'CHOKE2'
, ISNULL(OIL_PROD_FORECAST,0) AS 'OIL_PROD_FORECAST'
, ISNULL(WTR_PROD_FORECAST,0) AS 'WTR_PROD_FORECAST'
FROM #temp
ORDER BY
DAILY_RDG_DATE ASC
DROP TABLE IF EXISTS #temp
You can set up an optional parameter like this in SQL Server
WHERE ISNULL(#parameter,column_name) = column_name
Ok, if I abstract your problem properly, you're trying to apply different filtering logic based on the value of a field.
You might consider using a cursor for this, iterate over the table and apply if / else as needed.
Do you really need to compose the SQL command as a string? Maybe you're only doing that to share the code here, hopefully?
Anyway, It sounds like this would work for you:
WHERE (T1.WELL_NUM = #WINS OR #WINS IS NULL) AND
...other conditions...
I created a database with NBA player statistics just to practice SQL and SSRS. I am new to working with stored procedures, but I created the following procedure that should (I think) allow me to specify the team and number of minutes.
CREATE PROCEDURE extrapstats
--Declare variables for the team and the amount of minutes to use in --calculations
#team NCHAR OUTPUT,
#minutes DECIMAL OUTPUT
AS
BEGIN
SELECT p.Fname + ' ' + p.Lname AS Player_Name,
p.Position,
--Creates averages based on the number of minutes per game specified in #minutes
(SUM(plg.PTS)/SUM(plg.MP))*#minutes AS PTS,
(SUM(plg.TRB)/SUM(plg.MP))*#minutes AS TRB,
(SUM(plg.AST)/SUM(plg.MP))*#minutes AS AST,
(SUM(plg.BLK)/SUM(plg.MP))*#minutes AS BLK,
(SUM(plg.STL)/SUM(plg.MP))*#minutes AS STL,
(SUM(plg.TOV)/SUM(plg.MP))*#minutes AS TOV,
(SUM(plg.FT)/SUM(plg.MP))*#minutes AS FTs,
SUM(plg.FT)/SUM(plg.FTA) AS FT_Percentage,
(SUM(plg.FG)/SUM(plg.MP))*#minutes AS FGs,
SUM(FG)/SUM(FGA) as Field_Percentage,
(SUM(plg.[3P])/SUM(plg.MP))*#minutes AS Threes,
SUM([3P])/SUM([3PA]) AS Three_Point_Percentage
FROM PlayerGameLog plg
--Joins the Players and PlayerGameLog tables
INNER JOIN Players p
ON p.PlayerID = plg.PlayerID
AND TeamID = #team
GROUP BY p.Fname, p.Lname, p.Position, p.TeamID
ORDER BY PTS DESC
END;
I then tried to use the SP by executing the query below:
DECLARE #team NCHAR,
#minutes DECIMAL
EXECUTE extrapstats #team = 'OKC', #minutes = 35
SELECT *
When I do that, I encounter this message:
Msg 263, Level 16, State 1, Line 5
Must specify table to select from.
I've tried different variations of this, but nothing has worked. I thought the SP specified the tables from which to select the data.
Any ideas?
Declaring the stored procedure parameters with OUTPUT clause means the values will be returned by the stored procedure to the calling function. However you are using them as input parameters, please remove the OUTPUT clause from both input parameters and try.
Also remove the SELECT * in your execute statement, it is not required, the stored procedure will return the data as it has the select statement.
I have two tables one of them have historical(cdr_hist) data other table have data from today(cdr_stage). My script must run every 30 minutes and calculate data from last 4 hours but every night at 12 all data move at cdr_hist.
The question is how I can switch and take data from history table when script run at 12:00 because cdr_stage is empty...
I tried this:
IF OBJECT_ID ('[**CDR_Stage**]') IS NOT NULL
BEGIN
Select.....
From **CDR_Stage**
END
ELSE
Select.....
From **CDR_Hist**
END
But its not work correctly...
Any ideas??
No need for IFs , that can be done with pure sql using UNION and NOT EXISTS() :
SELECT * FROM CDR_Stage
UNION ALL
SELECT * FROM CDR_Hist
WHERE NOT EXISTS(SELECT 1 FROM CDR_Stage) -- Second select will return data only if first one won't .
You need to check the record existence instead of table existence
IF EXISTS (SELECT 1
FROM CDR_Stage)
SELECT *
FROM CDR_Stage
ELSE
SELECT *
FROM CDR_Hist
Or Dynamic Sql
DECLARE #sql VARCHAR(4000)
SET #sql = 'select * from '
+ CASE
WHEN EXISTS (SELECT 1
FROM CDR_Stage) THEN 'CDR_Stage'
ELSE 'CDR_Hist'
END
EXEC (#sql)
I have this query in a stored procedure:
SELECT
*,
ISNULL(dbo.ReturnShortageByItemCodeLinePackage(LineId, TestPackageId, MaterialDescriptionId), 0) AS Shortage
FROM
dbo.ViewMTO
I am using a function inside the query to calculate an integer value as you can see here :
ALTER FUNCTION [dbo].[ReturnShortageByItemCodeLinePackage]
(#lineId int,#testpackId int, #MaterialDescriptionId int)
RETURNS float
AS
BEGIN
DECLARE #shortageQuantity float
DECLARE #MIVQuantity float
DECLARE #totalQuantity float
DECLARE #spoolQuantity float
DECLARE #ExistInSiteQuantity float
DECLARE #BeforeDoneQuantity float
SELECT
#totalQuantity = Quantity,
#spoolQuantity = QuantitySpool,
#ExistInSiteQuantity = QuantityExistInSite,
#BeforeDoneQuantity = QuantityBeforeDone
FROM
[SPMS2].[dbo].Materials
WHERE
LineId = #lineId
AND TestPackageId = #testpackId
AND MaterialDescriptionId = #MaterialDescriptionId
SELECT
#MIVQuantity = SUM(QuantityDeliver)
FROM
MaterialIssueVoucherDetails miv
JOIN
MaterialRequestContractorDetails mrc ON miv.MaterialRequestContractorDetailId = mrc.Id
WHERE
TestPackageId = #testpackId
AND LineId = #lineId
AND miv.MaterialDescriptionId = #MaterialDescriptionId
IF #MIVQuantity IS NULL
BEGIN
SET #MIVQuantity = 0
END
SET #shortageQuantity = #totalQuantity - (#BeforeDoneQuantity + #ExistInSiteQuantity + #spoolQuantity + #MIVQuantity)
RETURN round(#shortageQuantity, 3)
END
My query is executed in 3 minutes, it is catastrophic for my users! Is there any better solution?
I can recommend three things:
A. The following line..
SELECT #totalQuantity= ...
FROM [SPMS2].[dbo].Materials
Is this accessing a different database via a Linked Server connection ? How fast is this connection ?
B. Your SP contains two SELECT statements. Which of them is the bottleneck ?
You can add some PRINT statements to show when each is started:
PRINT convert(nvarchar, GetDate(), 108) + ' This is the time !'
C. Try running the SQL show on my webpage below, which will highlight missing Indexes.
Find missing indexes
Hope this helps.
Convert your Scaler function to Table-Valued function, and then place the function in FROM clause for LEFT JOIN. Do check execution plans to find any warning.
Testing performance of Scalar vs Table-valued functions in sql server