MySQL является пакетом с открытыми исходными текстами. MySQL: особенности и сферы применения

РАБОТА С БАЗОЙ ДАННЫХ MySQL СРЕДСТВАМИ РНР

Лекция. Подготовлена Прохоровым В.С.


1. СОЕДИНЕНИЕ РНР-СЦЕНАРИЕВ с таблицами MySQL

Рассмотрим наиболее часто используемых функций, позволяющих работать с базой данных MySQL средствами РНР.

При взаимодействии РНР и MySQL программа взаимодействует с СУБД посредством совокупности функций.

1.1 Соединение с сервером. Функция mysql_connect

Прежде чем работать с базой данных, необходимо установить с ней сетевое соединение, а также провести авторизацию пользователя. Для этого служит функция mysql_connect()

resource mysql_connect(]])

Эта функция устанавливает сетевое соединение с базой данных MySQL, расположенной на хосте $server (по умолчанию это localhost, т.е. текущий компьютер) и возвращает идентификатор открытого соединения. Вся дальнейшая работа ведется именно с этим идентификатором. Все другие функции, принимающие этот идентификатор (дескриптор) в качестве аргумента, будут однозначно определять выбранную базу данных. При регистрации указывается имя пользователя $username и пароль $password (по умолчанию имя пользователя, от которого запущен текущий процесс – при отладке скриптов: root, и пустой пароль):

$dbpasswd = ""; //Пароль

//Выводим предупреждение

