Sitecore fast query

Sitecore has multiple ways of accessing data. Accessing data where the location and type is known is usually done using the Sitecore Query:

Item item = Sitecore.Context.Database.SelectSingleItem("/sitecore/context/settings/mysetting");

The string value represents the path to the item to be selected. Selecting multiple items can be done using a similar Sitecore Query:

Item[] items = Sitecore.Context.Database.SelectItems("/sitecore/context/settings/mysetting/*");

The string value represents a Sitecore Query stating to get all children of /sitecore/context/settings/mysetting.

Accessing unknown data is done using searching. One of our preferred methods is to use the build in Lucene indexer in Sitecore. The Lucene index can be configured to index basically anything, and you can have multiple indexes in your system.
But there is another method: Using the Sitecore Fast Query.

Sitecore Fast Query is an overlooked method. Sitecore is only using the technique one place in their own code. And there are limitations to the Fast Query that you need to know before using it. Sitecore Fast Query is a competitor to both Sitecore Query and the Lucene index, as it is faster than the Sitecore Query, but slower than the Lucene index. The Lucene index allows you to make very complex searches, including free text searches. The Sitecore Fast Query is not designed for free text searching, but it is easier to code a Fast Query statement (requires one line of code, as opposed to the 20+ lines of code needed for a Lucene search). Fast Query returns an array of Sitecore Items, where you can use LINQ to further drill down search.

So if I was to give some advice using Sitecore Fast Query? I have always used the Lucene index for my front end code as the Lucene index is the fastest (and it is stable now, which it was not in the first versions of Sitecore 6). For back end code (code working on the Sitecore Shell) I would start with a Fast Query, and if that doesn’t work, I would switch to a Lucene index. I use a DDD approach and creates a Repository that returns an array of items. And if the Fast Query is not fast (or flexible enough), all you have to do is to switch the code inside the Repository.

OK, enough talk, lets code. Here are some examples of Fast Queries:

Any fast query begins with the identifier word “fast:”. Followed by a XPath/Sitecore path like statement. This statement gets all pages where the field DocumentTitle equals mypage:

Database.SelectItems("fast:/sitecore/content//*[@DocumentTitle = 'mypage']");

Queries are not case sensitive. You can use greater/less than, equals or not equals:

Database.SelectItems("fast:/sitecore/content//*[@__sortorder > 500]");

Getting all items lockes by a specific user:

public class LockedItemsRepository
{
  public IEnumerable<Item> GetLockedItems(Database database, Account account)
  {
    return database.SelectItems("fast://*[@__lock='%\"" + account.Name + "\"%']");
  }
}

The example above is an example of a Repository. This repository only contains one function, and I only have one line of code. However, if my fast query is not fast enough, I can change the GetLockedItems to return items from a Lucene index.

Another example, taken from my Sitecore Large Gallery Button blog post. Getting all items modified by the current user:

private IEnumerable<Item> SearchForItems()
{
  return Sitecore.Context.ContentDatabase.SelectItems("fast:/sitecore/content//*[@__updated by = '" + CurrentUser + "']");
}

private string CurrentUser
{
  get
  {
    return Context.User.Name;
  }
}

You can further modify your collection by adding a LINQ statement. Here I get the last 10 modified documents:

IEnumerable<Item> searchedItems = SearchForItems().OrderByDescending(w => w.Statistics.Updated).Take(10);
foreach (Item item in searchedItems)
{
  // do something
}

 Let’s look at the drawbacks. Sitecore has written a PDF document called Using Sitecore Fast Query. In here you can read that:

  • You should not query more than 10 fields in one statement, as the performance decreases.
  • Only 4 axes are supported (parent:: child:: ancestor:. and descendant::)
  • Some special attributes cannot be searched (id, name, key, template, ..)
  • It cannot search in standard values
  • No support for functions, operators or subqueries

However, I have experienced that the fast query supports most of my simple searches. And since Lucene supports all advanced searches, Sitecore is very well covered. Fast query is brilliant but overlooked and should be a part of every developers toolbox.

About these ads

About briancaos

Developer at Pentia A/S since 2003. Have developed Web Applications using Sitecore Since Sitecore 4.1.
This entry was posted in General .NET, Sitecore 6 and tagged , , , . Bookmark the permalink.

