MySQL. Остановка выполнения sql-запроса через триггер

Базы данных 02.03.2010

Как приостановить выполнения SQL после триггера? То есть, при определенных условиях, описанных в триггере надо остановить выполнения SQL который и вызвал этот триггер.
Я размышлял и гуглил на эту тему, но единственное что у меня получилось, это выполнять ошибочный SQL-код, тем самым останавливать выполнение SQL кода, который выполнится после триггера.

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

Ну это все слова, а теперь покажу реализацию:

delimiter //
DROP TRIGGER IF EXISTS `customers_update_status`//
CREATE TRIGGER `customers_update_status` BEFORE UPDATE ON `customers` FOR EACH ROW BEGIN
    IF NEW.`status` < OLD.`status` THEN
        BEGIN
            INSERT INTO `customers` SET OLD.`status` = "STOP_SQL_QUERY";
        END;
    END IF;
END//
delimiter ;

Поле status имеет тип ENUM и у него нет значения STOP_SQL_QUERY, поэтому происходит ошибка и SQL-запрос идущий за триггером не выполняется. Это не корректное, но единственное найденное мной решение. Вообще, наверное еще лучше чтобы был не INSERT, а UPDATE. Тогда будет ошибка более корректна с виду.

зы. Кстати на официальной страничке CREATE TRIGGER в камментах приводится именно такой способ по остановке выполнения sql-запроса.

Sphinx. Для чего нужны дельта-индексы и как их готовить?

Базы данных 31.07.2009

sphinx-delta

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

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

Поэтому мы делаем два индекса:

  • Полный — индексируются все данные целиком (запускаем раз в сутки)
  • Дельта — индексируется только малая часть данных, добавленных в течении дня (запускаем каждые 5-10 минут)

Но как определять с какого момента индексировать данные в дельта-индексе?

Нам необходимо помнить крайний проиндексированный ид-записи из полного-индекса, и начинать индексировать данные только с него, все очень просто :)

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

1
2
3
4
CREATE TABLE `sphinx_delta_counter` (
    `index_name` ENUM( 'pyha_forum' ) NOT NULL,
    `last_post_id` INT UNSIGNED NOT NULL
) ENGINE = InnoDB;

Где,

  • «index_name» — имя индекса, например если у вас много индексов с разных таблиц (можно опустить, если у вас один индекс);
  • «last_post_id» — крайний номер записи для конкретного индекса.

Вставим для нашего индекса запись, чтобы потом можно было обновлять счетчик:

1
2
INSERT INTO `sphinx_delta_counter`
    SET `index_name` = 'pyha_forum', `last_post_id` = 0;

Вы конечно можете этот запрос и в индексе сфинкса использовать, предварительно переписав его на «on duplicate key» и добавив уникальный индекс на связку «index_name+last_post_id», однако я думаю это излишне.

Читать полностью »

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

Базы данных 28.07.2009

mysql-logo

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

Вот примеры запросов

Пробуем в лоб:

UPDATE `categories` SET `size` = (`count` / ((MAX(`count`) - MIN(`count`)) / 10));
ERROR 1111 (HY000): Invalid USE OF GROUP FUNCTION

Попробуем вложенный селект:

UPDATE `categories` SET `size` = (SELECT (`count` / ((MAX(`count`) - MIN(`count`)) / 10)) FROM `categories`);
ERROR 1093 (HY000): You can't specify target table 'categories' for update in FROM clause

Попробуем жоин:

UPDATE `categories` AS `c1`
JOIN `categories` AS `c2`
USING(`category_id`)
SET `c1`.`size` = (`c2`.`count` / ((MAX(`c2`.`count`) - MIN(`c2`.`count`)) / 10));

ERROR 1111 (HY000): Invalid USE OF GROUP FUNCTION

Читать полностью »

Установка и настройка Trac на FreeBSD

Базы данных, Инструменты, Операционные системы 20.07.2009

trac

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

Это даёт возможность использовать Trac в том числе и как веб-интерфейс для доступа к системе контроля версий subversion, а так же, через плагины, к Mercurial, git, Bazaar и другим. Trac написан на языке программирования python и в настоящее время распространяется по модифицированной лицензии BSD.

http://ru.wikipedia.org/wiki/Trac

Возможности

  • Возможность просмотра всех изменений в svn и trac-проекте.
  • Можно создавать подпроекты, например для портала это будет «Разработать сервис фотографий», «Разработка форума» или «Реконструкция поискового-модуля». И для каждого будут отдельные группы тикетов.
  • Просмотреть изменения кодов проекта в svn-ревизиях и сравнивание их.
  • Создание, просмотр и закрытие тикетов.
  • Управление пользователями, участвующие в разработке.
  • Wiki-движок, с помощью которого можно создавать как справочную информацию, так и документацию по проекту в целом.

Так же имеется куча плагинов для Trac, с помощью которых вы легко расширите функционал!

Установка

Для развертывания Trac нам понадобится:

  • Apache 2.2 — но вы можете так же развернуть и на Apache 1.3 или на Nginx, к примеру
  • mod_python3 — это для Apache 2, а для 1.3 надо просто «mod_python»
  • Subversion — либо другие системы контроля версия, например Mercurial, git или Bazaar
  • py-subversion — для работы из Python с Subversion
  • MySQL — можете также использовать SQLite или PgSQL. Подробнее http://trac.edgewall.org/wiki/DatabaseBackend
  • Ну и сам Trac разумеется :)

Читать полностью »

Восстановление структуры таблиц InnoDB

Базы данных 02.07.2009

mysql-logo

Бывает, что при перемещении базы sql-дамп не получается создать и остаются только файлы «*.frm», вы их заливаете в каталог «/var/db/mysql» и в надежде что заработают innodb-таблицы приходите в отчаянье, потому что они не работают...

Например при mysqldump, может выпасть ошибка:

Got error: 1146: Table `table_name` doesn't exist when using LOCK TABLES

Вам поможет этот хитрый трюк

Создаёте базу данных «my_test»:

mysql> CREATE DATABASE my_test;
mysql> USE my_test;

после чего, создаёте там соответствующую названию файлу «table_name.frm» пустую таблицу:

mysql> CREATE TABLE `table_name` (`id` INT PRIMARY KEY) ENGINE=Innodb;

после, замените созданный вами файл в тестовой таблице «my_test» исходным файлом таблицы:

cp /var/db/mysql/database_name/TABLE_NAME.frm /var/db/mysql/my_test/TABLE_NAME.frm

А теперь посмотрим структуру нашей таблицы:

mysql> USE my_test;
mysql> SHOW CREATE TABLE TABLE_NAME;

и вы увидите структуру, а дальше можете делать дамп или что вы там делали!

Также вы можете перенести все ваши побитые таблицы и переименовать базу в прежнее имя (удалив при этом старую естественно).

З.Ы. Почитайте полезную статью Восстановление данных InnoDB в MySQL