Updated the RebuildXmlStructures method with performance improvements. Added cache checking to the GetByPublishedVersion method since published content should always be 'latest' this will speed things up tremendously if items are found there. Added 2 more performance tests which show very large perf improvements, namely the Get_All_Published_Content_Of_Type shows a 77% improvement.

This commit is contained in:
Shannon
2013-07-29 15:49:56 +10:00
parent 696306e7c9
commit b9ba350a2f
4 changed files with 184 additions and 23 deletions

View File

@@ -449,7 +449,15 @@ namespace Umbraco.Core.Persistence.Repositories
foreach (var dto in dtos)
{
yield return CreateContentFromDto(dto, dto.VersionId);
var fromCache = TryGetFromCache(dto.NodeId);
if (fromCache.Success)
{
yield return fromCache.Result;
}
else
{
yield return CreateContentFromDto(dto, dto.VersionId);
}
}
}

View File

@@ -85,11 +85,10 @@ namespace Umbraco.Core.Persistence.Repositories
/// <returns></returns>
public TEntity Get(TId id)
{
Guid key = id is int ? ConvertIdToGuid(id) : ConvertStringIdToGuid(id.ToString());
var rEntity = _cache.GetById(typeof(TEntity), key);
if (rEntity != null)
var fromCache = TryGetFromCache(id);
if (fromCache.Success)
{
return (TEntity)rEntity;
return fromCache.Result;
}
var entity = PerformGet(id);
@@ -112,6 +111,17 @@ namespace Umbraco.Core.Persistence.Repositories
return entity;
}
protected Attempt<TEntity> TryGetFromCache(TId id)
{
Guid key = id is int ? ConvertIdToGuid(id) : ConvertStringIdToGuid(id.ToString());
var rEntity = _cache.GetById(typeof(TEntity), key);
if (rEntity != null)
{
return new Attempt<TEntity>(true, (TEntity) rEntity);
}
return Attempt<TEntity>.False;
}
protected abstract IEnumerable<TEntity> PerformGetAll(params TId[] ids);
/// <summary>
/// Gets all entities of type TEntity or a list according to the passed in Ids
@@ -173,14 +183,12 @@ namespace Umbraco.Core.Persistence.Repositories
/// <returns></returns>
public bool Exists(TId id)
{
Guid key = id is int ? ConvertIdToGuid(id) : ConvertStringIdToGuid(id.ToString());
var rEntity = _cache.GetById(typeof(TEntity), key);
if (rEntity != null)
var fromCache = TryGetFromCache(id);
if (fromCache.Success)
{
return true;
}
return PerformExists(id);
return PerformExists(id);
}
protected abstract int PerformCount(IQuery<TEntity> query);

View File

