簡體   English   中英

具有數百萬條記錄的SQL查詢優化

[英]SQL Query Optimization with million of records

我目前正在使用下面的查詢來獲取基於senderid的記錄。 我在messagein表中有200萬條記錄,並且該表中的條目也與此平行。 但是還需要5秒才能返回結果。 該表僅在Providerid上創建了一個非聚集索引(包括列priorityid,senderid,maskid),任何一位sql專家都可以幫我這個忙。

ALTER PROCEDURE [dbo].[GetNextSmsQueue] @NoOfRow int,
                                        @GatewayId int
AS
    BEGIN TRY
        BEGIN TRAN;
        CREATE TABLE #SmsIn ([Id] [bigint] NOT NULL,
                             [UserId] [bigint] NOT NULL,
                             [MaskId] [varchar](50) NOT NULL,
                             [Number] [varchar](20) NOT NULL,
                             [Message] [nvarchar](1300) NOT NULL,
                             [SenderId] [varchar](20) NOT NULL,
                             [UDH] [nvarchar](50) NULL,
                             [Credit] [int] NOT NULL,
                             [CurrentStatus] [int] NOT NULL,
                             [CheckDND] [bit] NULL,
                             [CheckFail] [bit] NULL,
                             [CheckBlackList] [bit] NULL,
                             [ProviderId] [int] NULL,
                             [PriorityId] [int] NULL,
                             [ScheduleDate] [datetime] NOT NULL,
                             [CreatedDate] [datetime] NOT NULL,
                             [EsmClass] [nvarchar](10) NOT NULL,
                             [DataCoding] [int] NOT NULL,
                             [Priority] [int] NOT NULL,
                             [Interface] [int] NOT NULL);
        DECLARE @PriorityIn table ([PriorityId] [int] NOT NULL);
        DECLARE @COUNT bigint;

        INSERT INTO @PriorityIn
        SELECT PriorityId
        FROM PriorityProviders
        WHERE ProviderId = @GatewayId
          AND Type = 0;

        SELECT @COUNT = COUNT(*)
        FROM MessageIn m
             LEFT JOIN @PriorityIn o ON m.PriorityId = o.PriorityId
        WHERE ((ProviderId IS NULL
            AND o.PriorityId IS NOT NULL)
            OR ProviderId = @GatewayId);

        IF @COUNT > 0
        BEGIN
            INSERT INTO #SmsIn ([Id],
                                [UserId],
                                [MaskId],
                                [Number],
                                [Message],
                                [SenderId],
                                [UDH],
                                [Credit],
                                [CurrentStatus],
                                [CheckDND],
                                [CheckFail],
                                [CheckBlackList],
                                [ProviderId],
                                [PriorityId],
                                [ScheduleDate],
                                [CreatedDate],
                                [EsmClass],
                                [DataCoding],
                                [Priority],
                                [Interface])
            (SELECT [Id],
                    [UserId],
                    [MaskId],
                    [Number],
                    [Message],
                    [SenderId],
                    [UDH],
                    [Credit],
                    [CurrentStatus],
                    [CheckDND],
                    [CheckFail],
                    [CheckBlackList],
                    [ProviderId],
                    [PriorityId],
                    [ScheduleDate],
                    [CreatedDate],
                    [EsmClass],
                    [DataCoding],
                    [Priority],
                    [Interface]
             FROM MessageIn
             WHERE MaskId IN (SELECT MaskId
                              FROM (SELECT ROW_NUMBER() OVER (PARTITION BY SenderId ORDER BY ScheduleDate) AS RowNo,
                                           MaskId
                                    FROM MessageIn msg
                                         LEFT JOIN @PriorityIn o ON msg.PriorityId = o.PriorityId
                                    WHERE ((msg.ProviderId IS NULL
                                        AND o.PriorityId IS NOT NULL)
                                        OR msg.ProviderId = @GatewayId)) res
                              WHERE res.RowNo <= @NoOfRow));

            DELETE msgin
            FROM MessageIn msgin
                 INNER JOIN #SmsIn temp ON msgin.MaskId = temp.MaskId;
        END;
        SELECT *
        FROM #SmsIn;
        DROP TABLE #SmsIn;
        COMMIT;
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0
        BEGIN
            ROLLBACK TRANSACTION;
        END;
    END CATCH;

