Entries Tagged ‘mysql’:

mysql, postgre, mongodb и снова mysql

На работе столкнулся с досадным недостатком mysql: он не умеет делать слияние отсортированных индексом массивов.

На пальцах: пусть есть таблица  objects (id, category_id, time) с индексом (category_id, time). Задача – выбрать среди данных нескольки категорий N последних.

Запрос:
SELECT  * FROM objects WHERE category_id IN (10,11,12,13, 14) ORDER BY time DESC LIMIT 10;
даже не думает работать по индексу. Он отбирает все объекты из этих категорий, сортирует их filesort’ом и потом отбирает первые. Хотя очень логично поступить аналогично сортировке слиянием: взять отсортированные последовательности для каждой категории и сливать их, пока не получим N элементов.

Итак, мелькнула идея попробовать применить PostgreSQL. Поставил, перелил в него таблицу, сделал аналогичные запросы – он приятно удивил: 0.5-0.6 секунд против 2.5-3.0 в мускуле. Причём Постгре был под виндой, а Мускул под FreeBSD. Не могу точно утверждать, индексы разруливает лучше или просто сыграл тот факт, что движок быстрее (а он реально быстрее), потому что он и без проставленных индексов работал быстрее мускула (в районе 1.0-1.5 сек).

Я бы на этом и остановился, но шеф настоял, чтобы я попробовал MongoDB. Опустив лирику, могу только подписаться под резюме: “Быстрый, как понос”. Для той же самой задачи он дал результаты порядка 0.2-0.3 сек.

И уже все были готовы перейти на использование MongoDB, как вдруг мелькнула шальная мысль. Сделали копию таблицу в Mysql MEMORY engine, внесли данные в нужном порядке, убрали (!) все индексы. Ура! Результаты порядка 0.02-0.05 сек.

Что тут сказать… Универсальных решений не бывает, вот и всё.

partial distinct

предлагаю SQL-задачку. не надуманная, возникла на работе.

контекст: музыкальный сайт, таблица (mysql) с плейлистами юзера

playlists:
{
int id, //автоинкремент
int song_id, //id самой песни
int user_id, //id юзера, который добавил себе песню
datetime added, //время, когда добавлена песня в его плейлист
}

song_id не уникальны, т.к. песню могли добавить несколько юзеров.

задача: написать SQL для выборки: “последние песни, добавленные в плейлисты пользователей”. для песен нужно вывести кто и когда их добавил в последний раз. дубликаты песен выводить не нужно, если песню добавили два юзера – вывести последнее добавление.

иными словами, нужно выбрать “последние N неповторяющихся песен в плейлистах с указанием того, кто последний и когда её добавил”.

то, что пока придумал я, имеет 4 select’а в запросе и 3й уровень вложенности этих select’ов. сможешь лучше?

P.S. конечно же, должно работать максимально быстро. в наличии есть индекс по added.

осторожно, SQL_CALC_FOUND_ROWS

Я всегда считал, что SQL_CALC_FOUND_ROWS – это круто.

Для тех, кто ещё не знает, что это – позволяет два запроса типа
“SELECT * FROM tbl WHERE somecondition LIMIT 100,10″,
“SELECT COUNT(*) FROM tbl WHERE somecondition”

выполнить в одном:
“SELECT SQL_CALC_FOUND_ROWS * FROM tbl WHERE somecondition LIMIT 100,10″
и затем вытащить количество найденных строк дополнительным запросом
“SELECT FOUND_ROWS()”.

Это очень удобно, и казалось, что очень эффективно (в моей голове не укладывалась мысль, что мускул может делать это хуже, чем втупую двумя запросами).

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

То есть, не так уж она хороша, эта удобная конструкция =(

темы к phpmyadmin

сегодня попробовал возможность встроить в PMA больше тем. Немножко тем нашёл здесь: http://www.phpmyadmin.net/home_page/themes.php#pma_3_1 – мне хватило. Теперь страницы PMA стали на порядок красивее, в добавок выбрал разные темы для разных серверов – перестал путаться. Советую.
P.S. в последней версии PMA настраивается цвет фона – тоже полезная фича.