Использование LEFT OUTER JOIN с функцией SQL PARTITION (многопользовательская база данных) - PullRequest
0 голосов
/ 23 января 2020

У меня есть следующая схема базы данных.

Профиль [Таблица]

pKey (auto)  
pgKey ('Group' foreign key to separate tenants)  
pProfile (the string data to return) 

HistoryData [Таблица]

hisKey (auto)  
hispKey (foreign key to Profile)  
hisgKey (foreign key to 'Group')  
hisData (the string data to return)    

Количество профилей для одного арендатора составляет 24 874
SELECT COUNT(p.pKey) FROM Profile p WHERE pgKey = 318

Количество строк HistoryData, которые меня интересуют (SeveranceFinal), составляет 16 591
( 10 профилей имеют 2 строки, остальные строки - это отношение 1 к 1 )
SELECT COUNT(h.hisKey) FROM HistoryData h WHERE h.hisgKey = 318 AND h.hisType = 'SeveranceFinal'

Если я напишу запрос, подобный этому:

SELECT COUNT(p.pKey) 
FROM Profile p INNER JOIN HistoryData h ON p.pKey = h.hispKey
WHERE p.pgKey = 318 AND h.hisType = 'SeveranceFinal'

Значение счетчика равно снова 16,591.

Если я напишу этот запрос на внешнее объединение:

SELECT COUNT(p.pKey) 
FROM Profile p LEFT OUTER JOIN ( 
  SELECT * FROM HistoryData WHERE hisType = 'SeveranceFinal' 
) h ON p.pKey = h.hispKey
WHERE p.pgKey = 318

Ожидаемое число будет 24,884 ( 10 больше, чем количество записей профиля из-за 10 человек с двумя строками данных в HistoryData ).

Проблема в том, что мне нужно вернуть всех профилей вместе с любыми соответствующими строками SeveranceFinal, , но только последний SeveranceFinal строка для всех, у кого есть. Количество должно соответствовать исходному количеству профилей, так как у меня всегда было бы 0 или 1 рядов SeveranceFinal, соединенных со строками профиля. Я пробовал этот запрос, но он никогда не завершается, он всегда истекает. Мне кажется, что я что-то не так делаю ( помните, что база данных мультитенантна и в таблице профиля есть миллионы строк, но с разными pgKey значениями )

SELECT COUNT(p.pKey) 
FROM Profile p LEFT OUTER JOIN 
    ( 
        SELECT hispKey, hisData FROM (
            SELECT hispKey, hisData, ROW_NUMBER() OVER (PARTITION BY hispKey ORDER BY hisIndex DESC) RowID 
            FROM HistoryData WHERE hisgKey = 318 AND hisType = 'SeveranceFinal' 
        ) t WHERE RowID = 1
    ) h ON p.pKey = h.hispKey
WHERE p.pgKey = 318

Что не так с запросом?

Примечания:
1. Если я просто выполню часть h этого запроса SELECT hispKey, hisData FROM ( ... ) t WHERE RowID = 1, которая будет возвращена «немедленно».
2. Если я изменю LEFT OUTER JOIN на INNER JOIN и INNER JOIN, он немедленно завершится и вернёт правильное значение 16 581 ( 10 меньше, чем количество строк SeveranceFinal из-за 10 профилей, которые имеют 2 строки )

Вот предлагаемый индекс из плана выполнения:

/*
USE [RBL_Profile]
GO
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[HistoryData] ([hisType],[hisgKey])
INCLUDE ([hispKey],[hisIndex])
GO
*/

Вот отображаемый план выполнения:

enter image description here

Но вот уже мои индексы в таблицах:

** Таблица профиля **

IX_Profile - nonclustered, unique located on PRIMARY: pAuthID, pgKey
IX_Profile_Group - nonclustered located on PRIMARY: pgKey
nc_Profile_GetProfiles - nonclustered located on PRIMARY: pgKey, pAuthID

** Таблица истории **

IX_HistoryData - nonclustered, unique located on PRIMARY: hisType, hispKey, hisIndex
IX_HistoryData_Profile - nonclustered located on PRIMARY: hispKey
PK_HistoryData - nonclustered, unique, primary key located on PRIMARY: hisKey

