Полнотекстовый поиск в InnoDB

Привет, Хабрачитатель!
Полнотекстовый поиск данных в InnoDB – это известная головная боль многих разработчиков под MySQL / InnoDB. Для тех, кто не в курсе дела я объясню. В типе таблиц MyISAM есть полноценный полнотекстовый поиск данных, однако сама таблица исторически имеет ограничения, которые являются принципиальными в отдельных проектах. В более «продвинутом» типе таблиц InnoDB полнотекстового поиска нет. Вот и приходится мириться бедным разработчикам либо с ограничениями MyISAM, либо с отсутствием поиска в InnoDB. Я хочу рассказать о том, какие есть способы организовать полноценный поиск в InnoDB без магии и исключительно штатными средствами. Также будет интересно сравнить скоростные характеристики каждого способа.

Для примера возьмем небольшую таблицу с 10000 записями.

CREATE TABLE users(
id INT(11) NOT NULL AUTO_INCREMENT,
login VARCHAR(255) DEFAULT NULL,
`password` VARCHAR(255) DEFAULT NULL,
name VARCHAR(255) DEFAULT NULL,
surname VARCHAR(255) DEFAULT NULL,
email VARCHAR(255) NOT NULL,
country VARCHAR(255) DEFAULT NULL,
city VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (id)
)
ENGINE = INNODB


В этой таблице мы храним данные пользователей сайта. На самом сайте есть форма поиска пользователей, в которую можно ввести произвольный запрос вида «Толстой Ясная Поляна». Для обработки такого запроса поиск должен осуществляться сразу по нескольким полям. Нам нужен поиск для полей login, name, surname, city, country. Запрос может быть как одиночным словом (имя или город) или же в виде набора слов, разделенных пробелом. Проблема в том, что нам необходимо искать этот набор слов сразу по нескольким полям, что сложно сделать в InnoDB без использования дополнительных функций.

Есть несколько относительно простых способов полнотекстового поиска данных в InnoDB:
  1. С помощью таблицы-«зеркала» в MyISAM
  2. С помощью таблицы-«зеркала» в MyISAM с кэшированными данными
  3. С помощью таблицы из ключевых слов в MyISAM
  4. Разбора запроса и прямой поиск в InnoDB
  5. Использование сторонних решений

Рассмотрим каждый из них подробнее.

С помощью таблицы-«зеркала» в MyISAM


Первый предлагаемый способ заключается в создании дополнительной таблицы в MyISAM. Как известно MyISAM достаточно неплохо поддерживает полнотекстовый поиск и это можно использовать. В эту дополнительную таблицу будут копироваться все данные из основной таблицы (users). Синхронизация будет обеспечиваться за счет триггеров. В новой таблице добавим поля login, name, surname, city, country. Таким образом, мы создадим «зеркало» основной таблицы, и работать будем с ним. Для возможности полнотекстового поиска добавим туда FULLTEXT индекс по всем 5 полям вместе:

CREATE TABLE search(
id INT(11) DEFAULT NULL,
login VARCHAR(255) DEFAULT NULL,
name VARCHAR(255) DEFAULT NULL,
surname VARCHAR(255) DEFAULT NULL,
country VARCHAR(255) DEFAULT NULL,
city VARCHAR(255) DEFAULT NULL,
FULLTEXT INDEX IX_search (city, country, login, name, surname)
)
ENGINE = MYISAM


Для синхронизации данных между основной таблицей и таблицей-«зеркалом» на users установим триггеры на запись, изменение и чтение:

Триггер на запись:

CREATE 
TRIGGER `insert`
AFTER INSERT
ON users
FOR EACH ROW
BEGIN 
INSERT INTO search (`id`,`login`,`name`,`surname`,`country`,`city` ) VALUES(
NEW.`id`, 
NEW.`login`,
NEW.`name`,
NEW.`surname`, 
NEW.`country`,
NEW.`city` 
);
END


Триггер на изменение:

