SQL Server NOLOCK and joins - sql

Background: I have a performance-critical query I'd like to run and I don't care about dirty reads.
My question is; If I'm using joins, do I have to specify the NOLOCK hint on those as well?
For instance; is:
SELECT * FROM table1 a WITH (NOLOCK)
INNER JOIN table2 b WITH (NOLOCK) ON a.ID = b.ID
Equivalent to:
SELECT * FROM table1 a WITH (NOLOCK)
INNER JOIN table2 b ON a.ID = b.ID
Or will I need to specify the (NOLOCK) hint on the join to ensure I'm not locking the joined table?

I won't address the READ UNCOMMITTED argument, just your original question.
Yes, you need WITH(NOLOCK) on each table of the join. No, your queries are not the same.
Try this exercise. Begin a transaction and insert a row into table1 and table2. Don't commit or rollback the transaction yet. At this point your first query will return successfully and include the uncommitted rows; your second query won't return because table2 doesn't have the WITH(NOLOCK) hint on it.

I was pretty sure that you need to specify the NOLOCK for each JOIN in the query. But my experience was limited to SQL Server 2005.
When I looked up MSDN just to confirm, I couldn't find anything definite. The below statements do seem to make me think, that for 2008, your two statements above are equivalent though for 2005 it is not the case:
[SQL Server 2008 R2]
All lock hints are propagated to all the tables and views that are accessed by the query plan, including tables and views referenced in a view. Also, SQL Server performs the corresponding lock consistency checks.
[SQL Server 2005]
In SQL Server 2005, all lock hints are propagated to all the tables and views that are referenced in a view. Also, SQL Server performs the corresponding lock consistency checks.
Additionally, point to note - and this applies to both 2005 and 2008:
The table hints are ignored if the table is not accessed by the query plan. This may be caused by the optimizer choosing not to access the table at all, or because an indexed view is accessed instead. In the latter case, accessing an indexed view can be prevented by using the OPTION (EXPAND VIEWS) query hint.

Neither. You set the isolation level to READ UNCOMMITTED which is always better than giving individual lock hints. Or, better still, if you care about details like consistency, use snapshot isolation.

Related

nhibernate two different databases in the same session

When writing sql, I can do
BEGIN Trans t;
SELECT a.name, b.name from db1.dbo.A as a
JOIN db2.dbo.B as b
ON b.aId = a.Id
COMMIT Trans t;
When two databases are on the same database instance.
I am wondering how I can achieve this with database mapping. So that I don't need to create multiple sessions for queries involves different databases.
No, so far I have not seen any other solution then creating a view within one database which does the cross DB query and then use nh mappings on that view, or maybe fully-qualified names. (see duplicate-link below your post).
There is a possibility to do it with DB synonyms. It is not an optimal solution performance-wise, but it might solve your current bind.
SQL Server Synonyms

Does a MERGE INTO statement lock the entire table when merging into a partitioned table based on the partitioned columns?

After some performance issues occurred in our production environment, I asked for assistance from our database administrators. While helping, they informed me that merging locks the table and suggested I use an UPDATE statement instead.
From everything I've read, I was under the impression that MERGE INTO and UPDATE have similar incremental locking patterns. Below is an example of the sort of MERGE INTO statement that our application is using.
MERGE INTO sample_merge_table smt
USING (
SELECT smt.*, sjt.*
FROM sample_merge_table smt
JOIN some_join_table sjt
ON smt.index_value = sjt.secondary_index_value
WHERE smt.partition_index = partitionIndex
) umt ON (smt.partition_index = partitionIndex AND smt.index_value = umt.index_value)
WHEN MATCHED THEN
UPDATE SET...
WHEN NOT MATCHED THEN
INSERT VALUES...
Upon running this statement, what would the locking procedure actually be? Would each table involved in the USING select be locked? Would the sample_merge_table be completely locked, or only the partition that is being accessed? Would the UPDATE statement lock incrementally, or does the MERGE INTO itself already own the required locks?
The merge statement works on a row basis, but locks everything before hand i.e. when the statement execution is finished planing and the affected rows identified.
Readings:
Deleted forum article

SQL Server : subscription : how to know if a table is under replication/subscription

In SQL Server, on the "Subscription side", how can you know if a table is under replication/subscription?
Any idea?
I'm not sure there's a simple answer to this, and I think the answers may vary based on the type of replication. I think you may have to rely on heuristics to answer it.
For snapshot replication, I'm unable to think of anything that would give the game away. Obviously, the presence of the replication tables (e.g. MSreplication_objects) tells you that replication is occurring within the database, but there aren't any specific clues about tables, so far as I'm aware.
For transactional replication (non updating), you may be able to go via MSreplication_objects (which will list some stored procs) and then use sys.sql_dependencies to locate the tables that these relate to
For transaction replication (updating), you can look in MSsubscription_articles (or look for the presence of the subscription updating triggers against the table)
For merge replication, you can look in sysmergearticles, but you'd also have to look in sysmergesubscriptions to determine that you're on the subscription side.
Go to the subscriber database check for the table dbo.MSreplication_subscriptions. If the database is subscriber, you will find this table. Also, to find out articles use this in the subscribed database
SELECT publisher,Publisher_Db,publication,article
FROM dbo.MSreplication_objects
I used Damien the Unbeliever's idea (+1) to produce this code that worked for me
SELECT DISTINCT
ot.object_id
,ot.schema_id
,r.publisher
,r.publisher_db
,r.publication
,r.article
FROM
dbo.MSreplication_objects R
INNER JOIN sys.objects so ON r.object_name = so.name AND so.type = 'P' --stored procedures
INNER JOIN sys.sql_dependencies dp ON so.object_id = dp.object_id
INNER JOIN sys.objects ot ON dp.referenced_major_id = ot.object_id --objects
AND r.article = ot.name
Simplest way would be to create a linked server to the main server and query the table [distribution].[dbo].[MSarticles].
select * from [distribution].[dbo].[MSarticles]
Take a look at DATABASEPROPERTYEX. It has an 'IsSubscribed' option that should do what you want it to do.

