2011-06-20 52 views
5

2つのテーブルTableATableBには、同時に取得して更新したい情報があります。私はINNER JOINとロック

SELECT TOP 2 SomeFieldA 
FROM TableA WITH (ROWLOCK , UPDLOCK , READPAST) 

すべてが正常に動作し、プロセス2を見ながら、プロセス1は、たとえば、行1および2を見て使用する場合は、行3と4は、これは正常な動作です、と言います。また、EXEC sp_lockを実行すると、2つのKEYエントリしか表示されません。私は

SELECT TOP 2 SomeFieldA 
FROM TableA WITH (ROWLOCK , UPDLOCK , READPAST) 
INNER JOIN 
Table B WITH (ROWLOCK , UPDLOCK , READPAST) 
ON TableA.ID = TableB.IDRef` 

に声明を変更する場合ただし、最初のプロセスは、1行目と2行目を見て、そのプロセス2は何も見ません。 sp_lockを実行すると、すべての行がブロックされたことが示されます。なぜこうなった?

編集:実行計画:

<?xml version="1.0" encoding="utf-16"?> 
<ShowPlanXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.1" Build="10.50.1617.0" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan"> 
    <BatchSequence> 
    <Batch> 
     <Statements> 
     <StmtSimple StatementCompId="2" StatementEstRows="2" StatementId="1" StatementOptmLevel="FULL" StatementOptmEarlyAbortReason="GoodEnoughPlanFound" StatementSubTreeCost="0.00670141" StatementText="SELECT TOP 2 * FROM Request R WITH (ROWLOCK , UPDLOCK , READPAST) INNER JOIN Options O WITH (ROWLOCK , UPDLOCK , READPAST) ON (R.RequestID = O.RequestID)&#xD;&#xA;&#xD;" StatementType="SELECT" QueryHash="0xA35BE09F9DD52334" QueryPlanHash="0x95BEDE8C14AB4C68"> 
      <StatementSetOptions ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="true" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="true" /> 
      <QueryPlan DegreeOfParallelism="1" CachedPlanSize="16" CompileTime="3" CompileCPU="3" CompileMemory="160"> 
      <RelOp AvgRowSize="58" EstimateCPU="2E-07" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="2" LogicalOp="Top" NodeId="0" Parallel="false" PhysicalOp="Top" EstimatedTotalSubtreeCost="0.00670141"> 
       <OutputList> 
       <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Request]" Alias="[R]" Column="RequestID" /> 
       <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Request]" Alias="[R]" Column="DateEntered" /> 
       <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Request]" Alias="[R]" Column="Priority" /> 
       <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Options]" Alias="[O]" Column="RequestID" /> 
       <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Options]" Alias="[O]" Column="SomeOptions" /> 
       </OutputList> 
       <RunTimeInformation> 
       <RunTimeCountersPerThread Thread="0" ActualRows="2" ActualEndOfScans="1" ActualExecutions="1" /> 
       </RunTimeInformation> 
       <Top RowCount="false" IsPercent="false" WithTies="false"> 
       <TopExpression> 
        <ScalarOperator ScalarString="(2)"> 
        <Const ConstValue="(2)" /> 
        </ScalarOperator> 
       </TopExpression> 
       <RelOp AvgRowSize="58" EstimateCPU="7.524E-05" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="2" LogicalOp="Inner Join" NodeId="1" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.00670121"> 
        <OutputList> 
        <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Request]" Alias="[R]" Column="RequestID" /> 
        <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Request]" Alias="[R]" Column="DateEntered" /> 
        <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Request]" Alias="[R]" Column="Priority" /> 
        <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Options]" Alias="[O]" Column="RequestID" /> 
        <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Options]" Alias="[O]" Column="SomeOptions" /> 
        </OutputList> 
        <RunTimeInformation> 
        <RunTimeCountersPerThread Thread="0" ActualRows="2" ActualEndOfScans="0" ActualExecutions="1" /> 
        </RunTimeInformation> 
        <NestedLoops Optimized="false"> 
        <Predicate> 
         <ScalarOperator ScalarString="[TestDatabase].[dbo].[Options].[RequestID] as [O].[RequestID]=[TestDatabase].[dbo].[Request].[RequestID] as [R].[RequestID]"> 
         <Compare CompareOp="EQ"> 
          <ScalarOperator> 
          <Identifier> 
           <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Options]" Alias="[O]" Column="RequestID" /> 
          </Identifier> 
          </ScalarOperator> 
          <ScalarOperator> 
          <Identifier> 
           <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Request]" Alias="[R]" Column="RequestID" /> 
          </Identifier> 
          </ScalarOperator> 
         </Compare> 
         </ScalarOperator> 
        </Predicate> 
        <RelOp AvgRowSize="45" EstimateCPU="0.0001603" EstimateIO="0.003125" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="2" LogicalOp="Clustered Index Scan" NodeId="2" Parallel="false" PhysicalOp="Clustered Index Scan" EstimatedTotalSubtreeCost="0.0032842" TableCardinality="3"> 
         <OutputList> 
         <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Options]" Alias="[O]" Column="RequestID" /> 
         <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Options]" Alias="[O]" Column="SomeOptions" /> 
         </OutputList> 
         <RunTimeInformation> 
         <RunTimeCountersPerThread Thread="0" ActualRows="2" ActualEndOfScans="0" ActualExecutions="1" /> 
         </RunTimeInformation> 
         <IndexScan Ordered="false" ForcedIndex="false" NoExpandHint="false"> 
         <DefinedValues> 
          <DefinedValue> 
          <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Options]" Alias="[O]" Column="RequestID" /> 
          </DefinedValue> 
          <DefinedValue> 
          <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Options]" Alias="[O]" Column="SomeOptions" /> 
          </DefinedValue> 
         </DefinedValues> 
         <Object Database="[TestDatabase]" Schema="[dbo]" Table="[Options]" Index="[PK__Options__33A8519A1DE57479]" Alias="[O]" IndexKind="Clustered" /> 
         </IndexScan> 
        </RelOp> 
        <RelOp AvgRowSize="20" EstimateCPU="8.51E-05" EstimateIO="0.0032035" EstimateRebinds="0" EstimateRewinds="1.33333" EstimateRows="6" LogicalOp="Table Scan" NodeId="3" Parallel="false" PhysicalOp="Table Scan" EstimatedTotalSubtreeCost="0.00340207" TableCardinality="6"> 
         <OutputList> 
         <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Request]" Alias="[R]" Column="RequestID" /> 
         <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Request]" Alias="[R]" Column="DateEntered" /> 
         <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Request]" Alias="[R]" Column="Priority" /> 
         </OutputList> 
         <RunTimeInformation> 
         <RunTimeCountersPerThread Thread="0" ActualRows="8" ActualEndOfScans="1" ActualExecutions="2" /> 
         </RunTimeInformation> 
         <TableScan Ordered="false" ForcedIndex="false" NoExpandHint="false"> 
         <DefinedValues> 
          <DefinedValue> 
          <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Request]" Alias="[R]" Column="RequestID" /> 
          </DefinedValue> 
          <DefinedValue> 
          <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Request]" Alias="[R]" Column="DateEntered" /> 
          </DefinedValue> 
          <DefinedValue> 
          <ColumnReference Database="[TestDatabase]" Schema="[dbo]" Table="[Request]" Alias="[R]" Column="Priority" /> 
          </DefinedValue> 
         </DefinedValues> 
         <Object Database="[TestDatabase]" Schema="[dbo]" Table="[Request]" Alias="[R]" IndexKind="Heap" /> 
         </TableScan> 
        </RelOp> 
        </NestedLoops> 
       </RelOp> 
       </Top> 
      </RelOp> 
      </QueryPlan> 
     </StmtSimple> 
     </Statements> 
    </Batch> 
    </BatchSequence> 
</ShowPlanXML> 

SQL:Query1を上

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

CREATE TABLE Options 
(
    RequestIDRef INT 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, 'a') 
INSERT INTO Options VALUES (2, 'b') 
INSERT INTO Options VALUES (3, 'c') 
INSERT INTO Options VALUES (4, 'd') 

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

さて、

BEGIN TRANSACTION 

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

WAITFOR DELAY '00:00:02.5' 

COMMIT TRANSACTION 

予想通り、2と1を返しますが、上のQuery2は何も返しません。しかし、INNER JOINと2番目のテーブルを削除すると、それは動作し、Query1で(2,1)、Query2で(3,4)を返します。

+0

をカバーしていないため、インデックスは、SELECT *とあまり使用されませんか? –

+0

クエリプランを追加できますか?実際のデータは?そしてインデックス? – gbn

+0

er ...テキストプラン、XMLではありません。 – gbn

答えて

4

論理的には、AとBのデカルト積は交差または一致する行に制限されます。

これらの一致する行を見つけるために、TableA.IDとTableB.IDRefが検索されます。のインデックスがない場合は、テーブルの少なくとも1つにのテーブルスキャンが必要です。すべての行がスキャンのためにロックされます

したがって、TableA.IDとTableB.IDRefの両方にインデックスが必要です。私はTableA.IDが既にPKとして持っているが、TableB.IDRefは持っていないと思う。 ORDER BY and WITH(ROWLOCK, UPDLOCK, READPAST)

TOPはBTW

それはノーORDERなしインデックスとTOPがあり、ここで私の答えに似て、後に適用されます。 ORDER BYを1番目のクエリに追加した場合、2番目のプロセスはあまりにも可能性の高いものを表示しません。

編集:あなたの更新のために、SELECT *は、インデックスの使用を無効にし、スキャンが発生します:彼らは、それぞれのテーブルにあるどのように多くの行

+0

こんにちはgbn、もう一度感謝します。しかし、それはまだ動作しません。私の編集に気づいてください。 –