I need to use A LOT of set statistics time on and set statistics time off so I can check every steps' running time. Is there any way I can usr a variable to replace ON and OFF?
CREATE Procedure CPP_InsertOneRows
(#turnStatistics bit = 0
)
AS
BEGIN
DECLARE #onOrOff CHAR(3);
IF #turnStatistics = 1
BEGIN
SET #onOrOff = 'ON';
END
ELSE
BEGIN
SET #onOrOff = 'OFF';
END
SET STATISTICS TIME OFF -- how can I use #onOrOff to replace the 'OFF' here?
SET STATISTICS IO Off
Am I using it correctly? Or is there other method to do this? Thanks~
You would have to do the actual turning on/off within the IF:
IF #turnStatistics = 1
SET STATISTICS TIME ON;
ELSE
SET STATISTICS TIME OFF;
...
SET STATISTICS TIME OFF;
You cannot use a variable for the value of OFF/ON, it must be a literal.
if you want to check the time taken for each step of your code you can use following mehtod
Print 'Step 1 started'
print CONVERT (TIME, GETDATE())
WAITFOR DELAY '00:00:01'; -- function
Print 'Step 1 ended'
print CONVERT (TIME, GETDATE())
Print 'Step 2 started'
print CONVERT (TIME, GETDATE())
WAITFOR DELAY '00:00:02'; --- function
Print 'Step 2 ended'
print CONVERT (TIME, GETDATE())
make sure you remove this after your testing or uses #trace parameter if this #trace=1 only you will run this by default is set to #trace=0 (with if blocks)
Related
I've always been a silent reader here until now.
Now I would like to ask for your expertise and post my ver first question here.
I have to achieve the following task on a weekly basis in my MariaDB via Events:
Every Week on Saturday night at midnight, i want to save the results of a certain view in an excel file (xlsx). The filename should be variable depending on the site_id and the current timestamp.
After saving the results into the file I want to cleanup the DB Tables with another Event, but the previous event must be successfully finished as a condition to start the cleanup event.
e.g.filename:
viewname_[site_id]_timestamp.xlsx
overall_weekly _3_01082022.xlsx
This is what I have so far:
EVENT 1(saving results into file):
CREATE EVENT overall_weekly
ON SCHEDULE EVERY 1 WEEK
STARTS TRUNCATE(CURRENT_TIMESTAMP) + '00:00:00' HOUR_SECONDS
ON COMPLETION PRESERVE
ENABLE
DO
DECLARE #path = char
DECLARE #view = char
DECLARE #site_id = int(3)
DECLARE #timestamp = timestamp
DECLARE #filetype = char(5)
DECLARE #full_filename = char
SET #path = "/home/reports/"
SET #view = "overall_traffic_weekly"
SET #site_id = 3
SET #timestamp = current_timestamp
SET #filetype = ".xlsx"
SET #full_filename = CONCAT(#path,#view,#site_id,#timestamp,#filetype)
SELECT * FROM
(
SELECT 'Column_name_1','Column_name2', ...
UNION ALL
(
SELECT * FROM overall_weekly
WHERE site_id = 3
)
) resulting_set
INTO OUTFILE #full_filename
FIELDS TERMINATED BY ';'
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '/n';
EVENT 2(cleanup):
EVENT 1 must be SUCCESSFULLY finished for event 2 to start.
IF event 1 finishes with errors, cleanup must not start.
CREATE EVENT cleanup
ON SCHEDULE EVERY 1 WEEK
STARTS TRUNCATE(CURRENT_TIMESTAMP) + '03:00:00' HOUR_SECONDS
ON COMPLETION PRESERVE
ENABLE
DO
TRUNCATE sourcetable1,
TRUNCATE Sourcetable2
;
Many thanks for reading.
Problem solved:
I used 2 tables instead and matched the 2 records together in a third table
When I run my query, it prints multiple execution times instead of just one. I only want one so what do I need to do to get this to only print one time stamp?
SET STATISTICS TIME ON
DECLARE #firstNum INT, #secondNum INT, #thirdNum INT, #evenSum INT
SET #firstNum = 1
SET #secondNum = 2
set #thirdNum = 2
SET #evenSum = 2
WHILE (#thirdNum <= 4000000)
BEGIN
SET #thirdNum = #firstNum + #secondNum
SET #firstNum = #secondNum
SET #secondNum = #thirdNum
IF (#thirdNum % 2) = 0
SET #evenSum += #thirdNum
END
PRINT 'Answer = ' + CONVERT(VARCHAR, #evenSum)
SET STATISTICS TIME OFF
If you remove PRINT 'Answer = ' + CONVERT(VARCHAR, #evenSum) from your code
then it won't print multiple execution time.
Here is the example of it.
Statistic time will print for each execution. Since you are looping you are performing multiple query statements (I believe this also applies for sets -i could be wrong though), each will provide an execution time. There really is no way to modify statistic time for what I think you are looking for.
You could declare a datetime2 and store the start time in the beginning by using SysDateTime, and get the end time upon completion, thus printing the difference onto the screen using DateDiff. (This will achieve what you are asking for. )
You could also look into client statistic (but that might not be what you want).
Side note and irrelevant: you are looping queries. This is not profient and you may be doing this to learn. I would recommend looking into Tally tables for replacing loops. You can greatly improve performance if you design your query correctly.
I am looking to run a query in t-SQL (MS SQL SMS) that will stop after X number of seconds. Say 30 seconds. My goal is to stop a query after 6 minutes. I know the query is not correct, but wanted to give you an idea.
Select * from DB_Table
where (gatedate()+datepart(seconds,'00:00:30')) < getdate()
In SQL Server Management Studio, bring up the options dialog (Tools..Options). Drill down to "Query Execution/SQL Server/General". You should see something like this:
The Execution time-out setting is what you want. A value of 0 specifies an infinite time-out. A positive value the time-out limit in seconds.
NOTE: this value "is the cumulative time-out for all network reads during command execution or processing of the results. A time-out can still occur after the first row is returned, and does not include user processing time, only network read time." (per MSDN).
If you are using ADO.Net (System.Data.SqlClient), the SqlCommand object's CommandTimeout property is what you want. The connect string timeout verb: Connect Timeout, Connection Timeout or Timeout specifies how long to wait whilst establishing a connection with SQL Server. It's got nothing to do with query execution.
Yes, let's try it out.
This is a query that will run for 6 minutes:
DECLARE #i INT = 1;
WHILE (#i <= 360)
BEGIN
WAITFOR DELAY '00:00:01'
print FORMAT(GETDATE(),'hh:mm:ss')
SET #i = #i + 1;
END
Now create an Agent Job that will run every 10 seconds with this step:
-- Put here a part of the code you are targeting or even the whole query
DECLARE #Search_for_query NVARCHAR(300) SET #Search_for_query = '%FORMAT(GETDATE(),''hh:mm:ss'')%'
-- Define the maximum time you want the query to run
DECLARE #Time_to_run_in_minutes INT SET #Time_to_run_in_minutes = 1
DECLARE #SPID_older_than smallint
SET #SPID_older_than = (
SELECT
--text,
session_id
--,start_time
FROM sys.dm_exec_requests
CROSS APPLY sys.dm_exec_sql_text(sql_handle)
WHERE text LIKE #Search_for_query
AND text NOT LIKE '%sys.dm_exec_sql_text(sql_handle)%' -- This will avoid the killing job to kill itself
AND start_time < DATEADD(MINUTE, -#Time_to_run_in_minutes, GETDATE())
)
-- SELECT #SPID_older_than -- Use this for testing
DECLARE #SQL nvarchar(1000)
SET #SQL = 'KILL ' + CAST(#SPID_older_than as varchar(20))
EXEC (#SQL)
Make sure the job is run by sa or some valid alternative.
Now you can adapt it to your code by changing:
#Search_for_query = put here a part of the query you are looking for
#Time_to_run_in_minutes = the max number of minutes you want the job to run
What will you be using to execute this query? If you create a .NET application, the timeout for stored procedures by default is 30 seconds. You can change the timeout to be 6 minutes if you wish by changing SqlCommand.CommandTimeout
In SQL Server, I just right click on the connection in the left Object Explorer pane, choose Activity Monitor, then Processes, right click the query that's running, and choose Kill Process.
I want to use infinite WHILE loop in SQL Server 2005 and use BREAK keyword to exit from it on certain condition.
while true does not work, so I have to use while 1=1.
Is there a better way to organize infinite loop ?
I know that I can use goto, but while 1=1 begin ... end looks better structurally.
In addition to the WHILE 1 = 1 as the other answers suggest, I often add a "timeout" to my SQL "infintie" loops, as in the following example:
DECLARE #startTime datetime2(0) = GETDATE();
-- This will loop until BREAK is called, or until a timeout of 45 seconds.
WHILE (GETDATE() < DATEADD(SECOND, 45, #startTime))
BEGIN
-- Logic goes here: The loop can be broken with the BREAK command.
-- Throttle the loop for 2 seconds.
WAITFOR DELAY '00:00:02';
END
I found the above technique useful within a stored procedure that gets called from a long polling AJAX backend. Having the loop on the database-side frees the application from having to constantly hit the database to check for fresh data.
Using While 1 = 1 with a Break statement is the way to do it. There is no constant in T-SQL for TRUE or FALSE.
If you really have to use an infinite loop than using while 1=1 is the way I'd do it.
The question here is, isn't there some other way to avoid an infinite loop? These things just tend to go wrong ;)
you could use the snippet below to kick a sp after soem condition are rised. I assume that you ahev some sort of CurrentJobStatus table where all the jobs/sp keeps their status...
-- *** reload data on N Support.usp_OverrideMode with checks on Status
/* run
Support.usp_OverrideMode.Number1.sql
and
Support.usp_OverrideMode.Number2.sql
*/
DECLARE #FileNameSet TABLE (FileName VARCHAR(255));
INSERT INTO #FileNameSet
VALUES ('%SomeID1%');
INSERT INTO #FileNameSet
VALUES ('%SomeID2%');
DECLARE #BatchRunID INT;
DECLARE #CounterSuccess INT = 0;
DECLARE #CounterError INT = 0;
-- Loop
WHILE WHILE (#CounterError = 0 AND #CounterSuccess < (select COUNT(1) c from #FileNameSet) )
BEGIN
DECLARE #CurrenstStatus VARCHAR(255)
SELECT #CurrenstStatus = CAST(GETDATE() AS VARCHAR)
-- Logic goes here: The loop can be broken with the BREAK command.
SELECT #CounterSuccess = COUNT(1)
FROM dbo.CurrentJobStatus t
INNER JOIN #FileNameSet fns
ON (t.FileName LIKE fns.FileName)
WHERE LoadStatus = 'Completed Successfully'
SELECT #CounterError = COUNT(1)
FROM dbo.CurrentJobStatus t
INNER JOIN #FileNameSet fns
ON (t.FileName LIKE fns.FileName)
WHERE LoadStatus = 'Completed with Error(s)'
-- Throttle the loop for 3 seconds.
WAITFOR DELAY '00:00:03';
select #CurrenstStatus = #CurrenstStatus +char(9)+ '#CounterSuccess ' + CAST(#CounterSuccess AS VARCHAR(11))
+ char(9)+ 'CounterError ' + CAST(#CounterError AS VARCHAR(11))
RAISERROR (
'Looping... # %s'
,0
,1
,#CurrenstStatus
)
WITH NOWAIT;
END
-- TODO add some codition on #CounterError value
/* run
Support.usp_OverrideMode.WhenAllSuceed.sql
*/
Note the code is flexibile you can add as many condition checks on the #FileNameSet table var
Mario
I have a simple query which loops and I want to see the PRINT messages during the execution. The query is something like this:
WHILE 1 = 1
BEGIN
WAITFOR DELAY '000:00:10'
PRINT 'here'
END
The PRINT 'here' does not output until I stop the process. However, I want to see it while it's running. Is this possible?
You can use RAISERROR with serverity 0 and the NOWAIT option
WHILE 1 = 1
BEGIN
WAITFOR DELAY '000:00:10'
RAISERROR ('here', 0, 1) WITH NOWAIT
END
I believe that the prints get buffered, releasing "chunks" as the buffer fills up.
try using raiserror:
How do I flush the PRINT buffer in TSQL?
Try this..
DECLARE #i INT = 1
WHILE ( #i <= 10)
BEGIN
--- do something
SELECT 'Completed ' + CAST(#i AS VARCHAR(50)) + ' : ' + CAST(GETDATE() AS VARCHAR(50));
SET #i = #i + 1
END
current suggestions don't work for SSMS 18 and above.
Print then raiserror(N'', 0, 1) seems to get around this.