Ответы пользователя по тегу MySQL
  • Как парсить xml в mysql?

    Dzuba
    @Dzuba
    Это можно сделать силами одного лишь mysql.
    Загрузка XML в таблицу: LOAD XML
    Периодический запуск (встроенный cron): Event Scheduler (не забудьте включить
    event_scheduler=ON в конфиге мускула). См.также: пост.
    Если нет рут-доступа к серверу, тогда просто вызывать по cron'у:
    mysql -u <имя_пользователя_mysql> --password=<пароль> -e "LOAD XML ...;"
    Ответ написан
    Комментировать
  • Хранение и выборка булевых значений. Mysql

    Dzuba
    @Dzuba
    Вы путаете. Никакой экономии по месту нет. И в моем решении, и в SET, все хранится в 1 байте. Компактнее некуда. А вот решение с 4 полями типа BOOLEAN занимает 4 байта.
    Я убежден, что приведенное мной решение является также и самым производительным из предложенных.
    Преимущество по скорости в нем достигается за счет использования индекса конструкцией WHERE IN (...). Точно такой же результат должен быть, если использовать эту конструкцию и с полем типа SET. Я даже изначально написал, что решение приемлемо для типов, цитирую:
    TINYINT UNSIGNED (либо BIT(4), либо SET)
    Это поскольку все они приводимы к целочисленному типу, и, при использовании каждого из них, фактически будут образовываться одинаковые значение в байте.
    Ответ написан
  • Хранение и выборка булевых значений. Mysql

    Dzuba
    @Dzuba
    Я бы попробовал следующее: хранить все 4 бита совместно в одном индексированном поле (назовем его bits), имеющем тип TINYINT UNSIGNED (либо BIT(4), либо SET).
    А запросы бы делал в виде:
    SELECT * FROM table WHERE bits IN (...)
    Где вместо многоточия должны быть перечислены те значения, которые удовлетворяют маске. Для маски, указанной вами в примере, запрос примет вид:
    SELECT * FROM table WHERE bits IN (b'1001', b'1011')
    На мой взгляд, при таком подходе и место экономится, и производительность будет наилучшей.
    Ответ написан
    5 комментариев
  • Алгоритм для поиска номера по маске

    Dzuba
    @Dzuba
    Да, прошляпил один момент — в первом варианте нужно добавить условие, что A != B. С ним запрос будет выглядеть, например, так:
    SELECT * FROM table WHERE D0=9 AND D1=1 AND D2=1 AND D3=D4 AND D4=D5 AND D7=D8 AND D8=D9 AND D3!=D7
    Ответ написан
  • Алгоритм для поиска номера по маске

    Dzuba
    @Dzuba
    Имею 2 варианта:

    Вариант 1. Хранить сами номера телефонов «поциферно» — в 10 полях таблицы (D0, D1, ..., D9), по 1 полю на каждую цифру номера. Произвести индексацию по этим полям.
    Плюсы: при поиске будут использоваться индексы.
    Минусы: растет размер таблицы, растет время обновления данных при вставке/замене и т.д.
    Пример для маски 911-AAA-X-BBB:
    SELECT * FROM table WHERE D0=9 AND D1=1 AND D2=1 AND D3=D4 AND D4=D5 AND D7=D8 AND D8=D9


    Вариант 2. При вводе маски (в основной программе) заранее подготовить список ВСЕХ (не обязательно содержащихся в таблице) номеров, удовлетворяющих маске, и использовать уже этот список в WHERE.
    Плюсы: при поиске будет использоваться индекс.
    Минусы: при «слабой» маске, таких номеров в списке может оказаться довольно много и сам текст запроса получится невообразимо большим.
    Этот метод будет хорош, когда маска «сильная», например: 911-AAAAAA-X (всего порядка 100 вариантов)
    Пример для маски 911-AAA-X-BBB:
    SELECT * FROM table WHERE phone IN (9110001111, 9110001222, 9110001333, ...)
    Ответ написан
    4 комментария
  • Топ по нескольким параметрам. PHP+MySQL

    Dzuba
    @Dzuba
    Сортировать можно по нескольким полям:
    SELECT * FROM votes
    GROUP BY item_id
    ORDER BY COUNT(*) DESC, AVG(vote_value) DESC
    LIMIT 10;

    Если Вас и это не устроит, то, пожалуйста, сформулируйте суть соотношения между рейтингом и количеством голосов.
    Ответ написан
    Комментировать
  • Сортировка по схожести?

    Dzuba
    @Dzuba
    Предложение 1: поскольку поля с фильмами представляют собой биты, то имеет смысл хранить их в виде чисел. Максимальное целое в mysql — 8-байтовый BIGINT. То есть, если всего фильмов тысяча, то потребуется полтора-два десятка таких чисел в каждой записи. Пусть N — количество таких чисел-1, userF0, ..., userFN — эти числа в записи выбранного пользователя. Тогда поиск 10 похожих пользователей в таблице с полями (user_id, f0, ..., fN) будет выглядеть так:
    SELECT user_id FROM таблица
    ORDER BY (BIT_COUNT(f0 & userF0) + ... + BIT_COUNT(fN & userFN)) DESC LIMIT 10;
    Минусы подхода: пробегать при запросе будет все записи, при добавлении новых фильмов нужно вызывать ALTER TABLE. За скорость тоже ручаться не могу.

    Предложение 2: создать 1 таблицу с юзерами и столько таблиц, сколько фильмов, в каждой из которых хранить список id юзеров, выбравших фильм. Тогда поиск похожих юзеров сведется к:
    SELECT tmp.user_id FROM (SELECT user_id FROM таблица1
        UNION ALL
        SELECT user_id FROM таблица2
        UNION ALL
        ...
        UNION ALL
        SELECT user_id FROM таблицаN) AS tmp
    GROUP BY tmp.user_id ORDER BY COUNT(tmp.*) DESC LIMIT 10;
    
    Минусы подхода: большое количество подзапросов, группировка.

    Предложение 3: создать 1 таблицу с юзерами (users) и 1 таблицу с юзеро-фильмами (user_films), т.е. с записями о предпочтениях юзеров следующего вида (user_id, film_id). Тогда для списка фильмов выбранного юзера (film_id0, ..., film_idN) поиск похожих юзеров сведется к:
    SELECT user_id FROM user_films
    WHERE film_id IN (film_id0, ..., film_idN)
    GROUP BY user_id ORDER BY COUNT(*) DESC LIMIT 10;
    
    Минусы подхода: группировка.
    Хотя при индексированном поле film_id может будет и не сильно медленно.
    Ответ написан
    6 комментариев
  • MySQL Select каждой n-ой строки

    Dzuba
    @Dzuba
    Поскольку такая таблица может иметь весьма приличный объем, отчего неизбежно пострадает скорость, я бы советовал реализовать всю логику в момент вставки новой записи, а именно:
    1. Создать доп. таблицы для записей часа, суток и т.д., в которых хранить только записи за соответствующие моменты времени. Тогда доступ к ним будет весьма быстрым. Правда объем еще увеличится.
    2. Если есть доступ к ПО, которое осуществляет запись в БД, проверять в нем величину соответствующего интервала. Если нет, или если требование «реализовать средствами MySQL» принципиально, то использовать триггер на вставку в исходную таблицу, в котором проверять условие и дублировать запись в таблицы для часа, суток и т.д.
    При этом в доп.таблицы достаточно вставлять не саму запись, а только ее id.
    Ответ написан
    Комментировать
  • Анализ графиков загрузки и оптимизация web-сервера?

    Dzuba
    @Dzuba
    Сам по себе высокий LA не проблема и не симптом, имхо. Нужно смотреть на состав процессов и основных показателей в моменты высоких значений LA в top.

    Если, например, при пиковой нагрузке высокий wa, то значит сервер «уперся» в диск и имеет смысл попытаться снизить нагрузку на дисковую подсистему при помощи простых мер: отключить access-логи, избавиться от ошибок в error-логах, указать «BufferedLogs on» в конфиге апача, поставить noatime для раздела и т.д.
    При этом (и при наличии запаса по памяти), в отношении мускула не следует скупиться на: table_cache, thread_cache_size, query_cache_size, max_heap_table_size, tmp_table_size и иные «кеширующие» параметры.
    Если же наоборот, при высоких LA и wa наблюдается нехватка памяти, нужно ужимать именно ее расход, поскольку система вылазит в своп, скорее всего.

    Если в том же slow.log'е наиболее часто фигурируют 1-2 долгих запроса, имеет смысл разобраться с их происхождением и, в зависимости от последнего, либо избавиться от них, либо оптимизировать их.

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

    Насчет связки nginx + php-fpm, одобряю, поскольку имею положительные впечатления от ее применения. Но переход на эту связку не отменяет написанного выше, ибо хуже не будет.
    Ответ написан
    4 комментария