Когда и почему объединения баз данных дороги? - PullRequest
332 голосов
/ 06 октября 2008

Я изучаю базы данных и смотрю на некоторые ограничения реляционных БД.

Я понимаю, что объединения больших таблиц очень дороги, но я не совсем уверен, почему. Что нужно сделать СУБД для выполнения операции соединения, где узкое место?
Как денормализация может помочь преодолеть эти расходы? Как помогают другие методы оптимизации (например, индексация)?

Личные впечатления приветствуются! Если вы собираетесь размещать ссылки на ресурсы, пожалуйста, избегайте Википедии. Я уже знаю, где это найти.

В связи с этим меня интересует денормализованный подход, используемый базами данных облачных сервисов, такими как BigTable и SimpleDB. См этот вопрос .

Ответы [ 7 ]

448 голосов
/ 06 октября 2008

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

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

Я думаю, что он написал это в Записи реляционных баз данных 1988-1991 , но эта книга была позже свернута в шестое издание Введение в системы баз данных , которое окончательный текст по теории и дизайну баз данных, в его восьмом издании, которое я пишу, и, вероятно, останется в печати в течение десятилетий. Крис Дэйт был экспертом в этой области, когда большинство из нас все еще бегали босиком.

Он обнаружил, что:

  • Некоторые из них действительны для особых случаев
  • Все они не в состоянии расплатиться за общее использование
  • Все они значительно хуже для других особых случаев

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

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

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

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

Важно понимать, что сканирование таблицы (проверка каждой строки таблицы в процессе создания объединения) на практике встречается редко. Оптимизатор запросов будет выбирать сканирование таблицы, только когда выполняется одно или несколько из следующих значений.

  • В отношении менее 200 строк (в этом случае сканирование будет дешевле)
  • Нет подходящих индексов для столбцов соединения (если целесообразно объединить эти столбцы, то почему они не проиндексированы? Исправить это)
  • Приведение типов требуется перед сравнением столбцов (WTF ?! исправить это или вернуться домой) СМ. КОНЕЦ ЗАМЕЧАНИЯ ПО ВЫПУСКУ ADO.NET
  • Одним из аргументов сравнения является выражение (без индекса)

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

Если кто-то захочет напомнить мне, что это изменяющийся мир, я думаю, вы обнаружите, что большие наборы данных на более жестком оборудовании только преувеличивают распространение результатов Дейта.

Для всех вас, кто работает над биллинговыми системами или генераторами нежелательной почты (как вам не стыдно) и возмущенно протягивает руку к клавиатуре, чтобы сказать мне, что вы точно знаете, что денормализация происходит быстрее, извините, но вы живете в одной из особых случаев - в частности, случай, когда вы обрабатываете все данных, в порядке. Это не общий случай, и вы оправданы в своей стратегии. Вы не оправданы в ложном обобщении. См. Конец раздела примечаний для получения дополнительной информации о надлежащем использовании денормализации в сценариях хранилищ данных.

Я также хотел бы ответить на

Соединения - это просто декартовы произведения с некоторым блеском для губ

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

Единственный способ получить оптимизатор для создания декартового произведения - не указывать предикат: SELECT * FROM A,B


Примечания


Дэвид Олдридж предоставляет некоторую важную дополнительную информацию.

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

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

Раньше я был умнее оптимизатора MSSQL. Это изменило две версии назад. Теперь это обычно учит меня . В самом реальном смысле это экспертная система, кодифицирующая всю мудрость многих очень умных людей в достаточно закрытой области, чтобы система, основанная на правилах, была эффективной.


Возможно, «Блохи» были бестактными. Меня просят быть менее надменным и напомнили, что математика не лжет. Это правда, но не все значения математических моделей должны обязательно восприниматься буквально. Квадратные корни отрицательных чисел очень удобны, если вы тщательно избегаете проверки их абсурдности (каламбур) и, черт побери, уверены, что все их отменили, прежде чем пытаться интерпретировать свое уравнение.

Причина, по которой я так жестоко отреагировал, заключалась в том, что в заявлении, сформулированном в нем, говорится, что

Соединения являются декартовыми произведениями ...

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

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


Предел для выбора стратегии объединения таблиц может различаться в зависимости от ядра СУБД. На него влияет ряд решений реализации, таких как коэффициент заполнения узла дерева, размер ключа и тонкости алгоритма, но, в широком смысле, высокопроизводительная индексация имеет время выполнения k log n + c . Термин C представляет собой фиксированные накладные расходы, в основном из времени установки, а форма кривой означает, что вы не получите выигрыш (по сравнению с линейным поиском), пока n не исчисляется сотнями.


