Будет ли этот SQL вызывать какие-либо проблемы?

0

Я уверен, что все знают радости concurrency, когда дело доходит до потоковой передачи.

Представьте себе следующий сценарий при каждой загрузке страницы на noobily setup MySQL db:

UPDATE stats SET visits = (visits+1)

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

  • 0
    Все должно быть в порядке. Я не пишу это как ответ, потому что я не совсем уверен.
Теги:

8 ответов

3
Лучший ответ

У вас есть две потенциальные проблемы:

  • Вы получите правильный ответ?
  • Вы получите необоснованную блокировку, все ваше приложение будет идти очень медленно или даже в тупик.

Правильный ответ зависит от того, могут ли два пользователя вычислить (посещение + 1) при одном и том же посещении. Мы можем представить, что база данных должна выполнять следующие действия:

  Read visit count
  Add one to visit count
  Write visit count

Итак, если два пользователя работают одновременно, они оба могут прочитать одно и то же старое значение? Это означает, что уровень изоляции транзакции вступает в игру. Как заметил Artefacto, уровень изоляции по умолчанию повторяется, и, следовательно, мы получаем:

 Grab a lock
 Read, increment, Write
 Release lock

Вместо

 Read  (two users same old value)
 Increment
 First user Grab Lock, second waits
 Write  
 Release, second user grabs lock
 Write (same value!)
 Release

Однако уровень конкуренции может быть довольно высоким и очень зависит от объема вашей транзакции. Предположим, что у вас есть:

  Begin transaction

  Do the visit increment stuff

  Do some serious business work

  End transaction   <==== visit lock is held until here

Тогда вы получите много людей, ожидающих этого посещения. Мы не знаем общую структуру вашего приложения, независимо от того, используете ли вы такие крупные транзакции. Скорее всего, вы получаете поведение по умолчанию для одной транзакции в SQL-заявлении, и в этом случае вы являетесь конкурентом только на время выполнения инструкции SQL, в значительной степени, как вы надеялись.

Другим людям может быть не так повезло: есть среды (например, Java EE Servlets), где неявные области транзакций могут быть созданы инфраструктурой, а затем более продолжительные транзакции, которые я показываю выше, происходят по умолчанию. Хуже того, что ваш код не написан последовательно (с инкрементным посещением всегда сначала или всегда последним) вы можете получить:

  Begin transaction
  Do the visit increment stuff
  Do some serious business work
  End transaction   <==== visit lock and business locks held until here

и

  Begin transaction
  Do some other serious business work
  Do the visit increment stuff      
  End transaction   <==== visit lock and maybesame business locks held until here

И бинго: Тупик

Для сайтов с большими объемами вы можете подумать о записи события "Посещение" в очередь и иметь демона, слушающего эти события и поддерживающего счет. Более сложное, но, возможно, меньшее количество конфликтов.

3

Нет, это не испортит. Это вполне приемлемо в любой ACID-совместимой БД. I означает Изоляцию. Каждый из этих запросов блокирует все строки в таблице visit. A (в ACID) означает Atomicity и означает, что транзакция должна выполняться полностью или полностью.

  • 0
    Что если он явно не начнет транзакцию?
  • 0
    Я ничего не знаю о транзакциях в MySQL, это автоматически для нубов?
Показать ещё 5 комментариев
2

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

В документах MySQL по транзакциям (например, здесь) он дает вашу форму UPDATE как хорошую практику типичный случай, в частности, и я цитирую...:

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

UPDATE tablename SET pay_back=pay_back+125;

... Это очень эффективно и работает, даже если другой клиент изменил значения в pay_back [[column]]

2

Для MySQL руководство говорит:

[Повторяемое чтение] - это уровень изоляции по умолчанию для InnoDB. [...] Для операторов [...] UPDATE и DELETE блокировка зависит от того, использует ли оператор уникальный индекс с уникальным условием поиска или условие поиска типа диапазона. Для уникального индекса с уникальным условием поиска InnoDB блокирует только найденную индексную запись, а не пробел перед ней. Для других условий поиска InnoDB блокирует сканируемый диапазон индексов, используя блокировки блокировки или блокировки блокировки плюс индекс-запись, чтобы блокировать вставки другими сеансами в промежутки, охватываемые диапазоном.

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

UPDATE stats SET value = value + 1 WHERE key = 'visits'

с индексом на "ключ".

1

Это будет работать, если вы:

  • Выполняются транзакции
  • Правильно настроена блокировка строк.

Будьте особенно осторожны со второй точкой. Это не проблема, потому что MySQL позволяет вам блокировать блокировки до такой степени, что это действительно испортит.

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

1

Убедитесь, что у вас есть SET autocommit, поэтому это рассматривается как транзакция, и счет будет прекрасным. Единственное беспокойство - производительность (например, наличие горячей точки таблицы).

0

Как сказали все, это заблокирует строку, если вы используете InnoDB. Теперь, если вы используете только одну строку, и эта строка хранит статистику обо всех обращениях, тогда блокировка этой строки может замедлить работу, так как запросы ожидают получения блокировки. Это замедление может быть незаметным под вашими нагрузками. Если это важно, вы можете обойти его, написав несколько разных строк, скажем 0-255. Это все равно будет блокировать каждую строку, но вероятность блокировки теперь составляет 1/256 от того, что изначально было. Когда вы хотите получить общее количество, вы можете просто суммировать все строки.

UPDATE stats SET value=value+1 WHERE id=X 

где X - случайный id 0-255

затем

SELECT SUM(value) FROM stats

даст вам реальную сумму.

-1

Это нормально.
все, что "блокировка таблицы/блокировка строк" ​​- это базы данных дерьма, которые были изобретены, чтобы позаботиться.

Могут возникнуть другие проблемы, когда "тысяча пользователей загружает страницу одновременно", например, обновление индекса. Но эта другая история и noobily настройка MySQL в любом случае не являются случаем.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню