Более эффективный способ суммировать разницу между столбцами в postgres? - PullRequest
0 голосов
/ 19 сентября 2019

Для моего приложения у меня есть таблица с этими тремя столбцами: user, item, value

Вот некоторые примеры данных:

user    item    value
---------------------
1       1       50
1       2       45
1       23      35
2       1       88
2       23      44
3       2       12
3       1       27
3       5       76
3       23      44

Что мне нужно сделать, это для данного пользователя,выполнять простую арифметику со всеми остальными значениями.

Допустим, я хочу сравнить пользователя 1 со всеми остальными.Расчет выглядит примерно так:

first_user    second_user    result
1             2              SUM(ABS(50-88) + ABS(35-44))
1             3              SUM(ABS(50-27) + ABS(45-12) + ABS(35-44))

В настоящее время это узкое место в моей программе.Например, многие из моих запросов начинают занимать 500+ миллисекунд, этот алгоритм занимает около 95% времени.

У меня много строк в базе данных, и это O (n ^ 2) (этодолжен сравнить все значения пользователя 1 со всеми совпадающими значениями)

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

Второй способ - сделать алгоритм намного быстрее.Я искал "postgres SIMD", потому что я думаю, что SIMD звучит как идеальное решение для оптимизации этого.Я нашел пару связанных ссылок, таких как this и this , но я не уверен, применимы ли они здесь.Кроме того, им кажется, что им около 5 лет, и они относительно не поддерживаются.

Поддерживает ли Postgres такую ​​функцию?Где вы можете «векторизовать» столбец или, возможно, импортировать или включить какое-либо расширение или функцию, чтобы позволить вам быстро выполнять эти виды основных арифметических операций со многими строками?

1 Ответ

1 голос
/ 19 сентября 2019

Я не уверен, где вы получите O (n ^ 2) для этого.Вам нужно найти строки для пользователя 1, а затем прочитать данные для всех остальных.Предполагая, что элементов мало и много пользователей, это будет по существу O (n), где «n» - это количество строк в таблице.

Запрос можно сформулировать так:

select t1.user, t.user, sum(abs(t.value - t1.value))
from t left join
     t t1
     on t1.item = t.item and
        t1.user <> t.user and
        t1.user = 1
group by t1.user, t.user;

Для этого запроса требуется индекс для t(item, user, value).

...