171 lines
7.1 KiB
Transact-SQL
171 lines
7.1 KiB
Transact-SQL
SET ANSI_NULLS ON;
|
|
GO
|
|
SET QUOTED_IDENTIFIER ON;
|
|
GO
|
|
|
|
/*
|
|
Focused optimisation for dbo.AssetTimeline_GetByProject.
|
|
|
|
Diagnosis:
|
|
- Recent timeline logging showed this procedure at ~12 seconds after it had
|
|
previously been ~18-40 ms.
|
|
- The current procedure joins StoryAssets, AssetEvents, Scenes, Chapters,
|
|
Books, AssetKinds, AssetEventTypes, AssetStates, and LocationPaths.
|
|
- The first result set expands the recursive LocationPaths view for asset
|
|
locations; the second result set can be vulnerable to a poor cached plan
|
|
around the optional @BookID predicate.
|
|
- This rewrite mirrors the safer CharacterTimeline shape: filter project/book
|
|
scenes once, filter active project assets once, and materialise project
|
|
location paths once before joining.
|
|
*/
|
|
|
|
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_StoryAssets_Project_TimelineList' AND object_id = OBJECT_ID(N'dbo.StoryAssets'))
|
|
BEGIN
|
|
-- Supports project-scoped asset timeline list filtering and ordering.
|
|
CREATE INDEX IX_StoryAssets_Project_TimelineList
|
|
ON dbo.StoryAssets(ProjectID, IsArchived, IsResolved, Importance DESC, AssetName);
|
|
END;
|
|
GO
|
|
|
|
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_AssetEvents_StoryAssetID_SceneID' AND object_id = OBJECT_ID(N'dbo.AssetEvents'))
|
|
BEGIN
|
|
-- Supports asset-event reads after project assets have been filtered.
|
|
CREATE INDEX IX_AssetEvents_StoryAssetID_SceneID
|
|
ON dbo.AssetEvents(StoryAssetID, SceneID, AssetEventTypeID);
|
|
END;
|
|
GO
|
|
|
|
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_Locations_Project_Parent_Name' AND object_id = OBJECT_ID(N'dbo.Locations'))
|
|
BEGIN
|
|
-- Supports project-scoped location path materialisation for asset current locations.
|
|
CREATE INDEX IX_Locations_Project_Parent_Name
|
|
ON dbo.Locations(ProjectID, IsArchived, ParentLocationID, LocationName);
|
|
END;
|
|
GO
|
|
|
|
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_Locations_ParentLocationID' AND object_id = OBJECT_ID(N'dbo.Locations'))
|
|
BEGIN
|
|
-- Supports recursive location path expansion from parent to child locations.
|
|
CREATE INDEX IX_Locations_ParentLocationID
|
|
ON dbo.Locations(ParentLocationID, IsArchived, LocationName);
|
|
END;
|
|
GO
|
|
|
|
IF EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_StoryAssets_Project_TimelineList' AND object_id = OBJECT_ID(N'dbo.StoryAssets'))
|
|
BEGIN
|
|
UPDATE STATISTICS dbo.StoryAssets IX_StoryAssets_Project_TimelineList;
|
|
END;
|
|
GO
|
|
|
|
IF EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_AssetEvents_StoryAssetID_SceneID' AND object_id = OBJECT_ID(N'dbo.AssetEvents'))
|
|
BEGIN
|
|
UPDATE STATISTICS dbo.AssetEvents IX_AssetEvents_StoryAssetID_SceneID;
|
|
END;
|
|
GO
|
|
|
|
IF EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_AssetEvents_SceneID' AND object_id = OBJECT_ID(N'dbo.AssetEvents'))
|
|
BEGIN
|
|
UPDATE STATISTICS dbo.AssetEvents IX_AssetEvents_SceneID;
|
|
END;
|
|
GO
|
|
|
|
CREATE OR ALTER PROCEDURE dbo.AssetTimeline_GetByProject
|
|
@ProjectID int,
|
|
@BookID int = NULL
|
|
AS
|
|
BEGIN
|
|
SET NOCOUNT ON;
|
|
|
|
CREATE TABLE #TimelineScenes
|
|
(
|
|
SceneID int NOT NULL PRIMARY KEY,
|
|
BookSortOrder int NOT NULL,
|
|
ChapterSortOrder int NOT NULL,
|
|
SceneSortOrder int NOT NULL
|
|
);
|
|
|
|
INSERT #TimelineScenes (SceneID, BookSortOrder, ChapterSortOrder, SceneSortOrder)
|
|
SELECT s.SceneID, b.SortOrder, c.SortOrder, s.SortOrder
|
|
FROM dbo.Books b
|
|
INNER JOIN dbo.Chapters c ON c.BookID = b.BookID
|
|
INNER JOIN dbo.Scenes s ON s.ChapterID = c.ChapterID
|
|
WHERE b.ProjectID = @ProjectID
|
|
AND b.IsArchived = 0
|
|
AND c.IsArchived = 0
|
|
AND s.IsArchived = 0
|
|
AND (@BookID IS NULL OR b.BookID = @BookID)
|
|
OPTION (RECOMPILE);
|
|
|
|
CREATE TABLE #ProjectAssets
|
|
(
|
|
StoryAssetID int NOT NULL PRIMARY KEY,
|
|
ProjectID int NOT NULL,
|
|
AssetName nvarchar(200) NOT NULL,
|
|
AssetKindID int NOT NULL,
|
|
Description nvarchar(max) NULL,
|
|
Importance int NOT NULL,
|
|
CurrentStateID int NULL,
|
|
CurrentLocationID int NULL,
|
|
IsResolved bit NOT NULL,
|
|
CreatedDate datetime2 NOT NULL,
|
|
UpdatedDate datetime2 NOT NULL,
|
|
IsArchived bit NOT NULL
|
|
);
|
|
|
|
INSERT #ProjectAssets (StoryAssetID, ProjectID, AssetName, AssetKindID, Description, Importance, CurrentStateID, CurrentLocationID, IsResolved, CreatedDate, UpdatedDate, IsArchived)
|
|
SELECT StoryAssetID, ProjectID, AssetName, AssetKindID, Description, Importance, CurrentStateID, CurrentLocationID, IsResolved, CreatedDate, UpdatedDate, IsArchived
|
|
FROM dbo.StoryAssets
|
|
WHERE ProjectID = @ProjectID
|
|
AND IsArchived = 0
|
|
OPTION (RECOMPILE);
|
|
|
|
CREATE TABLE #ProjectLocationPaths
|
|
(
|
|
LocationID int NOT NULL PRIMARY KEY,
|
|
LocationName nvarchar(200) NOT NULL,
|
|
LocationPath nvarchar(max) NOT NULL
|
|
);
|
|
|
|
;WITH ProjectLocationTree AS
|
|
(
|
|
SELECT LocationID, LocationName, CAST(LocationName AS nvarchar(max)) AS LocationPath
|
|
FROM dbo.Locations
|
|
WHERE ProjectID = @ProjectID AND ParentLocationID IS NULL AND IsArchived = 0
|
|
|
|
UNION ALL
|
|
|
|
SELECT child.LocationID, child.LocationName, CAST(parent.LocationPath + N' > ' + child.LocationName AS nvarchar(max)) AS LocationPath
|
|
FROM dbo.Locations child
|
|
INNER JOIN ProjectLocationTree parent ON parent.LocationID = child.ParentLocationID
|
|
WHERE child.ProjectID = @ProjectID AND child.IsArchived = 0
|
|
)
|
|
INSERT #ProjectLocationPaths (LocationID, LocationName, LocationPath)
|
|
SELECT LocationID, LocationName, LocationPath
|
|
FROM ProjectLocationTree;
|
|
|
|
SELECT sa.StoryAssetID, sa.ProjectID, sa.AssetName, sa.AssetKindID, ak.KindName, sa.Description, sa.Importance,
|
|
sa.CurrentStateID, ast.StateName AS CurrentStateName, sa.CurrentLocationID,
|
|
location.LocationName AS CurrentLocationName, location.LocationPath AS CurrentLocationPath,
|
|
sa.IsResolved, sa.CreatedDate, sa.UpdatedDate, sa.IsArchived
|
|
FROM #ProjectAssets sa
|
|
INNER JOIN dbo.AssetKinds ak ON ak.AssetKindID = sa.AssetKindID
|
|
LEFT JOIN dbo.AssetStates ast ON ast.AssetStateID = sa.CurrentStateID
|
|
LEFT JOIN #ProjectLocationPaths location ON location.LocationID = sa.CurrentLocationID
|
|
WHERE sa.Importance >= 5 OR sa.IsResolved = 0
|
|
ORDER BY sa.Importance DESC, sa.AssetName;
|
|
|
|
SELECT ae.AssetEventID, ae.StoryAssetID, sa.ProjectID, sa.AssetName, sa.AssetKindID, ak.KindName,
|
|
ae.SceneID, ae.AssetEventTypeID, aet.TypeName AS AssetEventTypeName, aet.MarkerText,
|
|
ae.FromStateID, fs.StateName AS FromStateName, ae.ToStateID, ts.StateName AS ToStateName,
|
|
ae.EventTitle, ae.EventDescription, ae.CreatedDate, ae.UpdatedDate
|
|
FROM #TimelineScenes scene
|
|
INNER JOIN dbo.AssetEvents ae ON ae.SceneID = scene.SceneID
|
|
INNER JOIN #ProjectAssets sa ON sa.StoryAssetID = ae.StoryAssetID
|
|
INNER JOIN dbo.AssetKinds ak ON ak.AssetKindID = sa.AssetKindID
|
|
INNER JOIN dbo.AssetEventTypes aet ON aet.AssetEventTypeID = ae.AssetEventTypeID
|
|
LEFT JOIN dbo.AssetStates fs ON fs.AssetStateID = ae.FromStateID
|
|
LEFT JOIN dbo.AssetStates ts ON ts.AssetStateID = ae.ToStateID
|
|
ORDER BY scene.BookSortOrder, scene.ChapterSortOrder, scene.SceneSortOrder, sa.AssetName;
|
|
END;
|
|
GO
|