Глава 7. MySQL Native Driver
MySQL Native Driver это замена для MySQL Client Library (libmysqlclient).
MySQL Native Driver это часть официальных исходных текстов PHP с PHP 5.3.0.
Расширения базы данных MySQL
mysqli и PDO MYSQL
общаются с сервером MySQL. В прошлом это было сделано расширением, используя
услуги, предоставленные MySQL Client Library. Расширения были собраны для
MySQL Client Library, чтобы использовать ее протокол клиент-сервер.
С MySQL Native Driver есть теперь альтернатива, поскольку расширения базы
данных MySQL могут быть собраны, чтобы использовать драйвер MySQL Native
Driver вместо MySQL Client Library.
MySQL Native Driver написан на C как расширение PHP.
7.1. Обзор
Хотя MySQL Native Driver написан как расширение PHP, важно отметить, что
это не предоставляет новый API PHP программисту. Программисту API для
возможности соединения базы данных MySQL предоставляют расширения MySQL,
mysqli и PDO MYSQL.
Эти расширения могут теперь использовать услуги MySQL Native Driver, чтобы
общаться с MySQL Server. Поэтому вы не должны думать о
MySQL Native Driver как об API.
Почему это применяется?
Использование MySQL Native Driver предлагает много преимуществ перед
пользованием MySQL Client Library.
MySQL Client Library написана MySQL AB (теперь куплена Oracle Corporation)
и была открыта в соответствии с лицензией MySQL. Это в конечном счете
поддержка MySQL, отключаемая по умолчанию в PHP. Однако, MySQL Native Driver
был развит как часть проекта PHP и поэтому открыт в соответствии с лицензией
PHP. Это удаляет проблемы лицензирования, которые были в прошлом.
Кроме того, в прошлом необходимо было построить расширения базы данных
MySQL для MySQL Client Library. Это, как правило, означало, что необходимо
было установить MySQL на машине, где вы строили исходный код PHP. Кроме того,
когда работало ваше приложение PHP, расширения базы данных MySQL обращались к
файлу MySQL Client library во время выполнения, таким образом, файл должен
был быть установлен на вашей системе. С MySQL Native Driver это больше не
имеет места, поскольку драйвер включен как часть стандартного дистрибутива.
Таким образом, вам не нужен установленный MySQL, чтобы построить PHP или
управлять приложениями базы данных PHP.
Так как MySQL Native Driver написан как расширение PHP,
это сильно связано с работами PHP. Это приводит к росту эффективности,
особенно когда дело доходит до использования памяти, поскольку драйвер
использует систему управления памятью PHP. Это также поддерживает
ограничения памяти PHP. Использование MySQL Native Driver
приводит к сопоставимой или лучшей работе, чем MySQL Client Library,
это всегда гарантирует наиболее эффективное использование памяти.
Один пример эффективности памяти то, что, пользуясь MySQL Client Library,
каждая строка сохранена в памяти дважды, тогда как с
MySQL Native Driver только однажды.
Поскольку MySQL Native Driver использует систему управления памятью PHP,
использование памяти может быть прослежено с помощью
memory_get_usage . Это невозможно с
libmysqlclient потому что он использует функцию C malloc().
Специальные функции
MySQL Native Driver также обеспечивает некоторые специальные функции, не
доступные, когда расширения базы данных MySQL пользуются
MySQL Client Library. Эти специальные функции упоминаются ниже:
Средство статистики может оказаться очень полезно в идентификации
исполнительных узких мест.
MySQL Native Driver также допускает постоянные связи, когда используется с
расширением mysqli .
Поддержка SSL
MySQL Native Driver понимает SSL с PHP version 5.3.3.
Поддержка сжатого протокола
С PHP 5.3.2 MySQL Native Driver поддерживает сжатый протокол
клиент-сервера. MySQL Native Driver не поддерживал это в 5.3.0 и
5.3.1. Расширения вроде ext/mysql ,
ext/mysqli , которые настраиваются, чтобы
использовать MySQL Native Driver, может также использовать в своих интересах
эту особенность. Отметьте, что
PDO_MYSQL НЕ
поддерживает сжатие, когда используется вместе с mysqlnd.
Поддержка именованных каналов
Поддержка именованных каналов Windows была добавлена в PHP version 5.4.0.
7.2. Установка
Журнал изменений
Таблица 7.1. Журнал изменений
Версия |
Описание |
5.3.0 |
MySQL Native Driver добавлен с поддержкой всех расширений MySQL
(mysql, mysqli и PDO_MYSQL). |
5.4.0 |
MySQL Native Driver теперь используется по умолчанию для всех расширений
MySQL (mysql, mysqli and PDO_MYSQL). |
5.5.0 |
Добавлена поддержка SHA-256 Authentication Plugin.
|
Установка в Unix
Расширения базы данных MySQL должны формироваться, чтобы пользоваться
MySQL Client Library. Чтобы использовать MySQL Native Driver, PHP
должен быть построен, определив, что расширения базы данных MySQL собраны с
поддержкой MySQL Native Driver. Это сделано через параметры конфигурации до
сборки исходного кода PHP.
Например, чтобы построить расширение MySQL
mysqli или PDO MYSQL с MySQL Native Driver,
следующая команда была бы дана:
./configure --with-mysql=mysqlnd \
--with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd [other options]
Установка в Windows
В официальных дистрибутивах с PHP Windows с версии 5.3 MySQL Native Driver
позволяют по умолчанию, таким образом, никакая дополнительная конфигурация не
требуется, чтобы использовать его. Все расширения базы данных MySQL будут
использовать MySQL Native Driver.
Поддержка SHA-256 Authentication Plugin
MySQL Native Driver требует, чтобы функциональность OpenSSL PHP была
загружена и позволяла соединиться с MySQL через учетные записи, которые
используют MySQL SHA-256 Authentication Plugin.
Например, PHP мог формироваться, используя:
./configure --with-mysql=mysqlnd --with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd \
--with-openssl [other options]
7.3.
Конфигурация во время выполнения
Поведение этих функций затронуто параметрами настройки в
php.ini .
Таблица 7.2. Опции MySQL Native Driver
Для получения дальнейшей информации и определения режимов PHP_INI_*
см. http://www.php.net/manual/en/configuration.changes.modes.
Вот короткое объяснение конфигурационных директив.
-
mysqlnd.collect_statistics
boolean
Позволяет сбор различной статистики клиента, к которой можно получить
доступ через
mysqli_get_client_stats ,
mysqli_get_connection_stats ,
mysqli_get_cache_stats
и просмотр в разделе mysqlnd функции
phpinfo .
Этот параметр конфигурации позволяет всю
статистику MySQL Native Driver
кроме того, что касается управления памятью.
-
mysqlnd.collect_memory_statistics
boolean
Позвольте сбор различной статистики памяти, к которой можно получить
доступ через
mysqli_get_client_stats ,
mysqli_get_connection_stats ,
mysqli_get_cache_stats и в секции
mysqlnd вывода функции
phpinfo .
Этот параметр конфигурации позволяет статистику управления памятью в
полном наборе MySQL Native
Driver statistics.
-
mysqlnd.debug
string
Писать данные всего использования расширений
mysqlnd в указанный файл журнала.
Формат директивы mysqlnd.debug =
"option1[,parameter_option1][:option2[,parameter_option2]]" .
Возможности для строки формата следующие:
A[,file] - Прилагает вывод трассировки
к указанному файлу. Также гарантирует, что данные сохранены после каждой
записи. Это сделано, закрыв и вновь открыв файл трассировки (это медленно).
Это помогает гарантировать, чтобы полный файл журнала был сохранен
при сбое приложения.
a[,file] - Прилагает вывод трассировки к указанному файлу.
d - Позволяет вывод из макроса DBUG_<N> для текущего состояния.
Может сопровождаться списком ключевых слов, который выбирает вывод только для
макроса DBUG с тем ключевым словом. Пустой список ключевых слов подразумевает
вывод для всего макроса.
f[,functions] - Ограничивает действия отладчика к указанному списку
функций. Пустой список функций подразумевает, что все функции выбраны.
F - Отмечает каждую строку вывода отладчика названием исходного файла,
содержащего макрос, вызывающий вывод.
i - Отмечает каждую строку вывода отладчика PID текущего процесса.
L - Отмечает каждую строку вывода отладчика
номером строки исходного файла макроса, вызывающего вывод.
n - Отмечает каждую строку вывода отладчика
текущей глубиной вложения функции.
o[,file] - Аналог a[,file], но переписывает старый файл.
O[,file] - Аналог A[,file], но переписывает старый файл.
t[,N] - Позволяет отслеживание потока управления функции.
Максимальная глубина вложения определяется N и по умолчанию 200.
x - Этот выбор активирует профилирование.
m - Трассировка распределения и освобождения памяти данных.
Например:
d:t:x:O,/tmp/mysqlnd.trace
Эта особенность доступна только с отладочной сборкой PHP.
Работает в Microsoft Windows, используя отладочную сборку PHP, если PHP был
построен, используя Microsoft Visual C 9 и выше.
-
mysqlnd.log_mask
integer
Определяет, какие запросы будут зарегистрированы.
Умолчание 0, отключает регистрацию. Определите с использованием целого числа,
а не констант PHP. Например, 48 (16 + 32) зарегистрирует медленные запросы,
которые используют 'no good index' (SERVER_QUERY_NO_GOOD_INDEX_USED = 16) или
или не используют никакой индекс вообще (SERVER_QUERY_NO_INDEX_USED = 32).
Значение 2043 (1 + 2 + 8 + ... + 1024) зарегистрирует все
типы медленного запроса.
Типы следующие: SERVER_STATUS_IN_TRANS=1,
SERVER_STATUS_AUTOCOMMIT=2, SERVER_MORE_RESULTS_EXISTS=8,
SERVER_QUERY_NO_GOOD_INDEX_USED=16,
SERVER_QUERY_NO_INDEX_USED=32,
SERVER_STATUS_CURSOR_EXISTS=64,
SERVER_STATUS_LAST_ROW_SENT=128,
SERVER_STATUS_DB_DROPPED=256,
SERVER_STATUS_NO_BACKSLASH_ESCAPES=512 и SERVER_QUERY_WAS_SLOW=1024.
-
mysqlnd.mempool_default_size
integer
Размер по умолчанию пула памяти, который
используется наборами результатов.
-
mysqlnd.net_read_timeout
integer
mysqlnd и MySQL Client Library,
libmysqlclient
используют различный сетевой API.
mysqlnd использует потоки PHP, тогда как
libmysqlclient использует собственную обертку
вокруг операционных вызовов уровня сети. PHP по умолчанию устанавливает
для потоков тайм-аут 60 секунд. Это установлено через
php.ini ,
default_socket_timeout . Это относится ко всем
потокам, которые не устанавливают никакое другое значение.
mysqlnd не устанавливает никакое другое
значение, и поэтому связи длительных запросов могут быть разъединены после
default_socket_timeout секунд,
приводя к сообщению об ошибке 2006 - MySQL Server
has gone away. MySQL Client Library устанавливает тайм-аут
24 * 3600 секунд (1 день) и ждет других тайм-аутов, например, тайм-ауты
TCP/IP. mysqlnd теперь использует тот же самый
очень длинный тайм-аут. Значение конфигурируемо через новую опцию
php.ini
mysqlnd.net_read_timeout .
mysqlnd.net_read_timeout используется
любым расширением (ext/mysql ,
ext/mysqli ,
PDO_MySQL ), которое использует
mysqlnd . mysqlnd
предписывает PHP Streams использовать
mysqlnd.net_read_timeout .
Обратите внимание на то, что могут быть тонкие различия между
MYSQL_OPT_READ_TIMEOUT из MySQL
Client Library и PHP Streams, Например,
MYSQL_OPT_READ_TIMEOUT зарегистрирован, чтобы
работать только на связи TCP/IP и, до MySQL 5.1.2, только для Windows.
У потоков PHP может не быть этого ограничения.
Пожалуйста, проверьте документацию потоков, если сомневаетесь.
-
mysqlnd.net_cmd_buffer_size
integer
mysqlnd
ассигнует внутренний буфер команд/сети
mysqlnd.net_cmd_buffer_size (в
php.ini ) байт
для каждой связи. Если команда протокола MySQL Client Server, например,
COM_QUERY (нормальный
запрос), не вписывается в буфер, mysqlnd
вырастит буфер к размеру, требуемому для отправки команды. Каждый раз, когда
буфер расширен для одной связи,
command_buffer_too_small растет на единицу.
Если mysqlnd
должен вырастить буфер вне его начального размера в
mysqlnd.net_cmd_buffer_size байт
для почти каждой связи, необходимо полагать, что увеличение размера по
умолчанию позволит избегать перераспределений.
Размер буфера по умолчанию составляет 2048 байтов в PHP 5.3.0.
В более поздних версиях умолчание составляет 4096 байтов.
Рекомендуется, чтобы размер буфера был установлен в не менее, чем
4096 байтов потому, что mysqlnd
также использование это, читая определенный коммуникационный пакет от MySQL.
В PHP 5.3.0 mysqlnd не вырастит буфер, если
MySQL пошлет пакет, который больше, чем текущий размер буфера. Как следствие,
mysqlnd не способен расшифровать пакет, и
клиентское приложение получит ошибку. Есть только две ситуации, когда пакет
может быть больше, чем 2048 байтов в
mysqlnd.net_cmd_buffer_size в PHP 5.3.0:
пакет транспортирует очень длинное сообщение об ошибке, или пакет содержит
метаданные колонки от COM_LIST_FIELD
(mysql_list_fields() и метаданные прибывают из
колонки последовательности с очень длинным значением
по умолчанию (>1900 байт).
С PHP 5.3.2 mysqlnd не позволяет устанавливать буфера меньшего
размера, чем 4096 байтов.
Значение может также быть установлено, используя
mysqli_options(link,
MYSQLI_OPT_NET_CMD_BUFFER_SIZE, size) .
-
mysqlnd.net_read_buffer_size
integer
Максимальный прочитанный размер куска в байтах, читая тело пакета
команд MySQL. Протокол клиент-сервера MySQL заключает в капсулу все свои
команды в пакетах. Пакеты состоят из маленького заголовка и тела с
фактическим полезным грузом. Размер тела закодирован в заголовке.
mysqlnd читает тело кусками в
MIN(header.size, mysqlnd.net_read_buffer_size)
байт. Если тело пакета больше, чем
mysqlnd.net_read_buffer_size байт,
mysqlnd должен вызвать
read() многократно.
Значение может также быть установлено, используя
mysqli_options(link,
MYSQLI_OPT_NET_READ_BUFFER_SIZE, size) .
-
mysqlnd.sha256_server_public_key
string
SHA-256 Authentication Plugin. Файл с публичным ключом
RSA сервера MySQL.
Клиенты могут пропустить установку публичного ключа RSA,
определяя ключ через этот параметр конфигурации PHP или устанавливать ключ
при использовании во время выполнения
mysqli_options .
Если файл публичных ключей RSA не будет дан клиентом, то ключ будет получен
как часть стандартной процедуры аутентификации SHA-256 Authentication Plugin.
-
mysqlnd.trace_alloc
string
-
mysqlnd.fetch_data_copy
integer
Выполнить копирование наборов результатов от внутренних буферов набора
результатов в переменные PHP вместо того, чтобы использовать ссылку по
умолчанию и логику copy-write. Пожалуйста, посмотрите подробности
здесь.
Копирование наборов результатов вместо того, чтобы иметь ссылку переменных
PHP позволяет освободить память, занятую для переменных PHP, раньше.
В зависимости от кода API, фактических запросов базы данных и размера их
наборов результатов, это может уменьшить объем потребляемой памяти mysqlnd.
Не устанавливайте, используя PDO_MySQL. PDO_MySQL
еще не был обновлен, чтобы поддержать новый режим получения.
7.4. Несовместимости
MySQL Native Driver в большинстве случаев совместим с MySQL Client
Library (libmysql ).
Эта секция несовместимости документов между этими библиотеками.
Значения типа данных bit
возвращен как двоичные строки (например, "\0" или "\x1F") с
libmysql или как десятичные последовательности
(например, "0" или "31") с mysqlnd .
Если вы хотите, чтобы код был совместим с обеими библиотеками, тогда всегда
возвращайте битовые поля как числа из MySQL для запросов вроде этого:
SELECT bit + 0 FROM table .
7.5. Постоянные связи
Используя постоянные связи
Если mysqli используется с
mysqlnd , когда постоянная связь создается, она
производит вызов COM_CHANGE_USER
(mysql_change_user() ).
Это гарантирует, что переидентификация связи происходит.
Так как есть издержки, связанные с вызовом
COM_CHANGE_USER ,
возможно выключить это во время компиляции.
Многократное использование постоянной связи тогда произведет вызов
COM_PING
(mysql_ping )
просто, чтобы проверить, можно ли повторно использовать связь.
Выключить COM_CHANGE_USER можно параметром
компиляции MYSQLI_NO_CHANGE_USER_ON_PCONNECT :
shell# CFLAGS="-DMYSQLI_NO_CHANGE_USER_ON_PCONNECT"
shell# ./configure --with-mysql=/usr/local/mysql/ \
--with-mysqli=/usr/local/mysql/bin/mysql_config \
--with-pdo-mysql=/usr/local/mysql/bin/mysql_config \
--enable-debug && make clean && make -j6
Или:
shell# export CFLAGS="-DMYSQLI_NO_CHANGE_USER_ON_PCONNECT"
shell# configure --whatever-option
shell# make clean
shell# make
Отметьте, что только mysqli в
mysqlnd применяет
COM_CHANGE_USER .
Другие драйверы применяют COM_PING
на начальном использовании постоянной связи.
7.6. Статистика
Используя статистические данные
MySQL Native Driver содержит поддержку сбора статистики по связи между
клиентом и сервером. Собранные статистические данные имеют два главных типа:
Статистика клиента.
Статистика связи.
При использовании mysqli
эти статистические данные могут быть получены через два вызова API:
Статистические данные соединены среди всех расширений, которые используют
MySQL Native Driver. Например, собирая
ext/mysql и
ext/mysqli с MySQL Native Driver,
оба вызова функции ext/mysql и
ext/mysqli изменят статистику.
Нет никакого способа узнать, насколько определенный вызов API любого
расширения, которое было собрано с MySQL Native Driver,
повлиял на определенную статистическую величину. Можно формировать драйвер
PDO MySQL, ext/mysql и
ext/mysqli , чтобы произвольно использовать
MySQL Native Driver. Делая так, все три расширения изменят статистику.
Доступ к статистике клиента
Для доступа к статистике клиента необходимо вызвать
mysqli_get_client_stats .
Вызов функции не требует никаких параметров.
Функция возвращает ассоциативный массив, который содержит название
статистической величины как ключ и статистические данные как значение.
К статистике клиента можно также получить доступ, вызывая
phpinfo .
Доступ к статистике связи
Для доступа к статистике связи вызовите
mysqli_get_connection_stats .
Это берет дескриптор соединения с базой данных в качестве параметра.
Функция возвращает ассоциативный массив, который содержит название
статистической величины как ключ и статистические данные как значение.
Буферизованные и небуферизированные наборы результатов
Наборы результатов могут быть буферизованными или не буферизированными.
Используя настройки по умолчанию,
ext/mysql и
ext/mysqli
работают с буферизированными наборами результатов для нормальных (не
подготовленных) запросов. Буферизированные наборы результатов кэшируются
на клиенте. После выполнения запросов все результаты получены от MySQL Server
и сохранены в кэше на клиенте. Большое преимущество буферизированных наборов
результатов состоит в том, что они позволяют серверу освобождать все ресурсы,
ассигнованные набору результатов, когда результаты были забраны клиентом.
Небуферизированные наборы результатов, с другой стороны, сохранены
намного более длительно на сервере. Если вы хотите уменьшить потребление
памяти на клиенте ценой увеличения нагрузки на сервер, используйте
небуферизированные результаты. Если вы испытываете высокую
нагрузку на сервера и число небуферизированных наборов результатов высоко,
необходимо рассмотреть перемещение нагрузки клиентам. Клиенты, как правило,
масштабируются лучше, чем серверы.
Нагрузка относится не только к буферам памяти:
сервер также должен сохранять другие ресурсы открытыми, например, дескрипторы
файлов и потоки прежде, чем набор результатов сможет быть освобожден.
Подготовленные запросы используют небуферизированные наборы результатов по
умолчанию. Однако, можно использовать
mysqli_stmt_store_result ,
чтобы позволить буферизованные наборы результатов.
Статистика, возвращенная MySQL Native Driver
Следующие таблицы показывают список статистики, возвращенной функциями
mysqli_get_client_stats и
mysqli_get_connection_stats .
Таблица 7.3. Статистика mysqlnd: сеть
Значение |
Область действия | Описание |
Примечания |
bytes_sent |
Connection | Число байтов, посланных PHP на сервер MySQL. |
Может использоваться, чтобы проверить
эффективность протокола сжатия. |
bytes_received |
Connection | Число байтов, полученных от сервера MySQL. |
Может использоваться, чтобы проверить
эффективность протокола сжатия. |
packets_sent |
Connection |
Количество переданных пакетов протокола MySQL Client Server. |
Используется для отладки внедрения протокола Client Server. |
packets_received |
Connection |
Количество полученных пакетов протокола MySQL Client Server. |
Используется для отладки внедрения протокола Client Server. |
protocol_overhead_in |
Connection |
Издержки протокола MySQL Client в байтах для входящего трафика.
В настоящее время только Packet Header (4 байта) рассматривают как издержки.
protocol_overhead_in = packets_received * 4 |
Используется для отладки внедрения протокола Client Server. |
protocol_overhead_out |
Connection |
Издержки протокола MySQL Client в байтах для исходящего трафика.
В настоящее время только Packet Header (4 байта) рассматривают как издержки.
protocol_overhead_out = packets_sent * 4 |
Используется для отладки внедрения протокола Client Server. |
bytes_received_ok_packet |
Connection |
Полный размер в байтах протокола полученных пакетов OK протокола
MySQL Client Server. OK-пакеты могут содержать сообщение о состоянии.
Длина сообщения о состоянии может измениться, и таким образом размер пакета
OK не фиксирован. |
Используется для отладки внедрения протокола Client Server.
Обратите внимание на то, что полный размер в байтах включает размер заголовка
пакета (4 байта, см. издержки протокола). |
packets_received_ok |
Connection |
Количество принятых пакетов OK MySQL Client Server. |
Используется для отладки внедрения протокола Client Server.
Обратите внимание на то, что полный размер в байтах включает размер заголовка
пакета (4 байта, см. издержки протокола). |
bytes_received_eof_packet
|
Connection |
Полный размер в байтах принятых пакетов EOF MySQL Client Server.
EOF может измениться по размеру в зависимости от версии сервера.
Кроме того, EOF может транспортировать сообщение об ошибке. |
Используется для отладки внедрения протокола Client Server.
Обратите внимание на то, что полный размер в байтах включает размер заголовка
пакета (4 байта, см. издержки протокола). |
packets_received_eof |
Connection |
Число принятых пакетов EOF MySQL Client Server.
Как с другой статистикой пакетов, будет увеличено число пакетов, даже если
PHP получит не ожидаемый пакет, а, например, сообщение об ошибке. |
Используется для отладки внедрения протокола Client Server.
Обратите внимание на то, что полный размер в байтах включает размер заголовка
пакета (4 байта, см. издержки протокола). |
bytes_received_rset_header_packet |
Connection |
Полный размер в байтах пакетов заголовка набора результатов протокола
MySQL Client Server. Размер пакетов варьируется в зависимости от полезного
груза (LOAD LOCAL INFILE ,
INSERT , UPDATE ,
SELECT , сообщение об ошибке). |
Используется для отладки внедрения протокола Client Server.
Обратите внимание на то, что полный размер в байтах включает размер заголовка
пакета (4 байта, см. издержки протокола). |
packets_received_rset_header
|
Connection |
Количество пакетов заголовка набора результатов протокола
MySQL Client Server. |
Используется для отладки внедрения протокола Client Server.
Обратите внимание на то, что полный размер в байтах включает размер заголовка
пакета (4 байта, см. издержки протокола). |
bytes_received_rset_field_meta_packet |
Connection |
Полный размер в байтах пакетов метаданных набора результатов (полевая
информация) протокола Client Server. Конечно, размер меняется в зависимости
от полей в наборе результатов. Пакет может также транспортировать ошибку или
пакет EOF в случае COM_LIST_FIELDS. |
Полезно для отладки внедрения протокола CS. Обратите внимание на то, что
полный размер в байтах включает размер заголовка пакета
(4 байта, см. издержки протокола). |
packets_received_rset_field_meta |
Connection |
Количество пакетов метаданных набора результатов протокола
MySQL Client Server (полевая информация). |
Полезно для отладки внедрения протокола CS. Обратите внимание на то, что
полный размер в байтах включает размер заголовка пакета
(4 байта, см. издержки протокола). |
bytes_received_rset_row_packet
|
Connection |
Полный размер в байтах пакетов данных о строках
набора результатов протокола MySQL Client Server.
Пакет может также транспортировать ошибку или пакет EOF.
Можно узнать количество ошибок и пакетов EOF, вычтя
rows_fetched_from_server_normal и
rows_fetched_from_server_ps из
bytes_received_rset_row_packet . |
Полезно для отладки внедрения протокола CS. Обратите внимание на то, что
полный размер в байтах включает размер заголовка пакета
(4 байта, см. издержки протокола). |
packets_received_rset_row
|
Connection |
Количество пакетов данных о строках набора результатов протокола
MySQL Client Server и их полный размер в байтах. |
Полезно для отладки внедрения протокола CS. Обратите внимание на то, что
полный размер в байтах включает размер заголовка пакета
(4 байта, см. издержки протокола). |
bytes_received_prepare_response_packet |
Connection |
Полный размер в байтах OK-пакетов протокола MySQL Client Server
для пакетов инициализации подготовленных запросов.
Пакет может также транспортировать ошибку. Размер пакета зависит от версии
MySQL: 9 байтов с MySQL 4.1 и 12 байтов с MySQL 5.0. Нет никакого безопасного
способа узнать, сколько ошибок произошло. Можно быть в состоянии
предположить, что ошибка произошла, если, например, вы всегда соединяетесь с
MySQL 5.0 или более новым, но
bytes_received_prepare_response_packet
!= packets_received_prepare_response * 12.
См. также ps_prepared_never_executed ,
ps_prepared_once_executed . |
Полезно для отладки внедрения протокола CS. Обратите внимание на то, что
полный размер в байтах включает размер заголовка пакета
(4 байта, см. издержки протокола). |
packets_received_prepare_response |
Connection |
Количество OK-пакетов протокола MySQL Client Server
для пакетов инициализации подготовленных запросов. |
Полезно для отладки внедрения протокола CS. Обратите внимание на то, что
полный размер в байтах включает размер заголовка пакета
(4 байта, см. издержки протокола). |
bytes_received_change_user_packet |
Connection |
Полный размер в байтах пакетов COM_CHANGE_USER
протокола MySQL Client Server.
Пакет может также транспортировать ошибку или EOF. |
Полезно для отладки внедрения протокола CS. Обратите внимание на то, что
полный размер в байтах включает размер заголовка пакета
(4 байта, см. издержки протокола). |
packets_received_change_user
|
Connection | Количество пакетов COM_CHANGE_USER. |
Полезно для отладки внедрения протокола CS. Обратите внимание на то, что
полный размер в байтах включает размер заголовка пакета
(4 байта, см. издержки протокола). |
packets_sent_command |
Connection |
Количество команд протокола MySQL Client Server, посланных PHP в MySQL.
Нет никакого способа узнать, какие определенные команды и сколько их послали.
Можно использовать его, чтобы проверить, послал ли PHP какие-либо команды в
MySQL, чтобы узнать, можно ли рассмотреть отключение поддержки MySQL
в двоичных модулях PHP. Нет также никакого способа узнать количество ошибок,
которые, возможно, произошли, посылая данные в MySQL. Единственная ошибка,
которая зарегистрирована, является command_buffer_too_small. |
Полезно для отладки внедрения протокола CS. Обратите внимание на то, что
полный размер в байтах включает размер заголовка пакета
(4 байта, см. издержки протокола). |
bytes_received_real_data_normal
|
Connection |
Число байтов полезного груза, принесенного клиентом PHP от
mysqlnd с
использованием текстового протокола. |
Это размер фактических данных, содержавшихся в наборах результатов,
которые не происходят из подготовленных запросов и которые были получены
клиентом PHP. Отметьте что, хотя полный набор результатов, возможно, вынули
из MySQL через mysqlnd ,
эта статистическая величина считает только фактические данные из
mysqlnd клиентом PHP.
Пример кода, который увеличит значение:
$mysqli = new mysqli();
$res = $mysqli->query("SELECT 'abc'");
$res->fetch_assoc();
$res->close();
Каждая операция получения увеличит значение.
Статистическая величина не будет увеличена, если набор результатов будет
только буферизован на клиенте, но не получен, как в следующем примере:
$mysqli = new mysqli();
$res = $mysqli->query("SELECT 'abc'");
$res->close();
Эта статистическая величина доступна с версии PHP 5.3.4. |
bytes_received_real_data_ps
|
Connection |
Число байтов полезного груза, принесенного клиентом PHP от
mysqlnd с использованием
протокола подготовленного запроса. |
Это размер фактических данных, содержавшихся в наборах результатов,
которые происходят из подготовленных запросов и которые были принесены
клиентом PHP. Значение не будет увеличено, если набор результатов не будет
впоследствии прочитан клиентом PHP. Отметьте что, хотя полный набор
результатов, возможно, получили из MySQL через
mysqlnd , эта статистическая величина считает
только фактические данные полученные из
mysqlnd клиентом PHP. См. также
bytes_received_real_data_normal .
Эта статистическая величина доступна с версии PHP 5.3.4.
|
Набор результатов
Таблица 7.4. Возвращенная mysqlnd статистика: набор результатов
Имя | Область действия |
Описание | Примечания |
result_set_queries
| Connection |
Количество запросов, которые произвели набор результатов.
Примеры запросов, которые производят набор результатов:
SELECT ,
SHOW . Статистическая величина не будет
увеличена, если будет ошибка при чтении пакета
заголовка набора результатов. |
Можно использовать в качестве косвенной меры для количества запросов,
которые PHP послал в MySQL, например, чтобы опознать клиента, который
вызывает высокую нагрузку базы данных. |
non_result_set_queries |
Connection |
Количество запросов, которые не произвели набор результатов.
Примеры запросов, которые не производят набор результатов:
INSERT , UPDATE ,
LOAD DATA .
Статистическая величина не будет увеличена, если будет ошибка при
чтении пакета заголовка набора результатов. |
Можно использовать в качестве косвенной меры для количества запросов,
которые PHP послал в MySQL, например, чтобы опознать клиента, который
вызывает высокую нагрузку базы данных. |
no_index_used |
Connection |
Количество запросов, которые произвели набор результатов, но не
использовали индекс (см. также опцию запуска mysqld
─log-queries-not-using-indexes). Если вы хотите, чтобы эти запросы были
сообщены, можно использовать
mysqli_report(MYSQLI_REPORT_INDEX), чтобы заставить ext/mysqli
бросить исключение. Если вы предпочитаете, чтобы было предупреждение вместо
исключения, используйте mysqli_report(MYSQLI_REPORT_INDEX ^
MYSQLI_REPORT_STRICT). | |
bad_index_used |
Connection |
Количество запросов, которые произвели набор результатов и не
использовали хороший индекс (см. также опцию запуска mysqld
─log-slow-queries). |
Если вы хотите, чтобы эти запросы были
сообщены, можно использовать
mysqli_report(MYSQLI_REPORT_INDEX), чтобы заставить ext/mysqli
бросить исключение. Если вы предпочитаете, чтобы было предупреждение вместо
исключения, используйте mysqli_report(MYSQLI_REPORT_INDEX ^
MYSQLI_REPORT_STRICT). |
slow_queries |
Connection |
SQL-операторы, которые взяли больше, чем
long_query_time секунд, чтобы выполниться и
требуют по крайней мере min_examined_row_limit
строк, которые будут исследованы. |
Не сообщается через
mysqli_report . |
buffered_sets |
Connection |
Количество буферизированных наборов результатов, возвращенное
не подготовленными запросами
в следующих примечаниях. |
Примеры вызовов API, которые буферизуют наборы результатов на клиенте:
mysql_query ,
mysqli_query ,
mysqli_store_result ,
mysqli_stmt_get_result .
Буферизование наборов результатов на клиенте гарантирует, что ресурсы сервера
освобождены как можно скорее, и делает прокрутку набора результатов легче.
Оборотная сторона дополнительное потребление памяти на клиенте для того,
чтобы буферизовать данные. Обратите внимание на то, что mysqlnd (в отличие от
MySQL Client Library) уважает предел памяти PHP, потому что это использует
функции управления внутренней памятью PHP, чтобы ассигновать память.
Это также причина почему
memory_get_usage
сообщает более высокое потребление памяти, используя mysqlnd вместо
MySQL Client Library.
memory_get_usage
не измеряет потребление памяти MySQL Client Library вообще, потому что
не использует функции управления внутренней памятью PHP! |
unbuffered_sets |
Connection |
Количество небуферизированных наборов результатов, возвращенных
нормальным (не подготовленным) запросом. |
Примеры вызовов API, которые не буферизуют наборы результатов на клиенте:
mysqli_use_result . |
ps_buffered_sets |
Connection |
Количество буферизированных наборов результатов, возвращенных
подготовленными запросами. По умолчанию подготовленные
запросы не буферизированы. |
Примеры вызовов API, которые буферизуют наборы результатов на клиенте:
mysqli_stmt_store_result . |
ps_unbuffered_sets |
Connection |
Количество небуферизированных наборов результатов,
возвращенных подготовленными запросами. |
По умолчанию подготовленные запросы не буферизированы. |
flushed_normal_sets |
Connection |
Количество наборов результатов от нормальных (не подготовленных)
запросов с непрочитанными данными, которые тихо сброшены для вас.
Это происходит только с небуферизированными наборами результатов. |
Небуферизированные наборы результатов должны быть полностью получены,
прежде чем новым запросом можно управлять на связи, иначе MySQL бросит
ошибку. Если приложение не приносит все строки от небуферизированного набора
результатов, mysqlnd действительно неявно приносит набор результатов, чтобы
очистить линию. См. также rows_skipped_normal ,
rows_skipped_ps . Некоторые возможные причины
для неявного сброса:
Дефектное клиентское приложение.
Клиент прекратил читать после того, как нашел то, что искал, но
заставил MySQL вычислить больше записей, чем необходимо.
Клиентское приложение неожиданно остановилось.
|
flushed_ps_sets |
Connection |
Количество наборов результатов из подготовленных запросов
с непрочитанными данными, которые тихо сброшены.
Это происходит только с небуферизированными наборами результатов. |
Небуферизированные наборы результатов должны быть полностью получены,
прежде чем новым запросом можно управлять на связи, иначе MySQL бросит
ошибку. Если приложение не приносит все строки от небуферизированного набора
результатов, mysqlnd действительно неявно приносит набор результатов, чтобы
очистить линию. См. также rows_skipped_normal ,
rows_skipped_ps . Некоторые возможные причины
для неявного сброса:
Дефектное клиентское приложение.
Клиент прекратил читать после того, как нашел то, что искал, но
заставил MySQL вычислить больше записей, чем необходимо.
Клиентское приложение неожиданно остановилось.
|
ps_prepared_never_executed
|
Connection |
Количество подготовленных, но никогда не выполненных запросов. |
Подготовленные запросы занимают ресурсы сервера. Вы не должны готовить
запрос, если вы не планируете выполнить его. |
ps_prepared_once_executed
|
Connection |
Количество подготовленных запросов, выполненных только один раз. |
Одна из идей подготовленных запросов то, что тот же самый запрос
выполняется много раз (с различными параметрами) и некоторый парсинг и
другая работа подготовки может быть сэкономлена, если выполнение запросы
разделено на стадии подготовки и выполнения.
Идея состоит в том, чтобы подготовить однажды и
кэшировать результаты, например, дерево
синтаксического анализа, которое будет снова использовано во время
многократного выполнения запроса. Если вы выполняете подготовленный запрос
только однажды, две стадии обработки могут быть неэффективными по сравнению с
нормальными запросами, потому что все кэширование означает дополнительную
работу, и это берет (ограниченные) ресурсы сервера, чтобы хранить информацию.
Следовательно, подготовленные запросы, которые выполняются только однажды,
могут вызвать вред для производительности. |
rows_fetched_from_server_normal
, rows_fetched_from_server_ps |
Connection |
Общее количество строк набора результатов успешно полученных от MySQL,
независимо от того, потребляло их или нет клиентское приложение.
Некоторые строки могли быть не получены клиентским приложением,
но неявно сброшены. |
См. packets_received_rset_row . |
rows_buffered_from_client_normal
, rows_buffered_from_client_ps |
Connection |
Общее количество успешно буферизированных строк, происходящих из
"нормального" запроса или подготовленного запроса.
Это количество строк, которые были принесены от MySQL и буферизованы на
клиенте. Обратите внимание на то, что есть два отличных статистических данных
по строкам, которые были буферизованы (MySQL к mysqlnd внутреннему буферу) и
буферизированные строки, которые были принесены клиентским приложением
(внутренний буфер mysqlnd к клиентскому приложению).
Если количество буферизированных строк выше, чем количество поученных
буферизированных строк, это может означать, что клиентское приложение
управляет запросами, которые вызывают большие наборы
результатов, чем необходимо. |
Примеры запросов, которые буферизуют результаты:
mysqli_query ,
mysqli_store_result . |
rows_fetched_from_client_normal_buffered ,
rows_fetched_from_client_ps_buffered |
Connection |
Общее количество строк, принесенных клиентом от буферизированного набора
результатов, созданного нормальным или подготовленным запросом.
| |
rows_fetched_from_client_normal_unbuffered ,
rows_fetched_from_client_ps_unbuffered |
Connection |
Общее количество строк, принесенных клиентом от небуферизированного
набора результатов, созданного "нормальным"
или подготовленным запросом. | |
rows_fetched_from_client_ps_cursor |
Connection |
Общее количество строк, полученных клиентом от курсора,
созданного подготовленным запросом. | |
rows_skipped_normal ,
rows_skipped_ps |
Connection |
Зарезервировано для будущего использования
(в настоящее время не поддержано). | |
copy_on_write_saved ,
copy_on_write_performed |
Process |
С mysqlnd переменные, возвращенные расширениями, указывают в mysqlnd
буфера результата внутренней сети. Если вы не замените переменные,
принесенные данные будут сохранены только однажды в памяти. Если вы заменяете
переменные, mysqlnd должен выполнить copy-write, чтобы защитить буферы
результата внутренней сети от изменения. С MySQL Client Library
вы всегда храните принесенные данные дважды в памяти.
Один раз во внутренних буферах MySQL Client Library и один раз в переменных,
возвращенных расширениями. В теории mysqlnd может сэкономить
40% памяти. Однако, обратите внимание на то, что экономия памяти не может
быть измерена, используя
memory_get_usage . | |
explicit_free_result ,
implicit_free_result |
Connection, Process (только во время
очистки подготовленных запросов). |
Общее количество освобожденных наборов результатов. |
Освобжденные наборы результатов, но для наборов результатов, созданных
командой init, например,
mysqli_options(MYSQLI_INIT_COMMAND, ...)
. |
proto_text_fetched_null ,
proto_text_fetched_bit ,
proto_text_fetched_tinyint
proto_text_fetched_short ,
proto_text_fetched_int24 ,
proto_text_fetched_int
proto_text_fetched_bigint ,
proto_text_fetched_decimal ,
proto_text_fetched_float
proto_text_fetched_double ,
proto_text_fetched_date ,
proto_text_fetched_year
proto_text_fetched_time ,
proto_text_fetched_datetime ,
proto_text_fetched_timestamp
proto_text_fetched_string ,
proto_text_fetched_blob ,
proto_text_fetched_enum
proto_text_fetched_set ,
proto_text_fetched_geometry ,
proto_text_fetched_other |
Connection |
Общее количество колонок определенного типа, принесенных от нормального
запроса (текстовый протокол MySQL). |
Отображение C API/метаданных MySQL к имени статистики:
MYSQL_TYPE_NULL -
proto_text_fetched_null
MYSQL_TYPE_BIT -
proto_text_fetched_bit
MYSQL_TYPE_TINY -
proto_text_fetched_tinyint
MYSQL_TYPE_SHORT -
proto_text_fetched_short
MYSQL_TYPE_INT24 -
proto_text_fetched_int24
MYSQL_TYPE_LONG -
proto_text_fetched_int
MYSQL_TYPE_LONGLONG -
proto_text_fetched_bigint
MYSQL_TYPE_DECIMAL ,
MYSQL_TYPE_NEWDECIMAL -
proto_text_fetched_decimal
MYSQL_TYPE_FLOAT -
proto_text_fetched_float
MYSQL_TYPE_DOUBLE -
proto_text_fetched_double
MYSQL_TYPE_DATE ,
MYSQL_TYPE_NEWDATE -
proto_text_fetched_date
MYSQL_TYPE_YEAR -
proto_text_fetched_year
MYSQL_TYPE_TIME -
proto_text_fetched_time
MYSQL_TYPE_DATETIME -
proto_text_fetched_datetime
MYSQL_TYPE_TIMESTAMP -
proto_text_fetched_timestamp
MYSQL_TYPE_STRING ,
MYSQL_TYPE_VARSTRING ,
MYSQL_TYPE_VARCHAR -
proto_text_fetched_string
MYSQL_TYPE_TINY_BLOB ,
MYSQL_TYPE_MEDIUM_BLOB ,
MYSQL_TYPE_LONG_BLOB ,
MYSQL_TYPE_BLOB -
proto_text_fetched_blob
MYSQL_TYPE_ENUM -
proto_text_fetched_enum
MYSQL_TYPE_SET -
proto_text_fetched_set
MYSQL_TYPE_GEOMETRY -
proto_text_fetched_geometry
Любые не перечисленные здесь типы
MYSQL_TYPE_* (не должно быть ни одного) -
proto_text_fetched_other
Обратите внимание на то, что константы MYSQL_*
не могут быть связаны с теми же самыми типами столбца SQL
в каждой версии MySQL. |
proto_binary_fetched_null ,
proto_binary_fetched_bit ,
proto_binary_fetched_tinyint
proto_binary_fetched_short ,
proto_binary_fetched_int24 ,
proto_binary_fetched_int ,
proto_binary_fetched_bigint ,
proto_binary_fetched_decimal ,
proto_binary_fetched_float ,
proto_binary_fetched_double ,
proto_binary_fetched_date ,
proto_binary_fetched_year ,
proto_binary_fetched_time ,
proto_binary_fetched_datetime ,
proto_binary_fetched_timestamp ,
proto_binary_fetched_string ,
proto_binary_fetched_blob ,
proto_binary_fetched_enum ,
proto_binary_fetched_set ,
proto_binary_fetched_geometry ,
proto_binary_fetched_other |
Connection |
Общее количество колонок определенного типа, принесенных из
подготовленного запроса (протокол двоичной синхронной
передачи данных MySQL). |
Для отображения типов см.
proto_text_* выше. |
Таблица 7.5. Возвращенная mysqlnd статистика: Connection
Имя | Область действия |
Описание | Примечания |
connect_success ,
connect_failure |
Connection |
Общее количество успешных/неудачных попыток подключения. |
Включены снова использованные связи и все другие виды связей. |
reconnect |
Process |
Общее количество попыток (real_)connect, предпринятых на уже
открытом дескрипторе связи. |
Кодовая последовательность $link = new mysqli(...);
$link->real_connect(...) вызовет повторно подключение. Но
$link = new mysqli(...);
$link->connect(...) не вызовет, потому что
$link->connect(...) явно закроет существующую
связь, прежде чем новая связь будет установлена. |
pconnect_success |
Connection |
Общее количество успешных постоянных попыток подключения. |
Заметьте, что connect_success
хранит сумму успешных постоянных и непостоянных попыток подключения.
Количество успешных непостоянных попыток подключения это
connect_success -
pconnect_success . |
active_connections |
Connection |
Общее количество активных постоянных и непостоянных связей. |
|
active_persistent_connections |
Connection |
Общее количество активных постоянных связей. |
Общее количество активных непостоянных связей это
active_connections -
active_persistent_connections . |
explicit_close |
Connection |
Общее количество явно закрытых связей (только в ext/mysqli). |
Примеры фрагментов кода, которые вызывают явное завершение:
$link = new mysqli(...); $link->close(...)
$link = new mysqli(...); $link->connect(...)
|
implicit_close |
Connection |
Общее количество неявно закрытых связей (только ext/mysqli). |
Примеры фрагментов кода, которые вызывают неявное завершение:
$link = new mysqli(...);
$link->real_connect(...)
unset($link)
Постоянная связь: объединенная связь была создана с real_connect
и может быть неизвестный набор опций. Закрыта неявно, чтобы избежать
возврата связи с неизвестными опциями.
Постоянная связь: ping/change_user терпит неудачу и
ext/mysqli закрывает связь.
Конец выполнения скрипта: закрываются связи, которые
не были закрыты пользователем.
|
disconnect_close |
Connection |
Неудачи связи обозначаются вызовом C API
mysql_real_connect
во время попытки установить связь. |
Это вызывает disconnect_close
потому что дескриптор связи, переданный вызову C API, будет закрыт. |
in_middle_of_command_close
| Process |
Связь была закрыта посреди выполнения команды (наборы результатов не
получены после отправки запроса, прежде, чем получить ответ во время
получения данных, передавая данные с LOAD DATA). |
Если вы не используете асинхронные запросы, это должно произойти только,
если ваш скрипт неожиданно останавливается, и PHP закрывает связи. |
init_command_executed_count
| Connection |
Общее количество выполненных команд init, например,
mysqli_options(MYSQLI_INIT_COMMAND, ...) . |
Количество успешного выполнения
init_command_executed_count -
init_command_failed_count . |
init_command_failed_count |
Connection |
Общее количество неудавшихся команд init. | |
Таблица 7.6. Возвращенная mysqlnd статистика: команды COM_*
Имя |
Область действия | Описание |
Примечания |
com_quit ,
com_init_db ,
com_query ,
com_field_list ,
com_create_db ,
com_drop_db ,
com_refresh ,
com_shutdown ,
com_statistics ,
com_process_info ,
com_connect ,
com_process_kill ,
com_debug , com_ping ,
com_time ,
com_delayed_insert ,
com_change_user ,
com_binlog_dump ,
com_table_dump ,
com_connect_out ,
com_register_slave ,
com_stmt_prepare ,
com_stmt_execute ,
com_stmt_send_long_data ,
com_stmt_close ,
com_stmt_reset ,
com_stmt_set_option ,
com_stmt_fetch ,
com_daemon |
Connection |
Общее количество попыток послать определенную команду COM_*
из PHP в MySQL. |
Статистические данные увеличены после проверки связи и немедленно
прежде, чем послать соответствующий пакет протокола клиент-сервера MySQL.
Если mysqlnd не пошлет пакет, то статистика не будет уменьшена.
В случае неудачи mysqlnd выпускает PHP-предупреждение
Error while sending %s packet. PID=%d.
Примеры использования:
Проверьте, посылает ли PHP определенные команды в MySQL, например,
проверка, что клиент посылает
COM_PROCESS_KILL .
Вычислите среднее количество выполненных подготовленных запросов,
сравнив COM_EXECUTE и
COM_PREPARE .
Проверьте, управлял ли PHP какими-либо неподготовленными
SQL-операторами, проверяя, что
COM_QUERY = 0.
Определите скрипты PHP, которые управляют чрезмерным количеством
SQL-операторов, проверяя COM_QUERY и
COM_EXECUTE .
|
Прочее
Таблица 7.7. Возвращенная mysqlnd статистика: Miscellaneous
Имя |
Область действия | Описание |
Примечания |
explicit_stmt_close ,
implicit_stmt_close |
Process |
Общее количество закрытых подготовленных запросов. |
|
mem_emalloc_count ,
mem_emalloc_ammount ,
mem_ecalloc_count ,
mem_ecalloc_ammount ,
mem_erealloc_count ,
mem_erealloc_ammount ,
mem_efree_count ,
mem_malloc_count ,
mem_malloc_ammount ,
mem_calloc_count ,
mem_calloc_ammount ,
mem_realloc_count ,
mem_realloc_ammount ,
mem_free_count |
Process |
Вызовы управления памятью. |
Только для разработчиков. |
command_buffer_too_small |
Connection |
Количество сетевых расширений буфера команд, посылая команды
от PHP в MySQL. |
mysqlnd ассигнует внутренний буфер команд/сети в
mysqlnd.net_cmd_buffer_size
(php.ini ) байт для каждой связи.
Если команда протокола MySQL Client Server, например,
COM_QUERY (нормальный запрос), не вписывается в
буфер, mysqlnd вырастит буфер к тому, что необходимо для отправки команды.
Каждый раз, когда буфер расширен для одной связи
command_buffer_too_small
будет увеличен на единицу.
Если mysqlnd должен вырастить буфер вне своего начального размера
mysqlnd.net_cmd_buffer_size
(php.ini ) байт для почти каждой связи,
необходимо рассмотреть, чтобы увеличить размер по умолчанию,
чтобы избежать перераспределений.
Размер буфера по умолчанию составляет 2048 байтов в PHP 5.3.0.
В будущих версиях размер составит 4 КБ или больше. Умолчание может изменяться
через настройки в php.ini
mysqlnd.net_cmd_buffer_size или через
mysqli_options(MYSQLI_OPT_NET_CMD_BUFFER_SIZE,
int size) .
Рекомендуется установить размер буфера в не менее, чем 4096 байтов, потому
что mysqlnd также использует его, читая определенный коммуникационный пакет
от MySQL. В PHP 5.3.0 mysqlnd не вырастит буфер, если MySQL пошлет пакет,
который больше, чем текущий размер буфера. Как следствие mysqlnd не способен
декодировать пакет и клиентское приложение получит ошибку.
Есть только две ситуации, когда пакет может быть больше, чем 2048-байтовое
умолчание mysqlnd.net_cmd_buffer_size в PHP
5.3.0: пакет транспортирует очень длинное сообщение об ошибке, или пакет
содержит метаданные колонки от COM_LIST_FIELD
(
mysql_list_fields )
и метаданные прибывают из колонки последовательности с очень длинным
значением по умолчанию (>1900 байт). Никакого отчета об ошибках на этом не
существует: это должно редко происходить.
С PHP 5.3.2 mysqlnd не позволяет устанавливать буфера, меньшего
размера, чем 4096 байтов. |
connection_reused |
| | |
7.7. Примечания
Эта секция обеспечивает коллекцию разных примечаний по использованию
MySQL Native Driver.
7.8. Управление памятью
Введение
MySQL Native Driver управляет памятью не так, как MySQL Client Library.
Библиотеки отличаются по способу, которым память ассигнована и освобождена,
как память ассигнуется в кусках, читая результаты из MySQL,
какие опции отладки существуют и как результаты, прочитанные из MySQL,
связаны с пользовательскими переменными PHP.
Следующие примечания предназначаются как введение и резюме пользователям,
заинтересованным в понимании MySQL Native Driver на кодовом уровне C.
Функции управления памятью
Все выделение памяти и освобождение сделаны, используя функции управления
памятью PHP. Поэтому потребление памяти mysqlnd может быть прослежено,
используя вызовы API PHP, например,
memory_get_usage .
Поскольку память ассигнуется и освобождается с использованием управления
памятью PHP, изменения могут не стать немедленно видимыми на уровне
операционной системы. Управление памятью PHP действует как полномочие,
которое может задержать возврат памяти системе.
Из-за этого сравнение использования памяти MySQL Native Driver и
MySQL Client Library трудное. MySQL Client Library использует требования
управления памятью операционной системы непосредственно, следовательно
эффекты могут немедленно наблюдаться на уровне операционной системы.
Любой предел памяти, проведенный в жизнь PHP, также затрагивает
MySQL Native Driver. Это может вызвать ошибки памяти, получая большие наборы
результатов, которые превышают размер объема оставшейся памяти, сделанного
доступным для PHP. Поскольку MySQL Client Library не использует функции
управления памятью PHP, она не соответствует никакому пределу памяти PHP.
Пользуясь MySQL Client Library, в зависимости от модели развертывания, объем
потребляемой памяти процесса PHP может вырасти вне предела памяти PHP.
Но также и скрипты PHP могут быть в состоянии обработать большие наборы
результатов, поскольку части памяти, ассигнованной, чтобы хранить наборы
результатов, находятся вне контроля PHP.
Функции управления памятью PHP призваны MySQL Native Driver
через легкую обертку. Среди прочего обертка делает отладку легче.
Обработка наборов результатов
Различные MySQL Server и клиентские API дифференцируются между
буферизированными
и небуферизированными наборами результатов. Небуферизированные наборы
результатов переданы построчно от MySQL клиенту, поскольку клиент итерирует
по результатам. Буферизированные результаты получены полностью библиотекой
клиента перед передачей их клиенту.
MySQL Native Driver использует PHP Streams для сетевой связи с
MySQL Server. Результаты, посланные MySQL, принесены от буферов сети PHP
Streams в буфер результата mysqlnd. Буфер результата сделан на zvals.
Во втором шаге результаты сделаны доступными для скрипта PHP.
Эта заключительная передача от буфера результата в переменные PHP влияет
на потребление памяти.
По умолчанию MySQL Native Driver пытается избежать хранить
буферизованные результаты дважды в памяти. Результаты сохранены только
однажды во внутренних буферах результата и zval.
Когда результаты будут получены в переменные скрипта PHP,
переменные сошлются на внутренние буферы результата. Результаты запроса базы
данных не скопированы и сохранены в памяти только однажды. Если пользователь
изменяет содержание переменной, содержащей результаты базы данных,
копирование при записи должно быть выполнено, чтобы избежать изменения
внутреннего буфера результата, на который ссылаются.
Содержание буфера не должно быть изменено, потому что пользователь может
решить прочитать набор результатов во второй раз.
Механизм копирования осуществляется, используя дополнительный справочный
список управления и счетчики ссылок zval.
Это должно быть также сделано, если пользователь читает набор результатов в
переменные PHP и освобождает набор результатов, прежде чем
переменные будут сброшены.
Вообще говоря, этот образец работает хорошо на скриптах, которые читают
набор результатов однажды и не изменяют переменные, содержащие результаты.
Его главный недостаток это издержки памяти, вызванные дополнительным
управлением ссылками, которое происходит, прежде всего, из-за того, что
пользовательские переменные, содержащие результаты, не могут быть полностью
освобождены, пока mysqlnd не прекращает ссылаться на них. MySQL Native driver
удаляет ссылку на пользовательские переменные, когда набор результатов
освобожден, или выполняется copy-write.
Наблюдатель будет видеть, что потребление общей памяти растет, пока набор
результатов не будет освобожден. Используйте
статистику, чтобы проверить,
освобождает ли скрипт действительно наборы результатов явно, или драйвер
делает неявные освобождения и таким образом память какое-то время
используется дольше, чем необходимо.
Статистические данные также помогают видеть, сколько произошло копий
на операциях записи.
Скрипт PHP, читая много маленьких строк буферизированного набора
результатов, используя фрагмент кода, равный или эквивалентный
while ($row = $res->fetch_assoc()) { ... } ,
может оптимизировать потребление памяти, прося копии вместо ссылок.
Хотя требование копий означает держать результаты дважды в памяти,
оно позволяет PHP освобождать копию, содержавшуюся в
$row когда набор результатов повторяется и до
освобождения самого набора результатов.
На нагруженном сервере, оптимизация пикового использования памяти может
помочь улучшению полной производительности системы,
хотя для отдельного скрипта подход копирования может привести к замедлению
из-за дополнительных ассигнований и операций копирования в памяти.
Способ копии может быть проведен в жизнь, установив
mysqlnd.fetch_data_copy=1.
Контроль и отладка
Есть многократные способы отследить использование памяти MySQL
Native Driver. Если цель состоит в том, чтобы получить быстрый обзор высокого
уровня или проверить эффективность памяти скриптов PHP, проверьте
статистику, собранную
библиотекой. Статистические данные позволяют вам, например, ловить
SQL-операторы, которые производят больше результатов, чем
обрабатывается скриптом PHP.
Трассировка отладки
может формироваться, чтобы сделать запись управления памятью.
Это помогает видеть, когда память ассигнуется или освобождается.
Однако размер требуемых кусков памяти не может быть перечислен.
Некоторые последние версии MySQL Native Driver
показывают эмуляцию случайных ситуаций с памятью.
Эта особенность предназначается, чтобы использоваться разработчиками
библиотеки C или mysqlnd
plugin.
Пожалуйста, ищите исходный код соответствующих параметров конфигурации PHP
и более подробную информацию. Особенность считают частной и могут изменить в
любое время без предшествующего уведомления.
7.9.
MySQL Native Driver Plugin API
MySQL Native Driver Plugin API является особенностью MySQL Native
Driver или mysqlnd .
Плагины Mysqlnd работают в слое между запросами
PHP и сервером MySQL. Это сопоставимо с MySQL Proxy. MySQL Proxy
работает в слое между любым клиентским приложением MySQL, например, запросом
PHP и сервером MySQL. Плагины Mysqlnd
могут предпринять типичные задачи MySQL Proxy, такие как выравнивание
нагрузки, контроль и исполнительная оптимизация.
Из-за различной архитектуры и местоположения, у плагинов
mysqlnd нет некоторых недостатков MySQL Proxy.
Например, у плагинов нет никакого единственного пункта сбоя, никакого
выделенного прокси-сервера и никакого нового языка программирования.
Плагин mysqlnd может считаться расширением
mysqlnd . Плагины могут перехватить большинство
функций mysqlnd . Функции
mysqlnd вызваны расширениями PHP MySQL, такими
как ext/mysql ,
ext/mysqli и
PDO_MYSQL .
В результате возможно для плагина mysqlnd
перехватить все вызовы, сделанные к этим расширениям
из клиентского приложения.
Внутренние вызовы функций mysqlnd
могут также быть перехвачены или заменены. Нет никаких ограничений на
управление внутренними таблицами функций mysqlnd .
Возможно настроить вещи так, чтобы, когда функции
mysqlnd вызваны расширениями, то использовался
mysqlnd , если вызов направлен к соответствующей
функции в mysqlnd . Способность управлять
внутренними таблицами функций mysqlnd
таким образом позволяют максимальную гибкость для плагинов.
Плагины Mysqlnd на самом деле расширения PHP,
написанные на C, они используют mysqlnd plugin
API (который встроен в MySQL Native Driver,
mysqlnd ). Плагины могут быть сделаны 100%
очевидными для запросов PHP. Никакие изменения приложений не необходимы,
потому что плагины воздействуют на другой слой. Плагин
mysqlnd может считаться работающим в слое ниже
mysqlnd .
Следующий список представляет некоторые возможные применения плагинов
mysqlnd .
Выравнивание нагрузки.
Контроль.
Производительность.
Кэширование. Пример этого: расширение
PECL/mysqlnd_qc (Query Cache).
Разделение. Пример этого: расширение PECL/mysqlnd_mc (Multi Connect).
Это расширение попытается разделить оператор
SELECT на n частей, применяя SELECT ... LIMIT part_1, SELECT LIMIT part_n.
Это посылает запросы различным серверам MySQL и сливает результат в клиенте.
Доступные плагины MySQL Native Driver
Есть много уже доступных плагинов mysqlnd. Они включают:
PECL/mysqlnd_mc
- Multi Connect.
PECL/mysqlnd_ms
- Master Slave.
PECL/mysqlnd_qc
- Query Cache.
PECL/mysqlnd_pscache
- Prepared Statement Handle Cache.
PECL/mysqlnd_sip
- SQL Injection Protection.
PECL/mysqlnd_uh
- User Handler.
7.9.1.
Сравнение плагинов mysqlnd с MySQL Proxy
Плагины Mysqlnd и MySQL Proxy это
различные технологии, использующие разные подходы. Обе это хорошие
инструменты для решения множества общих задач, таких как выравнивание
нагрузки, контроль и улучшения производительности.
Важное различие: MySQL Proxy работает со всеми клиентами MySQL, тогда как
плагины mysqlnd определены для запросов PHP.
Как PHP Extension, плагин mysqlnd
устанавливается на сервере приложений PHP, вместе с остальной частью PHP.
MySQL Proxy можно управлять на сервере приложений PHP или можно установить на
выделенной машине, чтобы обращаться с многими серверами приложений PHP.
У развертывания MySQL Proxy на сервере приложений есть два преимущества:
Никакого единственного пункта сбоя.
Легко масштабировать систему.
MySQL Proxy (и плагины mysqlnd )
может легко решить проблемы, которые иначе потребовали бы
изменений существующих приложений.
Но у MySQL Proxy есть некоторые недостатки:
MySQL Proxy может быть настроен программированием на C и Lua.
Lua предпочтительный язык MySQL Proxy. Для большинства экспертов PHP
Lua новый язык. Плагин mysqlnd
может быть написан на C. Также возможно написать плагины на PHP, используя
PECL/mysqlnd_uh.
MySQL Proxy работает как демон, фоновый процесс. MySQL Proxy
может вспомнить более ранние решения, поскольку все состояние
может быть сохранено. Однако, плагин mysqlnd
связан с основанным на запросе жизненным циклом PHP. MySQL Proxy может также
разделить одноразовые вычисленные результаты среди многократных серверов
приложений. Плагин mysqlnd
должен был бы хранить данные в постоянной среде, чтобы быть в состоянии
сделать это. Другой демон должен был бы использоваться с этой целью,
например, Memcache. Это дает MySQL Proxy преимущество в этом случае.
MySQL Proxy работает поверх проводного протокола. С MySQL Proxy
необходимо разобрать и перепроектировать протокол MySQL Client Server.
Действия ограничиваются теми, которые могут быть достигнуты, управляя
протоколом связи. Если проводной протокол изменяется (что происходит очень
редко), скрипты MySQL Proxy должны были бы быть изменены также.
Плагины Mysqlnd работают поверх C API,
который отражает libmysqlclient .
C API в основном обертка вокруг протокола MySQL Client Server
или проводного протокола, как это иногда называют.
Можно перехватить все вызовы C API. PHP использует C API, поэтому можно
зацепить все вызовы PHP без потребности программировать на
уровне проводного протокола.
Mysqlnd осуществляет проводной протокол.
Плагины могут поэтому разобрать, перепроектировать, управлять и даже заменить
протокол связи. Однако, это обычно не требуется.
Поскольку плагины позволяют вам создавать внедрения, которые используют
два уровня (C API и проводной протокол), у них есть большая гибкость, чем у
MySQL Proxy. Если плагин mysqlnd
осуществляется, используя API C, любые последующие изменения проводного
протокола не требуют изменений самого плагина.
7.9.2. Получение mysqlnd plugin API
mysqlnd plugin API просто часть
PHP-расширения MySQL Native Driver, ext/mysqlnd .
Это развито как часть хранилища исходного текста PHP и доступна
общественности через Git или посредством загрузки снимка исходных текстов.
Следующая таблица показывает версии PHP и соответствующие версии
mysqlnd .
Таблица 7.8. Связанная версия mysqlnd в выпуске PHP
PHP Version |
MySQL Native Driver |
5.3.0 | 5.0.5 |
5.3.1 | 5.0.5 |
5.3.2 | 5.0.7 |
5.3.3 | 5.0.7 |
5.3.4 | 5.0.7 |
Разработчики плагинов могут определить версию
mysqlnd посредством доступа
к MYSQLND_VERSION ,
которая является последовательностью формата
mysqlnd 5.0.7-dev - 091210 - $Revision: 300535
или через MYSQLND_VERSION_ID ,
который является целым числом, например, 50007.
Разработчики могут вычислить номер версии следующим образом:
Таблица 7.9. Таблица расчета MYSQLND_VERSION_ID
Version (часть) |
Пример |
Major*10000 | 5*10000 = 50000 |
Minor*100 | 0*100 = 0 |
Patch | 7 = 7 |
MYSQLND_VERSION_ID |
50007 |
Во время развития разработчики должны обратиться к номеру версии
mysqlnd для совместимости и тестов версий, так
как несколько итераций mysqlnd
могло произойти в течение разработки PHP с единственным номером версии PHP.
7.9.3.
Архитектура MySQL Native Driver Plugin
Эта секция предоставляет обзор архитектуры
mysqlnd .
Обзор MySQL Native Driver
Перед разработкой плагина mysqlnd
полезно знать, как устроен mysqlnd .
Mysqlnd состоит из следующих модулей:
Таблица 7.10. Модульная структура mysqlnd
Статистика |
mysqlnd_statistics.c |
Связь | mysqlnd.c |
Набор результатов | mysqlnd_result.c |
Метаданные набора результатов |
mysqlnd_result_meta.c |
Запрос | mysqlnd_ps.c |
Сеть | mysqlnd_net.c |
Проводной протокол |
mysqlnd_wireprotocol.c |
Объектно-ориентированная парадигма C
На кодовом уровне mysqlnd
использует образец C для осуществления ориентации объекта.
В C вы используете struct , чтобы
представлять объект. Члены структуры представляют свойства объектов.
Участники структуры, указывающие на функции, представляют методы.
В отличие от этого, с другими языками, такими как C++ или Ява, нет никаких
закрепленных правил о наследовании в объектно-ориентированной парадигме C.
Однако, есть некоторые соглашения, которые должны выполняться.
Жизненный цикл PHP
Рассматривая жизненный цикл PHP, есть два основных цикла:
Запуск и завершение PHP.
Цикл запроса.
Когда PHP запускается, он вызовет инициализацию модуля
(MINIT) каждого зарегистрированного расширения. Это позволяет каждому модулю
установить переменные и ассигновать ресурсы, которые будут существовать все
время работы PHP. При завершении работы PHP, он вызовет закрытие модуля
(MSHUTDOWN) для каждого расширения.
В течение работы PHP это получит много запросов. Каждый запрос составляет
другой жизненный цикл. По каждому запросу PHP вызовет функцию инициализации
запроса каждого расширения. Расширение может выполнить любую установку
переменных и распределение ресурсов, требуемое для обработки запросов.
Поскольку цикл запроса заканчивает закрытие запроса (RSHUTDOWN)
каждого расширения, таким образом, расширение может выполнить
любую требуемую очистку.
Как работает плагин
Плагин mysqlnd работает перехватывая вызовы
mysqlnd , сделанные к расширению
mysqlnd . Это достигается, получая таблицу
функций mysqlnd , резервируя ее и заменяя
своей таблицей функций, которая вызывает функции плагина как требуется.
Следующий код показывает, как таблица функций
mysqlnd заменяется:
/* a place to store original function table */
struct st_mysqlnd_conn_methods org_methods;
void minit_register_hooks(TSRMLS_D)
{
/* active function table */
struct st_mysqlnd_conn_methods * current_methods
= mysqlnd_conn_get_methods();
/* backup original function table */
memcpy(&org_methods, current_methods,
sizeof(struct st_mysqlnd_conn_methods);
/* install new methods */
current_methods->query = MYSQLND_METHOD(my_conn_class, query);
}
Манипуляции таблицы функции связи должны быть сделаны во время
инициализации модуля (MINIT). Таблица функций это глобальный совместно
используемый ресурс. В многопоточной окружающей среде с TSRM
манипуляция глобальным совместно используемым ресурсом во время обработки
запросов почти наверняка приведет к конфликтам.
Не используйте логику фиксированного размера, управляя таблицей функций
mysqlnd : новые методы могут быть добавлены в
конце таблицы функций. Таблица функций может измениться в
любое время в будущем.
Запрос родительских методов
Если оригинальные записи таблицы функций поддерживаются, все еще возможно
вызвать оригинальные записи таблицы функций, родительские методы.
В некоторых случаях, например,
Connection::stmt_init() ,
жизненно важно вызвать родительский метод до любой другой
деятельности в полученном методе.
MYSQLND_METHOD(my_conn_class, query)(MYSQLND *conn,
const char *query, unsigned int query_len TSRMLS_DC)
{
php_printf("my_conn_class::query(query = %s)\n", query);
query = "SELECT 'query rewritten' FROM DUAL";
query_len = strlen(query);
return org_methods.query(conn, query, query_len);
/* return with call to parent */
}
Распространение свойств
Объект mysqlnd представляется структурой C.
Невозможно добавить участника к структуре C во время выполнения. Пользователи
объектов mysqlnd
не могут просто добавить свойства к объектам.
Произвольные данные (свойства) могут быть добавлены к объектам
mysqlnd , используя соответствующую функцию
mysqlnd_plugin_get_plugin_<object>_data() .
Ассигнуя объект mysqlnd , делают интервалы в
конце объекта для хранения указателя void *
на произвольные данные. mysqlnd делает интервал
для одного указателя void * на плагин.
Следующая таблица показывает, как вычислить положение указателя
для определенного плагина:
Таблица 7.11. Расчет указателя для mysqlnd
Адрес памяти |
Контент |
0 |
Начало структуры объекта C mysqlnd. |
n |
Конец структуры объекта C mysqlnd. |
n + (m x sizeof(void*)) |
void* к данным объектов плагина m. |
Если вы планируете подклассифицировать какой-либо из конструкторов объекта
mysqlnd , необходимо иметь это в виду!
Следующий код показывает расширение свойств:
/* any data we want to associate */
typedef struct my_conn_properties {
unsigned long query_counter;
} MY_CONN_PROPERTIES;
/* plugin id */
unsigned int my_plugin_id;
void minit_register_hooks(TSRMLS_D) {
/* obtain unique plugin ID */
my_plugin_id = mysqlnd_plugin_register();
/* snip - see Extending Connection: methods */
}
static MY_CONN_PROPERTIES** get_conn_properties(const MYSQLND *conn TSRMLS_DC)
{
MY_CONN_PROPERTIES** props;
props = (MY_CONN_PROPERTIES**)mysqlnd_plugin_get_plugin_connection_data(
conn, my_plugin_id);
if (!props || !(*props))
{
*props = mnd_pecalloc(1, sizeof(MY_CONN_PROPERTIES), conn->persistent);
(*props)->query_counter = 0;
}
return props;
}
Разработчик ответственен за управление памятью данных.
Использование распределителя памяти mysqlnd
рекомендуют для данных. Эти функции вызывают, используя соглашение:
mnd_*loc() . У распределителя
mysqlnd есть некоторые полезные особенности,
такие как способность использовать распределитель
отладки в неотладочной сборке.
Таблица 7.12. Когда и как подклассифицировать
|
Когда подклассифицировать? |
У каждого экземпляра есть своя
собственная таблица функций? |
Как подклассифицировать? |
Connection (MYSQLND) | MINIT |
Нет | mysqlnd_conn_get_methods() |
Resultset (MYSQLND_RES) |
MINIT или позже. | Да |
mysqlnd_result_get_methods() или работа с таблицами
функций метода объекта. |
Resultset Meta (MYSQLND_RES_METADATA) |
MINIT | Нет |
mysqlnd_result_metadata_get_methods() |
Statement (MYSQLND_STMT) |
MINIT | Нет |
mysqlnd_stmt_get_methods() |
Network (MYSQLND_NET) |
MINIT или позже. | Да |
mysqlnd_net_get_methods() или работа с таблицами
функций метода объекта. |
Wire protocol (MYSQLND_PROTOCOL) |
MINIT или позже. | Да |
mysqlnd_protocol_get_methods() или работа с таблицами
функций метода объекта. |
Вы не должны управлять таблицами функций никогда позже, чем MINIT, если
это не позволено, согласно вышеупомянутой таблице.
Некоторые классы содержат указатель на таблицу функций метода.
Все экземпляры такого класса разделяют ту же самую таблицу функций.
Чтобы избежать хаоса, в особенности в переплетенной среде, такими таблицами
функций нужно управлять только во время MINIT.
Другие классы используют копии глобальной общей таблицы функций.
Копия таблицы функций класса создается вместе с объектом. Каждый объект
использует свою собственную таблицу функций. Это дает вам два варианта: можно
управлять таблицей функций по умолчанию объекта в MINIT,
и можно дополнительно усовершенствовать методы объекта, не влияя на другие
экземпляры того же самого класса.
Преимущество общего подхода таблицы функции: производительность.
Нет никакой потребности копировать таблицу функций для каждого объекта.
Таблица 7.13. Статус конструктора
Тип |
Распределение, создание, перезагрузка |
Можно модифицировать? |
Caller |
Connection (MYSQLND) |
mysqlnd_init() | Нет | mysqlnd_connect() |
Resultset(MYSQLND_RES) |
Распределение:
Перезагрузка и повторная инициализация во время:
Result::use_result()
Result::store_result
|
Да, но родитель должен быть вызван! |
Connection::list_fields()
Statement::get_result()
Statement::prepare() (только Metadata)
Statement::resultMetaData()
|
Resultset Meta (MYSQLND_RES_METADATA) |
Connection::result_meta_init() |
Да, но родитель должен быть вызван! |
Result::read_result_metadata() |
Statement (MYSQLND_STMT) |
Connection::stmt_init() |
Да, но родитель должен быть вызван! |
Connection::stmt_init() |
Network (MYSQLND_NET) |
mysqlnd_net_init() | Нет |
Connection::init() |
Wire protocol (MYSQLND_PROTOCOL) |
mysqlnd_protocol_init() | Нет |
Connection::init() |
Сильно рекомендуется, чтобы вы действительно не
полностью заменили конструктор. Конструкторы выполняют выделения памяти.
Выделения памяти жизненно важны для mysqlnd
plugin API и логики объекта mysqlnd .
Если вы не заботитесь о предупреждениях и настаиваете на том, чтобы
менять конструктор, необходимо, по крайней мере, вызвать родительский
конструктор прежде, чем сделать что-либо в своем конструкторе.
Независимо от всех предупреждений это может быть полезно
для конструкторов подкласса. Конструкторы это прекрасное место для изменения
таблиц функций объектов с таблицами необщего объекта, такими как Resultset,
Network, Wire Protocol.
Таблица 7.14. Статус деструктора
Тип |
Полученный метод должен вызвать родителя? |
Destructor |
Connection |
Да, после выполнения метода. |
free_contents(), end_psession() |
Resultset |
Да, после выполнения метода. |
free_result() |
Resultset Meta |
Да, после выполнения метода. |
free() |
Statement |
Да, после выполнения метода. |
dtor(), free_stmt_content() |
Network |
Да, после выполнения метода. |
free() |
Wire protocol |
Да, после выполнения метода. |
free() |
Деструкторы это соответствующее место, чтобы освободить свойства,
mysqlnd_plugin_get_plugin_
<object> _data() .
Перечисленные деструкторы могут не быть эквивалентны фактическому методу
mysqlnd , освобождая сам объект. Однако они самое
лучшее место для вас, чтобы освободить ваши данные. Как с конструкторами,
можно заменить методы полностью, но это не рекомендуется. Если многочисленные
методы будут перечислены в вышеупомянутой таблице, то необходимо будет
зацепить все перечисленные методы и освободить данные в том методе, который
вызывает первым mysqlnd .
Рекомендуемый метод для плагинов должен просто перехватить методы,
освободить вашу память и немедленно вызвать родительскую
реализацию после этого.
Из-за ошибки в версиях PHP 5.3.0 и 5.3.3 плагины не связывают
данные с постоянной связью. Это потому, что
ext/mysql и
ext/mysqli
не вызывают все необходимые вызовы метода
mysqlnd
end_psession() и плагины могут поэтому
пропустить память. Это было исправлено в PHP 5.3.4.
7.9.4.
mysqlnd plugin API
Ниже представлен список функций, обеспеченных в
mysqlnd plugin API:
mysqlnd_plugin_register()
mysqlnd_plugin_count()
mysqlnd_plugin_get_plugin_connection_data()
mysqlnd_plugin_get_plugin_result_data()
mysqlnd_plugin_get_plugin_stmt_data()
mysqlnd_plugin_get_plugin_net_data()
mysqlnd_plugin_get_plugin_protocol_data()
mysqlnd_conn_get_methods()
mysqlnd_result_get_methods()
mysqlnd_result_meta_get_methods()
mysqlnd_stmt_get_methods()
mysqlnd_net_get_methods()
mysqlnd_protocol_get_methods()
Нет никакого формального определения того, что такое плагин и как
работает его механизм.
Компоненты, часто находимые в механизмах плагинов:
Понятие плагина mysqlnd использует эти
особенности и дополнительно обладает открытой архитектурой.
Отсутствие ограничений
У плагина есть полный доступ к внутренним работам
mysqlnd . Нет никаких ограничений или пределов
безопасности. Все может быть переписано, чтобы осуществить дружественные или
враждебные алгоритмы. Рекомендуется, чтобы вы развернули плагины только
от надежного источника.
Как обсуждено ранее, плагины могут использовать указатели свободно.
Эти указатели не ограничиваются ни в каком случае и могут указать в данные
другого плагина. Простая арифметика может использоваться, чтобы прочитать
данные другого плагина.
Рекомендуется, чтобы вы всегда вызывали родительский метод. Плагины должны
всегда сотрудничать с mysqlnd самостоятельно.
Таблица 7.15. Проблемы: пример
формирования цепочки и сотрудничества
Расширение |
Указатель mysqlnd.query() |
Стек вызовов, вызывая родителя |
ext/mysqlnd |
mysqlnd.query() | mysqlnd.query |
ext/mysqlnd_cache | mysqlnd_cache.query() |
mysqlnd_cache.query()
mysqlnd.query
|
ext/mysqlnd_monitor |
mysqlnd_monitor.query() |
mysqlnd_monitor.query()
mysqlnd_cache.query()
mysqlnd.query
|
Здесь кэш (ext/mysqlnd_cache )
и монитор (ext/mysqlnd_monitor ) загружены.
Оба имеют подкласс Connection::query() .
Регистрация плагина происходит в MINIT ,
с использованием логики, показанной ранее. PHP вызывает расширения в
алфавитном порядке по умолчанию. Плагины не знают друг о друге и не
устанавливают дополнительные зависимости.
По умолчанию плагины вызывают родительскую реализацию метода запроса в их
полученной версии метода.
Резюме расширения PHP
Это резюме того, что происходит, используя плагин в качестве примера,
ext/mysqlnd_plugin , который выставляет
mysqlnd C plugin API в PHP:
Любое приложение PHP MySQL пытается установить связь с
192.168.2.29.
Приложение PHP будет использовать
ext/mysql ,
ext/mysqli или
PDO_MYSQL . Все три расширения PHP MySQL
применяют mysqlnd , чтобы установить связь с
192.168.2.29.
Mysqlnd вызывает метод connect, который
был подклассифицирован ext/mysqlnd_plugin
.
ext/mysqlnd_plugin вызывает перехватчик
пространства пользователя proxy::connect() ,
зарегистрированный пользователем.
Перехватчик пространства пользователя изменяет хост связи IP с
192.168.2.29 на 127.0.0.1 и возвращает связь, установленную
parent::connect() .
ext/mysqlnd_plugin выполняет эквивалент
parent::connect(127.0.0.1) , вызывая изначальный
метод mysqlnd для установления связи.
ext/mysqlnd устанавливает связь и
возвращается к ext/mysqlnd_plugin .
ext/mysqlnd_plugin тоже возвращается.
Независимо от того, какое расширение PHP MySQL использовалось,
приложение получает связь с 127.0.0.1. Само расширение PHP MySQL
возвращается к применению PHP. Круг закрывается.
7.9.5.
Введение в написание плагинов mysqlnd
Важно помнить, что плагин mysqlnd это
самостоятельное расширение PHP.
Следующий код показывает базовую структуру функции MINIT,
которая будет использоваться в типичном плагине
mysqlnd :
/* my_php_mysqlnd_plugin.c */
static PHP_MINIT_FUNCTION(mysqlnd_plugin)
{
/* globals, ini entries, resources, classes */
/* register mysqlnd plugin */
mysqlnd_plugin_id = mysqlnd_plugin_register();
conn_m = mysqlnd_get_conn_methods();
memcpy(org_conn_m, conn_m, sizeof(struct st_mysqlnd_conn_methods));
conn_m->query = MYSQLND_METHOD(mysqlnd_plugin_conn, query);
conn_m->connect = MYSQLND_METHOD(mysqlnd_plugin_conn, connect);
}
/* my_mysqlnd_plugin.c */
enum_func_status MYSQLND_METHOD(mysqlnd_plugin_conn, query)(/* ... */)
{
/* ... */
}
enum_func_status MYSQLND_METHOD(mysqlnd_plugin_conn, connect)(/* ... */)
{
/* ... */
}
Анализ задач: от C до пространства пользователя
class proxy extends mysqlnd_plugin_connection
{
public function connect($host, ...) { .. }
}
mysqlnd_plugin_set_conn_proxy(new proxy());
Процесс:
PHP: пользователь регистрирует отзыв плагина.
PHP: пользователь вызывает любой PHP MySQL API,
чтобы соединиться с MySQL.
C: ext/*mysql* вызывает метод mysqlnd.
C: mysqlnd заканчивается в ext/mysqlnd_plugin.
C: ext/mysqlnd_plugin
Вызывает отзыв пространства пользователя.
Или оригинальный метод mysqlnd ,
если отзыв пространства пользователя не задан.
Необходимо выполнить следующее:
Написать на С класс "mysqlnd_plugin_connection".
Принять и зарегистрировать объект прокси через
"mysqlnd_plugin_set_conn_proxy()".
Вызвать методы прокси пространства пользователя из C
(оптимизация: zend_interfaces.h).
Методы объекта пространства пользователя можно вызвать, используя
call_user_function()
или можно действовать на уровне ближе к Zend Engine и использовать
zend_call_method() .
Оптимизация: вызов методов из C, используя
zend_call_method
Следующий фрагмент кода показывает прототип для функции
zend_call_method , взятый из
zend_interfaces.h .
ZEND_API zval* zend_call_method(zval **object_pp, zend_class_entry *obj_ce,
zend_function **fn_proxy,
char *function_name, int function_name_len,
zval **retval_ptr_ptr, int param_count,
zval* arg1, zval* arg2 TSRMLS_DC);
Zend API поддерживает только два аргумента. Вам, возможно,
понадобится больше, например:
enum_func_status (*func_mysqlnd_conn__connect)
(MYSQLND *conn, const char *host,
const char * user, const char * passwd,
unsigned int passwd_len, const char * db,
unsigned int db_len, unsigned int port,
const char * socket, unsigned int mysql_flags TSRMLS_DC);
Чтобы обойти эту проблему, необходимо будет сделать копию
zend_call_method()
и добавить средство для дополнительных параметров. Можно сделать это,
создав макрос MY_ZEND_CALL_METHOD_WRAPPER .
Запрос пространства пользователя PHP
Этот фрагмент кода показывает оптимизированный метод для того, чтобы
вызвать функцию пространства пользователя из C:
/* my_mysqlnd_plugin.c */
MYSQLND_METHOD(my_conn_class,connect) (MYSQLND *conn, const char *host
/* ... */ TSRMLS_DC)
{
enum_func_status ret = FAIL;
zval * global_user_conn_proxy = fetch_userspace_proxy();
if (global_user_conn_proxy)
{
/* call userspace proxy */
ret = MY_ZEND_CALL_METHOD_WRAPPER(global_user_conn_proxy, host, /*...*/);
} else {
/* or original mysqlnd method = do nothing, be transparent */
ret = org_methods.connect(conn, host, user, passwd,
passwd_len, db, db_len, port,
socket, mysql_flags TSRMLS_CC);
}
return ret;
}
Запрос пространства пользователя:
простые аргументы
/* my_mysqlnd_plugin.c */
MYSQLND_METHOD(my_conn_class,connect) (/* ... */, const char *host, /* ...*/)
{
/* ... */
if (global_user_conn_proxy)
{
/* ... */
zval* zv_host;
MAKE_STD_ZVAL(zv_host);
ZVAL_STRING(zv_host, host, 1);
MY_ZEND_CALL_METHOD_WRAPPER(global_user_conn_proxy, zv_retval, zv_host
/*, ...*/);
zval_ptr_dtor(&zv_host);
/* ... */
}
/* ... */
}
Запрос пространства пользователя:
структуры как аргументы
/* my_mysqlnd_plugin.c */
MYSQLND_METHOD(my_conn_class, connect) (MYSQLND *conn, /* ...*/)
{
/* ... */
if (global_user_conn_proxy)
{
/* ... */
zval* zv_conn;
ZEND_REGISTER_RESOURCE(zv_conn, (void *)conn, le_mysqlnd_plugin_conn);
MY_ZEND_CALL_METHOD_WRAPPER(global_user_conn_proxy, zv_retval, zv_conn,
zv_host /*, ...*/);
zval_ptr_dtor(&zv_conn);
/* ... */
}
/* ... */
}
Первый аргумент многих методов mysqlnd это
что-то из C. Например, первым аргументом метода connect() является указатель
на MYSQLND . Структура MYSQLND представляет
объект связи mysqlnd .
Указатель объекта связи mysqlnd может
сравниться со стандартным дескриптором файла I/O. Как стандартный дескриптор
файла I/O, объект связи mysqlnd должен быть
связан с пространством пользователя, используя тип переменной ресурса PHP.
Из C до пространства пользователя и назад
class proxy extends mysqlnd_plugin_connection
{
public function connect($conn, $host, ...)
{
/* "pre" hook */
printf("Connecting to host = '%s'\n", $host);
debug_print_backtrace();
return parent::connect($conn);
}
public function query($conn, $query)
{
/* "post" hook */
$ret = parent::query($conn, $query);
printf("Query = '%s'\n", $query);
return $ret;
}
}
mysqlnd_plugin_set_conn_proxy(new proxy());
Пользователи PHP должны быть в состоянии вызвать родительскую
реализацию переписанного метода.
В результате подклассификации возможно усовершенствовать только выбранные
методы, и вы можете иметь "pre" или "post" перехватчики.
Встроенный класс:
mysqlnd_plugin_connection::connect()
/*my_mysqlnd_plugin_classes.c */
PHP_METHOD("mysqlnd_plugin_connection", connect)
{
/* ... simplified! ... */
zval* mysqlnd_rsrc;
MYSQLND* conn;
char* host; int host_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs",
&mysqlnd_rsrc, &host, &host_len) == FAILURE)
{
RETURN_NULL();
}
ZEND_FETCH_RESOURCE(conn, MYSQLND* conn, &mysqlnd_rsrc, -1,
"Mysqlnd Connection", le_mysqlnd_plugin_conn);
if (PASS == org_methods.connect(conn, host, /* simplified! */ TSRMLS_CC))
RETVAL_TRUE;
else RETVAL_FALSE;
}
|
|