Unlängst beschäftigte ich mich mit der Frage, welcher Weg der schnellste ist, um auf die Daten zu zugreifen: der Zugriff über eine CAML Abfrage oder der Zugriff über den Search Index.
Daher habe ich eine SharePoint Kontakt-Liste mit ca. 18.000 Datensätzen gefüllt und dann eine simple Abfrage programmiert. Die Aufgabenstellung war die Suche im “CompanyName” mit dem BeginsWith Operator.
Die CAML Variante:
lbAusgabe.Items.Clear();
SPList firmen = SPContext.Current.Web.Lists["Firmen"];
DateTime start = DateTime.Now;
int anz = 0;
string caml = @"<Where><BeginsWith>
<FieldRef Name='Company'/>
<Value Type='Text'>{0}</Value>
</BeginsWith></Where>";
SPQuery q = new SPQuery();
q.Query = string.Format(caml, txtSuche.Text);
q.QueryThrottleMode = SPQueryThrottleOption.Override;
q.RowLimit = 100;
foreach (SPListItem it in firmen.GetItems(q))
{
lbAusgabe.Items.Add(it["Company"].ToString() ?? "");
anz++;
}
DateTime ende = DateTime.Now;
double Dauer = (ende - start).TotalMilliseconds;
lblDauer.Text = "Dauer:" + Dauer.ToString("#,###");
lblAnzahl.Text = "Anzahl: " + anz.ToString();
Diese Abfrage liefert nur die ersten 100 Datensätze. Da die Abfrage aber über alle Datensätze läuft, ist es notwendig das List Throttling zu deaktivieren. Daher wird der QueryThrottleMode auf “Override” gestellt.
Die zweite Variante verwendet die Keyword Query Language (KQL) und greift somit auf den Search-Index zu:
int anz = 0;
lbAusgabe.Items.Clear();
SPList firmen = SPContext.Current.Web.Lists["Firmen"];
DateTime start = DateTime.Now;
KeywordQuery q = new KeywordQuery();
q.QueryText = "CompanyOWSTEXT:" + txtSuche.Text + "*";
q.QueryText += " AND Path:" + firmen.ParentWeb.Site.Url + firmen.ParentWebUrl + firmen.RootFolder + "*";
q.SelectProperties.Add("Company");
q.RowLimit = 100;
SearchExecutor se = new SearchExecutor();
ResultTableCollection rtc = se.ExecuteQuery(q);
var resultTables = rtc.Filter("TableType", KnownTableTypes.RelevantResults);
var resultTable = resultTables.FirstOrDefault();
foreach(DataRow dr in resultTable.Table.Rows)
{
lbAusgabe.Items.Add(dr["Company"].ToString() ?? "");
anz++;
}
DateTime ende = DateTime.Now;
double Dauer = (ende - start).TotalMilliseconds;
lblDauer.Text = "Dauer:" + Dauer.ToString("#,###");
lblAnzahl.Text = "Anzahl: " + anz.ToString();
Spannend war die Messung der Abfragezeiten. Um valide Ergebnisse zu bekommen, habe ich jede Abfrage mehrmals ausgeführt. Hier die Ergebnisse in Millisekunden:
|
CAML |
Search |
Abfrage 1 |
413 |
138 |
Abfrage 2 |
423 |
201 |
Abfrage 3 |
449 |
109 |
Abfrage 4 |
425 |
113 |
Abfrage 5 |
472 |
105 |
Abfrage 6 |
459 |
112 |
Mittelwert |
440,2 |
129,7 |
Hier ist eindeutig zu erkennen, dass der Zugriff über die Search deutlich schneller ist. Allerdings wurde in der Liste kein Index gesetzt. Sobald in der Kontakt-Liste auf das Feld “CompanyName” ein Index gesetzt wird, sieht das Ergebnis anders aus:
|
CAML |
Search |
CAML Mit index |
Abfrage 1 |
413 |
138 |
34 |
Abfrage 2 |
423 |
201 |
23 |
Abfrage 3 |
449 |
109 |
27 |
Abfrage 4 |
425 |
113 |
26 |
Abfrage 5 |
472 |
105 |
27 |
Abfrage 6 |
459 |
112 |
30 |
Mittelwert |
440,2 |
129,7 |
27,8 |
Und hier sieht man ganz klar, warum es empfehlenswert ist einen Index zu verwenden. Durch diese simple Konfiguration kann die Abfragezeit deutlich reduziert werden!
SharePoint ist keine Datenbank! Wenn die SharePoint-Listen aber dennoch als Datenbank verwendet werden, dann sollte man wie in jeder richtigen Datenbank auch Indizes verwenden!
Diese und weitere Varianten im Umgang mit SharePoint-Listen per Programmcode werden auch in unserer Schulung “SharePoint 2013 - Lösungen entwickeln und anpassen" behandelt.