Performance of inter-database query (between linked servers)

I have an import between 2 linked servers. I basically got to get the data from a multiple join into a table on my side.
The current query is something like this:
select a.*
from db1.dbo.tbl1 a
inner join db1.dbo.tbl2 on ...
inner join db1.dbo.tbl3 on ...
inner join db1.dbo.tbl4 on ...
inner join db2.dbo.myside on ...
db1 = linked server
db2 = my own database
After this one, I am using an insert into + select to add this data in my table which is located in db2. (usually few hundred records - this import running once a minute)
My question is related to performance. The tables on the linked server (tbl1, tbl2, tbl3, tbl4) are huge tables, with millions of records, and it is slowing down the import process.
I was told that, if I do the join on the "other" side (db1 - linked server) for example in a stored procedure, than, even if the query looks the same, it would run faster. Is that right? This is kinda hard to test. Note that the join contains a table from my database too.
Also. are there other "tricks" I could use in order to make this run faster? Thanks
It really depends on what your query is actually doing. You can use the "remote" hint on the joins to force the join to happen on the linked server. i.e.:
select a.*
from db1.dbo.tbl1 a
inner remote join db1.dbo.tbl2 on ...
inner remote join db1.dbo.tbl3 on ...
inner remote join db1.dbo.tbl4 on ...
inner join db2.dbo.myside on ...
(I assume you left the server out of the above and that all the "db1." references are really "linkedserver.db1".)
If you can do most of the work with just information on the linked server you can use OPENQUERY to speed things up. i.e.:
select a.*
from OPENQUERY(db1, 'SELECT a.* from db1.dbo.tbl1 a
inner join db1.dbo.tbl2 on ...
inner join db1.dbo.tbl3 on ...
inner join db1.dbo.tbl4 on ... ') a
inner join db2.dbo.myside on ...
But the best way to speed it up may be having a control table on the linked server to control what to return, but again it depends on your actual query, what it is doing, and what permissions you have on the linked server.
It is correct to place a stored procedure on db1 to improve performance, this way less data has to go over the pipe, since a lot is filtered in the joins.
If the data on the other side is static, why not place it into a materialized view? This way you only have to update the data once a day instead of each time the query is executed.
Stored procedures are cached, hence the first time you run the stored procedure it will take some time. All further calls to that stored procedure will execute a lot faster. You can see the performance impact by including the execution statistic in your SSMS.
To improve the join performance make sure you have indexes in place.
Notice that cross server inserts are dangerous since you are relying on the network. I'm also not sure whether you can use transactions in this scenario. If not, than it's another problem.
I have seen a scenario where temp database wasn't able to cope with the such an insert, and the fix was to use a cursor. This is was much slower, but more reliable for that scenario.

Using WITH NOLOCK Table Hint in Query Using View - Does it Propagate Within the View?

If a "WITH NOLOCK" query hint is used on a View in SQL Server, does it propagate that hint to the view definition itself, even if NOLOCK is NOT used for the raw tables in the View definition? The reason to need this is that sometimes the support staff wants to do huge time-consuming queries but would rather not force this lock on all queries using the view within the application itself.
Yes, NOLOCK will propagate to the tables used by the view definition (at least in SQL Server 2005).
See Table Hints in MSDN:
In SQL Server 2005, all lock hints are propagated to all the tables and views that are referenced in a view. Also, SQL Server performs the corresponding lock consistency checks.
However,
If a table contains computed columns and the computed columns are computed by expressions or functions accessing columns in other tables, the table hints are not used on those tables. This means the table hints are not propagated. For example, a NOLOCK table hint is specified on a table in the query. This table has computed columns that are computed by a combination of expressions and functions that access columns in another table. The tables referenced by the expressions and functions do not use the NOLOCK table hint when accessed.
If you're using indexed views you might want to read a bit more as there are some special cases there too.
Also see View Resolution for more info.
Just to supplement Rory's excellent answer.
He writes "Yes, NOLOCK will propagate to the tables used by the view definition (at least in SQL Server 2005)."
In fact this will work in SQL 2000 as well.
From BOL:
Because select_statement uses the SELECT statement, it is valid to use and hints as specified in the FROM clause. For more information, see FROM and SELECT.