【问题标题】:Is there any way to speed up this MSSQL 2012 View?有没有办法加快这个 MSSQL 2012 视图?
【发布时间】:2014-03-04 22:55:51
【问题描述】:

这是视图的声明:

USE [calendar2014]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE view [dbo].[AdminRegisteredCards] WITH SCHEMABINDING as 
    SELECT ISNULL(ROW_NUMBER() 
    OVER (ORDER BY ta.CreatedOn, ta.ItemId), -1000) AS AdminRegisteredCardsId,
    ta.ItemId,
    ta.CardNumber, 
    ta.FirstName, 
    ta.LastName, 
    ta.Birthday, 
    ta.PostalCode, 
    ta.[Description], 
    ta.CardActivated, 
    ta.ContactInfo, 
    ta.PhoneNumber,
    ta.ReceiveCalendarReminders, 
    ta.ReceiveGeneralMails, 
    ta.ReceivePrefStoreMails, 
    ta.CardStatus, 
    ta.SamoaCardId, 
    ta.CalendarUserId, 
    ta.LiveOpsRegistrantId,
    ta.UseType,
    ta.CreatedOn,
    ta.ModifiedBy, 
    ta.ModifiedOn 
    from (
        SELECT CalendarUser.CalendarUserId as ItemId,
        SamoaCard.CardNumber,
        SamoaCard.FirstName,
        SamoaCard.LastName,
        CalendarUser.Birthday,
        CalendarUser.PostalCode,
        RegisterSourceType.[Description],
        CalendarUserCard.CardActivated,
        CalendarUser.EmailAddress as ContactInfo,
        CalendarUser.PhoneNumber,
        CalendarUser.ReceiveCalendarReminders,
        CalendarUser.ReceiveGeneralMails,
        CalendarUser.ReceivePrefStoreMails,
        CASE WHEN CalendarUserCard.CardDeactivated IS NOT NULL THEN 'Deactivated' ELSE 'Activated' END AS CardStatus,
        SamoaCard.SamoaCardId,
        CalendarUser.CalendarUserId,
        null as LiveOpsRegistrantId,
        SamoaCard.CreatedOn,
        'C' as UseType,
        CalendarUser.ModifiedBy,
        CalendarUser.ModifiedOn 
        FROM dbo.CalendarUser CalendarUser
         INNER JOIN dbo.RegisterSourceType RegisterSourceType
          ON CalendarUser.RegisterType = RegisterSourceType.RegisterType
         INNER JOIN dbo.CalendarUserCard CalendarUserCard
          ON CalendarUserCard.CalendarUserId = CalendarUser.CalendarUserId
         INNER JOIN dbo.SamoaCard SamoaCard
          ON CalendarUserCard.SamoaCardId = SamoaCard.SamoaCardId

        UNION ALL

        SELECT LiveOpsRegistrant.LiveOpsRegistrantId as ItemId, 
            LiveOpsRegistrant.CardNumber,
            'Registered' as FirstName,
            'Card' as LastName,
            LiveOpsRegistrant.Birthday,
            null as PostalCode,
            'LiveOps' as Description,
            LiveOpsRegistrant.CreatedOn as CardActivated,
            LiveOpsRegistrant.PhoneNumber as ContactInfo,
            LiveOpsRegistrant.PhoneNumber,
            CONVERT(bit,0) as ReceiveCalendarReminders,
            CONVERT(bit,0) as ReceiveGeneralMails,
            CONVERT(bit,0) as ReceivePrefStoreMails,
            'Activated' AS CardStatus,
            SamoaCard.SamoaCardId,
            null as CalendarUserId,
            LiveOpsRegistrant.LiveOpsRegistrantId,
            SamoaCard.CreatedOn,
            'L' as UseType,
            SamoaCard.ModifiedBy,
            SamoaCard.ModifiedOn
        FROM dbo.LiveOpsRegistrant LiveOpsRegistrant
         INNER JOIN dbo.SamoaCard SamoaCard
          ON LiveOpsRegistrant.CardNumber = SamoaCard.CardNumber
    ) ta;

目前此视图需要非常很长时间才能访问 - 我们有大约 140 万条记录。

