Low performance with dynamic queries and cursors
Doing some legacy work, I found the following procedure that used to take between 1.5 to 6 hours, totally not expected when dealing with less than 2 million records. After the change it takes less than 3 minutes.
Why this script was taking too much time?
The script extracts only one value from one field, between 20 and 40
different sources, each source has from 100 to 100,000's records. Total records at the destination table is up to from half million to 2 millions.
The tableSOURCE_TABLE_FIELDScontains the table names, fields and criteria to build the dynamic queries.
DECLARE source_c CURSOR FOR --cursor starts here
SELECT table_name, field_name, condition
FROM SOURCE_TABLE_FIELDS
OPEN source_c
FETCH NEXT FROM source_c
INTO @table, @field, @condition;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT 'DEBUG CHECKPOINT: START LOOP'
declare @sql as nvarchar (1000)
declare @sql_source as nvarchar(1000)
set @sql_source = 'select ' + @field + ' as SOURCE_FIELD from [' + @table + '] A '
+ ' WHERE 1=1 ' +
+ @condition +
'EXCEPT SELECT DISTINCT DEST_FIELD FROM ' + @DESTINATION;
set @sql = 'INSERT INTO ' + @DESTINATION + '(DEST_FIELD) ' + @sql_source;
EXEC SP_EXECUTESQL @SQL
PRINT 'DEBUG CHECKPOINT: END LOOP'
FETCH NEXT FROM source_c INTO @table, @fild, @condition;
END
CLOSE source_c;
DEALLOCATE source_c;
Look at the
PRINT 'DEBUG'marks; sometimes the last line printed was from the end, sometimes the one at the start. It could take up to an hour to jump. (I checked this by printing timestamps and everything).
By sometimes I mean, usually after the first 10 loops, randomly. No matter if I sorted out the sources with small records at first or at last.
Important remarks:
- I don't have permission to access the SQL-Profiler
- I don't have access to sys.dm_exec_query_stats or any other high level stuff.
- I'm not a DBA, only a developer but with tons of SSIS work lately.
sql-server stored-procedures dynamic-sql
bumped to the homepage by Community♦ 22 mins ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
add a comment |
Doing some legacy work, I found the following procedure that used to take between 1.5 to 6 hours, totally not expected when dealing with less than 2 million records. After the change it takes less than 3 minutes.
Why this script was taking too much time?
The script extracts only one value from one field, between 20 and 40
different sources, each source has from 100 to 100,000's records. Total records at the destination table is up to from half million to 2 millions.
The tableSOURCE_TABLE_FIELDScontains the table names, fields and criteria to build the dynamic queries.
DECLARE source_c CURSOR FOR --cursor starts here
SELECT table_name, field_name, condition
FROM SOURCE_TABLE_FIELDS
OPEN source_c
FETCH NEXT FROM source_c
INTO @table, @field, @condition;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT 'DEBUG CHECKPOINT: START LOOP'
declare @sql as nvarchar (1000)
declare @sql_source as nvarchar(1000)
set @sql_source = 'select ' + @field + ' as SOURCE_FIELD from [' + @table + '] A '
+ ' WHERE 1=1 ' +
+ @condition +
'EXCEPT SELECT DISTINCT DEST_FIELD FROM ' + @DESTINATION;
set @sql = 'INSERT INTO ' + @DESTINATION + '(DEST_FIELD) ' + @sql_source;
EXEC SP_EXECUTESQL @SQL
PRINT 'DEBUG CHECKPOINT: END LOOP'
FETCH NEXT FROM source_c INTO @table, @fild, @condition;
END
CLOSE source_c;
DEALLOCATE source_c;
Look at the
PRINT 'DEBUG'marks; sometimes the last line printed was from the end, sometimes the one at the start. It could take up to an hour to jump. (I checked this by printing timestamps and everything).
By sometimes I mean, usually after the first 10 loops, randomly. No matter if I sorted out the sources with small records at first or at last.
Important remarks:
- I don't have permission to access the SQL-Profiler
- I don't have access to sys.dm_exec_query_stats or any other high level stuff.
- I'm not a DBA, only a developer but with tons of SSIS work lately.
sql-server stored-procedures dynamic-sql
bumped to the homepage by Community♦ 22 mins ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
This question and the answer may help you understand the prints occurring out of order. : dba.stackexchange.com/questions/24714/…
– Max Vernon
Feb 10 '17 at 23:26
add a comment |
Doing some legacy work, I found the following procedure that used to take between 1.5 to 6 hours, totally not expected when dealing with less than 2 million records. After the change it takes less than 3 minutes.
Why this script was taking too much time?
The script extracts only one value from one field, between 20 and 40
different sources, each source has from 100 to 100,000's records. Total records at the destination table is up to from half million to 2 millions.
The tableSOURCE_TABLE_FIELDScontains the table names, fields and criteria to build the dynamic queries.
DECLARE source_c CURSOR FOR --cursor starts here
SELECT table_name, field_name, condition
FROM SOURCE_TABLE_FIELDS
OPEN source_c
FETCH NEXT FROM source_c
INTO @table, @field, @condition;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT 'DEBUG CHECKPOINT: START LOOP'
declare @sql as nvarchar (1000)
declare @sql_source as nvarchar(1000)
set @sql_source = 'select ' + @field + ' as SOURCE_FIELD from [' + @table + '] A '
+ ' WHERE 1=1 ' +
+ @condition +
'EXCEPT SELECT DISTINCT DEST_FIELD FROM ' + @DESTINATION;
set @sql = 'INSERT INTO ' + @DESTINATION + '(DEST_FIELD) ' + @sql_source;
EXEC SP_EXECUTESQL @SQL
PRINT 'DEBUG CHECKPOINT: END LOOP'
FETCH NEXT FROM source_c INTO @table, @fild, @condition;
END
CLOSE source_c;
DEALLOCATE source_c;
Look at the
PRINT 'DEBUG'marks; sometimes the last line printed was from the end, sometimes the one at the start. It could take up to an hour to jump. (I checked this by printing timestamps and everything).
By sometimes I mean, usually after the first 10 loops, randomly. No matter if I sorted out the sources with small records at first or at last.
Important remarks:
- I don't have permission to access the SQL-Profiler
- I don't have access to sys.dm_exec_query_stats or any other high level stuff.
- I'm not a DBA, only a developer but with tons of SSIS work lately.
sql-server stored-procedures dynamic-sql
Doing some legacy work, I found the following procedure that used to take between 1.5 to 6 hours, totally not expected when dealing with less than 2 million records. After the change it takes less than 3 minutes.
Why this script was taking too much time?
The script extracts only one value from one field, between 20 and 40
different sources, each source has from 100 to 100,000's records. Total records at the destination table is up to from half million to 2 millions.
The tableSOURCE_TABLE_FIELDScontains the table names, fields and criteria to build the dynamic queries.
DECLARE source_c CURSOR FOR --cursor starts here
SELECT table_name, field_name, condition
FROM SOURCE_TABLE_FIELDS
OPEN source_c
FETCH NEXT FROM source_c
INTO @table, @field, @condition;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT 'DEBUG CHECKPOINT: START LOOP'
declare @sql as nvarchar (1000)
declare @sql_source as nvarchar(1000)
set @sql_source = 'select ' + @field + ' as SOURCE_FIELD from [' + @table + '] A '
+ ' WHERE 1=1 ' +
+ @condition +
'EXCEPT SELECT DISTINCT DEST_FIELD FROM ' + @DESTINATION;
set @sql = 'INSERT INTO ' + @DESTINATION + '(DEST_FIELD) ' + @sql_source;
EXEC SP_EXECUTESQL @SQL
PRINT 'DEBUG CHECKPOINT: END LOOP'
FETCH NEXT FROM source_c INTO @table, @fild, @condition;
END
CLOSE source_c;
DEALLOCATE source_c;
Look at the
PRINT 'DEBUG'marks; sometimes the last line printed was from the end, sometimes the one at the start. It could take up to an hour to jump. (I checked this by printing timestamps and everything).
By sometimes I mean, usually after the first 10 loops, randomly. No matter if I sorted out the sources with small records at first or at last.
Important remarks:
- I don't have permission to access the SQL-Profiler
- I don't have access to sys.dm_exec_query_stats or any other high level stuff.
- I'm not a DBA, only a developer but with tons of SSIS work lately.
sql-server stored-procedures dynamic-sql
sql-server stored-procedures dynamic-sql
edited Feb 10 '17 at 20:48
celerno
asked Feb 10 '17 at 19:18
celernocelerno
1012
1012
bumped to the homepage by Community♦ 22 mins ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
bumped to the homepage by Community♦ 22 mins ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
This question and the answer may help you understand the prints occurring out of order. : dba.stackexchange.com/questions/24714/…
– Max Vernon
Feb 10 '17 at 23:26
add a comment |
This question and the answer may help you understand the prints occurring out of order. : dba.stackexchange.com/questions/24714/…
– Max Vernon
Feb 10 '17 at 23:26
This question and the answer may help you understand the prints occurring out of order. : dba.stackexchange.com/questions/24714/…
– Max Vernon
Feb 10 '17 at 23:26
This question and the answer may help you understand the prints occurring out of order. : dba.stackexchange.com/questions/24714/…
– Max Vernon
Feb 10 '17 at 23:26
add a comment |
1 Answer
1
active
oldest
votes
You've written the SQL using an EXCEPT DISTINCT clause, when you would likely have much better luck adding a NOT EXISTS to your WHERE clause. Essentially you are adding rows to the destination table where they do not already exist there.
This isn't a reason. The same "except" query (with all sources as unions) is being used and running with exceptional performance. The slowness comes from the while/loop.
– celerno
Feb 11 '17 at 20:24
1
SQL is set based, so it's always better to avoid loops where possible. Yes, it would be better to do all inserts in one pass.
– Matthew Sontum
Feb 11 '17 at 22:22
I have read in depth about this, actually this comment qualifies as answer; thanks
– celerno
Feb 13 '17 at 15:35
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "182"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f163925%2flow-performance-with-dynamic-queries-and-cursors%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
You've written the SQL using an EXCEPT DISTINCT clause, when you would likely have much better luck adding a NOT EXISTS to your WHERE clause. Essentially you are adding rows to the destination table where they do not already exist there.
This isn't a reason. The same "except" query (with all sources as unions) is being used and running with exceptional performance. The slowness comes from the while/loop.
– celerno
Feb 11 '17 at 20:24
1
SQL is set based, so it's always better to avoid loops where possible. Yes, it would be better to do all inserts in one pass.
– Matthew Sontum
Feb 11 '17 at 22:22
I have read in depth about this, actually this comment qualifies as answer; thanks
– celerno
Feb 13 '17 at 15:35
add a comment |
You've written the SQL using an EXCEPT DISTINCT clause, when you would likely have much better luck adding a NOT EXISTS to your WHERE clause. Essentially you are adding rows to the destination table where they do not already exist there.
This isn't a reason. The same "except" query (with all sources as unions) is being used and running with exceptional performance. The slowness comes from the while/loop.
– celerno
Feb 11 '17 at 20:24
1
SQL is set based, so it's always better to avoid loops where possible. Yes, it would be better to do all inserts in one pass.
– Matthew Sontum
Feb 11 '17 at 22:22
I have read in depth about this, actually this comment qualifies as answer; thanks
– celerno
Feb 13 '17 at 15:35
add a comment |
You've written the SQL using an EXCEPT DISTINCT clause, when you would likely have much better luck adding a NOT EXISTS to your WHERE clause. Essentially you are adding rows to the destination table where they do not already exist there.
You've written the SQL using an EXCEPT DISTINCT clause, when you would likely have much better luck adding a NOT EXISTS to your WHERE clause. Essentially you are adding rows to the destination table where they do not already exist there.
answered Feb 11 '17 at 15:14
Matthew SontumMatthew Sontum
366312
366312
This isn't a reason. The same "except" query (with all sources as unions) is being used and running with exceptional performance. The slowness comes from the while/loop.
– celerno
Feb 11 '17 at 20:24
1
SQL is set based, so it's always better to avoid loops where possible. Yes, it would be better to do all inserts in one pass.
– Matthew Sontum
Feb 11 '17 at 22:22
I have read in depth about this, actually this comment qualifies as answer; thanks
– celerno
Feb 13 '17 at 15:35
add a comment |
This isn't a reason. The same "except" query (with all sources as unions) is being used and running with exceptional performance. The slowness comes from the while/loop.
– celerno
Feb 11 '17 at 20:24
1
SQL is set based, so it's always better to avoid loops where possible. Yes, it would be better to do all inserts in one pass.
– Matthew Sontum
Feb 11 '17 at 22:22
I have read in depth about this, actually this comment qualifies as answer; thanks
– celerno
Feb 13 '17 at 15:35
This isn't a reason. The same "except" query (with all sources as unions) is being used and running with exceptional performance. The slowness comes from the while/loop.
– celerno
Feb 11 '17 at 20:24
This isn't a reason. The same "except" query (with all sources as unions) is being used and running with exceptional performance. The slowness comes from the while/loop.
– celerno
Feb 11 '17 at 20:24
1
1
SQL is set based, so it's always better to avoid loops where possible. Yes, it would be better to do all inserts in one pass.
– Matthew Sontum
Feb 11 '17 at 22:22
SQL is set based, so it's always better to avoid loops where possible. Yes, it would be better to do all inserts in one pass.
– Matthew Sontum
Feb 11 '17 at 22:22
I have read in depth about this, actually this comment qualifies as answer; thanks
– celerno
Feb 13 '17 at 15:35
I have read in depth about this, actually this comment qualifies as answer; thanks
– celerno
Feb 13 '17 at 15:35
add a comment |
Thanks for contributing an answer to Database Administrators Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f163925%2flow-performance-with-dynamic-queries-and-cursors%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
This question and the answer may help you understand the prints occurring out of order. : dba.stackexchange.com/questions/24714/…
– Max Vernon
Feb 10 '17 at 23:26