我在这里碰到了一点笨蛋。我的主要目标是能够在C#和Entity Framework中使用它,而我们从高处开始的指令就是远离存储过程。
我有2个表:一个外部参照和一个(Celko)树表。
/**
** Table [dbo].[EntityXref]
**/
IF EXISTS(SELECT * FROM sys.tables WHERE name = N'EntityXref' AND type = N'U')
DROP TABLE [dbo].[EntityXref]
GO
CREATE TABLE dbo.[EntityXref]
( Id BIGINT IDENTITY(1,1) NOT NULL
, EntityId INT NOT NULL
, EntityTypeId INT NOT NULL
, ChildEntityId INT NOT NULL
, ChildEntityTypeId INT NOT NULL
, CONSTRAINT [PK_EntityXref] PRIMARY KEY NONCLUSTERED ([Id] ASC) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
, CONSTRAINT [UQ_EntityXref] UNIQUE CLUSTERED (EntityId, EntityTypeId, ChildEntityId, ChildEntityTypeId)
)
/**
** Table [dbo].[EntityTree]
**/
IF EXISTS(SELECT * FROM sys.tables WHERE name = N'EntityTree' AND type = N'U')
DROP TABLE dbo.EntityTree
GO
CREATE TABLE dbo.EntityTree
( Id BIGINT IDENTITY(1,1) NOT NULL
, SystemId INT NOT NULL DEFAULT 1
, EntityId INT NOT NULL -- could be an AgencyId, UserId, ClientId, VendorId, etc
, EntityTypeId INT NOT NULL -- Defines the entity type
, isActive BIT NOT NULL
, lft BIGINT NOT NULL
, rgt BIGINT NOT NULL
, CONSTRAINT [PK_EntityTree] PRIMARY KEY CLUSTERED ([Id] ASC) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
, CONSTRAINT [UQ_Entity] UNIQUE NONCLUSTERED (EntityId, EntityTypeId)
, CONSTRAINT [UQ_Left] UNIQUE NONCLUSTERED ([lft])
, CONSTRAINT [UQ_LeftRight] UNIQUE NONCLUSTERED ([lft], [rgt])
)
GO
基本树数据如下所示:
客户 - >代理商 - >用户 - >客户端
我们还拥有管理多个代理商的用户,因此也就是外部参照(名称不佳)表。我正在测试一个用户,该用户概述了98%的代理商,我需要所有客户。所以,我的难题是:
注:
这需要4秒才能运行但不能表示为视图:
DECLARE @t TABLE
( childentityid INT
, childentitytypeid INT
)
INSERT INTO @t
SELECT et.RootEntityId, et.RootEntityTypeId
FROM dbo.EntityXref et
WHERE et.EntityId = 17088 AND et.EntityTypeId = 7
SELECT *
FROM @t a
INNER JOIN dbo.GetMyCaseLoad b ON a.RootEntityId = b.ParentEntityId AND a.RootEntityTypeId = b.ParentEntityTypeId
GO
这需要36-40秒才能运行(此连接上有几种不同的排列!)
WITH xrefParent (parentEntityId, parentEntityTypeId) --, rootEntityId, rootEntityTypeId)
AS (SELECT ChildEntityId, ChildEntityTypeId /*, EntityId, EntityTypeId */ FROM dbo.EntityXref WHERE EntityId = 17088 AND EntityTypeId = 7)
SELECT *
FROM GetMyCaseLoad cl
INNER JOIN xrefParent p ON cl.ParentEntityId = p.parentEntityId AND cl.ParentEntityTypeId = p.parentEntityTypeId
-- WHERE p.rootEntityId = 17088 AND p.rootEntityTypeId = 7
GO
有关如何将临时表的好处纳入实体框架消费视图的任何想法?
添加了定义:
CREATE VIEW GetMyCaseLoad AS
SELECT Parent.Id [ParentRecordId]
, Parent.EntityId [ParentEntityId]
, Parent.EntityTypeId [ParentEntityTypeId]
, Child.SystemId [ChildSystemId]
, Child.Id [ChildRecordId]
, Child.EntityId [ChildEntityId]
, Child.EntityTypeId [ChildEntityTypeId]
, Child.isActive [ChildIsActive]
, Child.lft [ChildLeft]
, Child.rgt [ChildRight]
FROM dbo.EntityTree Parent
, dbo.EntityTree Child
WHERE Child.lft > Parent.lft
AND Child.rgt < Parent.rgt
AND Child.EntityTypeId = 4
GO
CREATE VIEW GetMyFullCaseLoad AS
SELECT x.Id [XrefRecordId]
, x.EntityId [XrefParentEntityId]
, x.EntityTypeId [XrefParentEntityTypeId]
, c.ParentRecordId
, c.ParentEntityId
, c.ParentEntityTypeId
, c.ChildRecordId
, c.ChildEntityId
, c.ChildEntityTypeId
, c.ChildIsActive
, c.ChildLeft
, c.ChildRight
, x.CanRead
, x.CanWrite
FROM EntityXref x
INNER JOIN dbo.GetMyCaseLoad c ON x.ChildEntityId = c.ParentEntityId AND x.ChildEntityTypeId = c.ParentEntityTypeId
GO
第二种观点是我们正在努力加快的目标。
SIDE注意:当前系统需要大约2-3分钟才能恢复记录。第二个视图或CTE基于新的数据结构(邻接树与设置树)在40秒内完成。用临时表4秒。
答案 0 :(得分:7)
CTE的问题在于它们没有实现,它们没有专门的统计数据(它们依赖于基础对象的统计数据),它们没有索引(尽管在某些情况下它们可以在引用的表上使用索引。)
临时表的优点是它们本质上是物化的(在tempdb中),它们可以有索引(如果你定义它们),并且绝对有专门的统计数据。
在很多情况下,这意味着使用临时表而不是CTE可以产生更好的执行计划。使用CTE几乎不会加快速度,而很多情况下临时表都会加速。
我会推迟比我更高的权力,并留下他的引用:
永远不应该使用CTE来提高性能。使用CTE几乎不会加快速度,因为它只是一次性视图。你可以用它们做一些巧妙的事情,但加快查询速度并不是其中之一。
此引用来自accepted answer至问题&#34; CTE与临时表之间的区别是什么?&#34;
PS:我看到您在第一个查询中使用了TABLE
变量。这与临时表不同。在性能方面,临时表几乎总是会超过TABLE
变量。有关TABLE
变量和临时表之间差异的优秀文章,请在问题&#34;关于临时表和表变量之间的差异的内容中阅读此accepted answer SQL Server?&#34; 。
答案 1 :(得分:0)
在dbo.EntityXref(EntityId,EntityTypeId)上添加索引?
我猜这是因为这真的是临时表的唯一区别,如果你没有索引,它只会在插入临时表时进行一次扫描。在其他排列中,它可能会成为循环表扫描。
唯一比表扫描更糟的是循环表扫描。