有没有办法优化这个视图?

【问题讨论】:

  • @SaUce - 这不太准确。嵌套子查询有可能成为问题。如果 OP 使用的是新版本的 SQL Server,公用表表达式可能会有所帮助。
  • @JustinNiessner:是的,我使用的是 MSSQL 2012。
  • JOIN ON 子句上的额外括号不是必需的,可能会有点混乱。为什么要将ISNULLROW_NUMBER() 一起使用?
  • 不是我格式化了你的代码,而是更容易看到子选择和额外的括号
  • @Serg NickyvV 正在谈论基础表。他们肯定有架构和索引...

标签: sql-server tsql view sql-server-2012 query-optimization


【解决方案1】:
USE [calendar2014]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE view [dbo].[AdminRegisteredCards]


    WITH inCalender AS(
        SELECT CalendarUser.CalendarUserId as ItemId,
        SamoaCard.CardNumber,
        SamoaCard.FirstName,
        SamoaCard.LastName,
        CalendarUser.Birthday,
        CalendarUser.PostalCode,
        RegisterSourceType.[Description],
        CalendarUserCard.CardActivated,
        CalendarUser.EmailAddress as ContactInfo,
        CalendarUser.PhoneNumber,
        CalendarUser.ReceiveCalendarReminders,
        CalendarUser.ReceiveGeneralMails,
        CalendarUser.ReceivePrefStoreMails,
        CASE WHEN CalendarUserCard.CardDeactivated IS NOT NULL THEN 'Deactivated' ELSE 'Activated' END AS CardStatus,
        SamoaCard.SamoaCardId,
        CalendarUser.CalendarUserId,
        null as LiveOpsRegistrantId,
        SamoaCard.CreatedOn,
        'C' as UseType,
        CalendarUser.ModifiedBy,
        CalendarUser.ModifiedOn 
        FROM dbo.CalendarUser CalendarUser
         INNER JOIN dbo.RegisterSourceType RegisterSourceType
          ON CalendarUser.RegisterType = RegisterSourceType.RegisterType
         INNER JOIN dbo.CalendarUserCard CalendarUserCard
          ON CalendarUserCard.CalendarUserId = CalendarUser.CalendarUserId
         INNER JOIN dbo.SamoaCard SamoaCard
          ON CalendarUserCard.SamoaCardId = SamoaCard.SamoaCardId
),inLive AS(

        SELECT LiveOpsRegistrant.LiveOpsRegistrantId as ItemId, 
            LiveOpsRegistrant.CardNumber,
            'Registered' as FirstName,
            'Card' as LastName,
            LiveOpsRegistrant.Birthday,
            null as PostalCode,
            'LiveOps' as Description,
            LiveOpsRegistrant.CreatedOn as CardActivated,
            LiveOpsRegistrant.PhoneNumber as ContactInfo,
            LiveOpsRegistrant.PhoneNumber,
            CONVERT(bit,0) as ReceiveCalendarReminders,
            CONVERT(bit,0) as ReceiveGeneralMails,
            CONVERT(bit,0) as ReceivePrefStoreMails,
            'Activated' AS CardStatus,
            SamoaCard.SamoaCardId,
            null as CalendarUserId,
            LiveOpsRegistrant.LiveOpsRegistrantId,
            SamoaCard.CreatedOn,
            'L' as UseType,
            SamoaCard.ModifiedBy,
            SamoaCard.ModifiedOn
        FROM dbo.LiveOpsRegistrant LiveOpsRegistrant
         INNER JOIN dbo.SamoaCard SamoaCard
          ON LiveOpsRegistrant.CardNumber = SamoaCard.CardNumber
    ) 

    Select 
 ISNULL(ROW_NUMBER() 
    OVER (ORDER BY I.CreatedOn, I.ItemId), -1000) AS AdminRegisteredCardsId,
    I.ItemId,
    I.CardNumber, 
    I.FirstName, 
    I.LastName, 
    I.Birthday, 
    I.PostalCode, 
    I.[Description], 
    I.CardActivated, 
    I.ContactInfo, 
    I.PhoneNumber,
    I.ReceiveCalendarReminders, 
    I.ReceiveGeneralMails, 
    I.ReceivePrefStoreMails, 
    I.CardStatus, 
    I.SamoaCardId, 
    I.CalendarUserId, 
    I.LiveOpsRegistrantId,
    I.UseType,
    I.CreatedOn,
    I.ModifiedBy, 
    I.ModifiedOn 
    from inCalender I Left outer join
    inLive L on I.ItemId = L.CardNumber

