【问题标题】:Arangodb AQL Filter NOT IN collection, very slowArangodb AQL 过滤器不在收集中,非常慢
【发布时间】:2015-02-10 17:13:53
【问题描述】:

我想查找没有个人资料的用户集。

ArangoDB 2.4.3

LENGTH(users) -> 130k
LENGTH(profiles) -> 110k

users.userId -> unique hash index
profiles.userId -> unique hash index

我做的这个 AQL sn-p 比仲夏穿越大峡谷的蜗牛还慢。

LET usersWithProfiles = ( /* This part is ok */
FOR i IN users
    FOR j IN profiles
        FILTER i.userId == j.userId
RETURN i
)

LET usersWithoutProfiles = ( /* This is not */
FOR i IN usersWithProfiles
    FILTER i NOT IN users
RETURN i
)

RETURN LENGTH(usersWithoutProfiles)

我很确定有一种完全理智的方法可以做到这一点,但我错过了它。有什么想法吗?

编辑 1(在 @dothebart 的回复之后):

这是新查询,但还是很慢

LET userIds_usersWithProfile = (
FOR i IN users
    FOR j IN profile
        FILTER i.userId == j.userId
RETURN i.userId
)

LET usersWithoutProfiles = (
FOR i IN users 
    FILTER i.userId NOT IN userIds_usersWithProfile
RETURN i
)

RETURN LENGTH(usersWithoutProfiles)

【问题讨论】:

    标签: arangodb aql


    【解决方案1】:

    另请注意,原始查询的这一部分非常昂贵:

    LET usersWithoutProfiles = (
      FOR i IN usersWithProfiles
        FILTER i NOT IN users
        RETURN i
    )
    

    原因是FILTER 使用users,此时它是一个表达式,它将集合中的所有文档构建为一个数组。 我建议使用此查询,而不是使用此查询,它将返回没有关联个人资料记录的用户的 _key 属性:

    FOR user IN users 
      LET profile = (
        FOR profile IN profiles 
          FILTER profile.userId == user.userId 
          RETURN 1
      ) 
      FILTER LENGTH(profile) == 0 
      RETURN user._key
    

    【讨论】:

    • 太棒了,像魅力一样工作!谢谢你(以及解释)! :)
    【解决方案2】:

    性能不佳的原因是它无法为您的操作使用索引,因为它需要对集合中的每个文档进行全面比较。

    您可以使用 explain https://www.arangodb.com/2015/02/02/arangodb-2-4-2 实用程序让 arangodb 告诉您查询的费用在哪里。

    您的查询可能不会达到您的预期。 usersWithoutProfiles 将为空,因为任何具有 Profile 的用户都可以在 users 集合中找到。如果你想拥有用户集合的另一部分,它可能看起来像这样:

    LET usersWithProfiles = ( /* This part is ok */
    FOR i IN users
        FOR j IN profiles
            FILTER i.userId == j.userId
    RETURN i
    )
    
    /* now we pick the IDs, we could have done that in your first query... */
    LET userWithProfilesIds = FOR i IN userWithProfiles RETURN i.userId;
    
    /* now filter the user list by that */
    LET usersWithoutProfiles = FOR i IN users 
         FILTER i.userId NOT IN userWithProfileIds
         RETURN i;
    
    RETURN LENGTH(usersWithoutProfiles)
    

    应该会给你一个正确的结果。

    【讨论】:

    • 谢谢,我不敢相信我在第二部分犯了这个逻辑错误:o 尽管如此,查询仍然很慢 :( - 我在 100% cpu 5 分钟后重新启动了数据库。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多