【问题标题】:Is it a good approach to use internal data structure as memory database?使用内部数据结构作为内存数据库是一种好方法吗?
【发布时间】:2016-04-28 05:30:09
【问题描述】:

我正在开发一个非常小规模的程序,主要是使用单词首字母来搜索完整的字符串和附加的额外信息,包括程序中的 CRUD 操作。由于只有大约 10k 字符串要搜索,我更喜欢使用内存中的方法来加快搜索速度(因为大多数查询是 SELECT)。

简单地使用List<myobject> data 之类的东西并执行以下操作:data.Where((s => s.text.Substring(0,3) == expected)); 是一种好方法吗?当我使用这种方法时,我可以对数据库优化(如索引)做些什么吗?

【问题讨论】:

    标签: c# .net database in-memory-database


    【解决方案1】:

    TL;DR
    我建议评估您的要求。如果使用简单的List<> 满足您的要求,并且您对分析应用程序的性能结果感到满意,请使用它。如果不考虑使用内存数据库。


    数据库检索数据足够快的主要原因之一是Index。当您使用常见的 C# 数据结构时,您会错过此功能。我认为如果您处理少量记录,那么您不会遇到性能问题,但如果您有很多记录,那么您应该考虑使用in memory databases。 请记住,所选数据库可能不支持您希望为数据建立索引的方式,或者您有复杂的查询,而索引不会提高其性能。

    如果您只有键和对应的值,请查看 RedisStackExchange.Redis

    要考虑的另一件事是并发!数据库通常支持从多个线程访问数据并处理同一数据的多个读取器或写入器。您可以使用thread-safe collections in .NET,但您必须做很多工作才能获得内置于数据库中的功能。

    【讨论】:

    • 很遗憾听到索引不可用。但是让我们看看这些内部结构在这个特定问题上能起到什么作用。
    【解决方案2】:

    如果您只进行前缀搜索(如问题所示),您可能可以使用列表,只要您保持排序并进行二进制搜索而不是线性搜索(这就是 where会的)。

    如果您进行完全匹配,字典虽然速度会快得多,但在这里不是正确的工具,因为您想要进行仍然是 O(N) 的搜索。

    如果你想使用 LINQ,你最好只使用 EF 和 SQL Server CE。这是一个非常轻松的选择,尽管您显然添加了一些重要的依赖项。

    如果您想在 C# 中推出自己的解决方案,该解决方案的工作方式与数据库的工作方式几乎相同,您正在寻找的数据结构称为 Trie[1] 这仍然不会为您提供 LINQ(除非您编写一堆更多的代码),但会给你很好的搜索性能。

    [1]https://en.wikipedia.org/wiki/Trie

    【讨论】:

    • 如果我想让where 进行二分搜索,我需要告诉框架什么吗?因为二分查找只擅长排序数组。
    • @xxbidiao 没有。您将要使用 List.BinarySearch 而不是 LINQ
    • 不知道SortedList这个工作做得好不好(可以用where做二分查找)。
    • 我对@9​​87654327@ 没有任何经验,也找不到关于 linq 与该集合的圈复杂度的任何信息。您可能想要分析与 BinarySearch 方法。
    【解决方案3】:

    如果您正在使用数据结构,那么您最好使用复杂度为 o(1) 的数据结构,例如 字典哈希表,而不是 列表 具有更慢的复杂性。请注意,该列表正在占用您的一些空闲内存。

    【讨论】:

    • 是的,我肯定会寻找更好的复杂性——我只是以列表为例,因为这是一种支持 LINQ 操作的结构。
    • 字典也支持 LINQ!所有IEnumerables 都支持LINQ。 @xxbidiao
    • 我同意医生的观点 :-)
    • 嗯,是的,我的意思是这只是我所期待的一个干净的例子。但值得一提的是,日常 c# 中使用的大多数常见内部数据结构都支持它。
    • 枚举字典放弃了使用它的主要原因。
    【解决方案4】:

    检查这个测试:

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    
    namespace CSharpConsoleApplication.Tests
    {
        class JustATest
        {
            public static void Run()
            {
                var list = new List<Test>();
    
                for (int i = 0; i < 1000000; i++)
                    list.Add(new Test() { Text = "a" + i.ToString().PadLeft(6, '0') });
    
    
                string input = "a011";
                List<Test> found = null;
    
    
    
    
                // Get the results with LinQ
    
                var w = new Stopwatch(); w.Start();
                found = list.Where(t => t.Text.Substring(0, 4) == input).ToList();
                w.Stop();
                Console.WriteLine("Search list with linq. Results count = {0}", found.Count);
                Console.WriteLine(w.Elapsed);
                Console.ReadLine();
    
    
    
    
                // Store data in dictionary if no refresh needed
    
                // Populate the dictionary
                var objectsDictionary = new Dictionary<string, List<Test>>();
    
                w.Restart();
                PopulateDictionary(objectsDictionary, list, input.Length);
                w.Stop();
                Console.WriteLine("Populate dictionary");
                Console.WriteLine(w.Elapsed);
                Console.ReadLine();
    
                // Search in dictionary
                w.Restart();
                if (objectsDictionary.ContainsKey(input))
                    found = objectsDictionary[input];
                //objectsDictionary[input].ForEach(t => Console.WriteLine(t.Text));
    
                w.Stop();
                Console.WriteLine("Search in dictionary. Results count = {0}", found.Count);
                Console.WriteLine(w.Elapsed);
                Console.ReadLine();
            }
    
            static void PopulateDictionary(Dictionary<string, List<Test>> dictionary, List<Test> list, int textLength)
            {
                foreach (var t in list)
                {
                    string text = t.Text.Substring(0, textLength);
    
                    if (dictionary.ContainsKey(text))
                        dictionary[text].Add(t);
                    else
                        dictionary.Add(text, new List<Test>() { t });
                }
            }
    
            class Test
            {
                public string Text { get; set; }
            }
    
        }
    }
    

    【讨论】:

    • 有趣。如果只搜索固定长度,字典似乎比列表快一点。实际上,如果数据本身很小,那么拥有重复数据是个好主意。在线 c# 运行器上的输出为:Search list with linq. Results count = 1000 00:00:00.2860005 Populate dictionary 00:00:00.2699203 Search in dictionary. Results count = 1000 00:00:00.0000888
    • 我不确定这是否会有所帮助。我的想法是,如果您的数据不经常更改,将它们存储在字典中(当然会有一些开销)使用搜索条件作为关键字,会产生更快的搜索结果。
    猜你喜欢
    • 1970-01-01
    • 2012-04-11
    • 2012-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多