執行計划在以下位置提供: 執行計划

更新的查詢:

BEGIN TRY
begin tran;
CREATE TABLE #tmpMaskId (MaskId varchar(25) PRIMARY KEY)

INSERT INTO #tmpMaskId(MaskId)
SELECT DISTINCT MaskId From 
(SELECT  ROW_NUMBER() OVER ( PARTITION BY SenderId ORDER BY scheduledate ) AS RowNo, MaskId FROM MessageIn msg 
LEFT JOIN PriorityProviders o on o.ProviderId = @GatewayId AND o.Type = 0 and msg.PriorityId = o.PriorityId
WHERE  
((msg.ProviderId is null AND o.PriorityId is not null) OR msg.ProviderId = @GatewayId)
)as res WHERE res.RowNo <= @NoOfRow

Select [Id],[UserId],m.[MaskId],[Number],[Message],[SenderId],[UDH],[Credit],[CurrentStatus],[CheckDND],[CheckFail],[CheckBlackList],[ProviderId]
      ,[PriorityId],[ScheduleDate],[CreatedDate],[EsmClass],[DataCoding],[Priority],[Interface]
From MessageIn m inner join #tmpMaskId msk on m.MaskId = msk.MaskId

DELETE msgin
FROM MessageIn msgin
INNER JOIN #tmpMaskId temp ON msgin.MaskId=temp.MaskId

DROP TABLE #tmpMaskId
Commit;
END TRY
BEGIN CATCH
     IF @@TRANCOUNT > 0
     BEGIN
        ROLLBACK TRANSACTION;
     END
END CATCH;
ALTER PROCEDURE [dbo].[GetNextSmsQueue]
@NoOfRow    INT
,@GatewayId INT
AS
BEGIN TRY
BEGIN TRAN;

CREATE TABLE #tmpMaskId (MaskId INT PRIMARY KEY)

DECLARE @PriorityIn TABLE ([PriorityId] [INT] NOT NULL)

INSERT INTO @PriorityIn
SELECT PriorityId
FROM PriorityProviders
WHERE ProviderId=@GatewayId AND Type=0

INSERT INTO #tmpMaskId (MaskId)
SELECT DISTINCT MaskId
FROM (
     SELECT ROW_NUMBER() OVER (PARTITION BY SenderId ORDER BY ScheduleDate) AS RowNo
         ,MaskId
     FROM MessageIn msg
     WHERE ((msg.ProviderId IS NULL AND o.PriorityId IS NOT NULL) OR msg.ProviderId=@GatewayId)
     ) res
WHERE res.RowNo<=@NoOfRow

SELECT [Id]
    ,[UserId]
    ,[MaskId]
    ,[Number]
    ,[Message]
    ,[SenderId]
    ,[UDH]
    ,[Credit]
    ,[CurrentStatus]
    ,[CheckDND]
    ,[CheckFail]
    ,[CheckBlackList]
    ,[ProviderId]
    ,[PriorityId]
    ,[ScheduleDate]
    ,[CreatedDate]
    ,[EsmClass]
    ,[DataCoding]
    ,[Priority]
    ,[Interface]