Иногда хорошая идея денормализации

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

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

Правильно спроектированное хранилище данных периодически создается путем массового преобразования из нормализованной системы обработки транзакций. Такое разделение баз данных об операциях и отчетах имеет очень желательный эффект, так как устраняет конфликт между OLTP и OLAP (оперативная обработка транзакций, т. Е. Ввод данных, и оперативная аналитическая обработка, т. Е. Отчетность).

Важным моментом здесь является то, что помимо периодических обновлений хранилище данных только для чтения . Это ставит под сомнение вопрос об аномалиях обновления.

Не допускайте ошибки в денормализации вашей базы данных OLTP (базы данных, в которой происходит ввод данных). Это может быть быстрее для выставления счетов, но если вы сделаете это, вы получите аномалии обновления. Вы когда-нибудь пытались заставить Reader's Digest прекратить посылать вам материалы?

Дисковое пространство в наши дни дешевое, так что вышибитесь. Но денормализация - это только часть истории хранилищ данных. Гораздо больший прирост производительности получается из предварительно вычисленных свернутых значений: ежемесячные итоги и тому подобное. всегда о сокращении рабочего набора.


Проблема ADO.NET с несоответствиями типов

Предположим, у вас есть таблица SQL Server, содержащая индексированный столбец типа varchar, и вы используете AddWithValue для передачи параметра, ограничивающего запрос к этому столбцу. Строки C # имеют Unicode, поэтому предполагаемый тип параметра будет NVARCHAR, который не соответствует VARCHAR.

VARCHAR в NVARCHAR - это расширяющееся преобразование, поэтому оно происходит неявно, но попрощайтесь с индексацией и удачи в выяснении, почему.


«Подсчитать попадания диска» (Рик Джеймс)

Если все кэшируется в ОЗУ, JOINs довольно дешево. То есть нормализация не имеет большого снижения производительности .

Если «нормализованная» схема приводит к тому, что JOINs часто попадает на диск, но эквивалентная «денормализованная» схема не должна попадать на диск, то денормализация побеждает в конкуренции за производительность.

Комментарий от оригинального автора: современные движки баз данных очень хороши в организации последовательности доступа, чтобы минимизировать пропуски кэша во время операций соединения. Вышеприведенное, хотя и верно, может быть неверно истолковано, поскольку подразумевает, что объединение обязательно проблематично дорого для больших данных. Это может привести к плохому принятию решений со стороны неопытных разработчиков.

43 голосов
/ 06 октября 2008

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

В любом случае стоимость объединения зависит от его типа и нескольких других факторов. Это совсем не обязательно должно быть дорого - несколько примеров.

  • Хеш-соединение, при котором массовые данные равносильны, действительно очень дешево, и стоимость становится значительной, только если хеш-таблица не может быть кэширована в памяти. Индекс не требуется. Равное распределение между объединенными наборами данных может быть очень полезным.
  • Стоимость объединения сортировки-слияния определяется стоимостью сортировки, а не слиянием - метод доступа на основе индекса может практически исключить стоимость сортировки.
  • Стоимость соединения с вложенным циклом в индексе определяется высотой индекса b-дерева и доступом к самому блоку таблицы. Это быстро, но не подходит для массовых объединений.
  • Соединение с вложенным циклом на основе кластера намного дешевле, с меньшим количеством логических операций ввода-вывода, необходимых для каждой строки соединения - если объединенные таблицы находятся в одном и том же кластере, то объединение становится очень дешевым за счет размещения объединенных строк.

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

27 голосов
/ 06 октября 2008

Я думаю, что весь вопрос основан на ложной предпосылке. Соединения на больших столах не обязательно дорогие. Фактически, эффективное объединение является одной из основных причин, по которой реляционные базы данных существуют . Объединения на больших наборах часто дороги, но очень редко вы хотите объединить все содержимое большой таблицы A со всем содержимым большой таблицы B. Вместо этого вы пишете запрос так, что только используются важные строки каждой таблицы, а фактический набор, сохраняемый соединением, остается меньшим.

