ORDER BY и UPDLOCK - A (не) рабочий пример - PullRequest
0 голосов
/ 21 июня 2011

Хотя я не могу раскрыть информацию о реальных таблицах (если бы мог, я бы это сделал), вызывающих проблемы, описанные в моем предыдущем вопросе, я с нуля создал (не) рабочий пример, который воспроизводит точно (тип данных по данным тип, размер столбца по размеру столбца) проблема, с которой я сталкиваюсь. Поэтому я создал новую базу данных с именем «QueueTest» и запустил следующий скрипт:

CREATE TABLE Request
(
    RequestID   BIGINT PRIMARY KEY,
    Priority    TINYINT,
    DateEntered DATETIME
)

CREATE TABLE Options
(
    RequestIDRef    BIGINT PRIMARY KEY,
    SomeOptions     NVARCHAR(MAX)
)

ALTER TABLE Options ADD

    CONSTRAINT FK_REQUESTIDREF FOREIGN KEY ( RequestIDRef ) REFERENCES [Request] ( RequestID )

GO

INSERT INTO Request VALUES ( 1, 2, GETDATE() )
INSERT INTO Request VALUES ( 2, 1, GETDATE() )
INSERT INTO Request VALUES ( 3, 3, GETDATE() )
INSERT INTO Request VALUES ( 4, 2, GETDATE() )

INSERT INTO Options VALUES ( 1, 'Options1' )
INSERT INTO Options VALUES ( 2, 'Options2' )
INSERT INTO Options VALUES ( 3, 'Options3' )
INSERT INTO Options VALUES ( 4, 'Options4' )

CREATE NONCLUSTERED INDEX IX_OPTIONS_REQUESTIDREF ON [Options] ( RequestIDRef )
CREATE NONCLUSTERED INDEX IX_REQUEST_PRIORITY_DATEENTERED ON [Request] ( Priority , DateEntered ) INCLUDE ( RequestID )

После этого я открыл два новых запроса Query1 и Query2 и запустил следующие сценарии для имитации проблемы:

BEGIN TRANSACTION

SELECT TOP 2 RequestID FROM ( Request R WITH ( ROWLOCK , UPDLOCK , READPAST ) INNER JOIN Options O WITH ( ROWLOCK , UPDLOCK , READPAST ) ON ( R.RequestID = O.RequestIDRef ) ) ORDER BY Priority ASC , DateEntered ASC

WAITFOR DELAY '00:00:02.500'

COMMIT TRANSACTION

Результаты, которые я получил, были

Query1 | Query 2
   2   |
   1   |

пока я, конечно, ожидал

Query1 | Query 2
   2   |    4
   1   |    3

Итак, я предполагаю, что, хотя у меня есть индексы, описанные выше, Query1 все еще блокирует всю таблицу. Вот план выполнения для обоих запросов:

План выполнения

StmtText
-----------------------
SET SHOWPLAN_TEXT ON

(1 row(s) affected)

StmtText
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

BEGIN TRANSACTION

SELECT TOP 2 RequestID FROM ( Request R WITH ( ROWLOCK , UPDLOCK , READPAST ) INNER JOIN Options O WITH ( ROWLOCK , UPDLOCK , READPAST ) ON ( R.RequestID = O.RequestIDRef ) ) ORDER BY Priority ASC , DateEntered ASC

(2 row(s) affected)

StmtText
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  |--Top(TOP EXPRESSION:((2)))
       |--Nested Loops(Inner Join, WHERE:([QueueTest].[dbo].[Options].[RequestIDRef] as [O].[RequestIDRef]=[QueueTest].[dbo].[Request].[RequestID] as [R].[RequestID]))
            |--Index Scan(OBJECT:([QueueTest].[dbo].[Request].[IX_REQUEST_PRIORITY_DATEENTERED] AS [R]), ORDERED FORWARD)
            |--Clustered Index Scan(OBJECT:([QueueTest].[dbo].[Options].[PK__Options__5366EEE80BC6C43E] AS [O]))

(4 row(s) affected)

StmtText
---------------------------------

WAITFOR DELAY '00:00:02.500'

COMMIT TRANSACTION

(2 row(s) affected)

Обратите внимание, что когда я выполнил оба запроса с SET SHOWPLAN_TEXT ON, я думаю, что инструкция WAITFOR DELAY не была соблюдена - фактически первый запрос завершился немедленно, поэтому, когда я запустил второй, он уже завершился. *

Что может быть причиной проблемы с блокировкой? Пожалуйста, помогите мне, так как я не могу понять это сам.

Редактировать: Обратите внимание, что я не могу создать вид с помощью инструкции SELECT TOP 2. 2 здесь для иллюстрации, в то время как в реальной ситуации это параметр, передаваемый хранимой процедуре, которая затем запускает эту SELECT. Обратите внимание, что при создании индексированного представления с использованием

SET QUOTED_IDENTIFIER ON
GO

ALTER VIEW TestView WITH SCHEMABINDING AS

    SELECT RequestID , Priority , DateEntered FROM( dbo.Request R INNER JOIN dbo.Options O ON ( R.RequestID = O.RequestIDRef ) )

GO

CREATE UNIQUE CLUSTERED INDEX IX_TESTE_1 ON TestView ( RequestID )
CREATE NONCLUSTERED INDEX IX_TESTE_2 ON TestView ( Priority ASC , DateEntered ASC ) INCLUDE ( RequestID )

, а затем выбор из TestView WITH ( ROWLOCK , UPDLOCK , READPAST ) также не работал ни с, ни без предложения ORDER BY.

1 Ответ

1 голос
/ 21 июня 2011

У вас есть «Сканирование кластерного индекса» и «Сканирование индекса», которое блокирует все строки в обеих таблицах, как я уже говорил в моих предыдущих ответах.

Также из предыдущих ответов:

  1. Использовать индексированное представление
  2. Нет подсказок в просмотр
  3. Добавить подсказку NOEXPAND при вызове представления

Наконец, индекс IX_REQUEST_PRIORITY_DATEENTERED не имеет условия JOIN. Это может удалить один из сканов

Если вы не слушаете бит «view» выше, попробуйте оба этих

CREATE NONCLUSTERED INDEX IX_REQUEST_PRIORITY_DATEENTERED ON [Request]
  (RequestID , Priority , DateEntered )


CREATE NONCLUSTERED INDEX IX_REQUEST_PRIORITY_DATEENTERED ON [Request]
  (Priority , DateEntered , RequestID )
...