This Might Be Useful

Archive for the ‘SQL’ Category

Восстановление удаленных записей в mySQL из binlog

Monday, January 12th, 2009 | Linux, SQL, Shell | No Comments »

Вчера я случайно удалил почти все записи из таблицы статистики просмотра видеозаписей Движущихся Картинок. Событие более чем печальное. До этого я предполагал, что восстановить удаленные записи практически невозможно. Оказалось, что можно. Если включены бинарные логи (для их включения в настройках mySQL надо указать параметр log-bin).
В результате некоторых раздумий получилась команда:
/usr/bin/mysqlbinlog --database=нужная_база_данных –start-datetime=”2008-01-01 00:00:00″ путь_ко_всем_binlog | tr “\t” ” ” | tr “\n” ” ” | tr “;”"\n” | grep “INSERT INTO \`побитая_таблица\`” > p.sql

Параметр start-datetime содержит в себе дату, с которой вынимаем логи. Можно еще указать время остановки (в моем случае это было неактуально).
Далее нужно указать не просто путь к логам, а все файлы логов (например, /var/lib/mysql/lalala-bin.*).
Несколько tr‘ов нужны потому, что запрос мой был многострочным, а надо было мне получать один запрос в одну строку.

В конечном счете в файле p.sql я получил нужные мне запросы. Единственное, что в конце строк не было точки с запятой. Это было исправное просто:
cat p.sql | sed "s/\"\)/\"\);/g" > p2.sq
Просто у меня каждый запрос оканчивался на ….”)

Когда я попытался скормить запросы mySQL’у оказалось, что из-за того, что были удалены не все записи, начались проблемы с уникальностью некоторых полей. Чтобы не копаться в дампе руками, сделал так:
cat p2.sql | sed "s/INSERT INTO/INSERT IGNORE INTO/g" > p3.sql

И уже p3.sql успешно скормил mySQL’у.

Отсюда выводы: во первых, всегда делайте бекапы (как можно чаще), и во вторых всегда включайте логирование.

P.S. Конечно же из binlog’ов можно вытащить все, что делалось с базой. И Восстановить то состояние, которое нужно.

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

Двигаем при выводе строчки в таблице друг относительно друга

Thursday, August 14th, 2008 | PHP, SQL | No Comments »

Часто встречается ситуация, когда необходимо вручную устанавливать порядок вывода записей в некоем списке. То есть клиент должен иметь возможность двигать строчки вверх-вниз друг относительно друга. Некоторые "программисты" изобретают для этого сложнейшие велосипеды. На самом же деле сделать это очень просто. Просто создаем дополнительное поле `customorder`, которое по умолчанию равно `id` (в случае, усли `id` не auto_increment, можно его ставить в (MAX(`customorder`) + 1)). Затем используем вот такую простую функцию:

PHP:
  1. function move_line($id, $up) {
  2.   $rez = mysql_query('SELECT `customorder`
  3.       FROM `thetable`
  4.       WHERE `id` = '.intval($id));
  5.   list($o) = mysql_fetch_row($rez);
  6.   $rez = mysql_query('SELECT `id`, `customorder`
  7.       FROM `thetable`
  8.       WHERE `customorder` '.($up ? '<' : '>').' '.$o.'
  9.       ORDER BY `order` '.($up ? 'DESC' : 'ASC').'
  10.       LIMIT 1');
  11.   if (mysql_num_rows($rez) > 0) {
  12.     list($nid, $no) = mysql_fetch_row($rez);
  13.     mysql_query('UPDATE `content`
  14.       SET `customorder` = '.$no.'
  15.       WHERE `id` = '.$id);
  16.     mysql_query('UPDATE `content`
  17.       SET `customorder` = '.$o.'
  18.       WHERE `id` = '.$nid);
  19.   }
  20. } // move_line

И да, я знаю, что это можно сделать меньшим количеством запросов. Но так нагляднее :).

Как заставить JOIN в MySQL нормально использовать индексы и максимально ускорить выполнение запросов

Wednesday, July 30th, 2008 | SQL | 8 Comments »

Несколько раз натыкался на эту проблему, но только сегодня полноценно ее решил. Проблема проста: есть запрос с несколькими JOIN'ами. При выполнении запроса толком не используются индексы. В результате все ужасно тормозит.
Запрос примерно такой:

SQL:
  1. SELECT `a`.*, `b`.*
  2. FROM `a` LEFT JOIN `b` ON `a`.`field1` = `b`.`field2`
  3. WHERE `b`.`field3` = "something"
  4. ORDER BY `a`.`field4`

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

  1. Создать индекс по каждому из полей, используемых в WHERE и JOIN. Отдельно по каждому.
  2. Убедиться, что в WHERE указано максимально жесткое условие дабы сократить диапазон выборки.
  3. А теперь - внимание! Убедиться, что у `a`.`field1` и `b`.`field2` одинаковый collation!

Комментарий по последнему пункту: В моем случае у одного поля был latin1_swedish_ci, у второго - utf8_general_ci. Вроде как по данным выходило правильно. Но запрос работал очень медленно, порядка 3 секунд (использовались три таблицы с большим количеством записей - ~100,000, ~30,000 и ~3,000). После применения пункта номер один и особенно пункта номер три запрос стал выполняться за 0.1 (одну десятую!) секунды.

Реализация аналога LIMIT из MySQL в MS SQL

Thursday, May 8th, 2008 | SQL | No Comments »

В MS SQL отсутствует LIMIT в SELECT'е. Это поразительно и глупо, но это так. И после MySQL это невероятно раздражает. Поэтому было найдено решение проблемы. Сравнительно медленное, но зато работающее не только в новых версиях MS SQL (где есть row_number(), облегчающий жизнь). Итак, для того, чтобы сделать то же, что в MySQL делает следующий запрос:

SQL:
  1. SELECT *
  2. FROM `some_table`
  3. LIMIT 10, 20

в MS SQL надо написать:

SQL:
  1. SELECT top 20 * FROM [some_table]
  2. WHERE [primary_key_field] NOT IN
  3.   (
  4.     SELECT top 10 [primary_key_field]
  5.     FROM [some_table]
  6.     ORDER BY [primary_key_field]
  7.   )
  8. ORDER BY [primary_key_field]

Календарь латвийских именин

Monday, April 28th, 2008 | SQL | No Comments »

База именин для латвийских имен. Формат довольно простой и грубый, но использовать можно. Поле `date` это дата в формате [m]mdd, `name` - это имя в латышском написании, а `simplename` - упрощенная версия имени, в которой длинные буквы продублированны, а смягченные заменены на их твердые аналоги. Дамп c MySQL 5.0 сервера.
(more...)

 Страница: 1 (всего: 2)  1  2 »