Get items - the fastest way

Reading time ~3 minutes

What is the fastest way of getting items? I present you results of my experiment performed some time ago.

Introduction

Maybe the title is a little bit misleading because finding the fastest way of getting items was not my goal (you can find an answer for this too).

At early days of Helix and Habitat I was wondering if recommended approach for getting items with additional filtering is not a step back in terms of speed.

Previously I was using in my opinion the fastest way - queries

fast:/sitecore/content/*[@@templatename="TestItem"]

I was scared of:

item.Children.Where(i => TemplateManager.GetTemplate(i).InheritsFrom(id))

I thought that it cannot be faster, but is what’s the truth?

Experiment

I decided to perform test to find our what’s the truth.

Test Data

First I had to create some test data:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$root = "/sitecore/content"
$testTemplate = New-Item -Path "/sitecore/templates/User Defined" -Name "TestItem" -ItemType "System/Templates/Template"
[Sitecore.Data.Items.TemplateItem]$testTemplate = $testTemplate
$performanceRoot = New-Item -Path $root -Name "PerformanceRoot" -ItemType $testTemplate.FullName

0..9 | % {
$level0 = $_
$level0Parent = New-Item -Parent $performanceRoot -Name $level0 -ItemType $testTemplate.FullName
0..9 | % {
$level1 = $_
$level1Parent = New-Item -Parent $level0Parent -Name $level1 -ItemType $testTemplate.FullName
0..9 | % {
$level2 = $_
New-Item -Parent $level1Parent -Name $level2 -ItemType $testTemplate.FullName | Out-Null
}
}
}

In content tree it looked like this:

Logic

After I had my items ready in database I wrote different function for obtaining items. Note that that filtering in some methods is different than recommended by Helix (checking template name instead of inheritance).

1
2
3
4
5
6
7
8
9
public static Result GetDescendantsAllItems(Item item, ID id)
{
var r = new Result();
var items = item.Axes.GetDescendants()
.Where(i => TemplateManager.GetTemplate(i).InheritsFrom(id))
.ToList();
r.Items.AddRange(items);
return r;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static Result ChildrenRecursive(Item item, ID id)
{
var r = new Result();
var itemChildren = item.Children;
var items = itemChildren
.Where(i => TemplateManager.GetTemplate(i).InheritsFrom(id))
.ToList();
r.Items.AddRange(items);
foreach (Item i in itemChildren)
{
if (i.HasChildren)
{
r.Items.AddRange(ChildrenRecursive(i, id).Items);
}
}
return r;
}
1
2
3
4
5
6
public static Result SelectItems(Item item, string query)
{
var r = new Result();
r.Items.AddRange(item.Axes.SelectItems(query));
return r;
}
1
2
3
4
5
6
7
8
9
public static Result ChildrenSingleLevel(Item item, ID id)
{
var r = new Result();
var items = item.Children
.Where(i => TemplateManager.GetTemplate(i).InheritsFrom(id))
.ToList();
r.Items.AddRange(items);
return r;
}
1
2
3
4
5
6
public static Result SelectItem(Item item, string query)
{
var r = new Result();
r.Items.Add(item?.Axes.SelectSingleItem(query));
return r;
}
1
2
3
4
5
6
7
8
public static Result GetDescendantsSingleItem(Item item, ID id)
{
var r = new Result();
var items = item.Axes.GetDescendants()
.FirstOrDefault(i => TemplateManager.GetTemplate(i).InheritsFrom(id));
r.Items.Add(items);
return r;
}
1
2
3
4
5
6
7
8
public static Result ChildrenSingleItem(Item item, ID id)
{
var r = new Result();
var items = item.Children
.FirstOrDefault(i => TemplateManager.GetTemplate(i).InheritsFrom(id));
r.Items.Add(items);
return r;
}
1
2
3
4
5
6
public static Result SelectItemFast(Item item, string query)
{
var r = new Result();
r.Items.Add(item.Database.SelectSingleItem(query));
return r;
}
1
2
3
4
5
6
public static Result SelectItemsFast(Item item, string query)
{
var r = new Result();
r.Items.AddRange(item.Database.SelectItems(query));
return r;
}

Tests

After everything was setup I performed tests. I used something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
$item = Get-Item .
$templateItem = Get-Item -Path "/sitecore/templates/User Defined/TestItem"

Write-Host "`nGetDescendants - AllItems" -ForegroundColor Green
$GetDescendantsAllItems = [Tests]::GetDescendantsAllItems($item, $templateItem.ID)
$GetDescendantsAllItems.Items.Count
$GetDescendantsAllItems.TimeSpan.TotalMilliseconds

Write-Host "`nChildren - Recursive" -ForegroundColor Green
$ChildrenRecursive = [Tests]::ChildrenRecursive($item, $templateItem.ID)
$ChildrenRecursive.Items.Count
$ChildrenRecursive.TimeSpan.TotalMilliseconds

Write-Host "`nSelect Items - AllItems" -ForegroundColor Green
$SelectItemsRecursive = [Tests]::SelectItems($item, ".//*[@@templatename='TestItem']")
$SelectItemsRecursive.Items.Count
$SelectItemsRecursive.TimeSpan.TotalMilliseconds

Write-Host "`nSelect Items Fast - AllItems" -ForegroundColor Green
$query = "fast:$($item.Paths.path)//*[@@templatename='TestItem']"
$SelectItemsFast = [Tests]::SelectItemsFast($item, $query, $count)
$SelectItemsFast.Items.Count
$SelectItemsFast.TimeSpan.TotalMilliseconds

Write-Host "`nChildren - SingleLevel" -ForegroundColor Green
$ChildrenSingleLevel = [Tests]::ChildrenSingleLevel($item, $templateItem.ID)
$ChildrenSingleLevel.Items.Count
$ChildrenSingleLevel.TimeSpan.TotalMilliseconds

Write-Host "`nSelect Items - SingleLevel" -ForegroundColor Green
$SelectItems = [Tests]::SelectItems($item, "./*[@@templatename='TestItem']")
$SelectItems.Items.Count
$SelectItems.TimeSpan.TotalMilliseconds

Write-Host "`nGetDescendants - SingleItem" -ForegroundColor Green
$GetDescendantsSingleItem = [Tests]::GetDescendantsSingleItem($item, $templateItem.ID)
$GetDescendantsSingleItem.Items.Count
$GetDescendantsSingleItem.TimeSpan.TotalMilliseconds

Write-Host "`nChildren - SingleItem" -ForegroundColor Green
$ChildrenSingleItem = [Tests]::ChildrenSingleItem($item, $templateItem.ID)
$ChildrenSingleItem.Items.Count
$ChildrenSingleItem.TimeSpan.TotalMilliseconds

Write-Host "`nSingle Item - SingleLevel" -ForegroundColor Green
$SelectItem = [Tests]::SelectItem($item, "./*[@@templatename='TestItem']")
$SelectItem.Items.Count
$SelectItem.TimeSpan.TotalMilliseconds

Write-Host "`nSingle Item - Recursive" -ForegroundColor Green
$SelectItemRecursive = [Tests]::SelectItem($item, ".//*[@@templatename='TestItem']")
$SelectItemRecursive.Items.Count
$SelectItemRecursive.TimeSpan.TotalMilliseconds

Write-Host "`nSelect Item Fast - SingleItem" -ForegroundColor Green
$query = "fast:$($item.Paths.path)/*[@@templatename='TestItem']"
$SelectItemFast = [Tests]::SelectItemFast($item, $query, $count)
$SelectItemFast.Items.Count
$SelectItemFast.TimeSpan.TotalMilliseconds

Write-Host "`nSelect Item Fast - AllItems" -ForegroundColor Green
$query = "fast:$($item.Paths.path)//*[@@templatename='TestItem']"
$SelectItemFast = [Tests]::SelectItemFast($item, $query, $count)
$SelectItemFast.Items.Count
$SelectItemFast.TimeSpan.TotalMilliseconds

Results

Average time - no cache

Function Time [ms] Items
GetDescendants - AllItems 536.63012 1110
Children - Recursive 650.29703 1110
Select Items - AllItems 693.7084 1110
Select Items Fast - AllItems 694.98984 1110
Children - SingleLevel 12.03793 10
Select Items - SingleLevel 21.28989 10
GetDescendants - SingleItem 493.75492 1
Children - SingleItem 14.90564 1
Single Item - SingleLevel 23.95847 1
Single Item - Recursive 25.20063 1
Single Item Fast - SingleItem 26.48343 1
Single Item Fast - Recursive 35.9395 1

Average time - with cache

Function Time [ms] Items
GetDescendants - AllItems 16.84566 1110
Children - Recursive 24.65328 1110
Select Items - AllItems 94.90774 1110
Select Items Fast - AllItems 32.19504 1110
Children - SingleLevel 0.20868 10
Select Items - SingleLevel 0.64663 10
GetDescendants - SingleItem 16.11355 1
Children - SingleItem 0.16458 1
Single Item - SingleLevel 0.26698 1
Single Item - Recursive 0.25829 1
Single Item Fast - SingleItem 11.44318 1
Single Item Fast - Recursive 22.55551 1

Summary

My goal was to answer my question not test Sitecore speed. I wanted to know whether using InheritsFrom instead of putting conditions in query isn’t slower.

It turned out that there is noting to be afraid of. Actually the new method is even faster than the old one.

SXA 1.5 hotfix: UploadMediaDialog

How to solve the issue with UploadMediaDialog Continue reading

Beautify Sitecore field names

Published on November 30, 2017