Лучший подход для запроса строк в очень большой базе данных? - PullRequest
0 голосов
/ 11 октября 2019

В базе данных Postgres я выполняю запрос, который ищет строку, которая является хешем sha256 в таблице с прибл. 5 * 10 ^ 8 строк. Этот запрос может занять до 9 секунд, что звучит нормально для одной точки данных, однако мне нужно выполнить этот запрос на объединение 10 ^ 9 раз (для каждого элемента в другой таблице). Столбец, содержащий хэш sha256, проиндексирован, также у меня нет никакой дополнительной информации (идентификатор или метка времени), которую я мог бы использовать для поиска только части строки и этого идентификатора.

Моя текущая настройкачтобы вызвать этот медленный запрос от демона python (используя psycopg2), отправьте ему идентификатор из таблицы 10 ^ 9 строк и распечатайте время выполнения каждые 100 выполнений. Я пытался фиксировать каждые несколько запросов, но это не дало ощутимой разницы, автокоммит по умолчанию = выкл.

Я что-то упустил, что могло бы выполнить этот запрос быстрее, или это лучший выбор, чтобы вывести свою базу данных в что-то вродеasticsearch, а затем выполнять поиск строк с помощьюластиком поиска?

РЕДАКТИРОВАТЬ: объяснение медленного запроса:

EXPLAIN UPDATE txout
SET fk_tx_id = txid.tx_id
FROM
(
 SELECT tx.tx_id, txout.tx_hash
 FROM tx tx
 INNER JOIN txout
 ON tx.tx_hash = txout.tx_hash
 WHERE txout.fk_block_id = 398361
) AS txid
WHERE txout.tx_hash = txid.tx_hash
AND txout.fk_block_id = 398361;
-[ RECORD 1 ]--
QUERY PLAN | Update on txout  (cost=149874.29..323547.14 rows=5 width=345)
-[ RECORD 2 ]--
QUERY PLAN |   ->  Nested Loop  (cost=149874.29..323547.14 rows=5 width=345)
-[ RECORD 3 ]--
QUERY PLAN |         ->  Merge Join  (cost=149873.60..150727.71 rows=19864 width=400)
-[ RECORD 4 ]--
QUERY PLAN |               Merge Cond: (txout.tx_hash = txout_1.tx_hash)
-[ RECORD 5 ]--
QUERY PLAN |               ->  Sort  (cost=77894.30..78025.39 rows=52438 width=329)
-[ RECORD 6 ]--
QUERY PLAN |                     Sort Key: txout.tx_hash
-[ RECORD 7 ]--
QUERY PLAN |                     ->  Index Scan using idx_txout_fk_block_id on txout  (cost=0.58..65716.10 rows=52438 width=329)
-[ RECORD 8 ]--
QUERY PLAN |                           Index Cond: (fk_block_id = 398361)
-[ RECORD 9 ]--
QUERY PLAN |               ->  Materialize  (cost=71979.30..72241.49 rows=52438 width=71)
-[ RECORD 10 ]--
QUERY PLAN |                     ->  Sort  (cost=71979.30..72110.39 rows=52438 width=71)
-[ RECORD 11 ]--
QUERY PLAN |                           Sort Key: txout_1.tx_hash
-[ RECORD 12 ]--
QUERY PLAN |                           ->  Index Scan using idx_txout_fk_block_id on txout txout_1  (cost=0.58..65716.10 rows=52438 width=71)
-[ RECORD 13 ]--
QUERY PLAN |                                 Index Cond: (fk_block_id = 398361)
-[ RECORD 14 ]--
QUERY PLAN |         ->  Index Scan using idx_tx_hash on tx  (cost=0.70..8.69 rows=1 width=75)
-[ RECORD 15 ]--
QUERY PLAN |               Index Cond: (tx_hash = txout_1.tx_hash)

Ответы [ 3 ]

0 голосов
/ 11 октября 2019

У вас есть трехстороннее соединение, и неясно, что это должно сделать. Почему бы просто:

EXPLAIN (ANALYZE, BUFFERS) UPDATE txout
SET fk_tx_id = tx.tx_id
FROM
tx tx
WHERE txout.fk_block_id = 398361
and txout.tx_hash = txid.tx_hash

Кроме того, нет особого смысла выполнять его 5 * 10 ^ 8 раз, если не так много различных значений fk_block_id. Вы будете просто обновлять одни и те же строки снова и снова и устанавливать для них одно и то же.

0 голосов
/ 12 октября 2019

Я думаю, что ваш запрос может быть упрощен до:

UPDATE txout
    SET fk_tx_id = tx.tx_id
    FROM tx
    WHERE tx.tx_hash = txout.tx_hash AND
          txout.fk_block_id = 398361;

Для этого запроса вам нужны индексы txout(fk_block_id, tx_hash) и tx(tx_hash).

0 голосов
/ 11 октября 2019

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

Решение Postgresql Если это так, то создание явного внешнего ключа (и связанного с ним индекса) в postgresql окажется первым решением, которое стоит попробовать, хотя он уверен, что с сотнямимиллионов строк в одну сторону и миллиардов в другую, вам понадобится довольно сильная настройка, лежащая в основе вашей базы данных postgresql для построения индекса. После этого запросы должны быть разумными.

решение эластичного поиска Чтобы ответить на ваш более глобальный вопрос, использование чего-то вроде эластичного поиска полностью меняет проблему, поскольку использует суперэффективные обратные индексы для запроса строки супер, иоснован на распределенной системе, где данные отбрасываются на нескольких узлах (то есть на нескольких машинах). Поэтому, если у вас есть много экземпляров в кластере эластичного поиска, вы можете значительно ускорить поиск текста, разбив поиск среди различных сегментов (который распараллеливает поиск), и используя предварительно вычисленный инвертированный индекс. Тем не менее, настройка кластера эластичного поиска является обязательством, и поглощение / индексирование миллиардов записей также не будет быстрым.

Разделяй и властвуй Другое направление, которое вы можете сделать, - это выполнитьприсоединяться локально на вашем компьютере, возможно, разбивая полные таблицы на основе первого символа ваших хэшей, чтобы вы могли «паралеллизировать» ваше объединение с одной работой на первый символ. Кроме того, сортировка и предварительное индексирование обеих таблиц, в postgresql и в памяти, может значительно ускорить такие объединения.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...