несколько раз приходилось видеть, как люди, только-только начавшие работать с базами данных, использовуют sql-синтаксис только для выборки/вставки/удаление/обновления, причём запросы формируются порой на основе одного единственного примера и не подлежат дальнейшему обсуждению. спешу таких людей обрадовать: sql — это язык программирования. в нём содержатся функции, над значениями разрешается производить арифметические операции. в общем, sql (и mysql в частности) содержит очень много полезных плюшек, не использоние которых приводит к ненужному разрастанию кода программы и дополнительным запросам к базе данных.
допустим, имеем таблицу новостей со следующими полями:
- id — идентификатор новости;
- subject — название новости;
- date_add — дата добавления;
- text — текст новости;
- count — количество просмотров новости.
обновлять значения в mysql очень просто
представим, что нам нужно подсчитывать пользователей, прочитавших каждую новость. новички для обновления записей обычно пишут такой код:
$id = 1; $q = 'SELECT `count` FROM `news` WHERE `id` = ' . $id; $r = mysql_query($q); $n = mysql_fetch_array($r); $n['count'] = $n['count`] + 1; $q = 'UPDATE `news` SET `count` = ' . $n['count'] . ' WHERE `id` = ' . $id; $r = mysql_query($q);
мало того, что здесь производится дополнительный (и ненужный) подзапрос к базе, код при некоторых ситуациях будет работать некорректно. два человека решили почитать одну новость и одновременно зашли на одну страницу. два отдельных процесса параллельно запустились на сервере. первый процесс select-запросом считал запись, после чего второй процесс сделал тоже самое. как видно, в обоих исполняемых частях кода содержится одно значение. после этого оба процесса увеличат на единицу одно (старое) значение и запишут его в обратно в базу. не важно, какой процесс после этого отработает раньше, всё-равно одно значение будет потеряно. чтобы такого не произошло, достаточно использовать следующий код:
$id = 1; $q = 'UPDATE `news` SET `count` = `count` + 1 WHERE `id` = ' . $id; $r = mysql_query($q);
в этом случае промежуточную работу возьмёт на себя сама база данных: запрос от второго потока не сможет изменить запись, пока это не сделает запрос от потока № 1.
mysql содержит развитые средства для работы с датой/временем
для получение текущего времени существует внутренняя фунция, которую лучше и вызывать (например, если требуется установить при вставке текущую дату), а не передавать из php значение даты.
SELECT NOW()
запрос вставки может выглядеть так:
INSERT INTO `news` SET `date_add` = NOW(), `subject` = 'название', `text` = 'содержимое новости'
если же используется так называемых unixtime, mysql также позволит получить его значение. следующий запрос:
SELECT FROM_UNIXTIME(123456789)
может вернуть значение 2009-02-14 02:31:30.
для быстрого преобразования дат из одного формата в формат ГГГГ-ММ-ДД можно воспользоваться таким приёмом:
SELECT STR_TO_DATE('12.11.2010', '%d.%m.%Y')
функция вернёт значение 2010-11-12.
запрашивать нужно только те данные, которые требуются для вывода результатов
постоянно терзать базу, заставляя её возвращать огромные результаты выборки, плохая идея. да, субд оптимизируется под работу с данными. но при каждом запросе формировать таблицы на десятки (сотни) мегабайт явно излишне. поэтому в select-запросе обязательно перечисляются поля, реально требующиеся в скрипте (для вывода списка новостей, например, не требуется текст каждой новости) и используется ограничитель limit (и только так). запрос получение 10 последних новостей может выглядеть так:
SELECT `id`, `subject`, `date_add` FROM `news` ORDER BY `date_add` DESC LIMIT 0, 10
при вставке лучше явно указать вставляемые значения
сначала это может показаться ненужным. в самом деле, имея таблицу новостей с помощью следующего запроса прекрасно добавим запись:
INSERT INTO `news` VALUES(NULL, 'название', NOW(), 'содержимое новости', 0)
но представьте, что в таблицу будет добавлено дополнительное поле. запрос выше вызовет ошибку. поэтому пишем так:
INSERT INTO `news` (`subject`, `date_add`, `text`) VALUES('название', NOW(), 'содержимое новости')
при добавлении нового поля запрос всё-равно будет успешно выполнен и запись добавлена. новое поле получит значение по умолчанию.
mysql содержит множество полезных функций, например: MD5(), SHA1(), LEFT(), REPLACE(), DATE_FORMAT() и т. д. поэтому, когда возникнет непреодолимое желание что-то сделать через дополнительный подзапрос на стороне php, посмотрите в документации mysql, не предоставляет ли субд аналогичную функцию, и если это так без раздумий пользуйтесь ей.

днём интернета

шоколадкой для работы мозга

коробочкой ароматного чая для бодрости

продлением хостинга на +1 месяц
Для большого объема SELECT COUNT можно оптимизировать: http://plutov.by/post/mongodb_counters