Насколько дорогостоящими являются объединения в SQL? И / или, каков компромисс между производительностью и нормализацией?

#mysql #sql #performance #join

#mysql #sql #Производительность #Присоединиться

Вопрос:

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

Я знаю, что существует компромисс между нормализацией и производительностью, и мне интересно, какова наилучшая практика для проведения этой линии? В моей конкретной ситуации у меня есть система обмена сообщениями, в которой есть три отдельные таблицы: messages_threads (общий держатель сообщения), messages_recipients (кто участвует) и messages_messages (фактические сообщения временные метки).

Чтобы вернуть представление «Входящие», я должен соединить таблицу messages_threads, таблицу users и таблицы pictures слева с таблицами messages_recipients, чтобы получить информацию для заполнения представления (изображение профиля, имя отправителя, идентификатор потока)… и мне все еще нужно добавить соединение в сообщения, чтобы извлечь текст из последнего сообщения, чтобы отобразить пользователю «предварительный просмотр» последнего сообщения.

Мой вопрос: насколько дорогостоящими являются объединения в SQL для производительности? Я мог бы, например, сохранить имя отправителя (для извлечения которого я должен использовать left join от users) в поле в таблице messages_threads под названием «sendername», но с точки зрения нормализации меня всегда учили избегать избыточности данных?

Где вы проводите черту? Или я переоцениваю, насколько SQL-соединения снижают производительность?

Ответ №1:

Лучшая практика — всегда начинать с 3NF, а затем рассматривать денормализацию только в том случае, если вы обнаружите конкретную проблему с производительностью.

Производительность — это всего лишь одна из проблем, с которыми вам приходится сталкиваться при работе с базами данных. Дублируя данные, вы рискуете допустить наличие в вашей базе данных противоречивых данных, тем самым сводя на нет один из основных принципов реляционных баз данных, согласованность ( C в ACID ) a.

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

И помните мантру оптимизации: измеряйте, а не гадайте! И измерение в среде, подобной производственной. И продолжайте периодически измерять (и настраивать) — оптимизация — это всего лишь операция set и forget, если ваша схема и данные никогда не меняются (очень маловероятно).


a) Возврат к производительности обычно можно сделать безопасным, используя триггеры для поддержания согласованности. Это, конечно, замедлит ваши обновления, но все же может позволить вашим выборкам выполняться быстрее.

Комментарии:

1. Спасибо, пакс, ты прав — я должен придерживаться ACID. Спасибо, что разъяснили мне это, я прочитал статью о денормализации больших сайтов и начал сомневаться в моей структуре.

2. @Walker, денормализация является иногда жизнеспособным вариантом. Вы просто должны убедиться, что это скорее поможет, чем помешает 🙂 Как и в большинстве случаев в жизни, есть компромиссы.

Ответ №2:

Я бы не стал так сильно беспокоиться о дополнительном соединении. По моему опыту, большая потеря производительности от объединений происходит при объединении больших наборов данных. Предположительно, в вашем представлении сообщений будут отображаться максимум 20-100 строк.

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

Если вам действительно интересно, вы можете настроить бенчмарк. phpMyAdmin сообщает вам, сколько времени потребовалось для выполнения запроса; вы можете проверить время с окончательным соединением и без него. (Просто имейте в виду, что все запросы выбора phpmyadmin ограничены, поэтому вы можете ожидать более длительного времени выполнения, если вы выбираете более 20 строк).

Комментарии:

1. phpMyAdmin не является инструментом, подходящим для такого рода работы. Вы должны использовать настольный инструмент, такой как EMS MySQL Manager, Navicat для MySQL или какой-либо другой.

2. Если вам нужны данные из двух больших наборов данных, ОБЪЕДИНЕНИЯ, как правило, являются наиболее эффективным способом их получения.

3. У меня есть Sequel Pro, который довольно хорошо работает для тестирования производительности — я понятия не имел, что LEFT JOIN обходится дороже, чем JOIN — Мне определенно придется вернуться и заменить множество операторов LEFT JOIN во всем моем коде.

Ответ №3:

На этот вопрос нет простого ответа. Стоимость соединений сильно варьируется в зависимости от доступных индексов, количества записей и многих других факторов. На самом деле в MySQL существует по крайней мере пара стратегий объединения, которые сортируются от наилучшего к наихудшему сценарию.

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

Денормализация должна выполняться, только если у вас реальная проблема с производительностью и нет другого способа ее решить (например, добавление индекса, изменение параметров, переписывание запроса, …) и должна основываться на глубоком анализе проблемы.

Ответ №4:

По моему опыту, влияние дополнительных сегментов соединения в запросе, как правило, не приводит к сбоям в работе приложения. Индексирование, избегание подзапросов и, иногда, избегание операторов LEFT JOIN окажут наибольшее влияние.

Как упоминает Сэм Дюфель, настройте тест, чтобы увидеть, следует ли обходить используемое вами ЛЕВОЕ соединение. Также может быть полезно сгенерировать кучу фиктивных данных, чтобы посмотреть, масштабируются ли они по мере увеличения количества записей в соединении.

Ответ №5:

Объединения — это стратегия повышения эффективности запроса. И вопреки другому ответу, внешние объединения столь же эффективны, как и внутренние, в каждом продукте, с которым мне довелось ознакомиться, который включает MySQL (оба основных движка), SQL Server, Sybase и Oracle.

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

Ответ №6:

ВСЕГДА предпочитаю нормализацию. Для меня ужасно, что денормализации ВСЕ еще уделяется такое внимание.

НОРМАЛИЗОВАТЬ — вот для чего настроены ядра баз данных.

Комментарии:

1. Спасибо, Рэнди, единственная причина, по которой я усомнился в этом, — это чтение о денормализации Twitter.

2. да — и я, вероятно, погорячился. но на самом деле вы даже не должны рассматривать это, пока не докажете, что у вас возникла какая-то проблема с вашей должным образом нормализованной системой.

Ответ №7:

Невозможно или полезно отвечать на вопрос о том, насколько дорогостоящими являются объединения.

Соединение — это просто команда в SQL-запросе, то, что база данных делает с этим соединением, является чем-то совершенно другим. Что дорого в запросе, так это такие вещи, как сканирование таблицы, когда базе данных приходится читать всю таблицу, чтобы найти некоторые данные. Запрос с десятью объединениями в таблицах, где есть полезные индексы, может быть намного быстрее, чем запрос к одной таблице без каких-либо полезных индексов.

Три или четыре объединения в запросе, безусловно, не являются причиной для отмены нормализации таблиц в попытке повысить производительность. Для сравнения: для нашего веб-сайта мы используем ненормализованную таблицу для чтения, потому что нам потребуется около 40 объединений, чтобы собрать нужные нам данные.