Оптимизация Запросов Mysql

В повседневной работе вы сталкиваетесь с довольно похожими ошибками при написании запросов.

В этой статье я хотел бы привести примеры того, как НЕ писать запросы.

  • Выбрать все поля ВЫБРАТЬ * ИЗ таблицы При написании запросов не используйте выборку всех полей - "*".

    Укажите только те поля, которые вам действительно нужны.

    Это уменьшит объем получаемых и отправляемых данных.

    Также не забывайте о покрытии индексов.

    Даже если вам действительно нужны все поля таблицы, лучше их перечислить.

    Во-первых, это улучшает читаемость кода.

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

    Во-вторых, со временем количество столбцов в вашей таблице может измениться, и если сегодня столбцов INT пять, то через месяц могут добавиться поля TEXT и BLOB, что замедлит выбор.

  • Запросы в цикле.

    Необходимо четко понимать, что SQL — это язык, работающий с множествами.

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

    Это можно сделать достаточно просто, приняв простое правило — «никогда не выполнять запросы в цикле».

    Примеры того, как это можно сделать: 1. Образцы $news_ids = get_list('ВЫБРАТЬ news_id ИЗ Today_news '); while($news_id = get_next($news_ids)) $news[] = get_row('ВЫБЕРИТЕ заголовок, тело ИЗ новости WHERE news_id = '.

    $news_id); Правило очень простое – чем меньше запросов, тем лучше (хотя из этого, как и из любого правила, есть исключения).

    Не забывайте о конструкции IN().

    Приведенный выше код можно записать в один запрос: ВЫБЕРИТЕ заголовок, тело ИЗ Today_news INNER JOIN news USING(news_id) 2. Вставки $log = parse_log(); в то время как ($ запись = следующий ($ журнал)) query('INSERT INTO logs SET value = '.

    $log['value']); Гораздо эффективнее объединить и выполнить один запрос: INSERT INTO logs (значение) ЗНАЧЕНИЯ (.

    ), (.

    ) 3. Обновления Иногда вам нужно обновить несколько строк в одной таблице.

    Если обновленное значение такое же, то все просто: UPDATE news SET title='тест' ГДЕ id IN (1, 2, 3).

    Если изменяемое значение для каждой записи разное, то это можно сделать с помощью следующего запроса: ОБНОВЛЕНИЕ новостей НАБОР заголовок = СЛУЧАЙ КОГДА news_id = 1 ТОГДА 'аа' КОГДА news_id = 2 ТОГДА 'bb' КОНЕЦ ГДЕ news_id IN (1, 2) Наши тесты показывают, что такой запрос выполняется в 2-3 раза быстрее, чем несколько отдельных запросов.

  • Выполнение операций над индексированными полями ВЫБЕРИТЕ user_id ИЗ пользователей WHERE blogs_count * 2 = $value Этот запрос не будет использовать индекс, даже если индексируется столбец blogs_count. Чтобы использовать индекс, в индексированном поле запроса не должно выполняться никаких преобразований.

    Для таких запросов переместите функции преобразования в другую часть: ВЫБЕРИТЕ user_id ИЗ пользователей ГДЕ blogs_count = $value / 2; Похожий пример: ВЫБРАТЬ user_id ИЗ пользователей WHERE TO_DAYS(CURRENT_DATE) — TO_DAYS(зарегистрирован) <= 10; не будет использовать индекс в зарегистрированном поле, тогда как ВЫБРАТЬ user_id ИЗ пользователей, ГДЕ зарегистрировано > = DATE_SUB(CURRENT_DATE, INTERVAL 10 DAY); воля.

  • Получение строк только для подсчета их количества $result = mysql_query("SELECT * FROM table", $link); $num_rows = mysql_num_rows($result); Если вам нужно выбрать количество строк, удовлетворяющих определенному условию, используйте запрос к таблице SELECT COUNT(*) FROM, а не выбирайте все строки только для подсчета количества строк.

  • Получение дополнительных строк $result = mysql_query("SELECT * FROM table1", $link); while($row = mysql_fetch_assoc($result) && $i < 20) { … } Если вам нужно получить только n строк, используйте LIMIT вместо того, чтобы отбрасывать лишние строки в приложении.

  • Использование ORDER BY RAND() ВЫБРАТЬ * ИЗ таблицы ORDER BY RAND() LIMIT 1; Если в таблице более 4-5 тысяч строк, то ORDER BY RAND() будет работать очень медленно.

    Гораздо эффективнее было бы выполнить два запроса: Если таблица имеет первичный ключ auto_increment и нет пробелов: $rnd = rand(1, query('SELECT MAX(id) FROM table')); $row = query('SELECT * FROM table WHERE id = '.

    $rnd); или: $cnt = query('SELECT COUNT(*) FROM table'); $row = query('SELECT * FROM table LIMIT '.

    $cnt.', 1'); что, однако, также может быть медленным, если в таблице очень большое количество строк.

  • Использование большого количества JOINов ВЫБИРАТЬ v.video_id имя, г.

    жанр ОТ видео АС v ЛЕВОЕ ПРИСОЕДИНЕНИЕ link_actors_videos КАК ЛА НА la.video_id = v.video_id ЛЕВОЕ ПРИСОЕДИНЕНИЕ актеры КАК ON a.actor_id = la.actor_id ЛЕВОЕ ПРИСОЕДИНЕНИЕ link_genre_video КАК LG ON lg.video_id = v.video_id ЛЕВОЕ ПРИСОЕДИНЕНИЕ жанры КАК г НА g.genre_id = lg.genre_id Необходимо помнить, что при соединении таблиц один-ко-многим количество строк в выборке будет увеличиваться с каждым следующим JOIN. В таких случаях быстрее разбить такой запрос на несколько простых.

  • Использование ПРЕДЕЛА ВЫБРАТЬ… ИЗ таблицы LIMIT $start, $per_page Многие думают, что такой запрос вернет $ за_страницу записей (обычно 10-20) и поэтому будет работать быстро.

    Первые несколько страниц будут работать быстро.

    Но если количество записей велико, и вам необходимо выполнить запрос SELECT. FROM table LIMIT 1000000, 1000020, то для выполнения такого запроса MySQL сначала выберет 1000020 записей, отбросит первый миллион и вернет 20. Это может быть совсем не быстрым.

    Тривиальных способов решения проблемы не существует. Многие просто ограничивают количество доступных страниц разумным количеством.

    Вы также можете ускорить такие запросы, используя покрывающие индексы или сторонние решения (например, sphinx).

  • Не использовать ОБНОВЛЕНИЕ ДУБЛИКАЦИОННОГО КЛЮЧА $row = query('SELECT * FROM table WHERE id=1'); если($строка) query('UPDATE table SET столбец = столбец + 1 WHERE id=1') еще query('INSERT INTO table SET columns = 1, id=1'); Подобную конструкцию можно заменить одним запросом при условии наличия первичного или уникального ключа для поля id: INSERT INTO table SET столбец = 1, id=1 ON DUPLICATE KEY UPDATE столбец = столбец + 1
Читать оригинальная статья в MySQL Consulting. P.S. Пишите мне в личку темы статей по MySQL, которые вы хотели бы прочитать.

Теги: #MySQL #оптимизация #запросы #MySQL

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.