Pull to refresh

Подводные камни при работе с php-handlersocket

Reading time 4 min
Views 4.6K
HandlerSocket — это noSQL-плагин для mySQL, позволяющий обращаться к базам данных в обход уровня SQL.

Данная статья предназначена для тех, кто успешно поставил HandlerSocket и php-handlersocket, а также столкнулся со скудным мануалом и странным поведением этого плагина для php.

Если вы впервые слышите о данном решении, то рекомендую предварительно ознакомиться со следующими материалами:
NoSQL в MySQL: разгон MySQL до 750 000 запросов в секунду
Первый опыт работы с Handler Socket & php_handlersocket
Некоторые тонкости Update & Insert в Handler Socket

При пристальном рассмотрении и знании глубинных недр mySQL, многие из вопросов достаточно наивны, но это именно те вопросы, которые озадачили меня за время разработки. При этом не всегда понятно, что из выявленных мной «фич» является следствием внутренней структуры mySQL, что – результатом работы тентаклей создателя HandlerSocket Yoshinori Matsunobu, а что, в свою очередь – кодом php-handlersocket.

Для иллюстрации примеров используется следующая таблица с исходными данными:

CREATE TABLE IF NOT EXISTS `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`country_id` int(11) NOT NULL,
`city_id` int(11) NOT NULL,
`language` varchar(2) NOT NULL,
`name` varchar(255) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
KEY `idx_name` (`name`),
KEY `idx_country_language` (`country_id`,`language`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=0;

INSERT INTO `test` (`id`, `country_id`, `city_id`, `language`, `name`, `created_at`) VALUES
(1, 1, 1, 'es', 'Terminator', '2011-07-02 00:00:00'),
(2, 1, 1, 'en', 'Flash Gordon’', '2011-07-02 01:00:00'),
(3, 3, 4, 'en', 'Batman', '2011-07-02 02:00:00'),
(4, 1, 2, 'jp', 'Godzilla', '2011-07-02 03:00:00'),
(5, 2, 8, 'es', 'Superman’, '2011-07-02 04:00:00');

И, разумеется, сами HandlerSocket’ы

$hsr = new HandlerSocket('localhost', 9998); // Для чтения
$hsw = new HandlerSocket('localhost', 9999); // Для записи

А теперь на минуту представим, что перед нами только севший за использование php-handlersocket джуниор и его более опытный товарищ.

Я выполнил executeInsert(), а в базе ничего не появилось!

Если ты используешь innoDB, то сделай FLUSH TABLE. innoDB — транзакционные таблицы, поэтому надо сообщить mySQL, что «все приехало». Разумеется, с myISAM подобных проблем нет.

А почему мое поле AUTO_INCREMENT всегда получает значение 0?

Считать auto_increment не входит в обязанности php-handlersocket. Но это не запрещает считать его самим, главное не забыть после окончания работы с php-handlersocket установить его в таблице с помощью ALTER TABLE SET auto_increment.

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

При использовании executeInsert() нельзя пропускать поля в openIndex(), но можно останавливаться на достигнутом, т.е. не указывать все поля в таблице до конца.

Не работает:

$hsw->openIndex(0, 'test_db', 'test', '', 'id,name');
$hsw->executeInsert(0, array(999, 'Green Lantern'));

Работает:

$hsw->openIndex(0, 'test_db', 'test', '', 'id,country_id,city_id,language,name');
$hsw->executeInsert(0, array(999, 2, 3, 'en', 'Green Lantern'));

Мне позарез надо выполнить «SELECT * FROM Customers»!

По умолчанию, если не указан параметр $limit, php-handlersocket возвращает лишь одну запись, соответвтующую заданным критериям. Для того, чтобы получить все записи из таблицы, независимо от критериев, можно попробовать следующее:

$hsr->openIndex(0, 'test_db', 'test', '', 'id,country_id,city_id,language,name,created_at');
$res = $hsr->executeSingle(0, '>', array(0), 9999999999);

Стоит, однако, помнить, что в $res вернется массив, который может быть очень большим, что может привести к непоправимым последствиям.

Мне жизненно необходима обратная сортировка по индексу!

Тогда тебе стоит на время стать индусом! Внимание, никогда не пытайся воспроизвести это в домашних условиях:

$hsr->openIndex(0, 'test_db’', 'test', '', 'id,country_id,city_id,language,name,created_at');
$res = $hsr->executeSingle(0, '<', array(9999999999));

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

$hsr->openIndex(0, 'test_db’', 'test', 'idx_name', 'id,country_id,city_id,language,name,created_at');
$res = $hsr->executeSingle(0, '<', array('ZZZZZZZZZ'));

Рекомендую относиться к данным «фичам» очень скептически.

Какая-то ерунда с $limit и $skip. $limit=3, $skip=0 возвращает первые 3 запиcи, а $limit=3, $skip=3 не возвращаeт вообще ничего!

Дело в том, что php-handlersocket считает, что $limit – это количество всех записей, которые должны быть выбраны, начиная с нулевой, а $skip – с какой по порядку записи необходимо возвращать результат. Т.е. использование значений параметров $limit=3, $skip=3 означает «эй, возьми мне всего 3 записи и верни мне те, которые после третьей», что приводит к возврату пустого массива. Для эмуляции «LIMIT 3, 3» необходимо использовать следующее:

$hsw->openIndex(0, 'db_test', 'test', '', 'id,country_id,city_id,language,name,created_at');
$r = $hsw->executeSingle(0, '>', array(0), 6, 3);

У меня не работает выборка по индексу, где два поля и одно из них является текстовым (idx_country_language)!

К сожалению, как показала практика, php-handlersocket не способен искать по индексам, содержащим текстовые поля или даты. Как вариант, можно посоветовать использовать тип поля ENUM, там где это возможно. При этом с выборкой по индексам на одно поле (текстовое или дату) php-handlersocket справляется замечательно.

Выводы

HandlerSocket + php-handlersocket являются на данный момент очень интересным, но все же костылем для mySQL. Переписать весь сайт на их использование не получится ни в коем случае, а вот для банального key-value-storage с приятными дополнениями данное решение рекомендуется.
Tags:
Hubs:
+46
Comments 18
Comments Comments 18

Articles