echo("

");

Переменные $dblocation, $dbuser и $dbpasswd хранят имя сервера, имя пользователя и пароль.

1.2 Разрыв соединения с сервером. Функция mysql_close

Соединение с MySQL – сервером будет автоматически закрыто по завершении работы сценария, либо же при вызове функции mysql_close

bool mysql_close ()

Эта функция разрывает соединение с сервером MySQL, и возвращает true при успешном выполнении операции и false в противном случае. Функция принимает в качестве аргумента дескриптор соединения с базой данных, возвращаемый функцией mysql_connect.

$dblocation = "localhost"; //Имя сервера

$dbuser = "root"; //Имя пользователя

$dbpasswd = ""; //Пароль

//Осуществляем соединение с сервером базы данных

//Подавляем вывод ошибок символом @ перед вызовом функции

$dbcnx = @ mysql_connect($dblocation, $dbuser, $dbpasswd);

if (!$dbcnx) //Если дескриптор равен 0, соединение не установлено

//Выводим предупреждение

echo("

B настоящий момент сервер базы данных не доступен, поэтому корректное отображение страницы невозможно.");

if (mysql_close($dbcnx)) //разрываем соединение

echo("Соединение с базой данных прекращено");

echo("He удалось завершить соединение");

1.3 Создание базы данных. Функция CREATE DATABASE

Команда - создание базы данных доступна только администратору сервера, и на большинстве хостингов ее нельзя выполнять:

CREATE DATABASE ИмяБазыДанных

Создает новую базу данных с именем имяБазыданных.

Пример работы с этой функцией:

@mysql_query("CREATE DATABASE $dbname");

Рекомендуется везде использовать апострофы ("SQL – команда") в качестве ограничителей строк, содержащих SQL – команды. Этим можно гарантировать, что никакая $ - переменная случайно не будет интерполирована (т.е. не заменится на свое значение), и увеличится безопасность скриптов.

Команда создания базы данных CREATE DATABASE доступна только суперпользователю, и на большинстве хостингов простому пользователю ее выполнить невозможно. Она доступна только администратору сервера.

Для экспериментов создадим базу данных testbase, выполнив SQL-запрос из командной строки. Для этого нужно войти в систему MySQL и ввести в командной строке MySQL:

mysql> create database testbase;

После этого следует набрать:

mysql>use testbase;

База данных создана:



1.4 Выбор базы данных. Функция mysql_select_db

До того как послать первый запрос серверу MySQL, необходимо указать, с какой базой данных мы собираемся работать. Для этого предназначена функция mysql_select_db:

bool mysql_select_db(string $database_name [,resource $link_identifier])

Она уведомляет PHP, что в дальнейших операциях с соединением $link_identifier будет использоваться база данных $database_name.

Использование этой функции эквивалентно вызову команды use в SQL-запросе, т. е. функция mysql_select_db выбирает базу данных для дальнейшей работы, и все последующие SQL-запросы применяются к выбранной базе данных. Функция принимает в качестве аргументов название выбираемой базы данных database_name и дескриптор соединения resource. Функция возвращает true при успешном выполнении операции и false - в противном случае:

//Код соединения с базой данных

if (! @mysql_select_db($dbname, $dbcnx))

//Выводим предупреждение

echo("

B настоящий момент база данных не доступна, поэтому корректное отображение страницы невозможно. ");

1.5 Обработка ошибок

Если в процессе работы с MySQL возникают ошибки (например, в запросе не сбалансированы скобки или же не хватает параметров), то сообщение об ошибке и ее номер можно получить с помощью описанных далее двух функций.

Важно аккуратно и своевременно использовать эти функции, потому что иначе отладка сценариев может усложниться.

● Функция:

int mysql_errno ()

возвращает номер последней зарегистрированной ошибки. Идентификатор соединения $link_identifier можно не указывать, если за время работы сценария было установлено только одно соединение.

● Функция:

string mysql_error()

возвращает не номер, а строку, содержащую текст сообщения об ошибке. Ее удобно применять в отладочных целях. Обычно mysql_error используют вместе с конструкцией or die (), например:

@mysql_connect("localhost", "user", "password")

or die("Ошибка при подключении к базе данных: ".mysql_error());

Оператор @, как обычно, служит для подавления стандартного предупреждения, которое может возникнуть в случае ошибки.

В последних версиях РНР предупреждения в MySQL-функциях по умолчанию не регистрируются.

1.6 Автоматизация подключения к MySQL. Файл ( config.php )

Обычно на сайте существует сразу несколько скриптов, которым нужен доступ к одной и той же базе данных.

Код, ответственный за подключение к MySQL рекомендуется выделить в отдельный файл, а затем подключать с помощью функции include к нужным скриптам.

Имеет смысл помещать функции для соединения, выбора и создания базы данных в тот же файл (config.php), где объявлены переменные с именем сервера $dblocation, именем пользователя $dbuser, паролем $dbpasswd и именем базы данных $dbname:

Листинг config.php:

//config.php код файла, содержащего параметры соединения с сервером и выбора базы данных

//выводит сообщения об ошибках соединения в браузер

$dblocation = "localhost"; //Имя сервера

$dbname = "вставить имя базы" //Имя базы данных: создаваемой или уже существующей

$dbuser = "root"; //Имя пользователя базы данных

$dbpasswd = ""; //Пароль

//Осуществляем соединение с сервером базы данных

//Подавляем вывод ошибок символом @ перед вызовом функции

$dbcnx=@mysql_connect($dblocation,$dbuser,$dbpasswd);

if (!$dbcnx) //Если дескриптор равен 0, соединение с сервером базы данных не установлено

//Выводим предупреждение

echo("

В настоящее время сервер базы данных не доступен, поэтому корректное отображение страницы невозможно.

");

//Создаем базу данных $dbname – это может делать только суперпользователь

//Если база данных уже существует, будет некритическая ошибка

@mysql_query("CREATE DATABASE if not exists $dbname’);

//Код соединения с базой данной: осуществляем однозначный выбор только что созданной базы или уже существующей базы данных

//Подавляем вывод ошибок символом @ перед вызовом функции

if(!@mysql_select_db($dbname, $dbcnx)) //Если дескриптор равен 0, соединение с базой данных не установлено

//Выводим предупреждение

echo("

В настоящее время база данных не доступна, поэтому корректное отображение страницы невозможно.

");

//Небольшая вспомогательная функция, которая выводит сообщение

//об ошибке в случае ошибки запроса к базе данных

function puterror($message)

echo("");



2. ВЫПОЛНЕНИЕ ЗАПРОСОВ К БАЗЕ ДАННЫХ

2.1 Создание таблицы. Функция CREATE TABLE:

CREATE TABLE Имя Таблицы (ИмяПоля тип, ИмяПоля тип,)

Этой командой в базе данных создается новая таблица с колонками (полями), определяемыми своими именами (ИмяПоля) и указанными типами. После создания таблицы в нее можно будет добавлять записи, состоящие из перечисленных в данной команде полей.

Листинг test_11.php. Программа, создающая новую таблицу в базе данных:

include "config.php";//Подключение к серверу и выбор базы данных

mysql_query("CREATE TABLE if not exists people

id INT AUTO_INCREMENT PRIMARY KEY,

or die("MySQL error: ".mysql_error());



Этот сценарий создает новую таблицу people с двумя полями. Первое поле имеет тип INT (целое) и имя id. Второе - тип TEXT (текстовая строка) и имя name.

Если таблица существует, сработает конструкция or die ().

Необязательная фраза if not exists, если она задана, говорит серверу MySQL, что он не должен генерировать сообщение об ошибке, если таблица с указанным именем уже существует в базе данных.

Преподаватели и наставники, ведущие обучение MySQL, могут предлагать свои варианты организации последовательности изучения MySQL в комментариях к данному разделу учебника. Также свои замечания по организации учебника могут предлагать читатели, ведущие самостоятельное изучение MySQL. Чтобы самостоятельное изчение MySQL было эффективным, необходимо привлекать методический опыт, который дает обучение MySQL. Учебник для начинающих должен способствовать быстрому старту разработчика.

Базы данных: основные понятия

Оглавление документа

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

Например, мы используем записную книжку для хранения номеров телефонов своих друзей и планирования своего времени. Телефонная книга содержит информацию о людях, живущих в одном городе. Все это своего рода базы данных. Ну а раз это базы данных, то посмотрим, как в них хранятся данные. Например, телефонная книга представляет собой таблицу (табл. 10.1).

В этой таблице данные – это собственно номера телефонов, адреса и ФИО., т.е. строки «Иванов Иван Иванович», «32-43-12 » и т.п., а названия столбцов этой таблицы, т.е. строки «ФИО», «Номер телефона» и «Адрес» задают смысл этих данных, их семантику.

Таблица 10.1. Пример базы данных: телефонная книга

Теперь представьте, что записей в этой таблице не две, а две тысячи, вы занимаетесь созданием этого справочника и где-то произошла ошибка (например, опечатка в адресе). Видимо, тяжеловато будет найти и исправить эту ошибку вручную. Нужно воспользоваться какими-то средствами автоматизации. Для управления большим количеством данных программисты (не без помощи математиков) придумали системы управления базами данных (СУБД). По сравнению с текстовыми базами данных электронные СУБД имеют огромное число преимуществ, от возможности быстрого поиска информации, взаимосвязи данных между собой до использования этих данных в различных прикладных программах и одновременного доступа к данным нескольких пользователей.

Для точности дадим определение базы данных, предлагаемое Глоссарий.ру

База данных – это совокупность связанных данных, организованных по определенным правилам, предусматривающим общие принципы описания, хранения и манипулирования, независимая от прикладных программ. База данных является информационной моделью предметной области. Обращение к базам данных осуществляется с помощью системы управления базами данных (СУБД). СУБД обеспечивает поддержку создания баз данных, централизованного управления и организации доступа к ним различных пользователей.

Итак, мы пришли к выводу, что хранить данные независимо от программ, так, что они связаны между собой и организованы по определенным правилам, целесообразно. Но вопрос, как хранить данные, по каким правилам они должны быть организованы, остался открытым. Способов существует множество (кстати, называются они моделями представления или хранения данных). Наиболее популярные – объектная и реляционная модели данных.

Автором реляционной модели считается Э. Кодд, который первым предложил использовать для обработки данных аппарат теории множеств (объединение, пересечение, разность, декартово произведение) и показал, что любое представление данных сводится к совокупности двумерных таблиц особого вида, известного в математике как отношение.

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

Примеры реляционных СУБД: Mysql, PostgreSql. В основу объектной модели положена концепция объектно-ориентированного программирования, в которой данные представляются в виде набора объектов и классов, связанных между собой родственными отношениями, а работа с объектами осуществляется с помощью скрытых (инкапсулированных) в них
методов.

Примеры объектных СУБД: Cache, GemStone (от Servio Corporation), ONTOS (ONTOS).

В последнее время производители СУБД стремятся соединить два этих подхода и проповедуют объектно-реляционную модель представления данных. Примеры таких СУБД – IBM DB2 for Common Servers, Oracle8.

Поскольку мы собираемся работать с Mysql, то будем обсуждать аспекты работы только с реляционными базами данных. Нам осталось рассмотреть еще два важных понятия из этой области: ключи и индексирование, после чего мы сможем приступить к изучению языка запросов SQL.

1. Ключи

Для начала давайте подумаем над таким вопросом: какую информацию нужно дать о человеке, чтобы собеседник точно сказал, что это именно тот человек, сомнений быть не может, второго такого нет? Сообщить фамилию, очевидно, недостаточно, поскольку существуют однофамильцы. Если собеседник человек, то мы можем приблизительно объяснить, о ком речь, например вспомнить поступок, который совершил тот человек, или еще как-то. Компьютер же такого объяснения не поймет, ему нужны четкие правила, как определить, о ком идет речь. В системах управления базами данных для решения такой задачи ввели понятие первичного ключа.

Первичный ключ (primary key, PK) – минимальный набор полей, уникально идентифицирующий запись в таблице. Значит, первичный ключ – это в первую очередь набор полей таблицы, во-вторых, каждый набор значений этих полей должен определять единственную запись (строку) в таблице и, в-третьих, этот набор полей должен быть минимальным из всех обладающих таким же свойством.

Поскольку первичный ключ определяет только одну уникальную запись, то никакие две записи таблицы не могут иметь одинаковых значений первичного ключа.

Например, в нашей таблице (см. выше) ФИО и адрес позволяют однозначно выделить запись о человеке. Если же говорить в общем, без связи с решаемой задачей, то такие знания не позволяют точно указать на единственного человека, поскольку существуют однофамильцы, живущие в разных городах по одному адресу. Все дело в границах, которые мы сами себе задаем. Если считаем, что знания ФИО, телефона и адреса без указания города для наших целей достаточно, то все замечательно, тогда поля ФИО и адрес могут образовывать первичный ключ. В любом случае проблема создания первичного ключа ложится на плечи того, кто проектирует базу данных (разрабатывает структуру хранения данных). Решением этой проблемы может стать либо выделение характеристик, которые естественным образом определяют запись в таблице (задание так называемого логического, или естественного, PK), либо создание дополнительного поля, предназначенного именно для однозначной идентификации записей в таблице (задание так называемого суррогатного, или искусственного, PK).

Примером логического первичного ключа является номер паспорта в базе данных о паспортных данных жителей или ФИО и адрес в телефонной книге (таблица выше). Для задания суррогатного первичного ключа в нашу таблицу можно добавить поле id (идентификатор), значением которого будет целое число, уникальное для каждой строки таблицы. Использование таких суррогатных ключей имеет смысл, если естественный первичный ключ представляет собой большой набор полей или его выделение нетривиально.

Кроме однозначной идентификации записи, первичные ключи используются для организации связей с другими таблицами.

Например, у нас есть три таблицы: содержащая информацию об исторических личностях (Persons), содержащая информацию об их изобретениях (Artifacts) и содержащая изображения как личностей, так и артефактов (Images) (рис 10.1).

Первичным ключом во всех этих таблицах является поле id (идентификатор). В таблице Artifacts есть поле author, в котором записан идентификатор, присвоенный автору изобретения в таблице Persons. Каждое значение этого поля является внешним ключом для первичного ключа таблицы Persons. Кроме того, в таблицах Persons и Artifacts есть поле photo, которое ссылается на изображение в таблице Images. Эти поля также являются внешними ключами для первичного ключа таблицы Images и устанавливают однозначную логическую связь Persons-Images и Artifacts-Images. То есть если значение внешнего ключа photo в таблице личности равно 10, то это значит, что фотография этой личности имеет id=10 в таблице изображений. Таким образом, внешние ключи используются для организации связей между таблицами базы данных (родительскими и дочерними) и для поддержания ограничений ссылочной целостности данных.

2. Индексирование

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

Для этого (для оптимизации производительности запросов) производят индексирование некоторых полей таблицы. Использовать индексы полезно для быстрого поиска строк с указанным значением одного столбца. Без индекса чтение таблицы осуществляется по всей таблице, начиная с первой записи, пока не будут найдены соответствующие строки. Чем больше таблица, тем больше накладные расходы. Если же таблица содержит индекс по рассматриваемым столбцам, то база данных может быстро определить позицию для поиска в середине файла данных без просмотра всех данных. Это происходит потому, что база данных помещает проиндексированные поля поближе в памяти, так, чтобы можно было побыстрее найти их значения. Для таблицы, содержащей 1000 строк, это будет как минимум в 100 раз быстрее по сравнению с последовательным перебором всех записей. Однако в случае, когда необходим доступ почти ко всем 1000 строкам, быстрее будет последовательное чтение, так как при этом не требуется операций поиска по диску. Так что иногда индексы бывают только помехой. Например, если копируется большой объем данных в таблицу, то лучше не иметь никаких индексов. Однако в некоторых случаях требуется задействовать сразу несколько индексов (например, для обработки запросов к часто используемым таблицам).

Если говорить о Mysql, то там существует три вида индексов: PRIMARY, UNIQUE, и INDEX, а слово ключ (KEY) используется как синоним слова индекс (INDEX). Все индексы хранятся в памяти в виде B-деревьев.

PRIMARY – уникальный индекс (ключ) с ограничением, что все индексированные им поля не могут иметь пустого значения (т.е. они NOT NULL). Таблица может иметь только один первичный индекс, но он может состоять из нескольких полей.

UNIQUE – ключ (индекс), задающий поля, которые могут иметь только уникальные значения.

INDEX – обычный индекс (как мы описали выше). В Mysql, кроме того, можно индексировать строковые поля по заданному числу символов от начала строки.

3. СУБД Mysql

Продолжим разговор о СУБД Mysql. Mysql – это реляционная система управления базами данных. То есть данные в ее базах хранятся в виде логически связанных между собой таблиц, доступ к которым осуществляется с помощью языка запросов SQL. Mysql – свободно распространяемая система, т.е. платить за ее применение не нужно. Кроме того, это достаточно быстрая, надежная и, главное, простая в использовании СУБД, вполне подходящая для не слишком глобальных проектов.

Работать с Mysql можно не только в текстовом режиме, но и в графическом. Существует очень популярный визуальный интерфейс (кстати, написанный на PHP) для работы с этой СУБД. Называется он PhpMyAdmin. Этот интерфейс позволяет значительно упростить работу с базами данных в Mysql.

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

Перед тем как переходить к детальному изучению языка SQL, несколько слов об установке Mysql и подготовке к работе. Если вы не собираетесь заниматься администрированием сервера, то информация, приведенная ниже, пригодится вам только для общего развития. Итак, устанавливается Mysql очень просто – автоматически, пару раз нажмите OK, и все. После этого вы можете зайти в директорию, где лежат файлы типа Mysql.exe, Mysqld.exe и т.п. (у нас под Windows XP это c:\Mysql\bin) Последний файл запускает Mysql-сервер. В некоторых системах сервер запускается в виде сервиса. После запуска сервера следует запустить Mysql-клиент, запустив программу Mysql.exe. Здесь даже пароля не спросят. Более того, если вы наберете shell> Mysql.exe -u root или shell>Mysql -u root Mysql то получите все права администратора Mysql сервера. Кстати, выполнять эти команды надо, находясь в той директории, где лежат файлы Mysql.exe.
Для начала, не вдаваясь в подробности команд, исправим эти два недочета (отсутствие пароля у администратора и возможность входа анонимным пользователям):

Все данные о пользователях Mysql хранит в таблице user в специальной базе данных Mysql, доступ к которой имеет только администратор сервера. Поэтому, чтобы изменить какой-либо пароль, нужно изменить эту таблицу. Пароль задается с помощью функции PASSWORD, которая кодирует введенные данные. Кроме изменения пароля администратора, нужно еще удалить всех пользователей, не имеющих логина (команда DELETE). Команда Flush Privileges заставляет вступить в действие изменения, произошедшие в системной базе данных (Mysql).

Теперь создадим базу данных, с которой будем работать (мы все еще работаем как администратор сервера):
Mysql>create database book;

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

Mysql> show tables
->
->

Теперь последнее действие – создадим простого пользователя, предоставим ему доступ к созданной базе данных, и начнем работать.

Mysql> GRANT ALL PRIVILEGES ON book.* TO nina@localhost
IDENTIFIED BY "123";

Команда GRANT наделяет пользователя nina, зашедшего на сервер с этой же машины (c localhost) и идентифицируемого паролем «123», определенными правами (в данном случае всеми) на все таблицы базы данных book. Теперь мы можем выйти и зайти как пользователь nina с соответствующим паролем:

shell>Mysql -u nina -p
Enter password : ***
Welcome to the Mysql monitor!...
Mysql>

Если вы собираетесь пользоваться базой данных на чужом сервере, то его администратор проделает все описанные выше действия за вас, т.е. все настроит и создаст пользователя и базу данных. В следующей главе описаны команды языка SQL, которые пригодятся для работы с данными, хранящимися в СУБД Mysql.

4.

5.

6.

7. Построение интерфейса для добавления информации

Итак, у нас есть какая-то таблица в базе данных. Чтобы построить интерфейс для добавления информации в эту таблицу, нужно ее структуру (т.е. набор ее полей) отобразить в html-форму.

Разобьем эту задачу на следующие подзадачи:

  • установка соединения с БД;
  • выбор рабочей БД;
  • получение списка полей таблицы;
  • отображение полей в html-форму.
После этого данные, введенные в форму, нужно записать в базу данных.

Рассмотрим все эти задачи по порядку.

8. Установка соединения

Итак, первое, что нужно сделать, - это установить соединение с базой данных.

Воспользуемся функцией Mysql_connect.

Синтаксис Mysql_connect

ресурс Mysql_connect ([строка server
[, строка username [, строка password
[, логическое new_link
[, целое client_flags]]]]])

Данная функция устанавливает соединение с сервером Mysql и возвращает указатель на это соединение или FALSE в случае неудачи.

Для отсутствующих параметров устанавливаются следующие значения по умолчанию:
server = "localhost:3306"
username = имя пользователя владельца процесса сервера
password = пустой пароль

Если функция вызывается дважды с одними и теми же параметрами, то новое соединение не устанавливается, а возвращается ссылка на старое соединение.

Чтобы этого избежать, используют параметр new_link, который заставляет в любом случае открыть еще одно соединение.

Параметр client_flags - это комбинация следующих констант:

MYSQL_CLIENT_COMPRESS (использовать протокол сжатия),
MYSQL_CLIENT_IGNORE_SPACE (позволяет вставлять пробелы после имен функций), MYSQL_CLIENT_INTERACTIVE (ждать interactive_timeout секунд - вместо wait_timeout - до закрытия соединения).

Параметр new_link появился в PHP 4.2.0, а параметр client_flags - в PHP 4.3.0.

Соединение с сервером закрывается при завершении исполнения скрипта, если оно до этого не было закрыто с помощью функции Mysql_close().

Итак, устанавливаем соединение с базой данных на локальном сервере для пользователя nina с паролем “123”:

$conn = Mysql_connect (

or die("Невозможно установить
соединение: "
. Mysql_error ());
echo "Соединение установлено" ;
Mysql_close ($conn );
?>

Действие Mysql_connect равносильно команде

shell>Mysql -u nina -p123

9. Выбор базы данных

После установки соединения нужно выбрать базу данных, с которой будем работать. Наши данные хранятся в базе данных book. В Mysql выбор базы данных осуществляется с помощью команды use:

Mysql>use book;


В PHP для этого существует функция Mysql_select_db.

Синтаксис Mysql_select_db:

Логическое

Mysql_select_db (строка database_name [, ресурс link_identifier])

Эта функция возвращает TRUE в случае успешного выбора базы данных и FALSE

  • в противном случае.
Сделаем базу данных book рабочей:

$conn = Mysql_connect (
"localhost" , "nina" , "123" )
or die("Невозможно установить
соединение: "
. Mysql_error ());
echo "Соединение установлено" ;
Mysql_select_db ("book" );
?>

10. Получение списка полей таблицы

Теперь можно заняться собственно решением задачи. Как получить список полей таблицы? Очень просто. В PHP и на этот случай есть своя команда - Mysql_list_fields.

10.1. Синтаксис Mysql_list_fields

ресурс Mysql_list_fields (
строка database_name,
строка table_name
[, ресурс link_identifier])

Эта функция возвращает список полей в таблице table_name в базе данных database_name. Получается, что выбирать базу данных нам было необязательно, но это пригодится позже. Как можно заметить, результат работы этой функции - переменная типа ресурс. То есть это не совсем то, что мы хотели получить. Это ссылка, которую можно использовать для получения информации о полях таблицы, включая их названия, типы и флаги.

Функция Mysql_field_name возвращает имя поля, полученного в результате выполнения запроса. Функция Mysql_field_len возвращает длину поля. Функция Mysql_field_type возвращает тип поля, а функция Mysql_field_flags возвращает список флагов поля, записанных через пробел. Типы поля могут быть int, real, string, blob и т.д. Флаги могут быть not_null, primary_key, unique_key, blob,
auto_increment и т.д.

Синтаксис у всех этих команд одинаков:

строка Mysql_field_name (ресурс result, целое field_offset)
строка Mysql_field_type (ресурс result, целое field_offset)
строка Mysql_field_flags (ресурс result, целое field_offset)
строка Mysql_field_len (ресурс result, целое field_offset)

Здесь result - это идентификатор результата запроса (например, запроса, отправленного функциями Mysql_list_fields или Mysql_query (о ней будет рассказано позднее)), а field_offset - порядковый номер поля в результате.

Вообще говоря, то, что возвращают функции типа Mysql_list_fields или Mysql_query, представляет собой таблицу, а точнее, указатель на нее. Чтобы получить из этой таблицы конкретные значения, нужно задействовать специальные функции, которые построчно читают эту таблицу. К таким функциям и относятся Mysql_field_name и т.п. Чтобы перебрать все строки в таблице результата выполнения запроса, нужно знать число строк в этой таблице. Команда Mysql_num_rows(ресурс result) возвращает число строк во множестве результатов
result.

А теперь попробуем получить список полей таблицы Artifacts (коллекция экспонатов).

$conn = Mysql_connect (
"localhost" , "nina" , "123" )
or die("Невозможно установить
соединение: "
. Mysql_error ());
echo "Соединение установлено" ;
Mysql_select_db ("book" );
$list_f = Mysql_list_fields (
"book" , "Artifacts" , $conn );
$n = Mysql_num_fields ($list_f );
for($i = 0 ; $i < $n ; $i ++){



$flags_str = Mysql_field_flags (
$list_f , $i );
echo "
Имя поля: " . $name_f ;
echo "
Тип поля: " . $type ;
echo "
Длина поля: " . $len ;
echo "
Строка флагов поля: "
.
$flags_str . "


" ;
}
?>

В результате должно получиться примерно вот что (если в таблице всего два поля, конечно):

Имя поля: id
Тип поля: int
Длина поля: 11
Строка флагов поля:
not_null primary_key auto_increment
Имя поля: title
Тип поля: string
Длина поля: 255
Строка флагов поля:
Отображение списка полей в html-форму

Теперь немножко подкорректируем предыдущий пример. Будем не просто выводить информацию о поле, а отображать его в подходящий элемент html- формы. Так, элементы типа BLOB переведем в textarea (заметим, что поле description, которое мы создавали с типом TEXT, отображается как имеющее тип BLOB), числа и строки отобразим в текстовые строки ввода , а элемент, имеющий метку автоинкремента, вообще не будем отображать, поскольку его значение устанавливается автоматически.

Все это решается довольно просто, за исключением выделения из списка флагов флага auto_increment. Для этого нужно воспользоваться функцией explode.

Синтаксис explode:

массив explode(строка separator, строка string [, int limit ])

Эта функция разбивает строку string на части с помощью разделителя separator и возвращает массив полученных строк.

В нашем случае в качестве разделителя нужно взять пробел “ ", а в качестве исходной строки для разбиения - строку флагов поля.

Итак, создадим форму для ввода данных в таблицу Artifacts:

$conn = Mysql_connect ("localhost" , "nina" , "123" );
// устанавливаем соединение
$database = "book" ;
$table_name = "Artifacts" ;
Mysql_select_db ($database ); // выбираем базу данных для
// работы

// число строк в результате
// предыдущего запроса (т.е. сколько всего
// полей в таблице Artifacts)
echo "

" ;
// создаем форму для ввода данных
echo "

Add new row in
$table_name
"
;
echo "" ;
// для каждого поля получаем его имя, тип, длину и флаги
for($i = 0 ; $i < $n ; $i ++){
$type = Mysql_field_type ($list_f , $i );
$name_f = Mysql_field_name ($list_f , $i );
$len = Mysql_field_len ($list_f , $i );
$flags_str = Mysql_field_flags ($list_f , $i );
// из строки флагов делаем массив,
// где каждый элемент массива - флаг поля
$flags = explode (" " , $flags_str );
foreach ($flags as $f ){
if ($f == "auto_increment" ) $key = $name_f ;
// запоминаем имя автоинкремента
}
/* для каждого поля, не являющегося автоинкрементом, в
зависимости от его типа выводим подходящий элемент формы */
if ($key <> $name_f ){
echo "" ;
switch ($type ){
case "string" :
$w = $len / 5 ;
echo "" ;
break;
case "int" :
$w = $len / 4 ;
echo "" ;
break;
case "blob" :
echo "" ;
break;
}
}
echo "" ;
}
echo "

" . $name_f . "
size = $w >size = $w >
" ;
echo "" ;
echo "" ;
?>

Если открытые соединения отсутствуют, функция пытается соединиться с СУБД, аналогично функции Mysql_connect() без параметров. Результат запроса буферизируется.

Замечание: строка запроса НЕ должна заканчиваться точкой с запятой.

Только для запросов SELECT, SHOW, EXPLAIN, DESCRIBE, Mysql_query() возвращает указатель на результат запроса, или FALSE, если запрос не был выполнен. В остальных случаях Mysql_query() возвращает TRUE, если запрос выполнен успешно, и FALSE - в случае ошибки. Значение, не равное FALSE, говорит о том, что запрос был выполнен успешно. Оно не говорит о количестве затронутых или возвращенных рядов. Вполне возможна ситуация, когда успешный запрос не затронет ни одного ряда. Mysql_query() также считается ошибочным и вернет FALSE, если у пользователя недостаточно прав для работы с указанной в запросе таблицей.

Итак, теперь мы знаем, как отправить запрос на вставку строк в базу данных.
$list_f = Mysql_list_fields ($database , $table_name );
// получаем список полей в базе
$n = Mysql_num_fields ($list_f ); // число строк в результате
// предыдущего запроса
// составим один запрос сразу для всех полей таблицы
$sql = "INSERT INTO $table_name SET " ; // начинаем создавать
// запрос, перебираем все поля таблицы
for($i = 0 ; $i < $n ; $i ++){
$name_f = Mysql_field_name ($list_f , $i ); // вычисляем имя поля
$value = $_POST [ $name_f ]; // вычисляем значение поля
$j = $i + 1 ;
$sql = $sql . $name_f . " = "$value"" ; // дописываем в
// строку $sql пару имя=значение
if ($j <> $n ) $sql = $sql . ", " ; // если поле не
// последнее в списке, то ставим запятую
}
// перед тем как записывать что-то в базу,
// можно посмотреть, какой запрос получился
//echo $sql;
$result = Mysql_query ($sql , $conn ); // отправляем запрос
// выводим сообщение успешно ли выполнен запрос
if (! $result ) echo " Can"t add ($table_name) " ;
else echo "Success!
" ;
?>

Листинг 11.0.2. insert.php

Итак, задачу добавления данных с помощью web-интерфейса мы решили. Однако тут есть одна тонкость. При решении мы не учитывали тот факт, что значения некоторых полей (author, photo) должны браться из других таблиц (Persons, Images). Поскольку Mysql с внешними ключами не работает, этот момент остается на совести разработчиков системы, т.е. на нашей совести. Нужно дописать программу таким образом, чтобы была возможность вводить в такие поля правильные значения. Но мы делать этого не будем, поскольку задача лекции состоит в том, чтобы познакомить читателя с элементами технологии, а не в том, чтобы создать работающую систему. Кроме того, имеющихся у читателя знаний вполне достаточно, чтобы решить эту проблему самостоятельно. Мы же обратимся к другой задаче - отображение данных, хранящихся в базе данных СУБД Mysql.

12.

13.

14.

15. Литература

http://mysql.ru/docs/man/
http://www.intuit.ru/department/database/mysql/

Оптимальное использование MySQL

Введение

Для того, чтобы начать работать с MySQL, нужно скачать эту базу данных, установить, настроить и изучить документацию.

В процессе предоставления услуг хостинга мы обращаем внимание на наиболее часто встречаюшиеся ошибки, которые совершают пользователи при разработке своих виртуальных серверов. Одним из "тяжелых" мест для типичного веб-мастера является работа с MySQL-сервером. Обычно изучение принципов функционирования SQL и методов работы с базами данных ведется по литературе, из которой выбираются только актуальные на момент чтения вещи - как соединиться с базой, как сделать запрос, как обновить информацию или добавить новую запись в базу данных и так далее.

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

Эта статья поможет Вам оптимизировать работу с СУБД MySQL. Изложенный материал не претендует на детальное описание оптимизации MySQL вообще, а лишь обращает внимание на наиболее часто совершаемые пользователями ошибки и рассказывает о том, как их избежать. Более подробно узнать о тонкостях настройки MySQL можно на специализированных страницах, ссылки на которые приведены в конце этой статьи.

Какие данные нужно хранить в MySQL

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

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

Оптимизация запросов

В ситуациях, когда реально требуется получить только определенную порцию данных из MySQL, можно использовать ключ LIMIT для функции SELECT . Это полезно, когда, например, нужно показать результаты поиска чего-либо в базе данных. Допустим, в базе есть список товаров, которые предлагает Ваш интернет-магазин. Выдавать весь список товаров в нужной категории несколько негуманно по отношению к пользователю - каналы связи с интернет не у всех быстрые и выдача лишних ста килобайт информации зачастую заставляет пользователяй провести не одну минуту в ожидании результатов загрузки страницы. В таких ситуациях информацию выдают порциями по, допустим, 10 позиций. Неправильно делать выборку из базы всей информации и фильтрацию вывода скриптом. Гораздо оптимальнее будет сделать запрос вида

select good, price from books limit 20,10

В результате, MySQL "отдаст" Вам 10 записей из базы начиная с 20-й позиции. Выдав результат пользователю, сделайте ссылки "Следующие 10 товаров", в качестве параметра передав скрипту следующую позицию, с которой будет делаться вывод списка товаров, и используйте это число при генерации запроса к MySQL.

Также следует помнить, что при составлении запросов к базе данных (SQL queries) следует запрашивать только ту информацию, которая Вам реально нужна. Например, если в базе 10 полей, а в данный момент реально требуется получить только два из них, вместо запроса

select * from table_name

используйте конструкцию вида

select field1, field2 from table_name

Таким образом Вы не будете нагружать MySQL ненужной работой, занимать лишнюю память и совершать дополнительные дисковые операции.

Также следует использовать ключ WHERE там, где нужно получать информацию, попадающую под определенный шаблон. Например, если нужно получить из базы поля с названиями книг, автором которых является Иванов, следует использовать конструкцию вида

select title from books where author=" Иванов"

Также есть ключ LIKE, который позволяет искать поля, значения которых "похожи" на заданный шаблон:

select title from books where author like " Иванов%"

В данном случае MySQL выдаст названия книг, значения поля author у которых начинаются с " Иванов"

.

Ресурсоемкие операции

Вместе с тем следует помнить, что существуют операции, выполнение которых само по себе требует больших ресурсов, чем для обычных запросов. Например, использование операции DISTINCT к фукнции SELECT вызывает потребление гораздо большего количества процессорного времени, чем обычный SELECT. DISTINCT пытается искать уникальные значения, зачастую производя множество сравнений, подстановок и расчетов. Причем, чем больше становится объем данных к котором применяется DISTINCT (ведь Ваша база со временем растет), тем более медленно будет выполняться такой запрос и рост ресурсов, нужных для выполнения такой функции, будет происходить далеко не прямо пропорцонально объему хранимых и обрабатываемых данных, а гораздо быстрее.

Индексы

Индексы используют для более быстрого поиска по значению одного из полей. Если индекс не создается, то MySQL осуществляет последовательный просмотр всех полей с самой первой записи до самой последней, осуществляя сопоставление выбранного значения с исходным. Чем больше таблица и чем больше в ней полей, тем дольше осуществляется выборка. Если же у данной таблицы существует индекс для рассматриваемого столбца, то MySQL сможет сделать быстрое позиционирование к физическому расположению данных без необходимости осуществлять полный просмотр таблицы. Например, если таблица состоит из 1000 строк, то скорость поиска будет как минимум в 100 раз быстрее. Эта скорость будет еще выше, если есть необходимость обратиться сразу ко всем 1000 столбцам, т.к. в этом случае не происходит затрат времени на позиционирование жесткого диска.

В каких ситуациях создание индекса целесообразно:

  1. Быстрый поиск строк при использовании конструкции WHERE
  2. Поиск строк из других таблиц при выполнении объединения
  3. Поиск значения MIN() или MAX() для проиндексированного поля
  4. Сортировка или группировка таблицы в случае, если используется проиндексированное поле
  5. В некоторых случаях полностью теряется необходимость обращаться к файлу данных. Если все используемые поля для некоторой таблицы цифровые и формируют левосторонний индекс для некоторого ключа, то значения могут быть возвращены полностью из индексного дерева с намного большей скоростью.
  6. Если выполняются запросы вида
    SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;
    и существует смешанный индекс для полей col1 и col2, то данные будут возвращены напрямую. Если же созданы отдельные индексы для col1 и для col2, то оптимизатор попробует найти наиболее ограниченный индекс путем определения того, какой из индексов может найти меньше строк, и будет использовать этот индекс для получения данных.
    Если у таблицы есть смешанный индекс, то будет использоваться любое левостороннее совпадение с существующим индексом. Например, если есть смешанный индекс 3-х полей (col1, col2, col3), то индексный поиск можно осуществлять по полям (col1), (col1, col2) и (col1, col2, col3).

Подробнее об индексировании

Поддержка соединения

Как Вы наверняка знаете, для работы с MySQL-сервером необходимо предварительно установить с ним соединение, предъявив логин и пароль. Процесс установки соединения может продолжаться гораздо большее время, нежели непосредственная обработка запроса к базе после установки соединения. Следуя логике, надо избегать лишних соединений к базе, не отсоединяясь от нее там, где это можно сделать, если в дальнейшем планируется продолжить работу с SQL-сервером. Например, если Ваш скрипт установил соединение к базе, сделал выборку данных для анализа, не нужно закрывать соединение к базе, если в процессе работы этого же скрипта Вы планируете результаты анализа поместить в базу.

Также можно поддерживать так называемое persistent (постоянное) соединение к базе, но это возможно в полном объеме при использовании более сложных сред программирования, чем php или perl в обычном CGI-режиме, когда интерпретатор соответствующего языка разово запускается веб-сервером для выполнения пришедшего запроса.

MySQL относится к числу баз данных, обеспечивающих наиболее простое администрирование на всех платформах. Кроме того, эта база данных не требовательна к ресурсам, поэтому может эксплуатироваться даже на персональных компьютерах с небольшим объемом оперативной памяти и жесткого диска. В связи с этим разработчики, использующие средства PHP, продолжительное время применяют MySQL для создания полной локальной среды разработки для веб на клиентских компьютерах всевозможных типов, даже на портативных.

Любой разработчик, работающий в среде PHP, способен самостоятельно администрировать базу данных MySQL, в отличие от некоторых других баз данных. Для того чтобы еще больше упростить задачу администрирования, можно воспользоваться многочисленными инструментальными средствами, которые не только предусмотрены в самой базе данных MySQL, но и могут быть получены от сторонних разработчиков.

Основными понятиями, с которыми следует ознакомиться на данном этапе, являются:

  • база данных - контейнер для всей коллекции данных MySQL;
  • таблица - вложенный в базу данных контейнер, в котором хранятся сами данные;
  • строка - отдельная запись, в которой могут содержаться несколько полей;
  • столбец - имя поля внутри строки.

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

Доступ к MySQL из командной строки

Работать с MySQL можно тремя основными способами: используя командную строку, используя веб-интерфейс наподобие phpMyAdmin и используя такой язык программирования, как PHP. Третий из перечисленных способов будет рассмотрен в последующих статьях, а сейчас давайте рассмотрим первые два способа.

Если у вас в соответствии с инструкциями, изложенными в статье , установлен WAMP-сервер OpenServer, то доступ к исполняемой программе MySQL можно получить из следующего каталога:

курса MySQL с нуля .

Вместо MySQL-5.7-x64 нужно подставить версию, указанную в настройках OpenServer во вкладке "Модули".

Нужно открыть программу "Командная строка" и перейти в этот каталог. Делается это при помощи команды cd ПУТЬ_К_НУЖНОЙ_ПАПКЕ:

Код доступен только после покупки курса MySQL с нуля .

После этого нужно запустить программу mysql.exe в этом каталоге, передав её специальный параметр. Для этого в командной строке теперь нужно выполнить команду:

Код доступен только после покупки курса MySQL с нуля .

В результате запустится MySQL-клиент. Он подключён к MySQL-серверу, который был запущен при старте OpenServer-a.

Если это не приведет к желаемому результату и будет выдано сообщение об ошибке подключения к серверу MySQL «Can"t connect to MySQL server on "localhost"», убедитесь, что OpenServer запущен и в модулях указан MySQL.

Параметр -u расшифровывается как user. То есть это флажок для указания пользователя, под которым нужно подключиться к серверу. root - это самый главный пользователь в MySQL. Он создаётся при установке сервера и по умолчанию у него нет пароля.

Но вернёмся к нашему терминалу. Через этот консольный клиент мы можем отправлять различные команды серверу. Давайте выполним команду, которая выводит все базы данных, созданные на этом сервере.

Код доступен только после покупки курса MySQL с нуля .

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

Работа с MySQL через phpMyAdmin

Для управления базами данных и таблицами будет намного проще и быстрее использовать программу phpMyAdmin. Перед тем как вводить в адресную строку браузера следующую строку, нужно убедиться в том, что программа OpenServer уже запущена и, значит, база данных MySQL готова к работе:

Тут нас встретит вот такое красивое окошечко для входа в систему.

Также как и в случае с консольным приложением указываем пользователя root и оставляем пустым пароль. Жмём "войти".

После этого вы попадёте в панель управления базами данных с довольно дружелюбным интерфейсом. Слева вы увидите всё тот же список баз данных, который вы получали в консольной версии. Можете по ним потыкать, посмотреть, что там внутри.

А сейчас давайте нажмём на вкладку SQL и перейдём в окно, где можно напрямую писать запросы к СУБД MySQL, как это было бы в консоли:

В открывшемся окне введите всё тот же запрос:

Код доступен только после покупки курса MySQL с нуля .

Нажимаем кнопку "вперёд" и видим тот же результат, что и в случае с консольным приложением.

Основные понятия языка SQL

По словам Эндрю Тейлора (Andrew Taylor), разработавшего язык SQL, название этого языка не является сокращением от Structured Query Language (или от чего-то подобного), хотя многие считают, что так оно и есть. Язык SQL лежит в основе более строгого и более общего метода хранения данных по сравнению с предыдущим стандартом организации баз данных в стиле DBM, который основан на использовании плоских файлов.

Язык SQL определен стандартами ANSI (American National Standards Institute) и ECMA (European Computer Manufacturer"s Association); обе эти организации по стандартизации являются международно признанными. Но следует учитывать, что в общих рекомендациях стандартов SQL наблюдаются заметные различия, касающиеся программных продуктов коммерческих компаний, с одной стороны, и организаций, занимающихся разработкой баз данных с открытым исходным кодом, с другой. Например, за последние несколько лет наблюдалось стремительное развитие так называемых объектно-реляционных баз данных, а также программных продуктов SQL, специально предназначенных для рынка веб. Перечень баз данных, которые могут применяться в сочетании с системой PHP, чрезвычайно велик, поэтому при выборе наиболее подходящей базы данных необходимо руководствоваться определенными принципами.

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

Но, несмотря на сказанное выше, значительная часть средств поддержки языка SQL действительно соответствует стандарту. Поэтому в программах, как правило, неоднократно используется лишь несколько операторов SQL, независимо от того, какой конкретный программный продукт был выбран для внедрения.

По существу, база данных SQL имеет очень простую логическую структуру. Каждая конкретная инсталляция программного обеспечения SQL обычно может состоять из нескольких баз данных. Например, одна БД может применяться для хранения данных о заказчиках, а другая - содержать данные о товарах. (Возникает определенная сложность, связанная с тем, что сам сервер SQL и коллекции поддерживаемых этим сервером таблиц обычно принято обозначать общим термином база данных.) Каждая база данных содержит несколько таблиц, каждая таблица состоит из тщательно определенных столбцов, а каждая позиция в таблице может рассматриваться как внесенная в таблицу запись, или строка.

Любой сервер SQL поддерживает четыре так называемых оператора манипулирования данными, и в целом эти операторы лежат в основе подавляющего большинства операций, выполняемых с реляционной базой данных. Этими четырьмя основными операторами базы данных являются SELECT, INSERT, UPDATE и DELETE. Операторы SQL, называемые также командами - очень удобны и позволяют выполнять практически все необходимые действия в базе данных.

Важной особенностью указанных четырех операторов SQL является то, что они позволяют манипулировать только значениями, хранящимися в базе данных, но не воздействуют на структуру самой базы данных. Иными словами, команды на основе этих операторов могут использоваться, например, для ввода данных, а не для создания базы данных; с помощью таких команд можно удалить из базы данных любой фрагмент данных, но сама "оболочка" останется нетронутой, поэтому, в частности, нельзя присвоить другой базе данных, работающей под управлением того же сервера, имя существующей базы данных. Для того чтобы добавить или удалить столбцы, уничтожить целую базу данных, не оставив и следа, или создать новую базу данных, необходимо применить другие команды, такие как DROP, ALTER и CREATE.

Все эти операторы мы подробно рассмотрим в следующей статье, посвященной командам MySQL.

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

Вопросы оптимизации в таких случаях касаются не только администратора базы данных.

1. Оптимизируйте ваши запросы для кэша запросов.

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

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

// Кэш запроса НЕ РАБОТАЕТ $r = mysql_query("SELECT username FROM user WHERE signup_date >= CURDATE()"); // Кэш запроса РАБОТАЕТ! $today = date("Y-m-d"); $r = mysql_query("SELECT username FROM user WHERE signup_date >= "$today"");

Причина того, что кэш запросов не работает в первом случае, заключается в использовании функции CURDATE() . Такой подход используется для всех недетерминированных функций, например, NOW(), RAND() и т.д. Так как возвращаемый результат функции может измениться, то MySQL решает не размещать данный запрос в кэше. Все что, нужно, чтобы исправить ситуацию - это добавить дополнительную строчку кода PHP перед запросом.

2. Используйте EXPLAIN для ваших запросов SELECT

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

Результат запроса EXPLAIN показывает, какие индексы используются, как таблица сканируется и сортируется, и так далее.

Возьмем запрос SELECT (предпочтительно, чтобы он был сложным, с JOIN), добавим перед ним ключевое слово EXPLAIN. Вы можете использовать PhpMyAdmin для этого. Такой запрос выведет результат в прекрасную таблицу. Допустим, мы забыли добавить индекс для столбца, который используется для JOIN:

После добавления индекса для поля group_id:

Теперь вместо сканирования 7883 строк, будут сканироваться только 9 и 16 строк из двух таблиц. Хорошим методом оценки производительности является умножение всех чисел в столбце “rows”. Результат примерно пропорционален прорабатываемому объему данных.

3. Используйте LIMIT 1, если нужно получить уникальную строку

Иногда, во время использования запроса, вы уже знаете, что ищете только одну строку. Вы можете получить уникальную запись или просто проверить существование любого количества записей, которые удовлетворяют предложению WHERE.

В таком случае добавление LIMIT 1 к вашему запросу может улучшить производительность. При таком условии механизм базы данных останавливает сканирование записей как только найдет одну и не будет проходит по всей таблице или индексу.

// Есть ли какой нибудь пользователь из Алабамы? // Так не нужно делать: $r = mysql_query("SELECT * FROM user WHERE state = "Alabama""); if (mysql_num_rows($r) > 0) { // ... } // Вот так будет значительно лучше: $r = mysql_query("SELECT 1 FROM user WHERE state = "Alabama" LIMIT 1"); if (mysql_num_rows($r) > 0) { // ... }

4. Индексируйте поля поиска

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

Как вы можете видеть, данное правило применимо и к поиску по части строки, например, “last_name LIKE ‘a%’”. Когда для поиска используется начало строки, MySQL может использовать индекс столбца, по которому проводится поиск.

Вам также следует разобраться, для каких видов поиска нельзя использовать обычное индексирование. Например, при поиске слова (“WHERE post_content LIKE ‘%apple%’”) преимущества индексирования будут не доступны. В таких случая лучше использовать или построение собственных решений на основе индексирования.

5. Индексирование и использование одинаковых типов для связываемых столбцов

Если ваше приложение содержит много запросов с директивой JOIN, вам нужно индексировать столбцы, которые связываются в обеих таблицах. Это оказывает эффект на внутреннюю оптимизацию операций связывания в MySQL.

Также связываемые столбцы должны иметь одинаковый тип. Например, если вы связываете столбец DECIMAL со столбцом INT из другой таблицы, MySQL не сможет использовать индекс по крайней мере для одной из одной таблицы. Даже кодировка символов должна быть одинаковой для одинаковых столбцов строчного типа.

// Поиск компании из определенного штата $r = mysql_query("SELECT company_name FROM users LEFT JOIN companies ON (users.state = companies.state) WHERE users.id = $user_id"); // оба столбца для названия штата должны быть индексированы // и оба должны иметь одинаковый тип и кодировку символов // или MySQL проведет полное сканирование таблицы

6. Не используйте ORDER BY RAND()

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

Если вам действительно нужно случайным образом располагать строки в результате вашего запроса, то существует множество лучших способов решить такую задачу. Конечно, это будет реализовано дополнительным кодом, но вы будете спасены от проблемы, которая растет по экспоненциальному закону вместе с ростом объема данных. Дело в том, что MySQL выполняет операцию RAND() (которая занимает время процессора) для каждой отдельной строки в таблице перед тем, как отсортировать ее и выдать вам только одну строку.

// Так делать НЕ НУЖНО: $r = mysql_query("SELECT username FROM user ORDER BY RAND() LIMIT 1"); // Вот так будет лучше работать: $r = mysql_query("SELECT count(*) FROM user"); $d = mysql_fetch_row($r); $rand = mt_rand(0,$d - 1); $r = mysql_query("SELECT username FROM user LIMIT $rand, 1");

Так вы получаете случайное число, которое меньше, чем количество строк в результате запроса, и используете его как смещение в предложении LIMIT.

7. Старайтесь не использовать SELECT *

Чем больше данных будет прочитано из таблицы, тем медленнее выполняется запрос. Такие операции также занимают время для выполнения дисковых операций. А если сервер базу данных отделен от веб сервера, то задержки будут вызваны еще и передачей данных по сети между серверами.

Хорошей привычкой является указание столбца при выполнении SELECT.

// Плохо: $r = mysql_query("SELECT * FROM user WHERE user_id = 1"); $d = mysql_fetch_assoc($r); echo "Welcome {$d["username"]}"; // Так лучше: $r = mysql_query("SELECT username FROM user WHERE user_id = 1"); $d = mysql_fetch_assoc($r); echo "Welcome {$d["username"]}"; // Разница становится существенной на больших объемах данных

8. Старайтесь использовать поле id везде

Хорошей практикой является использование в каждой таблице поля id, для которого установлены свойства PRIMARY KEY, AUTO_INCREMENT, и оно имеет тип из семейства INT. Предпочтительно - UNSIGNED, так как в этом случае значение не может быть отрицательным.

Даже если в вашей таблице есть поле с уникальным именем пользователя, не делайте его основным ключом. Поля с типом VARCHAR медленно работают в качестве основных ключей. Также структура вашей базы данных будет лучше, если в ней внутри использовать ссылки на записи на основании id.

Кроме того механизм MySQL использует основные ключи для своих внутренних задач, и использование поля id создает оптимальные условия для их решения.

Одним возможным исключением из данного правила являются “ассоциативные таблицы”, которые используются для отношений многие-ко-многим между двумя другими таблицами. Например, таблица “posts_tags” содержит 2 столбца: post_id, tag_id. Они используются для описания отношений между двумя таблицами “post” и “tags”. Описанная таблица может иметь основной ключ, который содержит оба поля id.

9. Используйте ENUM вместо VARCHAR

// Создаем подготовленное выражение if ($stmt = $mysqli->prepare("SELECT username FROM user WHERE state=?")) { // Привязываем параметры $stmt->bind_param("s", $state); // Выполняем $stmt->execute(); // Привязываем переменные результата $stmt->bind_result($username); // Получаем значения $stmt->fetch(); printf("%s is from %s\n", $username, $state); $stmt->close(); }

13. Небуферированные запросы

Обычно, когда вы выполняете запрос из скрипта, то работа скрипта прерывается до тех пор, пока запрос не будет выполнен. Такой порядок действий можно изменить с помощью небуферированных запросов.

Отличное объяснение функции из документации PHP:

“mysql_unbuffered_query() отправляет SQL запрос на сервер MySQL без автоматического получения и буферирования строк результата, как это делает функция mysql_query(). Таким образом, сохраняется определенный объем памяти запросами SQL, которые выдают большой набор результата, и можно начинать работать с набором результата сразу же после получения первой строки, не дожидаясь пока запрос SQL будет полностью выполнен.”

Однако существует несколько ограничений. Вы должны либо прочитать все строки либо вызвать перед тем, как выполнить следующий запрос. Также нельзя использовать или для набора результата.

14. Храните IP адрес как UNSIGNED INT

Многие программисты создают поле VARCHAR(15) для хранения IP адреса, даже не задумываясь о том, что будут хранить в этом поле целочисленное значение. Если использовать INT, то размер поля сократится до 4 байт, и оно будет иметь фиксированную длину.

Нужно использовать тип UNSIGNED INT, так как IP адрес задействует все 32 бита беззнакового целого.

$r = "UPDATE users SET ip = INET_ATON("{$_SERVER["REMOTE_ADDR"]}") WHERE user_id = $user_id";

15. Таблицы с фиксированной длиной записи (Static) работают быстрее

Когда каждый отдельный столбец в таблице имеет фиксированную длину, то вся таблица в целом рассматривается как . Примеры типов столбцов, которые не имеют фиксированной длины: VARCHAR, TEXT, BLOB. Если вы включите хотя бы один столбец с таким типом, то таблица перестает рассматриваться как "static" и будет по-другому обрабатываться механизмом MySQL.

Таблицы "static" быстрее обрабатываются механизмом MySQL при поиске записей. Когда нужно прочитать определенную запись в таблице, то ее положение быстро вычисляется. Если размер строки не фиксирован, то для определения положения записи нужно время на поиск и сопоставление с индексом основного ключа.

Такие таблицы также проще кэшировать и проще восстанавливать при сбоях. Но они могут занимать больше места. Например, если конвертировать поле VARCHAR(20) в поле CHAR(20), то всегда будут заняты 20 байт вне зависимости от того, используются они или нет.

Использование техники "Вертикальное разделение" дает возможность отделить столбцы с переменной длиной в отдельную таблицу.

16. Вертикальное разделение

Вертикальное разделение - это действие по разделению структуры таблицы по вертикали с целью оптимизации.

Пример 1 : У вас есть таблица, которая содержит домашние адреса, редко используемые в приложении. Вы можете разделить вашу таблицу и хранить адреса в отдельной таблице. Таким образом основная таблица пользователей сократится в размере. А как известно, меньшая таблица обрабатывается быстрее.

Пример 2 : У вас в таблице есть поле “last_login”. Оно обновляется каждый раз, когда пользователь регистрируется на сайте. Но каждое обновление таблицы вызывает кэширование запроса, что может создать перегрузку системы. Вы можете выделить данное поле в другую таблицу, чтобы сделать обновления таблицы пользователей не такими частыми.

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

17. Разделяйте большие запросы DELETE или INSERT

Если вам нужно выполнить большой запрос DELETE или INSERT на работающем сайте, то нужно быть осторожным, чтобы не нарушить трафик. Когда выполняется большой запрос, то он может заблокировать ваши таблицы и привести к остановке приложения.

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

Если вы блокируете таблицы на продолжительное время (например, на 30 и более секунд) на высоко нагруженном веб сервере, вы можете вызвать накапливание процессов и запросов, что потребует значительного времени на расчистку или даже приведет к остановке вашего веб сервера.

Если у вас есть скрипт, который удаляет большое количество записей, просто используйте предложение LIMIT для разбиения его на маленькие партии, чтобы избежать описанной ситуации.

While (1) { mysql_query("DELETE FROM logs WHERE log_date <= "2009-10-01" LIMIT 10000"); if (mysql_affected_rows() == 0) { // выполняем удаление break; } // вы можете сделать небольшую паузу usleep(50000); }

18. Маленькие столбцы обрабатываются быстрее

Для механизма базы данных диск является наиболее важным узким местом. Стремление сделать все более компактным и маленьким обычно хорошо сказывается в сфере производительности за счет сокращения объема перемещаемых данных.

Документация MySQL содержит список для всех типов.

Если таблица будет содержать всего несколько строк, то нет причин делать основной ключ типа INT, а не MEDIUMINT, SMALLINT или даже TINYINT. если вам нужна только дата, используйте DATE вместо DATETIME.

Нужно только помнить о возможностях роста.

19. Выбирайте правильный механизм хранения данных

Есть два основных механизма хранения данных для MySQL: MyISAM и InnoDB. Каждый имеет свои достоинства и недостатки.

MyISAM отлично подходит для приложений с большой нагрузкой по чтению, но он не очень хорошо масштабируется при наличии большого количества записей. Даже если вы обновляете одно поле в одной строке, вся таблица будет заблокирована и ни один процесс не сможет ничего прочитать пока запрос не завершится. MyISAM быстро выполняет вычисления для запросов типа SELECT COUNT(*).

InnoDB является более сложным механизмом хранения данных, и он может быть более медленным, чем MyISAM для большинства маленьких приложений. Но он поддерживает блокирование строк, что лучше для масштабирования таблиц. Также он поддерживает некоторые дополнительные особенности, такие как транзакции.

20. Используйте объектно-реляционное отображение

Использование объектно-реляционного отображения (ORM - Object Relational Mapper) дает ряд преимуществ. Все, что можно сделать в ORM , можно сделать вручную, но с большими усилиями и более высокими требованиями к уровню разработчика.

ORM отлично подходит для "ленивой загрузки". Это означает, что получение значений возможно тогда, когда они нужны. Но нужно быть аккуратным, потому что можно создать много маленьких запросов, которые понизят производительность.

ORM может также объединять ваши запросы в транзакции, которые выполняются существенно быстрее, чем индивидуальные запросы к базе данных.

Для PHP можно использовать ORM .

21. Будьте осторожны с постоянными соединениями

Постоянные соединения предназначены для сокращения потерь на восстановление соединений к MySQL. Когда создается постоянное соединение, то оно остается открытым даже после завершения скрипта. Так как Apache повторно использует дочерние процессы, то процесс выполняется для нового скрипта, и он использует тоже соединение с MySQL.

Это звучит здорово в теории. Но в действительности это функция не стоит медного гроша из-за проблем. Она может вызывать серьезные неприятности с ограничениями количества соединений, переполнение памяти и так далее.

Apache работает на принципах параллельности, и создает множество дочерних процессов. Вот в чем заключается причина того, что постоянные соединения не работают как ожидается в данной системе. Прежде, чем использовать функцию mysql_pconnect(), проконсультируйтесь с вашим системным администратором.