Следует Я следую совету SQL?

Обновление : я применил предложенный индекс без у пользы кажется. Запрос все еще истекает (или я убил его через 30 секунд)

Вот новый план:

enter image description here

Вот план в Xml:

<?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.4000.0" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan">
  <BatchSequence>
    <Batch>
      <Statements>
        <StmtSimple StatementCompId="1" StatementEstRows="1" StatementId="1" StatementOptmLevel="FULL" StatementOptmEarlyAbortReason="GoodEnoughPlanFound" StatementSubTreeCost="0.0179336" StatementText="SELECT COUNT(p.pKey) &#xD;&#xA;FROM Profile p LEFT OUTER JOIN &#xD;&#xA; ( &#xD;&#xA;        SELECT hispKey, hisData FROM (&#xD;&#xA;            SELECT hispKey, hisData, ROW_NUMBER() OVER (PARTITION BY hispKey ORDER BY hisIndex DESC) RowID &#xD;&#xA;           FROM HistoryData WHERE hisgKey = 318 AND hisType = 'SeveranceFinal' &#xD;&#xA;      ) t WHERE RowID = 1&#xD;&#xA;   ) h ON p.pKey = h.hispKey&#xD;&#xA;WHERE p.pgKey = 318&#xD;&#xA;" StatementType="SELECT" QueryHash="0xFF065B887470862B" QueryPlanHash="0xC85BCB9BD79F6735">
          <StatementSetOptions ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="true" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="true" />
          <QueryPlan CachedPlanSize="32" CompileTime="5" CompileCPU="5" CompileMemory="536">
            <RelOp AvgRowSize="11" EstimateCPU="1.1E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1" LogicalOp="Compute Scalar" NodeId="0" Parallel="false" PhysicalOp="Compute Scalar" EstimatedTotalSubtreeCost="0.0179336">
              <OutputList>
                <ColumnReference Column="Expr1009" />
              </OutputList>
              <ComputeScalar>
                <DefinedValues>
                  <DefinedValue>
                    <ColumnReference Column="Expr1009" />
                    <ScalarOperator ScalarString="CONVERT_IMPLICIT(int,[Expr1013],0)">
                      <Convert DataType="int" Style="0" Implicit="true">
                        <ScalarOperator>
                          <Identifier>
                            <ColumnReference Column="Expr1013" />
                          </Identifier>
                        </ScalarOperator>
                      </Convert>
                    </ScalarOperator>
                  </DefinedValue>
                </DefinedValues>
                <RelOp AvgRowSize="11" EstimateCPU="1.1E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1" LogicalOp="Aggregate" NodeId="1" Parallel="false" PhysicalOp="Stream Aggregate" EstimatedTotalSubtreeCost="0.0179336">
                  <OutputList>
                    <ColumnReference Column="Expr1013" />
                  </OutputList>
                  <StreamAggregate>
                    <DefinedValues>
                      <DefinedValue>
                        <ColumnReference Column="Expr1013" />
                        <ScalarOperator ScalarString="Count(*)">
                          <Aggregate AggType="countstar" Distinct="false" />
                        </ScalarOperator>
                      </DefinedValue>
                    </DefinedValues>
                    <RelOp AvgRowSize="9" EstimateCPU="4.18E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1" LogicalOp="Left Outer Join" NodeId="2" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.0179325">
                      <OutputList />
                      <NestedLoops Optimized="false">
                        <Predicate>
                          <ScalarOperator ScalarString="[RBL_Profile].[dbo].[Profile].[pKey] as [p].[pKey]=[RBL_Profile].[dbo].[HistoryData].[hispKey]">
                            <Compare CompareOp="EQ">
                              <ScalarOperator>
                                <Identifier>
                                  <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[Profile]" Alias="[p]" Column="pKey" />
                                </Identifier>
                              </ScalarOperator>
                              <ScalarOperator>
                                <Identifier>
                                  <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[HistoryData]" Column="hispKey" />
                                </Identifier>
                              </ScalarOperator>
                            </Compare>
                          </ScalarOperator>
                        </Predicate>
                        <RelOp AvgRowSize="11" EstimateCPU="0.0001581" EstimateIO="0.003125" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1" LogicalOp="Index Seek" NodeId="3" Parallel="false" PhysicalOp="Index Seek" EstimatedTotalSubtreeCost="0.0032831" TableCardinality="1371980">
                          <OutputList>
                            <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[Profile]" Alias="[p]" Column="pKey" />
                          </OutputList>
                          <IndexScan Ordered="true" ScanDirection="FORWARD" ForcedIndex="false" ForceSeek="false" ForceScan="false" NoExpandHint="false">
                            <DefinedValues>
                              <DefinedValue>
                                <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[Profile]" Alias="[p]" Column="pKey" />
                              </DefinedValue>
                            </DefinedValues>
                            <Object Database="[RBL_Profile]" Schema="[dbo]" Table="[Profile]" Index="[nc_Profile_GetProfiles]" Alias="[p]" IndexKind="NonClustered" />
                            <SeekPredicates>
                              <SeekPredicateNew>
                                <SeekKeys>
                                  <Prefix ScanType="EQ">
                                    <RangeColumns>
                                      <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[Profile]" Alias="[p]" Column="pgKey" />
                                    </RangeColumns>
                                    <RangeExpressions>
                                      <ScalarOperator ScalarString="(318)">
                                        <Const ConstValue="(318)" />
                                      </ScalarOperator>
                                    </RangeExpressions>
                                  </Prefix>
                                </SeekKeys>
                              </SeekPredicateNew>
                            </SeekPredicates>
                          </IndexScan>
                        </RelOp>
                        <RelOp AvgRowSize="11" EstimateCPU="4.8E-07" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1" LogicalOp="Filter" NodeId="4" Parallel="false" PhysicalOp="Filter" EstimatedTotalSubtreeCost="0.014645">
                          <OutputList>
                            <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[HistoryData]" Column="hispKey" />
                          </OutputList>
                          <Filter StartupExpression="false">
                            <RelOp AvgRowSize="19" EstimateCPU="8E-08" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1" LogicalOp="Compute Scalar" NodeId="5" Parallel="false" PhysicalOp="Sequence Project" EstimatedTotalSubtreeCost="0.0146445">
                              <OutputList>
                                <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[HistoryData]" Column="hispKey" />
                                <ColumnReference Column="Expr1007" />
                              </OutputList>
                              <SequenceProject>
                                <DefinedValues>
                                  <DefinedValue>
                                    <ColumnReference Column="Expr1007" />
                                    <ScalarOperator ScalarString="row_number">
                                      <Sequence FunctionName="row_number" />
                                    </ScalarOperator>
                                  </DefinedValue>
                                </DefinedValues>
                                <RelOp AvgRowSize="19" EstimateCPU="2E-08" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1" LogicalOp="Segment" NodeId="6" Parallel="false" PhysicalOp="Segment" EstimatedTotalSubtreeCost="0.0146444">
                                  <OutputList>
                                    <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[HistoryData]" Column="hispKey" />
                                    <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[HistoryData]" Column="hisIndex" />
                                    <ColumnReference Column="Segment1012" />
                                  </OutputList>
                                  <Segment>
                                    <GroupBy>
                                      <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[HistoryData]" Column="hispKey" />
                                    </GroupBy>
                                    <SegmentColumn>
                                      <ColumnReference Column="Segment1012" />
                                    </SegmentColumn>
                                    <RelOp AvgRowSize="22" EstimateCPU="0.000100022" EstimateIO="0.0112613" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1" LogicalOp="Sort" NodeId="7" Parallel="false" PhysicalOp="Sort" EstimatedTotalSubtreeCost="0.0146444">
                                      <OutputList>
                                        <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[HistoryData]" Column="hispKey" />
                                        <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[HistoryData]" Column="hisIndex" />
                                      </OutputList>
                                      <MemoryFractions Input="1" Output="1" />
                                      <Sort Distinct="false">
                                        <OrderBy>
                                          <OrderByColumn Ascending="true">
                                            <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[HistoryData]" Column="hispKey" />
                                          </OrderByColumn>
                                          <OrderByColumn Ascending="false">
                                            <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[HistoryData]" Column="hisIndex" />
                                          </OrderByColumn>
                                        </OrderBy>
                                        <RelOp AvgRowSize="22" EstimateCPU="0.0001581" EstimateIO="0.003125" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1" LogicalOp="Index Seek" NodeId="8" Parallel="false" PhysicalOp="Index Seek" EstimatedTotalSubtreeCost="0.0032831" TableCardinality="29897300">
                                          <OutputList>
                                            <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[HistoryData]" Column="hispKey" />
                                            <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[HistoryData]" Column="hisIndex" />
                                          </OutputList>
                                          <IndexScan Ordered="true" ScanDirection="FORWARD" ForcedIndex="false" ForceSeek="false" ForceScan="false" NoExpandHint="false">
                                            <DefinedValues>
                                              <DefinedValue>
                                                <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[HistoryData]" Column="hispKey" />
                                              </DefinedValue>
                                              <DefinedValue>
                                                <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[HistoryData]" Column="hisIndex" />
                                              </DefinedValue>
                                            </DefinedValues>
                                            <Object Database="[RBL_Profile]" Schema="[dbo]" Table="[HistoryData]" Index="[IX_HistoryData_Group]" IndexKind="NonClustered" />
                                            <SeekPredicates>
                                              <SeekPredicateNew>
                                                <SeekKeys>
                                                  <Prefix ScanType="EQ">
                                                    <RangeColumns>
                                                      <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[HistoryData]" Column="hisType" />
                                                      <ColumnReference Database="[RBL_Profile]" Schema="[dbo]" Table="[HistoryData]" Column="hisgKey" />
                                                    </RangeColumns>
                                                    <RangeExpressions>
                                                      <ScalarOperator ScalarString="'SeveranceFinal'">
                                                        <Const ConstValue="'SeveranceFinal'" />
                                                      </ScalarOperator>
                                                      <ScalarOperator ScalarString="(318)">
                                                        <Const ConstValue="(318)" />
                                                      </ScalarOperator>
                                                    </RangeExpressions>
                                                  </Prefix>
                                                </SeekKeys>
                                              </SeekPredicateNew>
                                            </SeekPredicates>
                                          </IndexScan>
                                        </RelOp>
                                      </Sort>
                                    </RelOp>
                                  </Segment>
                                </RelOp>
                              </SequenceProject>
                            </RelOp>
                            <Predicate>
                              <ScalarOperator ScalarString="[Expr1007]=(1)">
                                <Compare CompareOp="EQ">
                                  <ScalarOperator>
                                    <Identifier>
                                      <ColumnReference Column="Expr1007" />
                                    </Identifier>
                                  </ScalarOperator>
                                  <ScalarOperator>
                                    <Const ConstValue="(1)" />
                                  </ScalarOperator>
                                </Compare>
                              </ScalarOperator>
                            </Predicate>
                          </Filter>
                        </RelOp>
                      </NestedLoops>
                    </RelOp>
                  </StreamAggregate>
                </RelOp>
              </ComputeScalar>
            </RelOp>
          </QueryPlan>
        </StmtSimple>
      </Statements>
    </Batch>
  </BatchSequence>
</ShowPlanXML>

1 Ответ

0 голосов
/ 23 января 2020

Можете ли вы попробовать больше установить запрос:

WITH FilteredHistoryData AS (
    SELECT hispKey, hisIndex
    FROM HistoryData
    WHERE hisgKey = 318 
        AND hisType = 'SeveranceFinal'
)

SELECT p.pKey, h.hisIndex LatestIndex
FROM Profile p
LEFT JOIN FilteredHistoryData h
    ON p.pKey = h.hispKey
LEFT JOIN FilteredHistoryData h_fresher
    ON h.hispKey = h_fresher.hispKey
    AND h_fresher.hisIndex > h.hisIndex
WHERE h_fresher.hispKey IS NULL
    AND p.pgKey = 318
...