<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>SQL Server with Mr. Denny &#187; Database Administration</title>
	<atom:link href="http://itknowledgeexchange.techtarget.com/sql-server/tag/database-administration/feed/" rel="self" type="application/rss+xml" />
	<link>http://itknowledgeexchange.techtarget.com/sql-server</link>
	<description></description>
	<lastBuildDate>Mon, 10 Jun 2013 17:25:32 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>Extra Bytes Per Row With AlwaysOn Availability Groups</title>
		<link>http://itknowledgeexchange.techtarget.com/sql-server/extra-bytes-per-row-with-alwayson-availability-groups/</link>
		<comments>http://itknowledgeexchange.techtarget.com/sql-server/extra-bytes-per-row-with-alwayson-availability-groups/#comments</comments>
		<pubDate>Tue, 28 May 2013 16:27:36 +0000</pubDate>
		<dc:creator>Denny Cherry</dc:creator>
				<category><![CDATA[AlwaysOn]]></category>
		<category><![CDATA[Database Administration]]></category>
		<category><![CDATA[Execution Plans]]></category>
		<category><![CDATA[Index]]></category>
		<category><![CDATA[Index Performance]]></category>
		<category><![CDATA[Index Seek]]></category>
		<category><![CDATA[Indexing]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQL Server 2012]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/sql-server/?p=2676</guid>
		<description><![CDATA[One of things to keep in mind with SQL Server 2012 AlwaysOn Availability Groups is that when the availability group has readable secondary replicas any rows that are changed will have an additional 14 bytes added to each row.  These 14 bytes are used by the readable secondary to handle the read committed snapshot isolation [...]]]></description>
				<content:encoded><![CDATA[<p>One of things to keep in mind with SQL Server 2012 AlwaysOn Availability Groups is that when the availability group has readable secondary replicas any rows that are changed will have an additional 14 bytes added to each row.  These 14 bytes are used by the readable secondary to handle the read committed snapshot isolation level (RCSI) so that the readable secondary replicas work correctly.</p>
<p>To look at what’s going on lets create a sample new table in a table and take a peak at the data.  To setup this test we create a new database and setup that database for use with AlwaysOn Availability Groups.  The availability group is setup with no readable secondary replicas.</p>
<blockquote><p>create table MyTest (c1 int identity(1,1),<br />
c2 int,<br />
c3 varchar(100))<br />
GO<br />
insert into MyTest<br />
(c2, c3)<br />
values<br />
(1, &#8216;test&#8217;)<br />
GO 400</p></blockquote>
<p>This creates a new table in the database with 400 rows in it.  Looking at the output from DBCC IND we can see that this table takes up 2 data pages with a root page (this will become important later on).</p>
<p>Looking at the data for the first data page we can see the following information.</p>
<blockquote><p>Slot 0 Offset 0&#215;60 Length 23</p>
<p>Record Type = PRIMARY_RECORD        Record Attributes =  NULL_BITMAP VARIABLE_COLUMNS<br />
Record Size = 23<br />
Memory Dump @0x000000003CACA060</p>
<p>0000000000000000:   30000c00 01000000 01000000 03000001 00170074  0&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;t<br />
0000000000000014:   657374                                        est</p>
<p>Slot 0 Column 1 Offset 0&#215;4 Length 4 Length (physical) 4</p>
<p>c1 = 1</p>
<p>Slot 0 Column 2 Offset 0&#215;8 Length 4 Length (physical) 4</p>
<p>c2 = 1</p>
<p>Slot 0 Column 3 Offset 0&#215;13 Length 4 Length (physical) 4</p>
<p>c3 = test</p>
<p>Slot 0 Offset 0&#215;0 Length 0 Length (physical) 0</p>
<p>KeyHashValue = (8194443284a0)</p></blockquote>
<p>When we update this row changing the value of c2 to equal 2 nothing really changes which we can see from DBCC PAGE again.</p>
<blockquote><p>Slot 0 Offset 0&#215;60 Length 23</p>
<p>Record Type = PRIMARY_RECORD        Record Attributes =  NULL_BITMAP VARIABLE_COLUMNS<br />
Record Size = 23<br />
Memory Dump @0x000000003EECA060</p>
<p>0000000000000000:   30000c00 01000000 02000000 03000001 00170074  0&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;t<br />
0000000000000014:   657374                                        est</p>
<p>Slot 0 Column 1 Offset 0&#215;4 Length 4 Length (physical) 4</p>
<p>c1 = 1</p>
<p>Slot 0 Column 2 Offset 0&#215;8 Length 4 Length (physical) 4</p>
<p>c2 = 2</p>
<p>Slot 0 Column 3 Offset 0&#215;13 Length 4 Length (physical) 4</p>
<p>c3 = test</p>
<p>Slot 0 Offset 0&#215;0 Length 0 Length (physical) 0</p>
<p>KeyHashValue = (8194443284a0)</p></blockquote>
<p>Next I’ve changed the settings for the availability group to support readable secondary replicas.  Once that change has been made we change the value of c2 for the same row to equal the value of 3.  Again we can look at this with DBCC PAGE.</p>
<blockquote><p>Slot 0 Offset 0x1d4e Length 37</p>
<p>Record Type = PRIMARY_RECORD        Record Attributes =  NULL_BITMAP VARIABLE_COLUMNS VERSIONING_INFO<br />
Record Size = 37<br />
Memory Dump @0x000000003AEEBD4E</p>
<p>0000000000000000:   70000c00 01000000 03000000 03000001 00170074  p&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;t<br />
0000000000000014:   65737400 00000000 0000000f 06000000 00        est&#8230;&#8230;&#8230;&#8230;..</p>
<p>Version Information =<br />
Transaction Timestamp: 1551<br />
Version Pointer: Null</p>
<p>Slot 0 Column 1 Offset 0&#215;4 Length 4 Length (physical) 4</p>
<p>c1 = 1</p>
<p>Slot 0 Column 2 Offset 0&#215;8 Length 4 Length (physical) 4</p>
<p>c2 = 3</p>
<p>Slot 0 Column 3 Offset 0&#215;13 Length 4 Length (physical) 4</p>
<p>c3 = test</p>
<p>Slot 0 Offset 0&#215;0 Length 0 Length (physical) 0</p>
<p>KeyHashValue = (8194443284a0)</p></blockquote>
<p>Looking at these two outputs from DBCC PAGE we can see a couple of differences.  First we see an additional value in the “Record Attributes” field which adds in VERSIONING_INFO to the value.  We also see that the record size has changed from 32 to 37.  Additionally we see that the Version Information has been added.</p>
<p>Looking at the DBCC PAGE output on one of the replicas for the same page as before we see some different information.</p>
<blockquote><p>Slot 0 Offset 0x1d4e Length 37</p>
<p>Record Type = PRIMARY_RECORD        Record Attributes =  NULL_BITMAP VARIABLE_COLUMNS VERSIONING_INFO<br />
Record Size = 37<br />
Memory Dump @0x000000003893BD4E</p>
<p>0000000000000000:   70000c00 01000000 03000000 03000001 00170074  p&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;t<br />
0000000000000014:   65737440 01000001 0000000f 06000000 00        est@&#8230;&#8230;&#8230;&#8230;.</p>
<p>Version Information =<br />
Transaction Timestamp: 1551<br />
Version Pointer: (file 1 page 320 currentSlotId 0)</p>
<p>Slot 0 Column 1 Offset 0&#215;4 Length 4 Length (physical) 4</p>
<p>c1 = 1</p>
<p>Slot 0 Column 2 Offset 0&#215;8 Length 4 Length (physical) 4</p>
<p>c2 = 3</p>
<p>Slot 0 Column 3 Offset 0&#215;13 Length 4 Length (physical) 4</p>
<p>c3 = test</p>
<p>Slot 0 Offset 0&#215;0 Length 0 Length (physical) 0</p>
<p>KeyHashValue = (8194443284a0)</p></blockquote>
<p>Specifically at this point we see that the Version Pointer now has a value in it. This tells us that the SQL Server has put a copy of the original page into the tempdb database so that we can read it.</p>
<p>A question comes up as to what happens to the page when this row information is added.  Specifically does the page split because of this additional 14 bytes of new data per row.  The answer to this question is “it depends”.  In my testing that I did when I updated a single row the page didn’t split, mostly this would be because there was some free space in the database page.  When I updated rows 2-40 and looked at DBCC IND I saw that in fact the page had split.</p>
<p>Looking at the values within the page there are now 159 rows in the page which was the original database page when there were 322 rows within the database page.  The remainder of the rows were copied into a new database page.</p>
<p>Now that we’ve identified that SQL Server is going to be page splitting older database pages, potentially like crazy what can we do about it?  The answer to that question is to just deal with it and to decrease the fill factor as needed so that page splits happen as little as possible.</p>
<p>To make matters worse when we rebuild the index on the table and look at the output from DBCC PAGE again we can see that the additional flag has been removed from row 1 (seen below).  This tells us that no only will this problem come up the first time that data is modified, it’ll come up every time that index rebuilds are done when the data is changed for the first time after the rebuild.</p>
<blockquote><p>Slot 0 Offset 0&#215;60 Length 23</p>
<p>Record Type = PRIMARY_RECORD        Record Attributes =  NULL_BITMAP VARIABLE_COLUMNS<br />
Record Size = 23<br />
Memory Dump @0x000000003E0CA060</p>
<p>0000000000000000:   30000c00 01000000 03000000 03000001 00170074  0&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;t<br />
0000000000000014:   657374                                        est</p>
<p>Slot 0 Column 1 Offset 0&#215;4 Length 4 Length (physical) 4</p>
<p>c1 = 1</p>
<p>Slot 0 Column 2 Offset 0&#215;8 Length 4 Length (physical) 4</p>
<p>c2 = 3</p>
<p>Slot 0 Column 3 Offset 0&#215;13 Length 4 Length (physical) 4</p>
<p>c3 = test</p>
<p>Slot 0 Offset 0&#215;0 Length 0 Length (physical) 0</p>
<p>KeyHashValue = (8194443284a0)</p></blockquote>
<p><span style="color: #000000">Changing the data again, this time changing the first 40 rows (id values 1-40) the new flag comes into place as expected.  If we reorganize the index instead of doing a rebuild this time the flags are left in place.</span></p>
<p><span style="color: #000000">This tells us that the better option for doing index maintenance on databases which are being protected by AlwaysOn Availability Groups is going to be to use reorganize commands instead of rebuild commands.  This way the 14 byte pointer isn’t removed from the rows so that when they are modified the additional 14 bytes of data doesn’t need to be added.</span></p>
<p>If you’ve got rows which are changed all the time then this will be a way to handle it.  If the rows never change after the data is reorged then it may or may not be something worth worrying about.</p>
<p><span style="color: #000000">Hopefully this helps answer the questions of what these extra bytes are for and how we can deal with them. </span></p>
<p><span style="color: #000000">Denny </span></p>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/sql-server/extra-bytes-per-row-with-alwayson-availability-groups/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Error Handeling and DBCC CHECKDB</title>
		<link>http://itknowledgeexchange.techtarget.com/sql-server/error-handeling-and-dbcc-checkdb/</link>
		<comments>http://itknowledgeexchange.techtarget.com/sql-server/error-handeling-and-dbcc-checkdb/#comments</comments>
		<pubDate>Wed, 15 May 2013 14:00:35 +0000</pubDate>
		<dc:creator>Denny Cherry</dc:creator>
				<category><![CDATA[Database Administration]]></category>
		<category><![CDATA[Error Message]]></category>
		<category><![CDATA[ERRORLOG]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQL Server stored procedures]]></category>
		<category><![CDATA[Stored Procedures]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/sql-server/?p=2653</guid>
		<description><![CDATA[A client that I&#8217;ve been working at for a while needed to start doing DBCC CHECKDBs on their production server.  We hadn&#8217;t been for a little while due to maintenance window constraints on their old production server.  Now that we&#8217;ve scaled the application across 6 different servers we can now do DBCC CHECKDB on the [...]]]></description>
				<content:encoded><![CDATA[<p>A client that I&#8217;ve been working at for a while needed to start doing DBCC CHECKDBs on their production server.  We hadn&#8217;t been for a little while due to maintenance window constraints on their old production server.  Now that we&#8217;ve scaled the application across 6 different servers we can now do DBCC CHECKDB on the production server regularly to ensure that there aren&#8217;t any database corruption problems on their production server.</p>
<p>As a part of this configuration we wanted to do the DBCC CHECKDB as a part of the backup job so that after the DBCC CHECKDB is complete the databases will then be backed up.</p>
<p>The catch here is that we didn&#8217;t want to have to dig through the errorlog file to figure out what the database was that&#8217;s having the problem, and we didn&#8217;t want the job to fail if there was a problem so I started looking at catching errors when running DBCC CHECKDB.  Sadly there aren&#8217;t really any good ways to do this.  TRY/CATCH doesn&#8217;t work because DBCC doesn&#8217;t actually throw error messages like a normal SQL statement does.  It returns the errors, but it doesn&#8217;t actually throw the errors so the CATCH block isn&#8217;t actually captured.  Running DBCC CHECKDB within an EXEC sp_executesql doesn&#8217;t catch the error either for the same reason, the error isn&#8217;t thrown it is simply displayed.  (The reason that the errors from DBCC CHECKDB show up in Management Studio in red I would assume is because SSMS is catching the format and displaying it correctly.)</p>
<p>To catch the errors I had to resort to some old school &#8220;error handeling&#8221; using the @@ERROR system function.  While this isn&#8217;t perfect, I&#8217;m not looking for perfect here.  I&#8217;m just looking for something that says that there&#8217;s an error so that I can send an email when there is an error then continue to loop through the databases looking for others with problems.</p>
<p>As this is step 1 of a multistep job this step is configured to move on to the next step on success or failure (as an email will have been sent and the data logged to the ERRORLOG) then we&#8217;ll procede to the backups.</p>
<p>The code that I&#8217;m using looks something like this&#8230;</p>
<p><code>/*Populate the table #dbs with the databases that need to be checked.*/<br />
DECLARE cur CURSOR FOR SELECT name from #dbs<br />
OPEN cur<br />
FETCH NEXT FROM cur INTO @name<br />
WHILE @@FETCH_STATUS 0<br />
BEGIN<br />
SET @sql = 'DBCC CHECKDB ([' + @name + '])'<br />
EXEC sp_executesql @sql<br />
IF @@ERROR 0<br />
BEGIN<br />
set @subject = 'CHECKDB failure for ' + @name<br />
set @body = 'DBCC CHECKDB failed for database ' + @name + '<br />
Command run was: ' + @sql<br />
exec msdb.dbo.sp_send_dbmail...<br />
END<br />
FETCH NEXT FROM cur INTO @name<br />
END<br />
CLOSE cur<br />
DEALLOCATE cur</code></p>
<p>There&#8217;s some custom code at the top which figures out which databases to process so that the job step runs DBCC CHECKDB on the same databases which the job will backup (this is figured out based on the database size, if the database is online, and if the database is currently being bulk loaded).  This code isn&#8217;t shown as it&#8217;s not relivant to this specific problem.</p>
<p>Denny</p>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/sql-server/error-handeling-and-dbcc-checkdb/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>I&#8217;m using simple recovery, so the log file isn&#8217;t important right?</title>
		<link>http://itknowledgeexchange.techtarget.com/sql-server/im-using-simple-recovery-so-the-log-file-isnt-important-right/</link>
		<comments>http://itknowledgeexchange.techtarget.com/sql-server/im-using-simple-recovery-so-the-log-file-isnt-important-right/#comments</comments>
		<pubDate>Wed, 01 May 2013 14:00:34 +0000</pubDate>
		<dc:creator>Denny Cherry</dc:creator>
				<category><![CDATA[Bulk Logged Recovery Model]]></category>
		<category><![CDATA[Database Administration]]></category>
		<category><![CDATA[Full Recovery Model]]></category>
		<category><![CDATA[Manageability]]></category>
		<category><![CDATA[Recovery Model]]></category>
		<category><![CDATA[Simple Recovery Model]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Storage]]></category>
		<category><![CDATA[Transaction Log]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/sql-server/?p=2645</guid>
		<description><![CDATA[One of the big myths of SQL Server resolves around the transaction log, and how it&#8217;s used with the simple recovery model. Many people think that the simple recovery model doesn&#8217;t use the transaction log.  More specifically they think that it&#8217;s there because it has to be there, but that SQL Server doesn&#8217;t actually use [...]]]></description>
				<content:encoded><![CDATA[<p>One of the big myths of SQL Server resolves around the transaction log, and how it&#8217;s used with the simple recovery model.</p>
<p>Many people think that the simple recovery model doesn&#8217;t use the transaction log.  More specifically they think that it&#8217;s there because it has to be there, but that SQL Server doesn&#8217;t actually use it.  The reality is that SQL Server still uses the transaction log, much like it does in full or bulk logged recovery modes.  There are some transactions which are going to be minimally logged, but for the most part the INSERT, UPDATE and DELETE commands are going to be fully logged just like normal.</p>
<p>What SQL Server does with the transaction log in simple recovery model is that when the transactions are committed they are written to the transaction log and the pages are dirtied in the buffer pool.  When checkpoint runs the dirty pages in the buffer pool are written to the disk.  Everything up to this point is basically the same as with the other recovery models.  Once the checkpoint has been completed things get different between simple recovery and the other two recovery models.  With the simple recovery model the virtual log files which were just checkpointed and had their dirty pages written to disk will be marked as no longer in use (status=0).  With bulk logged and full recovery this doesn&#8217;t happen until the transaction log backup has been completed.</p>
<p>Hopefully this helps dispel the myth.</p>
<p>Denny</p>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/sql-server/im-using-simple-recovery-so-the-log-file-isnt-important-right/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Deleting LOB Data and Shrinking the Database</title>
		<link>http://itknowledgeexchange.techtarget.com/sql-server/deleting-lob-data-and-shrinking-the-database/</link>
		<comments>http://itknowledgeexchange.techtarget.com/sql-server/deleting-lob-data-and-shrinking-the-database/#comments</comments>
		<pubDate>Wed, 13 Mar 2013 14:00:52 +0000</pubDate>
		<dc:creator>Denny Cherry</dc:creator>
				<category><![CDATA[Andre Kamman]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Database Administration]]></category>
		<category><![CDATA[DBCC PAGE]]></category>
		<category><![CDATA[Mladen Prajdić]]></category>
		<category><![CDATA[Paul Randal]]></category>
		<category><![CDATA[SQL Saturday]]></category>
		<category><![CDATA[SQL Saturday 194]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQL Server 2005]]></category>
		<category><![CDATA[SQL Server 2008]]></category>
		<category><![CDATA[SQL Server 2008 R2]]></category>
		<category><![CDATA[SQL Server 2012]]></category>
		<category><![CDATA[System Objects]]></category>
		<category><![CDATA[Tables]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/sql-server/?p=2564</guid>
		<description><![CDATA[While attending SQL Saturday 194 in Exeter over in England one of the attendees came to Mladen Prajdić, Andre Kamman and myself with an interesting problem.  She had a database table which was about 200 Gigs in size which she wanted to delete about half of the data from the table.  The catch was that the [...]]]></description>
				<content:encoded><![CDATA[<p>While attending <a href="http://www.sqlsaturday.com/194/eventhome.aspx">SQL Saturday 194</a> in Exeter over in England one of the attendees came to Mladen Prajdić, Andre Kamman and myself with an interesting problem.  She had a database table which was about 200 Gigs in size which she wanted to delete about half of the data from the table.  The catch was that the database table was full of LOB data where the rows were very large, with an average LOB data size of over a meg.  She also needed to shrink the database after the database was deleted so that she could reclaim the space from the database.  Oh and all this had to be done on SQL Server 2005 Standard Edition. (Everything here applies to SQL Server up through SQL Server 2012 as well.)</p>
<p>Deleting the data from the database is the easy part, a simple delete loop will handle that nicely.  The problem is when you delete rows from a table which contains LOB data the LOB pages aren&#8217;t cleared when they are deallocated.  We can see this by running the following code.</p>
<p><code>CREATE DATABASE Lobtest<br />
GO<br />
use Lobtest<br />
GO<br />
CREATE TABLE t1 (c1 int IDENTITY(1,1) PRIMARY KEY, c2 ntext)<br />
GO<br />
INSERT INTO T1 (c2) VALUES (replicate('a', 20000))<br />
GO<br />
DBCC IND ('LobTest', 't1', 1)<br />
GO<br />
DBCC TRACEON(5201, -1)<br />
GO<br />
DELETE FROM t1<br />
GO<br />
DBCC IND ('LobTest', 't1', 1)<br />
GO<br />
DECLARE @dbid as int = db_id('Lobtest')<br />
DBCC PAGE (@dbid, 1, 231, 3)<br />
GO</code></p>
<p>You can see that page 231 is a LOB page which is allocated to the table t1. When you look at the actual page using DBCC PAGE after the row has been deleted we can see that there is data in the page, and that the page header shows that the page is still allocated to the table t1. This can be seen by looking in the header of the page for the header value labeled &#8220;Metadata: ObjectId = 245575913&#8243;.</p>
<p>When you go to shrink the database the SQL Server engine will get to the LOB pages and it will need to figure out if the LOB row is a part of a row which still exists or not. In order to do this SQL Server will need to scan through the pages which make up the table looking for any rows which reference the page it is trying to delete.</p>
<p>When doing shrinks after deleing large amounts of LOB data SQL Server will generate large amounts of IO while figuring this out and the shrink operation will take an extremely long time. (Paul Randle talks more about <a href="http://www.sqlskills.com/blogs/paul/why-lob-data-makes-shrink-run-slooooowly-t-sql-tuesday-006/">it here</a>.)</p>
<p>So the question that this person at SQL Saturday had was, how can I reclaim the space from my database within a reasonable time.</p>
<p>The solution that we came up with was actually pretty simple.  Do the database deletion as normal.  Then backup and restore the database.  Then do the shrink, followed by rebuilding the clustered indexes in order to fix the fragmentation issue which the shrink will introduce.</p>
<p>This works for a pretty simple reason, because the PFS page shows that the LOB page isn&#8217;t allocated even though the page is full of data (you can verify this by looking at page 1 in file 1 in the sample database created by the script above).  When the database engine backups up the database the database engine looks at the PFS pages to figure out which pages to back up.  Because the PFS pages show that the pages are empty the database engine doesn&#8217;t bother to backup the pages, so when the pages are restored they are restored as blank pages.  This means that after the restore the shrink operation can run without an issue.</p>
<p>In the case of this application there was a maintenance window which could be taken advantage of which would allow the backup and the restore to happen.</p>
<p>Another option which we came up with which would require less downtime involved using database mirroring.  By configuring database mirroring (which is initialized via a backup and restore process giving us the same basic approach) and then failing over to the mirror we would end up in the same position.  We could then shrink the database without issue (probably pausing database mirroring so that we didn&#8217;t have to wait for the second server to process the shrink in real time) and then fail back the database to the original server.</p>
<p>As geeky as it was, Mladen, Andre and I had a great time figuring this out, and the attendee had a great time watching us go through all the possible options as we excluded them one by one.  And most importantly she got her problem solved.</p>
<p>So if you end up in this situation here&#8217;s a solution that will help you shrink the database so that you can reclaim the space that the LOB data pages are taking up without having to wait forever.</p>
<p>Denny</p>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/sql-server/deleting-lob-data-and-shrinking-the-database/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The Least Expensive SQL Server 2012 High Availability Solution</title>
		<link>http://itknowledgeexchange.techtarget.com/sql-server/the-least-expensive-sql-server-2012-high-availability-solution/</link>
		<comments>http://itknowledgeexchange.techtarget.com/sql-server/the-least-expensive-sql-server-2012-high-availability-solution/#comments</comments>
		<pubDate>Wed, 12 Dec 2012 14:00:48 +0000</pubDate>
		<dc:creator>Denny Cherry</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Database Administration]]></category>
		<category><![CDATA[Microsoft Cluster Service]]></category>
		<category><![CDATA[Microsoft Windows]]></category>
		<category><![CDATA[MSCS]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQL Server 2012]]></category>
		<category><![CDATA[Storage]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/sql-server/?p=2268</guid>
		<description><![CDATA[As we all know by now AlwaysOn Availability Groups are an enterprise edition feature and SQL Server Clustering is a standard edition feature.  Butt what happens when you have a small business that is running its apps on SQL Server Express.  Can&#8217;t SQL Express have any sort of high availability? Officially the answer is no, [...]]]></description>
				<content:encoded><![CDATA[<p>As we all know by now AlwaysOn Availability Groups are an enterprise edition feature and SQL Server Clustering is a standard edition feature.  Butt what happens when you have a small business that is running its apps on SQL Server Express.  Can&#8217;t SQL Express have any sort of high availability?</p>
<p>Officially the answer is no, however with a little bit of creative configuration you sure can.</p>
<p><strong>The Overall Environment</strong></p>
<p>To setup SQL Server Express in a Windows Cluster I&#8217;m building this on a two node Windows Server 2012 cluster using a file share hosted on my domain controller to host the actual databases.  To ensure that the domain controller is rebooted as little as possible the domain controller is installed in core mode.  The cluster nodes are Windows Server 2012 standard edition (which now supports clustering) as is the domain controller.</p>
<p><strong>Installation</strong></p>
<p>As SQL Server 2012 express edition doesn&#8217;t support Windows Clustering out of the box the installation will be a little different from doing a normal clustered install under standard or enterprise edition.  To install I did a normal SQL Express install on node1.  The only change from a normal install that I made was that I configured the SQL Server instance to start under a domain account.  When I got to the data directories part I configured the data folder to a network share on the domain controller.</p>
<p>Once the installation on node1 was completed I stopped the SQL Server services.  Then I renamed the folder that I installed the SQL Server database files into.  The reason for this is that I need to configure the second instance to put the database files into the same location.  I can then install SQL Server 2012 express edition onto the second node.</p>
<p>The installation on node2 is done exactly like it was done on node1.</p>
<p>Once the installation is done on both nodes configure the SQL Server service to have a startup type as &#8220;Manual&#8221; instead of disabled or automatic.  Leave the SQL Agent service as disabled as even though SQL Express installs the SQL Agent the SQL Agent isn&#8217;t supported on SQL Express.</p>
<p><strong>Configuring Clustering</strong></p>
<p>Once the installation on Node2 is done the cluster can be configured.  To do this bring up the Failover Cluster Administrator on one of the nodes and connect to the cluster.  If the cluster hasn&#8217;t been configured yet run through the normal Clustering Configuration wizard.</p>
<p>We&#8217;ll now configure a new cluster role on the cluster.  To do this right click on &#8220;Role&#8221; then select &#8220;Configure Role&#8221; from the context menu as shown below.</p>
<p><a href="http://itknowledgeexchange.techtarget.com/sql-server/?attachment_id=2270" rel="attachment wp-att-2270"><img class="alignnone size-full wp-image-2270" src="http://cdn.ttgtmedia.com/ITKE/uploads/blogs.dir/20/files/2012/08/NewRole.jpg" alt="" width="287" height="326" /></a></p>
<p>When the wizard opens click next to get to the list of services.  Then select the Generic Service item from the list as shown below.</p>
<p><a href="http://itknowledgeexchange.techtarget.com/sql-server/?attachment_id=2271" rel="attachment wp-att-2271"><img class="alignnone size-full wp-image-2271" src="http://cdn.ttgtmedia.com/ITKE/uploads/blogs.dir/20/files/2012/08/SelectRole.jpg" alt="" width="683" height="470" /></a></p>
<p>On the next screen you&#8217;ll be asked what service you wish to cluster.  From this list select the SQL Server service as shown below.</p>
<p><a href="http://itknowledgeexchange.techtarget.com/sql-server/?attachment_id=2272" rel="attachment wp-att-2272"><img class="alignnone size-full wp-image-2272" src="http://cdn.ttgtmedia.com/ITKE/uploads/blogs.dir/20/files/2012/08/SelectService.jpg" alt="" width="683" height="470" /></a></p>
<p>On the next screen you&#8217;ll be asked to name the resource group.  Give the group a name which is unique on the domain and click next.  The next screen will ask you to select the needed storage.  Simply click next on this screen as we aren&#8217;t using any local shared storage.  The next screen asks you if any registry settings need to be replicated between the machines.  We don&#8217;t need to replicate anything as SQL Server doesn&#8217;t make much use of the registry for the actual SQL Server service so we can simply click next on this screen as well.  The next screen is simply a screen to review the changes which will be made.  You can simply click next on this screen after reviewing the information on the screen.  When the summary screen displays click finish.</p>
<p>Post Clustering SQL Config Changes</p>
<p>The first change that you&#8217;ll need to make is to enable the TCP network protocol on both nodes.  By default SQL Express has the TCP network protocol disabled which need to be corrected before uses will be able to connect to the SQL Server service.</p>
<p>The next change that you&#8217;ll need to make is to change the local server name in the master database from the name of the last node which was installed to the cluster name using a script similar to the one shown below.  In the case of this script the nodes are named node1 and node2 and the cluster name is clustersql.  Once this script has been run the SQL Server instance should be restarted or failed over to the other node.</p>
<blockquote><p>exec sp_dropserver &#8216;nodeb&#8217;<br />
GO<br />
exec sp_addserver &#8216;clustersql&#8217;, local<br />
GO</p></blockquote>
<p>&nbsp;</p>
<p>At this point the cluster is up and running and applications can have their databases configured on the SQL Server Instance.</p>
<p>Denny</p>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/sql-server/the-least-expensive-sql-server-2012-high-availability-solution/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Databases With Large Tables Should Use Auto Stats Async Update Feature</title>
		<link>http://itknowledgeexchange.techtarget.com/sql-server/databases-with-large-tables-should-use-auto-stats-async-update-feature/</link>
		<comments>http://itknowledgeexchange.techtarget.com/sql-server/databases-with-large-tables-should-use-auto-stats-async-update-feature/#comments</comments>
		<pubDate>Wed, 05 Dec 2012 14:00:17 +0000</pubDate>
		<dc:creator>Denny Cherry</dc:creator>
				<category><![CDATA[Auto Update Statistics Asynchronously]]></category>
		<category><![CDATA[Auto Update Stats]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Database Administration]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Statistics]]></category>
		<category><![CDATA[Tables]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/sql-server/?p=2264</guid>
		<description><![CDATA[A pretty cool feature that was introduced in SQL Server 2008 R2 SP1 is the ability to change the auto stats algorithm from the default of 20%+500 rows to a sliding scale.  This feature is only available by turning on trace flag 2371 so it won&#8217;t be turned on by default for you. When turning [...]]]></description>
				<content:encoded><![CDATA[<p>A pretty cool feature that was introduced in SQL Server 2008 R2 SP1 is the ability to change the auto stats algorithm from the default of 20%+500 rows to a <a href="http://itknowledgeexchange.techtarget.com/sql-server/new-sql-2008-r2-sp1-trace-flag-adjusts-autostats-threshold/">sliding scale</a>.  This feature is only available by turning on trace flag 2371 so it won&#8217;t be turned on by default for you.</p>
<p>When turning on this trace flag because you&#8217;ve got a large database the goal obviously is to use autostats so you&#8217;ll need to have auto stats turned on.  In addition you&#8217;ll want to turn on the &#8220;Auto Update Statistics Asynchronously&#8221; setting for the database or databases which hold the super large table.  The reason that you&#8217;ll want to turn on the auto stats async update feature is that if you don&#8217;t you may see queries time out when auto stats starts to kick in.</p>
<p>Auto stats as we all know update the statistics when the correct number of rows in the table have changed.  When you&#8217;ve got very large tables that then trigger auto stats to run if it takes more than 30 seconds for the update stats command to run the query that triggered the auto stats to time out, which causes that transaction to roll back, which means that the auto stats command will also roll back.  So the next query will then fire the auto stats update and the process will repeat over and over.</p>
<p>The symptoms that you&#8217;ll see on the SQL Server are queries which are timing out at random even though the execution plan looks totally normal.  You&#8217;ll also see a massive amount of IO being generated on the disks which are hosting the database as auto stats does a lot of querying of the table and as auto stats is running over and over you&#8217;ll be thrashing the hard drive pretty quickly.</p>
<p>When you turn on the async auto stats setting on the database when the auto stats is triggered by the SQL Server the query in question doesn&#8217;t have to wait for the update stats command to finish.  Instead the update statistics command runs in the background letting the query continue to run as normal.  Now the query will run using the old statistics which is probably OK in this case as they were ok 2 seconds earlier so if they are used for a few more seconds it probably isn&#8217;t all that big of a deal.</p>
<p>Now I don&#8217;t recommend turning this setting on for every database on the server.  All of the smaller databases will update statistics just fine within the timeout period.</p>
<p>So the table that I ran across in my case where I had to turn this setting on took over 2 minutes in order to manually run update statistics on the table so using synchronous statistics updates via auto stats was basically useless.</p>
<p>Denny</p>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/sql-server/databases-with-large-tables-should-use-auto-stats-async-update-feature/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Fixing a table that has overflowed its primary key</title>
		<link>http://itknowledgeexchange.techtarget.com/sql-server/fixing-a-table-that-has-overflowed-its-primary-key/</link>
		<comments>http://itknowledgeexchange.techtarget.com/sql-server/fixing-a-table-that-has-overflowed-its-primary-key/#comments</comments>
		<pubDate>Wed, 21 Nov 2012 09:00:38 +0000</pubDate>
		<dc:creator>Denny Cherry</dc:creator>
				<category><![CDATA[Clustered Index]]></category>
		<category><![CDATA[Data Types]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Database Administration]]></category>
		<category><![CDATA[Database Design]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Stored Procedures]]></category>
		<category><![CDATA[T/SQL]]></category>
		<category><![CDATA[Tables]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/sql-server/?p=2179</guid>
		<description><![CDATA[During TechEd Europe I got a very scary phone call.  A very large table was throwing errors that the value being inserted into the primary key column was overflowing the data type that makes up that column.  In this case the data type in question was INT, so we were trying to stick the number [...]]]></description>
				<content:encoded><![CDATA[<p>During TechEd Europe I got a very scary phone call.  A very large table was throwing errors that the value being inserted into the primary key column was overflowing the data type that makes up that column.  In this case the data type in question was INT, so we were trying to stick the number 2,147,483,648 into the column and that number just doesn’t fit.  The error that we got looked something like this:</p>
<blockquote><p>System.Data.SqlClient.SqlException: Error 8115, Level 16, State 1, Procedure <em>SomeStoredProcedure</em>, Line 103, Message: Arithmetic overflow error converting IDENTITY to data type int.  Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.</p></blockquote>
<p>Ourshort term solution was quick and easy, to change identity seed of the column from 0 to the lowest possible number, in this case -2,147,483,648 which got us back up and running pretty quickly.  This however isn’t a very long term solution for this system.  The application is only about 3 or 4 years old, and has been growing very quickly over the last year or so.  We estimated based on the last few weeks worth of data that we would run out of negative numbers within about 12 months at the most.  We sent an estimate of 9 months to the business when we advised them that the system was back up and running.  We also told them that we wanted this fixed within 5-6 months to be save because if we didn’t get this fixed before running out of negative numbers there wouldn’t be any short term fix and that we’d be looking at a multi-day outage to fix the problem.</p>
<p>We couldn’t just rush into a database side fix, as the fix in this case is to change the data type from INT to BIGINT.  As the application does use this column in a couple of places the .NET application needed to be reviewed to ensure that anything that was looking for an INT was corrected to handle the BIGINT correctly.</p>
<p>Based on the amount of data within the table (about 300 Gigs) it was decided that taking an outage to make the change in place wasn’t really an option as doing the size change in place would require somewhere around a 5 day outage to remove and rebuild all the non-clustered indexes.  To make things a little more complex there is a second table which has a 1=1 relationship with this table, and the second table is even larger (about 800 Gigs), though thankfully the second table doesn’t have any non-clustered indexes.</p>
<p>The solution that was decided on was to move the data from the current table to a table with a BIGINT data type while the application was running.  To do this meant that we needed to get all the data copied over to the new table and in sync while the old table was being used.  It was decided that the easiest way to do this would be to use triggers.  In this case instead of one complex trigger to handle all insert, update and delete operations three separate triggers were used for each of the two tables.  First I created two new tables, with the exact same schema as the old tables, with the exception that the new tables used the bigint data type for the primary key instead of the int data type for the primary key and the new table was setup with the ident being the next available positive number.  Once that was done the triggers were setup.  The insert trigger is pretty basic.  Take the data that was just loaded and stick it into the new table.</p>
<blockquote><p>CREATE TRIGGER t_MyTable1_insert ON dbo.MyTable1<br />
FOR INSERT<br />
AS<br />
SET IDENTITY_INSERT MyTable1_bigint ON<br />
INSERT INTO MyTable1_bigint<br />
(Col1, Col2, Col3, Col4…)<br />
SELECT Col1, Col2, Col3, Col4<br />
FROM inserted<br />
SET IDENTITY_INSERT MyTable1_bigint OFF<br />
GO</p></blockquote>
<p><span style="color: #000000;">The update and delete triggers required a little more logic.  The trick with the triggers was that I needed to avoid doing massive implicit data conversions.  In order to ensure that SQL was doing what I wanted (which it should be doing anyway, but it made me feel better doing explicit conversions) I explicit conversions into place for the JOIN predicates as shown.  The update trigger is shown first, then the delete trigger.</span></p>
<blockquote><p>CREATE TRIGGER t_MyTable1_update ON dbo.MyTable1<br />
FOR UPDATE<br />
AS<br />
UPDATE MyTable1_bigint<br />
SET MyTable1_bigint.[Col2] = inserted.[Col2],<br />
MyTable1_bigint.[Col3] = inserted.[Col3],<br />
MyTable1_bigint.[Col4] = inserted.[Col4],<br />
…<br />
FROM inserted<br />
WHERE cast(inserted.Col1 as bigint) = MyTable1_bigint.Col1<br />
GO</p></blockquote>
<blockquote><p>CREATE TRIGGER t_MyTable1_delete ON dbo.MyTable1<br />
FOR DELETE<br />
AS<br />
DELETE FROM MyTable1_bigint<br />
WHERE Col1 in (SELECT cast(Col1 as bigint) FROM deleted)<br />
GO</p></blockquote>
<p><span style="color: #000000;">Once these tables were up and running all the new data changes were being loaded into the table.  At this point it was just a matter of coping the existing data into the table.  There are a few ways that this can be done.  In this case I opted for an SSIS package with a single data pump task, and two data transformations within the data pump task with one transformation for each table.</span></p>
<p><span style="color: #000000;">In order to make the load as fast as possible I used the fast load option and loaded 1000 rows at a time.  Within the data task if there was an error I redirected the rows to another data pump task which simply dropped the rows into the same table, but this time going row by row.  Any failures from that import were simply ignored.  While handling failed rows like this is time consuming it is easier than running T-SQL scripts to verify which rows are needed and which rows aren’t needed.  SSIS also gives an easy option to ignore the foreign key relationship between the two tables so if the child table gets rows first that isn’t a problem as we know that the parent table will catch up.  The SSIS package looked like this:</span></p>
<p><span style="color: #000000;"><a href="http://itknowledgeexchange.techtarget.com/sql-server/fixing-a-table-that-has-overflowed-its-primary-key/ssis/" rel="attachment wp-att-2186"><img class="alignnone size-full wp-image-2186" src="http://cdn.ttgtmedia.com/ITKE/uploads/blogs.dir/20/files/2012/08/ssis.jpg" alt="" width="480" height="365" /></a></span></p>
<p><span style="color: #000000;">When all is said and done and the data is in sync between the new and old tables, the current tables will be dropped and the new tables will be renamed and put into place so that the application can continue to run without issue, with just a few minutes of downtime.</span></p>
<p><span style="color: #000000;">So why did this happen?  When the applications database was being designed the developers didn’t think about how many rows the database was going to get over time, so they didn’t account for needing to support more than 2.1 billion rows over time.  If I (or another data architect) had been involved in the project at it’s start this hopefully would have been caught at design time.  However when the application was first being designed the company was brand new and didn’t have the funds for a data architect to help with the application design so this problem was missed.</span></p>
<p><span style="color: #000000;">Hopefully you never hit this problem, but if you do this helps you get out of it.</span></p>
<p><span style="color: #000000;">Denny</span></p>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/sql-server/fixing-a-table-that-has-overflowed-its-primary-key/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Backup Databases on Creation</title>
		<link>http://itknowledgeexchange.techtarget.com/sql-server/backup-databases-on-creation/</link>
		<comments>http://itknowledgeexchange.techtarget.com/sql-server/backup-databases-on-creation/#comments</comments>
		<pubDate>Sat, 17 Nov 2012 14:00:56 +0000</pubDate>
		<dc:creator>Denny Cherry</dc:creator>
				<category><![CDATA[Backup & recovery]]></category>
		<category><![CDATA[BACKUP DATABASE]]></category>
		<category><![CDATA[CREATE TRIGGER]]></category>
		<category><![CDATA[Data Loss]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Database Administration]]></category>
		<category><![CDATA[DDL Trigger]]></category>
		<category><![CDATA[Recovery]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQL Server 2008 R2]]></category>
		<category><![CDATA[SQL Server 2012]]></category>
		<category><![CDATA[T/SQL]]></category>
		<category><![CDATA[Transactions]]></category>
		<category><![CDATA[Trigger]]></category>
		<category><![CDATA[xp_create_subdir]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/sql-server/?p=2194</guid>
		<description><![CDATA[One of the companies which I work with has the occasion to create new databases when they do releases of their software.  Normally this isn&#8217;t a problem, except that they are setup to use maintenance plans to handle the backup and pruning of their transaction logs.  As all the new databases are created in the [...]]]></description>
				<content:encoded><![CDATA[<p>One of the companies which I work with has the occasion to create new databases when they do releases of their software.  Normally this isn&#8217;t a problem, except that they are setup to use maintenance plans to handle the backup and pruning of their transaction logs.  As all the new databases are created in the full recovery model this can end up causing some problems for them as within 12 minutes they start getting emails saying that the transaction log backup job has failed.  And these emails will keep coming in, possibly for hours until the full backup job kicks in later that night.</p>
<p>To solve this problem, I added a DDL trigger to the server which will cause the new database to be backed up as soon as the database is created.  The trigger itself is rather simple.  Most of the trigger is setting variables.  Then I make sure that the database isn&#8217;t a database snapshot, as database snapshots can&#8217;t be backed up.  If it isn&#8217;t a snapshot we continue with everything else.</p>
<p>Then I create a subfolder for the backups to be put into (the backups for each database go into their own folder, so as this is a new database the folder needs to be created).  Then I commit the transaction, as database backups can&#8217;t be taken within a transaction.  Then we do the actual database backup.  I then throw a message to the end user using the RAISERROR statement telling them that they can ignore the other error that they are going to get about the transaction being closed before the trigger was complete.  This is just an annoyance of my needing to commit the transaction before taking the backup.  Sure I could have setup a job which takes the backup and emails if there was a failure, but that just seems to complex for something so simple.  The code for my trigger is below.</p>
<blockquote><p>CREATE TRIGGER BackupNewDatabase<br />
ON ALL SERVER<br />
FOR CREATE_DATABASE<br />
AS<br />
declare @database sysname, @event_data XML = EVENTDATA(), @folder nvarchar(4000), @file nvarchar(4000)</p>
<p>SET @database = @event_data.value(&#8216;(/EVENT_INSTANCE/DatabaseName)[1]&#8216;, &#8216;sysname&#8217;)</p>
<p>set @folder = &#8216;X:\Backups\&#8217; + @database</p>
<p>set @file = @folder + &#8216;\&#8217; + @database + &#8216;.bak&#8217;</p>
<p>if exists (select * from sys.databases where name = @database and source_database_id is null)<br />
BEGIN<br />
EXEC master.dbo.xp_create_subdir @folder</p>
<p>COMMIT</p>
<p>BACKUP DATABASE @database to disk=@file</p>
<p>raiserror( &#8216;You can ignore the error message which says that the transaction ended within the trigger.&#8217;, 16,1)<br />
END<br />
GO</p></blockquote>
<p>Hopefully you find this solution helpful if you get into a situation like this,<br />
Denny</p>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/sql-server/backup-databases-on-creation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Encrypting data in the same column</title>
		<link>http://itknowledgeexchange.techtarget.com/sql-server/encrypting-data-in-the-same-column/</link>
		<comments>http://itknowledgeexchange.techtarget.com/sql-server/encrypting-data-in-the-same-column/#comments</comments>
		<pubDate>Wed, 10 Oct 2012 09:00:00 +0000</pubDate>
		<dc:creator>Denny Cherry</dc:creator>
				<category><![CDATA[Data Encryption]]></category>
		<category><![CDATA[Data Loss]]></category>
		<category><![CDATA[Data Security]]></category>
		<category><![CDATA[Data Types]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Database Administration]]></category>
		<category><![CDATA[Database Design]]></category>
		<category><![CDATA[Database security]]></category>
		<category><![CDATA[Encryption]]></category>
		<category><![CDATA[Identity theft]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQL Server stored procedures]]></category>
		<category><![CDATA[Stored Procedures]]></category>
		<category><![CDATA[T/SQL]]></category>
		<category><![CDATA[Tables]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/sql-server/?p=2175</guid>
		<description><![CDATA[I wrote a little while ago about the fact that sensitive data needs to be encrypted within the database for all applications.  This is the first technique that is available to you to encrypt data in a database with as little outage as possible. In this technique we’ll encrypt the data using just a single [...]]]></description>
				<content:encoded><![CDATA[<p>I wrote a little while ago about the fact that sensitive <a href="http://itknowledgeexchange.techtarget.com/sql-server/sensitive-data-must-be-encrypted/">data needs to be encrypted</a> within the database for all applications.  This is the first technique that is available to you to encrypt data in a database with as little outage as possible.</p>
<p>In this technique we’ll encrypt the data using just a single column.  This technique requires butting some additional logic within the application to figure out if the value is encrypted or not, but other than that logic, which you can leave in and strip out later the changes to the application are pretty minimal as the column stays the same, so that means that the stored procedures don’t need to be changed.</p>
<p>The first thing to remember is that the encrypted data will be larger, possibly much larger than the plain text version of the data.  Because of this you’ll need to increase the size of the field which you’ll be putting the data into.  Now the good news is that if this column isn’t indexed this change should be pretty quick and easy as it should just be a meta change which tells the SQL Server that the column size can be bigger without having to actually change the pages.  You can see this by making some changes to the [HumanResources].[Employee] table within the AdventureWorks database.  By turning on STATISTICS IO and using the ALTER TABLE statement we see that there is no IO generated when we change the size of the LoginID column from nvarchar(256) to nvarchar(512).</p>
<blockquote><p>set statistics io on<br />
alter table MyTable<br />
alter column LoginID nvarchar(512)</p></blockquote>
<p>Once the column is made larger the .NET code needs to be modified to see if the data is compressed for not.  Now there is no sure fire way to check to see if a value has been encrypted or not, but a pretty good test is to look at the last two characters of the value.  If they are both an equal sign (==) then it is probably safe to assume that the value is encrypted.  To don’t want to just attempt to decrypt the data and look for an error message, and if there is an error assume that the encrypted value is in plain text, throwing and catching error messages in .NET is very expensive, especially compared to simply checking to see if the last two characters are an equal sign.  This isn’t to say that you shouldn’t have TRY/CATCH logic around the code that decrypts the values as someone could easily enough put two equal signs at the end of their password.</p>
<p>At this point either a .NET app or a T-SQL script can loop through the values in the table which aren’t encrypted and then encrypt them, updating the rows which aren’t already encrypted.</p>
<p>Look for more blog posts in this series on how to encrypt data which already exists within your applications database.</p>
<p>Denny</p>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/sql-server/encrypting-data-in-the-same-column/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Old Web Based Applications Need To Be Removed</title>
		<link>http://itknowledgeexchange.techtarget.com/sql-server/old-web-based-applications-need-to-be-removed/</link>
		<comments>http://itknowledgeexchange.techtarget.com/sql-server/old-web-based-applications-need-to-be-removed/#comments</comments>
		<pubDate>Wed, 15 Aug 2012 14:00:11 +0000</pubDate>
		<dc:creator>Denny Cherry</dc:creator>
				<category><![CDATA[Data Loss]]></category>
		<category><![CDATA[Data Security]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Database Administration]]></category>
		<category><![CDATA[SELECT statement]]></category>
		<category><![CDATA[SQL Injection]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Stored Procedures]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/sql-server/?p=2241</guid>
		<description><![CDATA[What happens to most obsolete web based applications at most companies?  They sit idle on a web server for months, sometimes years.  Why is this a problem? Because many of these old applications can be easily exploited via SQL Injection allowing access into the SQL Server databases which they connected to.  The reason that these old [...]]]></description>
				<content:encoded><![CDATA[<p>What happens to most obsolete web based applications at most companies?  They sit idle on a web server for months, sometimes years.  Why is this a problem? Because many of these old applications can be easily exploited via SQL Injection allowing access into the SQL Server databases which they connected to.  The reason that these old apps are a great way into the SQL Server is because they are old, and were probably written before things like SQL Injection protection became more common place.</p>
<p>This tweet from Daniel (@<a href="http://twitter.com/DaniSQL">DaniSQL</a>) is a perfect example of this.</p>
<p><a href="http://itknowledgeexchange.techtarget.com/sql-server/?attachment_id=2242" rel="attachment wp-att-2242"><img class="alignnone size-full wp-image-2242" src="http://cdn.ttgtmedia.com/ITKE/uploads/blogs.dir/20/files/2012/08/old-app.jpg" alt="" width="301" height="94" /></a></p>
<p>An old application that isn&#8217;t being used anymore is still available on the Internet facing web farm.  Because this application isn&#8217;t being used any more it wasn&#8217;t on any lists of deployed applications, so when security audits were done it wasn&#8217;t seen as it wasn&#8217;t listed as an active application.  However it was apparently able to provide a hacker with a way into the database because it was still connected to a SQL Server instance and it was susceptible to SQL Injection.</p>
<p>The solution to this problem is sadly easy, remove the web based application from the web farm as the application isn&#8217;t being used anywhere.  It&#8217;s a lot easier than fixing the application, and a whole lot cheaper (10 minutes of a system administrator&#8217;s time versus weeks or months of a developers time).</p>
<p>I urge you to audit the applications and websites which are deployed to your web farms, especially the Internet facing web farms and see what&#8217;s on there.  When you audit them, don&#8217;t audit them against the list of what&#8217;s there.  Actually dig into the IIS config of each and every server (yes I&#8217;m well aware that doing this sucks) and actually see what&#8217;s configured on each machine.  If you don&#8217;t know if an application is actually being used ask around.  If it isn&#8217;t, remove it (or at least stop the site in IIS) so that you don&#8217;t have to worry about <a href="http://blog.dynamoo.com/2012/08/xinthesidersdowncom-injection-attack-in.html">scripts breaking into your database and updating your data</a>.</p>
<p>Now thankfully this current attack which is going around is just updating data, but it could easily enough be changed by the attacker to gather data as well, so do yourself a favor and protect yourself.</p>
<p>Denny</p>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/sql-server/old-web-based-applications-need-to-be-removed/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