CREATE 
TRIGGER `update`
AFTER UPDATE
ON users
FOR EACH ROW
BEGIN 
DELETE FROM `search` WHERE `id`= NEW.`id`;
INSERT INTO `search` (`id`,`login`,`name`,`surname`,`country`,`city` ) VALUES(
NEW.`id`, 
NEW.`login`,
NEW.`name`,
NEW.`surname`, 
NEW.`country`,
NEW.`city` 
);
END


И простой триггер на удаление:

CREATE 
TRIGGER `delete`
AFTER DELETE
ON users
FOR EACH ROW
BEGIN
DELETE FROM `search` WHERE `id`= OLD.`id`;
END


Поиск осуществляется с помощью следующего запроса:

SELECT `users`.* FROM `users` 
INNER JOIN `search` 
ON `search`.`id` = `users`.`id` 
WHERE 
MATCH(`search`.city, `search`.country, `search`.login, `search`.name, `search`.surname) AGAINST (' Владимир Тупин Санкт-Петербург ' IN BOOLEAN MODE) >0
ORDER BY MATCH(`search`.city, `search`.country, `search`.login, `search`.name, `search`.surname) AGAINST (' Владимир Тупин Санкт-Петербург ' IN BOOLEAN MODE) DESC

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

Главный плюс такого подхода — это гибкость поиска за счет добавления дополнительных индексов и составления новых комбинаций поиска (страна+город или логин + имя + фамилия). Таким образом, мы можем свободно формировать новые наборы для поиска и правила релевантности.
Минусы этого способа (как и всех способов с созданием «зеркала») – это избыточное хранение данных. Поэтому его целесообразно использовать при небольших объемах данных как в нашем примере.

С помощью таблицы-«зеркала» в MyISAM с кэшированными данными


Второй способ также заключается в создании зеркала данных, однако здесь мы будем хранить данные только в одном поле. В поставленной задаче поиск осуществляется сразу по группе полей и мы попробуем объединить их в одно текстовое поле, разделив пробелами. Таким образом, целому набору данных в таблице users будет соответствовать одно единственное поле. Создадим таблицу search с двумя полями id и text. Id – будет соответствовать id основной таблицы (users), text – это наши «кэшированные» данные.

CREATE TABLE search(
  id INT(11) DEFAULT NULL,
  `text` TEXT DEFAULT NULL,
  FULLTEXT INDEX IX_search_text (`text`)
)
ENGINE = MYISAM


Синхронизация также осуществляется с помощью триггеров:

Добавление:

CREATE 
TRIGGER `insert`
AFTER INSERT
ON users
FOR EACH ROW
BEGIN
  INSERT INTO search (`id`, `text`) VALUES(NEW.`id`, 
    LOWER( 
      CONCAT_WS(' ', 
          NEW.`name`,
          NEW.`surname`, 
          NEW.`login`, 
          NEW.`country`, 
          NEW.`city`
      )
    )
  );
END


Изменение:

CREATE 
TRIGGER `update`
AFTER UPDATE
ON users
FOR EACH ROW
BEGIN
  DELETE FROM search WHERE `id` = NEW.`id`;
  INSERT INTO search (`id`, `text`) VALUES(NEW.`id`, 
    LOWER( 
      CONCAT_WS(' ', 
          NEW.`name`,
          NEW.`surname`, 
          NEW.`login`, 
          NEW.`country`, 
          NEW.`city`
      )
    )
  );
END CREATE 


Удаление:

TRIGGER `delete`
AFTER DELETE
ON users
FOR EACH ROW
BEGIN
  DELETE FROM search WHERE `id` = OLD.`id`;
END


Поисковый запрос выглядит так:

SELECT `users`.* FROM `users` 
INNER JOIN `search` 
ON `search`.`id` = `users`.`id`   
WHERE 
MATCH(`search`.`text`) AGAINST ('Владимир Тупин Санкт-Петербург' IN BOOLEAN MODE) >0
ORDER BY MATCH(`search`.`text`) AGAINST ('Владимир Тупин Санкт-Петербург' IN BOOLEAN MODE) DESC
 


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

