Я нахожусь здесь немного здесь. Моя основная цель - иметь возможность использовать это в C# и Entity Framework, и наша директива от максимума заключается в том, чтобы держаться подальше от хранимых процедур.SQL CTE vs Temp Table
У меня есть 2 стола: стол xref и (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% агентств, и мне нужны все клиенты. Итак, моя загадка:
ПРИМЕЧАНИЕ:
- EntityTypeId = 7 -> Учетная запись пользователя используется для генерации отчетов
- EntityTypeId = 4 -> Клиентского счета
Это занимает 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 секунд для запуска (seve RAL различные перестановки по этому присоединиться!)
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
Любые идеи о том, как получить преимущества из временной таблицы в представление для потребления Entity Framework?
Добавлены определения:
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
2-я точка зрения является то, что мы пытаемся ускорить.
СТОРОНА ПРИМЕЧАНИЕ: Текущая система занимает около 2-3 минут, чтобы вернуть записи. Второе представление или CTE делает это через 40 секунд на основе новой структуры данных (дерево смежности и дерево набора). С временной таблицей 4 секунды.
Интересно, можете ли вы создать образец демо в sqlFiddle, чтобы мы могли что-то работать. Возможно, вам захочется создать более простой пример, чтобы показать ключевую проблему. Кроме того, вопрос о выполнении должен включать 'EXPLAIN PLAN' –
Что такое' GetMyCaseLoad'? Это взгляд или таблица? –
Я не совсем понимаю, что делает CTE для вас, кроме как сделать запрос труднее читать. Я сомневаюсь, что это смущает SQL Server, но, возможно, в какой-то момент в будущем это может запутать вас * или ваших коллег. –