Time out retrieving items from list - sql

I have a problem retrieving items from a fairly large list. I can quickly and easily retrieve items from a small list with more or less 50 items, but when I try to retrieve items from a list containing more or less 4600 items, the sqlsever.exe process spikes for the duration of the request, but the items are never retrieved. If have set up the web applications throttling settings, so it can’t be that which is causing the problem. Here is the code that I originally used to retrieve the items. There is really nothing special to it.
using (SPSite site = new SPSite(siteUrl))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists[uid.ToString()];
SPListItemCollection itemCollection = list.Items;
foreach (SPListItem i in itemCollection) //This is where the code stops responding
{
//Use list items
}
}
}
After that didn’t work, I tried a couple of other methods to retrieve the items from the list. Here is the code:
SPList list = web.Lists[uid.ToString()];
SPQuery query = new SPQuery();
query.Query = "";
query.QueryThrottleMode = SPQueryThrottleOption.Override;
SPListItemCollection itemCollection = list.GetItems(query);
//The code stops here
//I added this part for interest sake, i wanted to if it was the looping that caused the problem
//It seems the when you try to access properties of the item collection that the problem occurs
int itemCount = itemCollection.Count;
foreach (SPListItem i in itemCollection)
{
//Use list items
}
I also tried:
SPList list = web.Lists[uid.ToString()];
SPListItemCollectionPosition pos;
DataTable dt = list.GetDataTable(new SPQuery(), SPListGetDataTableOptions.None, out pos); //The code stops responding here
foreach (DataRow i in dt.Rows)
{
//Use data rows
}
Does anyone know what could be causing this problem?
Thank you in advance!

After a very long struggle we found a solution.
We found this post:
http://trycatch.be/blogs/tom/archive/2009/04/22/never-turn-off-quot-auto-create-amp-auto-update-statistics-quot.aspx
We tested it and it worked!!!
So all we had to do was switch "Auto create statistics" and "Auto update statistics" to true, and to problem was solved
Thanks for all the replys

You'll kill your server if you always try to retrieve all items either through list.Items, list.GetItems(query) (with an empty query).
You need to define a relevant query and specify the amount of results you want to retrieve through the RowLimit property of your SPQuery
SPQuery query = new SPQuery();
query.Query = "<OrderBy><FieldRef Name='Title' /></OrderBy>"; // any relevant query here
query.RowLimit = 50;
Failing to do so will load all the items in memory prior to any other operation. You will probably kill your application pool available memory or your sql server memory when it will try to load all these data !
Hope that helped.

Try to get data using CAML query.
Once you have data you can put that in SPQuery.

Try to load the items not all at the same time. You can load them bulk wise (page wise) with the help of SPQuery.ListItemCollectionPosition (http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spquery.listitemcollectionposition.aspx).

Related

Fastest way to get the properties of umbraco documents

I am working on search functionality for a website designed through umbraco. I am using Examine to fetch the search results. Here is my code:
var Searcher = ExamineManager.Instance.SearchProviderCollection["ExternalSearcher"];
var searchCriteria = Searcher.CreateSearchCriteria(BooleanOperation.Or);
var query = searchCriteria.Field("tags", searchTerm.Fuzzy(0.5f)).Compile();
var searchResults = Searcher.Search(query);
With this method i can only get the nodes in which the search term belongs.But I want to directly fetch the whole value from the property.
I want to know what is the fastest way to fetch all the values from the same property in all the nodes.
I have finally managed to get the values directly from the property.This is the code I have used:
List<string> nodesList = new List<string>();
var Searcher = ExamineManager.Instance.SearchProviderCollection["ExternalSearcher"];
var searchCriteria = Searcher.CreateSearchCriteria(BooleanOperation.Or);
var query = searchCriteria.Field("tags", queryString.Fuzzy(0.5f)).Compile();
var searchResults = Searcher.Search(query);
foreach (var item in searchResults)
{
string paths = ((Examine.SearchResult)item).Fields["tags"];
nodesList.Add(paths);
}
using ((Examine.SearchResult)item).Fields["tags"] gets the property value directly.
If you want to costumize your search you need to define a new index set with the properties that you actually want to search on the /config/examineIndex.config file.
Quite well explained in this post.

