Я уверен, что все знают радости concurrency, когда дело доходит до потоковой передачи.
Представьте себе следующий сценарий при каждой загрузке страницы на noobily setup MySQL db:
UPDATE stats SET visits = (visits+1)
Если тысяча пользователей загружает страницу одновременно, будет ли счет причиной каких-либо проблем? это механизм блокировки/блокировки таблицы? Какой из них использует mysql.
У вас есть две потенциальные проблемы:
Правильный ответ зависит от того, могут ли два пользователя вычислить (посещение + 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
И бинго: Тупик
Для сайтов с большими объемами вы можете подумать о записи события "Посещение" в очередь и иметь демона, слушающего эти события и поддерживающего счет. Более сложное, но, возможно, меньшее количество конфликтов.
Нет, это не испортит. Это вполне приемлемо в любой ACID-совместимой БД. I
означает Изоляцию. Каждый из этих запросов блокирует все строки в таблице visit. A
(в ACID) означает Atomicity и означает, что транзакция должна выполняться полностью или полностью.
Все ответы до сих пор предполагают таблицу InnoDB
, которая поддерживает транзакции; с таблицами MyISAM
вместо этого вы получаете "атомные транзакции", что должно быть хорошо для вашего конкретного варианта использования (хотя для общего случая они недостаточно полны).
В документах MySQL по транзакциям (например, здесь) он дает вашу форму UPDATE
как хорошую практику типичный случай, в частности, и я цитирую...:
Это дает нам нечто, что аналогично блокировке столбцов, но на самом деле даже лучше, потому что мы только обновите некоторые столбцы, используя значения, относящиеся к их текущие значения. Это значит, что типичные заявления UPDATE что-то вроде этого:
UPDATE tablename SET pay_back=pay_back+125;
... Это очень эффективно и работает, даже если другой клиент изменил значения в
pay_back
[[column]]
Для MySQL руководство говорит:
[Повторяемое чтение] - это уровень изоляции по умолчанию для InnoDB. [...] Для операторов [...]
UPDATE
иDELETE
блокировка зависит от того, использует ли оператор уникальный индекс с уникальным условием поиска или условие поиска типа диапазона. Для уникального индекса с уникальным условием поиска InnoDB блокирует только найденную индексную запись, а не пробел перед ней. Для других условий поиска InnoDB блокирует сканируемый диапазон индексов, используя блокировки блокировки или блокировки блокировки плюс индекс-запись, чтобы блокировать вставки другими сеансами в промежутки, охватываемые диапазоном.
Итак, я бы сказал, да, все в порядке, хотя этот конкретный запрос может блокировать всю таблицу. Вероятно, было бы лучше:
UPDATE stats SET value = value + 1 WHERE key = 'visits'
с индексом на "ключ".
Это будет работать, если вы:
Будьте особенно осторожны со второй точкой. Это не проблема, потому что MySQL позволяет вам блокировать блокировки до такой степени, что это действительно испортит.
С другой стороны (когда блокировка настроена правильно), если вы нажмете какой-то (очень) интенсивный трафик, это может стать вашей горлою бутылки (поскольку она может выполняться только в одном потоке). Если вы держите транзакцию открытой дольше, чем просто для обновления числа, это становится более вероятным, и это может даже вызвать тупик, если вы не будете осторожны, поскольку подробно объясняет djna.
Убедитесь, что у вас есть SET autocommit
, поэтому это рассматривается как транзакция, и счет будет прекрасным. Единственное беспокойство - производительность (например, наличие горячей точки таблицы).
Как сказали все, это заблокирует строку, если вы используете InnoDB. Теперь, если вы используете только одну строку, и эта строка хранит статистику обо всех обращениях, тогда блокировка этой строки может замедлить работу, так как запросы ожидают получения блокировки. Это замедление может быть незаметным под вашими нагрузками. Если это важно, вы можете обойти его, написав несколько разных строк, скажем 0-255. Это все равно будет блокировать каждую строку, но вероятность блокировки теперь составляет 1/256 от того, что изначально было. Когда вы хотите получить общее количество, вы можете просто суммировать все строки.
UPDATE stats SET value=value+1 WHERE id=X
где X - случайный id 0-255
затем
SELECT SUM(value) FROM stats
даст вам реальную сумму.
Это нормально.
все, что "блокировка таблицы/блокировка строк" - это базы данных дерьма, которые были изобретены, чтобы позаботиться.
Могут возникнуть другие проблемы, когда "тысяча пользователей загружает страницу одновременно", например, обновление индекса. Но эта другая история и noobily настройка MySQL в любом случае не являются случаем.