【问题标题】:What is the most efficient search mechanism for this situation?这种情况下最有效的搜索机制是什么?
【发布时间】:2012-08-18 19:41:32
【问题描述】:

我有一个定义如下的类:

public class AlarmViolation
{
    public string ObjectId { get; set; }
    public int ChartType { get; set; }
    public string AlarmInternalId { get; set; }
    public short PositionInSequence { get; set; }
    public short SequenceCount { get; set; }
    public string TagValue { get; set; }
    public DateTime PurgeDate { get; set; }
}

然后我创建一个此类的列表如下:

List<AlarmViolation> alarmViolationList;

我目前执行如下 Linq 查询:

return alarmViolationList
  .Where(row => row.ObjectId == objectId)
  .Where(row => row.ChartType == this.ChartType)
  .Where(row => row.AlarmInternalId == this.InternalId)
  .Where(row => row.PositionInSequence == positionInSequence)
  .Where(row => row.SequenceCount == sequenceCount)
  .Any();

我目前的实现表现很差。该列表通常包含介于 150K 和 300K 之间的条目。此查询会定期执行数百次(大约每 3 分钟一次)。

如果我能以某种方式索引这个列表,或者如果这是一个数据库表,我会在 ObjectId + ChartType 上创建一个索引。

有人可以提出更有效的实施方案吗?如果您需要更多信息,我很乐意提供。

【问题讨论】:

  • 如果我要回答这个问题,我基本上会重复 usr 的回答和 Nawaz;它们不是相互排斥的,因此您可以使用 Nawaz 在您想要为 usr 使用的 IEquality&lt;AlarmViolation&gt; 实现中建议的比较顺序更改。

标签: c# list search


【解决方案1】:

如果我能以某种方式索引这个列表,或者如果这是一个数据库表,我会在 ObjectId + ChartType 上创建一个索引。

这表明您应该创建一个由 ObjectId 和 ChartType 组成的键类型 (AlarmViolationKey?),然后使用 Dictionary&lt;AlarmViolationKey, AlarmViolation&gt;。这将从根本上提高搜索时间。如果您对每个键有多个违规行为,并且您已经以一种不会更改的方式预先创建了列表,您可以改用Lookup

无论你做什么,基本上你都不想做你目前正在做的线性扫描——你想要一个基于哈希的查找。

(根据您的具体情况,您可能仍然需要一个列表,或者您可以完全使用字典而不是列表。没有更多上下文很难说。)

【讨论】:

    【解决方案2】:

    由于您只搜索相等性,我建议您使用哈希表。创建一个将包含您平等搜索的所有成员的类(在您的情况下:ObjectId,ChartType,AlarmInternalId,...)。实现EqualsGetHashCode

    接下来,使用Enumerable.ToDictionaryEnumerable.ToLookup 将所有对象放入查找表中。您可以使用新创建的“键”类来添加项目并搜索项目。

    这将为您提供恒定的时间查找,即使是多个结果。

    【讨论】:

    • 或者因为唯一感兴趣的是“key”,那么使用 HashSet(或者如果你真的喜欢 linqyness 创建一个 ToHashSet of public static HashSet&lt;TSource&gt; ToHashSet&lt;T&gt;(this IEnumerable&lt;T&gt; src){ return source.ToHashSet(); }
    • 这个扩展方法的好主意。无论如何,我正在为“键”不是键的可能性做准备(可能有多个匹配元素)。
    【解决方案3】:

    你为什么不写这个:

    return alarmViolationList
          .Any(row => row.ChartType == this.ChartType &&              //int
                      row.PositionInSequence == positionInSequence && //short
                      row.SequenceCount == sequenceCount &&           //short
                      row.AlarmInternalId == this.InternalId &&       //string
                      row.ObjectId == objectId);                      //string
    

    在我看来,这应该会在一定程度上提高性能。请注意,我在进行string 比较之后 intshort 比较,利用短路。

    【讨论】:

    • 仍然是线性扫描。这几乎没有任何改善。
    • @usr,除非有非常多的项目都具有相同的ChartType,否则这将更快地进行线性扫描。 “线性”意味着 O(n) 意味着 n * k,这可能比问题中的 k 值更小 - 基于这样一个事实,即 int 和 short 比较本身是 O(1) 而字符串比较本身是上)。了解哪些值更可能与数据使用匹配或不匹配也可以进一步改善这一点。
    • 来自问题的@Nawaz:The list will typically contain somewhere between 150K and 300K entries
    猜你喜欢
    • 1970-01-01
    • 2016-09-05
    • 2013-04-23
    • 1970-01-01
    • 2016-02-24
    • 1970-01-01
    • 2017-06-11
    • 2017-02-15
    • 2012-05-04
    相关资源
    最近更新 更多