<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2307145203574942123</id><updated>2012-02-16T02:28:31.079-08:00</updated><category term='Deadlock'/><category term='SQL SERVER 2005'/><category term='Script'/><category term='Performance'/><category term='SQL 2008'/><category term='64 bit SQL Server'/><category term='Stored Procedure'/><category term='Extended Stored Procedure'/><category term='Integration services'/><category term='Import- Export'/><category term='Indexes'/><category term='Optimizing SQLServer 2008'/><category term='Shorcut Keys'/><category term='SMO'/><category term='Triggers'/><category term='Websites usability'/><category term='websites indexing'/><category term='google apps'/><category term='Programming'/><category term='restore backup'/><category term='Cursors'/><category term='Administration'/><title type='text'>SQL Server</title><subtitle type='html'>SQL Server - TSQL, Queries, Stored procedure, triggers, tables, views, functions,sql server 2005 features, sql server 2008 features
 ( Select * from Random_Ideas Order By Common_Sense )</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default?start-index=101&amp;max-results=100'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>143</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-6991420637789244540</id><published>2009-08-12T10:41:00.000-07:00</published><updated>2009-08-12T10:42:46.921-07:00</updated><title type='text'>ISRO unveils mapping application 'Bhuvan'</title><content type='html'>ISRO will unveil its version of Google Earth, the iconic mapping service for the common man to zoom into any part of the world on their personal computer using satellite images.&lt;br /&gt;&lt;br /&gt;However, the new mapping service -- Bhuvan, which means earth in Sanskrit -- will allow users to have a closer look at any part of the subcontinent barring sensitive locations such as military and nuclear installations.&lt;br /&gt;&lt;br /&gt;ISRO Chairman G Madhavan Nair will unveil the Bhuvan webportal at a function here tomorrow in the presence of Minister of State in the PMO Prithviraj Chavan.&lt;br /&gt;&lt;br /&gt;Bhuvan will use images taken by ISRO's seven remote sensing satellites at least a year ago. These eyes in the sky can capture images of objects as small as a car on the road to build three-dimensional map of the world.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://bhuvan2.nrsc.gov.in"&gt;http://bhuvan2.nrsc.gov.in&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-6991420637789244540?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/6991420637789244540/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=6991420637789244540' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6991420637789244540'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6991420637789244540'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/08/isro-unveils-mapping-application-bhuvan.html' title='ISRO unveils mapping application &apos;Bhuvan&apos;'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-8217993459329520486</id><published>2009-07-09T11:01:00.000-07:00</published><updated>2009-07-09T11:06:09.139-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='google apps'/><title type='text'>Google Chrome Operating System</title><content type='html'>Google Chrome has always been a little more than a browser: it's optimized for running web applications, each tab runs as a separate process, the interface is minimalistic and there's even a task manager. "We realized that the web had evolved from mainly simple text pages to rich, interactive applications and that we needed to completely rethink the browser. What we really needed was not just a browser, but also a modern platform for web pages and applications, and that's what we set out to build," said Google in September 2008.&lt;br /&gt;&lt;br /&gt;Google's blog announces a natural extension of the Chrome project: an operating system for netbooks. "Google Chrome OS is an open source, lightweight operating system that will initially be targeted at netbooks. Later this year we will open-source its code, and netbooks running Google Chrome OS will be available for consumers in the second half of 2010. (...) Google Chrome OS will run on both x86 as well as ARM chips and we are working with multiple OEMs to bring a number of netbooks to market next year. The software architecture is simple — Google Chrome running within a new windowing system on top of a Linux kernel."&lt;br /&gt;&lt;br /&gt;As people use more and more web applications, the operating system becomes less important and it makes no sense to pay for it. The desktop mail client could be replaced by Gmail, the calendaring application could be replaced by Google Calendar, the office suite has lightweight alternatives: Google Docs and Zoho, it makes more sense to use an online feed reader like Google Reader, your scientific calculator is less powerful than Wolfram Alpha and you'll rarely need a video player when you have YouTube, Hulu and other video sites.&lt;br /&gt;&lt;br /&gt;This idea is not new and there are already operating systems optimized for the browser. For example, Good OS announced last year Cloud, an operating system that "integrates a web browser with a compressed Linux operating system kernel for immediate access to Internet, integration of browser and rich client applications, and full control of the computer from inside the browser". If Google manages to create a great user interface, the new operating system could be very successful.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://googleblog.blogspot.com/2009/07/introducing-google-chrome-os.html"&gt;http://googleblog.blogspot.com/2009/07/introducing-google-chrome-os.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-8217993459329520486?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/8217993459329520486/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=8217993459329520486' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/8217993459329520486'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/8217993459329520486'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/07/google-chrome-operating-system.html' title='Google Chrome Operating System'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-8513220330854366276</id><published>2009-03-31T12:20:00.000-07:00</published><updated>2009-03-31T12:25:54.254-07:00</updated><title type='text'>Gmail in 5 Indian Languages Hindi, Tamil, Telugu, Kannada and Malayalam</title><content type='html'>It's hard for me to imagine going without email for a day. It's such an easy and convenient way to communicate with my friends and family. However, there was one limitation that bothered me: my family members and friends who prefer to communicate in Hindi did not have an easy way to type and send email in their language of choice. I am extremely happy to announce the launch of a new feature in Gmail that makes it easy to type email in Indian languages.&lt;br /&gt;&lt;br /&gt;When you compose a new mail in Gmail, you should now see an icon with an Indian character, as the screenshot below shows. This feature is enabled by default for Gmail users in India. If you do not see this function enabled by default, you will need to go the "Settings" page and enable this option in the "Language" section.&lt;br /&gt;&lt;br /&gt;When you click the Indian languages icon, you can type words the way they sound in English and Gmail will automatically convert the word to its Indian local language equivalent. For example, if a Hindi speaker types "namaste" we will transliterate this to "नमस्ते." Similarly, "vanakkam" in Tamil will become "வணக்கம்." We currently support five Indian languages -- Hindi, Tamil, Telugu, Kannada and Malayalam -- and you can select the language of your choice from the drop-down list next to the icon.&lt;br /&gt;&lt;br /&gt;They built this new feature using Google's transliteration technology, which is also available on Google India Labs, Orkut, Blogger and iGoogle. I hope you find this feature useful to communicate with those of your friends and family who prefer to write in their native language, and it will be available soon to businesses and schools using Google Apps. Now back to replying to all those Hindi emails I got from my family and friends today!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-8513220330854366276?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/8513220330854366276/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=8513220330854366276' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/8513220330854366276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/8513220330854366276'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/03/gmail-in-5-indian-languages-hindi-tamil.html' title='Gmail in 5 Indian Languages Hindi, Tamil, Telugu, Kannada and Malayalam'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-7919345429283702386</id><published>2009-03-29T08:53:00.000-07:00</published><updated>2009-03-29T08:54:21.970-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>How to Minimize SQL Server Blocking</title><content type='html'>By default, blocking locks do not time out. The waiting connection waits until the lock is released, and the block is over. If you like, you can set a lock time-out so that a connection does not wait indefinitely for the blocking lock to be released. This is accomplished using the LOCK_TIMEOUT setting.&lt;br /&gt;&lt;br /&gt;When the LOCK_TIMEOUT setting is used to set a maximum amount of time that a connection can wait for a blocking lock to go away, the connection with the lock that is causing the blocking problem is not affected, but the connection waiting for the block is halted and an error message is received. When this happens, error message 1222, "Lock request time-out period exceeded," is sent to the application.&lt;br /&gt;&lt;br /&gt;This means that the application needs to include the appropriate error-handling code to deal with this situation and take the appropriate action, which includes rolling back the transaction. If the application does not know how to deal with this error message, and the transaction is not rolled back, it is possible that the application can continue as if the transaction was not automatically cancelled. Because of this, you should not use the LOCK-TIMEOUT setting unless your application(s) that will be affected by it know what to do when they receive this message from SQL Server.&lt;br /&gt;&lt;br /&gt;The syntax for the SET LOCK_TIMEOUT is:&lt;br /&gt;&lt;br /&gt;SET LOCK_TIMEOUT timeout_period&lt;br /&gt;&lt;br /&gt;Where timeout_period is the number of milliseconds that a connection waits for a blocking lock to go away before an error is returned from SQL Server to the application. A value of -1 is the default, which means to wait indefinitely. A value of 0 tells SQL Server not to wait at all, and to return the error immediately.&lt;br /&gt;&lt;br /&gt;This command is based on a per connection basis, and stays with the connection until the connection is broken, or a new SET LOCK_TIMEOUT command is issued. [7.0, 2000]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-7919345429283702386?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/7919345429283702386/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=7919345429283702386' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/7919345429283702386'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/7919345429283702386'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/03/how-to-minimize-sql-server-blocking.html' title='How to Minimize SQL Server Blocking'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-7711107717996212031</id><published>2009-03-29T08:42:00.000-07:00</published><updated>2009-03-29T08:45:43.842-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimizing SQLServer 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>A view runs on our development server in 30 seconds, but it takes over 10 minutes on the production server. Why?</title><content type='html'>&lt;span style="font-weight:bold;"&gt;Problem&lt;/span&gt;There are two SQL Server servers, both with virtually the same hardware. One is a development server, where we create and test Transact-SQL code, and the other is production SQL Server. Here's my problem. When a particular view runs on the development server, it takes about 30 seconds. But when the identical view on the production server, the view takes over 10 minutes to run. The databases on both servers are almost identical. Periodically copy the production database to the development server so that we are working with the same data and the same indexes. What could be causing the difference in time for this particular view to run?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Solution&lt;/span&gt;&lt;br /&gt;Assuming that the servers and the databases are virtually the same, and the statistics have been updated on both of them, here's what is suggestted you to check. First, do an Execution Plan of the view that is causing the problem on the development server. Find out if this particular view is using parallelism as part of the execution plan. I am guessing that this is the case.&lt;br /&gt;&lt;br /&gt;Now, do an Execution Plan of the view on the production server. Find out if this particular view is using parallelism as part of the execution plan. My guess is that it is not.&lt;br /&gt;&lt;br /&gt;If I am write so far, then check the SQL Server Parallelism setting for each server. I bet that it is set to "Use All Available CPUs" on the development server, and set to use only one CPU on the production server. If I am right, then set the production server to "Use All Available CPUs," and the performance difference of the same view on both servers should be resolved, and performance should be virtually identical on both servers.&lt;br /&gt;&lt;br /&gt;By default, SQL Server  is set to use "Use All Available CPUs" on a server. If this is not your current setting, then this has been changed by someone.&lt;br /&gt;&lt;br /&gt;Essentially, this setting tells SQL Server whether to attempt to execute queries in parallel using multiple processors. If the default "Use All Available CPUs" option is selected, then SQL Server will attempt to run queries in parallel, using multiple CPUs. This can sometimes result in dramatic performance differences in a query's performance. But if this option is turned off, then SQL Server will only use one CPU to execute a query, which can be much slower.&lt;br /&gt;&lt;br /&gt;Keep in mind that if SQL Server is set to use parallelism, that it may not always use it. If the server is very busy, it may not be used, but when the server is less busy, it may be used. This means that sometimes the view will be fast, and other times, slow (depending if parallelism is being used or not).&lt;br /&gt;&lt;br /&gt;On the other hand, sometimes parallelism can cause queries to take longer to execute than if parallelism is not used. In these cases, you can use a Query Hint to turn off parallelism for the odd-acting query.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-7711107717996212031?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/7711107717996212031/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=7711107717996212031' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/7711107717996212031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/7711107717996212031'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/03/view-runs-on-our-development-server-in.html' title='A view runs on our development server in 30 seconds, but it takes over 10 minutes on the production server. Why?'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-6493806452680649950</id><published>2009-03-29T08:40:00.000-07:00</published><updated>2009-03-29T08:41:11.922-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimizing SQLServer 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>SQL Server Transact-SQL DML</title><content type='html'>Generally, it is better to perform multiple UPDATEs on records in one fell swoop (using one query), instead of running the UPDATE statement multiple times (using multiple queries).&lt;br /&gt;&lt;br /&gt;For example, you could accomplish this two different ways:&lt;br /&gt;&lt;br /&gt;USE Northwind&lt;br /&gt;UPDATE Products&lt;br /&gt;SET UnitPrice = UnitPrice * 1.06&lt;br /&gt;WHERE UnitPrice &gt; 5&lt;br /&gt;&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;USE Northwind&lt;br /&gt;UPDATE Products&lt;br /&gt;SET UnitPrice = ROUND(UnitPrice, 2)&lt;br /&gt;WHERE UnitPrice &gt; 5&lt;br /&gt;&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;Or&lt;br /&gt;&lt;br /&gt;USE Northwind&lt;br /&gt;UPDATE Products&lt;br /&gt;SET UnitPrice = ROUND(UnitPrice * 1.06, 2)&lt;br /&gt;WHERE UnitPrice &gt; 5&lt;br /&gt;&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;As is obvious from this example, the first option requires two queries to accomplish the same task as the second query. Running one query instead of two or more usually produces the best performance. [6.5, 7.0, 2000, 2005]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-6493806452680649950?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/6493806452680649950/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=6493806452680649950' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6493806452680649950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6493806452680649950'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/03/sql-server-transact-sql-dml_29.html' title='SQL Server Transact-SQL DML'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-5143241138330824309</id><published>2009-03-25T10:20:00.000-07:00</published><updated>2009-03-25T10:21:11.472-07:00</updated><title type='text'>How many logical and physical processors do you have?</title><content type='html'>SELECT cpu_count AS [Logical CPUs], &lt;br /&gt;       cpu_count / hyperthread_ratio AS [Physical CPUs]&lt;br /&gt;FROM   sys.dm_os_sys_info&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-5143241138330824309?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/5143241138330824309/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=5143241138330824309' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5143241138330824309'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5143241138330824309'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/03/how-many-logical-and-physical.html' title='How many logical and physical processors do you have?'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-7982046868960292413</id><published>2009-03-25T10:15:00.000-07:00</published><updated>2009-03-25T10:16:52.412-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><title type='text'>Sorting different dateformats correctly</title><content type='html'>DECLARE @Stats TABLE&lt;br /&gt;        (&lt;br /&gt;            SomeDate DATETIME&lt;br /&gt;        )&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT  @Stats&lt;br /&gt;SELECT  20000 + ABS(CHECKSUM(NEWID())) % 30000&lt;br /&gt;FROM    master..spt_values&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;DECLARE @Style INT&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SET     @Style = 100&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;WHILE @Style &lt;= 113&lt;br /&gt;    BEGIN&lt;br /&gt;        -- Orders by ISO format but displays according to @Style parameter&lt;br /&gt;        SELECT TOP 10 @Style AS Style,&lt;br /&gt;                      CONVERT(VARCHAR(40), SomeDate, @Style) as SomeDate&lt;br /&gt;        FROM          @Stats&lt;br /&gt;        GROUP BY      CONVERT(VARCHAR(40), SomeDate, @Style),&lt;br /&gt;                      CONVERT(VARCHAR(8), SomeDate, 112)&lt;br /&gt;        ORDER BY      CONVERT(VARCHAR(8), SomeDate, 112) DESC&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;        SET           @Style = @Style + 1&lt;br /&gt;    END&lt;br /&gt;&lt;br /&gt;The general idea is to group by both ISO format and the style you wish and the sort by the ISO format and display the other format.&lt;br /&gt;The reason this work is that the two lines in GROUP BY clause are deterministic.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-7982046868960292413?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/7982046868960292413/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=7982046868960292413' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/7982046868960292413'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/7982046868960292413'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/03/sorting-different-dateformats-correctly.html' title='Sorting different dateformats correctly'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-7220334133176163441</id><published>2009-03-25T10:04:00.000-07:00</published><updated>2009-03-25T10:05:29.050-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><title type='text'>Performance Tuning for SQL Server Backup and Restore</title><content type='html'>Depending on the size of your database, select the backup method that is the best tradeoff between backup and restore time. For example, full backups take the longest to perform, but are the fastest to restore. Differential backups are overall faster than full backups, but take longer to restore. Incremental (transaction log) backups are the fastest, but are generally the slowest to restore. [7.0, 2000, 2005]&lt;br /&gt;&lt;br /&gt;*****&lt;br /&gt;&lt;br /&gt;If you are backing up your databases directly over a network (not really recommended as it hurts performance), one way to boost throughput is to perform the backup over a dedicated network which is devoted to backups and restores only. All devices should be on the same high-speed switch. Avoid going over a router when backing up over a network, as they can greatly slow down backup speed. [6.5, 7.0, 2000, 2005]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-7220334133176163441?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/7220334133176163441/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=7220334133176163441' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/7220334133176163441'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/7220334133176163441'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/03/performance-tuning-for-sql-server.html' title='Performance Tuning for SQL Server Backup and Restore'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-9068012537435061194</id><published>2009-03-13T03:02:00.000-07:00</published><updated>2009-03-13T03:06:04.682-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>SQL Server Transact-SQL DML</title><content type='html'>Performing UPDATES takes extra resources for SQL Server to perform. When performing an UPDATE, try to do as many of the following recommendations as you can in order to reduce the amount of resources required to perform the UPDATE. The more of the following suggestions you can do, the faster the UPDATE will perform.&lt;br /&gt;If you are UPDATing a column of a row that has a unique index, try to update only one row at a time.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Try not to change the value of a column that is also the primary key.&lt;br /&gt;&lt;br /&gt;When updating VARCHAR columns try to replace the contents with contents of the same length.&lt;br /&gt;&lt;br /&gt;Try to minimize the UPDATing of tables that have UPDATE triggers.&lt;br /&gt;&lt;br /&gt;Try to avoid UPDATing columns that will be replicated to other databases.&lt;br /&gt;&lt;br /&gt;Try to avoid UPDATing heavily indexed columns.&lt;br /&gt;&lt;br /&gt;Try to avoid UPDATing a column that has a reference in the WHERE clause to the column being updated.&lt;br /&gt;&lt;br /&gt;Of course, you may have very little choice when UPDATing your data, but at least give the above suggestions a thought.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-9068012537435061194?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/9068012537435061194/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=9068012537435061194' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/9068012537435061194'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/9068012537435061194'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/03/sql-server-transact-sql-dml.html' title='SQL Server Transact-SQL DML'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-3258487500489542382</id><published>2009-03-12T07:45:00.001-07:00</published><updated>2009-03-12T07:54:09.001-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Integration services'/><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL SERVER 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><title type='text'>How to Perform Multiple lookups to the same table</title><content type='html'>&lt;a href="http://1.bp.blogspot.com/_R4ryh6DRFl8/SbkgN3HmiBI/AAAAAAAAAFY/50F-k4YKtNI/s1600-h/Image1.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 155px; height: 227px;" src="http://1.bp.blogspot.com/_R4ryh6DRFl8/SbkgN3HmiBI/AAAAAAAAAFY/50F-k4YKtNI/s320/Image1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5312312657966434322" /&gt;&lt;/a&gt;&lt;br /&gt;In a SQL Server Integration Service (SSIS) package, when lookups are performed on the tables which are inserted in the same package by a previous task, the error “could not match” is raised. &lt;br /&gt; &lt;br /&gt;See the failed package layout. From the insert data, two records will be inserted and at the lookup those values are used to get the id. However, the package fails indicating that records are not found even though those records are in the table. &lt;br /&gt;&lt;br /&gt;This is happening due to the cache setting in the lookup. There are three types of cache, Full, Partial and No caching. &lt;br /&gt;&lt;br /&gt;Full pre-caching, is when the complete reference data set is read before the input is processed. This is the default caching type. &lt;br /&gt;&lt;br /&gt;Partial caching, is when the Lookup transformation specifies the size of the cache that is loaded with reference data. This option is available only with connections that support keyed access. &lt;br /&gt;&lt;br /&gt;No caching, the reference data set is accessed by each row in the rowset. &lt;br /&gt;&lt;br /&gt;As the default caching type is full, before the start of the data flow, it will cache the lookup data to improve the performance. As the data is inserted after the caching, the lookup it will failed. Therefore, for this kind of implementation you need to set caching type to No Cachin&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-3258487500489542382?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/3258487500489542382/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=3258487500489542382' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3258487500489542382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3258487500489542382'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/03/in-sql-server-integration-service-ssis.html' title='How to Perform Multiple lookups to the same table'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_R4ryh6DRFl8/SbkgN3HmiBI/AAAAAAAAAFY/50F-k4YKtNI/s72-c/Image1.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-2712981781413509122</id><published>2009-03-11T07:18:00.000-07:00</published><updated>2009-03-11T07:23:09.837-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='websites indexing'/><category scheme='http://www.blogger.com/atom/ns#' term='Websites usability'/><title type='text'>Action plan: how to get listed in Google's search results for many keywords</title><content type='html'>Targeting several keywords on your website is crucial if you want to get high rankings on Google. The more keywords that are related to a special topic can be found on your website, the more likely it is that Google will find your website relevant to that topic.&lt;br /&gt;&lt;br /&gt;There are good ways and bad ways to target multiple keywords. If you choose the wrong way, search engines will think that you are a spammer. If you choose the right way, your website will get higher rankings. The following three steps will help you to get high rankings for as many keywords as possible.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Step 1: Remove stuffed keywords from your web pages&lt;/strong&gt;&lt;br /&gt;Some webmasters think that the best way to optimize a website for multiple keywords is to add them on every web page and separate them with a comma.&lt;br /&gt;&lt;br /&gt;These websites usually have extremely long meta tags with dozens if not hundreds of keywords. You won't get high rankings on Google with that method. Add dozens of keywords on a web page is called keyword stuffing and all search engines consider this spam. You actually risk your search engine rankings if you use this method on your web pages.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;To do: &lt;/strong&gt;Check if your web pages contain long keywords lists. If yes, remove them from your pages.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Step 2: Optimize different pages of your website for different keywords&lt;/strong&gt;&lt;br /&gt;If you add many keyword on the same web page, then the web page will be somewhat relevant to many keywords. If you optimize a web page for one keyword/keyphrase, then your web page will be very relevant to this keyword.&lt;br /&gt;&lt;br /&gt;It is much easier to get high rankings if the web page is very relevant to the searched keyword. For that reason, you should optimize as many pages of your website for as many keywords as possible.&lt;br /&gt;&lt;br /&gt;The keywords for which you optimize your web pages should be related. If you have a shoe shop, optimize different pages of your website for the keywords sports shoes, sneakers, sandals and boots. By having optimized web pages for these keywords, you show Google that your website is relevant to the topic shoes.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;To do:&lt;/strong&gt; Find the best keywords for your website and then optimize different pages of your website for different keywords.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Step 3: Add keyword modifiers and combine these variations&lt;/strong&gt;&lt;br /&gt;In step two, you have optimized your web pages for keywords such as sneakers and sandals. The next step is to add modifiers to these keywords on your optimized pages. For example, the sneakers page could include these keyword variations: sneakers shop, nike sneakers, cool sneakers, etc.&lt;br /&gt;&lt;br /&gt;It's usually a good idea to combine all of these keyword variations in one sentence (for example for your web page title): Buy cool Nike sneakers in our sneakers shop in London. With this single sentence, your web page can be found for many keyword combinations that are included in this sentence.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;To do:&lt;/strong&gt; Find keyword modifiers and add different keyword variations to your optimized pages.&lt;br /&gt;&lt;br /&gt;If you optimize many pages of your website for different but related keywords and if you add variations of each keyword to each page than the content of your web site will be perfectly optimized for high rankings on Google.&lt;br /&gt;&lt;br /&gt;If you combine optimized content with good inbound links, your website will get the best possible rankings on Google and other search engines.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-2712981781413509122?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/2712981781413509122/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=2712981781413509122' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/2712981781413509122'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/2712981781413509122'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/03/action-plan-how-to-get-listed-in.html' title='Action plan: how to get listed in Google&apos;s search results for many keywords'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-5368748736879137797</id><published>2009-03-11T07:12:00.000-07:00</published><updated>2009-03-11T07:15:21.299-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Websites usability'/><title type='text'>Nine factors that affect your website usability</title><content type='html'>Optimizing web pages for search engines does not mean creating special pages for search engines. Optimizing web pages for search engines is often the same as optimizing web pages for web surfers.&lt;br /&gt;&lt;br /&gt;If you do it correctly, your website will be attractive to both web surfers and search engine spiders. The following list shows nine factors that can improve the usability of your website as well as your search engine rankings.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;1. You should have fast loading web pages&lt;/strong&gt;&lt;br /&gt;Usability: Web surfers don't want to wait for web pages.&lt;br /&gt;Search engine optimization: Search engines can index your web pages more easily. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2. Your web pages should be easy to read&lt;/strong&gt;&lt;br /&gt;Usability: It's easier for web surfers to read your web pages.&lt;br /&gt;Search engine optimization: Near-white text on a white background and tiny text is considered spam by most search engines.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;3. The contents of your web pages should be clearly arranged&lt;/strong&gt;&lt;br /&gt;Usability: Clear headings, paragraphs and bullet lists make your web pages easier to read.&lt;br /&gt;Search engine optimization: Clear headings, paragraphs and bullet lists make it easier for search engines to find the topic of your web pages.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;4. Your web page images should use the IMG ALT attribute&lt;/strong&gt;&lt;br /&gt;Usability: Web surfers with images turned off and visually impaired visitors will be able to see the content of your images.&lt;br /&gt;Search engine optimization: Search engines cannot index the content of your images but they can index the content of the IMG ALT attribute.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;5. You should use custom 404 not found error pages&lt;/strong&gt;&lt;br /&gt;Usability: If your 404 not found page contains links to other pages of your website or a search form then people might remain on your website.&lt;br /&gt;Search engine optimization: Proper 404 error pages make sure that search engines index the right pages of your website.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;6. Your website should be easy to navigate&lt;/strong&gt;&lt;br /&gt;Usability: Clear and concise navigation links that are easy to find help your website visitors to find content on your site.&lt;br /&gt;Search engine optimization: Clear and concise navigation links that contain your keywords make it easy for search engines to index all of your web pages.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;7. Important content is above the fold&lt;/strong&gt;&lt;br /&gt;Usability: Web surfers with small computer screens can quickly see what your web page is about.&lt;br /&gt;Search engine optimization: The sooner your important content appears in the HTML code of your web pages, the more likely it is that it will be indexed by search engines.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;8. Your web page titles are explanatory&lt;/strong&gt;&lt;br /&gt;Usability: If web surfers bookmark your web pages, a clear web page title will help them to find it again.&lt;br /&gt;Search engine optimization: The web page title is one of the most important SEO elements. It should contain your keywords and it should look attractive so that web surfers click on it when they see your web page title in the search results.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;9. The URLs of your web pages are meaningful and self-explanatory&lt;/strong&gt;&lt;br /&gt;Usability: It's much easier to remember a web page like www.example.com/support than a web page like www.example.com/123123-werwc.php?2342234.&lt;br /&gt;Search engine optimization: If your URLs contain your keywords, this can have a positive effect on your search engine rankings. Dynamic URLs with many variables can lead to problems with search engine spiders.&lt;br /&gt;&lt;br /&gt;There are many more factors that influence the position of your website in Google's search results.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-5368748736879137797?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/5368748736879137797/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=5368748736879137797' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5368748736879137797'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5368748736879137797'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/03/nine-factors-that-affect-your-website.html' title='Nine factors that affect your website usability'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-5526215463935842250</id><published>2009-03-10T12:07:00.000-07:00</published><updated>2009-03-10T12:10:26.393-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><title type='text'>What's new in SQL Server 2008 Reporting Services?</title><content type='html'>With the release of SQL Server 2008, Reporting Services (SSRS) reached its third version. While the previous version contained many new features, this latest release of SSRS is easier to use and an even more powerful enterprise-level reporting tool. This article will discuss the most significant and most useful new features that make SQL Server 2008 Reporting Services a worthwhile upgrade. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;IIS is no longer required &lt;/strong&gt;&lt;br /&gt;The previous two releases relied on IIS to host the RS Web service and the Report Manager Web application. Many organizations have made a rule of not installing IIS on the same machine as SQL Server for security reasons. This dependency on IIS therefore became a showstopper for using SSRS for many potential users. Based on user feedback, Microsoft re-architected SSRS 2008 and removed this dependency. &lt;br /&gt;&lt;br /&gt;SSRS now handles HTTP via HTTP.SYS, a native OS kernel that intercepts and handles HTTP requests just like IIS. If this sounds familiar, that's because it's the same mechanism used by the Native XML Web Services in SQL Server 2005 – a feature that, interestingly, was removed in SQL Server 2008. Microsoft also claims that this implementation provides better performance and scalability. The Reporting Services Configuration tool has been updated to provide management capabilities for Report Manager and Reporting Server services. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Better memory management &lt;/strong&gt;&lt;br /&gt;Users who have deployed SSRS in high-traffic environments may have noticed performance degradation when many concurrent users access reports with many pages. The reason for the slowness was that SSRS was holding rendered reports in memory, causing problems if memory demands became too high. SSRS now saves rendered pages to the file system to remove the load on server memory. For large reports, it also renders reports as the user is viewing them. This on-demand processing decreases the load on the server by not rendering pages the user might potentially not view at all. In addition to these memory enhancements, you can now also set a threshold on how much memory SQL Server Reporting Services should use. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Export into Microsoft Word &lt;/strong&gt;&lt;br /&gt;This feature has been requested pretty much since SSRS 2000 came out in 2004, mainly because there are more Word users than Excel users. For whatever reason, this feature did not make it to SQL Server 2005, but it's finally here and certainly a much welcome addition to all the other export options. &lt;br /&gt;&lt;strong&gt;&lt;br /&gt;Improved charting components&lt;/strong&gt;&lt;br /&gt;Last year Microsoft acquired Dundas Data Visualization technology for SSRS. Dundas is a company specializing in developing powerful visual components for developers, such as chart, gauge, map and calendar controls. Purchasing the code base for the chart, gauge and calendar controls allowed Microsoft to provide better integration of these components with SSRS and to control the components' future direction. Dundas components have always been visually stunning, so it's no surprise that the new chart component is like night and day compared with chart control in the previous versions of SSRS. &lt;br /&gt;&lt;br /&gt;In my opinion, if you do a lot of charting in your reports, this feature alone justifies the effort to upgrade SQL Server 2008 Reporting Services. The new chart region includes many additional chart types, such as cylinder, pyramid, radar and funnel. Other useful enhancements are interval labeling for avoiding label collisions, combining small slices into a single slice in a pie chart and more 2-D and 2-D visual effects.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Tablix data region &lt;/strong&gt;&lt;br /&gt;This new data region combines the functionality of both table and matrix data regions. This region allows you to combine multiple column groups and row groups, essentially allowing you to create reports that have both dynamic row and dynamic column output. You can now more easily create nested and recursive groups and make them adjacent to each other. There is a lot more to the Tablix data region than I can describe in this space. For more details, read the Understanding the Tablix Data Region section of Microsoft Books Online.&lt;br /&gt;&lt;strong&gt;&lt;br /&gt;Enhanced CSV export &lt;/strong&gt;&lt;br /&gt;Comma-separated value (CSV) export can be very useful for automating report processing if you are interested in extracting data elements from the report. SSRS CSV export in previous versions included both the data and the layout in the export. But the inclusion of report layout elements in the CSV output created additional work and complications. The new output format is much cleaner and easier to use for automating programmatic processing. &lt;br /&gt;&lt;br /&gt;There are plenty of significant reasons for you to give SSRS 2008 serious consideration. And remember, just like Integration Services, SSRS is a standalone tool you can install on a dedicated server. This means, if your organization is not ready to migrate to SQL Server 2008, you can upgrade just your reporting server and use these new features, using your 2000 or 2005 databases as data sources.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-5526215463935842250?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/5526215463935842250/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=5526215463935842250' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5526215463935842250'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5526215463935842250'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/03/whats-new-in-sql-server-2008-reporting.html' title='What&apos;s new in SQL Server 2008 Reporting Services?'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-406867545416963759</id><published>2009-03-10T12:01:00.000-07:00</published><updated>2009-03-12T07:54:36.746-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Integration services'/><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL SERVER 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Import- Export'/><title type='text'>History of SQL Server Integration Services</title><content type='html'>Integration Services is the successor to Data Transformation Services (DTS). DTS had humble beginnings. It was started on a shoestring budget with very few resources. Its first incarnation was a proof-of-concept transformation, which later became known as the data pump. The proof of concept caught the attention of some folks around Microsoft, and it was given some funding.&lt;br /&gt;&lt;br /&gt;The first release of DTS shipped with SQL Server 7.0 to receptive users. The alternatives at the time were either difficult to work with, expensive, or both. Many DBAs were forced to write custom transformation software, which was inflexible and difficult to maintain. Some tools had limitations, such as the need for source and destination schemas to match exactly, direct dependence on a particular database product, and/or no transformation capabilities. Many wrote custom parsing and transformation applications. For example, many companies are only now converting from hand-coded flat file parsers, SQL scripts, and transformation code to a standard platform such as Integration Services.&lt;br /&gt;&lt;br /&gt;The first release of DTS addressed several of these issues and simplified life for a lot of people. By using OLEDB for its data access layer, DTS could access various data sources with little or no custom coding. DTS was also affordable because it shipped "in the box" with SQL Server. Users had access to all the power of more expensive products, yet incurred no additional cost for their ETL tools. This was obviously a benefit to IT shops trying to stretch their budgets. DTS was a flexible product that was easy to use. There were also a number of standard tasks in the box, including the Transform Data, Execute Process, Active X Script, Execute SQL, and Bulk Insert Tasks.&lt;br /&gt;&lt;br /&gt;SQL Server 8.0 added even more functionality by adding more tasks. The Execute Package, FTP, and MSMQ Tasks added incremental improvements across the product. However, users experienced some frustration with DTS when attempting to work with large datasets and some of the other limitations inherent in a script-based tool. The time was ripe to create a truly enterprise-ready integration tool.&lt;br /&gt;&lt;br /&gt;In 2000, SQL Server decided to make a substantial investment in the ETL and Integration space and brought together some talented folks who formulated the ideas behind the Data Flow Task and the next version of Integration Services. Over a period of five years, the development time frame for SQL Server 2005, the DTS team completely redesigned and rewrote DTS to become Integration Services 2005.&lt;br /&gt;&lt;br /&gt;Integration Services 2008 is the next incarnation of that release. While not as revolutionary a release as in 2005, Integration Services 2008 brings some new capabilities and incremental improvements across the product.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-406867545416963759?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/406867545416963759/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=406867545416963759' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/406867545416963759'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/406867545416963759'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/03/history-of-sql-server-integration.html' title='History of SQL Server Integration Services'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-1653079259814385774</id><published>2009-03-10T11:58:00.000-07:00</published><updated>2009-03-12T07:54:36.747-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Integration services'/><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL SERVER 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Import- Export'/><title type='text'>What Is SQL Server Integration Services?</title><content type='html'>Depending on whom you ask, you might get different answers to that question ranging from descriptions such as a data import/export wizard, to an ETL tool, to a control flow engine, to an application platform, or to a high-performance data transformation pipeline. All are correct because Integration Services is a set of utilities, applications, designers, components, and services all wrapped up into one powerful software application suite. SQL Server Integration Services (SSIS) is many things to many people.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Data Import/Export Wizard&lt;/strong&gt;&lt;br /&gt;One of the most popular features of Integration Services is the Import/Export Wizard, which makes it easy to move data from a source location such as a flat file or database table to a flat file, table, or other destination. The Import/Export Wizard was the first utility developed back in the SQL Server 7.0 time frame and continues today as an important utility in the database administrator's (DBA) toolbox.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;ETL tool&lt;/strong&gt;&lt;br /&gt;ETL is an acronym for Extract, Transform, and Load and describes the processes that take place in data warehousing environments for extracting data from source transaction systems; transforming, cleaning, deduplicating, and conforming the data; and finally loading it into cubes or other analysis destinations. Although Data Transformation Services (DTS), Integration Services' predecessor application, was considered a valuable tool for doing ETL, Integration Services is where true Enterprise ETL became available in SQL Server.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Control flow engine&lt;/strong&gt;&lt;br /&gt;The processes involved in moving data from location to location and transforming it along the way are not restricted to only processing data. Integration Services provides a control flow for performing work that is tangentially related to the actual processing that happens in data flow, including downloading and renaming files, dropping and creating tables, rebuilding indexes, performing backups, and any other number of tasks. Integration Services provides a full-featured control flow to support such activities.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Application platform&lt;/strong&gt;&lt;br /&gt;Developers can create applications that use Integration Services as a platform, embedding the engines within their application using the provided object models. As a developer, you can embed the Integration Services engines and components within your applications using the object models.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;High performance data transformation data pipeline&lt;/strong&gt;&lt;br /&gt;That's a mouthful and really incorporates two ideas: high performance and data pipelining. The Data Flow Task is a high-performance tool because you can use it to perform complex data transformations on very large datasets for incredibly performant processing. The pipeline concept means that you can process data from multiple heterogeneous data sources, through multiple parallel sequential transformations, into multiple heterogeneous data destinations, making it possible to process data found in differing formats and on differing media in one common "sandbox" location.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-1653079259814385774?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/1653079259814385774/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=1653079259814385774' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/1653079259814385774'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/1653079259814385774'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/03/what-is-sql-server-integration-services.html' title='What Is SQL Server Integration Services?'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-4369468777133707100</id><published>2009-03-10T11:53:00.000-07:00</published><updated>2009-03-10T11:54:25.776-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL SERVER 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='restore backup'/><title type='text'>Performance Tuning SQL Server Backup and Restore</title><content type='html'>SQL Server backup and restore performance is often a greater issue than many DBAs realize. This is because the time it takes to backup and restore a database plays a very large part in how large a single SQL Server database can be. For example, if it takes more than 24 hours to backup or restore a database, obviously this presents some problems.&lt;br /&gt;What can sometimes happen to the DBA is that a database may be of reasonable size now, given their current server hardware, and backups and restores may take a reasonable amount of time. But as time goes by, the database grows, and at some point the amount of time to backup and restore the database becomes too long given the backup and restore window available. The moral to this story, keep a close eye on backup and restore times, and factor this in when projecting future hardware needs for your SQL Server databases. [6.5, 7.0, 2000, 2005]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-4369468777133707100?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/4369468777133707100/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=4369468777133707100' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/4369468777133707100'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/4369468777133707100'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/03/performance-tuning-sql-server-backup.html' title='Performance Tuning SQL Server Backup and Restore'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-1967641215273672645</id><published>2009-03-07T13:10:00.000-08:00</published><updated>2009-03-07T13:11:58.560-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Indexes'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>Reasons Why You May Not Want to Use a Heap</title><content type='html'>why heaps aren't usually a good choice when designing a database. Now, I didn't say that heaps are always bad, but in most cases, I think they should be avoided (read the list to see why).&lt;br /&gt;&lt;br /&gt;As I compiled the list, in some cases I have had the opportunity to verify that they are true, but in other cases, I have not had the time to verify them. I would like your input on the list. Is there anything on the list that is not true, or only partially true (under some circumstances, but not others), and what other reason are there to avoid using heaps that have I left out?&lt;br /&gt;&lt;br /&gt;I look forward to your feedback.&lt;br /&gt;&lt;br /&gt;If non-clustered indexes are not added to a heap, then all queries against a heap will require table scans to retrieve the requested data. If the heap is large, then these queries will be very resource intensive and hurt SQL Server's overall performance. &lt;br /&gt;Since the data in a heap is unordered, performing a table scan on a heap can cause a lot of extra I/O activity because inefficient random reads, not efficient sequential reads, are more the norm. &lt;br /&gt;While a non-clustered index can be added to a heap to speed up some queries, in almost all cases, to make use of a non-clustered index, the use of a bookmark lookup is required. A bookmark lookup means that once the record(s) to be returned by the query are identified in the non-clustered index, additional reads (the bookmark lookup) must be made of the related rows in the heap, so that all of the data requested by the query is returned. This is not very I/O efficient, especially if many rows are returned. At some point, it may be faster for SQL Server to do a table scan than it is to use a non-clustered index when returning many rows. &lt;br /&gt;Heaps cannot be replicated using SQL Server replication. &lt;br /&gt;If you want to create an XML index on an XML data column, a clustered index must exist on the table. &lt;br /&gt;If you want to create a spatial index on a spatial data column (GEOMETRY or GEOGRAPHY), a clustered index must exist on that table. &lt;br /&gt;If a heap has a non-clustered index on it (as the primary key), and data is inserted into the table, two writes have to occur. One write for inserting the row, and one write for updating the non-clustered index. On the other hand, if a table has a clustered index as the primary key, inserts take only one write, not two writes. This is because a clustered index, and its data, are one in the same. Because of this, it is faster to insert rows into a table with a clustered index as the primary key than it is to insert the same data into a heap that has a non-clustered index as its primary key. This is true whether or not the primary key is monotonically increasing or not. &lt;br /&gt;When data is updated in a heap, and the updated row is larger than the old row and can't fit into the old space, a forwarding record is inserted into the original location that points to the new location of the page. If this happens a lot, then there is a lot of space wasted in a database maintaining the forwarding records. This also contributes to additional I/O activity as both the pointer, and the row, have to be read. &lt;br /&gt;Even if data updated in a heap is not larger than the old row (the updated data is smaller or the same size than the original data), updating a heap with a non-clustered primary key is slower than updating the same table that has a clustered index as the primary key. This is because updating a table with a clustered index is less write intensive than updating a heap with a non-clustered index as its primary key. &lt;br /&gt;If a row is deleted from a heap with a non-clustered index as its primary key, it is slower than deleting the same row from the same table with a clustered index as its primary key. This is because it takes more I/O to perform this task on a heap than on a clustered index. &lt;br /&gt;When data is deleted from a heap, the data on the page is not compressed (reclaimed). And should all of the rows of a heap page are deleted, often the entire page cannot be reclaimed. This not only wastes space, it contributes to fragmentation of the data pages within a database. &lt;br /&gt;If you take two identical tables, one that is a heap with a non-clustered index as its primary key, and a table that has a clustered index as its primary key, the heap with the non-clustered index will be substantially larger, wasting valuable space and increasing disk I/O. &lt;br /&gt;The ALTER INDEX rebuild and reorganize options cannot be used to defragment and reclaim space in a heap (but they can used to defragment non-clustered indexes on a heap). If you want to defragment a heap, you have three options: 1) create a clustered index on the heap, then drop the clustered index; 2) Use SELECT INTO to copy the old table to a new table; or 3) use BCP or SSIS to move the data from the old table to a new table.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-1967641215273672645?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/1967641215273672645/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=1967641215273672645' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/1967641215273672645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/1967641215273672645'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/03/reasons-why-you-may-not-want-to-use.html' title='Reasons Why You May Not Want to Use a Heap'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-219212932296275497</id><published>2009-03-05T09:05:00.000-08:00</published><updated>2009-03-05T09:07:03.403-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL SERVER 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Import- Export'/><title type='text'>Importing and exporting bulk data with SQL Server's bcp utility</title><content type='html'>The Bulk Copy Program (bcp) utility in Microsoft SQL Server enables database administrators to import bulk data into a table or export it from a table into a file. It also supports several options that define how data will be exported, where it will be imported and which data will be loaded. &lt;br /&gt;This tip discusses several examples of bcp commands to bulk-copy data in and out of SQL Server tables. The examples have been tested on SQL Server 2005 and SQL Server 2008, and for all examples I used the AdventureWorks sample database.&lt;br /&gt;&lt;br /&gt;Exporting data with the bcp utility&lt;br /&gt;&lt;br /&gt;One of the simplest operations that you can perform with the bcp utility is to bulk-copy data out of a SQL Server table into a text file. By entering the command at a Windows command prompt, you can run a bcp command. The following command, for example, copies the data from the Sales.vSalesPerson view in the AdventureWorks database to the C:\Data\SalesPerson.txt file:&lt;br /&gt;&lt;br /&gt;bcp AdventureWorks.Sales.vSalesPerson out C:\Data\SalesPerson.txt -c –T&lt;br /&gt;&lt;br /&gt;As you can see, the bcp command begins with the utility name, followed by the fully qualified name of the table (database.schema.table). The out keyword is next, which tells the bcp utility that the data will be exported from the table. The path and file name of the target text file follows the out keyword. Note that the command examples in this tip might wrap to multiple lines. All the examples, however, should be run as a single command.&lt;br /&gt;&lt;br /&gt;In addition to these basic arguments, the bcp utility supports several switches that control the utility's behavior. In the example above, the -c switch indicates that all data is treated as character data, regardless of how it is stored in the source table. If you do not specify the -c switch or another type-related switch, you will be prompted to specify the type for each column after you enter the bcp command. You may notice that bcp command switches are case sensitive.&lt;br /&gt;&lt;br /&gt;The next switch in the above example is -T, which tells the bcp utility to use a trusted connection to connect to the SQL Server instance. If you do not specify -T, you must provide your user name (the -U switch) and your password (the -P switch), or you will be prompted for this information.&lt;br /&gt;&lt;br /&gt;Because no instance is specified in the preceding example, the utility uses the default instance on the local machine. To specify a SQL Server instance, use the -S switch, followed by the server name, as in the following example:&lt;br /&gt;&lt;br /&gt;bcp AdventureWorks.Sales.vSalesPerson out C:\Data\SalesPerson.txt -c -T -S Server01&lt;br /&gt;&lt;br /&gt;The bcp utility will now connect to the default instance on Server01. If you want to connect to an instance other than the default, you must specify the instance name along with the server name, as in Server01\SqlSrv.&lt;br /&gt;&lt;br /&gt;By default, the bcp utility uses tabs to separate fields in the target file. You can, however, override that behavior by using the -t switch, as in the following example:&lt;br /&gt;&lt;br /&gt;bcp AdventureWorks.Sales.vSalesPerson out C:\Data\SalesPerson.csv -c -T -t,&lt;br /&gt;&lt;br /&gt;In this case, a comma is specified after the -t switch, which means that the data fields will now be separated by commas. This allows you to save the data to a .csv file, as I've done here, which can be handy if you want to view the data in a Microsoft Excel file.&lt;br /&gt;&lt;br /&gt;These examples have been limited to exporting data from a table. But you can also use the bcp command to run a Transact-SQL query and export the query results. The following bcp command, for example, includes a SELECT statement that retrieves only the SalesPersonID, FirstName, and LastName columns from the vSalesPerson view:&lt;br /&gt;&lt;br /&gt;bcp "SELECT SalesPersonID, FirstName, LastName FROM AdventureWorks.Sales.vSalesPerson" &lt;br /&gt;queryout C:\Data\SalesPerson.csv -c -T -t,&lt;br /&gt;&lt;br /&gt;In this scenario, the query, enclosed in quotes, is passed into the bcp command instead of the table name. In addition, the out keyword has been replaced with queryout. But the rest of the command is the same as the preceding example. As a result, the SalesPerson.csv file will now contain only the three specified columns. You can also refine your query further: You can include, for example, a WHERE clause that qualifies which rows are returned from the source table.&lt;br /&gt;&lt;br /&gt;Importing data with the bcp utility &lt;br /&gt;&lt;br /&gt;The bcp utility makes importing data as simple as exporting data. To run the examples in this section, first run the following T-SQL script to create the SalesPeople table in the AdventureWorks database:&lt;br /&gt;&lt;br /&gt;USE AdventureWorks&lt;br /&gt;GO&lt;br /&gt;IF OBJECT_ID (N'SalesPeople', N'U') IS NOT NULL&lt;br /&gt;DROP TABLE dbo.SalesPeople&lt;br /&gt;GO&lt;br /&gt;CREATE TABLE dbo.SalesPeople (&lt;br /&gt;SalesPersonID INT IDENTITY PRIMARY KEY, &lt;br /&gt;FirstName NVARCHAR(50) NOT NULL, &lt;br /&gt;LastName NVARCHAR(50) NOT NULL&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;To import data, you need a source file from which to copy the data. For instance, the following command uses the recently created SalesPerson.csv file to load data into the SalesPeople table:&lt;br /&gt;&lt;br /&gt;bcp AdventureWorks.dbo.SalesPeople in C:\Data\SalesPerson.csv -c -T -t,&lt;br /&gt;&lt;br /&gt;First, you must specify the target table, followed by the in keyword that replaces out or queryout in this scenario. Next, you must specify the path and file name of the source file, followed by any applicable switches. &lt;br /&gt;&lt;br /&gt;When you run this command and view the results, note that while the source file includes the salesperson IDs, these values are not inserted into the SalesPersonID column. The column is defined as an IDENTITY column, so the source data is ignored. To retain the original values, you must add the -E switch to the command, as in the following example:&lt;br /&gt;&lt;br /&gt;bcp AdventureWorks.dbo.SalesPeople in C:\Data\SalesPerson.csv -c -T -t, -E&lt;br /&gt;&lt;br /&gt;Your table will now include the desired data.&lt;br /&gt;&lt;br /&gt;Using a format file&lt;br /&gt;&lt;br /&gt;When importing or exporting data, you may find that the structure of your source data does not match the structure of the target data. The columns in a text file, for example, might not be in the same order as those in your target table, or the number of columns may be different. You can address this issue by creating a format file that maps the structures of the source and destination. Let's look at an example to demonstrate how this works.&lt;br /&gt;&lt;br /&gt;Suppose you use the following command to export data from the vSalesPerson view to the SalesPeople.txt file:&lt;br /&gt;&lt;br /&gt;bcp "SELECT LastName, FirstName, SalesPersonID FROM AdventureWorks.Sales.vSalesPerson"&lt;br /&gt;queryout C:\Data\SalesPeople.txt -c -T -t,&lt;br /&gt;&lt;br /&gt;This command uses the same arguments as those in previous examples. Note, however, the order in which the columns are retrieved from the view: LastName, then FirstName, and finally SalesPersonID.&lt;br /&gt;&lt;br /&gt;Now suppose you plan to use this file to import data into the SalesPeople table. The columns in the table, however, are defined in a different order from that in the text file. To address this issue, you can create a format file to map the columns from the source to the destination. The following command demonstrates how to create a format file:&lt;br /&gt;&lt;br /&gt;bcp AdventureWorks.dbo.SalesPeople format nul -f C:\Data\SalesPeople.fmt -c -T -t,&lt;br /&gt;&lt;br /&gt;As previous examples show, the command first specifies the target table. This time, however, the table name is followed by the keywords format nul, which indicate that the bcp utility should create a format file. The -f argument is then used to specify a path and file name for the format file, followed by several switches. As a result, when you run this command, a format file is generated that contains the structure of the SalesPeople table.&lt;br /&gt;&lt;br /&gt;The following data shows the content of the SalesPeople.fmt format file that is generated by the above command:&lt;br /&gt;&lt;br /&gt;10.0        &lt;br /&gt;3        &lt;br /&gt;1 SQLCHAR   0   12   ","   1   SalesPersonID ""   &lt;br /&gt;2 SQLCHAR 0 100   "," 2 FirstName SQL_Latin1_General_CP1_CI_AS &lt;br /&gt;3 SQLCHAR 0 100 "\r\n"   3 LastName SQL_Latin1_General_CP1_CI_AS &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The first row of the file (10.0) identifies the version of bcp that is being used. The second row (3) identifies the number of columns in the table, and the next three rows provide information about the columns themselves:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The first field indicates the order in which the columns should appear in the source document. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The second field shows the source file data type for each column. Because I specified the -c switch when I generated the file, a character data type is used for all fields as they are extracted from the data file. SQL Server will then convert this data into the correct types as the data is inserted.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The third field shows the prefix length for the field, which is used by SQL Server to provide the most compact file storage. A value of 0 is used automatically if you specify the -c switch when creating the format file.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The fourth field indicates the number of bytes for the data type of a particular field.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The fifth field shows how columns and rows are terminated. Because the -t switch was used when creating the format file, the field values of the source file must be terminated by commas.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The sixth field maps to the order in which the columns appear in the SQL Server table.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The seventh and final field provides the collation information for character columns in the SQL server table.&lt;br /&gt;&lt;br /&gt;To use the format file to import data into the SalesPeople table, we must modify the file as follows:&lt;br /&gt;&lt;br /&gt;10.0        &lt;br /&gt;3        &lt;br /&gt;1   SQLCHAR   0   100   ","   3   LastName   SQL_Latin1_General_CP1_CI_AS   &lt;br /&gt;2 SQLCHAR 0 100 "," 2 FirstName SQL_Latin1_General_CP1_CI_AS &lt;br /&gt;3 SQLCHAR 0 12 "\r\n"   1 SalesPersonID   "" &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;As you can see, the order of the columns has been modified to reflect how they appear in the format file. The SalesPersonID column is now listed last and it is terminated with \r\n. The LastName column is now listed first and is terminated with a comma.&lt;br /&gt;&lt;br /&gt;After you modify and save the format file, it is ready to use in your bcp commands. The following example demonstrates how to call the format file:&lt;br /&gt;&lt;br /&gt;bcp AdventureWorks.dbo.SalesPeople in C:\Data\SalesPeople.txt -f C:\Data\SalesPeople.fmt –T&lt;br /&gt;&lt;br /&gt;Note that, when you import data from the SalesPeople.txt file, you must also use the -f switch to call the format file. Also notice that you no longer need to include the -t and -c switches because the information is now included in the format file.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-219212932296275497?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/219212932296275497/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=219212932296275497' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/219212932296275497'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/219212932296275497'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/03/importing-and-exporting-bulk-data-with.html' title='Importing and exporting bulk data with SQL Server&apos;s bcp utility'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-6932443631229362496</id><published>2009-02-13T02:19:00.000-08:00</published><updated>2009-02-13T02:28:26.281-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL SERVER 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Stored Procedure'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><title type='text'>Passing a Table to a Stored Procedure</title><content type='html'>SQL Server 2005 and previous versions do not support passing a table variable to a stored procedure. &lt;br /&gt;&lt;br /&gt;This article introduces the new feature added to SQL Server 2008, which supports passing a TABLE to a stored procedure or function.&lt;br /&gt;&lt;br /&gt;This article is based on SQL Server 2008 CTP 3. Some of the information may change by the time the product is finally released.&lt;br /&gt;&lt;br /&gt;Before we create a Function or Stored Procedure that accepts a TABLE variable, we need to define a User Defined TABLE Type. SQL Server 2008 introduced a new User defined TABLE type. A TABLE type represents the structure of a table that can be passed to a stored procedure or function.&lt;br /&gt;&lt;br /&gt;So the first step is to create a User Defined TABLE type. The following TSQL code creates a User defined TABLE type named "ItemInfo".&lt;br /&gt;&lt;br /&gt;     CREATE TYPE ItemInfo AS TABLE  ( &lt;br /&gt;         ItemNumber VARCHAR(50),&lt;br /&gt;         Qty INT     )&lt;br /&gt;&lt;br /&gt;You can use the system view SYS.TYPES to see the type that you have just created. The following query returns all the types defined in the system.&lt;br /&gt;&lt;br /&gt;   SELECT * FROM SYS.TYPES&lt;br /&gt;   /*  If you just need to find information about the TABLE types, you could find it from the following TSQL query.*/&lt;br /&gt;   SELECT * FROM SYS.TYPES WHERE is_table_type = 1&lt;br /&gt;/* There is another view, which is handy to find information about TABLE types. */&lt;br /&gt;   SELECT * FROM SYS.TABLE_TYPES&lt;br /&gt;&lt;br /&gt;We have created a TABLE type that we need. Now let us see how it works. Let us create a variable of type "ItemInfo" and try to insert a few records to it. Then lets query the table variable to see if the information is correctly inserted. [code]&lt;br /&gt;&lt;br /&gt; /* Let us declare a variable of type ItemInfo which is a TABLE Type */&lt;br /&gt;&lt;br /&gt;     DECLARE @items AS ItemInfo&lt;br /&gt;/*   Insert values to the variable */&lt;br /&gt; INSERT INTO @Items (ItemNumber, Qty)&lt;br /&gt;&lt;br /&gt;    SELECT '11000', 100 UNION ALL&lt;br /&gt;&lt;br /&gt;    SELECT '22000', 200 UNION ALL&lt;br /&gt;    SELECT '33000', 300&lt;br /&gt;&lt;br /&gt;/*   Lets check if the values are correctly inserted or not */&lt;br /&gt;&lt;br /&gt;    SELECT * FROM @Items&lt;br /&gt;&lt;br /&gt;/* OUTPUT:  &lt;br /&gt;    ItemNumber                                         Qty&lt;br /&gt;    -------------------------------------------------- -----------&lt;br /&gt;  11000                                             100&lt;br /&gt;  22000                                             200&lt;br /&gt;  33000                                             300&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;Now let us create a stored procedure that accepts a TABLE variable. Let us create a very simple stored procedure which accepts a TABLE variable and SELECTs contents of the table.&lt;br /&gt;&lt;br /&gt;    1 CREATE PROCEDURE TableParamDemo&lt;br /&gt;    2 (&lt;br /&gt;    3     @Items ItemInfo&lt;br /&gt;    4 )&lt;br /&gt;    5 &lt;br /&gt;    6 AS&lt;br /&gt;    7 &lt;br /&gt;    8 SELECT *&lt;br /&gt;    9 FROM @Items&lt;br /&gt;&lt;br /&gt;Well, this would generate the following error:&lt;br /&gt;&lt;br /&gt;    1 /*&lt;br /&gt;    2 Msg 352, Level 15, State 1, Procedure TableParamDemo, Line 1&lt;br /&gt;    3 The table-valued parameter "@Items" must be declared with the READONLY option.&lt;br /&gt;    4 */&lt;br /&gt;&lt;br /&gt;A table variable that is passed to a stored procedure or function should be marked as READONLY. The "callee" cannot modify the table being passed into it. Here is the correct code.&lt;br /&gt;&lt;br /&gt;    1 CREATE PROCEDURE TableParamDemo&lt;br /&gt;    2 (&lt;br /&gt;    3     @Items ItemInfo READONLY&lt;br /&gt;    4 )&lt;br /&gt;    5 &lt;br /&gt;   6 AS&lt;br /&gt;    7 &lt;br /&gt;    8 SELECT *&lt;br /&gt;    9 FROM @Items&lt;br /&gt;&lt;br /&gt;Now let us execute the stored procedure we just created. Run the following code.&lt;br /&gt;&lt;br /&gt;    1 /*&lt;br /&gt;    2     declare the variable&lt;br /&gt;    3 */&lt;br /&gt;    4 DECLARE @items AS ItemInfo&lt;br /&gt;    5 &lt;br /&gt;    6 /*&lt;br /&gt;    7     Insert values to the variable&lt;br /&gt;    8 */&lt;br /&gt;    9 &lt;br /&gt;   10 INSERT INTO @Items (ItemNumber, Qty)&lt;br /&gt;   11     SELECT '11000', 100 UNION ALL&lt;br /&gt;   12     SELECT '22000', 200 UNION ALL&lt;br /&gt;   13     SELECT '33000', 300&lt;br /&gt;   14 &lt;br /&gt;   15 /*&lt;br /&gt;   16     Execute the procedure&lt;br /&gt;   17 */&lt;br /&gt;   18 EXECUTE TableParamDemo @Items&lt;br /&gt;   19 &lt;br /&gt;   20 /*&lt;br /&gt;&lt;br /&gt;   21 OUTPUT:&lt;br /&gt;   22 &lt;br /&gt;   23 ItemNumber                                         Qty&lt;br /&gt;   24 -------------------------------------------------- -----------&lt;br /&gt;   25 11000                                             100&lt;br /&gt;   26 22000                                             200&lt;br /&gt;   27 33000                                             300&lt;br /&gt;  28 &lt;br /&gt;   29 */&lt;br /&gt;&lt;br /&gt;You cannot modify the TABLE parameter passed into the stored procedure. If you try to do so, you will get an error as shown in the following example.&lt;br /&gt;&lt;br /&gt;    1 CREATE PROCEDURE TableParamDemo&lt;br /&gt;    2 (&lt;br /&gt;    3     @Items ItemInfo READONLY&lt;br /&gt;    4 )&lt;br /&gt;    5 &lt;br /&gt;    6 AS&lt;br /&gt;    7 &lt;br /&gt;    8 SELECT *&lt;br /&gt;    9 FROM @Items&lt;br /&gt;   10 &lt;br /&gt;   11 INSERT INTO @Items (ItemNumber, Qty)&lt;br /&gt;   12     SELECT '1001', 20&lt;br /&gt;   13 &lt;br /&gt;   14 /*&lt;br /&gt;   15 OUTPUT:&lt;br /&gt;   16 &lt;br /&gt;   17 Msg 10700, Level 16, State 1, Procedure TableParamDemo, Line 11&lt;br /&gt;   18 The table-valued parameter "@Items" is READONLY and cannot be modified.&lt;br /&gt;   19 */&lt;br /&gt;Conclusions&lt;br /&gt;&lt;br /&gt;The support for TABLE variables is very interesting. While working with User Defined TABLE Type, please note that you cannot use it as a column of a table. Please also note that, once created, you cannot alter the structure of the TABLE.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-6932443631229362496?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/6932443631229362496/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=6932443631229362496' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6932443631229362496'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6932443631229362496'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/02/passing-table-to-stored-procedure.html' title='Passing a Table to a Stored Procedure'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-9149060487599705519</id><published>2009-02-13T02:16:00.000-08:00</published><updated>2009-02-13T02:17:28.899-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>SQL Server Federated Database Performance Tuning</title><content type='html'>For very large databases, consider using federated database servers to balance the processing load across multiple SQL 2000 or 2005 servers. This technique horizontally partitions SQL 2000 or 2005 data over one or more SQL Servers, allowing the client application to send SQL statements to the server in the federation having most of the data required by the statement. This way, the query load is spread over multiple SQL 2000 or 2005 servers.&lt;br /&gt;&lt;br /&gt;Federated database servers works best for databases that can be naturally partitioned over multiple servers. For example, if the data can be segregated by product line or geographical location, then the data can easily be separated over multiple databases in a federation.&lt;br /&gt;&lt;br /&gt;Here's a federated database might work. Let's say that a company has customers in North America, South America, Europe, and Asia, and that the data stored for every customer, no matter where they are located, is identical. One option would be to partition the data based horizontally on continent. In this case, four different SQL Servers would be needed in the federation, each storing its respective data.&lt;br /&gt;&lt;br /&gt;In almost all cases, when a query is run against the customer data stored in the federated SQL Servers, the data will all be related to a specific continent. Because of this, only one SQL Server will be hit with the query, not all of the SQL Servers. And assuming that customers in all continents will be queried, the separation of customers by continent on different SQL Servers will spread the queries among all of the servers, allowing greater performance and scalability. [2000, 2005]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-9149060487599705519?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/9149060487599705519/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=9149060487599705519' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/9149060487599705519'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/9149060487599705519'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/02/sql-server-federated-database.html' title='SQL Server Federated Database Performance Tuning'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-8050453323789835437</id><published>2009-02-08T07:15:00.000-08:00</published><updated>2009-02-08T07:20:21.947-08:00</updated><title type='text'>String comparison: binary vs. dictionary</title><content type='html'>It is well known that you get better performance if you compare two strings in a binary collation than in a dictionary collation. But is the performance difference significant enough to warrant the use of an explicit COLLATE clause in the string comparison expression? That was a question came up in a conversation I had with a colleague recently.&lt;br /&gt;&lt;br /&gt; To get a feel for the extent of the performance difference, I ran several tests comparing two commonly-used collations: &lt;br /&gt;&lt;br /&gt;·      Latin1_General_BIN, and &lt;br /&gt;·      SQL_Latin1_General_CP1_CI_AS&lt;br /&gt; &lt;br /&gt;More specifically, I ran the following T-SQL script in a loop for 100 times:&lt;br /&gt;&lt;br /&gt;DECLARE @s1 varchar(max), @s2 varchar(max), @i int&lt;br /&gt;DECLARE @dummy int, @dt datetime&lt;br /&gt;DECLARE @length int&lt;br /&gt;&lt;br /&gt;SET @length = 1000000  -- or 100, or 1000000&lt;br /&gt;&lt;br /&gt;SELECT @s1 = REPLICATE(CAST('a' as varchar(max)), @length)&lt;br /&gt;SELECT @s2 = REPLICATE(CAST('a' as varchar(max)), @length)&lt;br /&gt;&lt;br /&gt;SELECT @i = 1, @dt = GETDATE()&lt;br /&gt;&lt;br /&gt;    WHILE @i &lt; 1000&lt;br /&gt;    BEGIN&lt;br /&gt;       IF @s1 = @s2 COLLATE SQL_Latin1_General_CP1_CI_AS &lt;br /&gt;       --IF @s1 = @s2 COLLATE Latin1_General_BIN&lt;br /&gt;            SET @dummy =0&lt;br /&gt;       SET @i = @i + 1&lt;br /&gt;    END&lt;br /&gt;&lt;br /&gt;SELECT DATEDIFF(ms, @dt, GETDATE())&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;The script was run in a number of scenarios:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;·      The @length variable was set to 100, 10,000, and 1,000,000 to see the impact of the string length on the comparison method,&lt;br /&gt;&lt;br /&gt;·      The string comparison was done in the IF clause with either the Latin1_General_BIN collation or the SQL_Latin1_General_CP1_CI_AS collation&lt;br /&gt;&lt;br /&gt;The most salient point to note is that as the string length increases, the performance difference between the two comparison methods increases. While there was no performance difference when the strings were 100 bytes long, the binary comparison was about twice as fast as the dictionary comparison when the string length was 10,000 bytes. When the string length increased to 1,000,000, the binary comparison was about seven times faster.&lt;br /&gt;&lt;br /&gt; So, if you are comparing two short strings, you probably shouldn’t bother to explicitly cast the comparison into a binary collation. But when the strings can be very long, it can result in a huge performance improvement to explicitly specify a binary collation for string comparison.&lt;br /&gt;&lt;br /&gt; Note that string comparison in COLLATE Latin1_General_BIN and string comparison in COLLATE SQL_Latin1_General_CP1_CI_AS have different semantics. But there are many cases where you have control over your data, and the difference in comparison semantics does not matter (e.g. when you know your data is all in lower case). &lt;br /&gt;&lt;br /&gt; Nothing is particularly new here. Just want to contribute some data points to the community.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-8050453323789835437?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/8050453323789835437/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=8050453323789835437' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/8050453323789835437'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/8050453323789835437'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/02/string-comparison-binary-vs-dictionary.html' title='String comparison: binary vs. dictionary'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-5381854237727109969</id><published>2009-02-01T22:53:00.000-08:00</published><updated>2009-02-01T22:55:02.343-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL SERVER 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Indexes'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>Indexed View Performance Tuning and Optimization</title><content type='html'>If your application needs to access views often, consider adding a unique clustered index to your views to significantly improve performance. When a view is created with a unique clustered index, the view is created with the clustered index, which is created and stored in the database the same way as a clustered index on a table.&lt;br /&gt;&lt;br /&gt;Once a unique clustered index has been created for a view, you can also create non-clustered indexes for the same view, which can be used by queries against the view to enhance performance.&lt;br /&gt;&lt;br /&gt;As the underlying tables of the view are modified, the clustered index, and any non-clustered indexes of the view, is modified so that it is always up-to-date when it is accessed. And just like indexes on tables, indexes on views experience modification overhead. So only add an index to a view if the benefit of its speed increase when running exceeds the time it takes to update the view's index. &lt;br /&gt;&lt;br /&gt;Indexed views can be used by SQL Server two different ways. First, the view can be called directly from a query, as conventional views are currently used. But instead of running the view's underlying SELECT statement and creating the view's result set on the fly, it uses the unique clustered index to display the results of the view almost immediately. Second, any query that is run on SQL Server 2000/2005 is automatically evaluated to see if any existing indexed views exist that would fulfill the query. If so, the Query Optimizer uses the indexed query, even though it has not been specified in the query, greatly speeding the query.&lt;br /&gt;&lt;br /&gt;To get the most benefit out of indexed views, you need to use the SQL Server 2000/2005 Enterprise Edition. While you can create indexed views in the other editions of SQL Server 2000/2005, they will not be automatically considered by the query optimizer, and they require the use of the NOEXPAND hint to be used. [2000, 2005]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-5381854237727109969?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/5381854237727109969/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=5381854237727109969' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5381854237727109969'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5381854237727109969'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/02/indexed-view-performance-tuning-and.html' title='Indexed View Performance Tuning and Optimization'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-1611189832452579344</id><published>2009-01-30T06:23:00.000-08:00</published><updated>2009-01-30T06:29:14.362-08:00</updated><title type='text'>Good bye</title><content type='html'>&lt;p&gt;&lt;br /&gt;Not sure any words or condolences make an announcement like this any less painful.  Families and friends are directly impacted in a negative way when you hear about news like this and I consider all of you as friends and extended family members.  I don't even want to think about the anger and disappointment everyone feels over there.  To say I am shocked and confused is an understatement. &lt;br /&gt;&lt;br /&gt;Playing a blame game of what went wrong and where did it go wrong leaves me with no answers or directions.  Its easy to blame it on the current Economy of the USA, and perhaps I have been somewhat blinded by the fact it has not already hit our company.  I assumed this was hitting companies much bigger than ourselves that may have been overstaffed to start with.  Thinking it was more manufacturing based than educational based.  Did not correlate the massive amounts of home forclosures tied to taxes which support the educational world.  (90% comes from state taxes).  Did not think about the companies and how they pay taxes on profits.  Once again, companies all downsizing as there are no profits, hence no taxes paid by companies either.    Here is a local story I found online today as well.  &lt;a href="http://www.waow.com/Global/Story.asp?S=9442775" target="_blank"&gt;http://www.waow.com/Global/Story.asp?S=9442775&lt;/a&gt;  I heard more about things like this on the news last night.  (Keep in mind Wisconsin is only 1 state among many we are infiltrated with).   Seems like every night I turn on the news, there is a new local company cutting jobs.  Listen to the radio and massive layoffs for other companies forcasting billion dollar losses.  Shutting down stores, factories.    &lt;br /&gt; &lt;br /&gt;I hope our time together would be classified as one of the best experiences in our lives.  I hope we have allowed you to become better programmers than when you first started based on the programs you have developed.  I hope Suresh and myself will be remembered as one of the best managers you have ever had the ability to work for.  Perhaps this is not true with the most recent of events, but I am SO PROUD of the work you have done.  As a team, you guys have shown so much growth thru our time together. &lt;br /&gt;&lt;br /&gt;Anil, you have been a rock on this team with your programming practices and delivery builds.  I think your fundamentals have improved greatly as well as your ability to take complex concepts and ideas (Program Selection on CMT, SystemInfo.dll, Object Oriented Class level project builds) and bring them to life.  There is no doubt in my mind that you will go on to bigger and better things in the programming world.  You have what it takes to be a great programmer in this world.   &lt;br /&gt;&lt;br /&gt;Its hard to talk about success when external factors force our working relationships to be closed and terminated.  I will never consider the time we spent working together anything less than professional, productive and honorable.  I was lucky to be able to work with a staff as great as what you have been.  I really do hope you stay in touch and keep me up to date on personal as well as professional experiences in your lives.  This is a sad day for Renaissance Learning and one I never want to be part of again.  Several at RLI home offices have also been let go and over the next few months, more could happen.  Its a scary time that nobody wants any part of.  I hear from my grandparents about the Great Depression and how bad it was.  Its a different time now, yet watching so many people lose their jobs, even outside of RLI and surrounding communities makes me fear that it will be a long and difficult journey back to where we need to be.  I just hope we remember what it took to get us there and all the people that were sacrificed in the process.  &lt;/p&gt;&lt;p&gt;Anil, if you ever need a reference, don't be afraid to email me.  Currently I check my work email more often than my personal one, but as we have seen, things can change way to quick.  So stay in touch to both accounts.  &lt;/p&gt;&lt;p&gt;Thank you for everything you have developed for us as its been more than I could have asked for.  &lt;/p&gt;&lt;p&gt;  &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-1611189832452579344?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/1611189832452579344/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=1611189832452579344' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/1611189832452579344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/1611189832452579344'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/01/good-bye.html' title='Good bye'/><author><name>Jim C</name><uri>http://www.blogger.com/profile/04164936077211641619</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-752647878894314030</id><published>2009-01-27T21:36:00.000-08:00</published><updated>2009-01-27T21:42:33.081-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL SERVER 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='restore backup'/><title type='text'>Restore a SQL Server 2008 Database into SQL Server 2005</title><content type='html'>If you've tried to back up a database in SQL Server 2008 and then restore it into SQL Server 2005, you know that the database backups are not backward compatible. However, with SQL Server 2008 Management Studio, you can script data and schemas in SQL Server 2005 mode. This 10-Minute Solution takes you through the steps to back up the Northwind database on SQL Server 2008 and restore it to SQL Server 2005.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Problem&lt;/span&gt;&lt;br /&gt;Transferring databases from SQL Server 2008 to SQL Server 2005 is not possible with standard backup and restore facilities.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Solution&lt;/span&gt;&lt;br /&gt;Leverage the scripting wizard in SQL Server 2008 to script data as well as schemas in SQL Server 2005 compatibility mode.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Using the "Generate SQL Server Scripts" Wizard&lt;/span&gt;&lt;br /&gt;The Northwind database is no longer shipped as part of the SQL Server installation, but you can download it from &lt;a href="http://go.microsoft.com"&gt;go.microsoft.com&lt;/a&gt;. The data is scripted as INSERT statements.&lt;br /&gt;&lt;br /&gt;To create the scripts, you have to run the "Generate SQL Server Scripts" wizard, which you can run within SQL Server Management Studio (once Object Explorer is connected to the appropriate instance) by right clicking on the database and selecting "Tasks –&gt; Generate Scripts." &lt;br /&gt;&lt;br /&gt;1. Click "Script all objects in the selected database" (see Figure 2), and then click "Next." &lt;br /&gt;&lt;br /&gt;2. Amend the script options: Specifically, set "Script for Server Version" to "SQL Server 2005" and set "Script Data" to "True" (see Figure 3). (SQL Server 2000 is also supported.) If you are putting the database on a new instance for the first time, make sure the "Script Database Create" option is set to "True." Click "Next" when you are happy with the options. &lt;br /&gt;&lt;br /&gt;3. Select "Script to file," select the file name, and choose "Single file" and  Click "Next" for a summary&lt;br /&gt;4. Now click on "Finish" to get progress messages while the script runs and completes.&lt;br /&gt;  If the generation process fails, then you can use the "Report" option to see why.&lt;br /&gt;&lt;br /&gt;5. When the scripting is completed, look for the following lines:&lt;br /&gt;&lt;br /&gt;      CREATE DATABASE [Northwind] ON  PRIMARY &lt;br /&gt;&lt;br /&gt;      (NAME = N'Northwind', FILENAME =&lt;br /&gt;       N'C:\Program Files\Microsoft SQL Server\MSSQL10.SQL2008\MSSQL\DATA\northwnd.mdf' ,&lt;br /&gt;       SIZE = 3328KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )&lt;br /&gt;&lt;br /&gt;       LOG ON &lt;br /&gt;&lt;br /&gt;      (NAME = N'Northwind_log', FILENAME =&lt;br /&gt;       N'C:\Program Files\Microsoft SQL Server\MSSQL10.SQL2008\MSSQL\DATA\northwnd.ldf' , &lt;br /&gt;       SIZE = 1024KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)&lt;br /&gt;&lt;br /&gt;      GO&lt;br /&gt;&lt;br /&gt;      You will need to amend the paths to a valid path for the computer on which you are running. You also will need to comment out the following lines like this:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;      --EXEC sys.sp_db_vardecimal_storage_format N'Northwind', N'ON'&lt;br /&gt;      --GO&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Once you have made these changes, you can run the script in SQL Server 2005 Management Studio to recreate the database in your development environment. You can now test data against SQL Server 2008 and SQL Server 2005.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;The Inevitable Limitations&lt;/span&gt;&lt;br /&gt;Of course, this technique is not without its limitations. Here are a few to bear in mind:&lt;br /&gt;&lt;br /&gt;    * The data is insecure, as it is in clear readable text. So if you are using real data, you should delete the file created once you have loaded it into SQL Server 2005. You can regenerate the file from the SQL 2008 backup, if necessary.&lt;br /&gt;    * If you have a database with a large amount of data, the script file, of course, will be huge.&lt;br /&gt;    * SQL Server 2008 specifics in the source database will not be migrated.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-752647878894314030?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/752647878894314030/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=752647878894314030' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/752647878894314030'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/752647878894314030'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/01/restore-sql-server-2008-database-into.html' title='Restore a SQL Server 2008 Database into SQL Server 2005'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-6108663515103469601</id><published>2009-01-27T21:26:00.000-08:00</published><updated>2009-01-27T21:32:02.045-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SMO'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><title type='text'>SQL Server 2008 Management Studio Trick</title><content type='html'>I had a database selected in the Object Explorer window and I had the Object Explorer Details window open. I noticed a little icon at the bottom of the screen:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_R4ryh6DRFl8/SX_tG_nrCAI/AAAAAAAAAE4/-dnUAVmZrK8/s1600-h/2008ms_icon.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 123px; height: 72px;" src="http://4.bp.blogspot.com/_R4ryh6DRFl8/SX_tG_nrCAI/AAAAAAAAAE4/-dnUAVmZrK8/s320/2008ms_icon.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5296212391223822338" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Then I saw that the bar above it was a moveable bar. So I moved it and saw this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_R4ryh6DRFl8/SX_taDVZSjI/AAAAAAAAAFA/SEIr1TPULdA/s1600-h/2008ms_db.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 248px; height: 320px;" src="http://3.bp.blogspot.com/_R4ryh6DRFl8/SX_taDVZSjI/AAAAAAAAAFA/SEIr1TPULdA/s320/2008ms_db.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5296212718638418482" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Whoa! So then I tried a table, HumanResources.Department from AdventureWorks2008:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_R4ryh6DRFl8/SX_thlHPAJI/AAAAAAAAAFI/34oaJPidUzE/s1600-h/2008ms_table.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 287px; height: 249px;" src="http://3.bp.blogspot.com/_R4ryh6DRFl8/SX_thlHPAJI/AAAAAAAAAFI/34oaJPidUzE/s320/2008ms_table.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5296212847964913810" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Which caused me to check a procedure:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_R4ryh6DRFl8/SX_tmyuV2KI/AAAAAAAAAFQ/aP4l65eYhUQ/s1600-h/2008ms_proc.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 312px; height: 155px;" src="http://2.bp.blogspot.com/_R4ryh6DRFl8/SX_tmyuV2KI/AAAAAAAAAFQ/aP4l65eYhUQ/s320/2008ms_proc.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5296212937517947042" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Each line has a little icon on the side that lets you copy it, line by line. It’s really just a way to display the basic properties about the object in a readily accessible format. It’s not going to change my life, or yours, but it sure is handy to know a quick way to access some basic information.&lt;br /&gt;&lt;br /&gt;F4 is also a lot more handy in SSMS these days than it used to be. My favorite is when you hit F4 after clicking on a node in a graphical execution plan. But it works for several other things as well, including tables, procedures, etc. And doesn’t make you keep object explorer details open (which causes some problems of its own, at least pre-CU3).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-6108663515103469601?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/6108663515103469601/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=6108663515103469601' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6108663515103469601'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6108663515103469601'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/01/sql-server-2008-management-studio-trick.html' title='SQL Server 2008 Management Studio Trick'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_R4ryh6DRFl8/SX_tG_nrCAI/AAAAAAAAAE4/-dnUAVmZrK8/s72-c/2008ms_icon.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-6142364060125866463</id><published>2009-01-27T21:19:00.001-08:00</published><updated>2009-01-27T21:19:31.371-08:00</updated><title type='text'>SQL Server Query Execution Plan Analysis</title><content type='html'>If your SQL Server has multiple CPUs, and you have not changed the default setting in SQL Server to limit SQL Server's ability to use all of the CPUs in the server, then the query optimizer will consider using parallelism to execute some queries. Parallelism refers to the ability to execute a query on more than one CPU at the same time. In many cases, a query that runs on multiple processors is faster than a query that only runs on a single processor, but not always.&lt;br /&gt;&lt;br /&gt;The Query Optimizer will not always use parallelism, even though it potentially can. This is because the Query Optimizer takes a variety of different things into consideration before it decides to use parallelism. For example, how many active concurrent connections are there, how busy is the CPU, is there enough available memory to run parallel queries, how many rows are being processed, and what is the type of query being run? Once the Query Optimizer collects all the facts, then it decides if parallelism is best for this particular run of the query. You may find that one time a query runs without parallelism, but later, the same query runs again, but this time, parallelism is used.&lt;br /&gt;&lt;br /&gt;In some cases, the overhead of using multiple processors is greater than the resource savings of using them. While the query processor does try to weigh the pros and cons of using a parallel query, it doesn't always guess correctly.&lt;br /&gt;&lt;br /&gt;If you suspect that parallelism might be hurting the performance of a particular query, you can turn off parallelism for this particular query by using the OPTION (MAXDOP 1) hint.&lt;br /&gt;&lt;br /&gt;The only way to know for sure is to test the query both ways, and see what happens. [7.0, 2000, 2005]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-6142364060125866463?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/6142364060125866463/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=6142364060125866463' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6142364060125866463'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6142364060125866463'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/01/sql-server-query-execution-plan.html' title='SQL Server Query Execution Plan Analysis'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-2061610505424106132</id><published>2009-01-21T20:34:00.000-08:00</published><updated>2009-01-21T20:37:10.338-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='64 bit SQL Server'/><title type='text'>How can I confirm whether a SQL Server installation is 32 or x64 bit?</title><content type='html'>How about to confirm the component type when a particular SQL Server 2005 instance has been installed?&lt;br /&gt;&lt;br /&gt;You can obtain the relevant information using a TSQL statement or referring to the SQL installation directory on that Windows server. Each of these options are outlined below:&lt;br /&gt;&lt;br /&gt;    Transact-SQL statement:&lt;br /&gt;&lt;br /&gt;    Execute select @@version from Query Editor or Query Analyzer and the results will be :&lt;br /&gt;&lt;br /&gt;        SQL 90&lt;br /&gt;&lt;br /&gt;            Microsoft SQL Server 2005 - 9.00.2153.00 (X64) May 9 2006 13:58:37 Copyright (c) 1988-2005 Microsoft Corporation Standard Edition (64-bit) on Windows NT 5.2 (Build 3790: Service Pack 1)&lt;br /&gt;&lt;br /&gt;            Microsoft SQL Server 2005 - 9.00.2047.00 (Intel X86) Apr 14 2006 01:12:25 Copyright (c) 1988-2005 Microsoft CorporationStandard Edition on Windows NT 5.2 (Build 3790: Service Pack 1)&lt;br /&gt;&lt;br /&gt;        SQL 80&lt;br /&gt;&lt;br /&gt;            Microsoft SQL Server  2000 - 8.00.2148 (Intel X86)  Jul  7 2005 20:33:10  Copyright (c) 1988-2003 Microsoft Corporation Standard Edition on Windows NT 5.0 (Build 2195: Service Pack 4)&lt;br /&gt;&lt;br /&gt;    If the installation is 32 bit then as highlighted above you will see 'Intel X86', if not then you will see 'X64' after the SQL Server version number.&lt;br /&gt;&lt;br /&gt;    SQL Server Installation Directory:&lt;br /&gt;&lt;br /&gt;    The default installation directory for SQL Server is \Program Files\ and the same can be referenced as below on a x64 operating system:&lt;br /&gt;&lt;br /&gt;        C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Binn&lt;br /&gt;&lt;br /&gt;        32-bit:&lt;br /&gt;        C:\Program Files (x86)\Microsoft SQL Server\MSSQL.1\MSSQL\Binn&lt;br /&gt;&lt;br /&gt;For more information on the SQL Server 2005 x64 bit refer to&lt;br /&gt;&lt;a href="http://www.microsoft.com/sqlserver/2005/en/us/64-bit.aspx"&gt;http://www.microsoft.com/sqlserver/2005/en/us/64-bit.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-2061610505424106132?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/2061610505424106132/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=2061610505424106132' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/2061610505424106132'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/2061610505424106132'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/01/how-can-i-confirm-whether-sql-server.html' title='How can I confirm whether a SQL Server installation is 32 or x64 bit?'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-5784411592038526761</id><published>2009-01-21T20:14:00.000-08:00</published><updated>2009-01-21T20:16:12.374-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Import- Export'/><title type='text'>How to import an Excel file which has columns with more than 255 characters to SQL Server using SSIS?</title><content type='html'>When the driver determines that an Excel column contains text data, the driver selects the data type based on the longest value that it samples. If the driver does not discover any values longer than 255 characters in the rows that it samples, it treats the column as a 255-character string column instead of a memo column. Therefore, values longer than 255 characters may be truncated. To import data from a memo column without truncation, you must make sure that the memo column in at least one of the sampled rows contains a value longer than 255 characters, or you must increase the number of rows sampled by the driver to include such a row.&lt;br /&gt;&lt;br /&gt;You can increase the number of rows sampled by increasing the value of TypeGuessRows under the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Excel registry key.  By default it is 8 rows.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-5784411592038526761?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/5784411592038526761/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=5784411592038526761' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5784411592038526761'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5784411592038526761'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/01/how-to-import-excel-file-which-has.html' title='How to import an Excel file which has columns with more than 255 characters to SQL Server using SSIS?'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-2564345485460625571</id><published>2009-01-21T03:17:00.000-08:00</published><updated>2009-01-21T03:20:35.219-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL SERVER 2005'/><title type='text'>Uninstall and Remove Multiple Database Instances of Microsoft SQL Server 2005</title><content type='html'>When database system administrator installs Microsoft SQL Server 2005 and creates a few database engine instances, there will be problem and hard time to remove and uninstall these multiple database instance components and the corresponding SQL Server services. When users try to uninstall Microsoft SQL Server 2005 or remove database instance components using Add and Remove Programs or Uninstall or change a programs (Vista) in Control Panel, only one SQL Server 2005 database engine can be selected. After uninstallation has completed, when users attempt to run the SQL Server 2K5 Uninstall to completely clean remove any other instances or components, the action will fail with error message saying the uninstaller shortcut entry is invalid and asked if you want to remove the link.&lt;br /&gt;&lt;br /&gt;When you run Add and Remove Programs or Programs and Features (for Windows Vista) in Control Panel, it actually executes the ARPWrapper.exe program that is installed by Microsoft SQL Server Setup Support Files component by using the /Remove option. However, when ARPWrapper.exe completes its removal task, the program also uninstall Microsoft SQL Server Setup Support Files component and hence removes itself or deletes the reference to the ARPWrapper.exe program. This is the cause that prevents administrators to run the uninstaller again to remove database instances or uninstall SQL Server 2005.&lt;br /&gt;&lt;br /&gt;The resolution to remove multiple database engine instances from Microsoft SQL Server 2005 is to install ARPWrapper.exe again after removing each components. The following guide provides step-by-step instructions on how to uninstall stand-alone or multiple instance of SQL Server 2005 manually.&lt;br /&gt;&lt;br /&gt;   1. Login to the server with an administrator user account, or SQL Server 2005 service account.&lt;br /&gt;   2. Stop all active SQL Server services in Services applet in Control Panel as any active connections may prevent the uninstallation process from finishing successfully.&lt;br /&gt;   3. Go to Control Panel and then Add or Remove Programs applet.&lt;br /&gt;   4. Search and verify that Microsoft SQL Server Setup Support Files appears in the list of installed programs. If it’s found, proceed to next step. If Microsoft SQL Server Setup Support Files component is not listed as one of the installed program, install the component by running sqlsupport.msi file locates in Servers\setup\ folder of the original SQL Server 2005 installation media, or disc, folder and USB flash drive that contains SQL Server 2005 setup files.&lt;br /&gt;   5. Open command prompt (in Vista, use command prompt with administrator rights), and run the following command to uninstall the SQL Server components:&lt;br /&gt;&lt;br /&gt;      %ProgramFiles%\Microsoft SQL Server\90\Setup Bootstrap\ARPWrapper.exe /Remove&lt;br /&gt;   6. Uninstall the SQL Server instance components such as database engine one at a time.&lt;br /&gt;&lt;br /&gt;      Uninstall SQL Server 2005 Components&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_R4ryh6DRFl8/SXcErvbfcWI/AAAAAAAAAEw/hlgab8niBhs/s1600-h/remove-sql-2005.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 296px;" src="http://3.bp.blogspot.com/_R4ryh6DRFl8/SXcErvbfcWI/AAAAAAAAAEw/hlgab8niBhs/s320/remove-sql-2005.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5293705036509966690" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;   7. Once the removal completes, repeat all of the above steps again until all the SQL Server components are uninstalled.&lt;br /&gt;   8. Finally, uninstall the Microsoft SQL Server Setup Support Files component by using Add or Remove Programs (It should has been removed, but double check to ensure that).&lt;br /&gt;&lt;br /&gt;Above guide assumes that you didn’t encounter any other problems, and simply want to get rid of all DB instances of the SQL Server 2005. If you have other issues, refer to KB909906 on how to manually uninstall SQL Server.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-2564345485460625571?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/2564345485460625571/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=2564345485460625571' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/2564345485460625571'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/2564345485460625571'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/01/uninstall-and-remove-multiple-database.html' title='Uninstall and Remove Multiple Database Instances of Microsoft SQL Server 2005'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_R4ryh6DRFl8/SXcErvbfcWI/AAAAAAAAAEw/hlgab8niBhs/s72-c/remove-sql-2005.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-3047130321993682345</id><published>2009-01-20T21:32:00.000-08:00</published><updated>2009-01-20T21:35:40.793-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><title type='text'>25 most dangerous programming errors</title><content type='html'>The SANS Institute has explanations of the 25 most dangerous programming errors, according to security experts from all over the world working for a number of different computer security organizations. As pointed out early in the article:&lt;br /&gt;&lt;br /&gt;    The impact of these errors is far reaching. Just two of them led to more than 1.5 million web site security breaches during 2008 - and those breaches cascaded onto the computers of people who visited those web sites, turning their computers into zombies.&lt;br /&gt;&lt;br /&gt;The 25 errors, organized by type, are: &lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;br /&gt;Insecure Interaction Between Components&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    * Improper Input Validation&lt;br /&gt;    * Improper Encoding or Escaping of Output&lt;br /&gt;    * Failure to Preserve SQL Query Structure&lt;br /&gt;    * Failure to Preserve Web Page Structure&lt;br /&gt;    * Failure to Preserve OS Command Structure&lt;br /&gt;    * Cleartext Transmission of Sensitive Information&lt;br /&gt;    * Cross-Site Request Forgery&lt;br /&gt;    * Race Condition&lt;br /&gt;    * Error Message Information Leak&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Risky Resource Management&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    * Failure to Constrain Operations within the Bounds of a Memory Buffer&lt;br /&gt;    * External Control of Critical State Data&lt;br /&gt;    * External Control of File Name or Path&lt;br /&gt;    * Untrusted Search Path&lt;br /&gt;    * Failure to Control Generation of Code&lt;br /&gt;    * Download of Code Without Integrity Check&lt;br /&gt;    * Improper Resource Shutdown or Release&lt;br /&gt;    * Improper Initialization&lt;br /&gt;    * Incorrect Calculation&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Porous Defenses&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;    * Improper Access Control&lt;br /&gt;    * Use of a Broken or Risky Cryptographic Algorithm&lt;br /&gt;    * Hard-Coded Password&lt;br /&gt;    * Insecure Permission Assignment for Critical Resource&lt;br /&gt;    * Use of Insufficiently Random Values&lt;br /&gt;    * Execution with Unnecessary Privileges&lt;br /&gt;    * Client-Side Enforcement of Server-Side Security&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-3047130321993682345?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/3047130321993682345/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=3047130321993682345' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3047130321993682345'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3047130321993682345'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/01/25-most-dangerous-programming-errors.html' title='25 most dangerous programming errors'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-8438826875302804488</id><published>2009-01-18T20:37:00.000-08:00</published><updated>2009-01-18T20:39:36.021-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Indexes'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>Seek or scan?</title><content type='html'>One very common question that I see on the forums is on index seeks and index scans. A query is resulting in a table/clustered index scan, even though there’s an index on one or more of the columns been searched on.&lt;br /&gt;&lt;br /&gt;One of the more common reasons that this happens is because the index in question is not covering, and SQL has determined that the cost of doing the lookups to fetch the extra columns is higher than the cost of scanning the entire table.&lt;br /&gt;&lt;br /&gt;If an index does not cover a query, then bookmark lookups are required to get the additional columns, bookmark lookups are run one row at a time, and are seeks on the clustered index. Hence it’s clear that bookmark lookups on a large number of rows are exceedingly expensive and that is why SQL will switch to a clustered index/table scan when lookups are required on a significant percentage of the rows in the table.&lt;br /&gt;&lt;br /&gt;So, what consitutes a significant percentage of the rows in the table? 50%? 20%? 10%?&lt;br /&gt;&lt;br /&gt;The answer’s often surprising. It’s under 1% of the total rows in the table.&lt;br /&gt;&lt;br /&gt;Here’s some test code to demonstrate that.&lt;br /&gt;&lt;br /&gt;Setup code:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# CREATE TABLE [dbo].[SeekOrScan](  &lt;br /&gt;# [ID] [int] IDENTITY(1,1) NOT NULL primary key,  &lt;br /&gt;# SomeNumber int,  &lt;br /&gt;# padding char(100)  &lt;br /&gt;# ) ON [PRIMARY]  &lt;br /&gt;#   &lt;br /&gt;# CREATE NonCLUSTERED INDEX [idx_SeekOrScan] ON [dbo].[SeekOrScan] (SomeNumber) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Test code:&lt;br /&gt;&lt;br /&gt;   1. insert into [SeekOrScan] (SomeNumber)  &lt;br /&gt;   2. select top 1000000 0  &lt;br /&gt;   3. from master..spt_values a cross join master..spt_values b  &lt;br /&gt;   4. where a.name is null and b.name is null  &lt;br /&gt;   5.   &lt;br /&gt;   6. update [SeekOrScan] set SomeNumber = ID -- just so we've got sequential numbers for the between  &lt;br /&gt;   7. GO  &lt;br /&gt;   8.   &lt;br /&gt;   9. dbcc freeproccache  &lt;br /&gt;  10.   &lt;br /&gt;  11. select * from [SeekOrScan]  &lt;br /&gt;  12. where somenumber between 1 and 100000 -- 10% of table  &lt;br /&gt;  13. -- Clustered index scan  &lt;br /&gt;  14.   &lt;br /&gt;  15. dbcc freeproccache  &lt;br /&gt;  16.   &lt;br /&gt;  17. select * from [SeekOrScan]  &lt;br /&gt;  18. where somenumber between 1 and 50000 -- 5% of table  &lt;br /&gt;  19. -- Clustered index scan  &lt;br /&gt;  20.   &lt;br /&gt;  21. dbcc freeproccache  &lt;br /&gt;  22.   &lt;br /&gt;  23. select * from [SeekOrScan]  &lt;br /&gt;  24. where somenumber between 1 and 10000 -- 1%  &lt;br /&gt;  25. -- Clustered index scan  &lt;br /&gt;  26.   &lt;br /&gt;  27. dbcc freeproccache  &lt;br /&gt;  28.   &lt;br /&gt;  29. select * from [SeekOrScan]  &lt;br /&gt;  30. where somenumber between 1 and 5000  -- 0.5% of table  &lt;br /&gt;  31. -- clustered index scan  &lt;br /&gt;  32.   &lt;br /&gt;  33. dbcc freeproccache  &lt;br /&gt;  34.   &lt;br /&gt;  35. select * from [SeekOrScan]  &lt;br /&gt;  36. where somenumber between 1 and 3000  -- 0.3% of table  &lt;br /&gt;  37. -- nonclustered index seek  &lt;br /&gt;&lt;br /&gt;insert into [SeekOrScan] (SomeNumber) select top 1000000 0 from master..spt_values a cross join master..spt_values b where a.name is null and b.name is null update [SeekOrScan] set SomeNumber = ID -- just so we've got sequential numbers for the between GO dbcc freeproccache select * from [SeekOrScan] where somenumber between 1 and 100000 -- 10% of table -- Clustered index scan dbcc freeproccache select * from [SeekOrScan] where somenumber between 1 and 50000 -- 5% of table -- Clustered index scan dbcc freeproccache select * from [SeekOrScan] where somenumber between 1 and 10000 -- 1% -- Clustered index scan dbcc freeproccache select * from [SeekOrScan] where somenumber between 1 and 5000  -- 0.5% of table -- clustered index scan dbcc freeproccache select * from [SeekOrScan] where somenumber between 1 and 3000  -- 0.3% of table -- nonclustered index seek&lt;br /&gt;&lt;br /&gt;So somewhere around 0.4% of the table, the index seek with bookmark lookup became more expensive than a table scan.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-8438826875302804488?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/8438826875302804488/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=8438826875302804488' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/8438826875302804488'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/8438826875302804488'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/01/seek-or-scan.html' title='Seek or scan?'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-4128190943764844038</id><published>2009-01-14T22:17:00.000-08:00</published><updated>2009-01-14T22:27:29.652-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Optimizing SQLServer 2008'/><title type='text'>Optimizing SQLServer 2008</title><content type='html'>Optimization in SQL Server 2008&lt;br /&gt;Using parameterized queries is a well known SQL Server Best Practice. This technique ensures caching and reuse of existing query execution plans (instead of constantly compiling new plans), as well as avoiding SQL injection by mandating that input data be data type safe.&lt;br /&gt;See more about SQL Server parameterization Best Practices here: &lt;a href="http://blogs.msdn.com/sqlprogrammability/archive/2007/01/13/6-0-best-programming-practices.aspx"&gt;http://blogs.msdn.com/sqlprogrammability/archive/2007/01/13/6-0-best-programming-practices.aspx&lt;/a&gt;&lt;br /&gt;An application that I work with presented me with an interesting dilemma; It wanted to utilize the benefits of plan reuse but the parameter values that the application initially sends to SQL Server are not representative of the values passed in the subsequent re-execution of the statement. SQL Server compiled and cached a ‘good’ plan for the first parameter values. Unfortunately, this had the unintended side effect of caching a poor execution plan for all subsequent parameter values. To make this clearer let’s look at the following example query;&lt;br /&gt;Select * from t where col1 &gt; @P1 or col2 &gt; @P2 order by col1;&lt;br /&gt;Let’s assume for simplicities sake that col1 is unique and is ever increasing in value, col2 has 1000 distinct values and there are 10,000,000 rows in the table, and that the clustered index consists of col1, and a nonclustered index exists on col2.&lt;br /&gt;Imagine the query execution plan created for the following initially passed parameters: @P1= 1 @P2=99&lt;br /&gt;These values would result in an optimal queryplan for the following statement using the substituted parameters:&lt;br /&gt;Select * from t where col1 &gt; 1 or col2 &gt; 99 order by col1;&lt;br /&gt;Now, imagine the query execution plan if the initial parameter values were:  @P1 = 6,000,000 and @P2 = 550.&lt;br /&gt;As before, an optimal queryplan would be created after substituting the passed parameters:&lt;br /&gt;Select * from t where col1 &gt; 6000000 or col2 &gt; 550 order by col1;&lt;br /&gt;These two identical parameterized SQL Statements would potentially create and cache very different execution plans due to the difference of the initially passed parameter values. However, since SQL Server only caches one execution plan per query, chances are very high that in the first case the query execution plan will utilize a clustered index scan because of the ‘col1 &gt; 1’ parameter substitution. Whereas, in the second case a query execution plan using index seek would most likely be created.&lt;br /&gt;Unfortunately if the initial parameter values are similar to the first example above, then a ‘table scan’ execution plan gets created and cached, even though most of the following queries would rather use a plan that contains the index seek.&lt;br /&gt;There are a number of ways to work-around this issue;&lt;br /&gt;·      Recompile every time the query is executed using the RECOMPILE hint - This can be very CPU intensive and effectively eliminates the benefits of caching queryplans.&lt;br /&gt;·      Unparameterize the query – Not a viable option in most cases due to SQL injection risk.&lt;br /&gt;·      Hint with specific parameters using the OPTIMIZE FOR hint (However, what value(s) should the app developer use?) This is a great option if the values in the rows are static, that is; not growing in number, etc. – However in my case the rows were not static.&lt;br /&gt;·      Forcing the use of a specific index&lt;br /&gt;·      Use a plan guide – Using any of the recommendations above.&lt;br /&gt;SQL Server 2008 provides another alternative: OPTIMIZE FOR UNKNOWN&lt;br /&gt;&lt;br /&gt;SQL Server 2008 provides a different alternative; the OPTIMIZE FOR UNKNOWN optimizer hint. This hint directs the query optimizer to use the standard algorithms it has always used if no parameters values had been passed to the query at all. In this case the optimizer will look at all available statistical data to reach a determination of what the values of the local variables used to generate the queryplan should be, instead of looking at the specific parameter values that were passed to the query by the application.&lt;br /&gt;Full documentation of optimizer hints can be found here:&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms181714(SQL.100).aspx"&gt;http://msdn.microsoft.com/en-us/library/ms181714(SQL.100).aspx&lt;/a&gt;&lt;br /&gt;Example:&lt;br /&gt;@p1=1, @p2=9998,&lt;br /&gt;Select * from t where col &gt; @p1 or col2 &gt; @p2 order by col1&lt;br /&gt;option (OPTIMIZE FOR (@p1 UNKNOWN, @p2 UNKNOWN))&lt;br /&gt;Using this new optimizer hint option has allowed the ISV to generate queries that result in the benefits of parameterization; such as plan reuse, while eliminating the problems caused by the caching of queryplans that were created using nontypical initially passed parameter values.&lt;br /&gt;NOTE: This new optimizer hint option, like all optimizer hints, should be used only by experienced developers and database administrators in cases where SQL Server cannot create an optimal plan.&lt;br /&gt;Cross Posted from http://blogs.microsoft.com/mssqlisv&lt;br /&gt;Posted by &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl00_AuthorLink" href="http://blogs.msdn.com/user/Profile.aspx?UserID=19910"&gt;mssqlisv&lt;/a&gt;  &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl00_CommentsLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/11/26/optimize-for-unknown-a-little-known-sql-server-2008-feature.aspx#comments"&gt;4 Comments&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl01_PermaLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/10/31/sql-server-2008-new-binary-hex-string-conversion-functionality-can-dramatically-improve-related-query-performance-by-orders-of-magnitude.aspx"&gt;Friday, October 31, 2008 1:49 PM&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl01_PostTitle" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/10/31/sql-server-2008-new-binary-hex-string-conversion-functionality-can-dramatically-improve-related-query-performance-by-orders-of-magnitude.aspx"&gt;SQL Server 2008 : new binary – hex string conversion functionality can dramatically improve related query performance by orders of magnitude.&lt;/a&gt;&lt;br /&gt;In previous SQL Server releases it wasn’t possible to convert binary data to string characters in hex format directly, because SQL Server did not have a built-in Transact-SQL command for converting binary data to a hexadecimal string. The Transact-SQL CONVERT command converted binary data to character data in a one byte to one character fashion. SQL Server would take each byte of the source binary data, convert it to an integer value, and then uses that integer value as the ASCII value for the destination character data. This behavior applied to the binary, varbinary, and timestamp datatypes.&lt;br /&gt;&lt;br /&gt;The only workarounds were to use either a stored procedure as described in a Knowledge Base Article:  "INFO: Converting Binary Data to Hexadecimal String" (  &lt;a href="http://support.microsoft.com/kb/104829" target="_blank"&gt;http://support.microsoft.com/kb/104829&lt;/a&gt;   ) or by writing a CLR function.&lt;br /&gt;&lt;br /&gt;An ISV I work with doesn’t support CLR and therefore they implemented their own version of a custom convert function in form of a stored procedure. This one was even faster than everything else they found on the Internet.&lt;br /&gt;&lt;br /&gt;NEW – IN SQL SERVER 2008 the convert function was extended to support binary data – hex string conversion. It looks like a tiny improvement almost not worth mentioning.&lt;br /&gt;&lt;br /&gt;However, for the ISV it was a big step forward as some critical queries need this functionality. Besides the fact that they no longer have to ship and maintain their own stored procedure, a simple repro showed a tremendous performance improvement.&lt;br /&gt;&lt;br /&gt;Repro:&lt;br /&gt;=====&lt;br /&gt;&lt;br /&gt;I transformed the procedure described in the KB article mentioned above into a simple function. The stored procedure below will create a simple test table with one varbinary column and insert some test rows in 10K packages ( e.g. nr_rows = 100 -&gt; 1 million rows in the table ).&lt;br /&gt;&lt;br /&gt;The repro shows two different test cases:&lt;br /&gt;1. insert 0x0 two million times&lt;br /&gt;2. insert 0x0123456789A12345 two million times&lt;br /&gt;&lt;br /&gt;Depending on the length of the value the disadvantage of the stored procedure solution will be even bigger. On my test machine the results of the test queries below were:&lt;br /&gt;(both tests were done with the same SQL Server 2008 instance - no change of any settings)&lt;br /&gt;&lt;br /&gt;1. two million times value 0x0&lt;br /&gt;&lt;br /&gt;    a, using stored procedure : about 3460 logical reads, no disk IO, ~52 secs elapsed time&lt;br /&gt;    b, using new convert feature : about 5200 logical reads,  no disk IO, &lt; 1 sec elapsed time&lt;br /&gt;&lt;br /&gt;2. two million times value 0x0123456789A12345&lt;br /&gt;    a, using stored procedure : about 3460 logical reads, no disk IO, ~157 secs elapsed time&lt;br /&gt;    b, using new convert feature : about 5200 logical reads,  no disk IO, &lt; 1 sec elapsed time&lt;br /&gt;&lt;br /&gt;Repro Script:&lt;br /&gt;========&lt;br /&gt;&lt;br /&gt;create function sp_hexadecimal ( @binvalue varbinary(255) )&lt;br /&gt;returns varchar(255)&lt;br /&gt;as&lt;br /&gt;begin&lt;br /&gt;      declare @charvalue varchar(255)&lt;br /&gt;      declare @i int&lt;br /&gt;      declare @length int&lt;br /&gt;      declare @hexstring char(16)&lt;br /&gt;      select @charvalue = '0x'&lt;br /&gt;      select @i = 1&lt;br /&gt;      select @length = datalength(@binvalue)&lt;br /&gt;      select @hexstring = '0123456789abcdef'&lt;br /&gt;      while (@i &lt;= @length)&lt;br /&gt;      begin&lt;br /&gt;            declare @tempint int&lt;br /&gt;            declare @firstint int&lt;br /&gt;            declare @secondint int&lt;br /&gt;            select @tempint = convert(int, substring(@binvalue,@i,1))&lt;br /&gt;            select @firstint = floor(@tempint/16)&lt;br /&gt;            select @secondint = @tempint - (@firstint*16)&lt;br /&gt;            select @charvalue = @charvalue +&lt;br /&gt;            substring(@hexstring, @firstint+1, 1) +&lt;br /&gt;            substring(@hexstring, @secondint+1, 1)&lt;br /&gt;            select @i = @i + 1&lt;br /&gt;      end&lt;br /&gt;return ( @charvalue )&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;create procedure cr_conv_test_table ( @value varbinary(16), @nr_rows int )&lt;br /&gt;as&lt;br /&gt;begin&lt;br /&gt;      declare @exist int&lt;br /&gt;      declare @counter int&lt;br /&gt;      set NOCOUNT ON&lt;br /&gt;      set statistics time off&lt;br /&gt;      set statistics io off&lt;br /&gt;      set statistics profile off&lt;br /&gt;      set @exist = ( select count(*) from sys.objects&lt;br /&gt;                              where name = 'conv_test_table' and&lt;br /&gt;                                    type = 'U' )&lt;br /&gt;      if( @exist = 1 )&lt;br /&gt;            drop table conv_test_table&lt;br /&gt;&lt;br /&gt;      set @exist = ( select count(*) from sys.objects&lt;br /&gt;                              where name = 'conv_test_table_temp' and&lt;br /&gt;                                    type = 'U' )&lt;br /&gt;      if( @exist = 1 )&lt;br /&gt;            drop table conv_test_table_temp&lt;br /&gt;&lt;br /&gt;      create table conv_test_table ( varbincol varbinary(16) )&lt;br /&gt;      create table conv_test_table_temp ( varbincol varbinary(16) )&lt;br /&gt;      set @counter = 10000&lt;br /&gt;      while @counter &gt; 0&lt;br /&gt;            begin&lt;br /&gt;                  insert into conv_test_table_temp values ( @value )&lt;br /&gt;                  set @counter = @counter - 1&lt;br /&gt;            end&lt;br /&gt;      set @counter = @nr_rows&lt;br /&gt;      while @counter &gt; 0&lt;br /&gt;      begin&lt;br /&gt;            insert into conv_test_table select * from conv_test_table_temp&lt;br /&gt;            set @counter = @counter - 1&lt;br /&gt;      end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;-- create 2 million test rows&lt;br /&gt;execute cr_conv_test_table 0x0, 200&lt;br /&gt;&lt;br /&gt;set statistics time on&lt;br /&gt;set statistics io on&lt;br /&gt;&lt;br /&gt;-- compare runtime of stored procedure with new convert feature&lt;br /&gt;select count(*) from conv_test_table&lt;br /&gt; where dbo.sp_hexadecimal(varbincol) = '0x00'&lt;br /&gt;select count(*) from conv_test_table&lt;br /&gt; where CONVERT(varchar(255),varbincol,1) = '0x00'&lt;br /&gt;&lt;br /&gt;-- create 2 million test rows&lt;br /&gt;execute cr_conv_test_table 0x0123456789A12345, 200&lt;br /&gt;&lt;br /&gt;set statistics time on&lt;br /&gt;set statistics io on&lt;br /&gt;&lt;br /&gt;-- compare runtime of stored procedure with new convert feature&lt;br /&gt;select count(*) from conv_test_table&lt;br /&gt; where dbo.sp_hexadecimal(varbincol) = '0x0123456789A12345'&lt;br /&gt;select count(*) from conv_test_table&lt;br /&gt; where CONVERT(varchar(255),varbincol,1) = '0x0123456789A12345'&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Cross Posted from http://blogs.microsoft.com/mssqlisv&lt;br /&gt;Posted by &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl01_AuthorLink" href="http://blogs.msdn.com/user/Profile.aspx?UserID=19910"&gt;mssqlisv&lt;/a&gt;  &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl01_CommentsLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/10/31/sql-server-2008-new-binary-hex-string-conversion-functionality-can-dramatically-improve-related-query-performance-by-orders-of-magnitude.aspx#comments"&gt;0 Comments&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl02_PermaLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/08/22/how-to-create-an-autonomous-transaction-in-sql-server-2008.aspx"&gt;Friday, August 22, 2008 1:54 PM&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl02_PostTitle" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/08/22/how-to-create-an-autonomous-transaction-in-sql-server-2008.aspx"&gt;How to create an autonomous transaction in SQL Server 2008&lt;/a&gt;&lt;br /&gt;I have been asked by many customers and partners, especially those migrating from Oracle, this question: how to create an autonomous transaction in SQL Server? It turns out to be a tricky thing to do since SQL Server doesn't have built-in autonomous transaction support like Oracle.&lt;br /&gt;An Autonomous transaction is essentially a nested transaction where the inner transaction is not affected by the state of the outer transaction. In other words, you can leave the context of current transaction (outer transaction) and call another transaction (autonomous transaction). Once you finish work in the autonomous transaction, you can come back to continue on within current transaction. What is done in the autonomous transaction is truly DONE and won't be changed no matter what happens to the outer transaction. To make it easier to understand, here is an example of the described scenario.&lt;br /&gt;BEGIN TRAN OuterTran&lt;br /&gt;      INSERT TABLE1&lt;br /&gt;      BEGIN “AUTONOMOUS” TRAN InnerTran&lt;br /&gt;            INSERT TABLE2&lt;br /&gt;      COMMIT “AUTONOMOUS” TRAN InnerTran&lt;br /&gt;ROLLBACK TRAN OuterTran&lt;br /&gt;The above pseudo script is meant to preserve result of “INSERT TABLE2”. In SQL Server 2008 or prior versions, "ROLLBACK TRAN" would always rollback all inner transactions to the outermost "BEGIN TRAN" statement (without specifiying savepoint). So the "InnerTran" transaction would be rolled back as well, which is not the desired behavior for the particular scenario.&lt;br /&gt;You could wonder why we need an autonomous transaction in the first place. Why can't we just implement two separate transactions so they don't interfere with each other? There are scenarios where people do need logic structured like this. Logging errors in database is one of the most common scenarios. Below is a TSQL script demonstrating a nested transaction where the inner transaction attempts to save the runtime errors in a table.&lt;br /&gt;USE TEMPDB&lt;br /&gt;GO&lt;br /&gt;CREATE TABLE ErrorLogging (logTime DATETIME, msg VARCHAR(255))&lt;br /&gt;CREATE TABLE TestAT (id INT PRIMARY KEY)&lt;br /&gt;GO&lt;br /&gt;CREATE PROCEDURE usp_ErrorLogging&lt;br /&gt;      @errNumber INT&lt;br /&gt;AS&lt;br /&gt;      INSERT INTO ErrorLogging VALUES (GETDATE(), 'Error ' + CAST(@errNumber AS VARCHAR(8)) +' occurred.')&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;DECLARE @ERROR AS INT&lt;br /&gt;INSERT INTO TestAT VALUES (1)&lt;br /&gt;BEGIN TRAN OuterTran&lt;br /&gt;      INSERT INTO TestAT VALUES (1) -- This will raise primary key constraint violation error&lt;br /&gt;     &lt;br /&gt;      SELECT @ERROR = @@ERROR&lt;br /&gt;      IF @ERROR &lt;&gt; 0&lt;br /&gt;      BEGIN&lt;br /&gt;            BEGIN TRAN InnerTran&lt;br /&gt;                  EXEC usp_ErrorLogging @ERROR&lt;br /&gt;            COMMIT TRAN InnerTran&lt;br /&gt;     &lt;br /&gt;            ROLLBACK TRAN OuterTran&lt;br /&gt;      END&lt;br /&gt;&lt;br /&gt;IF @@TRANCOUNT &gt; 0     &lt;br /&gt;COMMIT TRAN OuterTran&lt;br /&gt;GO&lt;br /&gt;SELECT * FROM TestAT&lt;br /&gt;SELECT * FROM ErrorLogging&lt;br /&gt;GO&lt;br /&gt;If you run above script against SQL Server, you would see no error message recorded in table "ErrorLogging" due to the "ROLLBACK TRAN OuterTran" statement. So, how can we make it work?&lt;br /&gt;In SQL Server 2008, you can implement a loopback linked server to achieve the same goal. For more information about loopback linked server, check Books Online for details (&lt;a href="http://msdn.microsoft.com/en-us/library/ms188716.aspx"&gt;http://msdn.microsoft.com/en-us/library/ms188716.aspx&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;USE MASTER&lt;br /&gt;GO&lt;br /&gt;EXEC sp_addlinkedserver @server = N'loopback',@srvproduct = N' ',@provider = N'SQLNCLI', @datasrc = @@SERVERNAME&lt;br /&gt;GO&lt;br /&gt;EXEC sp_serveroption loopback,N'remote proc transaction promotion','FALSE'&lt;br /&gt;Go&lt;br /&gt;Note 'remote proc transaction promotion' is a new option on SQL Server 2008, which allows you to control whether or not you want to enlist remote stored procedure call in a distributed transaction. When this option is off  (FALSE) as we set in the above example, the local transaction will not be promoted to distributed transaction. This is how we are able to separate outer and inner transactions in a "autonomous transaction" fashion.&lt;br /&gt;The Inner transaction above can be replaced by:&lt;br /&gt;      BEGIN TRAN InnerTran&lt;br /&gt;            EXEC loopback.tempdb.dbo.usp_ErrorLogging @ERROR&lt;br /&gt;      COMMIT TRAN InnerTran&lt;br /&gt;Full working script is in the appendix below. I want to point out that this method of using a loopback linked server might not scale well if it's executed very frequently. And it only works in SQL Server 2008 due to new server option of 'remote proc transaction promotion' as discussed above. As always, test before you use it.&lt;br /&gt;If you are looking for alternative ways of creating autonomous transaction on SQL 2008 or 2005, you have these options:&lt;br /&gt;Loopback connection from SQLCLR procedure to start a new transaction. Compared to more rigid structure need of loopback linked server, SQLCLR is more flexible and gives you more control over how you want to handle interaction with database. If the logic of the autonomous transaction includes computational tasks, it's one of SQLCLR's strengths to provide performance gain as extra benefit.&lt;br /&gt;Using table variable to save data within transaction. Table variables are not affected by transaction rollback thus serve as temporary buffer for transaction data. Once transaction is done, you can dump data out of table variable to a permanent table. Table variables have limited scope and are less flexible. Usually they would also be slower due to lack of index/statistics. However, it does offer you a pure TSQL option with no need to create anything new.&lt;br /&gt;Loopback connection from Extended Stored Procedures.&lt;br /&gt;Extended Stored Procedure are on the SQL Server deprecation list and we strongly recommend NOT using it.&lt;br /&gt;In a future blog, I'll provide sample SQLCLR code and a script using a table variable to create autonomous transactions. I will also compare their performance differences with loopback linked server in a scalability test. Stay tuned.&lt;br /&gt;Appendix&lt;br /&gt;USE MASTER&lt;br /&gt;GO&lt;br /&gt;EXEC sp_addlinkedserver @server = N'loopback',@srvproduct = N' ',@provider = N'SQLNCLI', @datasrc = @@SERVERNAME&lt;br /&gt;GO&lt;br /&gt;EXEC sp_serveroption loopback,N'remote proc transaction promotion','FALSE'&lt;br /&gt;EXEC sp_serveroption loopback,N'RPC OUT','TRUE' -- Enable RPC to the given server.&lt;br /&gt;Go&lt;br /&gt;USE TEMPDB&lt;br /&gt;GO&lt;br /&gt;CREATE TABLE ErrorLogging (logTime DATETIME, msg VARCHAR(255))&lt;br /&gt;CREATE TABLE TestAT (id INT PRIMARY KEY)&lt;br /&gt;GO&lt;br /&gt;CREATE PROCEDURE usp_ErrorLogging&lt;br /&gt;      @errNumber INT&lt;br /&gt;AS&lt;br /&gt;      INSERT INTO ErrorLogging VALUES (GETDATE(), 'Error ' + CAST(@errNumber AS VARCHAR(8)) +' occurred.')&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;DECLARE @ERROR AS INT&lt;br /&gt;INSERT INTO TestAT VALUES (1)&lt;br /&gt;BEGIN TRAN OuterTran&lt;br /&gt;      INSERT INTO TestAT VALUES (1) -- This will raise primary key constraint violation error&lt;br /&gt;     &lt;br /&gt;      SELECT @ERROR = @@ERROR&lt;br /&gt;      IF @ERROR &lt;&gt; 0&lt;br /&gt;      BEGIN&lt;br /&gt;            BEGIN TRAN InnerTran&lt;br /&gt;                  EXEC loopback.tempdb.dbo.usp_ErrorLogging @ERROR&lt;br /&gt;            COMMIT TRAN InnerTran&lt;br /&gt;           &lt;br /&gt;            ROLLBACK TRAN OuterTran&lt;br /&gt;      END&lt;br /&gt;&lt;br /&gt;IF @@TRANCOUNT &gt; 0     &lt;br /&gt;COMMIT TRAN OuterTran&lt;br /&gt;GO&lt;br /&gt;SELECT * FROM TestAT&lt;br /&gt;SELECT * FROM ErrorLogging&lt;br /&gt;GO Cross Posted from http://blogs.microsoft.com/mssqlisv&lt;br /&gt;Posted by &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl02_AuthorLink" href="http://blogs.msdn.com/user/Profile.aspx?UserID=19910"&gt;mssqlisv&lt;/a&gt;  &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl02_CommentsLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/08/22/how-to-create-an-autonomous-transaction-in-sql-server-2008.aspx#comments"&gt;2 Comments&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl03_PermaLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/07/11/update-with-output-clause-triggers-and-sqlmoreresults.aspx"&gt;Friday, July 11, 2008 1:51 PM&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl03_PostTitle" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/07/11/update-with-output-clause-triggers-and-sqlmoreresults.aspx"&gt;UPDATE with OUTPUT clause – Triggers – and SQLMoreResults&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;NOTE:  the code in this BLOG is TSQL instead of ODBC calls.  Since ODBC can be hard to understand and other API’s will have the same basic issues, I decided to use the simpler and more concise TSQL, which should also appeal to a wider audience.&lt;br /&gt;&lt;br /&gt;An ISV I work with recently ran into an interesting problem; here is the description and solution.&lt;br /&gt;&lt;br /&gt;PROBLEM:&lt;br /&gt;Adding an unexpected trigger caused application code to fail due to incomplete SQL Syntax, and not reading through all returned results.&lt;br /&gt;&lt;br /&gt;The ISV wanted to utilize the OUTPUT Clause of the UPDATE statement in their ODBC (SNAC) based application. The OUTPUT clause is very useful in providing data back to the application regarding the row, or rows, which were updated (or: inserted / deleted).  In the example I use below, the application is interested in knowing the date/time of the updated row(s).&lt;br /&gt;&lt;br /&gt;This could be accomplished by issuing the following statement:&lt;br /&gt;UPDATE T SET COL2 = @Pcol2, COL3 = getdate() OUTPUT CAST(INSERTED.COL3 AS varchar(30))WHERE COL1 = @Pcol1&lt;br /&gt;&lt;br /&gt;The ISV coded up the application expecting a return value for number of rows affected, and if that value was greater than 0 then it also returned the value of the inserted date/time.&lt;br /&gt;&lt;br /&gt;This worked well, until an external Partner application added a trigger to the table listed in the UPDATE statement.&lt;br /&gt;&lt;br /&gt;Example: CREATE TRIGGER [dbo].[TTrigger1] on [dbo].[T] after update as update t2 set col3 = 0&lt;br /&gt;&lt;br /&gt;Now the application failed on the UPDATE statement with the following error message:&lt;br /&gt;[Microsoft][SQL Native Client][SQL Server]The target table 'T' of the DML statement cannot have any enabled triggers if the statement contains an OUTPUT clause without INTO clause.&lt;br /&gt;&lt;br /&gt;The error message is self-explanatory, but was a surprise to the ISV application (and the application developer).  The developer did not expect a trigger to ever be created on the table.&lt;br /&gt;There are two different methods of getting OUTPUT data from an UPDATE statement;&lt;br /&gt;·       UPDATE with the OUTPUT clause only – this returns output results directly as part of the statement. This option cannot have a trigger defined on the table.&lt;br /&gt;·       UPDATE with OUTPUT and INTO clauses – this returns the output a specific table, or table variable. This option must be used if there is any possibility the table will have a trigger on it at any point.&lt;br /&gt;·       See the following website for complete the OUTPUT Clause documentation:&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms177564.aspx"&gt;http://msdn.microsoft.com/en-us/library/ms177564.aspx&lt;/a&gt;&lt;br /&gt;The developer then utilized the following syntax to send the same statement to SQL Server, and also to get the expected result back: declare @p165 table (col2 varchar(30));UPDATE T SET COL2 = ?, COL3 = getdate() OUTPUT CAST(INSERTED.COL3 AS varchar(30)) into @p165 WHERE COL1 = 1;select * from @p165&lt;br /&gt;&lt;br /&gt;Now a subtlety occurred, can you guess what it was? If you guessed that additional results are returned you are correct.&lt;br /&gt;The ODBC code returned data in a loop utilizing the following API calls:  SQLFetch, SQLNumResultCols, SQLRowCount, SQLMoreResults:&lt;br /&gt;·       The first results returned were the number of rows affected by the trigger, not the number of rows affected by the UPDATE statement, which was what the application was actually expecting&lt;br /&gt;·       The second set of results were the number of rows affected by the UPDATE statement&lt;br /&gt;·       The third set of results were the number of rows returned by the SELECT statement reading the table variable&lt;br /&gt;·       And finally, the actual data from the updated row(s) – which is what we really wanted in the first place!&lt;br /&gt;So, the lessons to be learned here are:&lt;br /&gt;1.   Be aware that triggers will affect your UPDATE statements if utilizing the OUTPUT clause&lt;br /&gt;2.    You should utilize the INTO clause to avoid the issue&lt;br /&gt;3.    Always use SQLMoreResults to read all of the result-sets that could be returned from SELECT, UPDATE, INSERT, or DELETE statements.&lt;br /&gt;4.    Triggers should include the ‘SET NOCOUNT ON’ statement to avoid returning the ‘affected number of rows’.&lt;br /&gt;SOLUTION:&lt;br /&gt;The application was changed to utilize the INTO clause, and SQLMoreResults was used to return all the resulting data.  Using SET NOCOUNT ON in trigger logic is also a best practice that prevents additional results ‘Rows affected’ from being generated.&lt;br /&gt;&lt;br /&gt;Here is a script to duplicate the issues I’ve described:&lt;br /&gt;USE tempdb&lt;br /&gt;GO&lt;br /&gt;------You may want to run this script in steps from comment – to comment&lt;br /&gt;------so you can follow along, instead of running the entire script at once&lt;br /&gt;&lt;br /&gt;CREATE TABLE t(&lt;br /&gt;      [col1] [int] NOT NULL,&lt;br /&gt;      [col2] [varchar](30) NULL,&lt;br /&gt;      [col3] [datetime] NULL&lt;br /&gt;) ON [PRIMARY]&lt;br /&gt;GO&lt;br /&gt;insert into t values (1,'abc', getdate())&lt;br /&gt;insert into t values (1,'abc', getdate())&lt;br /&gt;insert into t values (1,'abc', getdate())&lt;br /&gt;GO&lt;br /&gt;select * from t&lt;br /&gt;GO&lt;br /&gt;UPDATE t SET col2 = 'Peter', col3 = getdate()&lt;br /&gt;OUTPUT CAST(INSERTED.col3 AS varchar(30))WHERE col1 = 1&lt;br /&gt;GO&lt;br /&gt;select * from t&lt;br /&gt;GO&lt;br /&gt;------So far everything is good, Now let’s add the new table and the trigger&lt;br /&gt;CREATE TABLE t2(&lt;br /&gt;      [col1] [int] NULL,&lt;br /&gt;      [col2] [datetime] NULL&lt;br /&gt;) ON [PRIMARY]&lt;br /&gt;GO&lt;br /&gt;insert into t2 values (2, getdate())&lt;br /&gt;insert into t2 values (2, getdate())&lt;br /&gt;GO&lt;br /&gt;select * from t2&lt;br /&gt;GO&lt;br /&gt;------In this example, the trigger: ttr1 will update the rows&lt;br /&gt;------of a second table: t2&lt;br /&gt;CREATE TRIGGER ttr1 on t after update as update t2 set col1 = 0&lt;br /&gt;GO&lt;br /&gt;------OK, let’s try now with the trigger on&lt;br /&gt;UPDATE t SET col2 = 'Peter', col3 = getdate() OUTPUT CAST(INSERTED.col3 AS varchar(30))WHERE col1 = 1&lt;br /&gt;GO&lt;br /&gt;------Chances are good you got the following error message&lt;br /&gt;--Msg 334, Level 16, State 1, Line 1&lt;br /&gt;--The target table 't' of the DML statement cannot have any enabled triggers --if the statement contains an OUTPUT clause without INTO clause.&lt;br /&gt;----- let’s fix that now.&lt;br /&gt;declare @p1 varchar(30)&lt;br /&gt;UPDATE t SET col2 = 'Peter', col3 = getdate() OUTPUT CAST(INSERTED.col3 AS varchar(30))into @p1 WHERE col1 = 1&lt;br /&gt;GO&lt;br /&gt;------Notice this failed as well with the following error message&lt;br /&gt;--Msg 1087, Level 16, State 1, Line 2&lt;br /&gt;--Must declare the table variable "@p1".&lt;br /&gt;------We need to use a table&lt;br /&gt;------for this to work correctly we must use a table or&lt;br /&gt;------a table variable where the ‘INTO’ data will reside,&lt;br /&gt;------and be retrieved from&lt;br /&gt;declare @p1 table (col2 varchar(30))&lt;br /&gt;UPDATE t SET col2 = 'Peter', col3 = getdate() OUTPUT CAST(INSERTED.col3 AS varchar(30))into @p1 WHERE col1 = 1&lt;br /&gt;select * from @p1&lt;br /&gt;--Now you get what we were originally looking for&lt;br /&gt;--    the date/times of the rows that were updated&lt;br /&gt;--Look at the results under the 'Messages' tab as well...&lt;br /&gt;--you will see the number of rows affected:&lt;br /&gt;--    2 for the rows inserted as part of the trigger&lt;br /&gt;--    3 for the rows Updated&lt;br /&gt;--    and 3 for the rows we selected from the table variable&lt;br /&gt;--Now, you can see that the application must utilize SQLMoreResults if it&lt;br /&gt;--wants to return all the valid results.&lt;br /&gt;&lt;br /&gt;Cross Posted from http://blogs.microsoft.com/mssqlisv&lt;br /&gt;Posted by &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl03_AuthorLink" href="http://blogs.msdn.com/user/Profile.aspx?UserID=19910"&gt;mssqlisv&lt;/a&gt;  &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl03_CommentsLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/07/11/update-with-output-clause-triggers-and-sqlmoreresults.aspx#comments"&gt;1 Comments&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl04_PermaLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/06/26/use-sql-server-replay-tools-to-reproduce-and-resolve-customer-issues.aspx"&gt;Thursday, June 26, 2008 10:13 AM&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl04_PostTitle" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/06/26/use-sql-server-replay-tools-to-reproduce-and-resolve-customer-issues.aspx"&gt;Use SQL Server replay tools to reproduce and resolve customer issues&lt;/a&gt;&lt;br /&gt;For many ISVs run that into issues at customer sites, it is sometimes difficult to isolate underlying problems, especially on a 24x7 production environment, where limitations apply to real time troubleshooting and live debugging. In situations like this, constructing a repro scenario in a separate environment would be ideal to minimize impact to live production system, and to speed up resolution process.&lt;br /&gt;&lt;br /&gt;SQL Server Profiler&lt;br /&gt;Allow me introduce SQL Profiler, which offers replay trace function.  Well, it’s not something new. First shipped in SQL Server 7.0, the feature has gone through many improvements in later releases. You can use the tool to take a captured trace as input and replay it against test database(s). It helps identify issues that could be reproduced by replaying the events in the trace. Profiler itself uses ODBC only. In SQL Server 2005 and 2008, the replay function can be configured to use multiple threads (up to 64) to replay workloads.&lt;br /&gt;Advantages:&lt;br /&gt;1.       SQL Server profiler is a built-in tool with full support of Microsoft product team. It works out of box.&lt;br /&gt;2.       Easy to set up and run. Capture a trace using predefined replay template with all required events, and replay it against original database(s) (target machine needs to meet certain requirements http://msdn2.microsoft.com/en-us/library/ms175525.aspx)&lt;br /&gt;3.       In addition to multi-threaded replay, it also provides option of step through to replay events in the order they were traced.&lt;br /&gt;Disadvantages:&lt;br /&gt;1.       Certain events can’t be replayed including replication, events involving GUID, session binding events, operations on Blobs using bcp, full-text, READTEXT, WRITETEXT, and etc. See BOL for more details (http://msdn2.microsoft.com/en-us/library/ms188238.aspx)&lt;br /&gt;2.       The tool does not support multiple machine replay (running multiple instances of Profiler from multiple machines to replay the trace).&lt;br /&gt;3.       Profiler GUI tool is client side tracing and might be intrusive and generate significant performance overhead when capturing events for replay. Be careful of what events to capture and consider using server side tracing (sp_trace_create).&lt;br /&gt;&lt;br /&gt;RML Utilities&lt;br /&gt;Starting in SQL Server 2000, SQL Server Customer Support Services team (CSS) started a project of similar tool, called Ostress, with higher flexibility and scalability to help troubleshoot some of the challenging SQL problems. The latest version is packaged in “Replay Markup Language(RML) Utilities” supporting both SQL 2005 and SQL 2000 (&lt;a href="http://support.microsoft.com/kb/944837"&gt;http://support.microsoft.com/kb/944837&lt;/a&gt;). The tool can replay multi-threaded events as profiler does but with multiple machine replay support. It can simulate up to 1000 concurrent threads. The tool has a component called Ostress (just like old version), which takes a TSQL batch file and “stress” test it by opening arbitrary number of connections and iterate the TSQL batch in each connection configurable number of loops. This is useful when workload can be characterized as same or similar batch from various number of users (connections).&lt;br /&gt;&lt;br /&gt;Advantages:&lt;br /&gt;1.       The tool offers both replay and stress test options.&lt;br /&gt;2.       It supports multiple machine replay (multiple instances of OStress) with up to 1000 concurrent threads.&lt;br /&gt;3.       OStress supports 7.0, 2000, and 2005 trace formats.&lt;br /&gt;Disadvantages:&lt;br /&gt;1.       The tool is provided as is, no technical support from Microsoft. But you can submit questions via contact in readme of the tool.&lt;br /&gt;2.       Requires extra steps to process trace file and convert to RML format before being replayed.&lt;br /&gt;3.       Does not support MARS replay.&lt;br /&gt;&lt;br /&gt;Recommendation&lt;br /&gt;When to use SQL profiler and when to use RML Utilities? If you have a workload that can be replayed/reproduced with no or low concurrency requirement (&lt;64&gt; 64 threads) or an isolated batch that can be “stress” tested for simulation, use RML Utilities. Keep in mind, for concurrency replay, full sync of ordered events is very hard to replay and no tools exist today to exactly duplicate the original trace. So the issues that happened on traced source server might not be reproduced consistently afterwards even on same environment.&lt;br /&gt;&lt;br /&gt;Both tools above are for database replay. For a simulation test of multi-tier application environment, consider load-test tool of Visual Studio (Team edition) or 3rd-party vendor products.&lt;br /&gt;Cross Posted from http://blogs.microsoft.com/mssqlisv&lt;br /&gt;Posted by &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl04_AuthorLink" href="http://blogs.msdn.com/user/Profile.aspx?UserID=19910"&gt;mssqlisv&lt;/a&gt;  &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl04_CommentsLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/06/26/use-sql-server-replay-tools-to-reproduce-and-resolve-customer-issues.aspx#comments"&gt;1 Comments&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl05_PermaLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/05/27/sql-server-intermittent-connectivity-issue.aspx"&gt;Tuesday, May 27, 2008 10:49 AM&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl05_PostTitle" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/05/27/sql-server-intermittent-connectivity-issue.aspx"&gt;SQL Server Intermittent Connectivity Issue&lt;/a&gt;&lt;br /&gt;Recently many customers of an ISV I work with, reported intermittent connectivity issues when running the ISV application on SQL Server. Some customers reported the issue to be SQL Server 2005 specific. Others stated that they are experiencing the same issue on both SQL Server 2000 and 2005. Due to the intermittent nature, and the variation of the issue, it took us quite a while  to collect all the data, (odbc trace, netmon trace, sql trace…), analyse it, and understand the exact cause.&lt;br /&gt;SynAttackProtect&lt;br /&gt;The first issue we found was a subtle Winsock behavior change in Window 2003 SP1. Windows 2003 SP1 introduces a configurable registry setting: SynAttackProtect, that protects the server from network Denial-Of-Service attacks.  By default the protection is on.  In a SQL Server environment, when the number of simultaneous client connection requests is more than the system can handle and SQL Server backlog queue is full, the client will receive a 'connection failed' error from SQL Server:&lt;br /&gt;TCP Provider: An existing connection was forcibly closed by the remote host&lt;br /&gt;The SQL Protocols team has a good Blog that explains the detailed interaction between SynAttackProtect setting and SQL Server. See &lt;a href="http://blogs.msdn.com/sql_protocols/archive/2006/04/12/574608.aspx" target="_blank" mce_href="http://blogs.msdn.com/sql_protocols/archive/2006/04/12/574608.aspx"&gt;http://blogs.msdn.com/sql_protocols/archive/2006/04/12/574608.aspx&lt;/a&gt;.&lt;br /&gt;In Windows 2003, this issue could be worked-around by configuring the registry setting to disable SynAttackProtect.&lt;br /&gt;1)    Launch regedit.exe&lt;br /&gt;2)    Add DWORD value named SynAttackProtect under registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\&lt;br /&gt;3)    Set data value to 0&lt;br /&gt;See &lt;a href="http://technet2.microsoft.com/windowsserver/en/library/8d3a9f4d-13d1-4280-ac57-30242504d8ba1033.mspx?mfr=true" target="_blank" mce_href="http://technet2.microsoft.com/windowsserver/en/library/8d3a9f4d-13d1-4280-ac57-30242504d8ba1033.mspx?mfr=true"&gt;http://technet2.microsoft.com/windowsserver/en/library/8d3a9f4d-13d1-4280-ac57-30242504d8ba1033.mspx?mfr=true&lt;/a&gt; for additional information.&lt;br /&gt;After applying the registry change, two customers reported the intermittent connection issue went away. Both customers had been stress-testing SQL Server.  SynAttackProtect is more likely to become an issue in a lab environment where SQL Server is being stress-tested with extreme load.  Customers running stress-testing in lab environments should turn off SynAttackProtect.  I am not sure I’d recommend proactively turning it off in a production system given the potential security risk.  If a production system ever runs into the SynAttackProtect issue, the where/why of the large number of connection requests should be examined first.&lt;br /&gt;Windows “Scalable Networking Pack”&lt;br /&gt;Windows Scalable Networking Pack was a second network stack change that was released as part of Windows 2003 SP1 + KB91222, or Windows 2003 SP2. With the Scalable Networking Pack, the TCP Chimney Offload feature is enabled by default to increase performance. However implementations on certain network cards are problematic when TCP Chimney Offload enabled, and can cause intermittent connection drop. When the connection is dropped due to incompatibility between the network card and Windows Scalable Networking Pack, typical error message is&lt;br /&gt;[08S01] [Microsoft][SQL Native Client]Communication link failure&lt;br /&gt;A workaround for this issue could be to disable to TCP Chimney Offload feature.&lt;br /&gt;1)    Launch regedit.exe&lt;br /&gt;2)    Edit DWORD EnableTCPChimney under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters, set data value to 0&lt;br /&gt;3)    Edit DWORD EnableRSS under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters, set data value to 0&lt;br /&gt;4)    Edit DWORD EnableTCPA under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters, set data value to 0&lt;br /&gt;5)    Restart the server&lt;br /&gt;Amongst others, network cards using Broadcom 5708 chipsets are known to have compatibility issues w/ TCP Chimney Offload.  Disabling TCP Chimney Offload would fix the incompatibility issue. However it would also remove the benefit of Windows TCP stack performance improvements. It should only be used as a workaround until a fix becomes available from the network card vendor. &lt;br /&gt;See support article &lt;a href="http://support.microsoft.com/kb/942861" target="_blank" mce_href="http://support.microsoft.com/kb/942861"&gt;http://support.microsoft.com/kb/942861&lt;/a&gt; for additional information.&lt;br /&gt;By now, the majority of customers solved the intermittent connectivity issue after applying the SynAttackProtect and/or TCP Chimney Offload changes. Some customers connecting to SQL Server through Citrix have to turn off the TCP Chimney Offload feature on the Citrix server to fix the issue.&lt;br /&gt;Query Timeout&lt;br /&gt;The particular ISV application runs with a configurable Query timeout, by default the timeout is set to 1 second.  When a query timeout happens, the application will retry the query for 16 times, if it still fails, the query will be submitted again with nolock hint.  How would that affect the connection?  At the first glance, it seems to be irrelevant, but it does. Here’s the sequence of what could happen.&lt;br /&gt;1)    The query is submitted to SNAC for execution&lt;br /&gt;2)    The execution of the query takes too long so the timeout expires&lt;br /&gt;3)    Once the timeout happens, client attempts to cancel the query and sends an ATTN packet to the server. After sending ATTN, the client then waits for the response from the server. A timeout is set for this wait, the value of the timeout is obtained through SQL_ATTR_CONNECT_TIMEOUT and if not set, the default to 120 seconds.&lt;br /&gt;4)    The wait for server to response also times out. This is treated as an error from the client and basically the connection is considered dead in such scenarios&lt;br /&gt;5)    The client marks the connection as dead and then returns the “Query timeout expired” error message.&lt;br /&gt;6)     The application code, on seeing a timeout expired message attempts to execute the request again on the same connection, but immediately hits the “communication link failure” message because the connection is deemed as dead by the client&lt;br /&gt;&lt;br /&gt;During the investigation, we discovered a regression in SQL Server 2005. SQL Server 2005 may not response to a query cancel (timeout) request in a timely manner if the query requires index scan through a large number of pages. Checking for any attention requests is delayed when the SQL Server storage engine is busy bringing pages in from disk. Resulting in&lt;br /&gt;[08S01] [Microsoft][SQL Native Client]Communication link failure&lt;br /&gt;&lt;br /&gt;A hotfix is available to fix the regression, see details in&lt;br /&gt;&lt;a href="http://support.microsoft.com/kb/945442" target="_blank" mce_href="http://support.microsoft.com/kb/945442"&gt;http://support.microsoft.com/kb/945442&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;All the remaining customers had some long running batch queries that index scan a large table. This is just the last piece we needed to complete the puzzle. After applying the hotfix, all customers reported the problem solved.&lt;br /&gt;Cross Posted from http://blogs.microsoft.com/mssqlisv&lt;br /&gt;Posted by &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl05_AuthorLink" href="http://blogs.msdn.com/user/Profile.aspx?UserID=19910"&gt;mssqlisv&lt;/a&gt;  &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl05_CommentsLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/05/27/sql-server-intermittent-connectivity-issue.aspx#comments"&gt;2 Comments&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl06_PermaLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/03/18/using-time-zone-data-in-sql-server-2008.aspx"&gt;Tuesday, March 18, 2008 4:25 PM&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl06_PostTitle" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/03/18/using-time-zone-data-in-sql-server-2008.aspx"&gt;Using time zone data in SQL Server 2008&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In SQL Server 2008 Microsoft has introduced a number of new date and time data types.  One of these is the datetimeoffset data type. This data type includes an offset from UTC time as well as the datetime value and ensures that the datetime can be retrieved in UTC or a particular timezone based on this offset.  There are also new functions to allow for conversions between different time zones using the new function SWITCHOFFSET(). &lt;br /&gt;&lt;br /&gt;An example from SQL Server 2008 Books On Line (BOL):&lt;br /&gt;CREATE TABLE dbo.test&lt;br /&gt;    (&lt;br /&gt;    ColDatetimeoffset datetimeoffset&lt;br /&gt;    );&lt;br /&gt;GO&lt;br /&gt;INSERT INTO dbo.test&lt;br /&gt;VALUES ('1998-09-20 7:45:50.71345 -5:00');&lt;br /&gt;GO&lt;br /&gt;SELECT SWITCHOFFSET (ColDatetimeoffset, '-08:00')&lt;br /&gt;FROM dbo.test;&lt;br /&gt;GO&lt;br /&gt;--Returns: 1998-09-20 04:45:50.7134500 -08:00&lt;br /&gt;SELECT ColDatetimeoffset&lt;br /&gt;FROM dbo.test;&lt;br /&gt;--Returns: 1998-09-20 07:45:50.7134500 -05:00&lt;br /&gt;&lt;br /&gt;One of the most common questions we are asked is why we use the offset and not a timezone name.  A timezone name is much easier to remember than an offset, and most people do not know an offset without looking it up, making queries more difficult. &lt;br /&gt;&lt;br /&gt;Unfortunately, there is no current international standard authority for timezone names and values.  Each system needs to use a system of their own choosing, and until there is an international standard, it is not feasible to try to have SQL Server provide one, and would ultimately cause more problems than it would solve.  However, there are a couple of common systems that are well recognized around the world.  One is the Dynamic timezone data that is stored in the Windows Vista registry.  This data can be read from the registry into a file, which is then imported into SQL Server.&lt;br /&gt;Another cross-platform standard is the public domain Olson Timezone database (&lt;a href="http://www.twinsun.com/tz/tz-link.htm" mce_href="http://www.twinsun.com/tz/tz-link.htm"&gt;http://www.twinsun.com/tz/tz-link.htm&lt;/a&gt;). There are many public domain programs for extracting a time zone from these files, but at this time most are programmatic solutions.   So a programmatic function could be written in the CLR, but to provide full database functionality and query-ability, a table is needed.&lt;br /&gt;&lt;br /&gt;The programmatic solutions take a date, then apply the many different rules that determine when a zone is in daylight savings time and when it is not.  However, there are also historical changes.  Daylight savings time changed in 2007, meaning that determining what the offset for a particular zone is at a particular time is different depending on the year.  Then there are times when leap seconds need to be added.  Therefore any data-driven solution must have rows that have valid time ranges as well.&lt;br /&gt;&lt;br /&gt;The approach recommended here is to take one of the DLLs found on the web and instead of providing a programmatic solution around a specific date – to write all of the rows out into a database as an offset with the valid ranges.  Currently this example uses the Windows standard naming conventions for timezones, with a mapping to the Olson timezone names, but you could easily add other names in other languages as well.&lt;br /&gt;&lt;br /&gt;Working with timezones is very complex, and the following is a suggestion only for some ideas on how to use time zone data more effectively.   This is an example program (no guarantees) that uses a .NET library and writes the data from the Olson tz files in table format, and which can then be imported into SQL Server.    The .NET timezone library can be found at &lt;a href="http://www.babiej.demon.nl/Tz4Net/main.htm" mce_href="http://www.babiej.demon.nl/Tz4Net/main.htm"&gt;http://www.babiej.demon.nl/Tz4Net/main.htm&lt;/a&gt; and they request a small donation.  &lt;br /&gt;&lt;br /&gt;Here is some sample code to write to files the timezone data (no guarantees – does not include leap seconds):&lt;br /&gt;&lt;br /&gt;            StreamWriter sr = File.CreateText(@"D:\TZMapping.txt");&lt;br /&gt;            StreamWriter tr = File.CreateText(@"D:\TZZones.txt");&lt;br /&gt;&lt;br /&gt;            string[] zoneNames = OlsonTimeZone.AllNames;&lt;br /&gt;            sr.WriteLine("ID\tDaylightName\tStandardName\tRawUtcOffset\tOffsetSeconds\tWin32Id");&lt;br /&gt;            tr.WriteLine("ID\tTransitionStart\tTransitionEnd\tDeltaSeconds\tDST");&lt;br /&gt;&lt;br /&gt;            for (int i = 0; i &lt; zoneNames.Length; i++)&lt;br /&gt;            {&lt;br /&gt;                OlsonTimeZone tz = OlsonTimeZone.GetInstanceFromOlsonName(zoneNames[i].ToString());&lt;br /&gt;                sr.Write(i.ToString() + "\t");&lt;br /&gt;                sr.Write(tz.DaylightName.Trim() + "\t");&lt;br /&gt;                sr.Write(tz.StandardName.Trim() + "\t");&lt;br /&gt;                sr.Write(tz.RawUtcOffset.ToString() + "\t");&lt;br /&gt;                sr.Write(tz.RawUtcOffset.TotalSeconds.ToString() + "\t");&lt;br /&gt;                sr.WriteLine(tz.Win32Id == null ? "" : tz.Win32Id.Trim());&lt;br /&gt;&lt;br /&gt;                DaylightTime[] times = tz.AllTimeChanges;&lt;br /&gt;                for (int j = 0; j &lt; times.Length; j++)&lt;br /&gt;                {&lt;br /&gt;                    tr.Write(i.ToString() + "\t");&lt;br /&gt;                    tr.Write(times[j].Start.ToString("yyyy-MM-dd HH:mm:ss") + "\t");&lt;br /&gt;                    tr.Write(times[j].End.ToString("yyyy-MM-dd HH:mm:ss") + "\t");&lt;br /&gt;                    tr.Write(times[j] is StandardTime ? "0\t" :times[j].Delta.TotalSeconds.ToString() + "\t");&lt;br /&gt;                    tr.WriteLine(times[j] is StandardTime ? false.ToString() : true.ToString() );&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            tr.WriteLine();&lt;br /&gt;            sr.WriteLine();&lt;br /&gt;            tr.Close();&lt;br /&gt;            sr.Close();&lt;br /&gt;&lt;br /&gt;Import the TZMapping file, which will become the parent table, with the ID as the primary key.   Your table structure might look like this:&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;a href="http://blogs.msdn.com/photos/mssqlisv/images/8324195/original.aspx"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Please note:  If you use the Flat File Datasource in the Import Data Wizard in SQL Server 2008 Management Studio, you will need to open the Advanced Tab to set the source OutPutColumnWidth to greater than the default of 50.   Then import the TZZones file, which will become the child table with the ID, TransitionStart, and TransitionEnd as the composite primary key with a foreign key reference to the TZMapping table.  The TZZones table includes historical timezone data.    Joining these new tables into your data into queries now allows for queries that include standard names, Windows IDs, etc.&lt;br /&gt;&lt;br /&gt;For example, offsets can now be retrieved by a preferred name:&lt;br /&gt;&lt;br /&gt;select UtcOffset from TZmapping where StandardName = 'US/Pacific (PST)'&lt;br /&gt;&lt;br /&gt;The following two queries return different offset amounts for the same day in two different years.  This is because the US changed daylight savings time, and the date in March now falls into daylight savings when it did not before.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;select (dbo.TZMapping.OffsetSeconds + dbo.TZZones.DeltaSeconds)/3600&lt;br /&gt;from dbo.TZMapping &lt;br /&gt;join dbo.TZZones&lt;br /&gt;on dbo.TZMapping.id = dbo.TZZones.id&lt;br /&gt;where dbo.TZMapping.StandardName = 'America/Los_Angeles (PST)'&lt;br /&gt;and '2006-03-15'&lt;br /&gt;between dbo.TZZones.TransitionStart&lt;br /&gt;and dbo.TZZones.TransitionEnd&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;select (dbo.TZMapping.OffsetSeconds + dbo.TZZones.DeltaSeconds)/3600&lt;br /&gt;from dbo.TZMapping &lt;br /&gt;join dbo.TZZones&lt;br /&gt;on dbo.TZMapping.id = dbo.TZZones.id&lt;br /&gt;where dbo.TZMapping.StandardName = 'America/Los_Angeles (PST)'&lt;br /&gt;and '2007-03-15'&lt;br /&gt;between dbo.TZZones.TransitionStart&lt;br /&gt;and dbo.TZZones.TransitionEnd&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Again, timezones are a complex area and each application will need to address how you are going to handle time zone data to make programs more user friendly.  This is just one small example.&lt;br /&gt;Cross Posted from http://blogs.microsoft.com/mssqlisv&lt;br /&gt;Posted by &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl06_AuthorLink" href="http://blogs.msdn.com/user/Profile.aspx?UserID=19910"&gt;mssqlisv&lt;/a&gt;  &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl06_CommentsLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/03/18/using-time-zone-data-in-sql-server-2008.aspx#comments"&gt;5 Comments&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl07_PermaLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/03/18/increase-your-sql-server-performance-by-replacing-cursors-with-set-operations.aspx"&gt;Tuesday, March 18, 2008 3:49 PM&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl07_PostTitle" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/03/18/increase-your-sql-server-performance-by-replacing-cursors-with-set-operations.aspx"&gt;Increase your SQL Server performance by replacing cursors with set operations&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;You have probably heard many times, from different sources, that as a best practice; avoid using TSQL cursors.&lt;br /&gt;During a recent visit to a partner we ran into a common cursor case, which I wanted to use as an example to demonstrate why you should avoid TSQL cursors in most cases, and how to convert cursor logic to simple set join operations. Now there are certain scenarios where using a cursor makes sense. For example, a cursor is ideal for row by row processing that can’t be accomplished by set based operations. A cursor is flexible in that it provides a window, or subset, of data and that allows manipulation of the data in various ways. Study carefully what you want to achieve on case by case basis before using a cursor. Keep in mind SQL Server, as a modern RDBMS system, performs much better with set operations.&lt;br /&gt;Here is simplified version of a real cursor that was used to update a big table with over 200 million rows.&lt;br /&gt;DECLARE @EntityId Varchar(16)&lt;br /&gt;DECLARE @PerfId Varchar(16)&lt;br /&gt;DECLARE @BaseId Varchar(16)&lt;br /&gt;DECLARE @UpdateStatus Int&lt;br /&gt;&lt;br /&gt;DECLARE outerCursor CURSOR FOR&lt;br /&gt;SELECT EntityId, BaseId&lt;br /&gt;FROM outerTable&lt;br /&gt;--Returns 204,000 rows&lt;br /&gt;&lt;br /&gt;OPEN outerCursor&lt;br /&gt;FETCH NEXT FROM outerCursor INTO @EntityId, @BaseId&lt;br /&gt;&lt;br /&gt;WHILE @@FETCH_STATUS = 0&lt;br /&gt;BEGIN&lt;br /&gt;            DECLARE innerCursor CURSOR FOR&lt;br /&gt;            SELECT PRFMR_ID&lt;br /&gt;            FROM innerTable&lt;br /&gt;            WHERE ENTY_ID = @BaseId&lt;br /&gt;                       &lt;br /&gt;            OPEN innerCursor&lt;br /&gt;            FETCH NEXT FROM innerCursor INTO @PerfId&lt;br /&gt;            SET @UpdateStatus = @@FETCH_STATUS&lt;br /&gt;           &lt;br /&gt;            WHILE @UpdateStatus = 0&lt;br /&gt;            BEGIN&lt;br /&gt;                  UPDATE 200MilRowTable&lt;br /&gt;                  SET ENTY_ID = @EntityId&lt;br /&gt;                  WHERE PRFMR_ID = @PerfId&lt;br /&gt;           &lt;br /&gt;                  FETCH NEXT FROM innerCursor INTO @PerfId&lt;br /&gt;                  SET @UpdateStatus = @@FETCH_STATUS&lt;br /&gt;            END&lt;br /&gt;           &lt;br /&gt;            CLOSE innerCursor&lt;br /&gt;            DEALLOCATE innerCursor --clean up inner cursor&lt;br /&gt;                       &lt;br /&gt;            FETCH NEXT FROM outerCursor INTO @EntityId, @BaseId&lt;br /&gt;END&lt;br /&gt;&lt;br /&gt;CLOSE outerCursor&lt;br /&gt;DEALLOCATE outerCursor –cleanup outer cursor&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You might notice that this is a nested cursor with 204,000 loops in total for outerCursor. The innerTable has 10 million rows but innerCursor varies in number of loops depending on @BaseId of outerCursor. When I arrived at the customer this cursor had been running for over a day. The developer was “hoping” that it would finish soon given another day or two. The problem was nobody knew for sure how much time this thing would need to complete. Well, we can find out how much progress it has made so far to make an educated guess:&lt;br /&gt;SELECT execution_count, st.text&lt;br /&gt;FROM sys.dm_exec_query_stats as qs&lt;br /&gt;CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as st&lt;br /&gt;WHERE st.text like '%FETCH NEXT FROM outerCursor INTO%'&lt;br /&gt;&lt;br /&gt;This would tell us how many times the outer cursor has looped already. It returned 107. That’s only around 0.5% (107/204,000) after 30 hours of running. If the trend were to continue, the cursor would need another 8+ months!!!&lt;br /&gt;A rewrite of the batch to take advantage of set operations is as simple as this:&lt;br /&gt;SELECT i.PRFMR_ID, o.EntityId INTO #tempTable&lt;br /&gt;FROM innerTable i join outerTable o on i.ENTY_ID = o.BaseId&lt;br /&gt;Go&lt;br /&gt;UPDATE 200MilRowTable&lt;br /&gt;SET m.ENTY_ID = t.EntityId&lt;br /&gt;FROM 200MilRowTable m join #tempTable t on m.PRFMR_ID = t.PRFMR_ID&lt;br /&gt;Go&lt;br /&gt;--note this is only one of a few ways to rewrite.&lt;br /&gt;In this particular case, “SELECT INTO” is minimally logged under simple recovery mode. The two statement approach makes it easier to understand the conversion logic.&lt;br /&gt;This batch took approximately 17 hours to complete. Between the statement, I also put the database into simple recovery mode and added appropriate indexes to the temp table. I also dropped indexes from 200MilRowTable that touched “ENTY_ID” to speed this up. Adding indexes back took another 7 hours. The total time was approximately 24 hours, which is just a small fraction of the original cursor batch. I need to point out that the non-cursor batch uses more resources since the UPDATE now spawns multiple threads to process parallely. Remember our goal here is to make this finish faster not worrying about how much resources it consumes.&lt;br /&gt;Note: this might not be a perfect example because the nested cursor is magnifying the slow performance.&lt;br /&gt;However, the bottom line is; aviod cursors if possible and use joins / set operations whenever you can.&lt;br /&gt;Cross Posted from http://blogs.microsoft.com/mssqlisv&lt;br /&gt;Posted by &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl07_AuthorLink" href="http://blogs.msdn.com/user/Profile.aspx?UserID=19910"&gt;mssqlisv&lt;/a&gt;  &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl07_CommentsLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/03/18/increase-your-sql-server-performance-by-replacing-cursors-with-set-operations.aspx#comments"&gt;2 Comments&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl08_PermaLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/03/06/appending-data-using-sql-2008-filestream.aspx"&gt;Thursday, March 06, 2008 11:33 AM&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl08_PostTitle" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/03/06/appending-data-using-sql-2008-filestream.aspx"&gt;Appending Data Using SQL 2008 Filestream &lt;/a&gt;&lt;br /&gt;SQL Server 2008 has a new feature called Filestream, which allows you to save large binary files in the file system, instead of in the database.  This is targeted directly at the scenario that many document management and web applications have today where they save some metadata in the database, with a column holding the path to the actual file.  However, there is no transactional context between the two; therefore, the data in the database can be changed to no longer point to the actual location, or the file moved without the pointer being updated. Users want to be able to have documents, pictures, video, etc. in the file system with the streaming support the file system provides, but have the metadata be consistent.  This is exactly what the Filestream feature is targeted for.&lt;br /&gt;&lt;br /&gt;When a large binary files gets ‘updated’ most users/applications will replace the file in its entirety (you do not usually update part of an image through the database). Filestream does not currently support in-place updates.  Therefore an update to a column with the filestream attribute is implemented by creating a new zero-byte file, which then has the entire new data value written to it.  When the update is committed, the file pointer is then changed to point to the new file, leaving the old file to be deleted at garbage collection time.  This happens at a checkpoint for simple recovery, and at a backup or log backup.&lt;br /&gt;&lt;br /&gt;Code that updates large value data types (varchar(max), nvarchar(max), and varbinary(max)) may use the .Write(offset) UPDATE clause; however since an in-place update of a column with the Filestream attribute is not supported, the .Write(offset) UPDATE clause will error out. Therefore, even though filestream is only a storage attribute, the update code does not work against both systems, requiring knowledge of underlying storage mechanism.&lt;br /&gt;&lt;br /&gt;Many of the update actions taken against large data types are actually appends.  And many logging scenarios continuously append to an ever-growing file.  Filestream offers an option for this case, to avoid the scenario where the original data is pulled to the client, data appended, and then a new file written with the combined data – leaving the old file to be garbage collected later.&lt;br /&gt;&lt;br /&gt; In order to avoid this round trip, a device FS control (FSCTL_SQL_FILESTREAM_FETCH_OLD_CONTENT) can be issued to trigger a server-side copy of the old content.  This avoids the data moving over the network. This control is not yet documented; note that the DeviceIoControl ControlCode constant that is needed is: 599392.  This will be added to the Filestream API documentation at a future date.&lt;br /&gt;&lt;br /&gt;Example code:&lt;br /&gt;[DllImport(“kernel32.dll”, SetLastError = true)]&lt;br /&gt;Static extern bool DeviceIoControl(&lt;br /&gt;IntPtr hDevice,&lt;br /&gt;Uint dwIoControlCode,&lt;br /&gt;IntPter lpInBuffer,&lt;br /&gt;Uint ninBufferSize,&lt;br /&gt;[out] IntPtr lpOutBuffer,&lt;br /&gt;Uiny nOutBufferSize,&lt;br /&gt;Ref uint lpBytesReturned,&lt;br /&gt;IntPtr lpOverlapped );&lt;br /&gt;&lt;br /&gt;                IntPtr hFile = IntPtr.Zero;&lt;br /&gt;Uint bytesReturned;&lt;br /&gt;                // hFile = mySafeHafle.DangereousGetHandle();  or something similar&lt;br /&gt;               &lt;br /&gt;Bool result = DeviceIoControl ( hFile, 599392, IntPtr.Zero, 0, IntPtr.Zero, 0, ref lpBytesReturned, InPtr.Zero );&lt;br /&gt;&lt;br /&gt;As Filestream is minimally logged, if there is no activity other than filestream activity, there is usually not enough activity to trigger a checkpoint, and the old files will not get deleted.  In non-simple recovery mode, the log will not increase, but the db will grow until those files get garbage collected.  This will occur in a background thread, and can impact the server through this activity.&lt;br /&gt;&lt;br /&gt;Therefore, it is a best practice to manually issue that checkpoint if in simple recovery mode; and to maintain an optimal transaction log backup to avoid the file growth.&lt;br /&gt;&lt;br /&gt;Other quick notes:&lt;br /&gt;&lt;br /&gt;Filestream deletes are significantly faster than blob deletes.&lt;br /&gt;If an application needs to commonly delete large data values, filestream will be more scalable as the metadata is changed, then the file garbage collected asynchronously.  For instance, the delete of a 6GB nvarbinary(max) file that took 6 seconds, happens in milliseconds with a filestream delete.&lt;br /&gt;&lt;br /&gt;Filestream maximum size is different for SNAC 9 and SNAC 10.&lt;br /&gt;Files using SNAC9 have a maximum size of 2GB.  SNAC 10 supports unlimited size.&lt;br /&gt;&lt;br /&gt;Note:  Altering an existing column without a filestream attribute to having the filestream attribute is not supported.&lt;br /&gt;This means that moving data from a blob storage mechanism to filestream mechanism requires that the data be copied to the new datatype with the filestream attribute.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Cross Posted from http://blogs.microsoft.com/mssqlisv&lt;br /&gt;Posted by &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl08_AuthorLink" href="http://blogs.msdn.com/user/Profile.aspx?UserID=19910"&gt;mssqlisv&lt;/a&gt;  &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl08_CommentsLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/03/06/appending-data-using-sql-2008-filestream.aspx#comments"&gt;1 Comments&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl09_PermaLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/02/25/now-is-time-to-try-sql-server-2008.aspx"&gt;Monday, February 25, 2008 10:57 AM&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl09_PostTitle" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/02/25/now-is-time-to-try-sql-server-2008.aspx"&gt;Now is time to try SQL Server 2008 &lt;/a&gt;&lt;br /&gt;Did you know that SQL Server 2008 is just around the corner, and that the SQL development team has just publicly released the latest Community Technology Preview (CTP 6) version?&lt;br /&gt;This latest beta version of SQL 2008 includes many exciting new features like filtered indexes, sparse columns, data compression, Microsoft sync, integrated full text search, Report rendering in Microsoft Word, Data visualization enhancements, extensive Books Online documentation, the first feature pack, and many, many more.&lt;br /&gt;Now is great time to try it for yourself! Download SQL Server 2008 &lt;a href="http://www.microsoft.com/sql/2008/prodinfo/download.mspx"&gt;here&lt;/a&gt; .&lt;br /&gt;Also, the SQLCAT teams (including us on the SQLCAT ISV team) have been busy working with our customers and partners implementing pre-release (CTP) builds. We have many lessons learned to share with you; these can be found &lt;a href="http://blogs.msdn.com/ControlPanel/Blogs/posteditor.aspx?SelectedNavItem=NewPost"&gt;here&lt;/a&gt;&lt;br /&gt;Additionally, we have a number of great best practices papers coming up:&lt;br /&gt;· Index Defragmentation Best Practices&lt;br /&gt;· Best Practices for using Resource Governor with a mixed (OLTP and Reporting) workload&lt;br /&gt;· Data Compression: Design and Implementation Best Practices, Performance Impact&lt;br /&gt;· XEvents Toolkit&lt;br /&gt;· SQL 2008 Usage-Based Optimization Efficacy (subject to name change)&lt;br /&gt;· Scale-Out Querying with Analysis Services 2008&lt;br /&gt;· Best practices for Data Warehousing in SQL Server 2008&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Cross Posted from http://blogs.microsoft.com/mssqlisv&lt;br /&gt;Posted by &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl09_AuthorLink" href="http://blogs.msdn.com/user/Profile.aspx?UserID=19910"&gt;mssqlisv&lt;/a&gt;  &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl09_CommentsLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2008/02/25/now-is-time-to-try-sql-server-2008.aspx#comments"&gt;1 Comments&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl10_PermaLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2007/06/29/detecting-overlapping-indexes-in-sql-server-2005.aspx"&gt;Friday, June 29, 2007 8:56 AM&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl10_PostTitle" href="http://blogs.msdn.com/sqlprogrammability/archive/2007/06/29/detecting-overlapping-indexes-in-sql-server-2005.aspx"&gt;Detecting Overlapping Indexes in SQL Server 2005&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;When SQL Server has an optimal index that satisfies the search predicates of a query the optimizer performs an index SEEK operation as opposed to an index (or table) scan to retrieve the required rows; this is desirable.  Based on this, one may be led to believe that having an index for every possible query predicate set would result in all the queries executing optimally.  While true, one has to keep in mind that the indexes need to be maintained when the underlying table data in the column included in the index changes, which amounts to overhead for the database engine.  So as you may guess, there are advantages of having indexes, but having too many can result in excessive overhead. This implies that you need to carefully evaluate the pros and cons before creating indexes.&lt;br /&gt;&lt;br /&gt;In your first evaluation scenario you clearly want to avoid the case of having overlapping indexes as there is no additional value that an overlapping index provides.  For example, consider a table ‘TabA’ and its three associated indexes created with the following definitions.&lt;br /&gt;&lt;br /&gt;CREATE TABLE TabA&lt;br /&gt;( Col1  INT, Col2  INT, Col3  INT, Col4 INT );&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;CREATE INDEX idx1 ON TabA ( Col1, Col2, Col3 );&lt;br /&gt;CREATE INDEX idx2 ON TabA ( Col1, Col2 );&lt;br /&gt;CREATE INDEX idx3 ON TabA ( Col1 DESC, Col2 DESC );&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;In the table structure above, the index idx1 is a superset (overlap) of the index idx2 and therefore redundant.  As can be expected any query that needs to perform a search on Col1 and Col2 could use index idx1 just as well as the index idx2 as seen in the graphical query plan below.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/photos/mssqlisv/images/3609317/original.aspx"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Such overlapping indexes are often a result of multiple developers working on the same product and not evaluating and understanding the existing schema before making additions.  Once created, detecting such overlapping indexes in a database can often be a laborious task requiring detailed analysis.  More importantly, most DBAs do not like to disable or drop indexes because they are not certain of the queries they were created to help with and fear the side effects the action may have.&lt;br /&gt;&lt;br /&gt;The script below uses the new system catalog introduced in SQL Server 2005 to report all duplicate indexes in the current database context.&lt;br /&gt;&lt;br /&gt;CREATE FUNCTION dbo.INDEX_COL_PROPERTIES (@TabName nvarchar(128), @IndexId INT, @ColId INT)&lt;br /&gt;RETURNS INT&lt;br /&gt;WITH EXECUTE AS CALLER&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;       DECLARE @IsDescending INT;&lt;br /&gt;       SELECT @IsDescending = is_descending_key&lt;br /&gt;       FROM sys.index_columns SYSIDXCOLS&lt;br /&gt;       WHERE OBJECT_ID(@TabName) = SYSIDXCOLS.object_id&lt;br /&gt;       AND @IndexId = SYSIDXCOLS.index_id&lt;br /&gt;       AND @ColId = SYSIDXCOLS.key_ordinal;&lt;br /&gt;&lt;br /&gt;       -- Return the value of @IsDescending as the property&lt;br /&gt;       RETURN(@IsDescending);&lt;br /&gt;END;&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;-- Find Duplicate Indexes in SQL Server Database&lt;br /&gt;CREATE VIEW IndexList_VW AS&lt;br /&gt;SELECT&lt;br /&gt;       SYSSCH.[name] AS SchemaName,&lt;br /&gt;       SYSOBJ.[name] AS TableName,&lt;br /&gt;       SYSIDX.[name] AS IndexName,&lt;br /&gt;       SYSIDX.[is_unique] AS IndexIsUnique,&lt;br /&gt;       SYSIDX.[type_desc] AS IndexType,&lt;br /&gt;       SYSIDX.[is_disabled] AS IsDisabled,&lt;br /&gt;       INDEX_COL( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 1 ) AS Column1,&lt;br /&gt;       INDEX_COL( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 2 ) AS Column2,&lt;br /&gt;       INDEX_COL( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 3 ) AS Column3,&lt;br /&gt;       INDEX_COL( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 4 ) AS Column4,&lt;br /&gt;       INDEX_COL( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 5 ) AS Column5,&lt;br /&gt;       INDEX_COL( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 6 ) AS Column6,&lt;br /&gt;       INDEX_COL( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 7 ) AS Column7,&lt;br /&gt;       INDEX_COL( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 8 ) AS Column8,&lt;br /&gt;       INDEX_COL( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 9 ) AS Column9,&lt;br /&gt;       INDEX_COL( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 10 ) AS Column10,&lt;br /&gt;       INDEX_COL( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 11 ) AS Column11,&lt;br /&gt;       INDEX_COL( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 12 ) AS Column12,&lt;br /&gt;       INDEX_COL( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 13 ) AS Column13,&lt;br /&gt;       INDEX_COL( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 14 ) AS Column14,&lt;br /&gt;       INDEX_COL( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 15 ) AS Column15,&lt;br /&gt;       INDEX_COL( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 16 ) AS Column16,&lt;br /&gt;       dbo.INDEX_COL_PROPERTIES( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 1 ) AS Column1_Prop,&lt;br /&gt;       dbo.INDEX_COL_PROPERTIES( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 2 ) AS Column2_Prop,&lt;br /&gt;       dbo.INDEX_COL_PROPERTIES( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 3 ) AS Column3_Prop,&lt;br /&gt;       dbo.INDEX_COL_PROPERTIES( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 4 ) AS Column4_Prop,&lt;br /&gt;       dbo.INDEX_COL_PROPERTIES( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 5 ) AS Column5_Prop,&lt;br /&gt;       dbo.INDEX_COL_PROPERTIES( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 6 ) AS Column6_Prop,&lt;br /&gt;       dbo.INDEX_COL_PROPERTIES( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 7 ) AS Column7_Prop,&lt;br /&gt;       dbo.INDEX_COL_PROPERTIES( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 8 ) AS Column8_Prop,&lt;br /&gt;       dbo.INDEX_COL_PROPERTIES( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 9 ) AS Column9_Prop,&lt;br /&gt;       dbo.INDEX_COL_PROPERTIES( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 10 ) AS Column10_Prop,&lt;br /&gt;       dbo.INDEX_COL_PROPERTIES( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 11 ) AS Column11_Prop,&lt;br /&gt;       dbo.INDEX_COL_PROPERTIES( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 12 ) AS Column12_Prop,&lt;br /&gt;       dbo.INDEX_COL_PROPERTIES( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 13 ) AS Column13_Prop,&lt;br /&gt;       dbo.INDEX_COL_PROPERTIES( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 14 ) AS Column14_Prop,&lt;br /&gt;       dbo.INDEX_COL_PROPERTIES( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 15 ) AS Column15_Prop,&lt;br /&gt;       dbo.INDEX_COL_PROPERTIES( SCHEMA_NAME(SYSOBJ.SCHEMA_ID)+'.'+SYSOBJ.[name], SYSIDX.index_id, 16 ) AS Column16_Prop&lt;br /&gt;FROM sys.indexes SYSIDX INNER JOIN sys.objects SYSOBJ ON SYSIDX.[object_id] = SYSOBJ.[object_id]&lt;br /&gt;       INNER JOIN sys.schemas SYSSCH ON SYSOBJ.schema_id = SYSSCH.schema_id&lt;br /&gt;WHERE SYSIDX.index_id &gt; 0&lt;br /&gt;       AND INDEXPROPERTY(SYSOBJ.[object_id], SYSIDX.[name], 'IsStatistics') = 0&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;SELECT&lt;br /&gt;       vwA.SchemaName,&lt;br /&gt;       vwA.TableName,&lt;br /&gt;       vwA.IndexIsUnique,&lt;br /&gt;       vwA.IndexType,&lt;br /&gt;       vwA.IndexName,&lt;br /&gt;       vwB.IndexName AS OverlappingIndex,&lt;br /&gt;       vwA.Column1, vwA.Column2, vwA.Column3, vwA.Column4, vwA.Column5, vwA.Column6, vwA.Column7, vwA.Column8,&lt;br /&gt;       vwA.Column9, vwA.Column10, vwA.Column11, vwA.Column12, vwA.Column13, vwA.Column14, vwA.Column15, vwA.Column16 &lt;br /&gt;FROM IndexList_VW vwA INNER JOIN IndexList_VW vwB ON vwA.TableName=vwB.TableName&lt;br /&gt;       AND vwA.IndexName &lt;&gt; vwB.IndexName&lt;br /&gt;       AND vwA.IsDisabled = 0&lt;br /&gt;       AND vwB.IsDisabled = 0&lt;br /&gt;       AND  (vwA.Column1=vwB.Column1 AND vwA.Column1_Prop=vwB.Column1_Prop)&lt;br /&gt;       AND ((vwA.Column2=vwB.Column2 AND vwA.Column2_Prop=vwB.Column2_Prop) OR vwA.Column2 IS NULL OR vwB.Column2 IS NULL)&lt;br /&gt;       AND ((vwA.Column3=vwB.Column3 AND vwA.Column3_Prop=vwB.Column3_Prop) OR vwA.Column3 IS NULL OR vwB.Column3 IS NULL)&lt;br /&gt;       AND ((vwA.Column4=vwB.Column4 AND vwA.Column4_Prop=vwB.Column4_Prop) OR vwA.Column4 IS NULL OR vwB.Column4 IS NULL)&lt;br /&gt;       AND ((vwA.Column5=vwB.Column5 AND vwA.Column5_Prop=vwB.Column5_Prop) OR vwA.Column5 IS NULL OR vwB.Column5 IS NULL)&lt;br /&gt;       AND ((vwA.Column6=vwB.Column6 AND vwA.Column6_Prop=vwB.Column6_Prop) OR vwA.Column6 IS NULL OR vwB.Column6 IS NULL)&lt;br /&gt;       AND ((vwA.Column7=vwB.Column7 AND vwA.Column7_Prop=vwB.Column7_Prop) OR vwA.Column7 IS NULL OR vwB.Column7 IS NULL)&lt;br /&gt;       AND ((vwA.Column8=vwB.Column8 AND vwA.Column8_Prop=vwB.Column8_Prop) OR vwA.Column8 IS NULL OR vwB.Column8 IS NULL)&lt;br /&gt;       AND ((vwA.Column9=vwB.Column9 AND vwA.Column9_Prop=vwB.Column9_Prop) OR vwA.Column9 IS NULL OR vwB.Column9 IS NULL)&lt;br /&gt;       AND ((vwA.Column10=vwB.Column10 AND vwA.Column10_Prop=vwB.Column10_Prop) OR vwA.Column10 IS NULL OR vwB.Column10 IS NULL)&lt;br /&gt;       AND ((vwA.Column11=vwB.Column11 AND vwA.Column11_Prop=vwB.Column11_Prop) OR vwA.Column11 IS NULL OR vwB.Column11 IS NULL)&lt;br /&gt;       AND ((vwA.Column12=vwB.Column12 AND vwA.Column12_Prop=vwB.Column12_Prop) OR vwA.Column12 IS NULL OR vwB.Column12 IS NULL)&lt;br /&gt;       AND ((vwA.Column13=vwB.Column13 AND vwA.Column13_Prop=vwB.Column13_Prop) OR vwA.Column13 IS NULL OR vwB.Column13 IS NULL)&lt;br /&gt;       AND ((vwA.Column14=vwB.Column14 AND vwA.Column14_Prop=vwB.Column14_Prop) OR vwA.Column14 IS NULL OR vwB.Column14 IS NULL)&lt;br /&gt;       AND ((vwA.Column15=vwB.Column15 AND vwA.Column15_Prop=vwB.Column15_Prop) OR vwA.Column15 IS NULL OR vwB.Column15 IS NULL)&lt;br /&gt;       AND ((vwA.Column16=vwB.Column16 AND vwA.Column16_Prop=vwB.Column16_Prop) OR vwA.Column16 IS NULL OR vwB.Column16 IS NULL)&lt;br /&gt;ORDER BY&lt;br /&gt;       vwA.TableName, vwA.IndexName&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;-- Drop function and view created above.&lt;br /&gt;DROP FUNCTION dbo.INDEX_COL_PROPERTIES&lt;br /&gt;GO&lt;br /&gt;DROP VIEW IndexList_VW&lt;br /&gt;GO&lt;br /&gt;Executing the script in a test database with the table (TabA) mentioned above produces output similar to the following.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/photos/mssqlisv/images/3609327/original.aspx"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Indexes idx1 and idx2 are reported to have an overlap, and in this case the subset index that has fewer columns (idx2) can be disabled without any negative side-effects (provided there are no Index hints pointing to this index. This is explained in more detail below).  This will result in the same performance for select statements but eliminate the overhead of the database engine having to maintain 2 indexes that serve the same general purpose.  This is particularly important if the underlying columns (Col1 and Col2) are highly volatile.&lt;br /&gt;&lt;br /&gt;A couple of additional points to keep in mind when using this script:&lt;br /&gt;-          Overlapping indexes are only those that have the columns in the same order.  For example an index created on Col1, Col2, Col3 (in that order) does not overlap with an index created on Col2, Col1, Col3, even though the columns included are the same&lt;br /&gt;-          Indexes created on the same set of columns with the same column order, but with different sort order specifications (ASC, DESC) are distinct indexes and are not overlapping&lt;br /&gt;-          Indexes with included columns introduced in SQL Server 2005 are correctly reported as overlapping by the above script.  For example, an index created as Col1, Col2 and Col3 as an included column overlaps with the index created on Col1, Col2, Col3.  For overlapping indexes that involve included columns it is imperative to disable or drop the index with the higher number of included columns (refer to: &lt;a href="http://msdn2.microsoft.com/en-us/library/ms188783(SQL.90).aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms188783(SQL.90).aspx"&gt;http://msdn2.microsoft.com/en-us/library/ms188783(SQL.90).aspx&lt;/a&gt; for more information about indexes with included columns)&lt;br /&gt;-          Clustered indexes and non-clustered indexes are clearly marked in the script output. If a clustered index is reported as overlapped and you plan to drop it, you may want to take some additional steps to make sure that the overlapping index, or some other index, is created as clustered, because it is a SQL Server best practice to have a clustered index on every table (refer to: &lt;a href="http://www.microsoft.com/technet/prodtechnol/sql/bestpractice/clusivsh.mspx" mce_href="http://www.microsoft.com/technet/prodtechnol/sql/bestpractice/clusivsh.mspx"&gt;http://www.microsoft.com/technet/prodtechnol/sql/bestpractice/clusivsh.mspx&lt;/a&gt; for more information)&lt;br /&gt;-          It is recommended to either disable a duplicate index or save its definition before dropping it, in order to be able to recreate it if necessary&lt;br /&gt;-          Before disabling or dropping an index you should make sure that there are no index hints in your application that explicitly use the index being disabled, for example: SELECT * FROM TabA WITH (INDEX (idx2)) WHERE col1 = 28. Disabling or dropping an index that is explicitly used via an index hint will result in the query execution failing with an error message 308 or 315.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Cross Posted from http://blogs.microsoft.com/mssqlisv&lt;br /&gt;Posted by &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl10_AuthorLink" href="http://blogs.msdn.com/user/Profile.aspx?UserID=19910"&gt;mssqlisv&lt;/a&gt;  &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl10_CommentsLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2007/06/29/detecting-overlapping-indexes-in-sql-server-2005.aspx#comments"&gt;2 Comments&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl11_PermaLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2007/06/05/new-sql-best-practice-articles-now-available.aspx"&gt;Tuesday, June 05, 2007 12:47 PM&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl11_PostTitle" href="http://blogs.msdn.com/sqlprogrammability/archive/2007/06/05/new-sql-best-practice-articles-now-available.aspx"&gt;New SQL Best Practice Articles now available&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Please have a look at four new Best Practices Articles&lt;br /&gt;SQL Server 2005 Predeployment I/O best practices &lt;a href="http://www.microsoft.com/technet/prodtechnol/sql/bestpractice/pdpliobp.mspx"&gt;http://www.microsoft.com/technet/prodtechnol/sql/bestpractice/pdpliobp.mspx&lt;/a&gt;                                by SQLISVPM team member Mike Ruthruff&lt;br /&gt;SQL Server 2005 Deployment Guidance for Web Hosting Environments &lt;a href="http://www.microsoft.com/technet/prodtechnol/sql/bestpractice/SQL2005DGWHE.mspx"&gt;http://www.microsoft.com/technet/prodtechnol/sql/bestpractice/SQL2005DGWHE.mspx&lt;/a&gt;by Alex DeNeui&lt;br /&gt;Resolving Common Connectivity Issues in SQL Server 2005 Analysis Services Connectivity Scenarios&lt;a href="http://www.microsoft.com/technet/prodtechnol/sql/bestpractice/CISQL2005ASCS.mspx"&gt;http://www.microsoft.com/technet/prodtechnol/sql/bestpractice/CISQL2005ASCS.mspx&lt;/a&gt;by Carl Rabeler&lt;br /&gt;Implementing Application Failover with Database Mirroring&lt;a href="http://www.microsoft.com/technet/prodtechnol/sql/bestpractice/implappfailover.mspx"&gt;http://www.microsoft.com/technet/prodtechnol/sql/bestpractice/implappfailover.mspx&lt;/a&gt;by Michael Thomassy, Sanjay Mishra&lt;br /&gt;Cross Posted from http://blogs.microsoft.com/mssqlisv&lt;br /&gt;Posted by &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl11_AuthorLink" href="http://blogs.msdn.com/user/Profile.aspx?UserID=19910"&gt;mssqlisv&lt;/a&gt;  &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl11_CommentsLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2007/06/05/new-sql-best-practice-articles-now-available.aspx#comments"&gt;1 Comments&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl12_PermaLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2007/04/30/will-64-bit-increase-the-performance-of-my-sql-server-application.aspx"&gt;Monday, April 30, 2007 5:25 PM&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl12_PostTitle" href="http://blogs.msdn.com/sqlprogrammability/archive/2007/04/30/will-64-bit-increase-the-performance-of-my-sql-server-application.aspx"&gt;Will 64-bit increase the performance of my SQL Server application?&lt;/a&gt;&lt;br /&gt;With 64-bit servers becoming more mainstream and SQL Server customers running more deployments on native 64-bit Windows there is a common misperception that running on 64-bit will always provide an increase in performance over 32-bit.  Many customers are surprised to find that some workloads actually run faster on 32-bit SQL Server than on the native 64-bit version.   The assumption that 64-bit will always outperform 32-bit is not true and is determined largely by characteristics of the particular workload and hardware.   Workloads that have a large volume of small uniform transactions using relatively simple query plans (OLTP-like in nature) which are not experiencing memory pressure may not benefit from running on native 64-bit SQL Server.&lt;br /&gt;Differences between 32-bit and 64-bit&lt;br /&gt;There are differences between 32-bit and 64-bit processes in general which apply to SQL Server.  The working set of 64-bit SQL Server is larger than 32-bit both in code and data; mainly due to doubling the size for pointers, 64-bit instructions, structures that are cacheline aligned and more. This means 64-bit will be more sensitive to the size of onboard chip caches which may be used less efficiently  when compared to 32-bit, resulting in a higher Cost per Instruction (CPI).  The end result is applications which are not memory constrained on 32-bit (especially OLTP) may incur a   performance penalty when running on 64-bit using the same hardware.  We have observed approximately 10-15% degradation in most cases however the impact will depend on the characteristics of the workload and hardware being used.&lt;br /&gt;Which applications will benefit most from 64-bit?&lt;br /&gt;Many SQL Server applications will realize significant performance benefit running on native 64-bit.  This platform will also provide much better scalability in the long term so it is important not to be short sighted when evaluating minor performance differences between the two platforms.  Native 64-bit SQL Server typically benefits memory hungry applications the most and also applications requiring memory for items other than data pages. Some of these include:&lt;br /&gt;•    Procedure Cache: Lots of stored procedures and dynamic SQL batches (OLTP)&lt;br /&gt;&lt;br /&gt;•     Workspace Memory:  Large number of concurrent hash joins or group by’s; large-scale sorts and index builds (Data Warehouse)&lt;br /&gt;&lt;br /&gt;•     Connection memory:  Large numbers of connections&lt;br /&gt;&lt;br /&gt;•     Thread memory:  High Concurrency OLTP, Complex query plans on multi-CPU machines&lt;br /&gt;&lt;br /&gt;•     CLR GC Heap memory:  CLR SP allocations&lt;br /&gt;&lt;br /&gt;•     Lock Memory:  Large scale OLTP&lt;br /&gt;SQL Server 32-bit version allows use of memory beyond the 2 or 3 GB (32-bit limitation of user mode virtual address space) through the use of Address Windowing Extensions however there are restrictions on the use of AWE mapped memory.  Specifically, the items above could not utilize AWE mapped memory (more on this below).&lt;br /&gt;What to consider when deciding between 32-bit and 64-bit&lt;br /&gt;When considering one platform over the other I would recommend thinking about the following:&lt;br /&gt;1.              Processor architecture plays a significant role. The processor used will impact the overhead introduced by running native 64-bit SQL Server on 64-bit Windows; specifically the amount of cache on the processor.  Older generation processors with less L2/L3 cache will likely incur more of a penalty running native 64-bit SQL Server than will newer processors with larger amounts of cache.  It is important to consider this and when possible favor chipsets that offer more cache.  The performance gain offered by processors with larger cache sizes vary and can only be determined through testing.  An exception to this rule would be AMD processors which have L2 cache but no L3 cache.  The memory architecture of AMD processors is very different from Intel processors and the lack of L3 cache may be offset by  the different architecture of the data transfer between processor and memory.  It is important to note that we are not endorsing one processor over the other; we have observed excellent SQL Server performance on both Intel and AMD processors.&lt;br /&gt;2.             Memory latency will have a significant impact.  The speed of data transfer between processors and memory will have a significant impact on performance.  When accessing main memory latency is important for performance.   Slower transfer speeds will result in higher latencies and a bigger performance penalty for cache misses.  Faster transfer speed will have a positive, and often, significant impact on the performance of 64-bit SQL Server.  Reducing memory latency is a key design point and strength of Non-Uniform Memory Access (NUMA) server architectures.&lt;br /&gt;3.              Consider the specifics of your particular workload.  If your workload is running on 32-bit and is not experiencing memory pressure or does not have any of the requirements mentioned above then the workload will likely not benefit from 64-bit. &lt;br /&gt;4.             Look for unexpected behaviors when testing.  We have seen a number of cases where moving to 64-bit resulted in unexpected behavior as a result of removing the virtual address space limitations.  On 32-bit systems it is common to run with AWE enabled to allow SQL Server to utilize memory beyond 2 or 3 GB.  This memory however can only be used for data cache.  On 64-bit this restriction is lifted and non-data cache memory can grow much larger than was possible on 32-bit.  This includes items such as procedure cache, lock memory, connection memory, workspace memory, etc…  While beneficial in most cases there are also cases where this can expose issues with the application’s use of SQL Server.  Some common scenarios include:&lt;br /&gt;•              Extensive growth of the procedure cache as a result of a high volume of non-parameterized SQL statements.  Service Pack 2 for SQL 2005 has some optimizations to help address these issues but it is considered a best practice to parameterize queries when possible and the sp2 optimizations do not replace the need to follow this advice.&lt;br /&gt;•               Failure to put a limit on ‘max server memory’ resulting in system wide memory pressure.  It is important on 64-bit systems to place an upper limit on ‘max server memory’ leaving sufficient room for the operating system and ensure the SQL Server service account is granted the ‘Lock pages in memory’ security privilege (On 64-bit SQL Server the lock pages in memory privilege is only valid for Enterprise edition).  The goal of setting an upper limit is to ensure that there is sufficient memory for the OS, other applications on the machine and allocations within SQL Server that are satisfied from outside the buffer pool.  SQL Server’s buffer pool is dynamic and will adjust to external memory pressure however being proactive is always a good strategy.  It is not uncommon on systems with large amount of physical memory (&gt;= 16GB) to leave several GB for these items.  Refer to  &lt;a href="http://support.microsoft.com/kb/918483"&gt;http://support.microsoft.com/kb/918483&lt;/a&gt; for more information.&lt;br /&gt;5.             Think long term.  Although there are times when a workload will perform slightly slower on native 64-bit the difference is most cases is not significant (usually 10% or less).  It is important not to let a small impact to performance overshadow the long term benefits of 64-bit SQL Server.  Native 64-bit will offer significantly better scalability than 32-bit and is the future of computing (especially for database applications).  Even if a workload does not require or benefit from the additional virtual address space now it may in the future.&lt;br /&gt;6.             Monitor and Test. By monitoring current performance of your application you may be able to get an idea of whether or not your specific workload will benefit from 64-bit SQL Server.  Some potential indicators of memory pressure which may indicate a scenario when 64-bit will help are:&lt;br /&gt;•                     High rate of I/O coupled with low page life expectancy and/or constant lazy writer activity.&lt;br /&gt;•                     Constant non-zero values for memory grants pending.&lt;br /&gt;•                     High rate of temporary objects being created/destroyed.&lt;br /&gt;•                     High value for stolen pages as a percentage of the total pages consumed by the SQL Server buffer pool.&lt;br /&gt;Ultimately however the only way to definitely know whether or not your application will benefit from running native 64-bit is to test.&lt;br /&gt;&lt;br /&gt;Cross Posted from http://blogs.microsoft.com/mssqlisv&lt;br /&gt;Posted by &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl12_AuthorLink" href="http://blogs.msdn.com/user/Profile.aspx?UserID=19910"&gt;mssqlisv&lt;/a&gt;  &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl12_CommentsLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2007/04/30/will-64-bit-increase-the-performance-of-my-sql-server-application.aspx#comments"&gt;3 Comments&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl13_PermaLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2007/03/23/upgrading-to-sql-server-2005-and-default-schema-setting.aspx"&gt;Friday, March 23, 2007 8:36 AM&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl13_PostTitle" href="http://blogs.msdn.com/sqlprogrammability/archive/2007/03/23/upgrading-to-sql-server-2005-and-default-schema-setting.aspx"&gt;Upgrading to SQL Server 2005 and DEFAULT_SCHEMA setting.&lt;/a&gt;&lt;br /&gt;Upgrading to SQL Server 2005 has many benefits . As we look back at the past year and the deployment of SQL Server 2005 with our ISV partners, one important but under-advertised feature in SQL Server 2005 became increasingly visible; the ability to control the dynamic name resolution behavior. This capability applies to workloads where object names are NOT fully-qualified with a two or a three part name (for example: “database.schema.object”). If you already fully qualify your object references, which is a SQL Server best practice, then this blog does not apply to you.&lt;br /&gt;&lt;br /&gt;In this post, I will first explain the behavior in SQL Server 2000 and expand on what changed in SQL Server 2005. Then I’ll point out how to identify the issue in your workloads and how to change the DEFAULT_SCHEMA setting to take advantage of the benefits.&lt;br /&gt;&lt;br /&gt;Dynamic Name Resolution - SQL Server 2000 vs. 2005&lt;br /&gt;A query such as "select * from table1" in SQL Server 2000 goes through a set of steps to resolve and validate the object references before execution. The search first looks at the identity of the connection executing the query. Let’s assume we have a user connection through "user1". For “select * from table1”, SQL Server 2000 searches for the object "user1.table1" first. If object does not exist, the next step is to search for "dbo.table1". These searches complete very quickly but can still be visible to the naked eye in cases where you have a workload with many ad-hoc queries (with today’s hardware this typically means over 100 queries per second) that contain not-fully-qualified object references. There is also a chance that, with the new flexibilities introduced in SQL Server 2005 around separation of users and schemas (&lt;a href="http://msdn2.microsoft.com/en-us/library/ms190387.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms190387.aspx"&gt;http://msdn2.microsoft.com/en-us/library/ms190387.aspx&lt;/a&gt;), you may see a higher overhead in name resolution compared to SQL Server 2000. In extreme cases, we have seen the impact of name resolution to be 10-15% on throughput.&lt;br /&gt;&lt;br /&gt;However SQL Server 2005 provides a mechanism to allow finer control over name resolution to the administrators. By manipulatng the value of the default_schema_name columns in the sys.database_principals Dynamic Management View, you can change the way name resolution is performed. You can assign a default schema for each database principal (a.k.a user) to go directly to the correct schema if an object name is not fully qualified, and bypass the unnecessary steps.&lt;br /&gt;&lt;br /&gt;Reusing the example from above; with DEFAULT_SCHEMA set to 'dbo' in a SQL Server 2005 database, user1 executing 'select * from table1' will directly resolve immediately to 'dbo.table1' without searching for 'user1.table1'.&lt;br /&gt;&lt;br /&gt;In fact, if you use the new CREATE USER syntax from SQL server 2005, you will get ‘dbo’ as the DEFAULT_SCHEMA by default. So if you are developing in a new database under SQL Server 2005, you are already taking advantage of this name resolution shortcut. However, the behavior for upgraded databases is different . During upgrade from previous versions of SQL Server, to preserve the same behavior, SQL Server 2005 sets the DEFAULT_SCHEMA to the name of the user. Example: ‘user1’ gets DEFAULT_SCHEMA of 'user1' when you upgrade a database from an earlier version to SQL Server 2005 by attaching or any other method. The reality is, in most instances, applications don't use anything but the ‘dbo’ schema. Nevertheless, it is close to impossible to detect whether your database and queries contain references to only objects in a specific schema.&lt;br /&gt;&lt;br /&gt;Why? Well, it may be that some of your objects and queries get generated dynamically and only parsed right before execution. Obviously preserving the backward compatible behavior also means that you still pay for the added cost of the late bound name resolution.&lt;br /&gt;&lt;br /&gt;This was exactly the reason why a few of our partners saw higher CPU cycles after the upgrade and experienced slower throughput in SQL Server 2005. In those cases, DEFAULT_SCHEMA setting got us back the throughput we were expecting from SQL Server 2005. The improvements have been as much as 15% in throughput.&lt;br /&gt;&lt;br /&gt;Obviously the best practice still stands: You should fully qualify all object names and not worry about the name resolution cost at all. The reality is, there are still many imperfect applications out there and this setting help great for those cases.&lt;br /&gt;&lt;br /&gt;How do you know if this is an issue for your workload?&lt;br /&gt;&lt;br /&gt;Lets take a look at ways we can tell if this setting could benefit your workload.&lt;br /&gt;&lt;br /&gt;The brute force method is to look at your app code or SQL Server 2005 Profiler for the queries that you are executing. If you do not have fully qualified names and you are executing them through a database principal (user) that has a DEFAULT_SCHEMA value that does not have the intended schema name for the not-fully-qualified objects in your queries, then you have the problem.&lt;br /&gt;&lt;br /&gt;Reiterating the example from above; user1, with DEFAULT_SCHEMA='user1', executing 'select * from table1' and resolving to 'dbo.table1' could benefit from setting DEFAULT_SCHEMA to 'dbo'.&lt;br /&gt;&lt;br /&gt;The other option is to use sys.dm_exec_cached_plans or sys.dm_exec_query_stats to look at the cached plans. Again you can go after the text and look for name qualification. You can also look for the results from the following query.&lt;br /&gt;&lt;br /&gt;You can use the following query to see the cached plans that may indicate an issue with not-fully-qualified object names;&lt;br /&gt;SELECT * FROM&lt;br /&gt;(&lt;br /&gt;                SELECT e.[text], e.[user_id], e.[dbid]&lt;br /&gt;                FROM (&lt;br /&gt;                                SELECT b.text,c.attribute,c.value&lt;br /&gt;FROM sys.dm_exec_cached_plans AS a&lt;br /&gt;                                                OUTER APPLY sys.dm_exec_sql_text(a.plan_handle) AS b&lt;br /&gt;                                                OUTER APPLY sys.dm_exec_plan_attributes(a.plan_handle) AS c&lt;br /&gt;                                ) AS d&lt;br /&gt;                PIVOT (MAX(d.value) FOR d.attribute IN ("user_id", "dbid")) AS e&lt;br /&gt;                ) AS f&lt;br /&gt;WHERE [dbid] not in (32767) -- leave out the resource database&lt;br /&gt;AND [user_id] not in (-2,1,4) -- leave out the generic plans, plans that belong to dbo and sys&lt;br /&gt;&lt;br /&gt;If the resultset is non-empty, your application may be a good candidate for the DEFAULT_SCHEMA setting consideration. This is a good shortcut but is not a 100% guarantee. Be aware that sys.dm_exec_cached_plans contains only the cached plans. The cache fluctuates under memory pressure so some queries may get pushed out of the cache due to aging and pressure or, in some cases, may not get cached at all due to cost or security restrictions.&lt;br /&gt;&lt;br /&gt;One additional thing to watch for; If you do not see a range of user_ids in the resultset, the benefits from setting the DEFAULT_SCHEMA may not be significant due to other optimizations and shortcuts in the engine around plan caching.&lt;br /&gt;&lt;br /&gt;How do you change the DEFAULT_SCHEMA?&lt;br /&gt;Assuming your database is using objects only in the dbo schema here is what you would run for each user:&lt;br /&gt;ALTER USER &lt;username/&gt; WITH DEFAULT_SCHEMA=dbo&lt;br /&gt;&lt;br /&gt;You can validate the current DEFAULT_SCHEMA settings by looking at the default_schema_name column in the sys.database_principals Dynamic Management View.&lt;br /&gt;Cross Posted from http://blogs.microsoft.com/mssqlisv&lt;br /&gt;Posted by &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl13_AuthorLink" href="http://blogs.msdn.com/user/Profile.aspx?UserID=19910"&gt;mssqlisv&lt;/a&gt;  &lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl13_CommentsLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2007/03/23/upgrading-to-sql-server-2005-and-default-schema-setting.aspx#comments"&gt;2 Comments&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl14_PermaLink" href="http://blogs.msdn.com/sqlprogrammability/archive/2007/02/22/why-cannot-i-grant-execute-permission-on-assemblies-anymore.aspx"&gt;Thursday, February 22, 2007 11:47 AM&lt;/a&gt;&lt;br /&gt;&lt;a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl14_PostTitle" href="http://blogs.msdn.com/sqlprogrammability/archive/2007/02/22/why-cannot-i-grant-execute-permission-on-assemblies-anymore.aspx"&gt;why cannot i GRANT EXECUTE permission on assemblies anymore ?&lt;/a&gt;&lt;br /&gt;Just a quick note that this is by design and no you don't need to use it.&lt;br /&gt; What are we talking about ?&lt;br /&gt;&lt;a title="Books online" href="http://msdn2.microsoft.com/en-us/library/ms189479.aspx" target="_blank" mce_href="http://msdn2.microsoft.com/en-us/library/ms189479.aspx"&gt;Books online&lt;/a&gt; talks about granting assembly permissions. You used to do&lt;br /&gt;GRANT execute on ASSEMBLY :: &lt;assembly_name&gt; to &lt;database_principal&gt; with SQL Server 2005&lt;br /&gt;Your database holds your assemblies and as such you could grant / revoke limited set of permissions. We initially allowed you to grant execute permission on the assembly but now when you execute the same on a server with the SP2  service pack, you get the following :&lt;br /&gt;Msg 102, Level 15, State 1, Line 0&lt;br /&gt;Incorrect syntax near 'EXECUTE...'.&lt;br /&gt;Why did this change ?&lt;br /&gt;Execute permission gave a false sense of security and was really inappropriate. Here's why:&lt;br /&gt;As we shipped SQL Server 2005, this permission set was supported in TSQL but never enforced. So you could say "deny execute on assembly" but nothing happened. With this fix to revert the support from TSQL, you will not be misled anymore and we wanted to get this fix to you in a service pack of the same product that introduced you this immensely easy way of expressing your logic in assemblies. Going forward, with database upgrades to next release, any lingering  assemblies that display this permission will be automatically corrected. And so you don't have to worry about a thing.&lt;br /&gt;So how can i secure assemblies registered to the server ?&lt;br /&gt;The assembly is really a container for types, objects etc which are independently permissible. The assembly itself can be marked safe, external_access and unsafe. In addition, you can use the 'trustworthy' property of the database for similar effect. For a complete list with description of our security model, please refer &lt;a title="CLR Integration Security" href="http://msdn2.microsoft.com/en-us/library/ms131071.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms131071.aspx"&gt;CLR Integration security&lt;/a&gt; in Books Online.&lt;br /&gt;Thanks,&lt;br /&gt;Mayank Nagar&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-4128190943764844038?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/4128190943764844038/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=4128190943764844038' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/4128190943764844038'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/4128190943764844038'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/01/optimizing-sqlserver-2008.html' title='Optimizing SQLServer 2008'/><author><name>mayank nagar</name><uri>http://www.blogger.com/profile/05941327743220090036</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/-ZrUpViz65V8/Tdi4eLiUyOI/AAAAAAAAACM/rUiF460W814/s220/Photo0252.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-1386461189164558999</id><published>2009-01-14T01:43:00.000-08:00</published><updated>2009-01-14T01:44:40.908-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>Optimizing SQL Server Database Design</title><content type='html'>When designing columns to store formatted data, such as Social Security numbers or phone numbers, you have two choices. You can choose to store the data with no formatting or with formatting. Each choice has its pros and cons. If you store the data with formatting, then your disk space requirements will be slightly higher than if you don't store the data with formatting. If you store the data without formatting, then you will have to add or remove formatting each time you INSERT or UPDATE a record, which adds to CPU and memory overhead on the server. In other words, the choice you make affects your server's load.&lt;br /&gt;Which option you should choose in order to maximize performance is not always obvious, but many database designers choose to store formatted data because they feel the savings in CPU time and memory overhead (because formatting isn't performed on the fly) is more important than saving some space on the disk drive. You will have to examine your application closely to determine, in your particular case, which option will save your application the most overhead. [6.5, 7.0, 2000, 2005]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-1386461189164558999?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/1386461189164558999/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=1386461189164558999' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/1386461189164558999'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/1386461189164558999'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/01/optimizing-sql-server-database-design.html' title='Optimizing SQL Server Database Design'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-6632075541778453341</id><published>2009-01-13T02:34:00.000-08:00</published><updated>2009-01-13T02:48:41.473-08:00</updated><title type='text'>The TRUSTWORHY bit database property in SQL Server 2005</title><content type='html'>In SQL Server 2005 we introduced a new database property named TRUSTWORTHY bit (TW bit for short) at the database level in order to work as a safeguard to reduce the default surface area regarding some powerful new features: EXECUTE AS USER and CLR assemblies. These new features are really powerful, but without the TW bit they would be ultimately under the control of the DBO and can potentially be misused to escalate privileges in the system.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;When the TW bit is OFF&lt;/span&gt;&lt;br /&gt;·         EXECUTE AS USER:&lt;br /&gt;&lt;br /&gt;·         If the TW bit is OFF, EXECUTE AS USER will be bound to the DB and the server-scoped permissions of the impersonated user and roles will be used as deny-only. Access to other DBs will be limited to access as guest.&lt;br /&gt;&lt;br /&gt;·         CLR:&lt;br /&gt;&lt;br /&gt;·         Only assemblies marked as SAFE can be created and used.&lt;br /&gt;&lt;br /&gt;  But when the TW bit is ON, it doesn't blindly change the behavior of these features, instead it allows the system to verify permissions on the DBO (based on the SID) on the server or on another database to allow extended functionality.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt; When the TW bit is ON&lt;/span&gt; &lt;br /&gt;·         EXECUTE AS USER:&lt;br /&gt;&lt;br /&gt;·         DBO role: authenticator. The DBO will be part of the token as an authenticator; this means that the DBO will “vouch” for the impersonated token, and it is up to the server or another DB to trust this DBO.&lt;br /&gt;&lt;br /&gt;·         For cross-DB access, the DBO requires AUTHENTICATE permission. The impersonated context will be valid for the target DB, but still sandboxed from the server&lt;br /&gt;&lt;br /&gt;·         For access across the server, the DBO requires AUTHENTICATE SERVER permission. The impersonated context will be valid across the server (and all the DBs). *Read security Note*&lt;br /&gt;&lt;br /&gt;·         CLR :&lt;br /&gt;&lt;br /&gt;·         DBO role: establish the assembly types allowed in the DB&lt;br /&gt;&lt;br /&gt;·         For using assemblies marked as EXTERNAL_ACCESS in the DB, the DBO requires EXTERNAL_ACCESS permission. *Read security Note*&lt;br /&gt;&lt;br /&gt;·         For using assemblies marked as UNSAFE in the DB, the DBO requires UNSAFE permission. *Read security Note*&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;  When the DBO is a low privileged principal in the system, and the DBO has good control on the DB (i.e. All the privileged principals in the DB are indeed trusted individuals), the TW bit works as expected and it can be used to establish a trusted environment with the features I just mentioned.&lt;br /&gt;&lt;br /&gt; Security Note: The set of functionality marked with the *Read Security Note* text are indeed very powerful and can be easily misused if not taken into account. These features assume that the DBO (and privileged principals in the DB) are indeed fully trusted as they could in essence escalate their own privileges to sysadmin.&lt;br /&gt;&lt;br /&gt; &lt;span style="font-weight:bold;"&gt; Limitations of the TW bit&lt;/span&gt;&lt;br /&gt;  The main limitation of this mechanism is the level of granularity: The whole DB is marked as TW or not, and it is not possible to distinguish between scenarios within the same DB. This presents a problem to the DBAs: either you trust the DBO (and everyone the DBO has entrusted with elevated permissions on the DB) or not, there is no middle ground.&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;  Also notice the overloaded significance of the TW bit. It may be possible that you only want to use one of the features it is gating, for example, the creation of EXTERNAL ACCESS assemblies, but because of its boolean nature, it would also allow the rest of the features. At that point the permissions granted to the DBO are the ones that will truly enable/disable any of these features.&lt;br /&gt; &lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;br /&gt;  The main risk: TW bit ON &amp; DBO is sysadmin&lt;/span&gt;&lt;br /&gt;  The risk with using the TW bit arises not from enabling it, but in conjunction to the nature of DBO. In practice, the first condition I mentioned (DBO is a low privileged user) is rarely true, and under these circumstances (DBO is a sysadmin &amp; the TW bit enabled) all of the features I mentioned on the TW ON section are immediately enabled on the DB, even if the DBA only desired to use one of them.&lt;br /&gt;&lt;br /&gt;  If the desired behavior is indeed to enable all these features on the DB, and the privileged users on the  DB are indeed trusted, there is no need to worry as the system will behave as expected, but it would be a good idea to keep such DBs closely monitored. Notice that in SQL Server 2005, out-of-the-box we already have a scenario with the TW bit ON &amp; sysadmin: msdb. MSDB is considered a system DB with various system modules, and the assumption is that DBAs are already protecting msdb as they would protect other system DBs such as master DB.&lt;br /&gt;&lt;br /&gt;  Unfortunately the case above is rarely the desired behavior, and based cases we have observed, we detected two different kinds of mistakes when enabling the WT bit:&lt;br /&gt;&lt;br /&gt;·         Something breaks: The application works perfectly during development/testing, but once it is deployed on a tightly controlled environment the application breaks.&lt;br /&gt;&lt;br /&gt;·          Nothing breaks: The application works, but the attack surface area has been increased accidentally.&lt;br /&gt;&lt;br /&gt;The solution for the first type of mistakes is simple: Grant the appropriate permissions to the DBO. It is the second type scenario the one that we should really worry about as it may not be obvious and it could allow a rogue user in the DB to escalate his privileges and take control of SQL Server.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;br /&gt; Conclusions&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;  The TW bit is used as a mechanism to control the surface area on very powerful features, but it relies on the DBO to be following least privilege principles, and not being a sysadmin. Having the combination of a sysadmin being the DBO on a DB that has been marked as TW bit = ON is a very dangerous one and we recommend to avoid it whenever it is possible.&lt;br /&gt;&lt;br /&gt; As an alternative to the TW bit, in SQL Server 2005 we also introduced the notion of module signing, and the digital signatures can be used to extend the impersonation context beyond the DBand to establish an explicit trust on signed assemblies.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-6632075541778453341?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/6632075541778453341/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=6632075541778453341' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6632075541778453341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6632075541778453341'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/01/trustworhy-bit-database-property-in-sql.html' title='The TRUSTWORHY bit database property in SQL Server 2005'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-6480864431108167822</id><published>2009-01-13T02:31:00.000-08:00</published><updated>2009-01-13T02:32:40.914-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><title type='text'>How to create a SQL trace using T-SQL</title><content type='html'>Some users want to know if there is a way to monitor events on SQL server without using SQL Profiler. Yes, there is: the engine support behind SQL Profiler is the feature called SQL Trace which is introduced in SQL 2005. SQL Trace provides a set of stored procedures to create traces on an instance of the SQL Server Database Engine. These system stored procedures can be used from within user's own applications to create traces manually, and allows to write custom applications specific to their needs.&lt;br /&gt;&lt;br /&gt;The following sample code shows how to create customized SQL trace to monitor events to user's interest.&lt;br /&gt;&lt;br /&gt;-- sys.traces shows the existing sql traces on the server&lt;br /&gt;&lt;br /&gt;select * from sys.traces&lt;br /&gt;&lt;br /&gt;go&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;--create a new trace, make sure the @tracefile must NOT exist on the disk yet&lt;br /&gt;&lt;br /&gt;declare @tracefile nvarchar(500) set @tracefile=N'c:\temp\newtraceFile'&lt;br /&gt;&lt;br /&gt;declare @trace_id int&lt;br /&gt;&lt;br /&gt;declare @maxsize bigint&lt;br /&gt;&lt;br /&gt;set @maxsize =1&lt;br /&gt;&lt;br /&gt;exec sp_trace_create @trace_id output,2,@tracefile ,@maxsize&lt;br /&gt;&lt;br /&gt;go&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;--- add the events of insterest to be traced, and add the result columns of interest&lt;br /&gt;&lt;br /&gt;--  Note: look up in sys.traces to find the @trace_id, here assuming this is the first trace in the server, therefor @trace_id=1&lt;br /&gt;&lt;br /&gt;declare @trace_id int&lt;br /&gt;&lt;br /&gt;set @trace_id=1&lt;br /&gt;&lt;br /&gt;declare @on bit&lt;br /&gt;&lt;br /&gt;set @on=1&lt;br /&gt;&lt;br /&gt;declare @current_num int&lt;br /&gt;&lt;br /&gt;set @current_num =1&lt;br /&gt;&lt;br /&gt;while(@current_num &lt;65)&lt;br /&gt;&lt;br /&gt;      begin&lt;br /&gt;&lt;br /&gt;      --add events to be traced, id 14 is the login event, you add other events per your own requirements, the event id can be found @ BOL http://msdn.microsoft.com/en-us/library/ms186265.aspx&lt;br /&gt;&lt;br /&gt;      exec sp_trace_setevent @trace_id,14, @current_num,@on&lt;br /&gt;&lt;br /&gt;      set @current_num=@current_num+1&lt;br /&gt;&lt;br /&gt;      end&lt;br /&gt;&lt;br /&gt;go&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;--turn on the trace: status=1&lt;br /&gt;&lt;br /&gt;-- use sys.traces to find the @trace_id, here assuming this is the first trace in the server, so @trace_id=1&lt;br /&gt;&lt;br /&gt;declare @trace_id int&lt;br /&gt;&lt;br /&gt;set @trace_id=1&lt;br /&gt;&lt;br /&gt;exec sp_trace_setstatus  @trace_id,1&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;--pivot the traced event&lt;br /&gt;&lt;br /&gt;select LoginName,DatabaseName,* from ::fn_trace_gettable(N'c:\temp\newtraceFile.trc',default)&lt;br /&gt;&lt;br /&gt;go&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;-- stop trace. Please manually delete the trace file on the disk&lt;br /&gt;&lt;br /&gt;-- use sys.traces to find the @trace_id, here assuming this is the first trace in the server, so @trace_id=1&lt;br /&gt;&lt;br /&gt;declare @trace_id int&lt;br /&gt;&lt;br /&gt;set @trace_id=1&lt;br /&gt;&lt;br /&gt;exec sp_trace_setstatus @trace_id,0&lt;br /&gt;&lt;br /&gt;exec sp_trace_setstatus @trace_id,2&lt;br /&gt;&lt;br /&gt;go&lt;br /&gt;&lt;br /&gt;The granularity level of SQL trace is server-wide event groups, which means it doesn’t allow to auditing specific event or action by specific user in a specific database. If you need a more granulated audit mechanism, you can start to look at the SQL Server Audit feature which is introduced in SQL Server 2008.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-6480864431108167822?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/6480864431108167822/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=6480864431108167822' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6480864431108167822'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6480864431108167822'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/01/how-to-create-sql-trace-using-t-sql.html' title='How to create a SQL trace using T-SQL'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-5068655869267903290</id><published>2009-01-13T01:19:00.000-08:00</published><updated>2009-01-13T01:21:03.632-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><title type='text'>Have You Backed Up Your Database Master Key?</title><content type='html'>If you have encrypted columns in a database or certificates used to create them, you need to make sure that you back up the Database Master Key as part of your maintenance, and then protect that backup file. Here's the short version of the command:&lt;br /&gt;&lt;br /&gt;BACKUP MASTER KEY&lt;br /&gt;TO FILE = '&lt;complete path and filename&gt;'&lt;br /&gt;ENCRYPTION BY PASSWORD = '&lt;password&gt;' ;&lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/aa337546(SQL.90).aspx"&gt;http://msdn.microsoft.com/en-us/library/aa337546(SQL.90).aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-5068655869267903290?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/5068655869267903290/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=5068655869267903290' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5068655869267903290'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5068655869267903290'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/01/have-you-backed-up-your-database-master.html' title='Have You Backed Up Your Database Master Key?'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-3622134561838732181</id><published>2009-01-13T00:58:00.000-08:00</published><updated>2009-01-13T00:59:33.260-08:00</updated><title type='text'>How do exes/dlls generated with the /platform:x switch interact?</title><content type='html'>Let's assume we have the following three dlls:&lt;br /&gt;&lt;br /&gt;   anycpu.dll      -- compiled "any cpu"&lt;br /&gt;&lt;br /&gt;   x86.dll           -- compiled "x86"&lt;br /&gt;&lt;br /&gt;   x64.dll           -- compiled "x64"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And the following three exes:&lt;br /&gt;&lt;br /&gt;   anycpu.exe     -- compiled "any cpu"&lt;br /&gt;&lt;br /&gt;   x86.exe          -- compiled "x86"&lt;br /&gt;&lt;br /&gt;   x64.exe          -- compiled "x64"&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;What happens if you try to use these exes and dlls together? We have to consider two possible scenarios, running on a 32-bit machine and running on a 64-bit machine...&lt;br /&gt;&lt;br /&gt;On a 32-bit x86 machine:&lt;br /&gt;&lt;br /&gt;anycpu.exe -- runs as a 32-bit process, can load anycpu.dll and x86.dll, will get BadImageFormatException if it tries to load x64.dll&lt;br /&gt;&lt;br /&gt;x86.exe -- runs as a 32-bit process, can load anycpu.dll and x86.dll, will get BadImageFormatException if it tries to load x64.dll&lt;br /&gt;&lt;br /&gt;x64.exe -- will get BadImageFormatException when it tries to run&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;On a 64-bit x64 machine:&lt;br /&gt;&lt;br /&gt;anycpu.exe -- runs as a 64-bit process, can load anycpu.dll and x64.dll, will get BadImageFormatException if it tries to load x86.dll&lt;br /&gt;&lt;br /&gt;x86.exe -- runs as a 32-bit process, can load anycpu.dll and x86.dll, will get BadImageFormatException if it tries to load x64.dll&lt;br /&gt;&lt;br /&gt;x64.exe -- runs as a 64-bit process, can load anycpu.dll and x64.dll, will get BadImageFormatException if it tries to load x86.dll&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-3622134561838732181?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/3622134561838732181/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=3622134561838732181' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3622134561838732181'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3622134561838732181'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2009/01/how-do-exesdlls-generated-with.html' title='How do exes/dlls generated with the /platform:x switch interact?'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-2768753810800563392</id><published>2008-12-28T21:13:00.000-08:00</published><updated>2008-12-28T21:14:34.931-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Indexes'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>Indexes for aggregates</title><content type='html'>It’s well known that indexes on columns used in where clause and for joins is a good thing in SQL, but what about other places. How about on aggregates?&lt;br /&gt;&lt;br /&gt;Consider a simple table with an amount and a customerID. It’s a common requirement to calculate the total amount that each customer has paid. No conditions are enforced, so this would seem like a place where an index won’t help. Well, let’s see. (sample code at end)&lt;br /&gt;&lt;br /&gt;The clustered index (and hence the physical order of the rows) is on the identity column.Take the following query.&lt;br /&gt;SELECT CustomerID, SUM(Amount) FROM Payments group by customerID&lt;br /&gt;&lt;br /&gt;Without any additional indexes, SQL will execute that as a hash match (aggregate) which comprises 63% of the query’s cost. That is because the data is not ordered by the grouped column, and hence cannot be simply be summed.&lt;br /&gt;&lt;br /&gt;Now add an index on CustomerID, Amount and run the same query. Now, the aggregate can be satisfied just with the non clustred index and, more importantly, the data is in order of customerID, so just a stream aggregate is required and the data does not have to be resorted or run through a hashing algorithm. Moreover, the stream aggregate is only 15% of the query’s cost&lt;br /&gt;&lt;br /&gt;CREATE TABLE Payments (&lt;br /&gt;PaymentKey INT IDENTITY PRIMARY KEY,&lt;br /&gt;CustomerID int,&lt;br /&gt;InvoiceID int,&lt;br /&gt;PaymentDate datetime,&lt;br /&gt;Amount Numeric(17,5)&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;;WITH DataPopulate (RowNo, CustomerID ,InvoiceID ,ADate, Amount) AS (&lt;br /&gt;SELECT 1 AS RowNo, FLOOR(RAND()*40) as CustomerID, FLOOR(RAND()*200) as InvoiceID,&lt;br /&gt; DATEADD(dd, FLOOR(RAND()*75454),'1753/01/01'), rand()*856542 AS Amount&lt;br /&gt;UNION ALL&lt;br /&gt;SELECT rowNo+1, FLOOR(RAND(RowNo*85455)*40) AS CustomerID,&lt;br /&gt; FLOOR(RAND(RowNo*85455)*500) AS InvoiceID,&lt;br /&gt; DATEADD(dd, FLOOR(RAND(RowNo*96322)*85454),'1753/01/01'),&lt;br /&gt; rand(RowNo*25411)*86542 AS Amount&lt;br /&gt;FROM DataPopulate WHERE RowNo&lt;10000&lt;br /&gt;)&lt;br /&gt;INSERT INTO Payments (CustomerId, InvoiceID, PaymentDate, Amount)&lt;br /&gt;SELECT CustomerID ,InvoiceID ,ADate, Amount FROM DataPopulate&lt;br /&gt;OPTION (MAXRECURSION 10000)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-2768753810800563392?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/2768753810800563392/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=2768753810800563392' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/2768753810800563392'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/2768753810800563392'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/indexes-for-aggregates.html' title='Indexes for aggregates'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-2169205119393892990</id><published>2008-12-28T20:08:00.000-08:00</published><updated>2008-12-28T20:15:21.529-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><title type='text'>When did CheckDB last run?</title><content type='html'>If corruption is found in a database it’s very important to know when the corruption started. In the cases where a restore is needed to fix the corruption, knowing which backup is clean can save a great deal of time in restoring databases and checking them.&lt;br /&gt;&lt;br /&gt;On SQL 2000, the only way to know was to to go back through the history of the checkDB jobs (everyone is running checkDB regularly, right?) and see when the last successful run was.&lt;br /&gt;&lt;br /&gt;On SQL 2005 and higher, when checkDB runs successfully, ie without finding any errors, it writes the date of the last run into the database’s boot page.  Whenever SQL Server then starts that database up, be it during a server start, a database restore or bringing the database online, SQL prints a message into the error log.&lt;br /&gt;&lt;br /&gt;CHECKDB for database ‘Testing’ finished without errors on 2008-12-22 10:20:06.007 (local time).&lt;br /&gt;&lt;br /&gt;This makes it very easy to see when the database was last known to be clean (without any corruption). Note that SQLL is not running checkDB when it prints that. It’s simply printing out the date that CheckDB last completed without finding any problems. The information can also be read out of the boot page using an undocumented DBCC command.&lt;br /&gt;&lt;br /&gt;   1. Use Testing  &lt;br /&gt;   2. GO  &lt;br /&gt;   3.   &lt;br /&gt;   4. DBCC TRACEON(3604)  &lt;br /&gt;   5. DBCC DBINFO  &lt;br /&gt;   6. DBCC TRACEOFF(3604)  &lt;br /&gt;&lt;br /&gt;Use Testing GO DBCC TRACEON(3604) DBCC DBINFO DBCC TRACEOFF(3604)&lt;br /&gt;&lt;br /&gt;This prints out a whole bunch of information, all found in the database’s boot page. The info of interest here is in the second block (on SQL 2008 RTM)&lt;br /&gt;&lt;br /&gt;dbi_dbccLastKnownGood = 2008-12-22 10:20:06.007&lt;br /&gt;&lt;br /&gt;If the date listed is 1900-01-01 00:00:00, it means that CheckDB has never run successfully on that database. If that is the case, there will be no entries in the error log when the database is started.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-2169205119393892990?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/2169205119393892990/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=2169205119393892990' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/2169205119393892990'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/2169205119393892990'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/when-did-checkdb-last-run.html' title='When did CheckDB last run?'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-1549712267868159488</id><published>2008-12-26T01:53:00.000-08:00</published><updated>2008-12-26T01:55:28.516-08:00</updated><title type='text'>Measuring Performance of Web Server</title><content type='html'>Measuring Web server performance is a skill that can only be refined by repeated experience and experimentation. There are many variables at play, such as the number of clients, speed of client connections, server resources, application code, and so on. It helps to have good tools at your disposal, and fortunately those are available.&lt;br /&gt;&lt;br /&gt;Microsoft provides the Web Application Stress (WAS) tool, which simulates multiple HTTP clients hitting your Web site. You can control the client load, number of connections, format of cookies, headers, and several other parameters from the tool's graphical interface. After a test run, WAS provides you with reports containing performance metrics such as response time, throughput, and performance counter data relevant to your application. The goal is simple: to maximize throughput and CPU utilization under high degrees of load. WAS is available from the Microsoft Internet Information Server Resource Kit and is also downloadable separately from &lt;a href="http://webtool.rte.microsoft.com."&gt;http://webtool.rte.microsoft.com.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;ASP.NET also exposes a number of performance counters that can be used to track the execution of your applications. Unlike traditional ASP, most of these performance counters are exposed per-application, instead of globally for the entire machine. The per-application counters are available under the ASP.NET Framework applications performance object, and you need to select a particular application instance when selecting a counter to monitor. Of course, you can still see the counter values for all applications using a special "__Total__" application instance in System Monitor. ASP.NET also exposes global-only counters which are not bound to a particular application instance. These counters are located under the ASP.NET System performance object. To view all available counters for ASP.NET (on Windows 2000 systems):&lt;br /&gt;&lt;br /&gt;   1. Select Start-&gt;Programs-&gt;Administrative Tools-&gt;Performance.&lt;br /&gt;   2. Click the View Report button in System Monitor.&lt;br /&gt;   3. Click the Add button.&lt;br /&gt;   4. Select ASP.NET Applications, then choose the All counters radio button. Click OK.&lt;br /&gt;   5. Select ASP.NET, then choose the All counters radio button. Click OK. &lt;br /&gt;&lt;br /&gt;The ASP.NET Trace feature is also useful for identifying performance bottlenecks in your code. It can show you important timing information between successive trace output statements, as well as information about the server control heierarchy, the amount of viewstate used, and the render size of controls on your page.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-1549712267868159488?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/1549712267868159488/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=1549712267868159488' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/1549712267868159488'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/1549712267868159488'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/measuring-performance-of-web-server.html' title='Measuring Performance of Web Server'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-5236649550657984036</id><published>2008-12-25T20:30:00.000-08:00</published><updated>2008-12-25T20:35:48.656-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Extended Stored Procedure'/><category scheme='http://www.blogger.com/atom/ns#' term='Stored Procedure'/><title type='text'>Using xp_ReadErrorLog in SQL Server 2005</title><content type='html'>I would like to share some interesting parameters I found for the undocumented extended stored procedure xp_ReadErrorLog. In doing some testing with this extended stored procedure I found four very interesting parameters. Adding to some of the articles already on the web that discuss undocumented stored procedures, in this article I will explain my testing, use and some examples of the procedure.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;br /&gt;Parameters revealed&lt;/span&gt;&lt;br /&gt;While working on some system startup procedures that would be making use of the xp_ReadErrorLog extended stored procedure, I came across some very interesting and useful parameters for the procedure. In testing I discovered some of the hidden parameter options that are similar, but still different in the way the extended stored procedure works from version SQL 2000 to SQL 2005. These are SQL 2005 only options. The parameter data types and size were determined by investigating the undocumented stored procedure sp_ReadErrorLog that uses the extended stored procedure.&lt;br /&gt;&lt;br /&gt;Well, the interesting part starts now with the parameters. As in the previous versions parameter 1 reads the error log number passed to it, where the default "0" reads the current log.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;xp_ReadErrorLog &lt;br /&gt;&lt;br /&gt; &lt;br /&gt;LogDate                  ProcessInfo  Text&lt;br /&gt;2008-03-04 12:11:01.450  Server       Microsoft SQL Server 2005 - 9.00.3159.00 (Intel X86)    Mar 23 2007 16:15:11&lt;br /&gt;2008-03-04 12:11:01.500  Server       (c) 2005 Microsoft Corporation.&lt;br /&gt;2008-03-04 12:11:01.500  Server       All rights reserved.   2008-03-04 12:11:01.500 Server     Server process ID is 1284.&lt;br /&gt;2008-03-04 12:11:01.500  Server       Authentication mode is MIXED.&lt;br /&gt;2008-03-04 12:11:01.510  Server       Logging SQL Server messages in file 'D:\SRVAPPS\MSSQL.1\MSSQL\LOG\ERRORLOG'.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now let's investigate Parameter (2). It turns out that a value of 1 (default) instructs the procedure to read the SQL error log. By passing a value of 2, the SQL server Agent log is read. Yes, the Agent log! So for example: xp_ReadErrorLog 0, 2 reads the current SQL server Agent log. Also note when using parameter 2 with the extended stored procedure that the column heading returned also changes.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;xp_ReadErrorLog 0,2&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;LogDate                  ErrorLevel  Text&lt;br /&gt;2008-03-04 12:11:10.000  3           [393] Waiting for SQL Server to recover databases...&lt;br /&gt;2008-03-04 12:11:14.000  3           [100] Microsoft SQLServerAgent version 9.00.3042.00 (x86 unicode retail build) ..&lt;br /&gt;2008-03-04 12:11:14.000  3           [101] SQL Server xxxxxxxx version 9.00.3159 (0 connection limit)&lt;br /&gt;2008-03-04 12:11:14.000  3           [102] SQL Server ODBC driver version 9.00.3042 2008-03-04 12:11:01.450  Server&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Now we know that we can read both SQL logs (error and agent) for any log file, so now let's look at parameter (3). For those times when you need to find some value in the logs and have used the old trick/process of reading the extended stored procedure into a table and then searching through the table to find a value, we now have parameter (3). Parameter 3 is a search string that can be used to return just the log entry rows that contain the value in the search string. And to make it even better or to refine the search further, parameter 4 is also a search string.&lt;br /&gt;&lt;br /&gt;An extra feature of this new version is that parameters 3 and 4 can be used in conjunction with each other for searching SQL error log (parameter 2 = 1) or SQL Agent log (parameter 2=2). So for example, xp_ReadErrorLog 0,1,'failed' will read the current SQL error log and return only rows that contain "failed". For an example of using parameter (4) example, xp_ReadErrorLog 0,1,'failed','login' will read current SQL error log returning only rows that contain "failed" and "login" in the same row. This makes it quite easy for retrieving those log entries for failed user logins from the SQL error logs, or maybe looking for those failed Agent jobs. Or those occasional times when you need to quickly find the port SQL started on or what machine the cluster is executing on.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;xp_ReadErrorLog 0, 1, 'Failed', 'login'&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;LogDate                  ProcessInfo  Text&lt;br /&gt;2008-03-04 12:11:12.340  Logon        Login failed for user 'Domain\xxxxxx'. [CLIENT: &lt;local machine&gt;]&lt;br /&gt;2008-03-04 15:29:08.710  Logon        Logon failed for login 'NT AUTHORITY\NETWORK SERVICE' due to trigger execution.&lt;br /&gt;2008-03-04 15:29:08.710  spid54       The client was unable to reuse a session with SPID 54, which had been reset...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;br /&gt;Parameters defined&lt;/span&gt;&lt;br /&gt;    * Parameter 1 (int), is the number of the log file you want to read, default is "0" for current log. The extended stored procedure xp_enumerrorlogs will come in handy in determining what SQL server error logs or SQL server Agent logs exist and when they were created. NOTE: extended stored procedure xp_enumerrorlogs parameter (1) works just like xp_ReadErrorLog parameter (2). A value of 1 shows available SQL error logs and a value of 2 shows Agent logs. The default value is 0.&lt;br /&gt;    * Parameter 2 (int), value of 1 reads SQL error logs, value of 2 reads SQL Server Agent logs, with a default value of 1.&lt;br /&gt;    * Parameter 3 varchar (255), is a search string for the log entry, with a default value of NULL.&lt;br /&gt;    *  Parameter 4 varchar (255), is another search string for the log entry, with a default value of NULL.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;br /&gt;Background&lt;/span&gt;&lt;br /&gt;An extended stored procedure is a dynamic link library that runs inside SQL server. It can execute from Query Analyzer or SQL Server Management Studio (SSMS) for example. In most cases these extended stored procedures can only be executed by users with sysadmin privileges. Also note as Microsoft has always said about undocumented processes may change in future release.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-5236649550657984036?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/5236649550657984036/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=5236649550657984036' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5236649550657984036'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5236649550657984036'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/using-xpreaderrorlog-in-sql-server-2005.html' title='Using xp_ReadErrorLog in SQL Server 2005'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-824640917230572962</id><published>2008-12-23T20:36:00.000-08:00</published><updated>2008-12-23T20:39:16.113-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><title type='text'>Extract User-Role Mapping</title><content type='html'>This script can be used with SQL 2000 and 2005. For example if you have 10 users in current database, it will retrieve all Group information along with default database, if the user has a login account else if will return a blank.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;Begin&lt;br /&gt;--Create a temp table that will hold the main result. This script will check your version, if SQL 2005 or 2000,&lt;br /&gt;--because  sp_helpuser return 6 values in SQL 2000 and 7 values in SQL 2005.&lt;br /&gt;    Create table #tmpUserPerm&lt;br /&gt;    (UserName varchar(100),&lt;br /&gt;    GroupName varchar(100),&lt;br /&gt;    LoginName varchar(100),&lt;br /&gt;    DefDBName varchar(100),&lt;br /&gt;    UserId int,&lt;br /&gt;    SID varbinary(100),&lt;br /&gt;    DefSchemaName varchar(100) null)&lt;br /&gt;&lt;br /&gt;    Declare @name varchar(100)&lt;br /&gt;    Declare @ver varchar(100)&lt;br /&gt;&lt;br /&gt;    --Create a temp table that will store all users except DBO and GUEST. If you want all users then &lt;br /&gt;    --you can remove "and name not in ('DBO', 'GUEST')" from the following statement.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    select uid, name into #TmpUser from sysusers &lt;br /&gt;    where issqluser = 1 and hasdbaccess &lt;&gt; 0 and name not in ('DBO', 'GUEST')&lt;br /&gt;&lt;br /&gt;    --Execute the below query to get current version of SQL SERVER&lt;br /&gt;    set @ver = convert(varchar(100),SERVERPROPERTY('productversion'))&lt;br /&gt;&lt;br /&gt;    if (@ver = '9.00.3054.00') --If SQL 2005 then &lt;br /&gt;    begin&lt;br /&gt; --Run a cursor for all users&lt;br /&gt;       declare cur Cursor for Select name from #Tmpuser&lt;br /&gt;       open cur&lt;br /&gt;       fetch next from cur into @name&lt;br /&gt;       while @@fetch_Status = 0&lt;br /&gt;       BEGIN&lt;br /&gt;    --Get data from sp_helpuser for current value of user (@NAME)&lt;br /&gt;           insert into #tmpUserPerm (UserName, GroupName, LoginName, DefDBName, DefSchemaName, UserId, SID)&lt;br /&gt;           Exec sp_helpuser @name&lt;br /&gt;           fetch next from cur into @name&lt;br /&gt;       END&lt;br /&gt;       close cur&lt;br /&gt;       deallocate cur&lt;br /&gt;       drop table #Tmpuser&lt;br /&gt;       select * from #tmpUserPerm order by 1&lt;br /&gt;       drop table #tmpUserPerm&lt;br /&gt;    END&lt;br /&gt;    else --If SQL SERVER 2000 or other &lt;br /&gt;    begin&lt;br /&gt; --Run cursor for all the user  names&lt;br /&gt;       declare cur1 Cursor for Select name from #Tmpuser&lt;br /&gt;       open cur1&lt;br /&gt;       fetch next from cur1 into @name&lt;br /&gt;       while @@fetch_Status = 0&lt;br /&gt;       BEGIN&lt;br /&gt; --Get data from sp_helpuser for current value of user (@NAME)&lt;br /&gt;          insert into #tmpUserPerm (UserName, GroupName, LoginName, DefDBName, UserId, SID)&lt;br /&gt;          Exec sp_helpuser @name&lt;br /&gt;          fetch next from cur1 into @name&lt;br /&gt;       END&lt;br /&gt;       close cur1&lt;br /&gt;       deallocate cur1&lt;br /&gt;       drop table #Tmpuser&lt;br /&gt;       select username, groupname, loginname, defdbname from #tmpUserPerm order by 1&lt;br /&gt;       drop table #tmpUserPerm&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-824640917230572962?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/824640917230572962/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=824640917230572962' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/824640917230572962'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/824640917230572962'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/extract-user-role-mapping.html' title='Extract User-Role Mapping'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-8324744267789779986</id><published>2008-12-23T00:48:00.000-08:00</published><updated>2008-12-23T00:49:07.706-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>Performance Tuning SQL Server Hardware</title><content type='html'>Generally, it is better to run fewer SQL Server databases on more smaller servers than it is to run many databases on one larger server. Here are some reasons why:&lt;br /&gt;&lt;br /&gt;    * Purchasing several smaller SQL Servers may be less expensive than buying one huge SQL Server, although this may not seem logical to many people not familiar with server hardware. Generally, smaller servers can be purchased at commodity prices, while very large servers are special order and have a cost premium associated with them.&lt;br /&gt;&lt;br /&gt;    * In many cases, your current, older SQL Server may not be upgradeable, or if it is, it may not be cost-effective to upgrade it as compared to purchasing new physical servers.&lt;br /&gt;&lt;br /&gt;    * As physical servers get larger (more CPUs), there is more and more CPU overhead generated, which in effect reduces the overall performance of the server. Each additional CPU adds a decreasing amount of additional CPU power. Two 4-CPU servers are more efficient from a CPU perspective than a single 8-CPU server.&lt;br /&gt;&lt;br /&gt;    * Some databases need to be tuned differently than other databases. If all of your databases are located on a single server, then you can't take advantage of SQL Server-wide performance tuning techniques to tune each separate database as each database will have to share all SQL Server-wide performance tuning settings.&lt;br /&gt;&lt;br /&gt;    * If the single, large server goes down, then all the databases go down. If the databases are on separate servers, then fewer databases go down.&lt;br /&gt;&lt;br /&gt;    * Most SQL Server-based applications grow over time. If each database is located on its own server, then it is easier to add incremental hardware (such as RAM) to the servers that need it. On a large server, you may find that you can't expand beyond a certain point.&lt;br /&gt;&lt;br /&gt;[6.5, 7.0, 2000, 2005]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-8324744267789779986?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/8324744267789779986/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=8324744267789779986' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/8324744267789779986'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/8324744267789779986'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/performance-tuning-sql-server-hardware.html' title='Performance Tuning SQL Server Hardware'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-6252878700187672692</id><published>2008-12-21T20:30:00.000-08:00</published><updated>2008-12-21T20:32:56.225-08:00</updated><title type='text'>Enabling vardecimal storage format</title><content type='html'>First, this feature is only available in EE and Dev SKU.&lt;br /&gt;&lt;br /&gt;Enabling vardecimal storage format on a table is a two step process as follows:&lt;br /&gt; &lt;br /&gt;First you need to enable database for Vardecimal storage format. This can be done using the stored procedure sp_db_vardecimal_storage_format. The exact command is as follows&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;exec sp_db_vardecimal_storage_format '&lt;dbname&gt;', 'ON'&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;When the above command is executed, SQL Server internally bumps the database version number but no tables are enabled for Vardecimal storage format. The database version needs to be bumped to indicate that the data in this database can potentially have a different storage format (i.e. the Vardecimal storage format). This is used to prevent attaching a Vardecimal enabled database to earlier versions of SQL Server 2005 as those versions don’t know how to interpret the new storage format. You can only enable Vardecimal storage format on user databases.&lt;br /&gt;&lt;br /&gt;To find out which database(s) is enabled for Vardecimal storage format, you can use the following command&lt;br /&gt;&lt;br /&gt;exec sp_db_vardecimal_storage_format&lt;br /&gt;&lt;br /&gt;Once you have enabled the database for Vardecimal storage format, you can now choose to enable one or more tables (based on the potential disk savings using the tool described earlier) with this new storage format as follows&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;sp_tableoption '&lt;table-name&gt;', 'vardecimal storage format', 1&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;This command, potentially an expensive one (same order as creating an index), converts all the rows in the table containing columns of type decimal/numeric to Vardecimal storage format. During this conversion, the table is locked and is not available. If the table has no clustered index, then all non-clustered indexes are rebuilt because the RIDs of the rows will change due to storage format change. However, if you have clustered index on the table, then only the non-clustered indexes containing decimal numeric column as key or included column need to be rebuilt. Note, that you cannot enable vardecimal storage format on all tables. Before enabling vardecimal storage format, SQL Server needs to make sure that we can always revert back to static storage format for decimal data and that update of decimal/numeric data always succeeds. If these conditions are not satisfied, the conversion to vardecimal storage format is denied.&lt;br /&gt;&lt;br /&gt;To disable Vardecimal storage format on the table, you can use the following command&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;sp_tableoption '&lt;table-name&gt;', 'vardecimal storage format', 0&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;SQL Server guarantees that you can always revert back to ‘static’ storage format unless you run out of disk space during conversion. Note, that the space overhead, to enable/disable Vardecimal storage format, is of the same order as building an index and it is not an online operation.&lt;br /&gt;&lt;br /&gt;You can use the following command to find out which tables(s) has been enabled for Vardecimal storage format&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;select objectproperty(object_id('&lt;table-name&gt;’), 'TableHasVarDecimalStorageFormat')&lt;br /&gt;&lt;br /&gt; or&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;select name, object_id, type_desc&lt;br /&gt;from sys.objects&lt;br /&gt;where &lt;br /&gt;objectproperty(object_id, N'TableHasVarDecimalStorageFormat') = 1&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-6252878700187672692?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/6252878700187672692/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=6252878700187672692' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6252878700187672692'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6252878700187672692'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/enabling-vardecimal-storage-format.html' title='Enabling vardecimal storage format'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-1752755600740926415</id><published>2008-12-21T20:25:00.000-08:00</published><updated>2008-12-21T20:29:42.703-08:00</updated><title type='text'>Reducing the Size of your Database in SQL Server 2005/SP2</title><content type='html'>An exciting new feature in SQL Server 2005/SP2 is Vardecimal Storage Format. This storage format lets you reduce the size of your table significantly if the table has one of more columns of type decimal or numeric without requiring any changes to your application.&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Up until now, the decimal and numeric types are stored as fixed length data in SQL Server. Both of these types are functionally equivalent and have a format of (p, s) where p is the precision (number of decimal digits) and s is the scale representing number of digits after the decimal. Depending on the precision (it can be declared in the range from 1 to 38), the decimal value can take anywhere from 5 bytes to 17 bytes. This can bloat the size of the table, especially when you have small decimal values for a column declared with high precision requirement. This issue is similar to char (17) vs. varchar(17). In this case, if most of your character data is 1 or 2 characters long but the max value is 17 characters long, you can reduce the size of the table by declaring the column to be of type varchar(17) instead of char(17).&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;The new vardecimal storage format stores the decimal/numeric values in a variable length storage format. It provides efficient storage of decimal/numeric data by eliminating the leading/trailing zeros and only storing the minimum required bytes. Using this format, you can get significant space savings (depending on your data distribution) in the space required to store decimal/numeric data. You can enable vardecimal storage format at a table level.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;In our in-house testing, we have seen significant reduction in the size of the FACT table(s) that has large number of decimal columns. FACT tables are typically the largest table in a Data Warehouse. Here are some the numbers from our testing.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Best case reduction in the size of the table&lt;br /&gt;&lt;br /&gt;57%&lt;br /&gt;&lt;br /&gt;69%&lt;br /&gt;&lt;br /&gt;51%&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Estimating the space savings with vardecimal storage format&lt;br /&gt;&lt;br /&gt;Before enabling Vardecimal storage format, you may want to know the potential reduction in the size of the table. Clearly, if the table has no decimal/numeric columns, there will be no savings. Note, that even if you have a table with decimal/numeric column types, there is no guarantee that you will be able to reduce the size of the table by enabling Vardecimal storage format. Again, this issue is similar to VARCHAR (17) vs. CHAR(17). If all the values in the column type has 17 characters, then average row length will be larger with VARCHAR(17) because it will be stored in the variable portion of the record structure. Recall, you need 2 bytes to store the offset of the variable length column. Also, if VARCAHR(17)  is the only variable length column in the table, there is another overhead of 2 bytes to store number of variable length columns in the row.  So in this case, the worst case, declaring column type as VARCAHR(17) may cost you 4 bytes more for each row than CHAR(17). &lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;SQL Server 2005/SP2 provides you a tool, a stored procedure, to estimate the ‘reduction in row size’ with Vardecimal storage format. The following example illustrates the reduction in row size for two tables that have same scheme but different data, t_decimal being the best case and t_decimal2 being the worst case (where each decimal value has max 38 digits as allowed by the declared precision)&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;create table t_decimal (c1 int, c2 decimal(10,2), c3 decimal (38,2), c4 varchar(10))&lt;br /&gt;&lt;br /&gt;go&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;create table t_decimal2 (c1 int, c2 decimal(10,2), c3 decimal (38,2), c4 varchar(10))&lt;br /&gt;&lt;br /&gt;go&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;-- insert rows into these tables.&lt;br /&gt;&lt;br /&gt;declare @i int&lt;br /&gt;&lt;br /&gt;select @i = 0&lt;br /&gt;&lt;br /&gt;while (@i &lt; 1000)&lt;br /&gt;&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;        insert into t_decimal values (1, 0.0,0.0, 'hello')&lt;br /&gt;&lt;br /&gt;        insert into t_decimal2 values&lt;br /&gt;&lt;br /&gt;                (1,12345678.99,123456789012345678901234567890123499.99, 'hello')&lt;br /&gt;&lt;br /&gt;         set @i = @i + 1&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;-- Now let us find the potential space savings for each of these tables&lt;br /&gt;&lt;br /&gt;-- This is the best case&lt;br /&gt;&lt;br /&gt;exec sys.sp_estimated_rowsize_reduction_for_vardecimal 't_decimal'&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Here is the output. Note, in this case, you can reduce the size of the row by almost 50%. Also, if you have more decimal/numeric columns, the savings will be proportionally larger.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;avg_rowlen_fixed_format  avg_rowlen_vardecimal_format    row_count&lt;br /&gt;&lt;br /&gt;--------------------------------------- --------------------------&lt;br /&gt;&lt;br /&gt;46.00                      24.00                         1000&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;-- this is worst case. Note in this case, the average row length actually increases&lt;br /&gt;&lt;br /&gt;-- with Vardecimal storage format.&lt;br /&gt;&lt;br /&gt;-- &lt;br /&gt;&lt;br /&gt;exec sys.sp_estimated_rowsize_reduction_for_vardecimal 't_decimal2'&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;avg_rowlen_fixed_format  avg_rowlen_vardecimal_format   row_count&lt;br /&gt;&lt;br /&gt;-------------------------   ---------- ----------------    ------&lt;br /&gt;46.00                              48.00                      1000&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-1752755600740926415?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/1752755600740926415/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=1752755600740926415' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/1752755600740926415'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/1752755600740926415'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/reducing-size-of-your-database-in-sql.html' title='Reducing the Size of your Database in SQL Server 2005/SP2'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-1074762644933160300</id><published>2008-12-21T20:21:00.000-08:00</published><updated>2008-12-21T20:22:26.458-08:00</updated><title type='text'>SQL Server Storage Engine -Enabling compression on a HEAP</title><content type='html'>I often get a question how to do enable compression on a table that is a heap (i.e. it does not have a clustered index). Clearly, one could create the clustered index with compression option set to PAGE and then drop the clustered index.  This is an expensive operation because&lt;br /&gt;&lt;br /&gt;·         Creating a clustered index requires a SORT&lt;br /&gt;&lt;br /&gt;·         When you drop the clustered index, internal allocation structure, namely the PFS (Page Free Space) needs to updated to reflect the free space on each page. Note, when a clustered index is dropped, the resultant heap retains the compression state.&lt;br /&gt;&lt;br /&gt;Instead, in SQL Server 2008, there is a new REBUILD command available that can be used to rebuild a HEAP. You can use this command to enable compression on the HEAP. Also, you can use this command to defragment a HEAP.  You may wonder what is there to defrag in a heap because the pages don’t need to be traversed in the key order? Well, it is possible the pages in a HEAP are not full so the defragmentation can be used to reclaim the free space. In any case, let us get back to compression. Let me start with the following example&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;create table t1_big (c1 int, c2 int, c3 char(1000))&lt;br /&gt;&lt;br /&gt;go&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;-   Load the data&lt;br /&gt;&lt;br /&gt;declare @i int&lt;br /&gt;&lt;br /&gt;select @i = 0&lt;br /&gt;&lt;br /&gt;while (@i &lt; 5000)&lt;br /&gt;&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;     insert into t1_big values (@i, @i + 5000,&lt;br /&gt;&lt;br /&gt;                              replicate('a', 500))&lt;br /&gt;&lt;br /&gt;     set @i = @i + 1&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;-   Look at the current row size&lt;br /&gt;&lt;br /&gt;-   The following query returns a length of 1015&lt;br /&gt;&lt;br /&gt;select max_record_size_in_bytes&lt;br /&gt;&lt;br /&gt;from sys.dm_db_index_physical_stats (db_id('compression'),&lt;br /&gt;&lt;br /&gt;                   object_id('compression.t1_big'),&lt;br /&gt;&lt;br /&gt;                   null, null, 'DETAILED')&lt;br /&gt;&lt;br /&gt;where object_name (object_id) like '%t1_big%'&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;-- Now, you can use the following NEW command to enable&lt;br /&gt;&lt;br /&gt;-- PAGE compression. You could have used this command to&lt;br /&gt;&lt;br /&gt;-- enable ROW compression or even NONE compression. As&lt;br /&gt;&lt;br /&gt;-- part of rebuilidng the HEAP, it is also defragmented.&lt;br /&gt;&lt;br /&gt;-- This command can also be executed ONLINE&lt;br /&gt;&lt;br /&gt;alter table t1_big rebuild &lt;br /&gt;&lt;br /&gt; with (&lt;br /&gt;&lt;br /&gt;    data_compression = PAGE)&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;-- compression setting shows the PAGE compression&lt;br /&gt;&lt;br /&gt;select object_name (object_id) as table_name, data_compression_desc&lt;br /&gt;&lt;br /&gt;from sys.partitions&lt;br /&gt;&lt;br /&gt;where object_name (object_id) like '%t1_big%'&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;-- check the length again and it returns a value 9&lt;br /&gt;&lt;br /&gt;-- Note, the example I have used here is not realistic so it&lt;br /&gt;&lt;br /&gt;-- show almost 99% compression but you get the idea.&lt;br /&gt;&lt;br /&gt;select max_record_size_in_bytes&lt;br /&gt;&lt;br /&gt;from sys.dm_db_index_physical_stats (db_id('compression'),&lt;br /&gt;&lt;br /&gt;                   object_id('compression.t1_big'),&lt;br /&gt;&lt;br /&gt;                   null, null, 'DETAILED')&lt;br /&gt;&lt;br /&gt;where object_name (object_id) like '%t1_big%'&lt;br /&gt;&lt;br /&gt;There are few restrictions on ALTER TABLE REBUILD command as follows&lt;br /&gt;&lt;br /&gt;(1)    If you use ONLINE option then HEAP rebuild is single threaded. Note, this restriction is not there when you are rebuilding an index which supports multi-threaded ONLINE build.  However, in both cases, OFFLINE build does support multi-threading.&lt;br /&gt;&lt;br /&gt;(2)    When you rebuild a HEAP and specify compression option, the corresponding non clustered indexes are also rebuilt because RIDs will change but the compression state of the indexes will not change. If you want to alter compression option of existing nonclustered indexes, you will need to execute ‘Alter Index’ command on each such indexes. So effectively, you will need to rebuild the nonclustered index twice if you want to change the compression setting both for the HEAP and its associated nonclustered indexes. Here is the rationale for this&lt;br /&gt;&lt;br /&gt;a.       Most index rebuild options are not applicable to HEAP. For this reason, we did not add ‘ALL’ keyword like the one with Alter Index command.&lt;br /&gt;&lt;br /&gt;b.      Since indexes are typically much smaller compare to the table, we think most customers will not want to change compression state on indexes automatically as part of rebuilding the HEAP or clustered index for that matter.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-1074762644933160300?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/1074762644933160300/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=1074762644933160300' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/1074762644933160300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/1074762644933160300'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/sql-server-storage-engine-enabling.html' title='SQL Server Storage Engine -Enabling compression on a HEAP'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-206319009158043447</id><published>2008-12-21T20:02:00.000-08:00</published><updated>2008-12-21T20:04:12.970-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><title type='text'>How to track database growth across multiple SQL Server instances</title><content type='html'>It is easy to track database growth on a single SQL Server instance.  We simply just need to store the results of sp_databases or loop through the databases and call sp_spaceused for each database.&lt;br /&gt;&lt;br /&gt;If you support hundreds of SQL instances like I do, you'd want to store the database growth information in a central repository.  From this central server, you could create a linked server for each SQL Server instance to track, but I hate creating linked servers.  I especially hate having to create hundreds of them on one SQL Server instance.  Instead of using linked servers, I created a CLR stored procedure.  It requires one table.&lt;br /&gt;&lt;br /&gt;You can download the code here.  It includes the C# source code as well as the dll for the CLR object and a sample SQL script file to get it setup on your central server.&lt;br /&gt;&lt;br /&gt;Once you have set it up, you can create a SQL job to call it.  If you have a small number of SQL instances to administer, you can simply add multiple calls to isp_DatabaseGrowth, like this:&lt;br /&gt;&lt;br /&gt;EXEC dbo.isp_DatabaseGrowth 'Server1\Instance1'&lt;br /&gt;&lt;br /&gt;EXEC dbo.isp_DatabaseGrowth 'Server2'&lt;br /&gt;&lt;br /&gt;If you have a large number of SQL instances to administer, I recommend looping through a table that contains one row for every SQL instance.  Here is what my job step looks like:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;DECLARE @serverId int, @serverName sysname, @max int &lt;br /&gt;&lt;br /&gt;SET @serverId = 1 &lt;br /&gt;&lt;br /&gt;SELECT IDENTITY(int, 1, 1) AS ServerId, ServerName&lt;br /&gt;INTO #Server&lt;br /&gt;FROM dbo.Server&lt;br /&gt;WHERE ServerName NOT IN ('Server1\Instance2', 'Server1\Instance3', 'Server3') --exclude certain SQL instances&lt;br /&gt;&lt;br /&gt;SELECT @max = MAX(ServerId)&lt;br /&gt;FROM #Server &lt;br /&gt;&lt;br /&gt;WHILE @serverId &lt;= @max&lt;br /&gt;BEGIN&lt;br /&gt;    SELECT @serverId = ServerId, @serverName = ServerName&lt;br /&gt;    FROM #Server&lt;br /&gt;    WHERE ServerId = @serverId &lt;br /&gt;&lt;br /&gt;    EXEC dbo.isp_DatabaseGrowth @serverName &lt;br /&gt;&lt;br /&gt;    SET @serverId = @serverId + 1&lt;br /&gt;END &lt;br /&gt;&lt;br /&gt;DROP TABLE #Server&lt;br /&gt;&lt;br /&gt;Here's the DDL for the Server table:&lt;br /&gt;&lt;br /&gt;CREATE TABLE [dbo].[Server]&lt;br /&gt;(&lt;br /&gt;    [ServerName] [sysname] NOT NULL,&lt;br /&gt;    CONSTRAINT [PK_Server] PRIMARY KEY CLUSTERED &lt;br /&gt;    (&lt;br /&gt;        [ServerName] ASC&lt;br /&gt;    )&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If any of your databases were upgraded to SQL Server 2005, the data returned from sp_spaceused/sp_databases may contain incorrect data due to row count inaccuracies in the catalog views.  Make sure to run DBCC UPDATEUSAGE on your databases after an upgrade to SQL Server 2005.  Databases that were created in SQL Server 2005 do not have this issue.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-206319009158043447?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/206319009158043447/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=206319009158043447' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/206319009158043447'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/206319009158043447'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/how-to-track-database-growth-across.html' title='How to track database growth across multiple SQL Server instances'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-814377657368477982</id><published>2008-12-21T19:58:00.000-08:00</published><updated>2008-12-21T19:59:07.905-08:00</updated><title type='text'>Link Servers</title><content type='html'>When you create a link between two SQL Servers, SQL Server does its best to perform as much work as it can on the remote server. This way, less data has to be moved from the remote server to the local server, helping to reduce overhead and boosting performance. But for some particular operations, they have to be performed on the local server, not the remote server. Some examples of locally performed operations include:&lt;br /&gt;&lt;br /&gt;    * Data conversion operations&lt;br /&gt;    * Queries that use the bit, timestamp, or uniqueidentifier data types&lt;br /&gt;    * Queries that use the TOP clause&lt;br /&gt;    * INSERTS, UPDATES, or DELETES&lt;br /&gt;&lt;br /&gt;Because of this, you may want to try to avoid performing any of the above operations using a remote linked server.&lt;br /&gt;&lt;br /&gt;If you are running a remote query against a linked server, and you want to find out which parts are performing on the remote server and which are performing on the local server, run the query from Query Analyzer or Management Studio and take a look at the query plan. It will tell you what part of your query is running where. It should be your goal to create code that runs mostly on the remote server, not the local server. [7.0, 2000, 2005]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-814377657368477982?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/814377657368477982/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=814377657368477982' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/814377657368477982'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/814377657368477982'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/link-servers.html' title='Link Servers'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-5828227721389102119</id><published>2008-12-18T19:53:00.000-08:00</published><updated>2008-12-28T21:15:32.903-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='Indexes'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>Optimizing SQL Server Non-Clustered Indexes</title><content type='html'>In some cases, even though a column (or columns of a composite index) has a non-clustered index, the Query Optimizer may not use it (even though it should), instead performing a table scan (if the table is a heap) or a clustered index scan (if there is a clustered index). This, of course, can produce unwanted performance problems.&lt;br /&gt;&lt;br /&gt;This particular problem can occur when there is a data correlation between the order of the rows in the table, and the order of the non-clustered index entries. This can occur when there is correlation between the clustered index and the non-clustered index. For example, the clustered index may be created on a date column, and the non-clustered index might be created on an invoice number column. If this is the case, then there is a correlation (or direct relationship) between the increasing dates and the increasing invoice numbers found in each row.&lt;br /&gt;&lt;br /&gt;The reason this problem occurs is because the Query Optimizer assumes there is no correlation, and it makes its optimization decisions based on this assumption.&lt;br /&gt;&lt;br /&gt;If you run into this problem, there are three potential resolutions to this problem:&lt;br /&gt;&lt;br /&gt;    * If possible, reorder the non-clustered index column (assuming a composite index) so that the column with the highest cardinality is the first column in the composite index.&lt;br /&gt;    * Create covering indexes.&lt;br /&gt;    * Add index hints to your queries to overrule the Query Optimizer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-5828227721389102119?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/5828227721389102119/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=5828227721389102119' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5828227721389102119'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5828227721389102119'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/optimizing-sql-server-non-clustered.html' title='Optimizing SQL Server Non-Clustered Indexes'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-8738986900305114688</id><published>2008-12-18T03:09:00.000-08:00</published><updated>2008-12-18T03:11:22.957-08:00</updated><title type='text'>Tips for building a Work Breakdown Structure</title><content type='html'>A Work Breakdown Structure (WBS) is the best way to understand the detailed work of the project when you have to build a schedule from scratch. It’s used to break the project down into the major phases, deliverables, and work components that will be built by the project. These work components can then be broken down into the activities that are required to build them. The WBS is not the same as the final schedule (which requires sequencing, resources, estimated effort, estimated duration, etc.).&lt;br /&gt;&lt;br /&gt;Here are five tips to keep in mind when building your WBS:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#1: Create a WBS dictionary for large projects&lt;br /&gt;&lt;/span&gt;Normally you wouldn’t need a WBS dictionary, but if your WBS has hundreds (or thousands) of detailed activities, there may just be too much to keep track of by hand. In this case, it might make sense to place all of the important information in a WBS dictionary. The dictionary helps keep track of all of the summary and detailed activities, including a short description, the WBS numeric identifier (1.1, 1.1.1, 1.1.2, etc.) and the estimated effort. If you enter your WBS dictionary into a specialized tool, the tool can also help to keep track of changes to the WBS as well.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#2: Use the summary activities as milestones&lt;/span&gt;&lt;br /&gt;Your WBS should contain both detailed and summary activities. (A summary activity is one that is broken down further; a detailed activity is one that is not broken down further.) Although a schedule usually includes only detailed activities, it makes sense to include the summary activities as milestones (i.e., markers signifying that a deliverable or set of deliverables is complete). A summary activity can be used as a milestone since it would indicate that all of the underlying detailed work has been completed.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#3: Break activities into two or more detailed activities&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;I’ve seen teams that break one activity in the WBS into only one activity at the next level. In my opinion, this doesn’t make sense because then the detailed activity represents the same work as the prior summary activity. This doesn’t buy you anything.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#4: Make the final detailed activities action oriented&lt;/span&gt;&lt;br /&gt;The detailed activities on your WBS (the ones that are not broken down further) are ultimately moved to your schedule. For that reason, it’s easier if the detailed activities in your WBS are action oriented — just as activities in your schedule would be. For example, instead of describing a detailed WBS activity as “meeting,” you should state it as “schedule a weekly meeting.” Instead of having a WBS detailed activity for “Testing Plan,” you should state it instead as “Create Testing Plan.” In this way, the detailed activities can be moved to the schedule with a minimum of wording changes.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#5: Don’t place requirements on the WBS&lt;br /&gt;&lt;/span&gt;If you place a deliverable on your WBS, you can break this deliverable down into the activities that are required to create it. You don’t break a deliverable down into the requirements that describe it. Requirements do not belong on a WBS. Only deliverables and activities belong on the WBS.&lt;br /&gt;&lt;br /&gt;By using these five techniques, you will save you time and rework on your next WBS.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-8738986900305114688?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/8738986900305114688/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=8738986900305114688' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/8738986900305114688'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/8738986900305114688'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/tips-for-building-work-breakdown.html' title='Tips for building a Work Breakdown Structure'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-3848060268791873814</id><published>2008-12-17T02:44:00.000-08:00</published><updated>2008-12-17T02:51:46.048-08:00</updated><title type='text'>The industry’s 10 best IT certifications</title><content type='html'>IT certifications boast numerous benefits. They bolster resumes, encourage higher salaries, and assist in job retention. But which IT certifications are best?&lt;br /&gt;&lt;br /&gt;Technology professionals generate much debate over just that question. Many claim vendor-specific programs best measure a candidate’s skills, while others propose vendor-independent exams are the only worthy way of measuring real-world expertise. Still other observers believe the highest-level accreditations — Microsoft’s MCSE or new Architect Series certification, Cisco’s CCIE, etc. — are the only credentials that truly hold value.&lt;br /&gt;&lt;br /&gt;Myself, I don’t fully subscribe to any of those mindsets. The best IT certification for you, after all, is likely to be different from that for another technology professional with different education, skills, and goals working at a different company in a different industry. For that reason, when pursuing any professional accreditation, you should give much thought and care to your education, experience, skills, goals, and desired career path.&lt;br /&gt;&lt;br /&gt;Once a career road map is in place, selecting a potential certification path becomes much easier. And that’s where this list of the industry’s 10 best IT certifications comes into play. While this list may not include the 10 best accreditations for you, it does catalog 10 IT certifications that possess significant value for a wide range of technology professionals.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#1: MCITP&lt;/span&gt;&lt;br /&gt;The new-generation Microsoft Certified IT Professional credential, or MCITP for short, is likely to become the next big Microsoft certification. Available for a variety of fields of expertise — including database developer, database administrator, enterprise messaging administrator, and server administrator — an MCITP validates a professional’s proven job-role capabilities. Candidates must pass several Microsoft exams that track directly to their job role before earning the new designation.&lt;br /&gt;&lt;br /&gt;As with Microsoft’s other new-generation accreditations, the MCITP certification will retire when Microsoft suspends mainstream support for the platforms targeted within the MCITP exams. By matching the new certification to popular job roles, as has been done to some extent with CompTIA’s Server+ (server administrator), Project+ (project manager), and A+ (desktop support) certifications, Microsoft has created a new certification that’s certain to prove timely, relevant, and valuable.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#2: MCTS&lt;/span&gt;&lt;br /&gt;The new-generation Microsoft Certified Technology Specialist (MCTS) helps IT staff validate skills in installing, maintaining, and troubleshooting a specific Microsoft technology. The MCTS certifications are designed to communicate the skills and expertise a holder possesses on a specific platform.&lt;br /&gt;&lt;br /&gt;For example, candidates won’t earn an MCTS on SQL Server 2008. Instead, they’ll earn an MCTS covering SQL Server business intelligence (MCTS: SQL Server 2008 Business Intelligence), database creation (MCTS: SQL Server 2008, Database Development), or SQL server administration (MCTS: SQL Server 2008, Implementation and Maintenance).&lt;br /&gt;&lt;br /&gt;These new certifications require passing multiple, tightly targeted exams that focus on specific responsibilities on specific platforms. MCTS designations will expire when Microsoft suspends mainstream support for the corresponding platform. These changes, as with other new-generation Microsoft certifications, add value to the accreditation.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#3: Security+&lt;/span&gt;&lt;br /&gt;Security continues to be a critical topic. That’s not going to change. In fact, its importance is only going to grow. One of the quickest ways to lose shareholder value, client confidence, and sales is to suffer a data breach. And no self-respecting technology professional wants to be responsible for such a breach.&lt;br /&gt;&lt;br /&gt;CompTIA’s Security+ accreditation provides a respected, vendor-neutral foundation for industry staff (with at least two years of experience) seeking to demonstrate proficiency with security fundamentals. While the Security+ accreditation consists of just a single exam, it could be argued that any IT employee charged with managing client data or other sensitive information should, at a minimum, possess this accreditation. The importance of ensuring staff are properly educated as to systems security, network infrastructure, access control, auditing, and organizational security principles is simply too important to take for granted.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#4: MCPD&lt;/span&gt;&lt;br /&gt;There’s more to information technology than just administration, support, and networking. Someone must create and maintain the applications and programs that power organizations. That’s where the new-generation Microsoft Certified Professional Developer (MCPD) credential comes into play.&lt;br /&gt;&lt;br /&gt;The MCPD accreditation measures a developer’s ability to build and maintain software solutions using Visual Studio 2008 and Microsoft .NET Framework 3.5. Split into three certification paths (Windows Developer 3.5, ASP.NET Developer 3.5, and Enterprise Applications Developer 3.5), the credential targets IT professionals tasked with designing, optimizing, and operating those Microsoft technologies to fulfill business needs.&lt;br /&gt;&lt;br /&gt;A redesigned certification aimed at better-measuring real-world skills and expertise, the MCPD will prove important for developers and programmers. Besides requiring candidates to pass several exams, the MCPD certification will retire when Microsoft suspends mainstream support for the corresponding platform. The change is designed to ensure the MCPD certification remains relevant, which is certain to further increase its value.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#5: CCNA&lt;/span&gt;&lt;br /&gt;The Cisco Certified Internetwork Expert (CCIE) accreditation captures most of the networking company’s certification glory. But the Cisco Certified Network Associate (CCNA) might prove more realistic within many organizations.&lt;br /&gt;&lt;br /&gt;In a world in which Microsoft and Linux administrators are also often expected to be networking experts, many companies don’t have the budgets necessary to train (or employ) a CCIE. But even small and midsize corporations can benefit from having their technology professionals earn basic proficiency administering Cisco equipment, as demonstrated by earning a CCNA accreditation.&lt;br /&gt;&lt;br /&gt;As smaller companies become increasingly dependent upon remote access technologies, basic Cisco systems skills are bound to become more important. Although many smaller organizations will never have the complexity or workload necessary to keep a CCIE busy, Cisco’s CCNA is a strong accreditation for technology professionals with a few years’ experience seeking to grow and improve their networking skills.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#6: A+&lt;/span&gt;&lt;br /&gt;Technology professionals with solid hardware and support skills are becoming tougher to find. There’s not much glory in digging elbow-deep into a desktop box or troubleshooting Windows boot errors. But those skills are essential to keeping companies running.&lt;br /&gt;&lt;br /&gt;Adding CompTIA’s A+ certification to a resume tells hiring managers and department heads that you have proven support expertise. Whether an organization requires desktop installation, problem diagnosis, preventive maintenance, or computer or network error troubleshooting, many organizations have found A+-certified technicians to be more productive than their noncertified counterparts.&lt;br /&gt;&lt;br /&gt;Changes to the A+ certification, which requires passing multiple exams, are aimed at keeping the popular credential relevant. Basic prerequisite requirements are now followed by testing that covers specific fields of expertise (such as IT, remote support, or depot technician). The accreditation is aimed at those working in desktop support, on help desks, and in the field, and while many of these staffers are new to the industry, the importance of an A+ certification should not be overlooked.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#7: PMP&lt;/span&gt;&lt;br /&gt;Some accreditations gain value by targeting specific skills and expertise. The Project Management Professional (PMP) certification is a great example.&lt;br /&gt;&lt;br /&gt;The Project Management Institute (PMI), a nonprofit organization that serves as a leading membership association for project management practitioners, maintains the PMP exam. The certification measures a candidate’s project management expertise by validating skills and knowledge required to plan, execute, budget, and lead a technology project. Eligible candidates must have five years of project management experience or three years of project management experience and 35 hours of related education.&lt;br /&gt;&lt;br /&gt;As organizations battle tough economic conditions, having proven project scheduling, budgeting, and management skills will only grow in importance. The PMI’s PMP credential is a perfect conduit for demonstrating that expertise on a resume.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#8: MCSE/MCSA&lt;/span&gt;&lt;br /&gt;Even years after their introduction, Microsoft Certified Systems Engineer (MCSE) and Microsoft Certified Systems Administrator (MCSA) credentials remain valuable. But it’s important to avoid interpreting these accreditations as meaning the holders are all-knowing gurus, as that’s usually untrue.&lt;br /&gt;&lt;br /&gt;In my mind, the MCSE and MCSA hold value because they demonstrate the holder’s capacity to complete a long and comprehensive education, training, and certification program requiring intensive study. Further, these certifications validate a wide range of relevant expertise (from client and server administration to security issues) on specific, widely used platforms.&lt;br /&gt;&lt;br /&gt;Also important is the fact that these certifications tend to indicate holders have been working within the technology field for a long time. There’s no substitute for actual hands-on experience. Many MCSEs and MCSAs hold their certifications on Windows 2000 or Windows Server 2003 platforms, meaning they’ve been working within the industry for many years. While these certifications will be replaced by Microsoft’s new-generation credentials, they remain an important measure of foundational skills on Windows platforms.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#9: CISSP&lt;/span&gt;&lt;br /&gt;As mentioned with the Security+ accreditation earlier, security is only going to grow in importance. Whatever an organization’s mission, product, or service, security is paramount.&lt;br /&gt;&lt;br /&gt;(ISC)², which administers the Certified Information Systems Security Professional (CISSP) accreditation, has done well building a respected, vendor-neutral security certification. Designed for industry pros with at least five years of full-time experience, and accredited by the American National Standards Institute (ANSI), the CISSP is internationally recognized for validating a candidate’s expertise with operations and network and physical security, as well as their ability to manage risk and understand legal compliance responsibilities and other security-related elements.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#10: Linux+&lt;/span&gt;&lt;br /&gt;While pursuing my first Microsoft certification 10 years ago, I remember debating the importance of Linux with several telecommunications technicians. They mocked the investment I was making in learning Microsoft technologies. These techs were confident Linux was going to displace Windows.&lt;br /&gt;&lt;br /&gt;Well, didn’t happen. Linux continues to make inroads, though. The open source alternative is an important platform. Those professionals who have Linux expertise and want to formalize that skill set will do well adding CompTIA’s Linux+ certification to their resumes.&lt;br /&gt;&lt;br /&gt;The vendor-neutral exam, which validates basic Linux client and server skills, is designed for professionals with at least six to 12 months of hands-on Linux experience. In addition to being vendor-neutral, the exam is also distribution neutral (meaning the skills it covers work well whether a candidate is administering Red Hat, SUSE, or Ubuntu systems).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-3848060268791873814?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/3848060268791873814/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=3848060268791873814' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3848060268791873814'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3848060268791873814'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/industrys-10-best-it-certifications.html' title='The industry’s 10 best IT certifications'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-7649425102580987860</id><published>2008-12-16T02:01:00.000-08:00</published><updated>2008-12-16T02:05:06.004-08:00</updated><title type='text'>10 services to turn off in MS Windows XP</title><content type='html'>As long as Microsoft Windows has been a network capable operating system, it has come with quite a few services turned on by default, and it is a good idea for the security conscious user of Microsoft’s flagship product to shut down any of these that he or she isn’t using.&lt;br /&gt;&lt;br /&gt;Each version of MS Windows provides different services, of course, so any list of services to disable for security purposes will be at least somewhat particular to a given version of Microsoft Windows. As such, a list like this one needs to be identified with a specific Microsoft Windows version, though it can still serve as a guide for the knowledgeable MS Windows user to check out the running services on other versions as well.&lt;br /&gt;&lt;br /&gt;If you are running Microsoft Windows XP on your desktop system, consider turning off the following services. You may be surprised by what is running without your knowledge.&lt;br /&gt;&lt;br /&gt;    * &lt;span style="font-weight:bold;"&gt;IIS&lt;/span&gt; – Microsoft’s Internet Information Services provide the capabilities of a Webserver for your computer.&lt;br /&gt;&lt;br /&gt;    *&lt;span style="font-weight:bold;"&gt; NetMeeting Remote Desktop Sharing&lt;/span&gt; — NetMeeting is primarily a VoIP and videoconferencing client for Microsoft Windows, but this service in particular is necessary to remote desktop access.&lt;br /&gt;&lt;br /&gt;    * &lt;span style="font-weight:bold;"&gt;Remote Desktop Help Session Manager&lt;/span&gt; – This service is used by the Remote Assistance feature that you can use to allow others remote access to the system to help you troubleshoot problems.&lt;br /&gt;&lt;br /&gt;    *&lt;span style="font-weight:bold;"&gt; Remote Registry &lt;/span&gt;– The capabilities provided by the Remote Registry service are frightening to consider from a security perspective. They allow remote users (in theory, only under controlled &lt;br /&gt;circumstances) to edit the Windows Registry.&lt;br /&gt;&lt;br /&gt;    * &lt;span style="font-weight:bold;"&gt;Routing and Remote Access&lt;/span&gt; – This service bundles a number of capabilities together, capabilities that most system administrators would probably agree should be provided separately. It is rare that any of them should be necessary for a typical desktop system such as Microsoft Windows XP, however, so they can all conveniently be turned off as a single service. Routing and Remote Access provides the ability to use the system as a router and NAT device, as a dialup access gateway, and a VPN server.&lt;br /&gt;&lt;br /&gt;    * &lt;span style="font-weight:bold;"&gt;Simple File Sharing&lt;/span&gt; – When a computer is not a part of a Microsoft Windows Domain, it is assumed by the default settings that any and all filesystem shares are meant to be universally accessible. In the real world, however, we should only want to provide shares to very specific, authorized users. As such, Simple File Sharing, which only provides blanket access to shares without exceptions, is not what we want to use for sharing filesystem resources. It is active by default on both MS Windows XP Professional and MS Windows XP Home editions. Unfortunately, this cannot be disabled on MS Windows XP Home. On MS Windows XP Professional, however, you can disable it by opening My Computer -&gt; Tools -&gt; Folder Options, clicking the View tab, and unchecking the Use simple file sharing (Recommended) checkbox in the Advanced settings: pane.&lt;br /&gt;&lt;br /&gt;    * &lt;span style="font-weight:bold;"&gt;SSDP Discovery Service&lt;/span&gt; – This service is used to discover UPnP devices on your network, and is required for the Universal Plug and Play Device Host service (see below) to operate.&lt;br /&gt;&lt;br /&gt;    * &lt;span style="font-weight:bold;"&gt;Telnet&lt;/span&gt; – The Telnet service is a very old mechanism for providing remote access to a computer, most commonly known from its use in the bad ol’ days of security for remote command shell access on Unix servers. These days, using Telnet to remotely manage a Unix system may be grounds for firing, where an encrypted protocol such as SSH should be used instead.&lt;br /&gt;&lt;br /&gt;    * &lt;span style="font-weight:bold;"&gt;Universal Plug and Play Device Host&lt;/span&gt; – Once you have your “Plug and Play” devices installed on your system, it is often the case that you will not need this service again.&lt;br /&gt;&lt;br /&gt;    * &lt;span style="font-weight:bold;"&gt;Windows Messenger Service&lt;/span&gt; – Listed in the Services window under the name Messenger, the Windows Messenger Service provides “net send” and “Alerter” functionality. It is unrelated to the Windows Messenger instant messaging client, and is not necessary to use the Windows Messenger IM network.&lt;br /&gt;&lt;br /&gt;On your system, these services may not all be turned on, or even installed. Whether a given service is installed and running may depend on whether you installed the system yourself, whether you are using XP Home or XP Professional, and from which vendor you got your computer if MS Windows XP was installed by a vendor.&lt;br /&gt;&lt;br /&gt;With the exception of Simple File Sharing, all of the above listed services can be disabled from the same place. Simply click on the Start button, then navigate to Settings -&gt; Control Panel, open Administrative Tools, and from there open the Services window. To disable any service in the list, double-click on its entry in that window and change the Startup type: setting. In general, you should change services you are turning off for security purposes to a “Disabled” state. When in doubt about whether a given service is necessary for other services, check the Dependencies tab in the service’s settings dialog.&lt;br /&gt;&lt;br /&gt;Obviously, this is not a comprehensive list of everything running on your computer that you may want to turn off. It is merely a list of ten items that you most likely do not need to have running, and constitute a security vulnerability if left running. Most users will never have need of any of the services in this list, once the computer is up and running. Other services may be disabled without ill effect as well, though you should research each item in the complete services list before you disable it to ensure that you actually do not need it running. Some of them are quite critical to the normal operation of your system, such as the Remote Procedure Call (RPC) service.&lt;br /&gt;&lt;br /&gt;Every running — but unused — service on your machine is an unnecessary security vulnerability. If a service is not important at all for authorized users and basic system functionality, turn it off.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-7649425102580987860?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/7649425102580987860/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=7649425102580987860' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/7649425102580987860'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/7649425102580987860'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/10-services-to-turn-off-in-ms-windows.html' title='10 services to turn off in MS Windows XP'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-5937458479636865313</id><published>2008-12-15T20:19:00.001-08:00</published><updated>2008-12-15T20:19:54.078-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>Performance Tuning for Views</title><content type='html'>While views are often convenient to use, especially for restricting users from seeing data they should not see, they aren't always good for performance. So if database performance is your goal, avoid using views (SQL Server 2000/2005 Indexed Views are another story).&lt;br /&gt;&lt;br /&gt;Views can slow down queries for several different reasons. For example, let's look at these two SELECT statements:&lt;br /&gt;&lt;br /&gt;    * SELECT * FROM table_name&lt;br /&gt;    * SELECT * FROM view_name&lt;br /&gt;&lt;br /&gt;Which is faster? If you test it, you will find that the first SELECT statement is faster, although the execution plan for both of them will be the same. How can that be? This is because it takes SQL Server extra work (such as looking up data in the system tables) before it can execute the view. This extra work is not part of the execution plan, so it appears that the two SELECT statements should run at the same speed, which they don't, because some of the work SQL Server is doing is hidden.&lt;br /&gt;&lt;br /&gt;Another way views can hurt performance is when JOINs or UNIONs are used, and you don't intend to use all of the columns. This results in SQL Server performing unnecessary work (such as an unnecessary JOIN or UNION), slowing down the performance.&lt;br /&gt;&lt;br /&gt;Views, like stored procedures, once they are run the first time, are optimized and their execution plan is stored in cache in case they need to be reused. But this is not reason enough to use a view.&lt;br /&gt;&lt;br /&gt;Views, besides hurting performance, are not all that flexible when you are working with them. For example, they can't be changed on the fly, they can’t be used to sort data, and using them for INSERTs, UPDATEs, and DELETEs is problematic. In addition, while views can be nested, this just compounds their problems, so avoid doing this.&lt;br /&gt;&lt;br /&gt;Instead of using views, use stored procedures instead. They are much more flexible and they offer better performance. [7.0, 2000, 2005]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-5937458479636865313?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/5937458479636865313/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=5937458479636865313' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5937458479636865313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5937458479636865313'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/performance-tuning-for-views.html' title='Performance Tuning for Views'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-7556874662124480924</id><published>2008-12-15T03:46:00.000-08:00</published><updated>2008-12-15T03:47:16.203-08:00</updated><title type='text'>Microsoft Internet Explorer Multiple Vulnerabilities</title><content type='html'>Some vulnerabilities have been reported in Microsoft Internet Explorer, which can be exploited by malicious people to compromise a user's system.&lt;br /&gt;&lt;br /&gt;1) An error when handling parameters passed to unspecified navigation methods can be exploited to corrupt memory via a specially crafted web page.&lt;br /&gt;&lt;br /&gt;2) An error when fetching a file with an overly long path from a WebDAV share can be exploited to corrupt heap memory via a specially crafted web page.&lt;br /&gt;&lt;br /&gt;3) An unspecified use-after-free error can be exploited to corrupt memory via a specially crafted web page.&lt;br /&gt;&lt;br /&gt;4) A boundary error when processing an overly long filename extension specified inside an "EMBED" tag can be exploited to cause a stack-based buffer overflow.&lt;br /&gt;&lt;br /&gt;Successful exploitation of the vulnerabilities may allow execution of arbitrary code.&lt;br /&gt;&lt;br /&gt;Patches are available for these critical issues.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-7556874662124480924?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/7556874662124480924/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=7556874662124480924' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/7556874662124480924'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/7556874662124480924'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/microsoft-internet-explorer-multiple.html' title='Microsoft Internet Explorer Multiple Vulnerabilities'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-6638258617898077373</id><published>2008-12-15T03:44:00.000-08:00</published><updated>2008-12-15T03:45:18.120-08:00</updated><title type='text'>Microsoft Excel Multiple Vulnerabilities</title><content type='html'>Some vulnerabilities have been reported in Microsoft Excel, which can be exploited by malicious people to compromise a user's system.&lt;br /&gt;&lt;br /&gt;1) An error while validating an index value in a NAME record can be exploited to corrupt memory via a specially crafted Excel Spreadsheet (XLS) file.&lt;br /&gt;&lt;br /&gt;2) An unspecified error in the processing of Excel records can be exploited to corrupt memory via a specially crafted XLS file.&lt;br /&gt;&lt;br /&gt;3) An unspecified error in the processing of Excel formulas can be exploited to corrupt memory via a specially crafted XLS file.&lt;br /&gt;&lt;br /&gt;Successful exploitation of the vulnerabilities may allow execution of arbitrary code.&lt;br /&gt;&lt;br /&gt;Patches are available for these critical issues.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-6638258617898077373?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/6638258617898077373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=6638258617898077373' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6638258617898077373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6638258617898077373'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/microsoft-excel-multiple.html' title='Microsoft Excel Multiple Vulnerabilities'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-3415950380736779520</id><published>2008-12-15T03:41:00.000-08:00</published><updated>2008-12-15T03:43:17.678-08:00</updated><title type='text'>Microsoft Office Word Multiple Vulnerabilities</title><content type='html'>Multiple vulnerabilities have been reported in Microsoft Office Word, which can be exploited by malicious people to compromise a user's system.&lt;br /&gt;&lt;br /&gt;1) An error when processing the "lcbPlcfBkfSdt" field within the FIB (File Information Block) can be exploited to corrupt memory via a specially crafted Word file.&lt;br /&gt;&lt;br /&gt;2) An integer overflow error exists when calculating the space required for the specified number of points in a polyline or polygon. This can be exploited to cause a heap-based buffer overflow during parsing of objects in Rich Text Format (.rtf) files e.g. when a user opens a specially crafted .rtf file with Word or previews a specially crafted e-mail.&lt;br /&gt;&lt;br /&gt;3) An unspecified error when parsing certain records can be exploited to corrupt memory via a specially crafted Word file.&lt;br /&gt;&lt;br /&gt;4) An error exists when processing consecutive "\do" drawing object tags encountered in RTF documents. This can be exploited to free a heap buffer twice and corrupt memory.&lt;br /&gt;&lt;br /&gt;5) An error when processing mismatched "\dpgroup" and "\dpendgroup" controlwords can be exploited to cause a buffer overflow via an RTF document containing an overly large number of "\dpendgroup" tags.&lt;br /&gt;&lt;br /&gt;6) A boundary error when parsing RTF documents containing multiple drawing object tags can be exploited to cause a heap-based buffer overflow.&lt;br /&gt;&lt;br /&gt;7) A boundary error when processing RTF documents can be exploited to overflow a static buffer via a document containing an overly large number of "\stylesheet" control words.&lt;br /&gt;&lt;br /&gt;8) An error when processing a malformed table property can be exploited to cause a stack-based buffer overflow via a specially crafted Word document.&lt;br /&gt;&lt;br /&gt;Successful exploitation of the vulnerabilities may allow execution of arbitrary code.&lt;br /&gt;Patches are available for these critical issues.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-3415950380736779520?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/3415950380736779520/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=3415950380736779520' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3415950380736779520'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3415950380736779520'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/microsoft-office-word-multiple.html' title='Microsoft Office Word Multiple Vulnerabilities'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-3719928834889138196</id><published>2008-12-09T19:46:00.001-08:00</published><updated>2008-12-09T19:48:35.761-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><title type='text'>2008 Index Fragmentation Maintenance</title><content type='html'>Nothing to it. Run it and it hits every database on the system. You can put it inside a stored procedure or inside a SQL Agent Job.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;DECLARE @DBName NVARCHAR(255)&lt;br /&gt;,@TableName NVARCHAR(255)&lt;br /&gt;,@SchemaName NVARCHAR(255)&lt;br /&gt;,@IndexName NVARCHAR(255)&lt;br /&gt;,@PctFrag DECIMAL&lt;br /&gt;&lt;br /&gt;DECLARE @Defrag NVARCHAR(MAX)&lt;br /&gt;&lt;br /&gt;CREATE TABLE #Frag&lt;br /&gt;(DBName NVARCHAR(255)&lt;br /&gt;,TableName NVARCHAR(255)&lt;br /&gt;,SchemaName NVARCHAR(255)&lt;br /&gt;,IndexName NVARCHAR(255)&lt;br /&gt;,AvgFragment DECIMAL)&lt;br /&gt;&lt;br /&gt;EXEC sp_msforeachdb 'INSERT INTO #Frag (&lt;br /&gt;DBName,&lt;br /&gt;TableName,&lt;br /&gt;SchemaName,&lt;br /&gt;IndexName,&lt;br /&gt;AvgFragment&lt;br /&gt;) SELECT ''?'' AS DBName&lt;br /&gt; ,t.Name AS TableName&lt;br /&gt; ,sc.Name AS SchemaName&lt;br /&gt; ,i.name AS IndexName&lt;br /&gt; ,s.avg_fragmentation_in_percent &lt;br /&gt; --,s.*&lt;br /&gt;FROM ?.sys.dm_db_index_physical_stats(DB_ID(''?''), NULL, NULL,&lt;br /&gt; NULL, ''Sampled'') AS s&lt;br /&gt; JOIN ?.sys.indexes i&lt;br /&gt; ON s.Object_Id = i.Object_id&lt;br /&gt; AND s.Index_id = i.Index_id&lt;br /&gt; JOIN ?.sys.tables t&lt;br /&gt; ON i.Object_id = t.Object_Id&lt;br /&gt; JOIN ?.sys.schemas sc&lt;br /&gt; ON t.schema_id = sc.SCHEMA_ID&lt;br /&gt;WHERE s.avg_fragmentation_in_percent &gt; 20&lt;br /&gt;AND t.TYPE = ''U''&lt;br /&gt;ORDER BY TableName,IndexName'&lt;br /&gt;&lt;br /&gt;DECLARE cList CURSOR&lt;br /&gt;FOR SELECT * FROM #Frag&lt;br /&gt;&lt;br /&gt;OPEN cList&lt;br /&gt;FETCH NEXT FROM cList&lt;br /&gt;INTO @DBName, @TableName,@SchemaName,@IndexName,@PctFrag&lt;br /&gt;WHILE @@FETCH_STATUS = 0&lt;br /&gt;BEGIN&lt;br /&gt;IF @PctFrag BETWEEN 20.0 AND 40.0&lt;br /&gt;BEGIN&lt;br /&gt;SET @Defrag = N'ALTER INDEX ' + @IndexName + ' ON ' + @DBName + '.' + @SchemaName + '.' + @TableName + ' REORGANIZE'&lt;br /&gt;EXEC sp_executesql @Defrag&lt;br /&gt;END&lt;br /&gt;ELSE IF @PctFrag &gt; 40.0&lt;br /&gt;BEGIN&lt;br /&gt;SET @Defrag = N'ALTER INDEX ' + @IndexName + ' ON ' + @DBName + '.' + @SchemaName + '.' + @TableName + ' REBUILD'&lt;br /&gt;EXEC sp_executesql @Defrag&lt;br /&gt;END&lt;br /&gt;&lt;br /&gt;FETCH NEXT FROM cList&lt;br /&gt;INTO @DBName, @TableName,@SchemaName,@IndexName,@PctFrag&lt;br /&gt;&lt;br /&gt;END&lt;br /&gt;CLOSE cList&lt;br /&gt;DEALLOCATE cList&lt;br /&gt;&lt;br /&gt;DROP TABLE #Frag&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-3719928834889138196?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/3719928834889138196/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=3719928834889138196' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3719928834889138196'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3719928834889138196'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/nothing-to-it.html' title='2008 Index Fragmentation Maintenance'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-5374178006550324682</id><published>2008-12-09T19:38:00.000-08:00</published><updated>2008-12-09T19:40:48.125-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Stored Procedure'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>Performance Tuning for Stored Procedures</title><content type='html'>For best performance, all objects that are called within the same stored procedure should all be owned by the same object owner or schema, preferably dbo, and should also be referred to in the format of object_owner.object_name or schema_owner.object_name.&lt;br /&gt;&lt;br /&gt;If the object owner's or schemas are not specified for objects, then SQL Server must perform name resolution on the objects, which causes a small performance hit.&lt;br /&gt;&lt;br /&gt;And if objects referred to in the stored procedure have different owners or schemas, SQL Server must check object permissions before it can access any object in the database, which adds unnecessary overhead. Ideally, the owner or schema of the stored procedure should own all of the objects referred to in the stored procedure.&lt;br /&gt;&lt;br /&gt;In addition, SQL Server cannot reuse a stored procedure "in-memory plan" over if the object owner or schema is not used consistently. If a stored procedure is sometime referred to with its object owner's  or schema name, and sometimes it is not, then SQL Server must re-execute the stored procedure, which also hinders performance. [7.0, 2000, 2005]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-5374178006550324682?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/5374178006550324682/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=5374178006550324682' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5374178006550324682'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5374178006550324682'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/performance-tuning-for-stored.html' title='Performance Tuning for Stored Procedures'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-3361410285423015206</id><published>2008-12-09T02:50:00.000-08:00</published><updated>2008-12-09T02:53:10.025-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><title type='text'>How to change all Object Owners to dbo</title><content type='html'>CreateALTER proc [dbo].[ChangeAllObjectOwnersTodbo]&lt;br /&gt;as&lt;br /&gt;set nocount on&lt;br /&gt;&lt;br /&gt;declare @uid int&lt;br /&gt;declare @objName varchar(50)&lt;br /&gt;declare @userName varchar(50)&lt;br /&gt;declare @currObjName varchar(50)&lt;br /&gt;declare @outStr varchar(256)&lt;br /&gt;set @uid = user_id('dbo')&lt;br /&gt;&lt;br /&gt;declare chObjOwnerCur cursor static&lt;br /&gt;for&lt;br /&gt;select user_name(uid) as 'username', [name] as 'name' from sysobjects where uid &lt;&gt; @uid&lt;br /&gt;&lt;br /&gt;open chObjOwnerCur&lt;br /&gt;if @@cursor_rows = 0&lt;br /&gt;begin&lt;br /&gt;  print 'All objects are already owned by dbo!'&lt;br /&gt;  close chObjOwnerCur&lt;br /&gt;  deallocate chObjOwnerCur&lt;br /&gt;  return 1&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;fetch next from chObjOwnerCur into @userName, @objName&lt;br /&gt;while @@fetch_status = 0&lt;br /&gt;begin&lt;br /&gt;  set @currObjName = 'dbo.' + @objName&lt;br /&gt;  if (object_id(@currObjName) &gt; 0)&lt;br /&gt;    print 'WARNING *** ' + @currObjName + ' already exists ***'&lt;br /&gt;  set @outStr = 'sp_changeobjectowner ''' + @userName + '.' + @objName + ''', ''dbo'''&lt;br /&gt;  print @outStr&lt;br /&gt;  print 'go'&lt;br /&gt;  fetch next from chObjOwnerCur into @userName, @objName&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;close chObjOwnerCur&lt;br /&gt;deallocate chObjOwnerCur&lt;br /&gt;set nocount off&lt;br /&gt;return 0&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-3361410285423015206?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/3361410285423015206/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=3361410285423015206' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3361410285423015206'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3361410285423015206'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/how-to-change-all-object-owners-to-dbo.html' title='How to change all Object Owners to dbo'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-6197430768399517170</id><published>2008-12-07T20:43:00.000-08:00</published><updated>2008-12-07T20:47:44.892-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>SQL injection</title><content type='html'>SQL injection is a technique that exploits a security vulnerability occurring in the database layer of an application. The vulnerability is present when user input is either incorrectly filtered for string literal escape characters embedded in SQL statements or user input is not strongly typed and thereby unexpectedly executed. It is in fact an instance of a more general class of vulnerabilities that can occur whenever one programming or scripting language is embedded inside another.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Forms of SQL injection vulnerabilities&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Incorrectly filtered escape characters&lt;/span&gt;&lt;br /&gt;This form of SQL injection occurs when user input is not filtered for escape characters and is then passed into a SQL statement. This results in the potential manipulation of the statements performed on the database by the end user of the application.&lt;br /&gt;&lt;br /&gt;The following line of code illustrates this vulnerability:&lt;br /&gt;&lt;br /&gt;statement = "SELECT * FROM users WHERE name = '" + userName + "';"&lt;br /&gt;&lt;br /&gt;This SQL code is designed to pull up the records of a specified username from its table of users. However, if the "userName" variable is crafted in a specific way by a malicious user, the SQL statement may do more than the code author intended. For example, setting the "userName" variable as&lt;br /&gt;&lt;br /&gt;a' or 't'='t&lt;br /&gt;&lt;br /&gt;renders this SQL statement by the parent language:&lt;br /&gt;&lt;br /&gt;SELECT * FROM users WHERE name = 'a' OR 't'='t';&lt;br /&gt;&lt;br /&gt;If this code were to be used in an authentication procedure then this example could be used to force the selection of a valid username because the evaluation of 't'='t' is always true.&lt;br /&gt;&lt;br /&gt;While most SQL Server implementations allow multiple statements to be executed with one call, some SQL APIs such as php's mysql_query do not allow this for security reasons. This prevents hackers from injecting entirely separate queries, but doesn't stop them from modifying queries. The following value of "userName" in the statement below would cause the deletion of the "users" table as well as the selection of all data from the "data" table (in essence revealing the information of every user):&lt;br /&gt;&lt;br /&gt;a';DROP TABLE users; SELECT * FROM data WHERE name LIKE '%&lt;br /&gt;&lt;br /&gt;This input renders the final SQL statement as follows:&lt;br /&gt;&lt;br /&gt;SELECT * FROM Users WHERE name = 'a';DROP TABLE users; SELECT * FROM DATA WHERE name LIKE '%';&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Incorrect type handling&lt;/span&gt;&lt;br /&gt;This form of SQL injection occurs when a user supplied field is not strongly typed or is not checked for type constraints. This could take place when a numeric field is to be used in a SQL statement, but the programmer makes no checks to validate that the user supplied input is numeric. For example:&lt;br /&gt;&lt;br /&gt;statement := "SELECT * FROM data WHERE id = " + a_variable + ";"&lt;br /&gt;&lt;br /&gt;It is clear from this statement that the author intended a_variable to be a number correlating to the "id" field. However, if it is in fact a string then the end user may manipulate the statement as they choose, thereby bypassing the need for escape characters. For example, setting a_variable to&lt;br /&gt;&lt;br /&gt;1;DROP TABLE users&lt;br /&gt;&lt;br /&gt;will drop (delete) the "users" table from the database, since the SQL would be rendered as follows:&lt;br /&gt;&lt;br /&gt;SELECT * FROM DATA WHERE id=1;DROP TABLE users;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Magic String&lt;/span&gt;&lt;br /&gt;The magic sting is a simple string of SQL used primarily at login pages. The magic string is&lt;br /&gt;&lt;br /&gt;'OR''='&lt;br /&gt;&lt;br /&gt;When used at a login page, you will be logged in as the user on top of the SQL table.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Vulnerabilities inside the database server&lt;/span&gt;&lt;br /&gt;Sometimes vulnerabilities can exist within the database server software itself, as was the case with the MySQL server's mysql_real_escape_string() function[1]. This would allow an attacker to perform a successful SQL injection attack based on bad Unicode characters even if the user's input is being escaped.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Blind SQL Injection&lt;/span&gt;&lt;br /&gt;Blind SQL Injection is used when a web application is vulnerable to SQL injection but the results of the injection are not visible to the attacker. The page with the vulnerability may not be one that displays data but will display differently depending on the results of a logical statement injected into the legitimate SQL statement called for that page. This type of attack can become time-intensive because a new statement must be crafted for each bit recovered. There are several tools that can automate these attacks once the location of the vulnerability and the target information has been established.[2]&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Conditional Responses&lt;/span&gt;&lt;br /&gt;One type of blind SQL injection forces the database to evaluate a logical statement on an ordinary application screen.&lt;br /&gt;&lt;br /&gt;SELECT booktitle FROM booklist WHERE bookId = 'OOk14cd' AND 1=1&lt;br /&gt;&lt;br /&gt;will result in a normal page while&lt;br /&gt;&lt;br /&gt;SELECT booktitle FROM booklist WHERE bookId = 'OOk14cd' AND 1=2&lt;br /&gt;&lt;br /&gt;will likely give a different result if the page is vulnerable to a SQL injection. An injection like this will prove that a blind SQL injection is possible, leaving the attacker to devise statements that evaluate to true or false depending on the contents of a field in another table.[3]&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Conditional Errors&lt;/span&gt;&lt;br /&gt;This type of blind SQL injection causes a SQL error by forcing the database to evaluate a statement that causes an error if the WHERE statement is true. For example,&lt;br /&gt;&lt;br /&gt;SELECT 1/0 FROM users WHERE username='Ralph'&lt;br /&gt;&lt;br /&gt;the division by zero will only be evaluated and result in an error if user Ralph exists.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Time Delays&lt;/span&gt;&lt;br /&gt;Time Delays are a type of blind SQL injection that cause the SQL engine to execute a long running query or a time delay statement depending on the logic injected. The attacker can then measure the time the page takes to load to determine if the injected statement is true.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Preventing SQL Injection&lt;/span&gt;&lt;br /&gt;To protect against SQL injection, user input must not directly be embedded in SQL statements. Instead, parameterized statements must be used (preferred), or user input must be carefully escaped or filtered.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Using Parameterized Statements&lt;/span&gt;&lt;br /&gt;In some programming languages such as Java and .NET parameterized statements can be used that work with parameters (sometimes called placeholders or bind variables) instead of embedding user input in the statement. In many cases, the SQL statement is fixed. The user input is then assigned (bound) to a parameter. This is an example using Java and the JDBC API:&lt;br /&gt;&lt;br /&gt;PreparedStatement prep = conn.prepareStatement("SELECT * FROM USERS WHERE USERNAME=? AND PASSWORD=?");&lt;br /&gt;prep.setString(1, username);&lt;br /&gt;prep.setString(2, password);&lt;br /&gt;&lt;br /&gt;Similarly, in C#:&lt;br /&gt;&lt;br /&gt;using (SqlCommand myCommand = new SqlCommand("SELECT * FROM USERS WHERE USERNAME=@username AND PASSWORD=HASHBYTES('SHA1', @password)", myConnection))&lt;br /&gt;    {                    &lt;br /&gt;        myCommand.Parameters.AddWithValue("@username", user);&lt;br /&gt;        myCommand.Parameters.AddWithValue("@password", pass);&lt;br /&gt; &lt;br /&gt;        myConnection.Open();&lt;br /&gt;        SqlDataReader myReader = myCommand.ExecuteReader())&lt;br /&gt;        ...................&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;In PHP version 5 and MySQL version 4.1 and above, it is possible to use prepared statements through vendor-specific extensions like mysqli[4]. Example[5]:&lt;br /&gt;&lt;br /&gt;$db = new mysqli("localhost", "user", "pass", "database");&lt;br /&gt;$stmt = $db -&gt; prepare("SELECT priv FROM testUsers WHERE username=? AND password=?");&lt;br /&gt;$stmt -&gt; bind_param("ss", $user, $pass);&lt;br /&gt;$stmt -&gt; execute();&lt;br /&gt;&lt;br /&gt;In ColdFusion, the CFQUERYPARAM statement is useful in conjunction with the CFQUERY statement to nullify the effect of SQL code passed within the CFQUERYPARAM value as part of the SQL clause.[6] [7]. An example is below.&lt;br /&gt;&lt;br /&gt;&lt;cfquery name="Recordset1" datasource="cafetownsend"&gt;&lt;br /&gt;SELECT *&lt;br /&gt;FROM COMMENTS&lt;br /&gt;WHERE COMMENT_ID =&lt;cfqueryparam value="#URL.COMMENT_ID#" cfsqltype="cf_sql_numeric"&gt;&lt;br /&gt;&lt;/cfquery&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Enforcing the Use of Parameterized Statements&lt;/span&gt;&lt;br /&gt;There are two ways to ensure an application is not vulnerable to SQL injection: using code reviews (which is a manual process), and enforcing the use of parameterized statements. Enforcing the use of parameterized statements means that SQL statements with embedded user input are rejected at runtime. Currently only the H2 Database Engine supports this feature.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Using Escaping&lt;/span&gt;&lt;br /&gt;A straight-forward, though error-prone way to prevent injections is to escape dangerous characters. One of the reasons for it being error prone is that it is a type of blacklist which is less robust than a whitelist. For instance, every occurrence of a single quote (') in a parameter must be replaced by two single quotes ('') to form a valid SQL string literal. In PHP, for example, it is usual to escape parameters using the function mysql_real_escape_string before sending the SQL query:&lt;br /&gt;&lt;br /&gt;$query = sprintf("SELECT * FROM Users where UserName='%s' and Password='%s'", &lt;br /&gt;                  mysql_real_escape_string($Username), &lt;br /&gt;                  mysql_real_escape_string($Password));&lt;br /&gt;mysql_query($query);&lt;br /&gt;&lt;br /&gt;However, escaping is error-prone as it relies on the programmer to escape every parameter. Also, if the escape function fails to handle a special character correctly, an injection is still possible.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-6197430768399517170?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/6197430768399517170/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=6197430768399517170' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6197430768399517170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6197430768399517170'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/sql-injection.html' title='SQL injection'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-4018191087975160173</id><published>2008-12-07T20:34:00.000-08:00</published><updated>2008-12-07T20:36:40.178-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><title type='text'>Find Out The Recovery Model For Your Database</title><content type='html'>You want to quickly find out what the recovery model is for your database but you don’t want to start clicking and right-clicking in SSMS/Enterprise Manager to get that information. This is what you can do, you can use databasepropertyex to get that info. Replace ‘msdb’ with your database name&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;SELECT DATABASEPROPERTYEX(‘msdb’,‘Recovery’)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What if you want it for all databases in one shot? No problem here is how, this will work on SQL Server version 2000&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;SELECT name,DATABASEPROPERTYEX(name,‘Recovery’)&lt;br /&gt; FROM sysdatabases&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For SQL Server 2005 and up, you should use the following command&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;SELECT name,recovery_model_desc&lt;br /&gt;FROM sys.databases&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-4018191087975160173?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/4018191087975160173/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=4018191087975160173' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/4018191087975160173'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/4018191087975160173'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/find-out-recovery-model-for-your.html' title='Find Out The Recovery Model For Your Database'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-5677070276901031113</id><published>2008-12-07T20:28:00.000-08:00</published><updated>2008-12-07T20:33:22.857-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><title type='text'>What is deferred name resolution and why do you need to care?</title><content type='html'>&lt;span style="font-style:italic;"&gt;DECLARE @x INT&lt;br /&gt; &lt;br /&gt;SET @x = 1&lt;br /&gt; &lt;br /&gt;IF (@x = 0)&lt;br /&gt;BEGIN&lt;br /&gt;    SELECT 1 AS VALUE INTO #temptable&lt;br /&gt;END&lt;br /&gt;ELSE&lt;br /&gt;BEGIN&lt;br /&gt;   SELECT 2 AS VALUE INTO #temptable&lt;br /&gt;END&lt;br /&gt; &lt;br /&gt;SELECT * FROM #temptable –what does this return&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is the error you get&lt;br /&gt;Server: Msg 2714, Level 16, State 1, Line 12&lt;br /&gt;There is already an object named ‘#temptable’ in the database.&lt;br /&gt;&lt;br /&gt;You can do something like this to get around the issue with the temp table&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;DECLARE @x INT&lt;br /&gt; &lt;br /&gt;SET @x = 1&lt;br /&gt; &lt;br /&gt;CREATE TABLE #temptable (VALUE INT)&lt;br /&gt;IF (@x = 0)&lt;br /&gt;BEGIN&lt;br /&gt;    INSERT #temptable&lt;br /&gt;    SELECT 1&lt;br /&gt;END&lt;br /&gt;ELSE&lt;br /&gt;BEGIN&lt;br /&gt;    INSERT #temptable&lt;br /&gt;    SELECT 2&lt;br /&gt;END&lt;br /&gt; &lt;br /&gt;SELECT * FROM #temptable –what does this return&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So what is thing called Deferred Name Resolution? Here is what is explained in Books On Line&lt;br /&gt;&lt;br /&gt;    When a stored procedure is created, the statements in the procedure are parsed for syntactical accuracy. If a syntactical error is encountered in the procedure definition, an error is returned and the stored procedure is not created. If the statements are syntactically correct, the text of the stored procedure is stored in the syscomments system table.&lt;br /&gt;&lt;br /&gt;    When a stored procedure is executed for the first time, the query processor reads the text of the stored procedure from the syscomments system table of the procedure and checks that the names of the objects used by the procedure are present. This process is called deferred name resolution because objects referenced by the stored procedure need not exist when the stored procedure is created, but only when it is executed.&lt;br /&gt;&lt;br /&gt;    In the resolution stage, Microsoft SQL Server 2000 also performs other validation activities (for example, checking the compatibility of a column data type with variables). If the objects referenced by the stored procedure are missing when the stored procedure is executed, the stored procedure stops executing when it gets to the statement that references the missing object. In this case, or if other errors are found in the resolution stage, an error is returned.&lt;br /&gt;&lt;br /&gt;So what is happening is that beginning with SQL server 7 deferred name resolution was enabled for real tables but not for temporary tables. If you change the code to use a real table instead of a temporary table you won’t have any problem&lt;br /&gt;Run this to see what I mean&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;DECLARE @x INT&lt;br /&gt; &lt;br /&gt;SET @x = 1&lt;br /&gt; &lt;br /&gt;IF (@x = 0)&lt;br /&gt;BEGIN&lt;br /&gt;    SELECT 1 AS VALUE INTO temptable&lt;br /&gt;END&lt;br /&gt;ELSE&lt;br /&gt;BEGIN&lt;br /&gt;   SELECT 2 AS VALUE INTO temptable&lt;br /&gt;END&lt;br /&gt; &lt;br /&gt;SELECT * FROM temptable –what does this return&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What about variables? Let’s try it out, run this&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;DECLARE @x INT&lt;br /&gt; &lt;br /&gt;SET @x = 1&lt;br /&gt; &lt;br /&gt;IF (@x = 0)&lt;br /&gt;BEGIN&lt;br /&gt;    DECLARE @i INT&lt;br /&gt;    SELECT @i = 5&lt;br /&gt;END&lt;br /&gt;ELSE&lt;br /&gt;BEGIN&lt;br /&gt;   DECLARE @i INT&lt;br /&gt;   SELECT @i = 6&lt;br /&gt;END&lt;br /&gt; &lt;br /&gt;SELECT @i&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And you get the follwing error&lt;br /&gt;Server: Msg 134, Level 15, State 1, Line 13&lt;br /&gt;The variable name ‘@i’ has already been declared. Variable names must be unique within a query batch or stored procedure.&lt;br /&gt;&lt;br /&gt;Now why do you need to care about deferred name resolution? Let’s take another example&lt;br /&gt;create this proc&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;CREATE PROC SomeTestProc&lt;br /&gt;AS&lt;br /&gt;SELECT dbo.somefuction(1)&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;CREATE FUNCTION somefuction(@id INT)&lt;br /&gt;RETURNS INT&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;SELECT @id = 1&lt;br /&gt;RETURN @id&lt;br /&gt;END&lt;br /&gt;Go&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;now run this&lt;br /&gt;&lt;br /&gt;   SP_DEPENDS ’somefuction’&lt;br /&gt;&lt;br /&gt;result: Object does not reference any object, and no objects reference it.&lt;br /&gt;&lt;br /&gt;Most people will not create a proc before they have created the function. So when does this behavior rear its ugly head? When you script out all the objects in a database, if the function or any objects referenced by an object are created after the object that references them then sp_depends won’t be 100% correct&lt;br /&gt;&lt;br /&gt;SQL Server 2005 makes it pretty easy to do it yourself&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;SELECT specific_name,*&lt;br /&gt;FROM information_schema.routines&lt;br /&gt;WHERE object_definition(OBJECT_ID(specific_name)) LIKE ‘%somefuction%’&lt;br /&gt;AND routine_type = ‘procedure’&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-5677070276901031113?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/5677070276901031113/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=5677070276901031113' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5677070276901031113'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5677070276901031113'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/what-is-deferred-name-resolution-and.html' title='What is deferred name resolution and why do you need to care?'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-6029945198618546298</id><published>2008-12-07T20:17:00.000-08:00</published><updated>2008-12-07T20:27:11.415-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><title type='text'>How Do You Check If A Temporary Table Exists In SQL Server</title><content type='html'>How do you check if a temp table exists?&lt;br /&gt;&lt;br /&gt;You can use IF OBJECT_ID(’tempdb..#temp’) IS NOT NULL Let’s see how it works &lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;–Create table&lt;br /&gt;USE Norhtwind&lt;br /&gt;GO&lt;br /&gt; &lt;br /&gt;CREATE TABLE #temp(id INT)&lt;br /&gt; &lt;br /&gt;–Check if it exists&lt;br /&gt;IF OBJECT_ID(‘tempdb..#temp’) IS NOT NULL&lt;br /&gt;BEGIN&lt;br /&gt;PRINT ‘#temp exists!’&lt;br /&gt;END&lt;br /&gt;ELSE&lt;br /&gt;BEGIN&lt;br /&gt;PRINT ‘#temp does not exist!’&lt;br /&gt;END&lt;br /&gt; &lt;br /&gt;–Another way to check with an undocumented optional second parameter&lt;br /&gt;IF OBJECT_ID(‘tempdb..#temp’,‘u’) IS NOT NULL&lt;br /&gt;BEGIN&lt;br /&gt;PRINT ‘#temp exists!’&lt;br /&gt;END&lt;br /&gt;ELSE&lt;br /&gt;BEGIN&lt;br /&gt;PRINT ‘#temp does not exist!’&lt;br /&gt;END&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;–Don’t do this because this checks the local DB and will return does not exist&lt;br /&gt;IF OBJECT_ID(‘tempdb..#temp’,‘local’) IS NOT NULL&lt;br /&gt;BEGIN&lt;br /&gt;PRINT ‘#temp exists!’&lt;br /&gt;END&lt;br /&gt;ELSE&lt;br /&gt;BEGIN&lt;br /&gt;PRINT ‘#temp does not exist!’&lt;br /&gt;END&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;–unless you do something like this&lt;br /&gt;USE tempdb&lt;br /&gt;GO&lt;br /&gt; &lt;br /&gt;–Now it exists again&lt;br /&gt;IF OBJECT_ID(‘tempdb..#temp’,‘local’) IS NOT NULL&lt;br /&gt;BEGIN&lt;br /&gt;PRINT ‘#temp exists!’&lt;br /&gt;END&lt;br /&gt;ELSE&lt;br /&gt;BEGIN&lt;br /&gt;PRINT ‘#temp does not exist!’&lt;br /&gt;END&lt;br /&gt; &lt;br /&gt;–let’s go back to Norhtwind again&lt;br /&gt;USE Norhtwind&lt;br /&gt;GO&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;–Check if it exists&lt;br /&gt;IF OBJECT_ID(‘tempdb..#temp’) IS NOT NULL&lt;br /&gt;BEGIN&lt;br /&gt;PRINT ‘#temp exists!’&lt;br /&gt;END&lt;br /&gt;ELSE&lt;br /&gt;BEGIN&lt;br /&gt;PRINT ‘#temp does not exist!’&lt;br /&gt;END&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;now open a new window from Query Analyzer (CTRL + N) and run this code again &lt;br /&gt;&lt;br /&gt;–Check if it exists&lt;br /&gt;IF OBJECT_ID(‘tempdb..#temp’) IS NOT NULL&lt;br /&gt;BEGIN&lt;br /&gt;PRINT ‘#temp exists!’&lt;br /&gt;END&lt;br /&gt;ELSE&lt;br /&gt;BEGIN&lt;br /&gt;PRINT ‘#temp does not exist!’&lt;br /&gt;END&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;It doesn’t exist and that is correct since it’s a local temp table not a global temp table&lt;br /&gt;&lt;br /&gt;Well let’s test that statement &lt;br /&gt;&lt;br /&gt;–create a global temp table&lt;br /&gt;&lt;span style="font-style:italic;"&gt;CREATE TABLE ##temp(id INT) –Notice the 2 pound signs, that’s how you create a global variable&lt;br /&gt; &lt;br /&gt;–Check if it exists&lt;br /&gt;IF OBJECT_ID(‘tempdb..##temp’) IS NOT NULL&lt;br /&gt;BEGIN&lt;br /&gt;PRINT ‘##temp exists!’&lt;br /&gt;END&lt;br /&gt;ELSE&lt;br /&gt;BEGIN&lt;br /&gt;PRINT ‘##temp does not exist!’&lt;br /&gt;END&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;It exists, right?&lt;br /&gt;Now run the same code in a new Query Analyzer window (CTRL + N) &lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;–Check if it exists&lt;br /&gt;IF OBJECT_ID(‘tempdb..##temp’) IS NOT NULL&lt;br /&gt;BEGIN&lt;br /&gt;PRINT ‘##temp exists!’&lt;br /&gt;END&lt;br /&gt;ELSE&lt;br /&gt;BEGIN&lt;br /&gt;PRINT ‘##temp does not exist!’&lt;br /&gt;END&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And yes this time it does exist since it’s a global table&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-6029945198618546298?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/6029945198618546298/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=6029945198618546298' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6029945198618546298'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6029945198618546298'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/how-do-you-check-if-temporary-table.html' title='How Do You Check If A Temporary Table Exists In SQL Server'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-4213291931945460840</id><published>2008-12-04T20:14:00.000-08:00</published><updated>2008-12-04T20:16:46.337-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><title type='text'>Finding all data types in user tables</title><content type='html'>This script queries sys.columns to get the entire list of columns and tables existing in the current database, then maps the columns datatype with a name from sys.systypes. The where clause filters the results for user created databases, less 'sysdiagrams', or you can use the commented out where clause to target a specific table.&lt;br /&gt;&lt;br /&gt;This is a great way to hunt down various data types and make sure different development teams are on the same page and don't do silly things like having the data types on their tables not matching other tables and causing frustrations in forgetting to cast the values.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;select object_name(c.object_id) "Table Name", c.name "Column Name", s.name "Column Type"&lt;br /&gt;  from sys.columns c&lt;br /&gt;  join sys.systypes s on (s.xtype = c.system_type_id)&lt;br /&gt;  where object_name(c.object_id) in (select name from sys.tables where name not like 'sysdiagrams')&lt;br /&gt;  -- where object_name(c.object_id) in (select name from sys.tables where name like 'TARGET_TABLE_NAME')&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-4213291931945460840?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/4213291931945460840/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=4213291931945460840' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/4213291931945460840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/4213291931945460840'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/finding-all-data-types-in-user-tables.html' title='Finding all data types in user tables'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-1358649326782620296</id><published>2008-12-03T20:11:00.000-08:00</published><updated>2008-12-05T03:13:07.258-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><title type='text'>Increment a string</title><content type='html'>It's good to create a serial number to tickets, or another serie from data type character.&lt;br /&gt;&lt;br /&gt;declare @litere nvarchar(3)&lt;br /&gt;declare @litera1 char(1)&lt;br /&gt;declare @litera2 char(1)&lt;br /&gt;&lt;br /&gt;set @litere='AQ'&lt;br /&gt;&lt;br /&gt;select @litera1=substring(@litere,2,1)&lt;br /&gt;select @litera2=substring(@litere,1,1)&lt;br /&gt;&lt;br /&gt;if @litera1='Z'&lt;br /&gt; begin &lt;br /&gt; set @litera1='A'&lt;br /&gt; set @litera2=char(ascii(substring(@litere,1,1))+1)&lt;br /&gt; end&lt;br /&gt;&lt;br /&gt;else&lt;br /&gt; set @litera1=char(ascii(substring(@litere,2,1))+1)&lt;br /&gt;&lt;br /&gt; select @litera1, @litera2&lt;br /&gt; set @litere=@litera2+@litera1&lt;br /&gt; select @litere&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-1358649326782620296?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/1358649326782620296/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=1358649326782620296' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/1358649326782620296'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/1358649326782620296'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/12/increment-string.html' title='Increment a string'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-1283114925341916782</id><published>2008-11-30T23:13:00.000-08:00</published><updated>2008-11-30T23:17:47.074-08:00</updated><title type='text'>Writing Outer Joins in T-SQL</title><content type='html'>Occasionally someone will ask for my help with a query and say that both a right outer join and a left outer join was tried, and still the expected results were not achieved. That made me realize that some developers do not completely understand outer joins and that an article explaining how to use them might help.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Inner Join Review&lt;/span&gt;&lt;br /&gt;The most commonly used join is an INNER JOIN. This type of join combines rows from two tables only when they match on the joining condition. Usually the primary key from one table matches a foreign key on another table, but join conditions can be more complex than that.&lt;br /&gt;&lt;br /&gt;(Note: Most of the information in this article can be applied to views as well as tables. For simplicity, the word "table" will be used to mean table or view unless stated otherwise. Keys are not defined on views, but the underlying table’s key column or columns are often included in the view. To keep things simple, let's assume that is the case.)&lt;br /&gt;&lt;br /&gt;INNER JOIN will retrieve a results row only where there is a perfect match between the two tables in the join condition. You will also often see one row from one of the tables matching multiple rows in the other table. For example, one customer can have many orders. One order can have many order details. The data on the one side will be repeated for each row on the many side. The following query is an example showing how the information from the Sales.SalesOrderHeader is repeated on each matching row: &lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;SELECT s.SalesOrderID, OrderDate,ProductID&lt;br /&gt;FROM Sales.SalesOrderHeader AS s &lt;br /&gt;INNER JOIN Sales.SalesOrderDetail AS d ON s.SalesOrderID = d.SalesOrderID&lt;br /&gt;ORDER BY s.SalesOrderID, ProductID&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Outer Join Introduction&lt;/span&gt;&lt;br /&gt;OUTER JOIN is used to join two tables even if there is not a match. An OUTER JOIN can be used to return a list of all the customers and the orders even if no orders have been placed for some of the customers. A keyword, RIGHT or LEFT, is used to specify which side of the join returns all possible rows. I like using LEFT because it makes sense to me to list the most important table first. Except for one example demonstrating RIGHT OUTER JOIN, this article will use left joins. Just a note: the keywords INNER and OUTER are optional.&lt;br /&gt;&lt;br /&gt;The next example returns a list of all the customers and the SalesOrderID for the orders that have been placed, if any. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;SELECT c.CustomerID, s.SalesOrderID&lt;br /&gt;FROM Sales.Customer c &lt;br /&gt;LEFT OUTER JOIN Sales.SalesOrderHeader s ON c.CustomerID = s.CustomerID&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It uses the LEFT keyword because the Sales.Customer table is located on the left side and we want all rows returned from that table even if there is no match in the Sales.SalesOrderHeader table. This is an important point. Notice also that the CustomerID column is the primary key of the Sales.Customer table and a foreign key in the Sales.SalesOrderHeader table. This means that there must be a valid customer for every order placed. Writing a query that returns all orders and the customers if they match doesn’t make sense. The LEFT table should always be the primary key table when performing a LEFT OUTER JOIN.&lt;br /&gt;&lt;br /&gt;If the location of the tables in the query are switched, the RIGHT keyword is used and the same results are returned: &lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;SELECT c.CustomerID, s.SalesOrderID&lt;br /&gt;FROM Sales.SalesOrderHeader s &lt;br /&gt;RIGHT OUTER JOIN Sales.Customer c ON c.CustomerID = s.CustomerID&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Notice that I didn’t change the join condition at all. It doesn’t matter which side of the equal sign the columns are listed; only where the tables are named is it important.&lt;br /&gt;&lt;br /&gt;If I have a LEFT OUTER JOIN, what is returned from the table on the right side of the join where there is not a match? Each column from the right side will return a NULL. Try this query which lists the non-matching rows first:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;SELECT c.CustomerID, s.SalesOrderID&lt;br /&gt;FROM Sales.Customer c &lt;br /&gt;LEFT OUTER JOIN Sales.SalesOrderHeader s ON c.CustomerID = s.CustomerID&lt;br /&gt;ORDER BY s.SalesOrderID&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;By adding a WHERE clause to check for a NULL SalesOrderID, you can find all the customers who have not placed an order. My copy of AdventureWorks returns 66 customers with no orders:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;SELECT c.CustomerID, s.SalesOrderID&lt;br /&gt;FROM Sales.Customer c &lt;br /&gt;LEFT OUTER JOIN Sales.SalesOrderHeader s ON c.CustomerID = s.CustomerID&lt;br /&gt;WHERE s.SalesOrderID IS NULL&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Occasionally, you will need to be more specific. How can you find all the customers who have not placed an order in 2002? There are several ways to solve this problem. You could create a view of all the orders placed in 2002 and join the view on the Sales.Customer table. Another option is to create a CTE, or Common Table Expression, of the orders placed in 2002. This example shows how to use a CTE to get the required results:&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;WITH s AS&lt;br /&gt;(   SELECT SalesOrderID, customerID&lt;br /&gt;    FROM Sales.SalesOrderHeader&lt;br /&gt;    WHERE OrderDate between '1/1/2002' and '12/31/2002'&lt;br /&gt;)&lt;br /&gt;SELECT c.CustomerID, s.SalesOrderID&lt;br /&gt;FROM Sales.Customer c &lt;br /&gt;LEFT OUTER JOIN s ON c.customerID = s.customerID&lt;br /&gt;WHERE s.SalesOrderID IS NULL&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;My favorite technique to solve this problem is much simpler. Additional criteria, in this case filtering on the OrderDate, can be added to the join condition. The query joins all customers to the orders placed in 2002. Then the results are restricted to those where there is no match. This query will return exactly the same results as the previous, more complicated query:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;SELECT c.CustomerID, s.SalesOrderID&lt;br /&gt;FROM Sales.Customer c &lt;br /&gt;LEFT OUTER JOIN Sales.SalesOrderHeader s ON c.CustomerID = s.CustomerID &lt;br /&gt;                              and s.OrderDate between '1/1/2002' and '12/31/2002' &lt;br /&gt;WHERE s.SalesOrderID IS NULL&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Using Aggregates with Outer Joins&lt;/span&gt;&lt;br /&gt;Aggregate queries introduce another pitfall watch out for. The following example is an attempt to list all the customers and the count of the orders that have been placed. Can you spot the problem?&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;SELECT c.CustomerID, count(*) OrderCount&lt;br /&gt;FROM Sales.Customer c &lt;br /&gt;LEFT OUTER JOIN Sales.SalesOrderHeader s ON c.CustomerID = s.CustomerID &lt;br /&gt;GROUP BY c.CustomerID&lt;br /&gt;ORDER BY OrderCount&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now the customers with no orders look like they have placed one order. That is because this query is counting the rows returned. To solve this problem, count the SalesOrderID column. NULL values are eliminated from the count.&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;SELECT c.CustomerID, count(SalesOrderID) OrderCount&lt;br /&gt;FROM Sales.Customer c LEFT OUTER JOIN Sales.SalesOrderHeader s&lt;br /&gt;ON c.CustomerID = s.CustomerID &lt;br /&gt;GROUP BY c.CustomerID&lt;br /&gt;ORDER BY OrderCount&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Multiple Joins&lt;/span&gt;&lt;br /&gt;Once more than two tables are involved in the query, things get a bit more complicated. When a table is joined to the RIGHT table, a LEFT OUTER JOIN must be used. That is because the NULL rows from the RIGHT table will not match any rows on the new table. An INNER JOIN causes the non-matching rows to be eliminated from the results. If the Sales.SalesOrderDetail table is joined to the Sales.SalesOrderHeader table and an INNER JOIN is used, none of the customers without orders will show up. NULL cannot be joined to any value, not even NULL.&lt;br /&gt;&lt;br /&gt;To illustrate this point, when I add the Sales.SalesOrderDetail table to one of the previous queries that checked for customers without orders, I get back no rows at all.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;SELECT c.CustomerID, s.SalesOrderID, d.SalesOrderDetailID&lt;br /&gt;FROM Sales.Customer c &lt;br /&gt;LEFT OUTER JOIN Sales.SalesOrderHeader s ON c.CustomerID = s.CustomerID &lt;br /&gt;INNER JOIN Sales.SalesOrderDetail d ON s.SalesOrderID = d.SalesOrderID&lt;br /&gt;WHERE s.SalesOrderID IS NULL&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;To get correct results, change the INNER JOIN to a LEFT JOIN.&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;SELECT c.CustomerID, s.SalesOrderID, d.SalesOrderDetailID&lt;br /&gt;FROM Sales.Customer c &lt;br /&gt;LEFT OUTER JOIN Sales.SalesOrderHeader s ON c.CustomerID = s.CustomerID &lt;br /&gt;LEFT OUTER JOIN Sales.SalesOrderDetail d ON s.SalesOrderID = d.SalesOrderID&lt;br /&gt;WHERE s.SalesOrderID IS NULL&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What about additional tables joined to Sales.Customer, the table on the left? Must outer joins be used? If it is possible that there are some rows without matches, it must be an outer join to guarantee that no results are lost. The Sales.Customer table has a foreign key pointing to the Sales.SalesTerritory table. Every customer’s territory ID must match a valid value in Sales.SalesTerritory. This query returns 66 rows as expected because it is impossible to eliminate any customers by joining to Sales.SalesTerritory:&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;SELECT c.CustomerID, s.SalesOrderID, t.Name&lt;br /&gt;FROM Sales.Customer c &lt;br /&gt;LEFT OUTER JOIN Sales.SalesOrderHeader s ON c.CustomerID = s.CustomerID &lt;br /&gt;INNER JOIN Sales.SalesTerritory t ON c.TerritoryID = t.TerritoryID&lt;br /&gt;WHERE SalesOrderID IS NULL&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Sales.SalesTerritory is the primary key table; every customer must match a valid territory. If you wanted to write a query that listed all territories, even those that had no customers, an outer join will be used. This time, Sales.Customers is on the right side of the join.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;SELECT t.Name, CustomerID&lt;br /&gt;FROM Sales.SalesTerritory t &lt;br /&gt;LEFT OUTER JOIN Sales.Customer c ON t.TerritoryID =c.TerritoryID&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-1283114925341916782?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/1283114925341916782/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=1283114925341916782' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/1283114925341916782'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/1283114925341916782'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/writing-outer-joins-in-t-sql.html' title='Writing Outer Joins in T-SQL'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-4845205958520334386</id><published>2008-11-30T22:59:00.000-08:00</published><updated>2008-11-30T23:02:20.090-08:00</updated><title type='text'>SQL Server Connection Strings</title><content type='html'>Some common and not so common connection strings for the .NET SqlConnection object.  The article includes .NET sample code and some tricks to increase the supportability of your application.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Trusted Authentication&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Data Source=ServerName; Initial Catalog=DatabaseName; Integrated Security=SSPI;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Trusted authentication uses the security credentials of the current user to make the connection to SQL Server.  SQL Server uses Windows (or Active Directory) to validate the current user.  ServerName can be the name of a server or the name of a SQL Server instance such as Server1\Instance2.  ServerName can also be expressed as an IP address.  SSPI stands for Security Support Provider Interface (in you were curious). &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;SQL Server Security Authentication&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Data Source=ServerName; Initial Catalog=DatabaseName; User Id=UserName; Password=UserPassword;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In SQL Server authentication SQL Server stores the username and password.  ServerName can be the name of a server or the name of a SQL Server instance such as Server1\Instance2.  ServerName can also be expressed as an IP address.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Setting the Application Name&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Data Source=ServerName; Initial Catalog=DatabaseName; Integrated Security=SSPI; Application Name=MyAppName;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I often set the Application Name when I construct connections strings.  Whatever text you assign to Application Name will appear in a couple of different places:&lt;br /&gt;&lt;br /&gt;    * It will be displayed in Profiler under the Application Name column.&lt;br /&gt;    * It will be shown in the output of sp_who2 in the Program Name column.&lt;br /&gt;    * It will be shown in the Activity Monitor in the Application column.  You can get to the Activity Monitor in SQL Server Management Studio by Management -&gt; Activity Monitor.&lt;br /&gt;    * It will appear in the program_name column if you select from master.dbo.sysprocesses (for SQL Server 2000)&lt;br /&gt;    * It will appear int he program_name column if you select from sys.dm_exec_sessions (for SQL Server 2005 and later).&lt;br /&gt;&lt;br /&gt;Setting the application name makes it very easy to find out what applications are issuing particular SQL statements against my database.  Setting the application name can also lead to an increase in the number of connections to your SQL Server.  Each client that uses connection pooling will create one pool inside each application per unique connection string.  If you use multiple application names you have the possibility to increase the number of pools and thus the number of connections to SQL Server.  I've always found it more beneficial to have the application name than to have a few less connections to my database servers.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Using MARS (Multiple Active Result Sets)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;Data Source=ServerName; Initial Catalog=DatabaseName; Integrated Security=SSPI; MultipleActiveResultSets=True;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you want to use MARS you'll need to enable it in the connection string.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Sample .NET code&lt;/span&gt;&lt;br /&gt;There are two common ways to create a connection string in .NET.  The first is to use an explicit connection string.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;SqlConnection conn = new SqlConnection();&lt;br /&gt;conn.ConnectionString = "Data Source=L40; Initial Catalog=master; Integrated Security=SSPI;";&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The second is to use the Connection String Builder object in .NET to construct a connection string.&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;SqlConnectionStringBuilder csb = new SqlConnectionStringBuilder();&lt;br /&gt;csb.DataSource = "L40";&lt;br /&gt;csb.InitialCatalog = "master";&lt;br /&gt;csb.IntegratedSecurity = true;&lt;br /&gt;&lt;br /&gt;SqlConnection conn = new SqlConnection();&lt;br /&gt;conn.ConnectionString = csb.ToString();&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-4845205958520334386?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/4845205958520334386/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=4845205958520334386' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/4845205958520334386'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/4845205958520334386'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/sql-server-connection-strings.html' title='SQL Server Connection Strings'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-8311906789303230091</id><published>2008-11-27T20:11:00.000-08:00</published><updated>2008-11-27T20:12:12.531-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><title type='text'>Table Information View -- No Cursors!</title><content type='html'>One of the most frequent request I get is for a procedure that can return sp_SpaceUsed type information for every table in a database. This is easy enough to do with cursors and dynamic SQL, but after looking at how sp_SpaceUsed worked and how SMO gets the same information, I decided that I could write it without either.&lt;br /&gt;&lt;br /&gt;Even better, one I wrote it though, I realized that it could easily be rewritten as a view. Now I could reuse it by joining it with other tables and views in new queries or procedures whenever I wanted. Enjoy!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; vwTableInfo - Table Information View&lt;br /&gt;&lt;br /&gt; This view display space and storage information for every table in the database.&lt;br /&gt;Columns are:&lt;br /&gt; Schema&lt;br /&gt; Name&lt;br /&gt; Owner  may be different from Schema)&lt;br /&gt; Columns  count of the max number of columns ever used)&lt;br /&gt; HasClusIdx 1 if table has a clustered index, 0 otherwise&lt;br /&gt; RowCount&lt;br /&gt; IndexKB  space used by the table's indexes&lt;br /&gt; DataKB  space used by the table's data&lt;br /&gt;&lt;br /&gt; 16-March-2008, RBarryYoung@gmail.com&lt;br /&gt;*/&lt;br /&gt;--CREATE VIEW vwTableInfo&lt;br /&gt;-- AS&lt;br /&gt;SELECT SCHEMA_NAME(tbl.schema_id) as [Schema]&lt;br /&gt;, tbl.Name&lt;br /&gt;, Coalesce((Select pr.name &lt;br /&gt;  From sys.database_principals pr &lt;br /&gt;  Where pr.principal_id = tbl.principal_id)&lt;br /&gt; , SCHEMA_NAME(tbl.schema_id)) as [Owner]&lt;br /&gt;, tbl.max_column_id_used as [Columns]&lt;br /&gt;, CAST(CASE idx.index_id WHEN 1 THEN 1 ELSE 0 END AS bit) AS [HasClusIdx]&lt;br /&gt;, Coalesce( ( select sum (spart.rows) from sys.partitions spart &lt;br /&gt; where spart.object_id = tbl.object_id and spart.index_id &lt; 2), 0) AS [RowCount]&lt;br /&gt;&lt;br /&gt;, Coalesce( (Select Cast(v.low/1024.0 as float) &lt;br /&gt; * SUM(a.used_pages - CASE WHEN a.type &lt;&gt; 1 THEN a.used_pages WHEN p.index_id &lt; 2 THEN a.data_pages ELSE 0 END) &lt;br /&gt;  FROM sys.indexes as i&lt;br /&gt;   JOIN sys.partitions as p ON p.object_id = i.object_id and p.index_id = i.index_id&lt;br /&gt;   JOIN sys.allocation_units as a ON a.container_id = p.partition_id&lt;br /&gt;  where i.object_id = tbl.object_id  )&lt;br /&gt; , 0.0) AS [IndexKB]&lt;br /&gt;&lt;br /&gt;, Coalesce( (Select Cast(v.low/1024.0 as float)&lt;br /&gt; * SUM(CASE WHEN a.type &lt;&gt; 1 THEN a.used_pages WHEN p.index_id &lt; 2 THEN a.data_pages ELSE 0 END) &lt;br /&gt;  FROM sys.indexes as i&lt;br /&gt;   JOIN sys.partitions as p ON p.object_id = i.object_id and p.index_id = i.index_id&lt;br /&gt;   JOIN sys.allocation_units as a ON a.container_id = p.partition_id&lt;br /&gt;  where i.object_id = tbl.object_id)&lt;br /&gt; , 0.0) AS [DataKB]&lt;br /&gt;, tbl.create_date, tbl.modify_date&lt;br /&gt;&lt;br /&gt;FROM sys.tables AS tbl&lt;br /&gt; INNER JOIN sys.indexes AS idx ON (idx.object_id = tbl.object_id and idx.index_id &lt; 2)&lt;br /&gt; INNER JOIN master.dbo.spt_values v ON (v.number=1 and v.type='E')&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-8311906789303230091?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/8311906789303230091/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=8311906789303230091' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/8311906789303230091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/8311906789303230091'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/table-information-view-no-cursors.html' title='Table Information View -- No Cursors!'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-8889617994278208124</id><published>2008-11-23T20:17:00.000-08:00</published><updated>2008-11-23T20:18:26.207-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>SQL Server Query Execution Plan Analysis</title><content type='html'>In most cases, the query optimizer will analyze joins and JOIN the tables using the most efficient join type, and in the most efficient order. But not always. In the graphical query plan you will see icons that represent the different types of JOINs used in the query. In addition, each of the JOIN icons will have two arrows pointing to it. The upper arrow pointing to the JOIN icon represents the outer table in the join, and the lower arrow pointing to the JOIN icon represent the inner table in the join. Follow the arrows back to see the name of the tables being joined.&lt;br /&gt;&lt;br /&gt;Sometimes, in queries with multiple JOINs, tracing the arrow back won't reveal a table, but another JOIN. If you place the cursor over the arrows pointing to the upper and lower JOINs, you will see a popup window that tells you how many rows are being sent to the JOIN for processing. The upper arrow should always have fewer rows than the lower arrow. If not, then the JOIN order selected by the query optimizer might be incorrect (see more on this below).&lt;br /&gt;&lt;br /&gt;First of all, let's look at JOIN types. SQL Server can JOIN a table using three different techniques: nested loop, hash, and merge. Generally, the fastest type of join in a nested loop, but if that is not feasible, then a hash JOIN or merge JOIN is used (as appropriate), both of which tend to be slower than the nested JOIN.&lt;br /&gt;&lt;br /&gt;When very large tables are JOINed, a merge join, not a nested loop join, may be the best option. The only way to know is to try both and see which one is the most efficient.&lt;br /&gt;&lt;br /&gt;If a particular query is slow, and you suspect it may be because the JOIN type is not the optimum one for your data, you can override the query optimizer's choice by using a JOIN hint. Before you use a JOIN hint, you will want to take some time to learn about each of the JOIN types and how each one works. This is a complicated subject, beyond the scope of this tip.&lt;br /&gt;&lt;br /&gt;JOIN order is also selected by the query optimizer, which it trying to select the most efficient order to JOIN tables. For example, for a nested loop join, the upper table should be the smaller of the two tables. For hash joins, the same is true; the upper table should be the smaller of the two tables. If you feel that the query optimizer is selecting the wrong order, you can override it using JOIN hints.&lt;br /&gt;&lt;br /&gt;In many cases, the only way to know for sure if using a JOIN hint to change JOIN type or JOIN order will boost or hinder performance is to give them a try and see what happens. [7.0, 2000, 2005]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-8889617994278208124?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/8889617994278208124/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=8889617994278208124' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/8889617994278208124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/8889617994278208124'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/sql-server-query-execution-plan.html' title='SQL Server Query Execution Plan Analysis'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-2093107274077561580</id><published>2008-11-20T20:10:00.000-08:00</published><updated>2008-11-20T20:11:44.097-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>SQL Server Full-Text Search Performance Tuning and Optimization</title><content type='html'>If you are using the SQL Server Full-Text Search service, Microsoft recommends these two settings for optimum performance:&lt;br /&gt;&lt;br /&gt;    * The virtual memory (PAGEFILE.SYS file) setting for your operating system should be set to an amount equal to 3 times the amount of physical RAM in the server. If you have a non-dedicated SQL Server (a server running applications in addition to SQL Server) then you will want to add the virtual memory needs of these other applications to the amount calculated above.&lt;br /&gt;&lt;br /&gt;    * The SQL Server MAX SERVER MEMORY setting should be set manually (dynamic memory allocation is turned off) so that enough virtual memory is left for the Full-Text Search service to run. To achieve this, select a MAX SERVER MEMORY setting that once set, leaves enough virtual memory so that the Full-Text Search service is able to access an amount of virtual memory equal to 1.5 times the amount of physical RAM in the server. This will take some trial and error to achieve this setting.&lt;br /&gt;&lt;br /&gt;To find out how much virtual memory is being used by SQL Server and the Full-Text Search Service, you can use the Task Manager. By default, the Task Manager does not display the amount of virtual memory used by a process. To see this number in Task Manager, you must first go to the "Processes" tab. Once there, select "View", and then "Select Columns". From the "Select Columns" dialog box, click on "Virtual Memory Size", then "OK". Now you will be able to see the amount of virtual memory size used by each process on your server using Task Manager. Use this information to help you tune your server for use with the Full-Text Search service. [7.0, 2000]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-2093107274077561580?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/2093107274077561580/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=2093107274077561580' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/2093107274077561580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/2093107274077561580'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/sql-server-full-text-search-performance.html' title='SQL Server Full-Text Search Performance Tuning and Optimization'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-2602945713194972758</id><published>2008-11-19T20:24:00.001-08:00</published><updated>2008-11-19T20:25:30.597-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>Reducing SQL Server Locks</title><content type='html'>Encapsulate all transactions within stored procedures, including both the BEGIN TRANSACTION and COMMIT TRANSACTION statements in the procedure. This provides two benefits that help to reduce blocking locks.&lt;br /&gt;&lt;br /&gt;First, it limits the client application and SQL Server to communications before and after the transaction, thus forcing any messages between the client and the server to occur at a time other than when the transaction is running (reducing transaction time).&lt;br /&gt;&lt;br /&gt;Second, it prevents the user from leaving an open transaction (holding locks open) because the stored procedure forces any transactions that it starts to complete or abort. [6.5, 7.0, 2000, 2005]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-2602945713194972758?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/2602945713194972758/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=2602945713194972758' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/2602945713194972758'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/2602945713194972758'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/reducing-sql-server-locks.html' title='Reducing SQL Server Locks'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-3266529474382211503</id><published>2008-11-18T22:18:00.000-08:00</published><updated>2008-11-18T22:46:43.420-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Cursors'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>Avoid cursors in SQL Server with these methods to loop over records</title><content type='html'>Many articles have beaten up on SQL Server cursors -- database objects that manipulate data in a set on a row-by-row basis -- and I want to add my name to the list of people who wish cursors had never been introduced. But, unfortunately, cursors are a fact of life. Problems with cursors include extending locks, their inability to cache execution plans and CPU/RAM overhead. Many T-SQL programmers and DBAs do not know how to successfully loop over records without the need for cursors. In this tip, I'll share some alternatives to cursors that provide looping functionality.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Method 1: Temp table with identity column&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;In the first approach, we will use a temp table with an identity column added to allow for row-by-row selection. If you're performing an INSERT/UPDATE/DELETE, be sure to use the explicit transactions. This vastly reduces the load on your log file by committing per loop, and it prevents huge rollbacks in the case of failure.&lt;br /&gt;&lt;br /&gt;set nocount on&lt;br /&gt;declare @i int --iterator&lt;br /&gt;declare @iRwCnt int --rowcount&lt;br /&gt;declare @sValue varchar(100)&lt;br /&gt;&lt;br /&gt;set @i = 1 --initialize&lt;br /&gt;&lt;br /&gt;create table #tbl(ID int identity(1,1), Value varchar(100))&lt;br /&gt;&lt;br /&gt;insert into #tbl(Value)&lt;br /&gt;select name&lt;br /&gt;from master..sysdatabases (nolock)&lt;br /&gt;&lt;br /&gt;set @iRwCnt = @@ROWCOUNT --SCOPE_IDENTITY() would also work&lt;br /&gt;&lt;br /&gt;create clustered index idx_tmp on #tbl(ID) WITH FILLFACTOR = 100&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt;Always do this after the insert, since it's faster to add the index in bulk than to update the index as you write into the temp table. Since you know the data in this column, you can set the fill factor to 100% to get the best read times.&lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;while @i &lt;= @iRwCnt&lt;br /&gt;begin&lt;br /&gt;select @sValue = Value from #tbl where ID = @i&lt;br /&gt;&lt;br /&gt;--begin tran&lt;br /&gt;print 'My Value is ' + @sValue --replace with your operations on this value&lt;br /&gt;--commit tran&lt;br /&gt;&lt;br /&gt;set @i = @i + 1&lt;br /&gt;end&lt;br /&gt;drop table #tbl&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Method 2: Temp table without ID&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;In the second approach, we use a temp table without an identity column and simply grab the top row to process, then loop until we find no more rows to process. If you're performing an INSERT/UPDATE/DELETE, again, be sure to use the explicit transactions to vastly reduce the load on your log file by committing per loop, which prevents huge rollbacks in the case of failure.&lt;br /&gt;&lt;br /&gt;set nocount on&lt;br /&gt;&lt;br /&gt;declare @i int --iterator&lt;br /&gt;declare @iRwCnt int --rowcount&lt;br /&gt;declare @sValue varchar(100)&lt;br /&gt;set @i = 1 --initialize&lt;br /&gt;&lt;br /&gt;create table #tbl(Value varchar(100))&lt;br /&gt;&lt;br /&gt;insert into #tbl(Value)&lt;br /&gt;select name&lt;br /&gt;from master..sysdatabases (nolock)&lt;br /&gt;&lt;br /&gt;set @iRwCnt = @@ROWCOUNT --SCOPE_IDENTITY() would also work&lt;br /&gt;&lt;br /&gt;create clustered index idx_tmp on #tbl(Value) WITH FILLFACTOR = 100&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt;Always do this after the insert, since it's faster to add the index in bulk than to update the index as you write into the temp table. Since you know the data in this column, you can set the fill factor to 100% to get the best read times.&lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;while @iRwCnt &gt; 0&lt;br /&gt;begin&lt;br /&gt;select top 1 @sValue = Value from #tbl&lt;br /&gt;set @iRwCnt = @@ROWCOUNT --ensure that we still have data&lt;br /&gt;&lt;br /&gt;if @iRwCnt &gt; 0&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;--begin tran&lt;br /&gt;print 'My Value is ' + @sValue --replace with your operations on this value&lt;br /&gt;--commit tran&lt;br /&gt;&lt;br /&gt;delete from #tbl where value = @sValue --remove processed record&lt;br /&gt;end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;drop table #tbl&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Method 3: Selecting a comma-delimited list of items&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;When most developers/DBAs are asked to come up with a list of comma-delimited values from a table, they typically use a cursor or temp table (as above) to loop through the records. However, if you do not need to use a GROUP BY or an ORDER BY, then you can use the method below that operates in batch to handle the task. This cannot be used with GROUP BY DISTINCT, or ORDER BY, because of how SQL Server handles those operations.&lt;br /&gt;&lt;br /&gt;Basically, this takes a given variable, and for every row in the table it adds the current value to the variable along with a comma.&lt;br /&gt;&lt;br /&gt;declare @vrs varchar(4000)&lt;br /&gt;declare @sTbl sysname&lt;br /&gt;set @sTbl = 'TableName'&lt;br /&gt;set @vrs = ''&lt;br /&gt;select @vrs = @vrs + ', ' + name from syscolumns where id = (select st.id from sysobjects as st where name = @sTbl) order by colorder&lt;br /&gt;set @vrs = right(@vrs, len(@vrs)-2)&lt;br /&gt;print @vrs&lt;br /&gt;&lt;br /&gt;This article gives you some good reasons why cursors in SQL Server should be avoided as well as some alternatives that give you looping functionality. Keep in mind that SQL Server is designed around batch processing, so the less you loop, the faster your system will run.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-3266529474382211503?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/3266529474382211503/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=3266529474382211503' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3266529474382211503'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3266529474382211503'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/avoid-cursors-in-sql-server-with-these.html' title='Avoid cursors in SQL Server with these methods to loop over records'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-8098076249811799138</id><published>2008-11-18T21:06:00.000-08:00</published><updated>2008-11-18T21:14:20.640-08:00</updated><title type='text'>Egoless programming: The path to better code</title><content type='html'>Egoless programming is a way for developers to distance themselves emotionally from their work so that they become open to criticism, often from individuals with less perceived ability. Enter egoless programming.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Some Guidlines&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;   1. Understand and accept that you will make mistakes.&lt;/span&gt;&lt;br /&gt; The point is to find them early, before they make it into production. Fortunately, except for the few of us developing rocket guidance software at JPL, mistakes are rarely fatal in our industry. We aren’t surgeons; we can learn, laugh, and move on.&lt;br /&gt;&lt;br /&gt; &lt;span style="font-weight:bold;"&gt;  2. You are not your code.&lt;/span&gt;&lt;br /&gt; Remember, the entire point of a review is to find problems, and problems will be found. Don’t take it personally when a problem is uncovered.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;   &lt;br /&gt;3. No matter how much karate you know, someone else will always know more.&lt;/span&gt;&lt;br /&gt; This fact kept the samurai from indiscriminately attacking people in Imperial Japan. In our less violent times, such an individual can teach you some new moves if you ask. There will always be people who know more than you. Seek and accept input from others, even when you think it’s not needed.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;br /&gt;   4. Don’t rewrite other programmers’ code. &lt;/span&gt;&lt;br /&gt;There’s a fine line between “fixing other programmers’ code” and “rewriting other programmers’ code.” The former implies that a bug or other functionality problem exists and needs to be fixed and can also refer to correcting gross readability problems. The latter, however, refers to changes made to code for the sake of style. Programmers fresh from college are often guilty of this. Things like renaming variables, use of a different construct, recommenting, or gratuitous reformatting of white space fall into this category. Such activities, even with the purest of motive, are high hubris and detrimental to team mentality.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;   5. Treat people who know less than you with respect, deference, and patience. &lt;/span&gt;&lt;br /&gt;Nontechnical people who deal with developers on a regular basis almost universally hold the opinion that we are prima donnas at best and crybabies at worst. Becoming angry only reinforces this perception and teaches people to avoid asking questions. This can only harm your work in the long run.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;   6. The only constant in the world is change. &lt;/span&gt;&lt;br /&gt;Be open to it and accept it with a smile. Look at each change to your requirements, platform, or tool as a new challenge, not as some serious inconvenience to be fought.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;   7. The only true authority stems from knowledge, not from position.&lt;/span&gt;&lt;br /&gt; Knowledge engenders authority, and authority engenders respect—so if you want respect in an egoless environment, cultivate knowledge.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;   8. Fight for what you believe but gracefully accept defeat. &lt;/span&gt;&lt;br /&gt;Understand that sometimes your ideas will be overruled. Even if you do turn out to be right, don’t take revenge or say, “I told you so” more than a few times at most, and don't make your dearly departed idea a martyr or rallying cry.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;   9. Don’t be “the guy in the room.” &lt;/span&gt;&lt;br /&gt;Don’t be the guy coding in the dark office emerging only to buy cola. The guy in the room is out of touch, out of sight, and out of control and has no place in an open, collaborative environment.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Following these rules will prevent needless eggshell walking by your coworkers and will allow them to get back to the one activity everyone in this profession enjoys: creating great things with their computers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-8098076249811799138?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/8098076249811799138/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=8098076249811799138' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/8098076249811799138'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/8098076249811799138'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/egoless-programming-path-to-better-code.html' title='Egoless programming: The path to better code'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-3152970724781396727</id><published>2008-11-17T00:55:00.000-08:00</published><updated>2008-11-17T01:38:53.054-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><title type='text'>"Nothing has changed" - Determining when a procedure has been altered</title><content type='html'>Someone need to determine when a stored procedure was last altered. Without having implemented a series of DDL triggers, how can this be accomplished?&lt;br /&gt;&lt;br /&gt;In Microsoft SQL Server, you can easily retrieve this information from the sys.procedures catalog view. The following query demonstrates this.&lt;br /&gt;&lt;br /&gt;SELECT &lt;br /&gt;     [name]&lt;br /&gt;    ,modify_date&lt;br /&gt;    ,create_date&lt;br /&gt;    ,*&lt;br /&gt;FROM&lt;br /&gt;    sys.procedures &lt;br /&gt;&lt;br /&gt;Of course you can take it a step further by limiting the results to a period of time where you know that no changes should have been made. For example, the following query lists all stored procedures that have been changed since August 1, 2007 (the time I last visited this client).&lt;br /&gt;&lt;br /&gt;SELECT &lt;br /&gt;     [name]&lt;br /&gt;    ,modify_date&lt;br /&gt;    ,create_date&lt;br /&gt;    ,*&lt;br /&gt;FROM&lt;br /&gt;    sys.procedures&lt;br /&gt;WHERE &lt;br /&gt;    modify_date &gt; '2008-10-01'&lt;br /&gt;&lt;br /&gt;Although, using this technique will not allow me to identify who made the change, I can at least determine that a change has taken place.&lt;br /&gt;Cheers!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-3152970724781396727?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/3152970724781396727/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=3152970724781396727' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3152970724781396727'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3152970724781396727'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/nothing-has-changed-determining-when.html' title='&quot;Nothing has changed&quot; - Determining when a procedure has been altered'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-6207553070627625494</id><published>2008-11-17T00:45:00.000-08:00</published><updated>2008-11-17T00:50:45.800-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><title type='text'>Reading the transaction log</title><content type='html'>SELECT        *&lt;br /&gt;FROM          ::fn_dblog(DEFAULT, DEFAULT) AS l&lt;br /&gt;INNER JOIN    sysobjects AS so ON so.name = l.[transaction name]&lt;br /&gt;&lt;br /&gt;SELECT        so.name AS ObjectName,&lt;br /&gt;              so.type AS ObjectType,&lt;br /&gt;              MAX(CAST(l.[Begin Time] AS DATETIME)) AS LogTime&lt;br /&gt;FROM          ::fn_dblog(DEFAULT, DEFAULT) l&lt;br /&gt;inner join    sysobjects so on so.name = l.[transaction name]&lt;br /&gt;--where              so.type = 'u'&lt;br /&gt;GROUP BY      so.name,&lt;br /&gt;              so.type&lt;br /&gt;ORDER BY      so.name,&lt;br /&gt;              so.type&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-6207553070627625494?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/6207553070627625494/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=6207553070627625494' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6207553070627625494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/6207553070627625494'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/reading-transaction-log.html' title='Reading the transaction log'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-4878225018989694288</id><published>2008-11-16T22:41:00.000-08:00</published><updated>2008-11-16T22:42:41.069-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>SQL Server Join Hints</title><content type='html'>JOIN hints can be used in a query to specify the type of JOIN the Query Optimizer is to use for the execution plan. The JOIN options are:&lt;br /&gt;&lt;br /&gt;    * Loop&lt;br /&gt;    * Merge&lt;br /&gt;    * Hash&lt;br /&gt;&lt;br /&gt;The syntax for a JOIN hint is (using an INNER JOIN as an example):&lt;br /&gt;&lt;br /&gt;FROM table_one INNER [LOOP | MERGE | JOIN] JOIN table_two&lt;br /&gt;&lt;br /&gt;Here's an example:&lt;br /&gt;&lt;br /&gt;FROM header_table INNER LOOP JOIN detail_table&lt;br /&gt;&lt;br /&gt;As you can see, the JOIN hint is between the type of JOIN (in this example, INNER) and the JOIN keyword. Only one JOIN hint can be used per JOIN in a query. In addition, JOIN hints can only be used when the ANSI JOIN syntax is used, not the older Microsoft JOIN syntax.&lt;br /&gt;&lt;br /&gt;The syntax above is not the only option to add a JOIN hint to a query. In addition, you can also use OPTION clause. Using the OPTION clause specifies that the hint be used throughout all of the query. While multiple hints can be added to the OPTION clause, each query hint can be used only once. In addition, only one OPTION clause can be used per query.&lt;br /&gt;&lt;br /&gt;Here's an example of using the OPTION clause:&lt;br /&gt;&lt;br /&gt;OPTION (INNER) or OPTION (MERGE) or OPTION (HASH)&lt;br /&gt;&lt;br /&gt;The Query Optimizer always tries to identify the fastest way to JOIN tables. The fastest JOIN method is the Loop JOIN, followed by the Merge and the Hash JOIN. While the Query Optimizer always tries to perform a Loop JOIN if possible, it is not always possible, and one of the other two types may have to be used.&lt;br /&gt;&lt;br /&gt;Before you attempt to use JOIN hint to specify a JOIN type, you should first take a look at your query, and the indexing of the relevant tables, to see if you can find a way, other than using a hint, to induce the Query Optimizer to use a Loop JOIN. Keep in mind that if you specify a Loop JOIN hint for a JOIN that is currently using a HASH JOIN, that you may get worse, not better performance. So always test JOIN hints to see what their end result in performance really is. [7.0, 2000]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-4878225018989694288?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/4878225018989694288/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=4878225018989694288' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/4878225018989694288'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/4878225018989694288'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/sql-server-join-hints.html' title='SQL Server Join Hints'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-5660177943674348956</id><published>2008-11-13T20:54:00.001-08:00</published><updated>2008-11-13T20:55:43.743-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Deadlock'/><title type='text'>Reducing SQL Server Deadlocks</title><content type='html'>When a deadlock occurs, by default, SQL Server choose a deadlock "victim" by identifying which of the two processes will use the least amount of resources to rollback, and then returns error message 1205.&lt;br /&gt;&lt;br /&gt;But what if you don't like default behavior? Can you change it? Yes, you can, by using the following command:&lt;br /&gt;&lt;br /&gt;SET DEADLOCK_PRIORITY { LOW | NORMAL | @deadlock_var }&lt;br /&gt;&lt;br /&gt;Where:&lt;br /&gt;&lt;br /&gt;Low tells SQL Server that the current session should be the preferred deadlock victim, not the session that incurs the least amount of rollback resources. The standard deadlock error message 1205 is returned.&lt;br /&gt;&lt;br /&gt;Normal tells SQL Server to use the default deadlock method.&lt;br /&gt;&lt;br /&gt;@deadlock_var is a character variable specifying which deadlock method you want to use. Specify "3" for low, or "6" for normal.&lt;br /&gt;&lt;br /&gt;This command is set a runtime for a specified user connection. [2000]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-5660177943674348956?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/5660177943674348956/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=5660177943674348956' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5660177943674348956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5660177943674348956'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/reducing-sql-server-deadlocks.html' title='Reducing SQL Server Deadlocks'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-7484164996061787759</id><published>2008-11-12T02:03:00.001-08:00</published><updated>2008-11-13T20:58:21.427-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>The Cost of Function Use In A Where Clause</title><content type='html'>A common mistake made in writing SQL statements is to wrap filtering columns of a WHERE clause inside of a function. SQL server performance is very dependant on SQL's ability to properly use indexes when it retrieves records. The lifeblood of proper query plan creation is using very deterministic filtering logic on indexed columns (Some refer to this as Sargable Where clauses).&lt;br /&gt;&lt;br /&gt;The biggest problem we see is when a filtering column is wrapped inside of a function, the query optimizer does not see the column and if an index exists on that column, the index likely will not be used (of course, just like anything else in our hi-tech world, this is not always the case).&lt;br /&gt;Take this example&lt;br /&gt;&lt;br /&gt;In the CadencedEventCustomer table, we have a nonclustered index on FullName1. The simple query below should use this index and should perform an index seek to find the qualifying records instantly (Seek = FAST).&lt;br /&gt;&lt;br /&gt;    Select&lt;br /&gt;       *&lt;br /&gt;    FROM&lt;br /&gt;       CadencedEventCustomer&lt;br /&gt;    WHERE&lt;br /&gt;       isNull(FullName1,'') = 'Ed Jones'&lt;br /&gt;&lt;br /&gt;Our intention here (albeit incorrect) is to correctly handle records in which the FullName1 field is null. Our concern is that Null records will be missed (more on this later).&lt;br /&gt;&lt;br /&gt;Since we are wrapping the FullName1 column in the IsNull function, the query optimizer doesn't see it and the index is not used.&lt;br /&gt;&lt;br /&gt;Here is the query plan produced by SQL Server's query engine:&lt;br /&gt;&lt;br /&gt;    |--Index Scan(OBJECT:([CIPv3].[dbo].[CadencedEventCustomer].[nci_CadencedEventCustomer_FullName1]), WHERE:(isnull([CIPv3].[dbo].[CadencedEventCustomer].[FullName1],'bob')='Ed Jones')) &lt;br /&gt;&lt;br /&gt;We see an Index Scan on the FullName1 index (the index exists, but a seek cannot be performed due to the function wrapping the indexed column). A Scan means the entire table is being searched from beginning to end until SQL happens to find all the records satisfying the condition. On a table with millions of records, this obviously takes a long time.&lt;br /&gt;&lt;br /&gt;The subtree cost of this query is 10.58. Subtree cost is a relative cost to SQL Server indicating how difficult this query is for SQL Server to retrieve the data. The higher the relative cost, the more of a hit on performance (CPU, IO, RAM, etc). From my experience, anything in the double digit range is getting pretty spendy and will not perform well in a production environment. In this case, the cost is attributed to the inability of the optimizer to use an index which means SQL Server is having to do a full table scan to return all the data for the query result...OUCH.&lt;br /&gt;&lt;br /&gt;If we remove the IsNull() function our query looks like this:&lt;br /&gt;&lt;br /&gt;    Select&lt;br /&gt;       *&lt;br /&gt;    FROM&lt;br /&gt;       CadencedEventCustomer&lt;br /&gt;    WHERE&lt;br /&gt;      FullName1 = 'Ed Jones'&lt;br /&gt;&lt;br /&gt;This is a much cleaner WHERE clause and SQL Server will now see the indexed column and will use the index correctly:&lt;br /&gt;&lt;br /&gt;    |--Index Seek(OBJECT:([CIPv3].[dbo].[CadencedEventCustomer].[nci_CadencedEventCustomer_FullName1]), SEEK:([CIPv3].[dbo].[CadencedEventCustomer].[FullName1]='Ed Jones') ORDERED FORWARD) &lt;br /&gt;&lt;br /&gt;Notice we now have a SEEK (Fast). The query subtree cost is now at 0.0093 !&lt;br /&gt;&lt;br /&gt;Keep in mind, this behavior is true for ALL Functions (Not just IsNull). We should try very hard to not wrap filtering WHERE clause columns within a function.&lt;br /&gt;&lt;br /&gt;Now....as for IsNull. The reason we are using IsNull() in the first place is to return records where the value is null in the column (I recommend not allowing nulls in the database, but that topic is for another article).&lt;br /&gt;&lt;br /&gt;However, if we look closely at this WHERE clause, we can immediately see that the net result of our query (in this case) is identical whether we use the IsNull function or not.&lt;br /&gt;&lt;br /&gt;    Select&lt;br /&gt;       *&lt;br /&gt;    FROM&lt;br /&gt;       CadencedEventCustomer&lt;br /&gt;    WHERE&lt;br /&gt;       isNull(FullName1,'') = 'Ed Jones'&lt;br /&gt;&lt;br /&gt;What this query says is return all records where the FullName1 = 'Ed Jones' and IF the FullName1 column in the database holds a Null Value assume that value is '' (an empty string instead of a Null value).&lt;br /&gt;&lt;br /&gt;So....Null values will be replaced with '' which still does NOT Equal 'Ed Jones'. The net effect is that records with NULL will NOT be returned.&lt;br /&gt;So if we change our query to this:&lt;br /&gt;&lt;br /&gt;    Select&lt;br /&gt;      *&lt;br /&gt;    FROM&lt;br /&gt;      CadencedEventCustomer&lt;br /&gt;    WHERE&lt;br /&gt;       FullName1 = 'Ed Jones'&lt;br /&gt;&lt;br /&gt;We would get exactly the same result.&lt;br /&gt;&lt;br /&gt;So the question is, when DO we need IsNull?&lt;br /&gt;&lt;br /&gt;Well....if the IsNull function is replacing nulls with a value that satisfies the comparison and returns TRUE, then the IsNull function is more useful (still not needed as we'll see below).&lt;br /&gt;&lt;br /&gt;Take this example:&lt;br /&gt;&lt;br /&gt;    Select&lt;br /&gt;       *&lt;br /&gt;    FROM&lt;br /&gt;       CadencedEventCustomer&lt;br /&gt;    WHERE&lt;br /&gt;       isNull(FullName1,'Ed Jones') = 'Ed Jones'&lt;br /&gt;&lt;br /&gt;In this case, if we find Null values in the FullName1 column, we will replace them with 'Ed Jones'. Notice that 'Ed Jones' satisfies our comparison and will return true. So in a sense, this logic is forcing the Query to return Null values instead of filtering them out. In this case, we can argue that the IsNull function is useful.&lt;br /&gt;&lt;br /&gt;Now, having said that, although the IsNull() logic is now useful, the problem is that the column is being hidden from the optimizer and we lose the index relief provided by the index.&lt;br /&gt;&lt;br /&gt;We can rewrite this SQL statement to get the same result AND to still get index relief for the optimizer.&lt;br /&gt;&lt;br /&gt;Essentially what we want is this:&lt;br /&gt;&lt;br /&gt;Select All CadencedEventCustomers Where the FullName1 is 'Ed Jones' OR where the FullName1 is a null value.&lt;br /&gt;&lt;br /&gt;So the correct rewrite to still obtain index relief is as follows:&lt;br /&gt;&lt;br /&gt;    Select&lt;br /&gt;       *&lt;br /&gt;    FROM&lt;br /&gt;       CadencedEventCustomer&lt;br /&gt;    WHERE&lt;br /&gt;       ((FullName1 = 'Ed Jones') OR (FullName1 IS NULL))&lt;br /&gt;&lt;br /&gt;Now we get the best of both worlds. We get the correct logic producing the results we want and SQL servers query engine can see the column so we get index relief.&lt;br /&gt;A few examples other than IsNull()&lt;br /&gt;&lt;br /&gt;I often see the use of Substring() and other string functions used in WHERE Clauses.&lt;br /&gt;Take the following&lt;br /&gt;WHERE SUBSTRING(MasterDealer.Name,4) = 'Ford'&lt;br /&gt;&lt;br /&gt;This is effectively hiding the MasterDealer.Name from the optimizer and is negating the use of any index on the Name column.&lt;br /&gt;The fix&lt;br /&gt;WHERE MasterDealerName Like 'Ford%'&lt;br /&gt;&lt;br /&gt;This produces the exact same result, yet also provides index relief.&lt;br /&gt;Another example working with dates&lt;br /&gt;WHERE DateDiff(mm,PlacedOnQueue,GetDate()) &gt;= 30&lt;br /&gt;&lt;br /&gt;Again, this is a common technique used when working with DateTime data. This is, again, hiding the PlacedOnQueue column from the optimizer.&lt;br /&gt;The fix&lt;br /&gt;WHERE PlacedOnQueue &lt; DateAdd(mm,-30,GetDate())&lt;br /&gt;&lt;br /&gt;The exact same results, yet this time we get index relief.&lt;br /&gt;&lt;br /&gt;Keep in mind, this behavior holds true for all functions wrapping columns in your WHERE clause. So remember anytime you feel a need to wrap a WHERE clause filtering column within a function, try really hard of a way to rewrite the statement without function use.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-7484164996061787759?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/7484164996061787759/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=7484164996061787759' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/7484164996061787759'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/7484164996061787759'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/cost-of-function-use-in-where-clause.html' title='The Cost of Function Use In A Where Clause'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-3048770583043490336</id><published>2008-11-11T22:55:00.000-08:00</published><updated>2008-11-11T23:06:50.667-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><title type='text'>Monitor Database Growth</title><content type='html'>This code provides a way of monitoring the growth of all your databases within a single instance. The first part is the creation of a monitoring table with the initial load of current databases and sizes. The second part is the SQL that can be put in a scheduled job to automate the growth monitoring.&lt;br /&gt;&lt;br /&gt;It is recommended that this job is run weekly or monthly, depending on how fast your databases grow. Also, the code was written for SQL 2005 but can easily be altered for SQL 2000 by changing sys.Master_Files to sysaltfiles and sys.databases to sysdatabases. Make sure to change your column names appropriately if you make this alteration!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span style="font-style:italic;"&gt;Create initial table and checks initial data&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;If exists (Select name from sys.objects where name = 'DBGrowthRate' and Type = 'U')&lt;br /&gt;  Drop Table dbo.DBGrowthRate&lt;br /&gt;&lt;br /&gt;Create Table dbo.DBGrowthRate (DBGrowthID int identity(1,1), DBName varchar(100), DBID int,&lt;br /&gt;NumPages int, OrigSize decimal(10,2), CurSize decimal(10,2), GrowthAmt varchar(100), &lt;br /&gt;MetricDate datetime)&lt;br /&gt;&lt;br /&gt;Select sd.name as DBName, mf.name as FileName, mf.database_id, file_id, size&lt;br /&gt;into #TempDBSize&lt;br /&gt;from sys.databases sd&lt;br /&gt;join sys.master_files mf&lt;br /&gt;on sd.database_ID = mf.database_ID&lt;br /&gt;Order by mf.database_id, sd.name&lt;br /&gt;&lt;br /&gt;Insert into dbo.DBGrowthRate (DBName, DBID, NumPages, OrigSize, CurSize, GrowthAmt, MetricDate)&lt;br /&gt;(Select tds.DBName, tds.database_ID, Sum(tds.Size) as NumPages, &lt;br /&gt;Convert(decimal(10,2),(((Sum(Convert(decimal(10,2),tds.Size)) * 8000)/1024)/1024)) as OrigSize,&lt;br /&gt;Convert(decimal(10,2),(((Sum(Convert(decimal(10,2),tds.Size)) * 8000)/1024)/1024)) as CurSize,&lt;br /&gt;'0.00 MB' as GrowthAmt, GetDate() as MetricDate&lt;br /&gt;from #TempDBSize tds&lt;br /&gt;where tds.database_ID not in (Select Distinct DBID from DBGrowthRate &lt;br /&gt;         where DBName = tds.database_ID)&lt;br /&gt;Group by tds.database_ID, tds.DBName)&lt;br /&gt;&lt;br /&gt;Drop table #TempDBSize&lt;br /&gt;&lt;br /&gt;Select *&lt;br /&gt;from DBGrowthRate&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span style="font-style:italic;"&gt;Code to run weekly to check the growth.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Select sd.name as DBName, mf.name as FileName, mf.database_id, file_id, size&lt;br /&gt;into #TempDBSize2&lt;br /&gt;from sys.databases sd&lt;br /&gt;join sys.master_files mf&lt;br /&gt;on sd.database_ID = mf.database_ID&lt;br /&gt;Order by mf.database_id, sd.name&lt;br /&gt;&lt;br /&gt;If Exists (Select Distinct DBName from #TempDBSize2 &lt;br /&gt;    where DBName in (Select Distinct DBName from DBGrowthRate))&lt;br /&gt; and Convert(varchar(10),GetDate(),101) &gt; (Select Distinct Convert(varchar(10),Max(MetricDate),101) as MetricDate &lt;br /&gt;                    from DBGrowthRate)&lt;br /&gt;  Begin&lt;br /&gt;  Insert into dbo.DBGrowthRate (DBName, DBID, NumPages, OrigSize, CurSize, GrowthAmt, MetricDate)&lt;br /&gt;  (Select tds.DBName, tds.database_ID, Sum(tds.Size) as NumPages, &lt;br /&gt;  dgr.CurSize as OrigSize,&lt;br /&gt;  Convert(decimal(10,2),(((Sum(Convert(decimal(10,2),tds.Size)) * 8000)/1024)/1024)) as CurSize,&lt;br /&gt;  Convert(varchar(100),(Convert(decimal(10,2),(((Sum(Convert(decimal(10,2),tds.Size)) * 8000)/1024)/1024)) &lt;br /&gt;     - dgr.CurSize)) + ' MB' as GrowthAmt, GetDate() as MetricDate&lt;br /&gt;  from #TempDBSize2 tds&lt;br /&gt;  join DBGrowthRate dgr&lt;br /&gt;  on tds.database_ID = dgr.DBID&lt;br /&gt;  Where DBGrowthID = (Select Distinct Max(DBGrowthID) from DBGrowthRate&lt;br /&gt;              where DBID = dgr.DBID)&lt;br /&gt;  Group by tds.database_ID, tds.DBName, dgr.CurSize)&lt;br /&gt;  End&lt;br /&gt; Else&lt;br /&gt;   IF Not Exists (Select Distinct DBName from #TempDBSize2 &lt;br /&gt;    where DBName in (Select Distinct DBName from DBGrowthRate))&lt;br /&gt;  Begin&lt;br /&gt;   Insert into dbo.DBGrowthRate (DBName, DBID, NumPages, OrigSize, CurSize, GrowthAmt, MetricDate)&lt;br /&gt;   (Select tds.DBName, tds.database_ID, Sum(tds.Size) as NumPages, &lt;br /&gt;   Convert(decimal(10,2),(((Sum(Convert(decimal(10,2),tds.Size)) * 8000)/1024)/1024)) as OrigSize,&lt;br /&gt;   Convert(decimal(10,2),(((Sum(Convert(decimal(10,2),tds.Size)) * 8000)/1024)/1024)) as CurSize,&lt;br /&gt;   '0.00 MB' as GrowthAmt, GetDate() as MetricDate&lt;br /&gt;   from #TempDBSize2 tds&lt;br /&gt;   where tds.database_ID not in (Select Distinct DBID from DBGrowthRate &lt;br /&gt;               where DBName = tds.database_ID)&lt;br /&gt;   Group by tds.database_ID, tds.DBName)&lt;br /&gt;  End&lt;br /&gt;&lt;br /&gt;--Select *&lt;br /&gt;--from DBGrowthRate&lt;br /&gt;----Verifies values were entered&lt;br /&gt;&lt;br /&gt;Drop table #TempDBSize2&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-3048770583043490336?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/3048770583043490336/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=3048770583043490336' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3048770583043490336'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/3048770583043490336'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/monitor-database-growth.html' title='Monitor Database Growth'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-488383184114050141</id><published>2008-11-11T22:50:00.000-08:00</published><updated>2008-11-11T23:06:50.668-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><title type='text'>Trace : Who has accessed my SQL 2005 server</title><content type='html'>This script returns login information from the default trace created in SQL Server 2005. When the sys.server_principals data is null that would mean the login is allowed via a Windows Group.&lt;br /&gt;&lt;br /&gt;sys.traces provides the information for the default trace such as the file path and the max files.&lt;br /&gt;&lt;br /&gt;fn_trace_gettable returns the data from trace file(s) in table format.&lt;br /&gt;&lt;br /&gt;sys.server_principals is the way you should access server logins in SQL Server 2005, replacing syslogins.&lt;br /&gt;&lt;br /&gt;An important thing to note is that the default trace will create up to 100MB (5 20MB files) of event data and then begin wrapping. Also it creates a new file when ever the SQL Server is restarted so you may not have the full 100MB of data if you reboot or restart SQL Server often.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT &lt;br /&gt;   I.NTUserName,&lt;br /&gt;   I.loginname,&lt;br /&gt;   I.SessionLoginName,&lt;br /&gt;   I.databasename,&lt;br /&gt;   Min(I.StartTime) as first_used,&lt;br /&gt;   Max(I.StartTime) as last_used,&lt;br /&gt;   S.principal_id,&lt;br /&gt;   S.sid,&lt;br /&gt;   S.type_desc,&lt;br /&gt;   S.name&lt;br /&gt;FROM&lt;br /&gt;   sys.traces T CROSS Apply&lt;br /&gt;   ::fn_trace_gettable(T.path, T.max_files) I LEFT JOIN&lt;br /&gt;   sys.server_principals S ON&lt;br /&gt;       CONVERT(VARBINARY(MAX), I.loginsid) = S.sid  &lt;br /&gt;WHERE&lt;br /&gt;    T.id = 1 And&lt;br /&gt;    I.LoginSid is not null&lt;br /&gt;Group By&lt;br /&gt;   I.NTUserName,&lt;br /&gt;   I.loginname,&lt;br /&gt;   I.SessionLoginName,&lt;br /&gt;   I.databasename,&lt;br /&gt;   S.principal_id,&lt;br /&gt;   S.sid,&lt;br /&gt;   S.type_desc,&lt;br /&gt;   S.name&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;default trace enabled Option&lt;/span&gt;&lt;br /&gt;Use the default trace enabled option to enable or disable the default trace log files. The default trace functionality provides a rich, persistent log of activity and changes primarily related to the configuration options.&lt;br /&gt;&lt;br /&gt;To open the default trace log in the default location:&lt;br /&gt;SELECT * &lt;br /&gt;FROM fn_trace_gettable&lt;br /&gt;('C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\LOG\log.trc', default)&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When set to 1, the default trace enabled option enables Default Trace. The default setting for this option is 1 (ON). A value of 0 turns off the trace.&lt;br /&gt;&lt;br /&gt;The default trace enabled option is an advanced option. If you are using the sp_configure system stored procedure to change the setting, you can change the default trace enabled option only when show advanced options is set to 1. The setting takes effect immediately without a server restart.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-488383184114050141?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/488383184114050141/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=488383184114050141' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/488383184114050141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/488383184114050141'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/trace-who-has-accessed-my-2005-server.html' title='Trace : Who has accessed my SQL 2005 server'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-850466277656603166</id><published>2008-11-11T02:10:00.000-08:00</published><updated>2008-11-13T20:58:21.427-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>Performance Tuning SQL Server's Configuration Settings</title><content type='html'>The default network packet size for clients communicating with SQL Server is 4096 bytes. In most cases, this is the overall best setting. But in some special cases, this SQL Server configuration setting should be changed. If the client regularly transfers large amounts of text or image data to SQL Server, or performs large BCP or DTS operations, then increasing the default size may boost performance because the number of network packets is reduced. On the other hand, if your application only sends and receives small amounts of data, then a smaller packet size can boost responsiveness.&lt;br /&gt;&lt;br /&gt;Keep in mind that client software can overrule this setting in SQL Server. Only try changing this setting if you are very familiar with network traffic analysis and have the ability to test the performance, before and after the change. [6.5, 7.0, 2000, 2005]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-850466277656603166?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/850466277656603166/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=850466277656603166' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/850466277656603166'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/850466277656603166'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/performance-tuning-sql-servers.html' title='Performance Tuning SQL Server&apos;s Configuration Settings'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-554286755631977407</id><published>2008-11-10T03:53:00.001-08:00</published><updated>2008-11-11T23:05:01.424-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><title type='text'>Shrinking databases</title><content type='html'>“Order the pages, shuffle the pages.”&lt;br /&gt;&lt;br /&gt;Do you ever shrink your data files? I’ve personally never been fond of it, especially for production databases. After all, they’ll simply have to grow again and, especially if the data files are on independent drives, there’s little difference between space free on the drive or space free in the data file. There is also a more insidious reason for not shrinking a database.&lt;br /&gt;&lt;br /&gt;Let’s take a very simple database (The creation code is at the end of the post). I have two tables, both with a tens of thousands of rows. Both tables have a clustered index on a uniqueidentifier and are heavily fragmented (&gt;99%).&lt;br /&gt;&lt;br /&gt;DBCC SHOWCONTIG(LargeTable1) -- 99.30%&lt;br /&gt;BCC SHOWCONTIG(LargeTable2) -- 99.21%&lt;br /&gt;&lt;br /&gt;To fix the fragmentation, rebuild both indexes. That fixes the fragmentation, but now the data file is using almost twice the space necessary.&lt;br /&gt;&lt;br /&gt;DBCC ShowFileStats -- 3363 extents total, 1697 used (215 MB total, 106 MB free)&lt;br /&gt;&lt;br /&gt;So, shrink the database to release the wasted space back to the OS&lt;br /&gt;&lt;br /&gt;DBCC SHRINKDATABASE (TestingShrink, 10) -- Shrink to 10% free&lt;br /&gt;&lt;br /&gt;That’s fixed the space issue. But now, have another look at those two indexes that were just rebuilt.&lt;br /&gt;&lt;br /&gt;DBCC SHOWCONTIG(LargeTable1)&lt;br /&gt;- Logical Scan Fragmentation ………………: 99.99%&lt;br /&gt;&lt;br /&gt;DBCC SHOWCONTIG(LargeTable2)&lt;br /&gt;- Logical Scan Fragmentation ………………: 7.08%&lt;br /&gt;&lt;br /&gt;Oops. Not exactly a desired outcome.&lt;br /&gt;&lt;br /&gt;When SQL shrinks a data file, it takes extents that are towards the end of the file and moves them to empty places further forward. It does this with no concern over logical order of pages or indexes. Net result, after shrinking a database, many of the indexes in that database will be badly fragmented.&lt;br /&gt;&lt;br /&gt;For this reason mainly I always recommend that, especially for production databases, the data files get grown as necessary and not shrunk. The space that can be reclaimed from the data file is not worth what the shrink does to page ordering. Especially since, as production databases tend to do, the file will simply be growing again sometime in the future.&lt;br /&gt;&lt;br /&gt;All too often I hear of maintenance plans that first rebuild all the indexes, then shrink the data files. That kind of maintenance is worse than useless. The index rebuild uses cpu and time to arrange indexes in logical order and in the process often grows the data file. The shrink then uses more time and cpu and often will leave the indexes more fragmented than they were before the rebuild.&lt;br /&gt;&lt;br /&gt;Basically, if you’re going to rebuild indexes, don’t shrink the data files. If you’re going to shrink data files, either don’t waste time rebuilding indexes, or do them after the shrink.&lt;br /&gt;&lt;br /&gt;Paul Randal wrote a very nice post on the downsides of shrink, entitled “Turn Auto Shrink Off!” Pretty much says it all.&lt;br /&gt;&lt;br /&gt;Caveat: There are cases where shrinking data files does make sense. When a process created lots of tables for processing then dropped them again, after a massive archiving job, after changing data types in a table to release a large amount of wasted space (more on that another time). Just be aware of the effect of a shrink on the fragmentation of indexes.&lt;br /&gt;&lt;br /&gt;Edit: Some more thoughts from Paul Randal on shrinking databases: Autoshrink. Turn it OFF!&lt;br /&gt;&lt;br /&gt;Sample Code:&lt;br /&gt;&lt;br /&gt;   1. SET NOCOUNT ON  &lt;br /&gt;   2. GO  &lt;br /&gt;   3.   &lt;br /&gt;   4. CREATE DATABASE TestingShrink  &lt;br /&gt;   5. GO  &lt;br /&gt;   6.   &lt;br /&gt;   7. ALTER DATABASE TestingShrink SET RECOVERY SIMPLE  &lt;br /&gt;   8. GO  &lt;br /&gt;   9.   &lt;br /&gt;  10. USE TestingShrink  &lt;br /&gt;  11. GO  &lt;br /&gt;  12.   &lt;br /&gt;  13. Create Table LargeTable1 ( -- row size of ~700 (10 rows per page)  &lt;br /&gt;  14. ID BIGINT,  &lt;br /&gt;  15. SomeString CHAR(600),  &lt;br /&gt;  16. Row_ID UNIQUEIDENTIFIER,  &lt;br /&gt;  17. AValue NUMERIC(30,8),  &lt;br /&gt;  18. RandomDate DATETIME  &lt;br /&gt;  19. )  &lt;br /&gt;  20.   &lt;br /&gt;  21. Create Table LargeTable2 ( -- row size of ~700 (10 rows per page)  &lt;br /&gt;  22. ID BIGINT,  &lt;br /&gt;  23. SomeString CHAR(600),  &lt;br /&gt;  24. Row_ID UNIQUEIDENTIFIER,  &lt;br /&gt;  25. AValue NUMERIC(30,8),  &lt;br /&gt;  26. RandomDate DATETIME  &lt;br /&gt;  27. )  &lt;br /&gt;  28. GO  &lt;br /&gt;  29.   &lt;br /&gt;  30. -- ensuring high fragmentation  &lt;br /&gt;  31. CREATE CLUSTERED INDEX idx_Large1 on LargeTable1 (Row_ID)  &lt;br /&gt;  32. CREATE CLUSTERED INDEX idx_Large2 on LargeTable2 (Row_ID)  &lt;br /&gt;  33. GO  &lt;br /&gt;  34.   &lt;br /&gt;  35. DECLARE @i SMALLINT  &lt;br /&gt;  36. SET @i = 0  &lt;br /&gt;  37. WHILE (@i&lt;8)  &lt;br /&gt;  38. BEGIN  &lt;br /&gt;  39. ;WITH DataPopulate (RowNo, Strng,Uniqueid,Num,ADate) AS (  &lt;br /&gt;  40. SELECT 1 AS RowNo, 'abc' as Strng, NewID() AS Uniqueid, rand()*856542 AS Num, DATEADD(dd, FLOOR(RAND()*75454),'1753/01/01')  &lt;br /&gt;  41. UNION ALL  &lt;br /&gt;  42. SELECT rowNo+1, 'abc' as Strng, NewID() AS Uniqueid, rand(RowNo*25411)*856542 AS Num, DATEADD(dd, FLOOR(RAND(RowNo*96322)*85454),'1753/01/01')  &lt;br /&gt;  43. FROM DataPopulate WHERE RowNo&lt;10000  &lt;br /&gt;  44. )  &lt;br /&gt;  45. INSERT INTO LargeTable1  &lt;br /&gt;  46. SELECT * FROM DataPopulate  &lt;br /&gt;  47. OPTION (MAXRECURSION 10000)  &lt;br /&gt;  48.   &lt;br /&gt;  49. ;WITH DataPopulate (RowNo, Strng,Uniqueid,Num,ADate) AS (  &lt;br /&gt;  50. SELECT 1 AS RowNo, 'abc' as Strng, NewID() AS Uniqueid, rand()*856542 AS Num, DATEADD(dd, FLOOR(RAND()*75454),'1753/01/01')  &lt;br /&gt;  51. UNION ALL  &lt;br /&gt;  52. SELECT rowNo+1, 'abc' as Strng, NewID() AS Uniqueid, rand(RowNo*25411)*856542 AS Num, DATEADD(dd, FLOOR(RAND(RowNo*96322)*85454),'1753/01/01')  &lt;br /&gt;  53. FROM DataPopulate WHERE RowNo&lt;10000  &lt;br /&gt;  54. )  &lt;br /&gt;  55. INSERT INTO LargeTable2  &lt;br /&gt;  56. SELECT * FROM DataPopulate  &lt;br /&gt;  57. OPTION (MAXRECURSION 10000)  &lt;br /&gt;  58. SET @i = @i+1  &lt;br /&gt;  59. END  &lt;br /&gt;  60. GO  &lt;br /&gt;  61.   &lt;br /&gt;  62. DBCC SHOWCONTIG(LargeTable1) -- 99.30%  &lt;br /&gt;  63. DBCC SHOWCONTIG(LargeTable2) -- 99.21%  &lt;br /&gt;  64. DBCC showfilestats -- 2467 extents total, 2463 used (157 MB total, 256kb free)  &lt;br /&gt;  65. GO  &lt;br /&gt;  66. -- Rebuild the indexes. This should grow the database quite a bit.  &lt;br /&gt;  67. Alter Index idx_Large1 on LargeTable1 rebuild  &lt;br /&gt;  68. Alter Index idx_Large2 on LargeTable2 rebuild  &lt;br /&gt;  69. go  &lt;br /&gt;  70.   &lt;br /&gt;  71. DBCC SHOWCONTIG(LargeTable1) -- 0%  &lt;br /&gt;  72. DBCC SHOWCONTIG(LargeTable2) -- 1%  &lt;br /&gt;  73. DBCC ShowFileStats -- 3363 extents total, 1697 used (215 MB total, 106 MB free)  &lt;br /&gt;  74. GO  &lt;br /&gt;  75.   &lt;br /&gt;  76. USE Master  &lt;br /&gt;  77. go  &lt;br /&gt;  78. DBCC SHRINKDATABASE (TestingShrink, 10) -- Shrink to 10% free  &lt;br /&gt;  79. go  &lt;br /&gt;  80. use TestingShrink  &lt;br /&gt;  81. GO  &lt;br /&gt;  82.   &lt;br /&gt;  83. DBCC ShowFileStats -- 1885 extents total, 1695 used (120 MB total, 12 MB free)  &lt;br /&gt;  84. DBCC SHOWCONTIG(LargeTable1) -- 99.99%  &lt;br /&gt;  85. DBCC SHOWCONTIG(LargeTable2) --7.08%  &lt;br /&gt;  86. GO  &lt;br /&gt;  87.   &lt;br /&gt;  88. USE master  &lt;br /&gt;  89. GO  &lt;br /&gt;  90.   &lt;br /&gt;  91. DROP DATABASE TestingShrink  &lt;br /&gt;  92. GO&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-554286755631977407?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/554286755631977407/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=554286755631977407' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/554286755631977407'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/554286755631977407'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/shrinking-databases.html' title='Shrinking databases'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-5148139999839077540</id><published>2008-11-07T01:21:00.000-08:00</published><updated>2008-11-07T01:23:06.461-08:00</updated><title type='text'>Vardecimal Storage Format</title><content type='html'>In Service Pack 2, SQL Server 2005 adds a new storage format for numeric and decimal datatypes called vardecimal. Vardecimal is a variable-length representation for decimal types that can save unused bytes in every instance of the row. The biggest amount of savings come from cases where the decimal definition is large (like decimal(38,6)) but the values stored are small (like a value of 0.0) or there is a large number of repeated values or data is sparsely populated.&lt;br /&gt;&lt;br /&gt;SQL Server 2005 also includes a stored procedure that can estimate the savings before you enable the new storage format.&lt;br /&gt;&lt;br /&gt;master.dbo.sp_estimate_rowsize_reduction_for_vardecimal ‘tablename’&lt;br /&gt;&lt;br /&gt;To enable vardecimal storage format, you need to first allow vardecimal storage on the database;&lt;br /&gt;&lt;br /&gt;exec sys.sp_db_vardecimal_storage_format N'databasename', N'ON'&lt;br /&gt;&lt;br /&gt;Once the database option is enabled, you can then turn on vardecimal storage at a table level using the following procedure;&lt;br /&gt;&lt;br /&gt;exec sp_tableoption 'tablename', 'vardecimal storage format', 1&lt;br /&gt;&lt;br /&gt;Vardecimal storage format presents an overhead due to the complexity inherent in variable length data processing. However in IO bound workloads, savings on IO bandwidth due to efficient storage can far exceed this processing overhead.&lt;br /&gt;&lt;br /&gt;If you would like more information on this topic, updated SQL Server 2005 Books Online for Service Pack 2 contains extensive information on the new vardecimal format.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-5148139999839077540?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/5148139999839077540/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=5148139999839077540' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5148139999839077540'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/5148139999839077540'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/vardecimal-storage-format.html' title='Vardecimal Storage Format'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-7246444034729709892</id><published>2008-11-06T21:38:00.000-08:00</published><updated>2008-11-11T23:06:24.034-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><title type='text'>Figuring out the most popular queries in seconds</title><content type='html'>Sql Server 2005 provides Dynamic Management Views(DMV) that can help save you a lot of work. One excellent and helpful DMV is sys.dm_exec_query_stats. In previous version of SQL Server to find out the highest impact queries on CPU or IO in system, you had to walk through a long set of analyses steps including getting aggregated information out of the data you collected from profiler. &lt;br /&gt;&lt;br /&gt;With sys.dm_exec_query_stats, you can figure out many combinations of query analyses by a single query. Here are some of the examples;&lt;br /&gt;• &lt;br /&gt;&lt;br /&gt;Find queries suffering most from blocking –&lt;br /&gt;(total_elapsed_time – total_worker_time)&lt;br /&gt;• &lt;br /&gt;&lt;br /&gt;Find queries with most CPU cycles –&lt;br /&gt;(total_worker_time)&lt;br /&gt;• &lt;br /&gt;&lt;br /&gt;Find queries with most IO cycles –&lt;br /&gt;(total_physical_reads + total_logical_reads + total_logical_writes)&lt;br /&gt;• &lt;br /&gt;&lt;br /&gt;Find most frequently executed queries –&lt;br /&gt;(execution_count)&lt;br /&gt;• &lt;br /&gt;&lt;br /&gt;You can find more information on how to use dynamic management views for performance troubleshooting in the “SQL Server 2005 Waits and Queues” whitepaper located at: &lt;br /&gt;&lt;a href="http://www.microsoft.com/technet/prodtechnol/sql/bestpractice/performance_tuning_waits_queues.mspx"&gt;http://www.microsoft.com/technet/prodtechnol/sql/bestpractice/performance_tuning_waits_queues.mspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2307145203574942123-7246444034729709892?l=sqlserverteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sqlserverteam.blogspot.com/feeds/7246444034729709892/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2307145203574942123&amp;postID=7246444034729709892' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/7246444034729709892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2307145203574942123/posts/default/7246444034729709892'/><link rel='alternate' type='text/html' href='http://sqlserverteam.blogspot.com/2008/11/figuring-out-most-popular-queries-in.html' title='Figuring out the most popular queries in seconds'/><author><name>Anil Yadav</name><uri>http://www.blogger.com/profile/09905003317091006921</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2307145203574942123.post-2588457578546406488</id><published>2008-11-06T21:09:00.000-08:00</published><updated>2008-11-13T20:58:21.427-08:00</updated><category scheme='http://