@@ -13,6 +13,7 @@ using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.Publishing;
@@ -250,6 +251,17 @@ namespace Umbraco.Core.Services
}
}
internal IEnumerable<IContent> GetPublishedContentOfContentType(int id)
{
using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
{
var query = Query<IContent>.Builder.Where(x => x.ContentTypeId == id);
var contents = repository.GetByPublishedVersion(query);
return contents;
}
}
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by Level
/// </summary>
@@ -431,6 +443,19 @@ namespace Umbraco.Core.Services
}
}
/// <summary>
/// Gets all published content items
/// </summary>
/// <returns></returns>
internal IEnumerable<IContent> GetAllPublished()
{
using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
{
var query = Query<IContent>.Builder.Where(x => x.Trashed == false);
return repository.GetByPublishedVersion(query);
}
}
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects, which has an expiration date less than or equal to today.
/// </summary>
@@ -1359,23 +1384,13 @@ namespace Umbraco.Core.Services
uow.Database.Execute(@"DELETE FROM cmsContentXml WHERE nodeId IN
(SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml
INNER JOIN cmsDocument ON cmsContentXml.nodeId = cmsDocument.nodeId)");
//get all content items that are published
// Consider creating a Path query instead of recursive method:
// var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith("-1"));
var rootContent = GetRootContent();
foreach (var content in rootContent.Where(content => content.Published))
{
list.Add(content);
list.AddRange(GetPublishedDescendants(content));
}
list.AddRange(GetAllPublished());
}
else
{
foreach (var id in contentTypeIds)
{
//first we'll clear out the data from the cmsContentXml table for this type
uow.Database.Execute(@"delete from cmsContentXml where nodeId in
(select cmsDocument.nodeId from cmsDocument
@@ -1383,7 +1398,7 @@ namespace Umbraco.Core.Services
where published = 1 and contentType = @contentTypeId)", new {contentTypeId = id});
//now get all published content objects of this type and add to the list
list.AddRange(GetContentOfContentType(id).Where(content => content.Published));
list.AddRange(GetPublishedContentOfContentType(id));
}
}

View File

@@ -11,6 +11,7 @@ using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
@@ -66,6 +67,90 @@ namespace Umbraco.Tests.Services
base.TearDown();
}
[Test]
public void Get_All_Published_Content()
{
var result = PrimeDbWithLotsOfContent();
var contentSvc = (ContentService) ServiceContext.ContentService;
var countOfPublished = result.Count(x => x.Published);
var contentTypeId = result.First().ContentTypeId;
using (DisposableTimer.DebugDuration<PerformanceTests>("Getting published content normally"))
{
//do this 10x!
for (var i = 0; i < 10; i++)
{
//clear the cache to make this test valid
RuntimeCacheProvider.Current.Clear();
var published = new List<IContent>();
//get all content items that are published
var rootContent = contentSvc.GetRootContent();
foreach (var content in rootContent.Where(content => content.Published))
{
published.Add(content);
published.AddRange(contentSvc.GetPublishedDescendants(content));
}
Assert.AreEqual(countOfPublished, published.Count(x => x.ContentTypeId == contentTypeId));
}
}
using (DisposableTimer.DebugDuration<PerformanceTests>("Getting published content optimized"))
{
//do this 10x!
for (var i = 0; i < 10; i++)
{
//clear the cache to make this test valid
RuntimeCacheProvider.Current.Clear();
//get all content items that are published
var published = contentSvc.GetAllPublished();
Assert.AreEqual(countOfPublished, published.Count(x => x.ContentTypeId == contentTypeId));
}
}
}
[Test]
public void Get_All_Published_Content_Of_Type()
{
var result = PrimeDbWithLotsOfContent();
var contentSvc = (ContentService)ServiceContext.ContentService;
var countOfPublished = result.Count(x => x.Published);
var contentTypeId = result.First().ContentTypeId;
using (DisposableTimer.DebugDuration<PerformanceTests>("Getting published content of type normally"))
{
//do this 10x!
for (var i = 0; i < 10; i++)
{
//clear the cache to make this test valid
RuntimeCacheProvider.Current.Clear();
//get all content items that are published of this type
var published = contentSvc.GetContentOfContentType(contentTypeId).Where(content => content.Published);
Assert.AreEqual(countOfPublished, published.Count(x => x.ContentTypeId == contentTypeId));
}
}
using (DisposableTimer.DebugDuration<PerformanceTests>("Getting published content of type optimized"))
{
//do this 10x!
for (var i = 0; i < 10; i++)
{
//clear the cache to make this test valid
RuntimeCacheProvider.Current.Clear();
//get all content items that are published of this type
var published = contentSvc.GetPublishedContentOfContentType(contentTypeId);
Assert.AreEqual(countOfPublished, published.Count(x => x.ContentTypeId == contentTypeId));
}
}
}
[Test]
public void Truncate_Insert_Vs_Update_Insert()
{
@@ -130,6 +215,51 @@ namespace Umbraco.Tests.Services
}
private IEnumerable<IContent> PrimeDbWithLotsOfContent()
{
var contentType1 = MockedContentTypes.CreateSimpleContentType();
contentType1.AllowedAsRoot = true;
ServiceContext.ContentTypeService.Save(contentType1);
contentType1.AllowedContentTypes = new List<ContentTypeSort>
{
new ContentTypeSort
{
Alias = contentType1.Alias,
Id = new Lazy<int>(() => contentType1.Id),
SortOrder = 0
}
};
var result = new List<IContent>();
ServiceContext.ContentTypeService.Save(contentType1);
IContent lastParent = MockedContent.CreateSimpleContent(contentType1);
ServiceContext.ContentService.SaveAndPublish(lastParent);
result.Add(lastParent);
//create 20 deep
for (var i = 0; i < 20; i++)
{
//for each level, create 20
IContent content = null;
for (var j = 1; j <= 10; j++)
{
content = MockedContent.CreateSimpleContent(contentType1, "Name" + j, lastParent);
//only publish evens
if (j % 2 == 0)
{
ServiceContext.ContentService.SaveAndPublish(content);
}
else
{
ServiceContext.ContentService.Save(content);
}
result.Add(content);
}
//assign the last one as the next parent
lastParent = content;
}
return result;
}
private IEnumerable<NodeDto> PrimeDbWithLotsOfContentXmlRecords(Guid customObjectType)
{
var nodes = new List<NodeDto>();