#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.
Существуют следующие варианты:
- Используйте асинхронные операции (go-tarantool поддерживает их) и ждите пакета, а не каждой операции. (Вы даже можете отправить одну партию, ожидая предыдущей.)
- Определите функцию Lua, которая принимает пакет запросов и возвращает пакет ответов (если, конечно, вам нужен каждый ответ).
- (Не знаю точно, но, возможно, вы также можете использовать Tarantool/SQL, который доступен в tarantool начиная со 2-й версии.)
Вы также можете использовать операцию «оценка» без наличия функции на стороне сервера, но для этого требуется разрешение «выполнить» для «вселенной», и поэтому обычно не рекомендуется (за исключением целей тестирования и экспериментов).