Adding key value to RavenDB document based on another document's values (For all documents in large collection)

I am new to RavenDB and could really use some help.
I have a collection of ~20M documents, and I need to add a key to each document. The challenge is that the value of the key needs to be derived from another document.
For instance, given the following document:
{
"Name" : "001A"
"Date" : "09-09-2013T00:00:00.0000000"
"Related" : [
"002B",
"003B"
]
}
The goal is to add a key that holds the dates for the related documents, i.e. 002B and 003B, by looking up the related documents in the collection and returning their date. E.g.:
{
"Name" : "001A"
"Date" : "09-09-2013T00:00:00.0000000"
"Related" : [
"002B",
"003B"
]
"RelatedDates" : [
"08-10-2013T00:00:00.0000000",
"08-15-2013T00:00:00.0000000"
]
}
I realize that I'm trying to treat the collection somewhat like a relational database, but this is the form that my data is in to begin with. I would prefer not to put everything into a relational dataset first in order to structure the data for RavenDB.
I first tried doing this on the client side, by paging through the collection and updating the records. However, I quickly reach the maximum number of request for the session.
I then tried patching on the server side with JavaScript, but I'm not sure if this is possible.
At this point I would greatly appreciate some strategic guidance on the right way to approach this problem, as well as, more tactical guidance on how to implement it.
The recommended way of doing this is via a Console application that loops thru all your records, similar to what you have already done but in a way that pages the data so you dont hit the maximum number of requests per session.
See this example from the ravendb source code example application:
you need to do something like this:
using (var store = new DocumentStore { ConnectionStringName = "RavenDB" }.Initialize())
{
int start = 0;
while (true)
{
using (var session = store.OpenSession())
{
var posts = session.Query<Post>()
.OrderBy(x => x.CreatedAt)
.Include(x => x.CommentsId)
.Skip(start)
.Take(128)
.ToList();
if (posts.Count == 0)
break;
foreach (var post in posts)
{
session.Load<PostComments>(post.CommentsId).Post = new PostComments.PostReference
{
Id = post.Id,
PublishAt = post.PublishAt
};
}
session.SaveChanges();
start += posts.Count;
Console.WriteLine("Migrated {0}", start);
}
}
}
I've done this sort of thing with about ~1.5M records and it wasnt exactly quick to do the migration. If your records are small then you can just Load<> and SaveChanges on each one as from experience programmatically patching the documents did not speed things up materially
As a side note, the ravendb google groups is very active if you want to ask specifically about doing this from the studio

given a list of objects using C# push them to ravendb without knowing which ones already exist

