Search
Active

2
Sign in to vote
0
Sign in to vote
Sign in
to vote
Type: Bug
ID: 508112
Opened: 11/4/2009 2:06:34 AM
Access Restriction: Public
0
Workaround(s)
0
User(s) can reproduce this bug
The new row constructor syntax of SQL Server 2008 to insert several rows is a quiet neat feature, unfortunately the performance is quiet bad. I really thought this would be a great performance optimization and a replacement for the old UNION ALL concatenated rows to add all rows in one bulk. In addition I really don’t understand the restriction to 1000 rows.

If this becomes optimized in future versions this might be a optimization (for time duration and network traffic) for client libraries like ADO.NET. Currently - including .NET 4.0 - ADO creates single insert statements to send a table-valued parameter from client to server.

My tests showed me that single INSERT statements are currently more than ten times (!) faster than using the row constructor. Due to this I don’t really understand the reason for the introduction of the row constructor, since it was already available by using UNION ALL.
Details (expand)
Product Language
English

Version

SQL Server 2008 - Developer Edition

Category

SQL Engine

Operating System

Windows XP SP2 Professional
Operating System Language
English
Steps to Reproduce
SET NOCOUNT ON;
USE tempdb;
GO
-- create table
CREATE TABLE TestInserts
(
Id INT NOT NULL IDENTITY(1,1)
PRIMARY KEY CLUSTERED
,SomeInt INT
,SomeText VARCHAR(20)
);
GO
-- variables for INSERT statements
DECLARE
@sqlInserts NVARCHAR(MAX)
,@sqlRows NVARCHAR(MAX)
,@sqlUnion NVARCHAR(MAX)
;
-- create INSERT statements
WITH cte (Num) AS
(
SELECT TOP(1000)
CONVERT(VARCHAR(20), Number)
FROM master.dbo.spt_values WHERE type = 'P'
)
SELECT
-- single inserts
@sqlInserts = (
SELECT 'INSERT INTO TestInserts VALUES (' + Num + ', ''Text: ' + Num + ''');' + CHAR(10)
FROM cte
FOR XML PATH('')
)
-- using 2008 row constructor notation
,@sqlRows =
'INSERT INTO TestInserts VALUES ' + CHAR(10)
+ STUFF(
(
SELECT ',(' + Num + ', ''Text: ' + Num + ''')' + CHAR(10)
FROM cte
FOR XML PATH('')
)
,1,1,N'')
-- using UNION ALL notation
,@sqlUnion =
'INSERT INTO TestInserts ' + CHAR(10)
+ STUFF(
(
SELECT 'UNION ALL SELECT ' + Num + ', ''Text: ' + Num + '''' + CHAR(10)
FROM cte
FOR XML PATH('')
)
,1,10,N'')
DECLARE
@now DATETIME2
,@offset INT;
-- exec single inserts
SELECT @now = SYSDATETIME();
EXECUTE sp_executesql @sqlInserts;
SELECT @offset = DATEDIFF(MILLISECOND, @now, SYSDATETIME());
PRINT ('Single Inserts: ' + CONVERT(VARCHAR(10), @offset) + 'ms');
-- exec row constructors
SELECT @now = SYSDATETIME();
EXECUTE sp_executesql @sqlRows;
SELECT @offset = DATEDIFF(MILLISECOND, @now, SYSDATETIME());
PRINT ('Row Constructor: ' + CONVERT(VARCHAR(10), @offset) + 'ms');
-- exec UNION ALL
SELECT @now = SYSDATETIME();
EXECUTE sp_executesql @sqlUnion;
SELECT @offset = DATEDIFF(MILLISECOND, @now, SYSDATETIME());
PRINT ('Union All: ' + CONVERT(VARCHAR(10), @offset) + 'ms');
Actual Results
Test results for the provided script:
Single Inserts: 156ms
Row Constructor: 1860ms
Union All: 1875ms
Expected Results
A way better performance of the row constructor.
It should definitely be faster than UNION ALL statements and many single INSERT statements. Databases are made to work in bulk operations and these bulk operations should be way faster than all other approaches.
Platform
32
File Attachments
0 attachments
Sign in to post a comment.
Posted by Microsoft on 11/23/2009 at 10:21 AM
Hi Florian,

This is a defect in the query optimizer which will be fixed in the next major release of SQL Server. I am not sure right now if this will make it into SQL Server 2008/R2.

Thanks for you help!
- Tobias, SQL Server Engine