仅使用40K行查看速度慢 - 层次结构类型数据

时间:2017-11-30 05:50:36

标签: sql sql-server

我拼命想要更快地看到我的观点。我正在查看的数据是位置表。每个位置(根节点除外)都有一个ParentID,这是一个自连接。

该表有40K行。我试图添加一个好的覆盖索引。但是当选择单行时,我得到250ms的响应。我已经检查了查询计划,除了很多2%的项目(100%的时间加入)之外,没有任何突出的东西。

为了获得帮助,我创建了一个脚本,用于创建一个非常相似的表格(由于隐私,仅限'描述'更改)。它具有相同的索引和表结构。它也有我使用的相同视图。

视图为每个唯一位置返回一行。 该视图还具有正在查看的位置名称。

该文件包含所有数据 - 所以40K行......并且是4.5Meg。运行时需要4分钟才能插入确切的数据。

我在这里托管了SQL脚本。它是40K线,所以......我认为这是最好的。 https://1drv.ms/u/s!Avhw2DacCYPugsJckaO-Mo9cwNTLpA

无论如何都要让这个观点更快。我真的看着50ms以下 - 希望更少。

我已经想到了一个索引视图,但是当我使用UNION时,我无法做到。如果我使用递归CTE,那就是UNION,所以再一次,不能。我认为我的索引是合适的,但不能提供我需要的性能。

我还有其他方法可以提高视图效果吗?

全部在SQL文件中,但这是主要结构。

folderIdFromCalendar = new FolderId(WellKnownFolderName.Calendar, username);
CalendarFolder calendar = CalendarFolder.Bind(service, folderIdFromCalendar , new PropertySet());

我尝试了这样的CTE,但响应时间似乎已经衰退了。

CREATE TABLE MyLocations 
(
    Id INT NOT NULL PRIMARY KEY,
    ParentId INT NULL,
    Description VARCHAR(100) NOT NULL,
    IsDeleted BIT NOT NULL,
    LocationLevel INT NOT NULL
) 

ALTER TABLE MyLocations ADD CONSTRAINT fk_Loop FOREIGN KEY (ParentId)  REFERENCES MyLocations(Id)

