diff --git a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs
index e60fd6623e..4c7cb57f19 100644
--- a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs
+++ b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs
@@ -80,7 +80,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
///
///
///
- private Sql ContentSourcesCount(IScope scope)
+ private Sql ContentSourcesCount(IScope scope, Func, Sql> joins = null)
{
var sqlTemplate = scope.SqlContext.Templates.Get(Constants.SqlTemplates.NuCacheDatabaseDataSource.ContentSourcesCount, tsql =>
tsql.Select(x => Alias(x.NodeId, "Id"))
@@ -90,6 +90,9 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
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' and 'right.Published' ends up being a parameter so not sure how we can do that
sql = sql
.InnerJoin().On((left, right) => left.NodeId == right.NodeId && right.Current)
@@ -147,12 +150,20 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
.Where(x => x.NodeId == id, "x")
.OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder);
+ // create a more efficient COUNT query without the join on the cmsContentNu table
+ var sqlCountQuery = ContentSourcesCount(scope,
+ s => s.InnerJoin("x").On((left, right) => left.NodeId == right.NodeId || SqlText(left.Path, right.Path, (lp, rp) => $"({lp} LIKE {syntax.GetConcat(rp, "',%'")})"), aliasRight: "x"))
+ .Where(x => x.NodeObjectType == Constants.ObjectTypes.Document && !x.Trashed)
+ .Where(x => x.NodeId == id, "x");
+ 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.
// We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that.
- foreach (var row in scope.Database.QueryPaged(PageSize, sql))
+ foreach (var row in scope.Database.QueryPaged(PageSize, sql, sqlCount))
{
yield return CreateContentNodeKit(row, serializer);
}
@@ -167,12 +178,17 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
.WhereIn(x => x.ContentTypeId, ids)
.OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder);
+ var sqlCountQuery = ContentSourcesCount(scope)
+ .Where(x => x.NodeObjectType == Constants.ObjectTypes.Document && !x.Trashed)
+ .WhereIn(x => x.ContentTypeId, ids);
+ 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.
// We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that.
- foreach (var row in scope.Database.QueryPaged(PageSize, sql))
+ foreach (var row in scope.Database.QueryPaged(PageSize, sql, sqlCount))
{
yield return CreateContentNodeKit(row, serializer);
}
@@ -182,9 +198,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
{
var sql = scope.SqlContext.Sql()
- .Select(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"))
+ .Select(x => Alias(x.NodeId, "Id"))
.AndSelect(x => Alias(x.ContentTypeId, "ContentTypeId"))
.AndSelect(x => Alias(x.Id, "VersionId"), x => Alias(x.Text, "EditName"), x => Alias(x.VersionDate, "EditVersionDate"), x => Alias(x.UserId, "EditWriterId"))
.AndSelect("nuEdit", x => Alias(x.Data, "EditData"))
@@ -201,6 +215,22 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
return sql;
}
+ private Sql MediaSourcesCount(IScope scope, Func, Sql> joins = null)
+ {
+ var sql = scope.SqlContext.Sql()
+
+ .Select(x => Alias(x.NodeId, "Id"))
+ .From();
+
+ if (joins != null)
+ sql = joins(sql);
+
+ sql = sql
+ .InnerJoin().On((left, right) => left.NodeId == right.NodeId)
+ .InnerJoin().On((left, right) => left.NodeId == right.NodeId && right.Current);
+
+ return sql;
+ }
public ContentNodeKit GetMediaSource(IScope scope, int id)
{
@@ -222,12 +252,17 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
.Where(x => x.NodeObjectType == Constants.ObjectTypes.Media && !x.Trashed)
.OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder);
+ var sqlCountQuery = MediaSourcesCount(scope)
+ .Where(x => x.NodeObjectType == Constants.ObjectTypes.Media && !x.Trashed);
+
+ var sqlCount = scope.SqlContext.Sql("SELECT COUNT(*) FROM (").Append(sqlCountQuery).Append(") npoco_tbl");
+
var serializer = _contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Media);
// 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.
// We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that.
- foreach (var row in scope.Database.QueryPaged(PageSize, sql))
+ foreach (var row in scope.Database.QueryPaged(PageSize, sql, sqlCount))
{
yield return CreateMediaNodeKit(row, serializer);
}
@@ -242,12 +277,19 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
.Where(x => x.NodeId == id, "x")
.OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder);
+ var sqlCountQuery = MediaSourcesCount(scope,
+ s => s.InnerJoin("x").On((left, right) => left.NodeId == right.NodeId || SqlText(left.Path, right.Path, (lp, rp) => $"({lp} LIKE {syntax.GetConcat(rp, "',%'")})"), aliasRight: "x"))
+ .Where(x => x.NodeObjectType == Constants.ObjectTypes.Media && !x.Trashed)
+ .Where(x => x.NodeId == id, "x");
+
+ var sqlCount = scope.SqlContext.Sql("SELECT COUNT(*) FROM (").Append(sqlCountQuery).Append(") npoco_tbl");
+
var serializer = _contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Media);
// 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.
// We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that.
- foreach (var row in scope.Database.QueryPaged(PageSize, sql))
+ foreach (var row in scope.Database.QueryPaged(PageSize, sql, sqlCount))
{
yield return CreateMediaNodeKit(row, serializer);
}
@@ -262,12 +304,18 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
.WhereIn(x => x.ContentTypeId, ids)
.OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder);
+ var sqlCountQuery = MediaSourcesCount(scope)
+ .Where(x => x.NodeObjectType == Constants.ObjectTypes.Media && !x.Trashed)
+ .WhereIn(x => x.ContentTypeId, ids);
+
+ var sqlCount = scope.SqlContext.Sql("SELECT COUNT(*) FROM (").Append(sqlCountQuery).Append(") npoco_tbl");
+
var serializer = _contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Media);
// 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.
// We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that.
- foreach (var row in scope.Database.QueryPaged(PageSize, sql))
+ foreach (var row in scope.Database.QueryPaged(PageSize, sql, sqlCount))
{
yield return CreateMediaNodeKit(row, serializer);
}