2015-02-10 2 views
3

Я хочу найти набор пользователей, не имеющих профиля.Arangodb AQL Filter NOT IN collection, очень медленно

ArangoDB 2.4.3 

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

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

Это AQL фрагмент кода я сделал это медленнее, чем улитка пересечения Гранд-Каньон в середине лета.

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) 

Я уверен, что есть совершенно нормальный способ сделать это правильно, но я пропущу его. Есть идеи?

Edit 1 (После того, как @dothebart «s ответ):

Это новый запрос, но он по-прежнему очень медленно

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) 

ответ

5

Следует также отметить, что эта часть исходного запроса была чрезвычайно дорогой:

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 
+0

Фантастический, работал как шарм! Спасибо (и за объяснение)! :) – rollingBalls

3

Причина плохой работы является то, что он не сможет использовать индексы для вашей операции, так как он должен полностью сравнивать каждый документ в коллекции.

Вы можете использовать shure использовать объяснение https://www.arangodb.com/2015/02/02/arangodb-2-4-2, чтобы арангод рассказывал вам, где стоят ваши расходы.

Ваш запрос, вероятно, не будет делать то, что вы ожидаете от него. usersWithoutProfiles будет пустым, так как любой пользователь с профилем будет найден в коллекции пользователей. Если вы хотите иметь другую часть коллекции пользователей, это может выглядеть так:

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) 

должен дать вам правильный результат.

+0

Спасибо, я не могу поверить, что я сделал, что логическая ошибка на втором part: o Тем не менее, запрос все еще медленный :(- я перезапустил db после 5 минут 100% -ного процессора. – rollingBalls

Смежные вопросы