Спрятать колонку

Mysql. Задача на рандомизацию

попалась занятная задачка:
форум, посты, даты постов нужно сделать случайными, но нужно сохранить порядок ответов в ветке.

идея решения проста. приведу пример:

t1, t2, t3 - время, когда были сделаны три поста (посты подряд идущие и необязательно из одной ветки)

t1 - 0
t2 - N
t3 - 2 * N

где N у нас время на которое мы раздвинем посты, возьмем сутки: 60 * 60 * 24
теперь видно, что вокруг поста t2 образовался зазор во времени равный плюс/минус N (одним суткам). и следовательно, можно можно добавить случайное числов рамках от -N... +N. вот такой получается запрос

MySql. События

Часто необходимо планировать действия, которые должны происходить с СУБД с определенным интервалом времени. К примеру, это может быть очистка временных таблиц, удаление старых логов и т.д. Раньше для этого необходимо было писать cron job, добавить его вызов (если хостер предоставляет такую возможность, а если нет). Много мороки получается. Начиная с MySql 5.1 все станет немного проще. В распоряжении разработчика теперь имеется оператор CREATE EVENT

CREATE 
    [DEFINER = { USER | CURRENT_USER }]
    EVENT 
    [IF NOT EXISTS]
    event_name    
    ON SCHEDULE schedule
    [ON COMPLETION [NOT] PRESERVE]
    [ENABLE | DISABLE | DISABLE ON SLAVE]
    [COMMENT 'comment']
    DO sql_statement;
 
schedule:
    AT TIMESTAMP [+ INTERVAL INTERVAL] ...
  | EVERY INTERVAL 
    [STARTS TIMESTAMP [+ INTERVAL INTERVAL] ...] 
    [ENDS TIMESTAMP [+ INTERVAL INTERVAL] ...]
 
INTERVAL:
    quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |
              WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
              DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}

Хорошей практикой при этом является инкапсуляция действий в функцию и вызов непосредственно ее. К примеру:

CREATE EVENT delete_trash 
   ON SCHEDULE 
   EVERY 1 DAY
   COMMENT 'This function deletes trash'
DO
   CALL del_trash;

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

SET GLOBAL event_scheduler := 1;

>> Читать далее

Поиск строки в таблице

Поводом для этой записи служит довольно рутинная задача: проверить, существует ли запись в таблице. Я бы до конца своей жизни пользовался запросом типа:

SELECT count(1) FROM all_objects 
WHERE object_name = 'SOME_OBJECT_NAME'

несмотря на то, что он весьма плох, из-за использования функции count.
Мне же показали другой вариант, который работает гораздо быстрее.
Это код на pl/sql:

DECLARE
    i_found PLS_INTEGER := 0;
BEGIN
   BEGIN
     SELECT 1 / 0 INTO i_found  FROM all_objects
     WHERE object_name = 'SOME_OBJECT_NAME';
     EXCEPTION
        WHEN ZERO_DIVIDE THEN 
           DBMS_OUTPUT.put_line('record found');
        WHEN NO_DATA_FOUND THEN 
           DBMS_OUTPUT.put_line('record not found');
     END;
   END;
END;

Очень оригинальная идея использования ошибки деления на ноль. Ислючение создается всегда, вопрос лишь в том, какое это будет исключение. Если это ZERO_DIVIDE, то получается, что запись есть, потому что произошла операция деления. Если NO_DATA_FOUND, то 1 / 0 никогда не отработал и в переменную i_found ничего не занеслось.
Этот метод работает примерно раза в два быстрее (зависит от количества данных), что весьма существенно при большой повторяемости данного запроса.
Мне стало интересно, существует ли более быстрый вариант определения наличия записи в таблице. Не может же быть так, что для нахождения записи мы создавали исключительную ситуацию, тратили время на его обработку и получали самый быстрый способ.

В Oracle есть стандартный оператор EXISTS, который позволяет проверять наличие записей в курсоре, а еще есть CASE, который помогает ветвить логику в запросе. И, как результат работы, родился следующий запрос:

SELECT 
    case
       when EXISTS(SELECT 1 FROM all_objects WHERE object_name = 'SOME_OBJECT_NAME') THEN 1
       else 0
   end
FROM dual

этот запрос возвращает 0, если записей нет и 1, если есть. Сначала, во вложенном запросе, мы ищем совпадение по условию, а в самом проверяем - вернул ли вложенный запрос на что-либо. Работает быстрее второго варианта примерно на 20% (на аналогичной выборке).

Ложка дегтя в бочке меда, куда же без нее
С позиции программиста все выглядит великолепно - я нашел еще более быстрый вариант решения задачки, но потратил на это некоторое время. В данном случае затраты были невелики: 20минут рабочего времени не слишком много. Но всегда стоит помнить, что в погоне за подобной "оптимизацией" мы можем выиграть немного времени, но потерять очень много именно на поиск. Поэтому всегда сначала нужно оценить задачу и решить: стоит ли игра свеч, возможно, мы потеряем больше, чем приобретем.

Если сможете предложить более хороший способ нахождения строки - милости прошу, будет интересно посмотреть другое решение.

>> Читать далее

Mysql. Best Practices

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

1. Всем и всегда первый совет: больше читайте книг, а еще больше документации.

К примеру, вопрос: "Можно ли в одном запросе выполнить несколько вставок?" Решается простым обращением к документации по mySql, где написано - можно и, порой, даже нужно. Чем полезно чтение я уже писал.

2. Оформление.

Следите за оформлением своего кода и за именованием. Всегда есть вероятность, что вам придется вернуться к этому запросу через месяц, и будет очень неприятно, если вы потратите лишние полчаса, чтобы вспомнить - "что это тут такое было?!". Помните, что после вас код будут поддерживать и дорабатывать.

>> Читать далее
RSS-материал

Наверх