<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://www2.sqlblog.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Kalen Delaney : rowsize</title><link>http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/rowsize/default.aspx</link><description>Tags: rowsize</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>Geek City: Detecting Overflowing Columns</title><link>http://www2.sqlblog.com/blogs/kalen_delaney/archive/2007/10/09/geek-city-detecting-overflowing-columns.aspx</link><pubDate>Tue, 09 Oct 2007 18:27:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:2916</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>0</slash:comments><comments>http://www2.sqlblog.com/blogs/kalen_delaney/comments/2916.aspx</comments><wfw:commentRss>http://www2.sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=2916</wfw:commentRss><description>&lt;BLOCKQUOTE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;SQL Server 2005 allows rows to include variable length columns which do not actually fit in the maximum row size of 8060 bytes. I previously posted about row-overflow columns, and discussed the maximum number of such columns that you could have in a single table. You can read that post&amp;nbsp;&lt;A href="http://sqlblog.com/blogs/kalen_delaney/archive/2007/07/16/geek-city-maximum-number-of-row-overflow-columns.aspx"&gt;here&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;Just recently I received another question that related to the section about row-overflow columns in &lt;EM&gt;Inside SQL Server 2005: The Storage Engine&lt;/EM&gt;. I described all the bytes that SQL Server needs for overhead in a data row, but I didn't mention how SQL Server knows that a column in an overflowing column or not. I mentioned that if a column is stored off the row, it leaves a 24-byte pointer behind, but how does SQL Server know that the those 24 bytes are a pointer and not an actual data value?&lt;/P&gt;
&lt;P&gt;I needed to do a little exploration to figure out the answer to that one. I'll show you some of&amp;nbsp;the tests I ran to find the answer, but first I'll just give the answer, in conjunction with a review of SQL Server's data row structure. The figure below can be found in The Storage Engine book, and the following discussion is not intended to replace the vast amount of information in that book and the complete discussion of the meaning of all the overhead bytes in each row.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://sqlblog.com/blogs/kalen_delaney/WindowsLiveWriter/c88dfe24cb20_8C45/Row%20internals%5B4%5D.jpg"&gt;&lt;IMG style="BORDER-RIGHT:0px;BORDER-TOP:0px;BORDER-LEFT:0px;BORDER-BOTTOM:0px;" height=259 src="http://sqlblog.com/blogs/kalen_delaney/WindowsLiveWriter/c88dfe24cb20_8C45/Row%20internals_thumb%5B2%5D.jpg" width=419 border=0&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;The bytes of interest here are the ones called "Column offset array", which are in the second to last position in the figure. If you have variable length columns, each of those columns uses two bytes to keep track of where on the row that column ends.&amp;nbsp;This information has to be stored with each row, because for each row, the variable length columns can be a different length. &amp;nbsp;&lt;/P&gt;
&lt;P&gt;Normally, a two byte value is a small int, which can represent values from &lt;BR&gt;-2^15 (-32,768) to 2^15-1 (32,767). Since byte offsets on the row can only be positive, negative numbers are not needed and &lt;STRONG&gt;SQL Server uses the sign bit (i.e. the high-order bit) to indicate that the column represents a row-overflow pointer and not an actual data value.&lt;/STRONG&gt;&amp;nbsp; I will show you one of the tests I ran that illustrates this. I actually ran many similar tests, and then got confirmation from someone on the SQL Server team at Microsoft that the high order bit of the column offset value is where the information is stored.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Validation:&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;First, create a table in a test database, which has the possibility of row-overflow.&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;USE testdb&lt;BR&gt;GO&lt;BR&gt;CREATE TABLE bigcols&lt;BR&gt;(a int, b varchar(8000), c varchar(8000) ) &lt;BR&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Now insert one row into the table, that is big, but will not need to overflow. The first variable length column is 8000 bytes, and the second is 24 bytes.&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;INSERT INTO bigcols&lt;BR&gt;SELECT 1, replicate('b', 8000), '123456789012345678901234'&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;USE DBCC IND to find the page number for the data page, and then use DBCC PAGE to look at the page.&amp;nbsp; In my testdb, DBCC IND indicated that the data page for this table was on file 1, page 1001. You will most likely get a different page number, so use that in your DBCC PAGE command.&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;DBCC IND (testdb, bigcols, -1)&lt;BR&gt;DBCC TRACEON(3604)&lt;BR&gt;DBCC PAGE (testdb, 1, 1001,1)&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Here is the first part of the row on page 1001:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;30000800 01000000 030060&lt;STRONG&gt;&lt;FONT color=#ff0000&gt;02 00&lt;/FONT&gt;&lt;FONT color=#00ff00&gt;511f&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#8000ff&gt;&lt;STRONG&gt;69&lt;BR&gt;1f&lt;/STRONG&gt;&lt;/FONT&gt;626262 ....&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;The &lt;FONT color=#ff0000&gt;&lt;STRONG&gt;red&lt;/STRONG&gt;&lt;/FONT&gt; bytes are number of variable length columns (2), the first variable length column offset is in &lt;FONT color=#00ff00&gt;&lt;STRONG&gt;green&lt;/STRONG&gt;&lt;/FONT&gt;, and the second column offset&amp;nbsp;is in &lt;STRONG&gt;&lt;FONT color=#8000ff&gt;blue&lt;/FONT&gt;&lt;/STRONG&gt;. 
&lt;P&gt;We have to reverse the bytes before translating, and there are two characters per byte, so the first column offset value is 0x1f51 or 8017. The second column offset is 0x1f69 or 8041, which is 24 bytes after the first. This is expected, as I inserted 24 bytes into the second variable length column. 
&lt;P&gt;I now insert another row, with a large value in the third column that will not fit on the page. 
&lt;P&gt;&lt;FONT face="Courier New"&gt;INSERT INTO bigcols&lt;BR&gt;SELECT 1, replicate('b', 8000), replicate('c', 8000)&lt;/FONT&gt; 
&lt;P&gt;Looking at DBCC IND I see that the row-overflow page is 1002 and the new data page is 1003.&amp;nbsp; Using DBCC PAGE to look at 1002 I see that it contains the c's (the last column). I then use DBCC PAGE to look at 1003. 
&lt;P&gt;&lt;FONT face="Courier New"&gt;DBCC IND (testdb, bigcols, -1)&lt;BR&gt;DBCC PAGE (testdb, 1, 1002,1)&lt;BR&gt;DBCC PAGE (testdb, 1, 1003,1)&lt;/FONT&gt; 
&lt;P&gt;Here is the first part of the row on page 1003:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="courier new"&gt;30000800 01000000 030060&lt;STRONG&gt;&lt;FONT color=#ff0000&gt;02 00&lt;/FONT&gt;&lt;FONT color=#00ff00&gt;511f&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;FONT face="courier new"&gt;&lt;FONT color=#8000ff&gt;&lt;STRONG&gt;69&lt;BR&gt;9f&lt;/STRONG&gt;&lt;/FONT&gt;626262 ....&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;The only difference from the first row, with no row-overflow columns, is the offset of the second variable length column. Interpreting 0x9f69 as an unsigned integer gives us 40809, which is obviously not an offset in a row, since it is 5 times more than the number of bytes allowed in a row. So instead, convert to binary 1001111101101001 and notice the high order 1. Now change that 1 to 0 giving 0001111101101001 and convert that to decimal. It gives us 8041, again indicating that the second variable length column ends 24 bytes after the first. The only difference is that SQL Server will interpret those 24 bytes in the second row as a pointer to row-overflow data and will interpret those 24 bytes in the first&amp;nbsp;row as the real data in the column.&lt;/P&gt;
&lt;P&gt;For more information about using DBCC IND and DBCC PAGE, you can read Inside SQL Server or some of &lt;A href="http://www.sqlmag.com/Authors/AuthorID/185/185.html"&gt;my articles in SQL Server Magazine&lt;/A&gt;. Or you can read the Microsoft SQL Server Storage Engine blog. &lt;A href="http://blogs.msdn.com/sqlserverstorageengine/archive/2006/12/13/More-undocumented-fun_3A00_-DBCC-IND_2C00_-DBCC-PAGE_2C00_-and-off_2D00_row-columns.aspx"&gt;Here is a post&lt;/A&gt; by Paul Randal, showing the use of DBCC IND and DBCC PAGE. The post explains the output of DBCC IND, and includes links to other posts that explain DBCC PAGE.&lt;/P&gt;
&lt;P&gt;Have fun!&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff00ff&gt;~Kalen&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://www2.sqlblog.com/aggbug.aspx?PostID=2916" width="1" height="1"&gt;</description><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/DBCC/default.aspx">DBCC</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/internals/default.aspx">internals</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/row-overflow/default.aspx">row-overflow</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/rowsize/default.aspx">rowsize</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/storage/default.aspx">storage</category></item><item><title>Geek City: Maximum Number of Row-overflow columns</title><link>http://www2.sqlblog.com/blogs/kalen_delaney/archive/2007/07/16/geek-city-maximum-number-of-row-overflow-columns.aspx</link><pubDate>Mon, 16 Jul 2007 22:45:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:1758</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>7</slash:comments><comments>http://www2.sqlblog.com/blogs/kalen_delaney/comments/1758.aspx</comments><wfw:commentRss>http://www2.sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=1758</wfw:commentRss><description>&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I received a question from one of my readers that concerned this paragraph in &lt;EM&gt;Inside SQL Server 2005: The Storage Engine&lt;/EM&gt;. 
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;The number of large variable-length columns that a table can have is not &lt;BR&gt;unlimited, although it is quite large. There is a limit of 1,024 columns &lt;BR&gt;in any table, so that is definitely a limit there. But another limit will &lt;BR&gt;be reached before that. When a column has to be moved off a regular page &lt;BR&gt;onto a row-overflow page, SQL Server keeps a pointer to the row-overflow &lt;BR&gt;information as part of the original row. The pointer is always 24 bytes, &lt;BR&gt;and the row still needs 2 bytes in the row for each variable-length &lt;BR&gt;column, whether or not the variable-length column is stored in the row. So &lt;BR&gt;it turns out that 308 is the maximum number of overflowing columns we can &lt;BR&gt;have, and such a row needs 8,008 bytes just for the 26 overhead bytes for &lt;BR&gt;each overflowing column in the row.&lt;/EM&gt; &lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Here is the question: I understood that 26 bytes overhead is required for each overflowing column&lt;BR&gt;in the row but not able to understand how you calculated 308 figure. Please explain. &lt;/P&gt;
&lt;P&gt;Ok, I will. &lt;/P&gt;
&lt;P&gt;In SQL Server 2005, the maximum number of bytes for any row, including the constant overhead bytes, is 8060. (A row might actually have 14 additional overhead bytes if it has been modified under one of the snapshot-based isolation levels, and those 14 bytes increase the maximum to 8074.) In addition to the bytes mentioned above, every row needs a few other overhead bytes:&lt;/P&gt;
&lt;P&gt;2 bytes: row status information&lt;BR&gt;2 bytes: length of the fixed length portion of the row&lt;BR&gt;2 bytes: number of columns&lt;BR&gt;1 bit per column: NULL bitmap (rounded up to whole number of bytes)&lt;BR&gt;2 bytes: row-offset location (stored at the end of the page)&lt;BR&gt;2 bytes: number of variable length columns (only IF there are any, otherwise these bytes aren't used)&lt;/P&gt;
&lt;P&gt;If we subtract 11 bytes from 8060 and divide by the 26 bytes each row-overflow column needs, the result is 309 and a fraction. However, if we actually had 309 columns in the table, each would need a bit in the bitmap and 309 bits needs&amp;nbsp;39 bytes. &lt;/P&gt;
&lt;P&gt;So for 309 overflowing columns, we would need 309 *26 + 10 overhead bytes + 39 bytes for the NULL bitmap, which is 8083 bytes, and is longer than the maximum row size.&lt;/P&gt;
&lt;P&gt;For 308 overflowing columns, we would need 308 *26 + 10 overhead bytes + 39 bytes, which is 8057 bytes, and that will fit in a single row.&lt;/P&gt;
&lt;P&gt;More details can be found in &lt;EM&gt;Inside SQL Server 2005: The Storage Engine&lt;/EM&gt;.&lt;/P&gt;
&lt;P&gt;Have fun!&lt;/P&gt;
&lt;P&gt;&lt;A href="http://sqlblog.com/blogs/kalen_delaney/WindowsLiveWriter/GeekCityMaximumNumberofRowoverflowcolumn_E3C0/ambi%5B1%5D.png"&gt;&lt;IMG style="BORDER-RIGHT:0px;BORDER-TOP:0px;BORDER-LEFT:0px;BORDER-BOTTOM:0px;" height=140 src="http://sqlblog.com/blogs/kalen_delaney/WindowsLiveWriter/GeekCityMaximumNumberofRowoverflowcolumn_E3C0/ambi.png" width=240 border=0&gt;&lt;/A&gt;&lt;/P&gt;&lt;img src="http://www2.sqlblog.com/aggbug.aspx?PostID=1758" width="1" height="1"&gt;</description><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/internals/default.aspx">internals</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/row-overflow/default.aspx">row-overflow</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/rowsize/default.aspx">rowsize</category></item><item><title>Did you know? -- Altering the length of a fixed-length column</title><link>http://www2.sqlblog.com/blogs/kalen_delaney/archive/2006/10/13/alter-table-will-not-reclaim-space.aspx</link><pubDate>Fri, 13 Oct 2006 16:33:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:301</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>14</slash:comments><comments>http://www2.sqlblog.com/blogs/kalen_delaney/comments/301.aspx</comments><wfw:commentRss>http://www2.sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=301</wfw:commentRss><description>&lt;P&gt;You may be well aware that if you alter the length of a column to a larger value, that SQL Server doesn’t go through all the rows at the time you issue the ALTER. The ALTER is a metadata only change, and the actual movement of data doesn’t happen until a row is updated. &lt;/P&gt;
&lt;P&gt;However, SQL Server does not reuse the original bytes in the row when a row’s length is altered. You may end up not being able to use the full allowable row length if you’ve altered column lengths. &lt;/P&gt;
&lt;P&gt;Here’s the example. Create a table with two large &lt;I style="mso-bidi-font-style:normal;"&gt;char&lt;/I&gt; columns and a &lt;I style="mso-bidi-font-style:normal;"&gt;smallint&lt;/I&gt;. The initial length of each row will be just a bit more than 3000 bytes, out of a maximum row length of 8060 bytes. &lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;CREATE TABLE bigchange&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;(col1 smallint, col2 char(2000), col3 char(1000));&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;GO&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;Now alter the second column to increase its length to 3000 bytes. The length of a row should now be just a bit more than 4000 bytes.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;ALTER TABLE bigchange &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;ALTER COLUMN col2 char(3000);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;GO&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="FONT-SIZE:14pt;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;Now try and add another 3000 byte column, which should bring the length to just over 7000 bytes. This will fail:&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="FONT-SIZE:14pt;COLOR:green;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;ALTER TABLE bigchange &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;ADD col4 char(3000);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="FONT-SIZE:8pt;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;Msg 1701, Level 16, State 1, Line 1&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="FONT-SIZE:8pt;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;Creating or altering table 'bigchange' failed because the minimum row size would be 9009, including 7 bytes of internal overhead. This exceeds the maximum allowable table row size of 8060 bytes.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;However, if you just create a table with two 3000-byte columns and a 1000-byte column, there will be no problem.&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="FONT-SIZE:14pt;COLOR:green;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;CREATE TABLE nochange&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;(col1 smallint, col2 char(3000), col3 char(1000), col4 char(3000));&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;GO&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="FONT-SIZE:14pt;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;Here’s a query you can run to see the metadata for where each column will start. Run it against the &lt;I style="mso-bidi-font-style:normal;"&gt;bigchange&lt;/I&gt; table:&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="FONT-SIZE:14pt;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;SELECT&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/SPAN&gt;c.name AS column_name, column_id, max_inrow_length,&lt;BR&gt;&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;pc.system_type_id, leaf_offset &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&lt;/SPAN&gt;FROM sys.system_internals_partition_columns pc&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;JOIN sys.partitions p &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;&lt;SPAN style="mso-tab-count:1;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;ON p.partition_id = pc.partition_id&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;JOIN sys.columns c&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;ON column_id = partition_column_id &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;AND c.object_id = p.object_id&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;WHERE p.object_id=object_id('bigchange');&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:blue;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;GO&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="FONT-SIZE:14pt;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;Here’s my results:&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="FONT-SIZE:8pt;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;column_name&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;column_id&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;max_inrow_length system_type_id leaf_offset&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="FONT-SIZE:8pt;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;------------- ----------- ---------------- -------------- -----------&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="FONT-SIZE:8pt;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;col1&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;1&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;2&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;52&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;4&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="FONT-SIZE:8pt;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;col2&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;2&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;3000&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;175&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;3006&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="FONT-SIZE:8pt;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;col3&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;3&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;1000&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;175&lt;SPAN style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;2006&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="FONT-SIZE:8pt;FONT-FAMILY:'Courier New';mso-no-proof:yes;"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;Note that col1 is only 2 bytes long, and starts at offset 4 (after the row header information) but that the next column doesn’t start until offset 2006. Bytes 6 – 2005, the original 2000 bytes for col2, are not used for anything now.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;So be careful when using large datatypes, especially if you want to make them fixed length instead of variable length.&lt;SPAN style="FONT-SIZE:14pt;FONT-FAMILY:'Courier New';"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="FONT-SIZE:14pt;FONT-FAMILY:'Courier New';"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0pt;mso-layout-grid-align:none;"&gt;&lt;SPAN style="COLOR:#cc99ff;"&gt;-- Kalen&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;img src="http://www2.sqlblog.com/aggbug.aspx?PostID=301" width="1" height="1"&gt;</description><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/ALTER+TABLE/default.aspx">ALTER TABLE</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/rowsize/default.aspx">rowsize</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/storage/default.aspx">storage</category></item></channel></rss>