3

SQLServerに次のようなテーブルがあります。

CREATE TABLE [dbo].[FCT_RawEvents](
    [EquipID] [int] NOT NULL,
    [EventTimeStamp] [int] NOT NULL,
    [EventMilliSeconds] [smallint] NULL,
    [EventID] [int] NOT NULL,
    [EventOn] [bit] NOT NULL,
    [JobID] [int] NULL,
    [FirstEvent] [bit] NULL,
    [OperatorId] [int] NULL,
    [Suppressed] [bit] NULL,
    [ManualOverride] [bit] NULL
) 

これには、オンまたはオフのいずれかのイベントが含まれます(EventOn = True、EventOn = False)。次に、特定の時間に「アクティブ」(抑制されていない)のすべてのイベントを取得する必要があります。動作するSQLがいくつかありますが、このテーブルには数百万の行があるため、実行速度がかなり遅くなります(5つのequipIdの場合は10秒)。

ここにあります:

DECLARE @StartDateTime datetime = '2013/01/01'
DECLARE @csvEquipIds nvarchar(MAX) = '5,6,7,8'

DECLARE @StartTimeStamp int = dbo.GetSecondsFromDate(@StartDateTime)
DECLARE @StartMilliSeconds smallint = DATEPART(Ms, @StartDateTime) 

DECLARE @EquipIds TABLE (EquipId int)
INSERT INTO @EquipIds(EquipId) SELECT EquipID FROM dbo.getEquipmentIDs(null,@csvEquipIds)

SELECT dbo.getDateFromSeconds(EventTimeStamp), * FROM
    (   SELECT  re.EquipID,EventTimeStamp,EventMilliSeconds,EventID,eventon,
            ROW_NUMBER() OVER (PARTITION BY re.EquipId,EventID ORDER BY EventTimeStamp DESC,EventMilliSeconds DESC) AS RowNo
        FROM dbo.FCT_RawEvents re
        JOIN @EquipIds eq
        ON eq.EquipId = re.EquipID
        WHERE (re.EventTimeStamp < @StartTimeStamp OR(re.EventTimeStamp = @StartTimeStamp AND re.EventMilliSeconds <= @StartMilliSeconds)) AND re.EventID > 0
        AND (re.Suppressed IS NULL)-- OR re.Suppressed = 0)
    ) ev
WHERE  RowNo = 1  AND EventOn = 1

ORDER BY EquipID,EventID, EventTimeStamp  desc, EventMilliSeconds desc

実行プランは、時間の80%がソートに費やされていることを示しています。これは、パーティション/注文ウィンドウ関数です。

実行計画:

私は決してINDEXの専門家ではありませんが、次のように追加しました。

CREATE CLUSTERED INDEX [IX_Clustered] ON [dbo].[FCT_RawEvents] 
(
    [EquipID] ASC,
    [EventTimeStamp] DESC,
    [EventMilliSeconds] DESC,
    [EventID] ASC,
    [EventOn] DESC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

CREATE NONCLUSTERED INDEX [IX_EquipEventTime] ON [dbo].[FCT_RawEvents] 
(
    [EquipID] ASC,
    [EventID] ASC,
    [EventTimeStamp] DESC,
    [EventMilliSeconds] DESC
)
INCLUDE ( [EventOn]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

CREATE NONCLUSTERED INDEX [IX_Suppressed] ON [dbo].[FCT_RawEvents] 
(
    [Suppressed] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

ソートはテーブルの大部分をスキャンしているようです。最初に一致するイベントが見つかるまで、「振り返って」ください。

インデックスを使用するか、SQLを改善することにより、ポインタをいただければ幸いです。

4

1 に答える 1

1

コメントのフォローアップ:

  • テーブル変数を一時テーブルに置き換えてみてください。テーブル変数には統計がありませんが、一時テーブルには統計があります。

  • 2番目のインデックスは冗長に見えます。

  • スカラー値関数を置き換えてみてください。

  • カラムの選択性を調べます

    EquipID, EventTimeStamp, EventMilliSeconds, EventID, EventOn 
    

選択性の高いものから低いものの順にインデックスを作成します。選択性は、列に重複する値がいくつあるかを示す尺度です。重複なし(選択性が高い)からすべて同じ値(選択性がゼロ)までの範囲です。理想的には、インデックスには選択度の高い順に列が含まれている必要があります。

たとえば、EquipIdカラムの選択性は次のようになります。

(SELECT COUNT(DISTINCT EquipId) FROM dbo.FCT_RawEvents) /
    (SELECT COUNT(*) FROM dbo.FCT_RawEvents)
  • 統計が最新であることを確認してください。
于 2013-01-23T13:12:56.007 に答える