updates sql usage in DatabaseDataSource

This commit is contained in:
Shannon
2021-01-22 00:15:07 +11:00
parent 4a400b125b
commit eec81a3890
2 changed files with 145 additions and 104 deletions

View File

@@ -28,9 +28,9 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
// we want arrays, we want them all loaded, not an enumerable
private Sql<ISqlContext> ContentSourcesSelect(IScope scope, Func<Sql<ISqlContext>, Sql<ISqlContext>> joins = null)
private Sql<ISqlContext> SqlContentSourcesSelect(IScope scope, Func<Sql<ISqlContext>, Sql<ISqlContext>> joins = null)
{
var sqlTemplate = scope.SqlContext.Templates.Get(Constants.SqlTemplates.NuCacheDatabaseDataSource.ContentSourcesSelect1, tsql =>
var sqlTemplate = scope.SqlContext.Templates.Get(Constants.SqlTemplates.NuCacheDatabaseDataSource.ContentSourcesSelect, tsql =>
tsql.Select<NodeDto>(x => Alias(x.NodeId, "Id"), x => Alias(x.UniqueId, "Uid"),
x => Alias(x.Level, "Level"), x => Alias(x.Path, "Path"), x => Alias(x.SortOrder, "SortOrder"), x => Alias(x.ParentId, "ParentId"),
x => Alias(x.CreateDate, "CreateDate"), x => Alias(x.UserId, "CreatorId"))
@@ -75,12 +75,48 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
return sql;
}
private Sql<ISqlContext> SqlContentSourcesSelectUmbracoNodeJoin(Sql<ISqlContext> s)
{
var syntax = s.SqlContext.SqlSyntax;
var sqlTemplate = s.SqlContext.Templates.Get(Constants.SqlTemplates.NuCacheDatabaseDataSource.ContentSourcesSelectUmbracoNodeJoin, s =>
s.InnerJoin<NodeDto>("x").On<NodeDto, NodeDto>((left, right) => left.NodeId == right.NodeId || SqlText<bool>(left.Path, right.Path, (lp, rp) => $"({lp} LIKE {syntax.GetConcat(rp, "',%'")})"), aliasRight: "x"));
var sql = sqlTemplate.Sql();
return sql;
}
private Sql<ISqlContext> SqlWhereNodeId(Sql<ISqlContext> s, int id)
{
var syntax = s.SqlContext.SqlSyntax;
var sqlTemplate = s.SqlContext.Templates.Get(Constants.SqlTemplates.NuCacheDatabaseDataSource.ContentSourcesSelectUmbracoNodeJoin, s =>
s.Where<NodeDto>(x => x.NodeId == SqlTemplate.Arg<int>("id"), "x"));
var sql = sqlTemplate.Sql(id);
return sql;
}
private Sql<ISqlContext> SqlOrderByLevelIdSortOrder(Sql<ISqlContext> s)
{
var syntax = s.SqlContext.SqlSyntax;
var sqlTemplate = s.SqlContext.Templates.Get(Constants.SqlTemplates.NuCacheDatabaseDataSource.OrderByLevelIdSortOrder, s =>
s.OrderBy<NodeDto>(x => x.Level, x => x.ParentId, x => x.SortOrder));
var sql = sqlTemplate.Sql();
return sql;
}
private Sql<ISqlContext> SqlObjectTypeNotTrashed(Sql<ISqlContext> s, Guid nodeObjectType)
{
var syntax = s.SqlContext.SqlSyntax;
var sqlTemplate = s.SqlContext.Templates.Get(Constants.SqlTemplates.NuCacheDatabaseDataSource.ObjectTypeNotTrashedFilter, s =>
s.Where<NodeDto>(x => x.NodeObjectType == SqlTemplate.Arg<Guid?>("nodeObjectType") && !x.Trashed));
var sql = sqlTemplate.Sql(nodeObjectType);
return sql;
}
/// <summary>
/// Returns a slightly more optimized query to use for the document counting when paging over the content sources
/// </summary>
/// <param name="scope"></param>
/// <returns></returns>
private Sql<ISqlContext> ContentSourcesCount(IScope scope, Func<Sql<ISqlContext>, Sql<ISqlContext>> joins = null)
private Sql<ISqlContext> SqlContentSourcesCount(IScope scope, Func<Sql<ISqlContext>, Sql<ISqlContext>> joins = null)
{
var sqlTemplate = scope.SqlContext.Templates.Get(Constants.SqlTemplates.NuCacheDatabaseDataSource.ContentSourcesCount, tsql =>
tsql.Select<NodeDto>(x => Alias(x.NodeId, "Id"))
@@ -104,11 +140,55 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
return sql;
}
private Sql<ISqlContext> SqlMediaSourcesSelect(IScope scope, Func<Sql<ISqlContext>, Sql<ISqlContext>> joins = null)
{
var sqlTemplate = scope.SqlContext.Templates.Get(Constants.SqlTemplates.NuCacheDatabaseDataSource.MediaSourcesSelect, tsql =>
tsql.Select<NodeDto>(x => Alias(x.NodeId, "Id"), x => Alias(x.UniqueId, "Uid"),
x => Alias(x.Level, "Level"), x => Alias(x.Path, "Path"), x => Alias(x.SortOrder, "SortOrder"), x => Alias(x.ParentId, "ParentId"),
x => Alias(x.CreateDate, "CreateDate"), x => Alias(x.UserId, "CreatorId"))
.AndSelect<ContentDto>(x => Alias(x.ContentTypeId, "ContentTypeId"))
.AndSelect<ContentVersionDto>(x => Alias(x.Id, "VersionId"), x => Alias(x.Text, "EditName"), x => Alias(x.VersionDate, "EditVersionDate"), x => Alias(x.UserId, "EditWriterId"))
.AndSelect<ContentNuDto>("nuEdit", x => Alias(x.Data, "EditData"))
.AndSelect<ContentNuDto>("nuEdit", x => Alias(x.RawData, "EditDataRaw"))
.From<NodeDto>());
var sql = sqlTemplate.Sql();
if (joins != null)
sql = joins(sql);
// TODO: We can't use a template with this one because of the 'right.Published' ends up being a parameter so not sure how we can do that
sql = sql
.InnerJoin<ContentDto>().On<NodeDto, ContentDto>((left, right) => left.NodeId == right.NodeId)
.InnerJoin<ContentVersionDto>().On<NodeDto, ContentVersionDto>((left, right) => left.NodeId == right.NodeId && right.Current)
.LeftJoin<ContentNuDto>("nuEdit").On<NodeDto, ContentNuDto>((left, right) => left.NodeId == right.NodeId && !right.Published, aliasRight: "nuEdit");
return sql;
}
private Sql<ISqlContext> SqlMediaSourcesCount(IScope scope, Func<Sql<ISqlContext>, Sql<ISqlContext>> joins = null)
{
var sqlTemplate = scope.SqlContext.Templates.Get(Constants.SqlTemplates.NuCacheDatabaseDataSource.MediaSourcesCount, tsql =>
tsql.Select<NodeDto>(x => Alias(x.NodeId, "Id")).From<NodeDto>());
var sql = sqlTemplate.Sql();
if (joins != null)
sql = joins(sql);
// TODO: We can't use a template with this one because of the 'right.Current' ends up being a parameter so not sure how we can do that
sql = sql
.InnerJoin<ContentDto>().On<NodeDto, ContentDto>((left, right) => left.NodeId == right.NodeId)
.InnerJoin<ContentVersionDto>().On<NodeDto, ContentVersionDto>((left, right) => left.NodeId == right.NodeId && right.Current);
return sql;
}
public ContentNodeKit GetContentSource(IScope scope, int id)
{
var sql = ContentSourcesSelect(scope)
.Where<NodeDto>(x => x.NodeObjectType == Constants.ObjectTypes.Document && x.NodeId == id && !x.Trashed)
.OrderBy<NodeDto>(x => x.Level, x => x.ParentId, x => x.SortOrder);
var sql = SqlContentSourcesSelect(scope)
.Append(SqlObjectTypeNotTrashed(scope.SqlContext.Sql(), Constants.ObjectTypes.Document))
.Append(SqlWhereNodeId(scope.SqlContext.Sql(), id))
.Append(SqlOrderByLevelIdSortOrder(scope.SqlContext.Sql()));
var dto = scope.Database.Fetch<ContentSourceDto>(sql).FirstOrDefault();
@@ -120,14 +200,14 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
public IEnumerable<ContentNodeKit> GetAllContentSources(IScope scope)
{
// Create a different query for the SQL vs the COUNT Sql since the auto-generated COUNT Sql will be inneficient
var sql = ContentSourcesSelect(scope)
.Where<NodeDto>(x => x.NodeObjectType == Constants.ObjectTypes.Document && !x.Trashed)
.OrderBy<NodeDto>(x => x.Level, x => x.ParentId, x => x.SortOrder);
var sql = SqlContentSourcesSelect(scope)
.Append(SqlObjectTypeNotTrashed(scope.SqlContext.Sql(), Constants.ObjectTypes.Document))
.Append(SqlOrderByLevelIdSortOrder(scope.SqlContext.Sql()));
// Use a more efficient COUNT query
var sqlCountQuery = SqlContentSourcesCount(scope)
.Append(SqlObjectTypeNotTrashed(scope.SqlContext.Sql(), Constants.ObjectTypes.Document));
// create a more efficient COUNT query without the join on the cmsContentNu table
var sqlCountQuery = ContentSourcesCount(scope)
.Where<NodeDto>(x => x.NodeObjectType == Constants.ObjectTypes.Document && !x.Trashed);
var sqlCount = scope.SqlContext.Sql("SELECT COUNT(*) FROM (").Append(sqlCountQuery).Append(") npoco_tbl");
var serializer = _contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Document);
@@ -138,26 +218,22 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
foreach (var row in scope.Database.QueryPaged<ContentSourceDto>(PageSize, sql, sqlCount))
{
yield return CreateContentNodeKit(row, serializer);
}
}
}
public IEnumerable<ContentNodeKit> GetBranchContentSources(IScope scope, int id)
{
var syntax = scope.SqlContext.SqlSyntax;
var sql = ContentSourcesSelect(scope,
s => s.InnerJoin<NodeDto>("x").On<NodeDto, NodeDto>((left, right) => left.NodeId == right.NodeId || SqlText<bool>(left.Path, right.Path, (lp, rp) => $"({lp} LIKE {syntax.GetConcat(rp, "',%'")})"), aliasRight: "x"))
.Where<NodeDto>(x => x.NodeObjectType == Constants.ObjectTypes.Document && !x.Trashed)
.Where<NodeDto>(x => x.NodeId == id, "x")
.OrderBy<NodeDto>(x => x.Level, x => x.ParentId, x => x.SortOrder);
var sql = SqlContentSourcesSelect(scope, SqlContentSourcesSelectUmbracoNodeJoin)
.Append(SqlObjectTypeNotTrashed(scope.SqlContext.Sql(), Constants.ObjectTypes.Document))
.Append(SqlWhereNodeId(scope.SqlContext.Sql(), id))
.Append(SqlOrderByLevelIdSortOrder(scope.SqlContext.Sql()));
// create a more efficient COUNT query without the join on the cmsContentNu table
var sqlCountQuery = ContentSourcesCount(scope,
s => s.InnerJoin<NodeDto>("x").On<NodeDto, NodeDto>((left, right) => left.NodeId == right.NodeId || SqlText<bool>(left.Path, right.Path, (lp, rp) => $"({lp} LIKE {syntax.GetConcat(rp, "',%'")})"), aliasRight: "x"))
.Where<NodeDto>(x => x.NodeObjectType == Constants.ObjectTypes.Document && !x.Trashed)
.Where<NodeDto>(x => x.NodeId == id, "x");
// Use a more efficient COUNT query
var sqlCountQuery = SqlContentSourcesCount(scope, SqlContentSourcesSelectUmbracoNodeJoin)
.Append(SqlObjectTypeNotTrashed(scope.SqlContext.Sql(), Constants.ObjectTypes.Document))
.Append(SqlWhereNodeId(scope.SqlContext.Sql(), id));
var sqlCount = scope.SqlContext.Sql("SELECT COUNT(*) FROM (").Append(sqlCountQuery).Append(") npoco_tbl");
var serializer = _contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Document);
// We need to page here. We don't want to iterate over every single row in one connection cuz this can cause an SQL Timeout.
@@ -166,20 +242,21 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
foreach (var row in scope.Database.QueryPaged<ContentSourceDto>(PageSize, sql, sqlCount))
{
yield return CreateContentNodeKit(row, serializer);
}
}
}
public IEnumerable<ContentNodeKit> GetTypeContentSources(IScope scope, IEnumerable<int> ids)
{
if (!ids.Any()) yield break;
var sql = ContentSourcesSelect(scope)
.Where<NodeDto>(x => x.NodeObjectType == Constants.ObjectTypes.Document && !x.Trashed)
var sql = SqlContentSourcesSelect(scope)
.Append(SqlObjectTypeNotTrashed(scope.SqlContext.Sql(), Constants.ObjectTypes.Document))
.WhereIn<ContentDto>(x => x.ContentTypeId, ids)
.OrderBy<NodeDto>(x => x.Level, x => x.ParentId, x => x.SortOrder);
.Append(SqlOrderByLevelIdSortOrder(scope.SqlContext.Sql()));
var sqlCountQuery = ContentSourcesCount(scope)
.Where<NodeDto>(x => x.NodeObjectType == Constants.ObjectTypes.Document && !x.Trashed)
// Use a more efficient COUNT query
var sqlCountQuery = SqlContentSourcesCount(scope, SqlContentSourcesSelectUmbracoNodeJoin)
.Append(SqlObjectTypeNotTrashed(scope.SqlContext.Sql(), Constants.ObjectTypes.Document))
.WhereIn<ContentDto>(x => x.ContentTypeId, ids);
var sqlCount = scope.SqlContext.Sql("SELECT COUNT(*) FROM (").Append(sqlCountQuery).Append(") npoco_tbl");
@@ -191,54 +268,15 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
foreach (var row in scope.Database.QueryPaged<ContentSourceDto>(PageSize, sql, sqlCount))
{
yield return CreateContentNodeKit(row, serializer);
}
}
private Sql<ISqlContext> MediaSourcesSelect(IScope scope, Func<Sql<ISqlContext>, Sql<ISqlContext>> joins = null)
{
var sql = scope.SqlContext.Sql()
.Select<NodeDto>(x => Alias(x.NodeId, "Id"), x => Alias(x.UniqueId, "Uid"),
x => Alias(x.Level, "Level"), x => Alias(x.Path, "Path"), x => Alias(x.SortOrder, "SortOrder"), x => Alias(x.ParentId, "ParentId"),
x => Alias(x.CreateDate, "CreateDate"), x => Alias(x.UserId, "CreatorId"))
.AndSelect<ContentDto>(x => Alias(x.ContentTypeId, "ContentTypeId"))
.AndSelect<ContentVersionDto>(x => Alias(x.Id, "VersionId"), x => Alias(x.Text, "EditName"), x => Alias(x.VersionDate, "EditVersionDate"), x => Alias(x.UserId, "EditWriterId"))
.AndSelect<ContentNuDto>("nuEdit", x => Alias(x.Data, "EditData"))
.AndSelect<ContentNuDto>("nuEdit", x => Alias(x.RawData, "EditDataRaw"))
.From<NodeDto>();
if (joins != null)
sql = joins(sql);
sql = sql
.InnerJoin<ContentDto>().On<NodeDto, ContentDto>((left, right) => left.NodeId == right.NodeId)
.InnerJoin<ContentVersionDto>().On<NodeDto, ContentVersionDto>((left, right) => left.NodeId == right.NodeId && right.Current)
.LeftJoin<ContentNuDto>("nuEdit").On<NodeDto, ContentNuDto>((left, right) => left.NodeId == right.NodeId && !right.Published, aliasRight: "nuEdit");
return sql;
}
private Sql<ISqlContext> MediaSourcesCount(IScope scope, Func<Sql<ISqlContext>, Sql<ISqlContext>> joins = null)
{
var sql = scope.SqlContext.Sql()
.Select<NodeDto>(x => Alias(x.NodeId, "Id"))
.From<NodeDto>();
if (joins != null)
sql = joins(sql);
sql = sql
.InnerJoin<ContentDto>().On<NodeDto, ContentDto>((left, right) => left.NodeId == right.NodeId)
.InnerJoin<ContentVersionDto>().On<NodeDto, ContentVersionDto>((left, right) => left.NodeId == right.NodeId && right.Current);
return sql;
}
}
public ContentNodeKit GetMediaSource(IScope scope, int id)
{
var sql = MediaSourcesSelect(scope)
.Where<NodeDto>(x => x.NodeObjectType == Constants.ObjectTypes.Media && x.NodeId == id && !x.Trashed)
.OrderBy<NodeDto>(x => x.Level, x => x.ParentId, x => x.SortOrder);
var sql = SqlMediaSourcesSelect(scope)
.Append(SqlObjectTypeNotTrashed(scope.SqlContext.Sql(), Constants.ObjectTypes.Media))
.Append(SqlWhereNodeId(scope.SqlContext.Sql(), id))
.Append(SqlOrderByLevelIdSortOrder(scope.SqlContext.Sql()));
var dto = scope.Database.Fetch<ContentSourceDto>(sql).FirstOrDefault();
@@ -250,13 +288,13 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
public IEnumerable<ContentNodeKit> GetAllMediaSources(IScope scope)
{
var sql = MediaSourcesSelect(scope)
.Where<NodeDto>(x => x.NodeObjectType == Constants.ObjectTypes.Media && !x.Trashed)
.OrderBy<NodeDto>(x => x.Level, x => x.ParentId, x => x.SortOrder);
var sqlCountQuery = MediaSourcesCount(scope)
.Where<NodeDto>(x => x.NodeObjectType == Constants.ObjectTypes.Media && !x.Trashed);
var sql = SqlMediaSourcesSelect(scope)
.Append(SqlObjectTypeNotTrashed(scope.SqlContext.Sql(), Constants.ObjectTypes.Media))
.Append(SqlOrderByLevelIdSortOrder(scope.SqlContext.Sql()));
// Use a more efficient COUNT query
var sqlCountQuery = SqlMediaSourcesCount(scope)
.Append(SqlObjectTypeNotTrashed(scope.SqlContext.Sql(), Constants.ObjectTypes.Media));
var sqlCount = scope.SqlContext.Sql("SELECT COUNT(*) FROM (").Append(sqlCountQuery).Append(") npoco_tbl");
var serializer = _contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Media);
@@ -267,23 +305,20 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
foreach (var row in scope.Database.QueryPaged<ContentSourceDto>(PageSize, sql, sqlCount))
{
yield return CreateMediaNodeKit(row, serializer);
}
}
}
public IEnumerable<ContentNodeKit> GetBranchMediaSources(IScope scope, int id)
{
var syntax = scope.SqlContext.SqlSyntax;
var sql = MediaSourcesSelect(scope,
s => s.InnerJoin<NodeDto>("x").On<NodeDto, NodeDto>((left, right) => left.NodeId == right.NodeId || SqlText<bool>(left.Path, right.Path, (lp, rp) => $"({lp} LIKE {syntax.GetConcat(rp, "',%'")})"), aliasRight: "x"))
.Where<NodeDto>(x => x.NodeObjectType == Constants.ObjectTypes.Media && !x.Trashed)
.Where<NodeDto>(x => x.NodeId == id, "x")
.OrderBy<NodeDto>(x => x.Level, x => x.ParentId, x => x.SortOrder);
var sqlCountQuery = MediaSourcesCount(scope,
s => s.InnerJoin<NodeDto>("x").On<NodeDto, NodeDto>((left, right) => left.NodeId == right.NodeId || SqlText<bool>(left.Path, right.Path, (lp, rp) => $"({lp} LIKE {syntax.GetConcat(rp, "',%'")})"), aliasRight: "x"))
.Where<NodeDto>(x => x.NodeObjectType == Constants.ObjectTypes.Media && !x.Trashed)
.Where<NodeDto>(x => x.NodeId == id, "x");
var sql = SqlMediaSourcesSelect(scope, SqlContentSourcesSelectUmbracoNodeJoin)
.Append(SqlObjectTypeNotTrashed(scope.SqlContext.Sql(), Constants.ObjectTypes.Media))
.Append(SqlWhereNodeId(scope.SqlContext.Sql(), id))
.Append(SqlOrderByLevelIdSortOrder(scope.SqlContext.Sql()));
// Use a more efficient COUNT query
var sqlCountQuery = SqlMediaSourcesCount(scope)
.Append(SqlObjectTypeNotTrashed(scope.SqlContext.Sql(), Constants.ObjectTypes.Media))
.Append(SqlWhereNodeId(scope.SqlContext.Sql(), id));
var sqlCount = scope.SqlContext.Sql("SELECT COUNT(*) FROM (").Append(sqlCountQuery).Append(") npoco_tbl");
var serializer = _contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Media);
@@ -294,22 +329,22 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
foreach (var row in scope.Database.QueryPaged<ContentSourceDto>(PageSize, sql, sqlCount))
{
yield return CreateMediaNodeKit(row, serializer);
}
}
}
public IEnumerable<ContentNodeKit> GetTypeMediaSources(IScope scope, IEnumerable<int> ids)
{
if (!ids.Any()) yield break;
var sql = MediaSourcesSelect(scope)
.Where<NodeDto>(x => x.NodeObjectType == Constants.ObjectTypes.Media && !x.Trashed)
var sql = SqlMediaSourcesSelect(scope)
.Append(SqlObjectTypeNotTrashed(scope.SqlContext.Sql(), Constants.ObjectTypes.Media))
.WhereIn<ContentDto>(x => x.ContentTypeId, ids)
.OrderBy<NodeDto>(x => x.Level, x => x.ParentId, x => x.SortOrder);
var sqlCountQuery = MediaSourcesCount(scope)
.Where<NodeDto>(x => x.NodeObjectType == Constants.ObjectTypes.Media && !x.Trashed)
.WhereIn<ContentDto>(x => x.ContentTypeId, ids);
.Append(SqlOrderByLevelIdSortOrder(scope.SqlContext.Sql()));
// Use a more efficient COUNT query
var sqlCountQuery = SqlMediaSourcesCount(scope)
.Append(SqlObjectTypeNotTrashed(scope.SqlContext.Sql(), Constants.ObjectTypes.Media))
.WhereIn<ContentDto>(x => x.ContentTypeId, ids);
var sqlCount = scope.SqlContext.Sql("SELECT COUNT(*) FROM (").Append(sqlCountQuery).Append(") npoco_tbl");
var serializer = _contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Media);
@@ -320,7 +355,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
foreach (var row in scope.Database.QueryPaged<ContentSourceDto>(PageSize, sql, sqlCount))
{
yield return CreateMediaNodeKit(row, serializer);
}
}
}
private ContentNodeKit CreateContentNodeKit(ContentSourceDto dto, IContentCacheDataSerializer serializer)