Кроме того, у вас есть эффективность, упомянутая Питером Воне, так что только важные части каждой записи должны храниться в памяти, пока не будет получен окончательный набор результатов. Кроме того, в больших запросах с большим количеством объединений обычно требуется начинать с небольших наборов таблиц и переходить к большим, чтобы набор, сохраняемый в памяти, оставался как можно меньшим как можно дольше.

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

11 голосов
/ 04 ноября 2008

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

Объединения могут увеличить случайные поиски - если вы прыгаете, читая маленькие части большого стола. Но оптимизаторы запросов ищут это и превращают в последовательное сканирование таблицы (отбрасывая ненужные строки), если считают, что так будет лучше.

Одиночная денормализованная таблица имеет аналогичную проблему - строки большие и поэтому меньше помещаются на одной странице данных. Если вам нужны строки, расположенные далеко друг от друга (а большой размер строки делает их дальше друг от друга), то у вас будет больше случайных операций ввода-вывода. Опять же, сканирование таблицы может быть вынуждено избежать этого. Но на этот раз при сканировании таблицы необходимо прочитать больше данных из-за большого размера строки. Добавьте к этому тот факт, что вы копируете данные из одного местоположения в несколько местоположений, и СУБД имеет гораздо больше информации для чтения (и кэширования).

Имея 2 таблицы, вы также получаете 2 кластеризованных индекса - и, как правило, можете индексировать больше (из-за меньших накладных расходов на вставку / обновление), что может значительно повысить производительность (главным образом, опять же, поскольку индексы (относительно) малы, быстро считывание с диска (или дешевое кэширование) и уменьшение количества строк таблицы, которые необходимо прочитать с диска).

Единственное, что связано с объединением, - это выяснение соответствия строк. Sql Server использует 3 различных типа объединений, в основном на основе размеров набора данных, для поиска подходящих строк. Если оптимизатор выбирает неправильный тип соединения (из-за неточной статистики, неадекватных индексов или просто ошибки оптимизатора или крайнего случая), это может существенно повлиять на время запроса.

  • Соединение циклов очень дешево для (как минимум 1) небольшого набора данных.
  • Соединение слиянием требует сначала обоих наборов данных. Однако если вы присоединяетесь к индексируемому столбцу, то индекс уже отсортирован, и дальнейшая работа не требуется. В противном случае при сортировке возникают некоторые накладные расходы процессора и памяти.
  • Для хеш-соединения требуется как память (для хранения хеш-таблицы), так и процессор (для создания хеша). Опять же, это довольно быстро в отношении дискового ввода-вывода. Однако , если ОЗУ недостаточно для хранения хеш-таблицы, Sql Server будет использовать tempdb для хранения частей хеш-таблицы и найденных строк, а затем обрабатывать только части хеш-таблицы одновременно. Как и для всего диска, это довольно медленно.

В оптимальном случае они не вызывают дискового ввода-вывода и поэтому незначительны с точки зрения производительности.

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

Поскольку время запроса обычно определяется затратами на ввод-вывод, а размер ваших данных не изменяется (за вычетом незначительных накладных расходов на строки) при денормализации, не будет огромной выгоды от простого объединения таблиц вместе. , Тип денормализации, который имеет тенденцию повышать производительность, IME, заключается в кэшировании вычисленных значений вместо чтения 10000 строк, необходимых для их вычисления.

4 голосов
/ 06 октября 2008

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

Для некоторых баз данных это не имеет значения, например, MS SQL большую часть времени знает правильный порядок соединения. Для некоторых (например, IBM Informix) порядок имеет все значение.

0 голосов
/ 20 сентября 2009

Принятие решения о денормализации или нормализации является довольно простым процессом, если принять во внимание класс сложности объединения. Например, я склонен проектировать свои базы данных с нормализацией, когда запросы O (k log n), где k относительно желаемой выходной величины.

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

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

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

0 голосов
/ 06 октября 2008

Разработка того, что сказали другие,

Соединения - это просто декартовы произведения с некоторым блеском для губ. {1,2,3,4} X {1,2,3} даст нам 12 комбинаций (nXn = n ^ 2). Этот вычисленный набор действует как ссылка, к которой применяются условия. СУБД применяет условия (например, где левые и правые равны 2 или 3), чтобы дать нам соответствующие условия. На самом деле он более оптимизирован, но проблема та же. Изменения в размере наборов будут увеличивать размер результата в геометрической прогрессии. Количество потребляемой памяти и циклов ЦП все выражается в экспоненциальной форме.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...