С помощью таблицы из ключевых слов в MyISAM



Третий способ основан на создании списка «ключевых слов» — поисковых тегов. Ключевые слова – это поля в таблице users. Например, для пользователя с полями (id=2144; login= leo; name=Лев;surname=Толстой;city=’Ясная Поляна’;country=Россия;email=leo@tolstoy.ru;password=;) ключевыми словами будут («leo»; «Лев»; «Толстой»; «Ясная Поляна»; «Россия»). Все эти слова мы будем записывать в отдельную таблицу MyISAM, в которой будут два поля id и text. Id соответствует id основной таблицы (users). А text – это поле, в которое будут записываться ключевые слова-теги. Каждому пользователю из таблицы users будут соответствовать 5 записей в новой таблице search. Таким образом, мы получили таблицу тегов каждого пользователя.

CREATE TABLE search(
  id INT(11) DEFAULT NULL,
  `text` VARCHAR(255) DEFAULT NULL,
  FULLTEXT INDEX IX_search_text (`text`)
)
ENGINE = MYISAM


Синхронизация данных осуществляется также за счет триггеров:

Создание:

CREATE 
TRIGGER `insert`
AFTER INSERT
ON users
FOR EACH ROW
BEGIN
  INSERT INTO search (`id`,`text`) VALUES
    (NEW.`id`, NEW.`login`),
    (NEW.`id`, NEW.`name`),
    (NEW.`id`, NEW.`surname`), 
    (NEW.`id`, NEW.`country`),
    (NEW.`id`, NEW.`city`);
END


Изменение:

CREATE 
TRIGGER `update`
AFTER UPDATE
ON users
FOR EACH ROW
BEGIN
  DELETE FROM search WHERE `id` = NEW.`id`
  INSERT INTO search (`id`,`text`) VALUES
    (NEW.`id`, NEW.`login`),
    (NEW.`id`, NEW.`name`),
    (NEW.`id`, NEW.`surname`), 
    (NEW.`id`, NEW.`country`),
    (NEW.`id`, NEW.`city`);
END


Удаление:

CREATE 
TRIGGER `delete`
AFTER DELETE
ON users
FOR EACH ROW
BEGIN
  DELETE FROM search WHERE `id` = OLD.`id`
END


Поисковый запрос:

SELECT `users`.* FROM `users` 
INNER JOIN `search` 
ON `search`.`id` = `users`.`id`
WHERE
  MATCH(`search`.`text`) AGAINST(' Владимир Тупин Санкт-Петербург ' IN BOOLEAN MODE) > 0  
GROUP BY `search`.`id`
ORDER BY COUNT(*) DESC


Обратите внимание, что если раньше релевантность определялась встроенным механизмом поиска MyISAM, то в этом случае ее определяем сами. В результате поиска мы получили только те теги, которые соответствуют запросу. И чем больше тегов одного пользователя, тем выше он в выборке.
Приведенный пример имеет недостаток: при равном числе тегов у нескольких записей происходит естественная сортировка, что не всегда верно с точки зрения релевантности.
Однако у этого метода есть высокий потенциал для дальнейшего развития. Во-первых, мы можем добавить в сортировку ORDER BY сумму оценок релевантностей от запроса MATCH AGAINST. Тем самым указанный выше недостаток будет устранен. Во-вторых, мы можем добавить в эту таблицу дополнительное поле веса тега weight, и каждому полю основной таблицы поставить в соответствие значение этого веса. Таким образом, мы можем добавить сортировку с учетом значимости (веса) отдельных полей. Это дает нам возможность делать акцент на каких то полях без ухудшения качества поиска.

Разбора запроса и прямой поиск в InnoDB


Четвертый способ суров и не использует MyISAM как предыдущие. В нем также нет дополнительных таблиц и триггеров. Мы будем просто искать по существующей таблице. Для начала нам необходимо проиндексировать все поля, в которых будет осуществляться поиск.

