Ответ 1
Денормализация для повышения производительности? Это звучит убедительно, но в нем нет воды.
Крис Дай, который в компании с д-ром Тедом Коддом был оригинальным сторонником реляционной модели данных, закончил терпение с дезинформированными аргументами против нормализации и систематически уничтожил их с помощью научного метода: он получил большие базы данных и протестировал эти утверждения.
Я думаю, что он написал это в Relational Database Writings 1988-1991, но эта книга была позже переведена в 6-ю версию "Введение в системы баз данных", которая является окончательным текстом по теории и дизайну базы данных, в ее восьмом издании, когда я пишу и вероятно, останется в печати на десятилетия вперед. Крис Дай был экспертом в этой области, когда большинство из нас все еще бегало по босиком.
Он обнаружил, что:
- Некоторые из них сохраняются для особых случаев
- Все они не могут окупиться для общего использования.
- Все они значительно хуже для других особых случаев.
Все возвращается к уменьшению размера рабочего набора. Соединения, связанные с правильно выбранными ключами с правильно настроенными индексами, являются дешевыми, не дорогостоящими, поскольку они позволяют значительно сократить результат до того, как строки будут реализованы.
Материализация результата включает в себя объемные чтения дисков, которые являются самым дорогим аспектом упражнения на порядок. Выполнение соединения, напротив, логически требует поиска только ключей. На практике даже не выбираются значения ключа: значения хеш-ключа используются для сопоставлений соединений, уменьшения стоимости объединения нескольких столбцов и радикального уменьшения стоимости объединений, связанных с сопоставлениями строк. Мало того, что он будет гораздо больше поместиться в кеш, там гораздо меньше чтения диска.
Кроме того, хороший оптимизатор выберет наиболее ограничительное условие и применит его до того, как он выполнит соединение, очень эффективно используя высокую избирательность объединений по индексам с высокой мощностью.
Правда, этот тип оптимизации также может быть применен к денормализованным базам данных, но люди, которые хотят денормализовать схему, обычно не думают о мощности, когда (если) они устанавливают индексы.
Важно понимать, что сканирование таблиц (рассмотрение каждой строки в таблице в процессе создания соединения) редко на практике. Оптимизатор запросов выбирает сканирование таблицы только тогда, когда выполняется одно или несколько из следующих действий.
- Менее 200 строк в соотношении (в этом случае сканирование будет дешевле)
- В столбцах объединения нет подходящих индексов (если это целесообразно для присоединения к этим столбцам, то почему они не индексируются? исправить).
- Для сопоставления столбцов требуется принуждение типа (WTF?! исправить или вернуться домой) СМ. КОНЕЦ ПРИМЕЧАНИЯ ДЛЯ ВЫДАЧИ ADO.NET
- Одним из аргументов сравнения является выражение (без индекса)
Выполнение операции более дорогое, чем не выполнение. Тем не менее, выполнение неправильной операции, принуждение к бессмысленным дисковым ввода-выводам, а затем отбрасывание шлака перед выполнением соединения, которое вам действительно нужно, намного дороже. Даже когда "неправильная" операция предварительно вычисляется, и показатели были разумно применены, остается значительное наказание. Денормализация для предкоммутации соединения - невзирая на аномалии обновления, - это приверженность конкретному соединению. Если вам нужно другое соединение, это обязательство будет стоить вам дорого.
Если кто-то хочет напомнить мне, что это меняющийся мир, я думаю, вы обнаружите, что более крупные наборы данных на более грубом оборудовании просто преувеличивают распространение результатов Date.
Для всех, кто работает с биллинговыми системами или генераторами нежелательной почты (стыдно за вас), и с негодованием настраивает руку на клавиатуру, чтобы сказать мне, что вы знаете, что денормализация выполняется быстрее, извините, но вы живете в одном особых случаев - в частности, случай, когда вы обрабатываете все данные в порядке. Это не общий случай, и вы оправданы в своей стратегии.
Вы не оправдались в ложном обобщении. Дополнительную информацию о надлежащем использовании денормализации в сценариях хранилищ данных см. В конце раздела примечаний.
Я также хотел бы ответить на
Соединения - это просто декартовы продукты с некоторым блеском для губ
Что за груз. Ограничения применяются как можно раньше, наиболее ограничительные. Вы прочитали теорию, но вы ее не поняли. Соединения рассматриваются как "декартовы продукты, к которым применяются предикаты" только с помощью оптимизатора запросов. Это символическое представление (фактически, нормализация) для облегчения символической декомпозиции, поэтому оптимизатор может производить все эквивалентные преобразования и ранжировать их по стоимости и избирательности, чтобы он мог выбрать лучший план запроса.
Единственный способ получить оптимизатора для создания декартова продукта - это не дать предикат: SELECT * FROM A,B
Примечания
Дэвид Олдридж предоставляет важную информацию.
Существует множество других стратегий, помимо индексов и табличных сканирований, и современный оптимизатор будет стоить им всех до составления плана выполнения.
Практический совет: если его можно использовать в качестве внешнего ключа, то проиндексируйте его, чтобы стратегия оптимизации была доступна оптимизатору.
Я был умнее, чем оптимизатор MSSQL. Это изменило две версии назад. Сейчас он учит меня вообще. Это, в очень реальном смысле, экспертная система, кодирующая всю мудрость многих очень умных людей в достаточно закрытом домене, который эффективен на основе правил.
"Bollocks", возможно, был бестактным. Меня просят быть менее надменным и напомнили, что математика не лжет. Это верно, но не все последствия математических моделей обязательно должны восприниматься буквально. Квадратные корни отрицательных чисел очень удобны, если вы старательно избегаете рассматривать их абсурдность (каламбур там) и чертовски уверены, что вы отмените их все, прежде чем пытаться интерпретировать свое уравнение.
Причина, по которой я так жестоко отреагировала, заключалась в том, что в заявлении, сформулированном в тексте, говорится, что
Соединения являются декартовыми произведениями...
Возможно, это не то, что было предназначено, но это то, что было написано, и оно категорически не соответствует действительности. Декартовой продукт - это отношение. Соединение - это функция. Более конкретно, объединение является функцией отношения. С пустым предикатом он произведет декартовой продукт и проверяет, что он делает это, является одной проверкой правильности для механизма запросов к базе данных, но на практике никто не пишет неограниченное объединение, поскольку они не имеют практического значения вне класса.
Я назвал это, потому что я не хочу, чтобы читатели попадали в древнюю ловушку, смешивая модель с моделью. Модель - это приближение, специально упрощенное для удобной манипуляции.
Отключение для выбора стратегии объединения таблицы-сканирования может варьироваться в зависимости от механизмов базы данных. На него влияют ряд решений, таких как tree- node fill-factor, размер ключа и тонкости алгоритма, но в целом высокопроизводительная индексация имеет время выполнения k log n + c. Термин C - это фиксированные накладные расходы, в основном выполненные из времени установки, а форма кривой означает, что вы не получаете выигрыш (по сравнению с линейным поиском), пока n не окажется в сотнях.
Иногда денормализация - хорошая идея
Денормализация - это приверженность конкретной стратегии объединения. Как упоминалось ранее, это мешает другим стратегиям объединения. Но если у вас есть ведра дискового пространства, предсказуемые шаблоны доступа и тенденция обрабатывать много или все из них, то предварительная компиляция соединения может быть очень полезной.
Вы также можете определить пути доступа, которые обычно используются вашей операцией, и прекомпилировать все соединения для этих путей доступа. Это предпосылка для хранилищ данных, или, по крайней мере, это когда они создаются людьми, которые знают, почему они делают то, что делают, а не только ради соответствия правилам.
Правильно спроектированный хранилище данных периодически создается массовым преобразованием из нормализованной системы обработки транзакций. Такое разделение баз данных операций и отчетов имеет очень желательный эффект от устранения столкновения между OLTP и OLAP (обработка онлайн-транзакций, т.е. ввод данных и онлайн-аналитическая обработка, т.е. отчетность).
Важным моментом здесь является то, что помимо периодических обновлений хранилище данных считывается только. Это вызывает спорный вопрос об аномалиях обновления.
Не делайте ошибки денормализации вашей базы данных OLTP (база данных, на которой происходит запись данных). Это может быть быстрее для биллинга, но если вы это сделаете, вы получите аномалии обновления. Когда-либо пытались заставить Reader Digest перестать отправлять вам материал?
В наши дни дисковое пространство дешево, поэтому выбивайте себя. Но денормализация является лишь частью истории для хранилищ данных. Значительно большие выигрыши в производительности производятся от предварительно вычисленных свернутых значений: ежемесячных итогов, таких вещей. Это всегда о сокращении рабочего набора.
Проблема ADO.NET с несоответствиями типов
Предположим, что у вас есть таблица SQL Server, содержащая индексированный столбец типа varchar, и вы используете AddWithValue для передачи параметра, ограничивающего запрос в этом столбце. Строки С# являются Unicode, поэтому тип выводимого параметра будет NVARCHAR, который не соответствует VARCHAR.
VARCHAR для NVARCHAR - это расширяющееся преобразование, поэтому оно происходит неявно - но попрощаться с индексированием, и удачи в том, чтобы решить, почему.
"Подсчитайте образы дисков" (Рик Джеймс)
Если все кэшируется в ОЗУ, JOINs
довольно дешево. То есть нормализация не имеет большого штрафа за производительность.
Если "нормализованная" схема приводит к тому, что JOINs
попадает на диск много, но эквивалентная "денормализованная" схема не должна попадать на диск, тогда денормализация выигрывает конкуренцию за производительность.
Комментарий от автора: Современные двигатели баз данных очень хорошо разбираются в последовательности доступа, чтобы минимизировать промахи в кэше во время операций объединения. Вышеизложенное, хотя и верно, может быть ошибочным, поскольку подразумевает, что соединения на больших данных неизбежно являются дорогостоящими. Это может привести к плохому принятию решений со стороны неопытных разработчиков.