FROM MessageIn mi
WHERE EXISTS (SELECT 1 FROM #tmpMaskId AS tmi WHERE tmi.MaskId=mi.MaskId)

DELETE msgin
FROM MessageIn msgin
INNER JOIN #tmpMaskId temp ON msgin.MaskId=temp.MaskId

COMMIT;
END TRY
BEGIN CATCH
IF @@TRANCOUNT>0 
BEGIN
         ROLLBACK TRANSACTION;
END;
END CATCH;

DROP TABLE #tmpMaskId

IMO,根據您的要求,我將僅從此proc返回記錄以發送短信。成功發送短信后,我僅將Message表中的要求id發送給另一個proc來刪除這些記錄。

從技術上來說聽起來不錯。您現有的proc並不會因為delete而變慢,但是在發送短信並再次嘗試插入之前無法刪除它。

在上一篇文章中,我指出您不需要Join on PriorityProviders。

我已經修改了我的腳本(如果可能的話,請改成INNER),

    SET NOCOUNT ON
    BEGIN TRY
    begin tran;

    CREATE TABLE #tmpMaskId (MaskId varchar(25) not null)

    INSERT INTO #tmpMaskId(MaskId)
    SELECT MaskId From 
    (SELECT  ROW_NUMBER() OVER ( PARTITION BY SenderId ORDER BY scheduledate ) AS RowNo, MaskId FROM MessageIn msg with(nolock)
    LEFT JOIN PriorityProviders with(nolock)
  o on o.ProviderId = msg.ProviderId and o.ProviderId= @GatewayId AND o.Type = 0 and msg.PriorityId = o.PriorityId

    WHERE  
    ((msg.ProviderId is null AND o.PriorityId is not null) OR msg.ProviderId = @GatewayId)
    )as res WHERE res.RowNo <= @NoOfRow

    CREATE TABLE #tmpMaskId (MaskId INT not null)
    create clusetered index ix_mask on #tmpMaskId


    Select [Id],[UserId],m.[MaskId],[Number],[Message],[SenderId],[UDH],[Credit],[CurrentStatus]
    ,[CheckDND],[CheckFail],[CheckBlackList],[ProviderId]
          ,[PriorityId],[ScheduleDate],[CreatedDate],[EsmClass],[DataCoding],[Priority],[Interface]
    From MessageIn m 
    inner join 
    #tmpMaskId msk 
    on m.MaskId = msk.MaskId

    DELETE msgin
    FROM MessageIn msgin
    where exists(select 1 from #tmpMaskId temp where msgin.MaskId=temp.MaskId)

    DROP TABLE #tmpMaskId

    Commit;
    END TRY
    BEGIN CATCH
         IF @@TRANCOUNT > 0
         BEGIN
            ROLLBACK TRANSACTION;
         END
    END CATCH;

請注意,我如何從Temp表中刪除PK並使其成為聚集索引。 我如何刪除distinct

現在的罪魁禍首是這種說法,

ROW_NUMBER() OVER ( PARTITION BY SenderId ORDER BY scheduledate ) AS RowNo

我認為一旦您發表評論,proc就會表現更好。

現在您只需要索引。

無論哪一列的“選擇性最高”,都將該列設為“聚集索引”。

因為我不知道每列的選擇性,所以我不能說應該使composite clustered composite Non clustered index還是composite Non clustered index

如果您選擇Composite Non Clustered index則將ID設為聚集索引(PK),並selective column on left side and so on保留最selective column on left side and so on

Composite Non Clustered index可以是( maskid,ProviderId,SenderId,PriorityId )Include(Resultset中要求的消息表的其他列)

我沒有告訴您刪除Row_number()創建composite non clustered index並重建索引,如上所述。

With (nolock) :與數據重復性無關。 如果沒有機會獲得未提交的數據。 如果消息表中沒有太多並發問題,並且插入/更新不是很頻繁。 然后,您可以安全地使用它。您可以在Google上搜索“ Advantage and disadvantage of with (Nolock )的Advantage and disadvantage of with (Nolock ”。 如果可以改善重要查詢,則可以在一兩個地方使用它。

就像您說的那樣,如果在maskid上創建索引會創建死鎖,這是由於Insert中的腳本錯誤所致。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM