Sort spills to tempdb due to varchar(max)
On a server with 32GB we are running SQL Server 2014 SP2 with a max memory of 25GB we have two tables, here you find a simplified structure of both tables:
CREATE TABLE [dbo].[Settings](
[id] [int] IDENTITY(1,1) NOT NULL,
[resourceId] [int] NULL,
[typeID] [int] NULL,
[remark] [varchar](max) NULL,
CONSTRAINT [PK_Settings] PRIMARY KEY CLUSTERED ([id] ASC)
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Resources](
[id] [int] IDENTITY(1,1) NOT NULL,
[resourceUID] [int] NULL,
CONSTRAINT [PK_Resources] PRIMARY KEY CLUSTERED ([id] ASC)
) ON [PRIMARY]
GO
with following non-clustered indexes:
CREATE NONCLUSTERED INDEX [IX_UID] ON [dbo].[Resources]
(
[resourceUID] ASC
)
CREATE NONCLUSTERED INDEX [IX_Test] ON [dbo].[Settings]
(
[resourceId] ASC,
[typeID] ASC
)
The database is configured with compatibility level
120.
When I run this query there are spills to tempdb
.
This is how I execute the query:
exec sp_executesql N'
select r.id,remark
FROM Resources r
inner join Settings on resourceid=r.id
where resourceUID=@UID
ORDER BY typeID',
N'@UID int',
@UID=38
If don't select the [remark]
field no spills occurs. My first reaction was that the spills occurred due to the low number of estimated rows on the nested-loop operator.
So I add 5 datetime and 5 integer columns to the settings table and add them to my select statement. When I execute the query no spills are happening.
Why are the spills only happening when [remark]
is selected? It has probably something to do with the fact that this is a varchar(max)
.
What can I do to avoid spilling to tempdb
?
sql-server query-performance tempdb cardinality-estimates
|
show 2 more comments
On a server with 32GB we are running SQL Server 2014 SP2 with a max memory of 25GB we have two tables, here you find a simplified structure of both tables:
CREATE TABLE [dbo].[Settings](
[id] [int] IDENTITY(1,1) NOT NULL,
[resourceId] [int] NULL,
[typeID] [int] NULL,
[remark] [varchar](max) NULL,
CONSTRAINT [PK_Settings] PRIMARY KEY CLUSTERED ([id] ASC)
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Resources](
[id] [int] IDENTITY(1,1) NOT NULL,
[resourceUID] [int] NULL,
CONSTRAINT [PK_Resources] PRIMARY KEY CLUSTERED ([id] ASC)
) ON [PRIMARY]
GO
with following non-clustered indexes:
CREATE NONCLUSTERED INDEX [IX_UID] ON [dbo].[Resources]
(
[resourceUID] ASC
)
CREATE NONCLUSTERED INDEX [IX_Test] ON [dbo].[Settings]
(
[resourceId] ASC,
[typeID] ASC
)
The database is configured with compatibility level
120.
When I run this query there are spills to tempdb
.
This is how I execute the query:
exec sp_executesql N'
select r.id,remark
FROM Resources r
inner join Settings on resourceid=r.id
where resourceUID=@UID
ORDER BY typeID',
N'@UID int',
@UID=38
If don't select the [remark]
field no spills occurs. My first reaction was that the spills occurred due to the low number of estimated rows on the nested-loop operator.
So I add 5 datetime and 5 integer columns to the settings table and add them to my select statement. When I execute the query no spills are happening.
Why are the spills only happening when [remark]
is selected? It has probably something to do with the fact that this is a varchar(max)
.
What can I do to avoid spilling to tempdb
?
sql-server query-performance tempdb cardinality-estimates
What happens when you add option(recompile) to the query that has spills?
– Randi Vertongen
2 hours ago
Here's a dbfiddle to help with getting a repro. It currently has no data, and thus produces a different plan. If you want to adjust the fiddle and post a new link, it will help us propose solutions.
– Forrest
1 hour ago
@randi: adding makes no difference
– Frederik Vanderhaegen
1 hour ago
May be you can tryselect r.id, LEFT(remark, 512)
(or whatever sensible substring length might be).
– mustaccio
1 hour ago
Is it actually causing a performance issue? If it only spills a tiny amount of data to tempdb, I think it will all be done in memory and it's really not a problem...
– Tony Hinkle
1 hour ago
|
show 2 more comments
On a server with 32GB we are running SQL Server 2014 SP2 with a max memory of 25GB we have two tables, here you find a simplified structure of both tables:
CREATE TABLE [dbo].[Settings](
[id] [int] IDENTITY(1,1) NOT NULL,
[resourceId] [int] NULL,
[typeID] [int] NULL,
[remark] [varchar](max) NULL,
CONSTRAINT [PK_Settings] PRIMARY KEY CLUSTERED ([id] ASC)
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Resources](
[id] [int] IDENTITY(1,1) NOT NULL,
[resourceUID] [int] NULL,
CONSTRAINT [PK_Resources] PRIMARY KEY CLUSTERED ([id] ASC)
) ON [PRIMARY]
GO
with following non-clustered indexes:
CREATE NONCLUSTERED INDEX [IX_UID] ON [dbo].[Resources]
(
[resourceUID] ASC
)
CREATE NONCLUSTERED INDEX [IX_Test] ON [dbo].[Settings]
(
[resourceId] ASC,
[typeID] ASC
)
The database is configured with compatibility level
120.
When I run this query there are spills to tempdb
.
This is how I execute the query:
exec sp_executesql N'
select r.id,remark
FROM Resources r
inner join Settings on resourceid=r.id
where resourceUID=@UID
ORDER BY typeID',
N'@UID int',
@UID=38
If don't select the [remark]
field no spills occurs. My first reaction was that the spills occurred due to the low number of estimated rows on the nested-loop operator.
So I add 5 datetime and 5 integer columns to the settings table and add them to my select statement. When I execute the query no spills are happening.
Why are the spills only happening when [remark]
is selected? It has probably something to do with the fact that this is a varchar(max)
.
What can I do to avoid spilling to tempdb
?
sql-server query-performance tempdb cardinality-estimates
On a server with 32GB we are running SQL Server 2014 SP2 with a max memory of 25GB we have two tables, here you find a simplified structure of both tables:
CREATE TABLE [dbo].[Settings](
[id] [int] IDENTITY(1,1) NOT NULL,
[resourceId] [int] NULL,
[typeID] [int] NULL,
[remark] [varchar](max) NULL,
CONSTRAINT [PK_Settings] PRIMARY KEY CLUSTERED ([id] ASC)
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Resources](
[id] [int] IDENTITY(1,1) NOT NULL,
[resourceUID] [int] NULL,
CONSTRAINT [PK_Resources] PRIMARY KEY CLUSTERED ([id] ASC)
) ON [PRIMARY]
GO
with following non-clustered indexes:
CREATE NONCLUSTERED INDEX [IX_UID] ON [dbo].[Resources]
(
[resourceUID] ASC
)
CREATE NONCLUSTERED INDEX [IX_Test] ON [dbo].[Settings]
(
[resourceId] ASC,
[typeID] ASC
)
The database is configured with compatibility level
120.
When I run this query there are spills to tempdb
.
This is how I execute the query:
exec sp_executesql N'
select r.id,remark
FROM Resources r
inner join Settings on resourceid=r.id
where resourceUID=@UID
ORDER BY typeID',
N'@UID int',
@UID=38
If don't select the [remark]
field no spills occurs. My first reaction was that the spills occurred due to the low number of estimated rows on the nested-loop operator.
So I add 5 datetime and 5 integer columns to the settings table and add them to my select statement. When I execute the query no spills are happening.
Why are the spills only happening when [remark]
is selected? It has probably something to do with the fact that this is a varchar(max)
.
What can I do to avoid spilling to tempdb
?
sql-server query-performance tempdb cardinality-estimates
sql-server query-performance tempdb cardinality-estimates
edited 1 hour ago
Frederik Vanderhaegen
asked 2 hours ago
Frederik VanderhaegenFrederik Vanderhaegen
6471316
6471316
What happens when you add option(recompile) to the query that has spills?
– Randi Vertongen
2 hours ago
Here's a dbfiddle to help with getting a repro. It currently has no data, and thus produces a different plan. If you want to adjust the fiddle and post a new link, it will help us propose solutions.
– Forrest
1 hour ago
@randi: adding makes no difference
– Frederik Vanderhaegen
1 hour ago
May be you can tryselect r.id, LEFT(remark, 512)
(or whatever sensible substring length might be).
– mustaccio
1 hour ago
Is it actually causing a performance issue? If it only spills a tiny amount of data to tempdb, I think it will all be done in memory and it's really not a problem...
– Tony Hinkle
1 hour ago
|
show 2 more comments
What happens when you add option(recompile) to the query that has spills?
– Randi Vertongen
2 hours ago
Here's a dbfiddle to help with getting a repro. It currently has no data, and thus produces a different plan. If you want to adjust the fiddle and post a new link, it will help us propose solutions.
– Forrest
1 hour ago
@randi: adding makes no difference
– Frederik Vanderhaegen
1 hour ago
May be you can tryselect r.id, LEFT(remark, 512)
(or whatever sensible substring length might be).
– mustaccio
1 hour ago
Is it actually causing a performance issue? If it only spills a tiny amount of data to tempdb, I think it will all be done in memory and it's really not a problem...
– Tony Hinkle
1 hour ago
What happens when you add option(recompile) to the query that has spills?
– Randi Vertongen
2 hours ago
What happens when you add option(recompile) to the query that has spills?
– Randi Vertongen
2 hours ago
Here's a dbfiddle to help with getting a repro. It currently has no data, and thus produces a different plan. If you want to adjust the fiddle and post a new link, it will help us propose solutions.
– Forrest
1 hour ago
Here's a dbfiddle to help with getting a repro. It currently has no data, and thus produces a different plan. If you want to adjust the fiddle and post a new link, it will help us propose solutions.
– Forrest
1 hour ago
@randi: adding makes no difference
– Frederik Vanderhaegen
1 hour ago
@randi: adding makes no difference
– Frederik Vanderhaegen
1 hour ago
May be you can try
select r.id, LEFT(remark, 512)
(or whatever sensible substring length might be).– mustaccio
1 hour ago
May be you can try
select r.id, LEFT(remark, 512)
(or whatever sensible substring length might be).– mustaccio
1 hour ago
Is it actually causing a performance issue? If it only spills a tiny amount of data to tempdb, I think it will all be done in memory and it's really not a problem...
– Tony Hinkle
1 hour ago
Is it actually causing a performance issue? If it only spills a tiny amount of data to tempdb, I think it will all be done in memory and it's really not a problem...
– Tony Hinkle
1 hour ago
|
show 2 more comments
2 Answers
2
active
oldest
votes
There are going to be several possible workarounds here.
You can manually adjust the memory grant, though I probably wouldn't go that route.
You can also use a CTE and TOP to push the sort lower, before grabbing the max length column. It will look something like below.
WITH CTE AS (
SELECT TOP 1000000000 r.ID, s.ID AS ID2, s.typeID
FROM Resources r
inner join Settings s on resourceid=r.id
where resourceUID=@UID
ORDER BY s.typeID
)
SELECT c.ID, ca.remark
FROM CTE c
CROSS APPLY (SELECT remark FROM dbo.Settings s WHERE s.id = c.ID2) ca(remark)
ORDER BY c.typeID
Proof-of-concept dbfiddle here
Sample data would still be appreciated!
add a comment |
Why are the spills only happening when [remark] is selected?
The spill is happening when you include that column because you don't get a big enough memory grant for the large string data being sorted.
You don't get a big enough memory grant because the actual number of rows is 10x more than the estimated number of rows (1,302 actual vs 126 estimated).
Why is the estimate off? Why does SQL Server think there's only one row in dbo.Settings with a resourceid
of 38?
It could be a statistics issue, which you can check by running DBCC SHOW_STATISTICS('dbo.Settings', 'IX_Test')
and see the counts for that histogram step. But the execution plan seems to indicate that the stats are as complete and up-to-date as they could be.
Since stats aren't helping, your best bet is probably a query rewrite - which Forrest has covered in his answer.
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%2f227288%2fsort-spills-to-tempdb-due-to-varcharmax%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
There are going to be several possible workarounds here.
You can manually adjust the memory grant, though I probably wouldn't go that route.
You can also use a CTE and TOP to push the sort lower, before grabbing the max length column. It will look something like below.
WITH CTE AS (
SELECT TOP 1000000000 r.ID, s.ID AS ID2, s.typeID
FROM Resources r
inner join Settings s on resourceid=r.id
where resourceUID=@UID
ORDER BY s.typeID
)
SELECT c.ID, ca.remark
FROM CTE c
CROSS APPLY (SELECT remark FROM dbo.Settings s WHERE s.id = c.ID2) ca(remark)
ORDER BY c.typeID
Proof-of-concept dbfiddle here
Sample data would still be appreciated!
add a comment |
There are going to be several possible workarounds here.
You can manually adjust the memory grant, though I probably wouldn't go that route.
You can also use a CTE and TOP to push the sort lower, before grabbing the max length column. It will look something like below.
WITH CTE AS (
SELECT TOP 1000000000 r.ID, s.ID AS ID2, s.typeID
FROM Resources r
inner join Settings s on resourceid=r.id
where resourceUID=@UID
ORDER BY s.typeID
)
SELECT c.ID, ca.remark
FROM CTE c
CROSS APPLY (SELECT remark FROM dbo.Settings s WHERE s.id = c.ID2) ca(remark)
ORDER BY c.typeID
Proof-of-concept dbfiddle here
Sample data would still be appreciated!
add a comment |
There are going to be several possible workarounds here.
You can manually adjust the memory grant, though I probably wouldn't go that route.
You can also use a CTE and TOP to push the sort lower, before grabbing the max length column. It will look something like below.
WITH CTE AS (
SELECT TOP 1000000000 r.ID, s.ID AS ID2, s.typeID
FROM Resources r
inner join Settings s on resourceid=r.id
where resourceUID=@UID
ORDER BY s.typeID
)
SELECT c.ID, ca.remark
FROM CTE c
CROSS APPLY (SELECT remark FROM dbo.Settings s WHERE s.id = c.ID2) ca(remark)
ORDER BY c.typeID
Proof-of-concept dbfiddle here
Sample data would still be appreciated!
There are going to be several possible workarounds here.
You can manually adjust the memory grant, though I probably wouldn't go that route.
You can also use a CTE and TOP to push the sort lower, before grabbing the max length column. It will look something like below.
WITH CTE AS (
SELECT TOP 1000000000 r.ID, s.ID AS ID2, s.typeID
FROM Resources r
inner join Settings s on resourceid=r.id
where resourceUID=@UID
ORDER BY s.typeID
)
SELECT c.ID, ca.remark
FROM CTE c
CROSS APPLY (SELECT remark FROM dbo.Settings s WHERE s.id = c.ID2) ca(remark)
ORDER BY c.typeID
Proof-of-concept dbfiddle here
Sample data would still be appreciated!
answered 1 hour ago
ForrestForrest
1,932517
1,932517
add a comment |
add a comment |
Why are the spills only happening when [remark] is selected?
The spill is happening when you include that column because you don't get a big enough memory grant for the large string data being sorted.
You don't get a big enough memory grant because the actual number of rows is 10x more than the estimated number of rows (1,302 actual vs 126 estimated).
Why is the estimate off? Why does SQL Server think there's only one row in dbo.Settings with a resourceid
of 38?
It could be a statistics issue, which you can check by running DBCC SHOW_STATISTICS('dbo.Settings', 'IX_Test')
and see the counts for that histogram step. But the execution plan seems to indicate that the stats are as complete and up-to-date as they could be.
Since stats aren't helping, your best bet is probably a query rewrite - which Forrest has covered in his answer.
add a comment |
Why are the spills only happening when [remark] is selected?
The spill is happening when you include that column because you don't get a big enough memory grant for the large string data being sorted.
You don't get a big enough memory grant because the actual number of rows is 10x more than the estimated number of rows (1,302 actual vs 126 estimated).
Why is the estimate off? Why does SQL Server think there's only one row in dbo.Settings with a resourceid
of 38?
It could be a statistics issue, which you can check by running DBCC SHOW_STATISTICS('dbo.Settings', 'IX_Test')
and see the counts for that histogram step. But the execution plan seems to indicate that the stats are as complete and up-to-date as they could be.
Since stats aren't helping, your best bet is probably a query rewrite - which Forrest has covered in his answer.
add a comment |
Why are the spills only happening when [remark] is selected?
The spill is happening when you include that column because you don't get a big enough memory grant for the large string data being sorted.
You don't get a big enough memory grant because the actual number of rows is 10x more than the estimated number of rows (1,302 actual vs 126 estimated).
Why is the estimate off? Why does SQL Server think there's only one row in dbo.Settings with a resourceid
of 38?
It could be a statistics issue, which you can check by running DBCC SHOW_STATISTICS('dbo.Settings', 'IX_Test')
and see the counts for that histogram step. But the execution plan seems to indicate that the stats are as complete and up-to-date as they could be.
Since stats aren't helping, your best bet is probably a query rewrite - which Forrest has covered in his answer.
Why are the spills only happening when [remark] is selected?
The spill is happening when you include that column because you don't get a big enough memory grant for the large string data being sorted.
You don't get a big enough memory grant because the actual number of rows is 10x more than the estimated number of rows (1,302 actual vs 126 estimated).
Why is the estimate off? Why does SQL Server think there's only one row in dbo.Settings with a resourceid
of 38?
It could be a statistics issue, which you can check by running DBCC SHOW_STATISTICS('dbo.Settings', 'IX_Test')
and see the counts for that histogram step. But the execution plan seems to indicate that the stats are as complete and up-to-date as they could be.
Since stats aren't helping, your best bet is probably a query rewrite - which Forrest has covered in his answer.
answered 1 hour ago
jadarnel27jadarnel27
4,1371331
4,1371331
add a comment |
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%2f227288%2fsort-spills-to-tempdb-due-to-varcharmax%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
What happens when you add option(recompile) to the query that has spills?
– Randi Vertongen
2 hours ago
Here's a dbfiddle to help with getting a repro. It currently has no data, and thus produces a different plan. If you want to adjust the fiddle and post a new link, it will help us propose solutions.
– Forrest
1 hour ago
@randi: adding makes no difference
– Frederik Vanderhaegen
1 hour ago
May be you can try
select r.id, LEFT(remark, 512)
(or whatever sensible substring length might be).– mustaccio
1 hour ago
Is it actually causing a performance issue? If it only spills a tiny amount of data to tempdb, I think it will all be done in memory and it's really not a problem...
– Tony Hinkle
1 hour ago