2011-06-20 17 views
5

Tengo dos tablas TableA y TableB que tienen información que quiero recuperar y actualizar al mismo tiempo. Cuando usoINNER JOIN y cerraduras

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

todo funciona bien y el Proceso 1 ve, por ejemplo, las filas 1 y 2, mientras que el Proceso 2 ve, por ejemplo, las filas 3 y 4. Este es el comportamiento esperado. Además, cuando ejecuto EXEC sp_lock veo solo dos entradas KEY. Sin embargo, cuando cambio la declaración a

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

el primer proceso ve filas 1 y 2, pero el proceso 2 ve nada. Ejecutando sp_lock muestra que ahora todas las filas han sido bloqueadas. ¿Por qué está pasando esto?

Editar: plan de Ejecución:

<?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:

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) 

Ahora,

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 

en Consulta1 devuelve 2 y 1, como se esperaba, pero en Query2 no devuelve nada. Sin embargo, si elimino el INNER JOIN y la segunda tabla, funciona y devuelve (2,1) en Query1 y (3,4) en Query2.

+0

¿Cuántas filas hay en cada mesa? –

+0

¿Puede agregar el plan de consulta, por favor? ¿Y datos reales? ¿Y los índices? – gbn

+0

er ... plan de texto, no XML por favor – gbn

Respuesta

4

Lógicamente, el producto cartesiano de A y B está restringido a la intersección o filas coincidentes.

Para encontrar estas filas coincidentes, se examinan TableA.ID y TableB.IDRef. Se requiere una exploración de tabla en al menos una de las tablas si no hay índice. Por lo tanto, todas las filas están bloqueadas para el escaneo

Por lo tanto, tanto TableA.ID como TableB.IDRef necesitan tener índices. Sospecho que TableA.ID ya tiene como PK, pero TableB.IDRef no lo tiene.

la parte superior es aplicado más adelante BTW

Es similar a mi respuesta aquí donde hay TOP sin ORDER BY y ningún índice: ORDER BY and WITH(ROWLOCK, UPDLOCK, READPAST). Si agregó ORDER BY a la primera consulta, entonces el segundo proceso no verá nada demasiado probable.

Editar: para su actualización, SELECT * invalidará el uso de índices y causar exploración: los índices no son de mucha utilidad con SELECT * porque no están cubriendo

+0

Hola gbn, y gracias una vez más. Pero todavía no funciona. Por favor, nota mi edición. –