MySQL InnoDB SELECT... LIMIT 1 ДЛЯ ОБНОВЛЕНИЯ Vs UPDATE... LIMIT 1

У меня есть таблица v_ext в MySQL с движком InnoDB:
 - id: первичный ключ
 - код: предварительно сгенерированный список кодов (скажем, 1000 кодов генерируются случайным образом)
 - user_id: первоначально NULL

Когда пользователь покупает товар, он получает код. Мне нужно обновить таблицу, чтобы заполнить столбец user_id. У меня есть два варианта:

START TRANSACTION;
SELECT id FROM v_ext WHERE user_id IS NULL LIMIT 1 FOR UPDATE; -- return id 54 for ex.
UPDATE v_ext SET user_id=xxx WHERE id=54;
COMMIT;

или

UPDATE v_ext SET user_id=xxx WHERE user_id IS NULL LIMIT 1;

Является ли второй вариант безопасным, если у меня одновременно есть тысячи пользователей? Если да, правильно ли предположить, что этот второй вариант лучше для производительности, так как ему нужен только один запрос?

Ответ 1

Поскольку я не получил ответа, я начал выполнять бенчмаркинг. Мои критерии таковы:

  • 20 000 предварительно сгенерированных кодов
  • Использование команды Apache ab с 20 000 запросов, 100 concurrency: ab -n 20000 -c 100
  • Servlet → EJB (JPA 2.0 EclipseLink, JTA) для выполнения обновления в БД (как это будет с помощью действия JSF в реальной ситуации)
  • 2 версии сервлета, одна с опцией 1 (SELECT... FOR UPDATE), и одна с опцией 2 (UPDATE... LIMIT 1)
  • Остановите Glassfish, ударите проверенный сервлет вручную 5 раз, чтобы согреть его, reset all до NULL до user_id
  • Тесты выполняются 3 раза в каждом и среднее значение

Результаты:

SELECT... FOR UPDATE; UPDATE...:

Concurrency Level:      100
Time taken for tests:   758.116 seconds
Complete requests:      20000
Failed requests:        0
Write errors:           0
Row updated:            20000

UPDATE.... LIMIT 1:

Concurrency Level:      100
Time taken for tests:   773.659 seconds
Complete requests:      20000
Failed requests:        0
Write errors:           0
Row updated:            20000

Итак, по крайней мере, в моей системе опция с двумя запросами кажется более эффективной, чем один запрос. Я не ожидал этого:)