Given 1000 documents with a complex data structure. for e.g. a Car class that has three properties, Make and Model and one Id property.
What is the most efficient way in C# to push these documents to raven db (preferably in a batch) without having to query the raven collection individually to find which to update and which to insert. At the moment I have to going like so. Which is totally inefficient.
note : _session is a wrapper on the IDocumentSession where Commit calls SaveChanges and Add calls Store.
private void PublishSalesToRaven(IEnumerable<Sale> sales)
{
var page = 0;
const int total = 30;
do
{
var paged = sales.Skip(page*total).Take(total);
if (!paged.Any()) return;
foreach (var sale in paged)
{
var current = sale;
var existing = _session.Query<Sale>().FirstOrDefault(s => s.Id == current.Id);
if (existing != null)
existing = current;
else
_session.Add(current);
}
_session.Commit();
page++;
} while (true);
}
Your session code doesn't seem to track with the RavenDB api (we don't have Add or Commit).
Here is how you do this in RavenDB
private void PublishSalesToRaven(IEnumerable<Sale> sales)
{
sales.ForEach(session.Store);
session.SaveChanges();
}
Your code sample doesn't work at all. The main problem is that you cannot just switch out the references and expect RavenDB to recognize that:
if (existing != null)
existing = current;
Instead you have to update each property one-by-one:
existing.Model = current.Model;
existing.Make = current.Model;
This is the way you can facilitate change-tracking in RavenDB and many other frameworks (e.g. NHibernate). If you want to avoid writing this uinteresting piece of code I recommend to use AutoMapper:
existing = Mapper.Map<Sale>(current, existing);
Another problem with your code is that you use Session.Query where you should use Session.Load. Remember: If you query for a document by its id, you will always want to use Load!
The main difference is that one uses the local cache and the other not (the same applies to the equivalent NHibernate methods).
Ok, so now I can answer your question:
If I understand you correctly you want to save a bunch of Sale-instances to your database while they should either be added if they didn't exist or updated if they existed. Right?
One way is to correct your sample code with the hints above and let it work. However that will issue one unnecessary request (Session.Load(existingId)) for each iteration. You can easily avoid that if you setup an index that selects all the Ids of all documents inside your Sales-collection. Before you then loop through your items you can load all the existing Ids.
However, I would like to know what you actually want to do. What is your domain/use-case?
This is what works for me right now. Note: The InjectFrom method comes from Omu.ValueInjecter (nuget package)
private void PublishSalesToRaven(IEnumerable<Sale> sales)
{
var ids = sales.Select(i => i.Id);
var existingSales = _ravenSession.Load<Sale>(ids);
existingSales.ForEach(s => s.InjectFrom(sales.Single(i => i.Id == s.Id)));
var existingIds = existingSales.Select(i => i.Id);
var nonExistingSales = sales.Where(i => !existingIds.Any(x => x == i.Id));
nonExistingSales.ForEach(i => _ravenSession.Store(i));
_ravenSession.SaveChanges();
}

Silverlight is not fetching data from my WCF RIA service

I just started learning Silverlight by walking through the labs posted on Channel9. When I tried to explore a little bit I found that my queries were not working as I thought they would.
To recreate what I have done you would need to create a new Silverlight Business application, create a data entity that is pointed to the Adventureworks LT db, and generate the web services for those entities (including edit).
I then simply drug a RichTextbox to Home.xaml and in Home.xaml.cs I added this code first to OnNavigatedTo and when that didn't work to the constructor.
AdventureWorksDomainContext ctx = new AdventureWorksDomainContext();
EntityQuery<Product> query =
from p in ctx.GetProductsQuery()
select p;
LoadOperation<Product> loadOp = ctx.Load(query);
var paragraph = new Paragraph();
foreach (var product in loadOp.Entities)
{
paragraph.Inlines.Add(new Run { Text = product.Name });
}
richTextBox1.Blocks.Add(paragraph);
When I run the page I never see loadOp.Entities contain a value and I only see the query I expect, go across the wire after all my code has been executed.
I feel like I'm missing something fundamental and this will make more sense if I can find someone to explain it to me.
Thanks,
Eric
The problem is related to the how you are loading the data. The actual Load operation is asynchronous, as is all Silverlight network calls. You are callingt ctx.Load(query) and then immediately setting the paragraph to the entities. You need to use a callback when Load is completed. Something like this,
AdventureWorksDomainContext ctx = new AdventureWorksDomainContext();
EntityQuery<Product> query =
from p in ctx.GetProductsQuery()
select p;
LoadOperation<Product> loadOp = ctx.Load(query,() =>
{
var paragraph = new Paragraph();
foreach (var product in loadOp.Entities)
{
paragraph.Inlines.Add(new Run { Text = product.Name });
}
richTextBox1.Blocks.Add(paragraph);
});
Since you aren't using the entities directly in a binding and are just iterating them, you need to make sure you wait until they are loaded. I can't remember the actual signature of the Load method, so you may need to modify my lambda to make it work.

SetForceCacheRefresh?

How do I re-read some (class) Items from the database? I have read them once and made same updates, updates I dont wont to save. Now I need a complete fresh collection of Items from the database.
I have noticed that there are a function called SetForceCacheRefresh, but how do I use it with a CreateCriteria?
// Mats
IList<T> list = null;
using (Repository rep = new Repository())
{
IQuery iqry = rep.Session.CreateQuery(hql);
iqry.SetForceCacheRefresh(true);
list = iqry.List<T>();
}
Note: Before calling List(), set SetForceCacheRefresh(true) to refresh.