CREATE TABLE users(
  id INT(11) NOT NULL,
  login VARCHAR(255) DEFAULT NULL,
  `password` VARCHAR(255) DEFAULT NULL,
  name VARCHAR(255) DEFAULT NULL,
  surname VARCHAR(255) DEFAULT NULL,
  email VARCHAR(255) NOT NULL,
  country VARCHAR(255) DEFAULT NULL,
  city VARCHAR(255) DEFAULT NULL,
  PRIMARY KEY (id),
  INDEX city (city),
  INDEX country (country),
  INDEX email (email),
  INDEX login (login),
  INDEX name (name),
  INDEX password (password),
  INDEX surname (surname)
)
ENGINE = INNODB


В InnoDB поиск можем осуществлять только с помощью оператора LIKE, но для его эффективной работы необходимо разбить запрос на слова, иначе запросы, состоящие из нескольких слов, останутся без результата. Для разбиения на слова и составления запроса напишем функцию:
CREATE 
FUNCTION search(str VARCHAR(255))
  RETURNS varchar(255) CHARSET cp1251
BEGIN
  DECLARE output VARCHAR(255) DEFAULT '';
  DECLARE temp_str VARCHAR(255);
  DECLARE first_part VARCHAR(255) DEFAULT "CONCAT_WS(' ',`name`,`surname`,`login`,`country`,`city`) LIKE '%";
  DECLARE last_part VARCHAR(255) DEFAULT "%'";
 
  WHILE LENGTH(str) != 0 DO    
    SET temp_str = SUBSTRING_INDEX (str, ' ', 1);
    IF temp_str = str
      THEN
        SET str = '';
      ELSE
       SET str = SUBSTRING(str, LENGTH(temp_str) + 2);
    END IF;
 
    IF output != ''
      THEN
        SET output = CONCAT(output, ' OR ');
    END IF;
 
    SET output = CONCAT(output, first_part, temp_str, last_part);
 
  END WHILE;
  RETURN output;
END


Функция возвращает нам фрагмент сформированного поискового запроса, который просто нужно подставить и выполнить:

SET @WHERE =  CONCAT('SELECT * FROM `users` WHERE ',  search ('Хабра Хабрович'));
PREPARE prepared FROM  @WHERE;
EXECUTE prepared;


Также можно использовать временные таблицы, они дадут ощутимое удобство при обработке результатов запроса.

Использование сторонних решений


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

Сравнение


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

Сравнение скорости выполнения поисковых запросов в базе данных MySQL в таблице InnoDB различными методами:



Подробнее:

Метод Средняя скорость выполнения одного запроса (сек.) Средняя скорость выполнения одного повторного запроса (сек.)
С помощью таблицы-«зеркала» в MyISAM 0.029738 0.011974
С помощью таблицы-«зеркала» в MyISAM с кэшированными данными 0.025652 0.012027
С помощью таблицы из ключевых слов в MyISAM 0.027876 0.008866
Разбора запроса и прямой поиск в InnoDB 0.136091 0.09541


Как и ожидалось, прямой LIKE поиск в InnoDB оказался самым медленным и существенно проигрывает всем остальным. Конечно этот способ еще можно оптимизировать, однако это вряд ли даст существенный выигрыш в скорости.
Три оставшихся метода поиска показали себя примерно на одном уровне. Как показала практика, при большом количестве одинаковых запросов ощутимое преимущество дает использование ключевых слов (тегов) в MyISAM. При большом количестве разнообразных поисковых запросов выигрыш дает второй способ – создание кэшированного зеркала. Если какие-то поля сильно отличаются по размеру от других(содержимое статьи, текст новости), то эффективнее показывает себя первый способ — создание таблицы-зеркала.