15 Responses to Sitecore fast query

  1. Also keep in mind that a huge drawback is the query itself. It’s basically bypassing the whole Sitecore caching mechanism.
    This means that you have to watch out that you’re not going to do several queries on an individual page, as this could become a scaling and performance risk.

  2. briancaos says:

    I was once told that the fast query is actually converted into SQL select statements that is fired diretly at the database, thus bypassing the Sitecore cache layers.
    This is a drawback for some queries, but a benefit for others.
    Searches that basically crawls the entire content tree (like getting all locked items, or items newer than a certain date) would benefit from not having to go through the cache layer, as you avoid flooding the cache with items. Other, more specific searches (like getting all children of an item) should probably go through the Sitecore cache layers, or the Lucene index.

  3. Alex Shyba says:

    Hi Brian,

    Great article. Fast Query indeed gets overlooked in my experience as well. Totally agree – it is a matter of right tool for the job.

    One thing I would add that was recently discovered. Fast Query does not support context language, which could be a showstopper for multilingual implementations.

  4. Sean Holmesby says:

    Hi Brian,
    Great post. Fast Query is something I’ve always wondered about because in my testing within the XPathBuilder in the Developer Center I get mixed results.
    For instance, we have a heap of suppliers in Sitecore, so if I test a Sitecore Query like:-
    /sitecore/content/suppliers//*[@@tid = '{A4C32168-4181-4C75-A204-16167554060D}'], and I get results in ~350ms every time.

    Then with the fast query equivalent:-
    fast:/sitecore/content/suppliers//*@@templateid = ‘{A4C32168-4181-4C75-A204-16167554060D}’], I get the first run being about 2,500ms, then consequent runs being 100ms.

    Further to this, when I tried to access a particular field of those items, say the ‘Package’ field, I found that:-
    Sitecore Query:
    /sitecore/content/Suppliers//*[@package= '{0574165D-C62D-40FD-8107-8D8C1FE90E23}'] retrieved items in ~320ms

    Sitecore Fast Query Equivalent:
    fast:/sitecore/content/Suppliers//*[@package= '{0574165D-C62D-40FD-8107-8D8C1FE90E23}'] retrieved all items in ~4,500ms.

    Given these results, I am yet to be convinced that I am using Sitecore Fast Query in the correct way, or in the right circumstances.

    Given my examples, would you have any tips for me?

  5. briancaos says:

    I did some further testing as well, and found similar results.
    I tested the following statement against the CORE database (chosen because it has a lot of contents):

    /sitecore/content//*[@__updated by = 'sitecore\admin']

    Without “fast:” it took 5ms. With fast it took 1.5 seconds. Not very fast, eh?

    But here’s the catch: The Sitecore Query only returns 100 items, or whatever the Query.MaxItems threshold in the web.config is stating. The fast query returns all 1058 results, which of course is slower.
    I then changed the Query.MaxItems to 2000 and did the run again. My Sitecore Query statement was now just as slow as the fast query, but the statement only returned 753 results? It should have returned 1058.

    As I said before, use the right tool for the job. I always use the Lucene index for my front end queries. For my back end tools, I prefer starting with a fast query statement, and if it does not work, I switch to Lucene.

  6. Sean Holmesby says:

    Weird results you have there…. especially with Sitecore Query returning about 300 less results than expected….

    I did some more testing with my suppliers. My Query.MaxItems is set to 0, which the comments tell me will return all items.
    I ran the Sitecore Query:-
    /sitecore/content/Suppliers//*[@__created > '20100501T050000']
    which returned 6265 results in ~450ms.

    The Fast Query equivalent returned the same amount of results (6265) in a little over 5 seconds. As you said, not very fast, but at least I got the same results for both.

    I suppose I’ll just test each query type whenever I need to use it in code, and see which of the three solutions fit best.

  7. Sumit says:

    Dear sir ,

    Plz kindly solution for index fast query

    but serverslow
    plz send query database fast query,

    Sumit.

  8. Kris says:

    Why doesn’t Sitecore combine Lucene with Sitecore queries? Working with both individually is a pain, but would seem to work great together.

  9. Pingback: Is Sitecore security slowing you down? « Brian Pedersen’s Sitecore and .NET Blog

  10. sumith says:

    what is the workaround for ” One thing I would add that was recently discovered. Fast Query does not support context language, which could be a showstopper for multilingual implementations.”

  11. Pingback: Sitecore query items returning out of order | Virtual Duct Tape

  12. When I create a “redirect” from startswith type, as I do to make it case insensitive. Greetings.

  13. When I create a “redirect” from startswith type, as I do to make When I create a “redirect” from startswith type, as I do to make it case insensitive?. Greetings.it case insensitive. Greetings.

  14. Rick Minozzi says:

    I have seen unpredictable results using Fast Query as well. We have been using it in one cast to retrieve an item by template id. Although i see in this post that Fast Query may not support this, it seems to be working 99% of the time.

    The oddity we have seen is that it doesn’t always return the expected result. After publishing brand new content, the new items are not returned all the time. Deleting these items from the WEB database and doing a republish resolves the issue.

    Anyone face this issue before?

  15. Blue says:

    How can Sitecore.Context.ContentDatabase be null MF

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s