【问题标题】:Combine multiple realm query results .net结合多个领域查询结果.net
【发布时间】:2020-05-10 08:35:57
【问题描述】:

作为Contains 的实现,我正在使用Andy Dent 的written 稍作调整的方法来查询我的领域数据库:

        private IQueryable<Entry> FilterEntriesByIds(IQueryable<Entry> allEntries, int[] idsToMatch)
        {
            // Fancy way to invent Contains<>() for LINQ
            ParameterExpression pe = Expression.Parameter(typeof(Entry), "Entry");

            Expression chainedByOr = null;
            Expression left = Expression.Property(pe, typeof(Entry).GetProperty("Id"));

            for (int i = 0; i < idsToMatch.Count(); i++) {
                Expression right = Expression.Constant(idsToMatch[i]);
                Expression anotherEqual = Expression.Equal(left, right);
                if (chainedByOr == null)
                    chainedByOr = anotherEqual;
                else
                    chainedByOr = Expression.OrElse(chainedByOr, anotherEqual);
            }
            MethodCallExpression whereCallExpression = Expression.Call(
              typeof(Queryable),
              "Where",
              new Type[] { allEntries.ElementType },
              allEntries.Expression,
              Expression.Lambda<Func<Entry, bool>>(chainedByOr, new ParameterExpression[] { pe }));

            return allEntries.Provider.CreateQuery<Entry>(whereCallExpression);
        }

只要我传递的 id 少于 2-3K,这一切都可以正常工作,当我使用大量的 id 时,应用程序就会崩溃,似乎是 stackoverflow 异常。

解决这个问题的第一个想法是将查询分成块然后合并结果,但是ConcatUnion 方法在这些领域IQueryables 上不起作用,所以,我还能如何合并这样的分块结果?还是有其他解决方法?

我不能只是将结果转换为列表或其他东西然后合并,我必须将领域对象返回为IQueryable&lt;&gt;

调用栈:

=================================================================
    Native Crash Reporting
=================================================================
Got a SIGSEGV while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.
=================================================================

No native Android stacktrace (see debuggerd output).

=================================================================
    Basic Fault Address Reporting
=================================================================
Memory around native instruction pointer (0x7c326075c8):0x7c326075b8  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x7c326075c8  fd 7b bb a9 fd 03 00 91 a0 0b 00 f9 10 0e 87 d2  .{..............
0x7c326075d8  10 d0 a7 f2 90 0f c0 f2 b0 0f 00 f9 10 00 9e d2  ................
0x7c326075e8  f0 d5 a9 f2 90 0f c0 f2 b0 13 00 f9 a0 a3 00 91  ................

=================================================================
    Managed Stacktrace:
============================
=====================================
      at Realms.QueryHandle:GroupBegin <0x00000>
      at Realms.RealmResultsVisitor:VisitCombination <0x0007f>
      at Realms.RealmResultsVisitor:VisitBinary <0x003f7>
      at System.Linq.Expressions.BinaryExpression:Accept <0x00073>
      at System.Linq.Expressions.ExpressionVisitor:Visit <0x00087>
      at Realms.RealmResultsVisitor:VisitCombination <0x000d7>
      at Realms.RealmResultsVisitor:VisitBinary <0x003f7>
      at System.Linq.Expressions.BinaryExpression:Accept <0x00073>
      at System.Linq.Expressions.ExpressionVisitor:Visit <0x00087>
      at Realms.RealmResultsVisitor:VisitCombination <0x000d7>
      at Realms.RealmResultsVisitor:VisitBinary <0x003f7>
      at System.Linq.Expressions.BinaryExpression:Accept <0x00073>
      at System.Linq.Expressions.ExpressionVisitor:Visit <0x00087>
      at Realms.RealmResultsVisitor:VisitCombination <0x000d7>
      at Realms.RealmResultsVisitor:VisitBinary <0x003f7>
      at System.Linq.Expressions.BinaryExpression:Accept <0x00073>
      at System.Linq.Expressions.Ex
pressionVisitor:Visit <0x00087>

UPD

我找到了引发此错误的元素的确切数量:3939,如果我传递的值大于该值,它就会崩溃。

【问题讨论】:

  • 这里可能有XY problem 的案例。 :) 不会向查询发送这么多 ID。相反,您可以将它们提取到单独的数据库表中(您可能不必在内存中保存数千个 ID)并在查询中使用它。
  • @ŠimonKocúrek 考虑到这是一种搜索机制,每次进行查询时从数据库中写入和读取的开销会不会太大?
  • 如果查询有数据库提供程序,请注意一个sql命令中的最大参数数,对于SQL Server是2100。
  • @MartinStaufcik 是的,这似乎是问题所在,但我怎样才能避免这样做并在不崩溃的情况下获得“相同”的结果?这就是问题
  • 由于是包含操作,可以发送多个查询,然后合并结果。

标签: c# optimization realm expression-trees


【解决方案1】:

不是数据库专家,只是在不同级别(包括领域)工作过,通常是在某人的较低级别引擎之上。 (Realm 的 real 向导提供的 c-tree Plus ISAM 引擎或 C++ 核心)。

我的第一印象是您拥有大部分静态数据,因此这是一个相当经典的问题,您希望预先生成更好的索引。

我认为您可以使用 Realm 构建这样的索引,但需要更多的应用程序逻辑。

这听起来有点像this SO question 中的倒排索引问题。

对于映射到您的单词的所有单单词组合,并且可能至少是双单词组合,您需要另一个链接到所有匹配单词的表。你可以用一个相当简单的循环来创建那些,从现有的单词中创建它们。

例如:您的OneLetter 表将有一个a 条目,它使用one-to-many 关系与主Words 表中的所有匹配词。

这将提供非常快的Ilist,您可以迭代匹配的单词。

然后您可以在 3 个字母或以上时切换到您的Contains 方法。

【讨论】:

  • 请注意,这种方法,因为它基于 Realm 表,所以 不需要 需要预先构建索引。您还可以添加新单词并为其添加 OneLetter 和 TwoLetter 条目。删除单词也可以。
【解决方案2】:

SQL Server 的 SQL 提供程序可以处理包含超过一个查询中 SQL 参数的最大数量限制(即 2100)的项目的包含操作。

此示例正在运行:

var ids = new List<int>();
for (int i = 0; i < 10000; i++)
{
    ids.Add(i);
}

var testQuery = dbContext.Entity.Where(x => ids.Contains(x.Id)).ToList();

这意味着,您可以尝试重写您的方法以使用ids.Contains(x.Id)

如何做到这一点的一个例子是in this post

更新:抱歉没有提到这是 Realm 的,但也许它仍然值得一试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多