Оптимизация таблиц MySQL и запросов к таблицам
Что-то определенное тут не будет сказано, а будут рассмотрен случай, подталкивающих к оптимизации.
Для начала зададимся исходными параметрами сайта:
1. сайт с посещаемостью более 10 000 человек в день
2. сайт представляет собой блог новостей с возможностью комментировать новости
3. При каждом просмотре новости увеличивается ее кол-во просмотров
4. Нужно выводить при выводе новостей: — Количество просмотров — Количество комментариев
При условии п.1 при каждом заходе пользователя в какую-либо новость, увеличивается кол-во просмотров. Зададимся вопросом: Где хранить кол-во просмотров?
Ответ будет следующим:
Хранить кол-во просмотров следует в отдельной таблице. Допустим таблица новостей у нас будет называться blog_news, а таблица просмотров новостей — blog_news_views.
Структура blog_news:
news_id, news_title, create_date, pagetext, active
Структура blog_news_views:
news_id, views
Почему мы так разделяем на две таблицы, когда проще сделать одной таблицей:
news_id, news_title, create_date, pagetext, active, views ?
Ответ:
У нас алгоритм увеличения кол-ва просмотров действует следующим образом. Посетитель заходи в новость, ему она показывается в развернутом виде + список комментариев, в этот момент происходит увеличение кол-ва просмотров, обычным методом:
UPDATE blog_news SET views=views+1 WHERE news_id = 12345;
В момент изменения любых данных в таблице, таблица «лочитца» т.е. закрывается для других изменений, дабы не произошло наложение. (Например, это может проявиться, когда два разных или более админов пытаются добавить новость в таблицу в один и тот же момент времени. Как вы думаете, кто первый добавит новость, если таблицу не закрыть при добавлении новости первым из админов? Не известно что получится или произойдет). И в момент закрытия происходит небольшая пауза, к обращению, т.е. даже любой SELECT будет ожидать открытия таблицы. А у нас есть условие, посещаемость 10000 человек в день, и скажем в один и тот же момент времени, хотя бы 5−6 человек просмотрят новость, для первого она откроется «мгновенно», а для остальных, будет ожидаться «разлочивания», потом отобразится еще кому-то следующему, и для оставшихся — ожидание, и так далее, пока не дойдет до конца, пусть это будут миллисекунды, но для последнего посетителя для текущей новости — может вытечь в секунды.
Что бы этого не происходила, все операции изменения, должны быть сведены к минимуму, или перенесены на другие таблицы (если такое возможно). Как в нашем случае — кол-во просмотров можно перенести в другую таблицы, сделать связку по полю news_id, проставить ключи INDEX в обе таблицы, и без угрызения совести перед посетителями за тормоза (которые в принципе уменьшатся) плюсовать просмотры.
В этом случае пусть хоть миллион человек просмотрит одновременно новость, залочится другая таблица (blog_news_views), которая на отображение никак не влияет.
Не всегда данный вариант может быть полезен, например не стоит выносить все изменяемые записи в отдельные таблицы, т.к. при выборке данных из таблицы, и при необходимости вывода записей из отделенных таблиц, Вам придется делать тяжелые запросы, а это тоже увеличивает время выполнения запроса.
Можно сказать, что оптимизация уникальна для каждого проекта и все зависит от методов программирования, иногда запросы могут выполняться минимально по времени, а обработка PHP кодом полученных данных, достаточно долго.
Интересно, а комментарии которые не нравятся автору тут удаляют?
Bebeshka нет, с чего такие мысли?
То есть получается что при запросе новости она сначала выдается пользователю а потом вносятся изменения в другую таблицу? И поэтому новость не «ждет» завершения всех операций с БД. А если надо использовать ob_start(); то такая оптимизация работать не будет?
Turakod, не много не понял вопроса, отвечу как понял, будет конечно работать оптимизация, так как буферизация работает только на вывод.
Ну при невключенной ob_start():
1. пользователь запросил новость
2. скрипт получил новость из БД
3. послал её на вывод (пользователю)
4. пользователь получил ее, читает.
5. скрипт послал запрос в БД увеличить кол-во прочтений.
6. работа скрипта завершается.
Так вот если ob_start() включена то скрипт ничено не выдаст до завершения своей работы. То есть 100 пользователей запросило новость в 1 момент времени и на пункте 5. скрипт может затормозить если таблица залочена другим запросом, и пользователь будет ждать, ведь весь вывод происходит после пункта 6.
а ob_start() — штучка полезная.
такс. залочится таблица тока news_views, а это не повлияет на вывод, т.к. вывод у нас, в другой таблице. а для того чтобы это все мгновенно происходило — увеличение просмотров, индекс на поле views ставить не нужно, а то индексы будут перестраиваться и будет тормоз.
по этому, делаешь вывод новости через об_старт, потом выводишь ее, делаешь принудительно flush() для вывода, а дальше плюсуешь просмотр. причем, делай проверку куками юзеру, что он уже посмотрел новость эту, ну или не куками, что бы лишний раз не плюсовалось, и главное что бы проверка не была основана на запросах в БД, можно в файлик писать, что такой-то юзер прочел новость, причем, можно сделать вобще все на файловой системе))) но не понятно что быстрее будет работать.
А ещё для таблички blog_news_views можно сменить тип на innodb — не будет лочиться вообще