CREATE NONCLUSTERED INDEX [IX_Location_LocationType] ON [dbo].[MyLocations]
(
    [LocationLevel] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

CREATE NONCLUSTERED INDEX [IX_Location_ParentLocationId_INCLUDES] ON [dbo].[MyLocations]
(
    [ParentId] ASC
)
INCLUDE (   [Id],
    [Description],
    [LocationLevel],
    [IsDeleted]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

SET NOCOUNT ON
GO

CREATE VIEW [dbo].[vwMyLocations]
WITH SchemaBinding

AS
    /*
       SELECT * FROM vwMyLocations
    */
    WITH cte AS
    (
    SELECT
        l1.Id as LocationId,
        l1.LocationLevel, 
        l1.ParentId,
        l1.Description AS thisLocationName,
        l1.IsDeleted,
        l1.Description AS Level1, 
        NULL AS Level2, 
        NULL AS Level3,
        NULL AS Level4,
        NULL AS Level5,
        NULL AS Level6,
        NULL AS Level7,
        NULL AS Level8,
        NULL AS Level9,
        NULL AS Level10
    FROM [dbo].MyLocations l1
    WHERE l1.LocationLevel = 1

    UNION ALL 

    SELECT 
        l2.Id AS LocationId,
        l2.LocationLevel,
        l2.ParentId,
        l2.Description AS thisLocationName,
        l1.IsDeleted | l2.IsDeleted, 
        l1.Description AS Level1, 
        l2.Description AS Level2, 
        NULL AS Level3,
        NULL AS Level4,
        NULL AS Level5,
        NULL AS Level6,
        NULL AS Level7,
        NULL AS Level8,
        NULL AS Level9,
        NULL AS Level10
    FROM [dbo].MyLocations l1
    INNER JOIN [dbo].MyLocations l2
        ON l2.ParentId = l1.Id
    WHERE l2.LocationLevel = 2

    UNION ALL

    SELECT 
        l3.Id AS LocationId,
        l3.LocationLevel,
        l3.ParentId,
        l3.Description AS thisLocationName,
        l1.IsDeleted | l2.IsDeleted | l3.IsDeleted,
        l1.Description AS Level1, 
        l2.Description AS Level2, 
        l3.Description AS Level3,
        NULL AS Level4,
        NULL AS Level5,
        NULL AS Level6,
        NULL AS Level7,
        NULL AS Level8,
        NULL AS Level9,
        NULL AS Level10
    FROM [dbo].MyLocations l1
    INNER JOIN [dbo].MyLocations l2
        ON l2.ParentId = l1.Id
    INNER JOIN [dbo].MyLocations l3
        ON l3.ParentId = l2.Id
    WHERE l3.LocationLevel = 3

    UNION ALL

    SELECT 
        l4.Id AS LocationId,
        l4.LocationLevel,
        l4.ParentId,
        l4.Description AS thisLocationName,
        l1.IsDeleted | l2.IsDeleted | l3.IsDeleted | l4.IsDeleted,
        l1.Description AS Level1, 
        l2.Description AS Level2, 
        l3.Description AS Level3,
        l4.Description AS Level4,
        NULL AS Level5,
        NULL AS Level6,
        NULL AS Level7,
        NULL AS Level8,
        NULL AS Level9,
        NULL AS Level10

    FROM [dbo].MyLocations l1
    INNER JOIN [dbo].MyLocations l2
        ON l2.ParentId = l1.Id
    INNER JOIN [dbo].MyLocations l3
        ON l3.ParentId = l2.Id
    INNER JOIN [dbo].MyLocations l4
        ON l4.ParentId = l3.Id
    WHERE l4.LocationLevel = 4

    UNION ALL

    SELECT 
        l5.Id AS LocationId,
        l5.LocationLevel,
        l5.ParentId,
        l5.Description AS thisLocationName,
        l1.IsDeleted | l2.IsDeleted | l3.IsDeleted | l4.IsDeleted | l5.IsDeleted,
        l1.Description AS Level1, 
        l2.Description AS Level2, 
        l3.Description AS Level3,
        l4.Description AS Level4,
        l5.Description AS Level5,
        NULL AS Level6,
        NULL AS Level7,
        NULL AS Level8,
        NULL AS Level9,
        NULL AS Level10

    FROM [dbo].MyLocations l1
    INNER JOIN [dbo].MyLocations l2
        ON l2.ParentId = l1.Id
    INNER JOIN [dbo].MyLocations l3
        ON l3.ParentId = l2.Id
    INNER JOIN [dbo].MyLocations l4
        ON l4.ParentId = l3.Id
    INNER JOIN [dbo].MyLocations l5
        ON l5.ParentId = l4.Id
    WHERE l5.LocationLevel = 5

    UNION ALL

    SELECT 
        l6.Id AS LocationId,
        l6.LocationLevel,
        l6.ParentId,
        l6.Description AS thisLocationName,
        l1.IsDeleted | l2.IsDeleted | l3.IsDeleted | l4.IsDeleted | l5.IsDeleted | l6.IsDeleted,
        l1.Description AS Level1, 
        l2.Description AS Level2, 
        l3.Description AS Level3,
        l4.Description AS Level4,
        l5.Description AS Level5,
        l6.Description AS Level6,
        NULL AS Level7,
        NULL AS Level8,
        NULL AS Level9,
        NULL AS Level10

    FROM [dbo].MyLocations l1
    INNER JOIN [dbo].MyLocations l2
        ON l2.ParentId = l1.Id
    INNER JOIN [dbo].MyLocations l3
        ON l3.ParentId = l2.Id
    INNER JOIN [dbo].MyLocations l4
        ON l4.ParentId = l3.Id
    INNER JOIN [dbo].MyLocations l5
        ON l5.ParentId = l4.Id
    INNER JOIN [dbo].MyLocations l6
        ON l6.ParentId = l5.Id
    WHERE l6.LocationLevel = 6

    UNION ALL

    SELECT 
        l7.Id AS LocationId,
        l7.LocationLevel,
        l7.ParentId,
        l7.Description AS thisLocationName,
        l1.IsDeleted | l2.IsDeleted | l3.IsDeleted | l4.IsDeleted | l5.IsDeleted | l6.IsDeleted | l7.IsDeleted,
        l1.Description AS Level1, 
        l2.Description AS Level2, 
        l3.Description AS Level3,
        l4.Description AS Level4,
        l5.Description AS Level5,
        l6.Description AS Level6,
        l7.Description AS Level7,
        NULL AS Level8,
        NULL AS Level9,
        NULL AS Level10

    FROM [dbo].MyLocations l1
    INNER JOIN [dbo].MyLocations l2
        ON l2.ParentId = l1.Id
    INNER JOIN [dbo].MyLocations l3
        ON l3.ParentId = l2.Id
    INNER JOIN [dbo].MyLocations l4
        ON l4.ParentId = l3.Id
    INNER JOIN [dbo].MyLocations l5
        ON l5.ParentId = l4.Id
    INNER JOIN [dbo].MyLocations l6
        ON l6.ParentId = l5.Id
    INNER JOIN [dbo].MyLocations l7
        ON l7.ParentId = l6.Id
     AND l7.LocationLevel = 7

    UNION ALL

    SELECT 
        l8.Id AS LocationId,
        l8.LocationLevel,
        l8.ParentId,
        l8.Description AS thisLocationName,
        l1.IsDeleted | l2.IsDeleted | l3.IsDeleted | l4.IsDeleted | l5.IsDeleted | l6.IsDeleted | l7.IsDeleted | l8.IsDeleted,
        l1.Description AS Level1, 
        l2.Description AS Level2, 
        l3.Description AS Level3,
        l4.Description AS Level4,
        l5.Description AS Level5,
        l6.Description AS Level6,
        l7.Description AS Level7,
        l8.Description AS Level8,
        NULL AS Level9,
        NULL AS Level10

    FROM [dbo].MyLocations l1
    INNER JOIN [dbo].MyLocations l2
        ON l2.ParentId = l1.Id
    INNER JOIN [dbo].MyLocations l3
        ON l3.ParentId = l2.Id
    INNER JOIN [dbo].MyLocations l4
        ON l4.ParentId = l3.Id
    INNER JOIN [dbo].MyLocations l5
        ON l5.ParentId = l4.Id
    INNER JOIN [dbo].MyLocations l6
        ON l6.ParentId = l5.Id
    INNER JOIN [dbo].MyLocations l7
        ON l7.ParentId = l6.Id
    INNER JOIN [dbo].MyLocations l8
        ON l8.ParentId = l7.Id
    WHERE l8.LocationLevel = 8

    UNION ALL

    SELECT 
        l9.Id AS LocationId,
        l9.LocationLevel,
        l9.ParentId,
        l9.Description AS thisLocationName,
        l1.IsDeleted | l2.IsDeleted | l3.IsDeleted | l4.IsDeleted | l5.IsDeleted | l6.IsDeleted | l7.IsDeleted | l8.IsDeleted | l9.IsDeleted,
        l1.Description AS Level1, 
        l2.Description AS Level2, 
        l3.Description AS Level3,
        l4.Description AS Level4,
        l5.Description AS Level5,
        l6.Description AS Level6,
        l7.Description AS Level7,
        l8.Description AS Level8,
        l9.Description AS Level9,
        NULL AS Level10

    FROM [dbo].MyLocations l1
    INNER JOIN [dbo].MyLocations l2
        ON l2.ParentId = l1.Id
    INNER JOIN [dbo].MyLocations l3
        ON l3.ParentId = l2.Id
    INNER JOIN [dbo].MyLocations l4
        ON l4.ParentId = l3.Id
    INNER JOIN [dbo].MyLocations l5
        ON l5.ParentId = l4.Id
    INNER JOIN [dbo].MyLocations l6
        ON l6.ParentId = l5.Id
    INNER JOIN [dbo].MyLocations l7
        ON l7.ParentId = l6.Id
    INNER JOIN [dbo].MyLocations l8
        ON l8.ParentId = l7.Id
    INNER JOIN [dbo].MyLocations l9
        ON l9.ParentId = l8.Id
    WHERE l9.LocationLevel = 9

    UNION ALL

    SELECT 
        l10.Id AS LocationId,
        l10.LocationLevel,
        l10.ParentId,
        l10.Description AS thisLocationName,
        l1.IsDeleted | l2.IsDeleted | l3.IsDeleted | l4.IsDeleted | l5.IsDeleted | l6.IsDeleted | l7.IsDeleted | l8.IsDeleted | l9.IsDeleted | l10.IsDeleted,
        l1.Description AS Level1, 
        l2.Description AS Level2, 
        l3.Description AS Level3,
        l4.Description AS Level4,
        l5.Description AS Level5,
        l6.Description AS Level6,
        l7.Description AS Level7,
        l8.Description AS Level8,
        l9.Description AS Level9,
        l10.Description AS Level10

    FROM [dbo].MyLocations l1
    INNER JOIN [dbo].MyLocations l2
        ON l2.ParentId = l1.Id
    INNER JOIN [dbo].MyLocations l3
        ON l3.ParentId = l2.Id
    INNER JOIN [dbo].MyLocations l4
        ON l4.ParentId = l3.Id
    INNER JOIN [dbo].MyLocations l5
        ON l5.ParentId = l4.Id
    INNER JOIN [dbo].MyLocations l6
        ON l6.ParentId = l5.Id
    INNER JOIN [dbo].MyLocations l7
        ON l7.ParentId = l6.Id
    INNER JOIN [dbo].MyLocations l8
        ON l8.ParentId = l7.Id
    INNER JOIN [dbo].MyLocations l9
        ON l9.ParentId = l8.Id
    INNER JOIN [dbo].MyLocations l10
        ON l10.ParentId = l9.Id
    WHERE l10.LocationLevel = 10
    )
    SELECT
        cte.LocationId,
        cte.LocationLevel,
        cte.IsDeleted,
        lt.DisplayName,
        cte.ParentId,
        cte.thisLocationName,
        cte.Level1, 
        cte.Level2, 
        cte.Level3,
        cte.Level4,
        cte.Level5,
        cte.Level6,
        cte.Level7,
        cte.Level8,
        cte.Level9,
        cte.Level10
     FROM cte
    INNER JOIN ref.LocationType lt
    ON lt.Id = cte.LocationLevel

GO

2 个答案:

答案 0 :(得分:1)

我认为此处不需要CTE,因此您可以使用INTO子句将所有数据存储在临时中,并从中选择最终查询。我相信它会最大限度地减少时间:但你必须管理它以保持某个地方,最终的查询只会写在视图中。

SELECT
    l1.Id as LocationId,
    l1.LocationLevel, 
    l1.ParentId,
    l1.Description AS thisLocationName,
    l1.IsDeleted,
    l1.Description AS Level1, 
    NULL AS Level2, 
    NULL AS Level3,
    NULL AS Level4,
    NULL AS Level5,
    NULL AS Level6,
    NULL AS Level7,
    NULL AS Level8,
    NULL AS Level9,
    NULL AS Level10
INTO #tmpLocation    
FROM [dbo].MyLocations l1
WHERE l1.LocationLevel = 1
UNION ALL
---------
---------
UNION ALL
--------
--------

最终查询将是:

SELECT
    cte.LocationId,
    cte.LocationLevel,
    cte.IsDeleted,
    lt.DisplayName,
    cte.ParentId,
    cte.thisLocationName,
    cte.Level1, 
    cte.Level2, 
    cte.Level3,
    cte.Level4,
    cte.Level5,
    cte.Level6,
    cte.Level7,
    cte.Level8,
    cte.Level9,
    cte.Level10
FROM #tmpLocation cte
INNER JOIN ref.LocationType lt ON lt.Id = cte.LocationLevel

注意:您还可以在临时表的LocationLevel列上添加索引

答案 1 :(得分:1)

由于你的等级有限,这可能会有所帮助

select  LocationId      = lc1.Id,
    LocationLevel       = lc1.LocationLevel,
    IsDeleted       = lc1.IsDeleted,
    DisplayName     = lt.DisplayName,
    ParentId        = lc1.ParentId,
    thisLocationName    = lc1.Description,
    Level1          = coalesce( case when lc5.LocationLevel = 1 then lc5.Description end,
                        case when lc4.LocationLevel = 1 then lc4.Description end,
                        case when lc3.LocationLevel = 1 then lc3.Description end,
                        case when lc2.LocationLevel = 1 then lc2.Description end,
                        case when lc1.LocationLevel = 1 then lc1.Description end
                        ),
    Level2          = coalesce( case when lc5.LocationLevel = 2 then lc5.Description end,
                        case when lc4.LocationLevel = 2 then lc4.Description end,
                        case when lc3.LocationLevel = 2 then lc3.Description end,
                        case when lc2.LocationLevel = 2 then lc2.Description end,
                        case when lc1.LocationLevel = 2 then lc1.Description end
                        ),
    Level3          = coalesce( case when lc5.LocationLevel = 3 then lc5.Description end,
                        case when lc4.LocationLevel = 3 then lc4.Description end,
                        case when lc3.LocationLevel = 3 then lc3.Description end,
                        case when lc2.LocationLevel = 3 then lc2.Description end,
                        case when lc1.LocationLevel = 3 then lc1.Description end
                        ),
    Level4          = coalesce( case when lc5.LocationLevel = 4 then lc5.Description end,
                        case when lc4.LocationLevel = 4 then lc4.Description end,
                        case when lc3.LocationLevel = 4 then lc3.Description end,
                        case when lc2.LocationLevel = 4 then lc2.Description end,
                        case when lc1.LocationLevel = 4 then lc1.Description end
                        ),
    Level5          = coalesce( case when lc5.LocationLevel = 5 then lc5.Description end,
                        case when lc4.LocationLevel = 5 then lc4.Description end,
                        case when lc3.LocationLevel = 5 then lc3.Description end,
                        case when lc2.LocationLevel = 5 then lc2.Description end,
                        case when lc1.LocationLevel = 5 then lc1.Description end
                        )
from    MyLocations lc1
    left join MyLocations lc2   on  lc1.ParentId        = lc2.Id
    left join MyLocations lc3   on  lc2.ParentId        = lc3.Id
    left join MyLocations lc4   on  lc3.ParentId        = lc4.Id
    left join MyLocations lc5   on  lc4.ParentId        = lc5.Id
    left join MyLocations lc6   on  lc5.ParentId        = lc6.Id
    left join MyLocations lc7   on  lc6.ParentId        = lc7.Id
    left join MyLocations lc8   on  lc7.ParentId        = lc8.Id
    left join MyLocations lc9   on  lc8.ParentId        = lc9.Id
    left join MyLocations lc10  on  lc9.ParentId        = lc10.Id
    inner join LocationType lt  on  lc1.LocationLevel   = lt.Id