В моем приложении BugTracker.NET я предполагаю, что ошибок будет не слишком много. Может быть, десятки тысяч, но не десятки миллионов. Это предположение позволяет мне кэшировать теги и идентификаторы элементов, на которые они ссылаются.
В базе данных теги сохраняются по мере ввода вместе с ошибками в текстовом поле с разделителями-запятыми.
Когда поле тега добавляется или изменяется, это запускает фоновый поток, который выбирает все ошибки и их теги, анализирует текст, формируя карту, где ключ является тегом, а значение представляет собой список всех идентификаторов, которые есть этот тег. Затем я кеширую эту карту в объекте приложения Asp.Net.
Ниже приведен код, который я только что описал.
Код можно оптимизировать так, чтобы вместо прохождения всех ошибок он просто постепенно изменял кэшированную карту, но даже неоптимизирован, он отлично работал.
Когда кто-то выполняет поиск по тегу, я смотрю значение на карте, получаю список идентификаторов, а затем извлекаю эти ошибки, используя SQL с "where id in (1, 2, 3 ...)" пункт.
public static void threadproc_tags(object obj)
{
System.Web.HttpApplicationState app = (System.Web.HttpApplicationState)obj;
SortedDictionary<string,List<int>> tags = new SortedDictionary<string,List<int>>();
// update the cache
DbUtil dbutil = new DbUtil();
DataSet ds = dbutil.get_dataset("select bg_id, bg_tags from bugs where isnull(bg_tags,'') <> ''");
foreach (DataRow dr in ds.Tables[0].Rows)
{
string[] labels = btnet.Util.split_string_using_commas((string) dr[1]);
// for each tag label, build a list of bugids that have that label
for (int i = 0; i < labels.Length; i++)
{
string label = normalize_tag(labels[i]);
if (label != "")
{
if (!tags.ContainsKey(label))
{
tags[label] = new List<int>();
}
tags[label].Add((int)dr[0]);
}
}
}
app["tags"] = tags;
}