I am trying to run a stored procedure with a while loop in it using Aqua Data Studio 6.5 and as soon as the SP starts Aqua Data starts consuming an increasing amount of my CPU's memory which makes absolutely no sense to me because everything should be off on the Sybase server I am working with. I have commented out and tested every piece of the SP and narrowed the issue down to the while loop. Can anyone explain to me what is going on?
create procedure sp_check_stuff as
begin
declare
#counter numeric (9),
#max_id numeric (9),
#exists numeric (1),
#rows numeric (1)
select #max_id = max(id)
from my_table
set #counter = 0
set #exists = 0
set #rows = 0
while #count <= #max_id
begin
//More logic which doesn't affect memory usage based
//on commenting it out and running the SP
set #counter = #counter + 1
set #exists = 0
set #rows = 0
end
end
return
How many times does the while loop iterate? I suspect Aqua Data Studio is building up data structures as the query runs and for every iteration of the loop, a further block of memory is needed to catalogue the plan/stats of that iteration.
Related
I wrote a simple loop code in SQL Server to measure performance of my SQL query. The measurement times I get from that code are in 95% of times as expected, very similar to each other, but sometimes the time can be 3-4 times higher than the normal one. There is no other process obtaining database at the same time.
declare #tTOTAL int = 0
declare #i integer = 0
declare #itrs integer = 100
while #i < #itrs
begin
CHECKPOINT; DBCC DROPCLEANBUFFERS; DBCC FREEPROCCACHE;
declare #t0 datetime2 = GETDATE()
// Here goes the query to measure its performance
SELECT COUNT(*) FROM [Comments] AS [c] WHERE [c].[Score] > 100
declare #t1 datetime2 = GETDATE()
set #tTotal = DATEDIFF(MILLISECOND,#t0,#t1)
select #tTotal as TimeT
set #i = #i + 1
end
If that is not the perfect way to measure query performance do you recommend any tool or way to do simple measurements as I want to do? (I need to get result of every single measurement, not only averages ...)
I am using goto in azure synapse to skip certain code and jump to the label, its not working as expected. what is the alternate for that.
As GOTO is not supported in Azure Synapse Analytics, dedicated SQL pools, you need to write procedure code that does not rely on GOTO.
This example is taken from the help page for GOTO and works perfectly fine on normal SQL Server:
DECLARE #Counter int;
SET #Counter = 1;
WHILE #Counter < 10
BEGIN
SELECT #Counter
SET #Counter = #Counter + 1
IF #Counter = 4 GOTO Branch_One --Jumps to the first branch.
IF #Counter = 5 GOTO Branch_Two --This will never execute.
END
Branch_One:
SELECT 'Jumping To Branch One.'
GOTO Branch_Three; --This will prevent Branch_Two from executing.
Branch_Two:
SELECT 'Jumping To Branch Two.'
Branch_Three:
SELECT 'Jumping To Branch Three.';
This is that same code refactored without GOTO, using IF ELSE control flow language and BEGIN END blocks to contain multiple statements and BREAK to exit the loop:
DECLARE #Counter INT;
SET #Counter = 1;
WHILE #Counter < 10
BEGIN
SELECT #Counter
SET #Counter = #Counter + 1
IF #Counter = 4
BEGIN
SELECT 'Jumping To Branch One.'
SELECT 'Jumping To Branch Three.';
BREAK
END
IF #Counter = 5
BEGIN
SELECT 'Jumping To Branch Two.'
END
END
There would be multiple ways to do it, eg write some of the inner code as functions or stored procedures. This is just a simple example. I have to say, I have not written a GOTO statement in SQL code for years as it tends to lead to so-called spaghetti code and can be hard to debug.
New to stored procedures. Can anyone explain the following SQL sample which appears at the start of a stored procedure?
Begin/End - Encloses a series of SQL statements so that a group of SQL statements can be executed
SET NOCOUNT ON - the count (indicating the number of rows affected by a SQL statement) is not returned.
DECLARE - setting local variables
While - loops round
With - unsure
Update batch - unsure
SET #Rowcount = ##ROWCOUNT; - unsure
BEGIN
SET NOCOUNT ON;
--UPDATE, done in batches to minimise locking
DECLARE #Batch INT= 100;
DECLARE #Rowcount INT= #Batch;
WHILE #Rowcount > 0
BEGIN
WITH t
AS (
SELECT [OrganisationID],
[PropertyID],
[QuestionID],
[BaseAnsweredQuestionID]
FROM dbo.Unioned_Table
WHERE organisationid = 1),
s
AS (
SELECT [OrganisationID],
[PropertyID],
[QuestionID],
[BaseAnsweredQuestionID]
FROM dbo.table
WHERE organisationid = 1),
batch
AS (
SELECT TOP (#Batch) T.*,
s.BaseAnsweredQuestionID NewBaseAnsweredQuestionID
FROM T
INNER JOIN s ON t.organisationid = s.organisationid
AND t.PropertyID = s.PropertyID
AND t.QuestionID = s.QuestionID
WHERE t.BaseAnsweredQuestionID <> s.BaseAnsweredQuestionID)
UPDATE batch
SET
BaseAnsweredQuestionID = NewBaseAnsweredQuestionID
SET #Rowcount = ##ROWCOUNT;
END;
The clue is in the comment --UPDATE, done in batches to minimise locking.
The intent is to update dbo.table's column BaseAnsweredQuestionID with the equivalent column from dbo.Unioned_Table, in batches of 100. The comment suggests the batching logic is necessary to prevent locking.
In detail:
DECLARE #Batch INT= 100; sets the batch size.
DECLARE #Rowcount INT= #Batch; initializes the loop.
WHILE #Rowcount > 0 starts the loop. #Rowcount will become zero when the update statement affects no rows (see below).
with a as () is a common table expression (commonly abbreviated to CTE) - it creates a temporary result set which you can effectively treat as a table. The next few queries define CTEs t, s and batch.
CTE batch contains just 100 rows by using the SELECT TOP (#Batch) term - it selects a random 100 rows from the two other CTEs.
The next statement:
UPDATE batch
SET BaseAnsweredQuestionID = NewBaseAnsweredQuestionID
SET #Rowcount = ##ROWCOUNT
updates the 100 rows in the batch CTE (which in turn is a join on two other CTEs), and populates the loop variable #Rowcount with the number of rows affected by the update statement (##ROWCOUNT). If there are no matching rows, ##ROWCOUNT becomes zero, and thus the loop ends.
I have the following sql:
UPDATE Customer SET Count=1 WHERE ID=1 AND Count=0
SELECT ##ROWCOUNT
I need to know if this is guaranteed to be atomic.
If 2 users try this simultaneously, will only one succeed and get a return value of 1? Do I need to use a transaction or something else in order to guarantee this?
The goal is to get a unique 'Count' for the customer. Collisions in this system will almost never happen, so I am not concerned with the performance if a user has to query again (and again) to get a unique Count.
EDIT:
The goal is to not use a transaction if it is not needed. Also this logic is ran very infrequently (up to 100 per day), so I wanted to keep it as simple as possible.
It may depend on the sql server you are using. However for most, the answer is yes. I guess you are implementing a lock.
Using SQL SERVER (v 11.0.6020) that this is indeed an atomic operation as best as I can determine.
I wrote some test stored procedures to try to test this logic:
-- Attempt to update a Customer row with a new Count, returns
-- The current count (used as customer order number) and a bit
-- which determines success or failure. If #Success is 0, re-run
-- the query and try again.
CREATE PROCEDURE [dbo].[sp_TestUpdate]
(
#Count INT OUTPUT,
#Success BIT OUTPUT
)
AS
BEGIN
DECLARE #NextCount INT
SELECT #Count=Count FROM Customer WHERE ID=1
SET #NextCount = #Count + 1
UPDATE Customer SET Count=#NextCount WHERE ID=1 AND Count=#Count
SET #Success=##ROWCOUNT
END
And:
-- Loop (many times) trying to get a number and insert in into another
-- table. Execute this loop concurrently in several different windows
-- using SMSS.
CREATE PROCEDURE [dbo].[sp_TestLoop]
AS
BEGIN
DECLARE #Iterations INT
DECLARE #Counter INT
DECLARE #Count INT
DECLARE #Success BIT
SET #Iterations = 40000
SET #Counter = 0
WHILE (#Counter < #Iterations)
BEGIN
SET #Counter = #Counter + 1
EXEC sp_TestUpdate #Count = #Count OUTPUT , #Success = #Success OUTPUT
IF (#Success=1)
BEGIN
INSERT INTO TestImage (ImageNumber) VALUES (#Count)
END
END
END
This code ran, creating unique sequential ImageNumber values in the TestImage table. This proves that the above SQL update call is indeed atomic. Neither function guaranteed the updates were done, but they did guarantee that no duplicates were created, and no numbers were skipped.
Is it possible to use T-SQL programming constructs outside the confines of stored procedures and functions? Specifically, can they be used in ad-hoc sql scripts? If so, is the full range of capabilities available (aside from passing in parameters and returning values that I guess would only be supported in stored procedures and functions)?
I'm from an Oracle PL/SQL background. PL/SQL can be used in stored procedures and functions, but also within anonymous PL/SQL code blocks that can be used in ad-hoc sql scripts and do not get stored in the DB. I'd like to know if T-SQL has similar capabilities.
Yes they can take this example solution to the fizzbuzz problem:
declare #counter int
declare #output varchar(15)
set #counter = 1
while #counter < 101
begin
set #output = ''
if #counter % 3 = 0
set #output = 'Fizz'
if #counter % 5 = 0
set #output = #output + 'Buzz'
if #output =''
set #output = #counter
print #output
set #counter = #counter + 1
end
Of course don't fall into the trap of using procedural code to work with data, SQL works best treating data as a set.