Large row support

Slot array

As rows on a page are deleted or updated over time, free space might appear among

remaining rows. When a new row is added, it might be stored in this free space, if the space is

sufficient. This means that rows on a page might not be physically stored in any particular

order. However, the Database Engine maintains the slot array entries in a logical order. As a

result, rows on a page are also accessed in a logical order, for example the order defined by

the key of the BTree index that owns the page.

To support large rows that don’t fit on a single page, the part of the row that doesn’t fit can be

stored on other pages. The maximum size of data and overhead that can be contained in a

single row on a page is 8,060 bytes.

The 8,060-byte restriction doesn’t apply to the data in the columns using the LOB data types.

By default for such columns, the data is stored in row if there’s sufficient space. Otherwise, the

row contains a 16-byte pointer to a separate tree of text/LOB pages storing the LOB data in a

allocation unit. The

table option

controls this

behavior.

varchar(7000)

varchar(2000)

varchar(7000)

varchar(max)

nvarchar(max)

varbinary(max)

The 8,060-byte restriction is relaxed for tables and indexes that contain variable length

columns using the

,

,

,

sql_variant

, or CLR user-defined data types.

When the total row size of all fixed and variable length columns in a heap or index exceeds the

8,060-byte limitation, the Database Engine dynamically moves one or more variable length

columns to pages in a

allocation unit, starting with the widest column.

This is done whenever an insert or update operation increases the total size of the row beyond

the 8,060-byte limit. When a column is moved to a page in a

allocation unit,

a 24-byte pointer on the original page in a

allocation unit is maintained. If a

subsequent operation reduces the row size, the Database Engine dynamically moves the

columns back to the original data page.

For example, a table can be created with two columns: one

and another. Individually, neither column exceeds 8,060 bytes, but combined they would do

so if the entire width of each column is filled. If this happens, the Database Engine dynamically

moves the

variable length column from the original page to the pages in a

allocation unit.

When a table or an index has

,

,

,

sql_variant

, or CLR user-defined

type columns that can exceed 8,060 bytes per row, consider the following:

Moving large rows to another page occurs dynamically as rows are lengthened based on

update operations. Update operations that shorten rows can cause them to be moved

back to the original page in a

allocation unit.

This data movement results in extra disk I/O. Query processing operations such as sorts

or joins on large records that contain row-overflow data might be slower.

Therefore, when you design a table with multiple

,

,

,

sql_variant

, or CLR user-defined type columns, consider the percentage of rows that are

likely to flow over and the frequency with which this overflow data is likely to be queried.

To avoid slower performance, normalize the table to move some of these columns to

another table to reduce or eliminate the likelihood of using row-overflow storage.

The length of individual columns must still fall within the limit of 8,000 bytes for

,

,

,

sql_variant

, and CLR user-defined type columns. Only their

combined lengths can exceed the 8,060-byte row limit of a table.

The sum of the lengths of other data type columns, for example

,

, and

data,

must still be within the 8,060-byte row limit. However, columns using the LOB data types

such as

,

, and

are exempt from the 8,060-

byte row limit.

Uniform

Mixed

LOB_DATA

large value types out of row

ROW_OVERFLOW_DATA

ROW_OVERFLOW_DATA

IN_ROW_DATA

ROW_OVERFLOW_DATA

IN_ROW_DATA