注意:
根据我假设我写的。我不知道应该将哪些键用作连接的一部分。可以相应地进行。 如果您得到任何重复记录,请不要感到惊讶,这样您就可以在 select 语句中放置一个 distinct 或使用适当的 join 加入该问题。

【讨论】:

  • 您建议原始查询具有“Union ALL”的“Left Outer Join”?
【解决方案2】:

正如我在 cmets 中提到的,如果你能得到我这些细节,我们将很乐意查看它,看看我们是否可以进一步优化它。意思是这里用较小的例子来说明我打算如何用“FULL OUTER JOIN”替换“UNION ALL”

采用这种方法的原因是这只是一次选择,您不会有任何子查询。因此没有保存内部查询检索到的数据并将其传递给外部查询的开销。

您可以看到,在下面的示例中,我假设我的一条评论是正确的,即“在 SamoaCard 表中,没有任何一行在 SamoaCardId 和 CardNumber 列中同时具有值​​”

    DECLARE @CalendarUserCard TABLE
    (
        SamoaCardId INT NOT NULL
        ,name       sysname NOT NULL
    )

    DECLARE @LiveOpsRegistrant TABLE
    (
         CardNumber             INT NOT NULL
        ,LiveOpsRegistrantId    sysname NOT NULL
    )

    DECLARE @SamoaCard  TABLE
    (
        SamoaCardId     INT NULL
        ,CardNumber         INT NULL

    )

    INSERT INTO @CalendarUserCard ( SamoaCardId, name ) SELECT 1,'CalendarUserCard 1'   UNION ALL SELECT 2,'CalendarUserCard 2'
    INSERT INTO @LiveOpsRegistrant ( CardNumber, LiveOpsRegistrantId ) SELECT 3,'LiveOpsRegistrantId 3' UNION ALL SELECT 4,'LiveOpsRegistrantId 4'
    INSERT INTO @SamoaCard ( SamoaCardId,CardNumber  ) SELECT 1,NULL UNION ALL SELECT 2,NULL UNION ALL SELECT NULL,3 UNION ALL SELECT NULL,4

    SELECT * FROM @CalendarUserCard
    SELECT * FROM @LiveOpsRegistrant
    SELECT * FROM @SamoaCard

    SELECT 
        CASE 
            WHEN SamoaCard.SamoaCardId IS NULL THEN 'Value From LiveOpsRegistrant'
            WHEN SamoaCard.CardNumber IS NULL THEN 'Value From CalendarUserCard'
        END TestAttributeColumn
        ,CASE 
            WHEN SamoaCard.SamoaCardId IS NULL THEN 'Registered'
            WHEN SamoaCard.CardNumber IS NULL THEN CalendarUserCard.name
        END FirstName
        ,CASE 
            WHEN SamoaCard.SamoaCardId IS NULL THEN 'L'
            WHEN SamoaCard.CardNumber IS NULL THEN 'C'
        END UseType
        ,CASE 
            WHEN SamoaCard.SamoaCardId IS NULL THEN LiveOpsRegistrant.LiveOpsRegistrantId
            WHEN SamoaCard.CardNumber IS NULL THEN NULL
        END AS LiveOpsRegistrantId
    FROM @CalendarUserCard CalendarUserCard
    INNER JOIN @SamoaCard SamoaCard
        ON CalendarUserCard.SamoaCardId = SamoaCard.SamoaCardId
    FULL OUTER JOIN @LiveOpsRegistrant LiveOpsRegistrant
        ON SamoaCard.CardNumber = LiveOpsRegistrant.CardNumber

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-03
    • 2020-07-29
    • 1970-01-01
    • 1970-01-01
    • 2020-06-14
    相关资源
    最近更新 更多