Создание MyISAM зеркал стоит применять для небольших таблиц (10-50 тыс записей в таблице), если записей в таблице больше, и позволяют технические возможности используйте сторонние механизмы (Sphinx, Apache Lucene).
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 55

    +2
    Спасибо за статью,
    Однозначно в избранное!
    • НЛО прилетело и опубликовало эту надпись здесь
        0
        Сфинкс использую, но что насчет интерграции? Каким образом они объединены?
        • НЛО прилетело и опубликовало эту надпись здесь
            0
            Аксенов на конференции говорил что недолюбливает этот способ использования (SphinxSE) ))
            • НЛО прилетело и опубликовало эту надпись здесь
                +1
                удобнее всего через sphinxql имхо

                sphinxse запросы корявенькие
                • НЛО прилетело и опубликовало эту надпись здесь
                    +1
                    дык можно sql_attr_string успешно делать начиная с какой-то версии
                    • НЛО прилетело и опубликовало эту надпись здесь
                        +1
                        наименее распространенный интерфейс (и через это наименее тестируемый соотв-но)

                        всякие новые интересные изменения строго в последнюю очередь

                        кривоватый синтаксис (причем afair спрямить концептуально нельзя)

                        но мы ж начали обсуждение с удобства, да? :)

                        вот имхо (имхо) удобнее всего в большинстве случае именно sphinxql

                        всем понятные запросы, через привычный mysql интерфейс, все привычно и наглядно
                        • НЛО прилетело и опубликовало эту надпись здесь
                          • НЛО прилетело и опубликовало эту надпись здесь
                              0
                              пишите, если што (в смысле баги или другие проблемы какие)
                            0
                            кстати, по поводу SphinxQL.

                            Насколько я понял, Sphinx реализует сервер MySQL 4?
                            Я просто из Erlang коннектился к сфинксу этим драйвером github.com/dizzyd/erlang-mysql-driver и получал кучу ошибок т.к. драйвер поддерживает только MySQL 5, пришлось долго разбираться.
                              +1
                              Все несколько затейливее. Мы поддерживаем протокол версии 10, который начиная от версии 4.1 и далее везде, включая 5.x. Ошибки бывают по двум причинам: 1) либо драйвер вместо флагов протокола разбирает еще и текстовый номер версии сервера, зачем-то пытается принимать всякие решения на ее основе, и сходит с ума (это чаще всего); 2) либо наша комбинация флагов оказывается для драйвера шибко неожиданной, и драйвер опять таки сходит с ума. Ну те. драйвера, скажем так, не всегда по одной только публичной спецификации работают и не во всех теоретически возможных случаях корректно ;)
            +2
            если кстати segfault-ы репортить в трекер, у нас появляются шансы их починить

            а если не репортить, не повляются

            такой дуализм
              0
              О, пользуясь случаем sphinxsearch.com/bugs/view.php?id=696 — зарепортил, но никто не заревьюил. Проблема все еще актуальна. Если искать по индексу триграмм слово короче 3-х символов, то зависает намертво. Проявляется только в 1.10, в предыдущей версии работало без сбоев.
                +1
                дык я ж не говорю — что мгновенно среагируем и сразу починим

                однако раз багрепорт есть — и нам есть, что проверять, когда руки дойдут

                по каждому (каждому) багрепорту рано или поздно работы ведутся
            +7
            Интересный костыль для добавления в innoDB функциональности, которая там не нужна.
            Для себя я решил давно и прочно, что если нужен поиск по базе, то его нужно делать НЕ средствами базы.
            Для мелких таблиц подход из статьи вполне применим, но если нужно искать по полутора гигабайтам, то увы.
            Любой полнотекстовый индекс будет весить никак не меньше половины данных.
            Как следствие — замедление поиска по мере накопления данных в таблице, блокировки, выход из буфферов и прочие нехорошие вещи.
            Абстрагируясь от вышеназванного, хотел бы покритиковать пару моментов. При беглом прочтении видно, что поиск по LIKE не использует индексов (поскольку данные из нескольких колонок конкатенируются вживую). Разумеется, такой запрос будет ужасно медленным. Также в триггерах не нравятся циклы (FOR EACH ROW) — дешевле делать синхронизацию через INSERT INTO mirror_table SELECT * FROM original_table WHERE original_table.id NOT IN (SELECT id FROM mirror_table) и аналогично удаление (обновление останется в цикле, но это обычно достаточно редкая операция).
              0
              > Любой полнотекстовый индекс будет весить никак не меньше половины данных.

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

              у меня навскидку сфинксом при hitless_words=all, stopwords=top100.txt получилось 31% от текста

              те. это индекс без позиций слов и с отрезанием top-100 стопов такой получился

              сильно зажатый индекс без позиций слов, говорят, до всего-то 7% от текста люди упихивали

              зачем он такой реально нужен, конечно, все равно не очень ясно :)
                0
                Мон пардон, имел в виду индекс в MySQL'е.
                Сфинкс — тема отдельная.
                  0
                  да я вообще про полнотекстовые индексы «в целом» — и чисто для информации

                  те. вот говорят, можно индекс ажно до 7% ужаться, а не 50% — любопытно же!!!
              +15
              Мне казалось что с появлением сфинкса проблема полнотекстового поиска ушла в небытие.
                +1
                >В типе таблиц MyISAM есть полноценный полнотекстовый поиск данных
                >полноценный
                O RLY?
                  +1
                  Спасибо, интересно.

                  По оформлению (извините, что придираюсь) — лучше вверху красивую картинку, а ниже цифры.
                    0
                    >> Существует ряд сторонних решений для полнотекстового поиска. Наиболее популярные платформы это Sphinx и проекты на базе Apache Lucene. Их использование лишено смысла при небольших объемах данных (таких как в нашем примере), а иногда просто невозможно в связи с ограничениями (хостер, злой админ, кривые руки и т. д.).

                    Да, ладно. А предположим у вас в текст в базе лежит словосочетание «красные конфеты». А пользователь на форме в сайте вводит «красная конфета». Как вы средствами MySQL будете обрабатывать эту ситуацию?
                      +2
                      Это как раз не сложно. Нужно подключить внешний морфологический движок и делать запрос в базу что-то типа — «красный красная красную… конфета конфеты конфету ...» Естественно необходимо правильно выставить весовые коефициенты
                        +3
                        Не тривиальное решение.

                        Не буду говорить за Сфинкс, но в Solr (lucene), это проблема без проблем. Поэтому не лучше ли не изобретать велосипед и использовать нормальный поисковый движок.
                          +1
                          эта проблема решается я хотел сказать
                            +1
                            У каждого решения есть свои плюсы и минусы.
                            Сфинкс хорошо безусловно, но не позволяет организовать поиск в реальном времени.
                            Lucene — решает проблему реального времени.
                            MySql Fulltext search — хорош тем, что не нужно ставить ничего дополнительного.
                              +1
                              MySql Fulltext search не является полноценным поиском без морфологического словаря и это есть проблема. Ибо статей подобных этой много. Но вот про морфологический словарь все забывают.
                              • НЛО прилетело и опубликовало эту надпись здесь
                                  0
                                  Realtime индексы убогие… Не поддерживают даже поиск по подстроке, стеммеры, морфологию и пр. Т.е. как ввел поисковое слово так его и будет искать. Нужно ручками реализовывать всю обработку (либо при индексировании прогнать текст через морфологическую либу либо при поиске запрос прогнать)
                                    0
                                    > стеммеры, морфологию и пр.

                                    я аж проснулся

                                    видимо если ее не включать в конфиге, то не поддерживают

                                    а если включать

                                    Z:\work\sphinx\sphinx>mysql -P9306
                                    Welcome to the MySQL monitor. Commands end with; or \g.
                                    Your MySQL connection id is 1
                                    Server version: 1.11-dev (r2691)

                                    mysql> insert into rt values (123,'running','',1);
                                    Query OK, 1 row affected (0.00 sec)

                                    mysql> select * from rt where match('run');
                                    +------+--------+------+
                                    | id | weight | gid |
                                    +------+--------+------+
                                    | 123 | 1500 | 1 |
                                    +------+--------+------+
                                    1 row in set (0.00 sec)
                                      0
                                      О блин… Я на конференции лично спрашивал, получил ответ что по подстроке не ищет в RT индексах. Потом немножко проверил сам и вроде тоже не смог по подстроке найти. В конце октября это было.
                                      Это работало с момента появления RT индексов (ну, с выходом 1.10 т.е.) или недавно появилось?
                                        0
                                        это морфология сработала — она есть (и почти вся остальная обработка текста тоже)

                                        подстрок пока нет — но будут
                                          0
                                          О как… Это хорошо. Приношу извинения.
                                            0
                                            да не за что

                                            фичей видимо много, а разработка не стоит на месте — и где какая сегодня поддерживается, запомнить тяжело :)

                        +2
                        Только sphinx. Все эти «встроенные поиски» даже рядом не стоят.
                          +3
                          Про триггера и вставку в MyISAM
                          Cтоит понимать, что транзакция на вставку в таблицу завершится тогда когда отработает триггер.
                          Триггер, разумеется, сумеет вставить в таблицу данные, и таблица будет залочена.
                          А вот паралельный запрос уже не сумеет вставить данные. Триггер будет ждать освобождения лока, а транзакция будет ждать триггер.

                          В общем при таком подходе теряется вся соль возможности паралельной вставки в InnoDB таблицу.
                            +2
                            А в Postgre кто нибудь работал с полнотекстовым индексом? (Мне не нужно, но просто интересно)
                              +1
                              Не поверите и тоже Sphinx
                                +1
                                Чего?
                              0
                              Синхронизация будет обеспечиваться за счет триггеров.

                              Лучше за счет репликации.
                                0
                                А в чем конкретно настолько продвинутее использовать основную таблицу в innodb, чтобы ради этого городить такой огород с зеркалами в myisam? Ну кроме транзакций, которые в небольших проектах и не особо нужны, атомарных операций myisam вполне достаточно. Ведь речь идет о небольшой проекте если правильно понял?
                                  0
                                  Приведенный пример несколько надуман. На деле эта самая таблица имеет куда больше полей. На проекте необходимо использование внешних ключей и транзакций, что недоступно в MyISAM
                                  0
                                  А кто что может сказать про качественные инфиксные индексаторы под запросы вида LIKE '%text%'?
                                    0
                                    Что насчет Zend Lucence?
                                      0
                                      Поскольку на пхп — жалкое и убогое поделие. Достаточно проиндексировать 10-20К документов, чтобы поиск начал занимать 2-3 секунды.
                                        +1
                                        Это же неголословно?
                                          +1
                                          Не голословно. Тестировал на массиве из 200К документов, самый простой булевый поиск занимал 30-40 секунд.
                                        0
                                        Отличная штука, она меня очень спасла. Использовал правда не Java версию, а зендовский модуль.
                                        У меня была проблема в том, что надо было искать по 8 таблицам, что очень не удобно. Надо писать свой костыль. А Zend Lucene быстро подключил.
                                        0
                                        Спасибо, отличная статья!
                                        Кармы не хватает, так бы однозначно плюсанул.

                                        Коллеги, я бы хотел осветить одну очень интересную «плюшку» MySQL, а именно использования xPath/XML-деревьев, которая доступна с версии 5.1. Испытал и внедрил в СMS на Zend Framework, название пока говорить не буду, планируется opensource. Получается эдакий аналог MongoDB и сравнительно шустрая скорость выборки. Есть пример работы с этим чудом на PHP. Но вот друзья, кармы не хватает. Я, конечно, не клянчу в открытую, если поможете — опубликую в ближайшую неделю, т.к я очень досконально изучил этот вопрос. Если нет, то опубликую в блоге и в посте по теме запощу линк в комментарии.
                                          0
                                          спасибо за статью. Отличная работа, осталось изложить все в ООП расширить ActiveRecord доп функциональностью и все будет пучком.

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

                                          Самое читаемое