Есть ли недостаток слепого использования INSERT в MySQL? - PullRequest
3 голосов
/ 29 сентября 2008

Часто я хочу добавить значение в таблицу или обновить значение, если его ключ уже существует. Это может быть выполнено несколькими способами, предполагая, что первичный или уникальный ключ установлен в столбцах «user_id» и «pref_key» в примере:

1. Слепая вставка, обновите при получении ошибки дублирующего ключа:

// Try to insert as a new value
INSERT INTO my_prefs 
(user_id, pref_key, pref_value)
VALUES (1234, 'show_help', 'true');

// If a duplicate-key error occurs run an update query
UPDATE my_prefs 
SET pref_value = 'true'
WHERE user_id=1234 AND pref_key='show_help';

2. Проверьте наличие, затем выберите или обновите:

// Check for existence
SELECT COUNT(*) 
FROM my_prefs
WHERE user_id=1234 AND pref_key='show_help';

// If count is zero, insert
INSERT INTO my_prefs 
(user_id, pref_key, pref_value) 
VALUES (1234, 'show_help', 'true');

// If count is one, update
UPDATE my_prefs 
SET pref_value = 'true' 
WHERE user_id=1234 AND pref_key='show_help';

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

Ответы [ 9 ]

12 голосов
/ 29 сентября 2008

взгляните на синтаксис ON DUPLICATE KEY в http://dev.mysql.com/doc/refman/5.0/en/insert-select.html

INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name [(col_name,...)]
SELECT ...
[ ON DUPLICATE KEY UPDATE col_name=expr, ... ]
7 голосов
/ 29 сентября 2008

Существует третий путь MySQL, который был бы предпочтительным в этой СУБД

INSERT INTO my_prefs 
(user_id, pref_key, pref_value) 
VALUES (1234, 'show_help', 'true')
ON DUPLICATE KEY 
UPDATE pref_value = 'true'
4 голосов
/ 29 сентября 2008

Лично я никогда не болею за программирование на основе исключений (ожидаю исключения при нормальной работе приложения), и для меня второй пример гораздо более читаемый / поддерживаемый.

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

3 голосов
/ 29 сентября 2008

Если вы хотите избежать «исключения», возможно, вставив дублет, и вы хотите использовать стандартный SQL (а ваш язык программирования / база данных возвращает количество обновленных строк), тогда используйте следующие «SQL» - команды (псевдо -код):

int i = SQL("UPDATE my_prefs ...");
if(i==0) {
    SQL("INSERT INTO my_prefs ...");
}

Это также учитывает, что - для большинства случаев использования - обновления происходят чаще, чем вставки.

2 голосов
/ 29 сентября 2008

Будут ли одновременные вставки в эти строки? Удаления?

«ON DUPLICATE» звучит великолепно (поведение именно то, что вам нужно) при условии, что вы не беспокоитесь о переносимости в не-MySQL базы данных.

«Слепая вставка» кажется разумной и надежной при условии, что строки никогда не удаляются. (Если случай INSERT завершается неудачно, потому что строка существует, UPDATE впоследствии должен быть успешным, потому что строка все еще существует. Но это предположение ложно, если строки удалены - вам потребуется логика повторов.) В других базах данных без «ON DUPLICATE» вы можете подумать об оптимизации, если посчитаете задержку плохой: вы можете избежать обхода базы данных в уже существующем случае, поместив эту логику в хранимую процедуру.

"Проверка на существование" - это сложно получить право, если есть одновременные ВСТАВКИ. Строки могут быть добавлены между вашим SELECT и вашим ОБНОВЛЕНИЕМ. Транзакции даже не очень помогают - я думаю, что даже на уровне изоляции «сериализуемый» вы будете иногда «ошибаться в сериализации доступа из-за одновременного обновления» (или каково бы ни было эквивалентное сообщение об ошибке MySQL). Вам понадобится логика повторов, поэтому я бы сказал, что тот, кто выше предлагает использовать этот метод, чтобы избежать «программирования на основе исключений», ошибочен, как и тот, кто предлагает сначала выполнить ОБНОВЛЕНИЕ по той же причине.

2 голосов
/ 29 сентября 2008

Вместо этого вы можете использовать REPLACE или, если вы используете более современный MySQL, вы можете использовать опцию " INSERT ... ON DUPLICATE KEY UPDATE "

Тот факт, что несколько человек говорили об этом в быстрой последовательности, говорит, что «всегда проверяйте документы MySQL», когда у вас есть проблема, поскольку они достойные и во многих случаях приводят непосредственно к решению.

0 голосов
/ 29 сентября 2008

Пока вы используете MySQL, вы можете использовать ключевое слово ON DUPLICATE. Например:

INSERT INTO my_prefs (user_id, pref_key, pref_value) VALUES (1234, 'show_help', 'true') 
ON DUPLICATE KEY UPDATE (pref_key, pref_value) VALUES ('show_help', 'true');
0 голосов
/ 29 сентября 2008

В вашей модели DAO у вас может быть поле id.

  • Если установлено значение null / -1 / что угодно, данные не были сохранены.

  • Когда вы сохраняете его (или извлекаете из базы данных), присвойте ему значение id в базе данных.

  • Ваш метод persist может проверить идентификатор и передать его в реализацию update () или add ().

  • Недостатки: синхронизация с базой данных и т. Д. Я уверен, что есть и другие, но я действительно должен сделать некоторую работу ...

0 голосов
/ 29 сентября 2008

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

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