Timeline performance improvements.
This commit is contained in:
parent
1dad31efab
commit
f1279f55ee
170
PlotLine/Sql/025_AssetTimelinePerformance.sql
Normal file
170
PlotLine/Sql/025_AssetTimelinePerformance.sql
Normal file
@ -0,0 +1,170 @@
|
||||
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
|
||||
Loading…
x
Reference in New Issue
Block a user