SQL Server How many bytes are used to store a null value in an nvarchar(n) column?

zxlwwiss  于 2023-10-15  发布在  其他
关注(0)|答案(3)|浏览(83)

We are designing a new database, and need to know if a nvarchar(n) column will use any bytes to store a null value?

  1. If a nvarchar(n) column stores a null value, how many bytes are used?
  2. How many bytes are used to store and empty string in a nvarchar(n) ? (i.e."")
shyt4zoc

shyt4zoc1#

The correct answer for how much space a NULL VARCHAR in SQL Server is, "It Depends". You'll find similar with NVARCHAR.

Note that this does not take into account ROW or PAGE Compression. This is all just for what happens in a "normal" table.

Here's a test table...

CREATE TABLE dbo.VarcharTest01
        (
         C01 INT         NOT NULL
        ,C02 VARCHAR(10) NULL
        ,C03 VARCHAR(10) NULL
        ,C04 VARCHAR(10) NULL
        ,C05 VARCHAR(10) NULL
        ,C06 VARCHAR(10) NULL
        ,C07 INT         NULL
        ,C08 VARCHAR(10) NULL
        ,C09 VARCHAR(10) NULL
        ,C10 VARCHAR(10) NULL
        ,C11 VARCHAR(10) NULL
        ,C12 VARCHAR(10) NULL
        ,CONSTRAINT PK_VarcharTest01 
         PRIMARY KEY CLUSTERED (c01)
        )
;
--===== Add 1 row, populating only the INT columns.
 INSERT INTO dbo.VarcharTest01
        (C01,C07)
 VALUES (1,-1)
;
--===== Display the data
 SELECT * FROM dbo.VarcharTest01
;

Example 1: All VARCHARS = NULL

Here are what the contents of the table look like:

Using DBCC PAGE (too long to go into here and I formatted the output for easy understanding), we get the following dump of what the row looks like.

Note that all hex values are "BIG ENDIAN". Width of Null Bitmap is (ColCnt-1)/8+1 = (12-1)/8+1 = 2

Note that NOTHING about the 10 VARCHAR columns appears in the row. It's because they're all NULL.

Last                             
Meta  Fixd                   All  NULL 
Data  Byte                   Col  Bit  
A  B  OffS   C01      C07    Cnt  Map  
-- -- ---- -------- -------- ---- ---- 
1  2  3 4  5 6 7 8  9 101112 1314 1516 Decimal Byte Number
-- -- ---- -------- -------- ---- ---- 
10 00 0c00 01000000 ffffffff 0c00 be0f

So one of the answers for how many bytes a NULL value is is absolutely ZERO.

Example 2: Empty Strings

