This article suggests intent locks are used at a higher level of the lock hierarchy to indicate that a lock has been taken on a lower level. The idea of this mechanism is that SQL Server doesn't need to check every row for active locks if it wants to place a lock on a page or table.
As an example, if I update a single row in AdventureWorks:
USE AdventureWorks2014;
BEGIN TRAN;
UPDATE Person.Person
SET LastName = 'Smith'
WHERE BusinessEntityID = 1;
and then in another session, run sp_whoisactive
with get_locks
to see what locks were taken:
EXEC sp_whoisactive @get_locks = 1;
I can see the following:
<Locks>
<Lock resource_type="KEY" index_name="IX_Person_LastName_FirstName_MiddleName" request_mode="X" request_status="GRANT" request_count="2" />
<Lock resource_type="KEY" index_name="PK_Person_BusinessEntityID" request_mode="X" request_status="GRANT" request_count="1" />
<Lock resource_type="OBJECT" request_mode="IX" request_status="GRANT" request_count="1" />
<Lock resource_type="PAGE" page_type="*" index_name="IX_Person_LastName_FirstName_MiddleName" request_mode="IX" request_status="GRANT" request_count="4" />
<Lock resource_type="PAGE" page_type="*" index_name="PK_Person_BusinessEntityID" request_mode="IX" request_status="GRANT" request_count="1" />
</Locks>
this backs up what the article above says - we have an exclusive row (key) lock on the two relevant indexes and therefore the pages and object have IX locks.
If I try and SELECT that row in another session:
SELECT * FROM Person.Person WHERE BusinessEntityID = 1
that query is indeed blocked.
My question therefore is, why is an intent lock a separate thing to a "regular" lock? Why would SQL Server not just place an X lock on the table?