Как массировать апсерт на Тарантуле?

#sql #tarantool

Вопрос:

В MySQL я могу сделать что-то вроде этого:

 -- post_id-user_id is unique pair
INSERT INTO userviews(post_id, user_id, view_count) 
VALUES(1,1,1),(2,1,1),(3,1,1),(4,1,1)
ON DUPLICATE KEY UPDATE 
view_count = view_count   1;
 

Или в PostgreSQL:

 INSERT INTO userviews(post_id, user_id, view_count)
VALUES(1,1,1),(2,1,1),(3,1,1),(4,1,1)
ON CONFLICT DO UPDATE SET view_count = view_count   1;
 

Как сделать такие вещи в Тарантуле? (В настоящее время я использую библиотеку Tarantool для циклического увеличения):

 import "github.com/tarantool/go-tarantool"
type AX []interface{}
...
for ... {
   conn.Upsert(`userviews`, tuple, AX{AX{` `,viewCountColumn, 1}})
}
 

Ответ №1:

Имейте в виду, что upsert() это работает иначе, чем у MySQL ON DUPLICATE KEY UPDATE . В отличие от MySQL, он проверяет уникальность только первичного ключа и игнорирует все остальные вторичные уникальные индексы. Не уверен, что это ваш случай, но если вам нужно воспроизвести точное поведение MySQL и обновить запись независимо от того, есть ли дубликат в первичном ключе или в каком-либо вторичном уникальном индексе, единственный достойный способ, который я нашел, — это написать функцию Lua, которая сначала пытается вставить кортеж, и если операция не удалась с кодом ошибки 3 (дубликат ключа существует в уникальном индексе), она выполняет обновление.

(Не знаю точно, но, возможно, вы также можете использовать Tarantool/SQL, который доступен в tarantool начиная со 2-й версии.)

К сожалению, он пока не поддерживает UPSERT: https://github.com/tarantool/tarantool/issues/5732

Ответ №2:

Я предполагаю, что проблема, которую вы хотите решить, связана с производительностью. Наивный вариант (выполнить операцию, дождаться ответа, продолжить следующую операцию) даст около (1 / сетевой RTT) RPS при максимальном: это около 1000 RPS за 1 мс RTT.

Существуют следующие варианты:

  1. Используйте асинхронные операции (go-tarantool поддерживает их) и ждите пакета, а не каждой операции. (Вы даже можете отправить одну партию, ожидая предыдущей.)
  2. Определите функцию Lua, которая принимает пакет запросов и возвращает пакет ответов (если, конечно, вам нужен каждый ответ).
  3. (Не знаю точно, но, возможно, вы также можете использовать Tarantool/SQL, который доступен в tarantool начиная со 2-й версии.)

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