If we populate the C02 column with an "Empty String", only the bitmap changes to say the column is no longer a NULL but nothing else happens... so one of the answers for how much an "Empty String" takes is Zero. In all cases, an "Empty String" occupies the same space as a NULL (and that can change as we'll soon see). Only the bitmap is changed to say column C02 no longer a NULL.

--===== Update the C02 column to an "Empty String"
 UPDATE dbo.VarcharTest01
    SET C02 = ''
;
--===== Display the data
 SELECT * FROM dbo.VarcharTest01
;

Here are the DBCC PAGE results from that. Note that ONLY the bitmap changed in valued.

Last                             
Meta  Fixd                   All  NULL 
Data  Byte                   Col  Bit  
A  B  OffS   C01      C07    Cnt  Map  
-- -- ---- -------- -------- ---- ---- 
1  2  3 4  5 6 7 8  9 101112 1314 1516 Decimal Byte Number
-- -- ---- -------- -------- ---- ---- 
10 00 0c00 01000000 ffffffff 0c00 bc0f

Example 3: First Non-Null Variable Width Column - 5 Bytes

If we populate column C02 with an "A", it will take 5 bytes!

--===== Update the C02 column to an "A"
 UPDATE dbo.VarcharTest01
    SET C02 = 'A'
;
--===== Display the data
 SELECT * FROM dbo.VarcharTest01
;

Here are what the content's of the table look like now...

Where do the 5 bytes come from? Two for the "Variable Width column count", two for the "1st Variable Width Column Offset" (it does NOT store the length of the column!), and 1 for the single byte entry of "A". Here are the formatted results from DBCC PAGE that show all that...

Last                             Var    
Meta  Fixd                   All  NULL Wdth 1st  
Data  Byte                   Col  Bit  Col  VCol C
A  B  OffS   C01      C07    Cnt  Map  Cnt  OffS 02
-- -- ---- -------- -------- ---- ---- ---- ---- --
1  2  3 4  5 6 7 8  9 101112 1314 1516 1718 1920 21 Decimal Byte Number
-- -- ---- -------- -------- ---- ---- ---- ---- --
30 00 0c00 01000000 ffffffff 0c00 bc0f 0100 1500 41

Note that the same thing that happened with adding the letter "A" is also what will happen if you add a single space (' ').

Example 4: 2 Bytes per NULL to the left of any populated VARCHAR

Let's add the letter "G" to C08.

--===== Update the C08 column to an "G"
 UPDATE dbo.VarcharTest01
    SET C08 = 'G'
;
--===== Display the data
 SELECT * FROM dbo.VarcharTest01
;

Here are what the contents of the table looks like now:

And here are the formatted results from DBCC PAGE... get ready for a shock!

Last                             Var  C02  C03  C04  C05  C06  C08
Meta  Fixd                   All  NULL Wdth 1st  2nd  3rd  4th  5th  6th  
Data  Byte                   Col  Bit  Col  Col  Col  Col  Col  Col  Col  C  C
A  B  OffS   C01      C07    Cnt  Map  Cnt  OffS OffS OffS OffS OffS OffS 02 08
-- -- ---- -------- -------- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- --
1  2  3 4  5 6 7 8  9 101112 1314 1516 1718 1920 2122 2324 2526 2728 2930 31 32 Decimal Byte Number
-- -- ---- -------- -------- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- --
30 00 0c00 01000000 ffffffff 0c00 3c0f 0600 1f00 1f00 1f00 1f00 1f00 2000 41 47

EVERY NULL VARCHAR COLUMN TO THE LEFT OF THE RIGHT-MOST POPULATED COLUMN HAS 2 BYTES ADDED TO THE ROW FOR STARTING POSITIONS THAT DON'T MATTER because the BitMap still says they're NULL.

And notice that nothing has yet shown up for columns C09 through C12. That's because there are no populated variable width columns to the right of of them.

So adding that 1 byte to C08 (the 6th VARCHAR column from the "left") caused an extra 2 bytes to appear for EVERY NULL VARCHAR column to the left of it and 2 extra bytes for itself!

My recommendation to everyone that uses a variable width "Created_By" column at the far "right" of the table is to stop doing that! :D Plan your variable width columns to appear from left to right from least sparse to most sparse. That means that your "Created_By" column should probably be the first (reading the columns left to right) of the variable width columns. :D

And, sure... you could use "SPARSE" columns but at a cost of an additional 4 bytes per entry, it might not be worth it and the MS documentation on that subject is worth a heavy study before using "SPARSE" columns.

So, the correct answers to the original and some of the follow on claims are...

In SQL Server, "It Depends"...

A NULL VARCHAR (or NVARCHAR) can take 0 or 2 bytes depending on whether or not there are any populated variable width columns to the right of it.

And "Empty Strings" work exactly the same way as NULLs concerning space used. It will also change the corresponding bit in the bitmap from "1" to "0".

jm81lzqq

jm81lzqq2#

Empty string will use 2 bytes. More details at: nchar-and-nvarchar
NULL will use 1 bit in the NULL bitmap.

7gyucuyw

7gyucuyw3#

It is a physical implementation detail, so it could be different for Oracle an for SQL Server. With SQL Server, NULLs a represented with a single bit in the null bitmap (one bit for each nullable column). An empty string, be it varchar or nvarchar, it's two bytes. Hope someone from Oracle side will complement.

相关问题