[英]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.