Tuesday, August 13, 2013

Failure to insert in Table costs Space Loss and Decrease Performance

Failure to insert in Table costs Space Loss and Decrease Performance

Regarding the space problem of SQL server, I have collected some fact that you might be interested. It's again one things related to performance issue.
SQL Server has an issue when an INSERT fails that includes LOB data, SQL Server allocates space for the insert but does not reclaim the space on the failure therefore taking up more space than necessary.  In this tip I walk through an example of this issue and ways to resolve it.
For the test, let's create a sample test table in my TEST database.
CREATE TABLE MYSQLTEST
       (MYPKKEY   CHAR(10),
        TESTVALUE NVARCHAR(MAX)
        CONSTRAINT [PK_MYPKKEY] PRIMARY KEY CLUSTERED
                  (
                       [MYPKKEY] ASC
                  )
)
GO

Before we do any inserts, let's check the space used by the table by issuing the following command:
sp_spaceused 'MYSQLTEST', true

name          rows         reserved      data         index_size       unused
MYSQLTEST  0              0 KB            0 KB        0 KB                0 KB
Let's insert the first record.
DECLARE @TMP NVARCHAR(MAX)
SET @TMP=REPLICATE('THIS IS A TEST',4000)
INSERT MYSQLTEST(MYPKKEY,TESTVALUE) VALUES ('KEY1',@TMP)
And then check the space used again.  Here we can see that reserved is 40KB, data is 32KB for 1 row.

sp_spaceused 'MYSQLTEST', true

name          rows         reserved      data         index_size       unused
MYSQLTEST  1              40 KB          32 KB      8 KB                0 KB


Now, let's try to insert the same row again which should fail because of the PK constraint.
DECLARE @TMP NVARCHAR(MAX)
SET @TMP=REPLICATE('THIS IS A TEST',4000)
INSERT MYSQLTEST(MYPKKEY,TESTVALUE) VALUES ('KEY1',@TMP)

As expected, the insert fails because we tried to insert a duplicate primary key value. Let's check the space used again.  We can now see that reserved is 56KB, data is 48KB for 1 row.

sp_spaceused 'MYSQLTEST', true

name          rows         reserved      data         index_size       unused
MYSQLTEST  1              56 KB          48 KB      8 KB                0 KB
Now, let's run the same insert statement 100 times.
Lets check the space used again.  Now we can see reserved is 6232KB, data is 848KB for 1 row
sp_spaceused 'MYSQLTEST', true

name          rows         reserved      data         index_size       unused
MYSQLTEST  1              6232 KB      848 KB    8 KB                5376 KB

If we want to reclaim the allocated space we can run the following CLEANTABLE command where TEST is the name of my database and MYSQLTEST is my table.
DBCC CLEANTABLE(TEST,MYSQLTEST,0)

Please refer to the Microsoft Article
To Fix the Issue