Every now and then you find a simple way to make everything much faster. We often find customers creating data warehouses or OLAP cubes even though they have a relatively small amount of data (a few gigs) compared to their server memory. If you have more server memory than the size of your database or working set, nearly any aggregate query should run in a second or less. In some situations there may be high traffic on from the transactional application and SQL server may wait for several other queries to run before giving you your results.
The purpose of this is make sure you don’t get two versions of the truth. In an ATM system, you want to give the bank balance after the withdrawal, not before or you may get a very unhappy customer. So by default databases are rightly very conservative about this kind of thing.
Unfortunately this split-second precision comes at a cost. The performance of the query may not be acceptable by today’s standards because the database has to maintain locks on the server. Fortunately, SQL Server gives you a simple way to ask for the current version of the data without the pending transactions. To better facilitate reporting, you can create a view that includes these directives.
CREATE VIEW CategoriesAndProducts AS
SELECT *
FROM dbo.Categories WITH(NOLOCK)
INNER JOIN dbo.Products WITH(NOLOCK) ON dbo.Categories.CategoryID = dbo.Products.CategoryID
In some cases quires that are taking minutes end up taking seconds. Much easier than moving the data to a separate database and it’s still pretty much real time give or take a few milliseconds. You’ve been warned not to use this for bank balances though.

{ 12 comments }
Wouldn't it be simpler to issue a "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED" for the session you want to access read-only, instead of duplicating your query logic with NOLOCK's interspersed?
No, messing with isolation level like that will give you uncommitted data. Why is there a blog post about something this basic in SQL Server? Don't waste our time…
NOLOCK will also give you uncommitted data:
http://msdn.microsoft.com/en-us/library/aa259216(…
READ UNCOMMITTED
"This option has the same effect as setting NOLOCK on all tables in all SELECT statements in a transaction."
NOLOCK will also give you uncommitted data.
http://msdn.microsoft.com/en-us/library/aa259216(…
READ UNCOMMITTED
"This option has the same effect as setting NOLOCK on all tables in all SELECT statements in a transaction."
NOLOCK will also give you uncommitted data.
http://msdn.microsoft.com/en-us/library/aa259216(…
READ UNCOMMITTED
"This option has the same effect as setting NOLOCK on all tables in all SELECT statements in a transaction."
NOLOCK will also give you uncommitted data. http://msdn.microsoft.com/en-us/library/aa259216(…
READ UNCOMMITTED
"This option has the same effect as setting NOLOCK on all tables in all SELECT statements in a transaction."
Thanks for a tip and trick but this is a bit basic thing.
More than that, the practical use of queries with NOLOCK is for example in a data-driven ASP.NET AJAX web application where the data shown to the user in a popup panel must be instantaneous (the panel is triggered when the user is hovering the mouse on a piece of data). In this case a query WITHOUT NOLOCK may be disappointing in terms of speed. This is an issue only with SQL Server. Oracle do not have similar feature to speed up the queries.
Marty, not everyone knows this stuff. I'm an Oracle guy, but I also do some SQL Server stuff every now and then and I'm not as well versed on the SQL Server front. These kind of quick tips come in handy. Nobody likes a smug M.F.
I though if you created a view, MS SQL server would not use indexes, so this may not be good if you want to further restrict the results. I would say just remember to use the with(lock) on all your queries, that do not necessarily need the latest version.
For our Datawarehouse which only refreshes once a day I use the WITH (NOLOCK) extensively. For an OLTP database I would NOT use it. That's it.
I've created a view for a data source and I need to be able to pass one of the filter values into the view.
Has anyone ever done that ?
Thanks,
Doug
Comments on this entry are closed.