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

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 с приятными дополнениями данное решение рекомендуется.

Similar posts

Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 18

    +1
    Большое спасибо за статью — действительно полезная информация.
      +1
      Пожалуйста. Просто я не очень люблю, когда есть хорошее решение для чего-либо, и при этом невозможно найти даже мало-мальски толковый «Hello, world!» под него.
      • UFO just landed and posted this here
          +1
          Как раз для хранения логов HS больше подходит, если нет auto increment, а лог ведется по дате, допустим. Вставили быстро в лог и забыли. Читать и анализировать можно не HS, а обычными средствами mySQL. Перед чтением — сделали FLUSH TABLE. Инсерты самого mySQL необходимо использовать в случае, если есть какие-либо триггеры или auto increment-поле.

          Как показала практика, HS просто замечателен для быстрого копирования громадной части таблицы или разового циклического update большого количества записей на разные значения. И это при том, что изначально он расчитывался явно на insert'ы.
          • UFO just landed and posted this here
              0
              Есть 32+ миллиона записей. На основании switch (if) надо в каждую из них проставить type = вычисляемому в коде значению. Если использовать банальный UPDATE mySQL и при этом апдейтить запись даже по первичному ключу — на глаз (можно даже не считать микросекунды) HS рвет простой mySQL в тряпки.
              • UFO just landed and posted this here
                  0
                  А мне непонятно пока.
                  32 миллиона в цикле перебираются сначала select'ом, затем update на каждую?
                    0
                    Ну мы немного «поумничали» и выбирается селектом через HS по 1000 записей (пробовали обычные mySQL, но взгрустнулось), потом апдейтятся HS-ным же update и все это делает «вжжжжж».
            0
            Для логов лучше использовать специально заточенные под это инструменты. Например, Archive Storage Engine
            • UFO just landed and posted this here
            0
            Спасибо, в закладки. Вы ответили на часть моих вопросов =)
              0
              Пожадуйста. Ожидаешь от плагина эмуляцию базовых привычных функций, а получаешь очень интересные последствия. Я сейчас жду и ищу к реализации ActiveRecord для php-handlersocket, потому что, несмотря на свой велосипед, хочется понять, начали люди пользоваться этой штукой (HS) всерьез или нет.
                0
                начали еще в декабре прошлого года :)
                хорошее дополнение, на некоторые грабли несколько раз спотыкался,
                например с автоинкрементом.

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

                спасибо за качественные дополнения
                  0
                  О, в нашем полку ковыряющих HandlerSocket прибыло! Спасибо за статью, такие нюансы очень интересны. Предлагаю организовать группу в GGroups, где будем обсуждать HS и сопутствующие MyNoSQL технологии. Велкам:
                  groups.google.com/group/handler-socket-ru
                0
                попробовал и HS и memcache-innodb из девелоперской сборки.
                на key\value операциях скорость одинаковая, однако memcache интерфейс поудобнее, и есть некоторая надежда что в будущих сборках это будет в релизе.
                  0
                  Спасибо за информацию, буду иметь в виду. Все-таки при работе с HS до сих пор не покидает впечатление, что он получился случайно.
                  0
                  >innoDB — транзакционные таблицы, поэтому надо сообщить mySQL, что «все приехало»

                  Круто, можно транзакции для key-value делать в отличии от мемкэша

                  Only users with full accounts can post comments. Log in, please.