← Все курсы · Курс SQL · Все руководства

Таблица Температура против представления в SQL: сохраненный ответ или сохраненный вопрос

Один из них повторяется каждый раз, когда вы на него смотрите. Другой этого не делает, что является одновременно и особенностью, и риском. · Часть Analyst Prep Kit

К , аналитик данных · Опубликовано

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

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

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

Сохраненный вопрос против сохраненного ответа — это идея, поэтому она отражает картину.

A saved question, or a saved answer A large base table is drawn at the bottom centre as a stack of four wide bars. Above it to the left sits a hollow rounded rectangle with a dashed outline, labelled view, containing nothing at all. Above it to the right sits a solid filled rounded rectangle, labelled temp table, containing four short rows of numbers. A blue arrow enters the hollow view box from the left, passes straight through it and continues down to the base table, showing that reading the view reaches all the way back to the data every time. A separate amber arrow enters the solid temp table box from the right and stops there, because the numbers it wants are already inside. A single faded amber arrow runs upward from the base table into the solid box, drawn much lighter than the others, standing for the one time the temp table was filled. view temp table
Чтение представления каждый раз возвращается к базовой таблице. Чтение временной таблицы останавливается на цифрах, попавших туда когда-то, на блеклой стрелке.
Что вы узнаете
  1. Что каждый из них
  2. Измерение
  3. Торговля свежестью, показанная
  4. Обновление временной таблицы
  5. Только один из них может быть проиндексирован
  6. Область действия: кто еще может это видеть
  7. CTE, временная таблица, представление: что когда
  8. Материализованные представления, которые одновременно
  9. Полное до и после
  10. Пограничные случаи, которые стоит знать
  11. Почему это работает
  12. Использование этого в вашем собственном проекте
  13. Все на одном экране
Каждое число на этой странице было измерено. Таблица заказов из 400 000 строк в SQLite, где агрегат сохраняется один раз в виде представления и один раз как временная таблица, каждая из которых считывается пять раз, при этом сообщается о самом быстром выполнении. Поведение одинаково в Постгрес, MySQL и SQL Server; синтаксические различия отмечены там, где они имеют значение.

1. Что представляет собой каждый из них

Оба созданы из SELECT и оба затем запрашиваются как таблица, и именно поэтому они путаются.

CREATE VIEW v_region AS
  SELECT region, COUNT(*) AS orders, SUM(units*unit_price) AS revenue
  FROM orders GROUP BY region;

CREATE TEMP TABLE t_region AS
  SELECT region, COUNT(*) AS orders, SUM(units*unit_price) AS revenue
  FROM orders GROUP BY region;

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

Прочтите любой из них, и вы получите те же четыре строки:

East  | 100000 | 86499255
North | 100000 | 33500090
South | 100000 | 86999300
West  | 100000 | 68000200

Идентичный вывод, и с этого момента все в них отличается.

2. Измерение

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

SELECT * FROM v_region      467.6 ms
SELECT * FROM t_region        0.0 ms

Четыре ряда в обе стороны. Просмотр занял почти полсекунды, потому что прочитать его — значит запустить GROUP BY более 400 000 строк каждый раз. Создание временной таблицы не заняло никакого измеримого времени, поскольку четыре строки уже находятся там.

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

view        4688.8 ms
temp table     0.2 ms

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

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

3. Показана торговля свежестью

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

the view       North | 100100 | 33600090
the temp table North | 100000 | 33500090

Взгляд заметил. Временная таблица этого не сделала и никогда не сделает, потому что она является копией ответа, который был на момент его создания.

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

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

4. Обновление временной таблицы

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

DELETE FROM t_region;
INSERT INTO t_region
  SELECT region, COUNT(*), SUM(units*unit_price) FROM orders GROUP BY region;

the temp table after the refresh    North | 100100 | 33600090

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

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

5. Индексироваться может только один из них

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

CREATE INDEX ix_t ON t_region(region);      index created
CREATE INDEX ix_v ON v_region(region);      views may not be indexed

Сообщение об ошибке является объяснением. Индекс — это отсортированная структура по хранимым строкам, а в представлении нет сохраненных строк для сортировки. Нечего строить.

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

6. Область действия: кто еще может ее видеть

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

Открытие второго подключения к той же базе данных и запрос каждой из них:

sees the view       : 4 rows
sees the temp table : no such table: t_region

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

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

7. CTE, временная таблица, представление: что когда

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

Живет радиСохраняет строкиМожно индексироватьобщий
CTEОдин запросОбычно нетНетНет
Таблица температурВаша сессияДаДаНет
ВидНавсегдаНетНетДа

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

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

8. Материализованные представления, которые одновременно

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

-- PostgreSQL
CREATE MATERIALIZED VIEW mv_region AS SELECT ... ;
REFRESH MATERIALIZED VIEW mv_region;

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

Поддержка варьируется. PostgreSQL и Оракул имеют их под этим именем. SQL Server имеет индексированные представления, которые обновляются автоматически и имеют ограничения на то, что может содержать запрос. MySQL и SQLite не имеют ни того, ни другого, и стандартный обходной путь — это именно тот шаблон, который описан в четвертом разделе: реальная таблица плюс запланированное задание, которое ее перезагружает.

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

Полное до и после

Та же задача: анализ, который несколько раз считывает региональный агрегат.

До

CREATE VIEW v_region AS SELECT region, COUNT(*), SUM(units*unit_price)
                        FROM orders GROUP BY region;

-- read it ten times over the course of the analysis
4688.8 ms of aggregation, and the numbers can move between reads

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

после

-- the definition, once, shared, always current for anyone who needs that
CREATE VIEW v_region AS SELECT region, COUNT(*) AS orders,
       SUM(units*unit_price) AS revenue FROM orders GROUP BY region;

-- today's frozen copy, for this session's work
CREATE TEMP TABLE t_region AS SELECT * FROM v_region;
CREATE INDEX ix_t ON t_region(region);

-- ten reads
0.2 ms total, and every step of the analysis sees identical numbers

Определение все еще находится в одном месте и до сих пор является общим. Чтение происходит мгновенно. Числа остаются неподвижными на протяжении всего сеанса, а обновление — это два оператора, когда вы хотите, чтобы они переместились.

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

Пограничные случаи, которые стоит знать

Шесть, которые появятся.

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

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

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

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

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

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

Почему это работает

Представление существует по причине, более древней, чем производительность. Реляционная модель отделяет способ хранения данных от способа их представления, поэтому запрос можно записать в стабильной логической форме, в то время как базовые таблицы реорганизуются под ней; именно разделение позволяет определению быть общим и пережить изменения (Кодд, 1970, Коммуникации ACM, 13(6), 377–387). Вот почему представление хранит запрос, а не строки: хранение строк привязывает его к моменту, и весь смысл в том, чтобы быть именем для вывода, а не для результата. 467,6 мс — это цена этой гарантии, и как только вы увидите в этом гарантию, а не неэффективность, выбор между двумя перестанет быть делом вкуса.

Материализованная версия — это признание того, что за гарантию не всегда стоит платить при каждом прочтении. Сохранение результата производного отношения и поддержание его пригодности для использования является хорошо изученной проблемой именно потому, что в тот момент, когда вы его сохраняете, он может не совпадать с таблицами, из которых он получен, и возникает интересный вопрос: как и когда вернуть его в соответствие, а не хранить ли его вообще (Блейкли, Ларсон & Тупой, 1986, Материалы Международной конференции ACM SIGMOD 1986 г. по управлению данными., 61–71). Обновление с двумя утверждениями в четвертом разделе — это его версия, созданная вручную, и причина, по которой его стоит делать сознательно, заключается в том, что альтернативой является не свежесть, а незнание.

Одно замечание в шпаргалке ниже. Он создан для того, чтобы его просматривали и вспоминали, а не перечитывали, поскольку преимущество самотестирования перед повторным изучением проявляется в обзорах реального использования в классе, а не только в контролируемых экспериментах (Янг, Луо, Вадилло, Ю и Шанкс, 2021, Психологический вестник, 147(4), 399–435).

Использование этого в вашем собственном проекте

Переписывание уровня отчетности — это проект. Вместо этого сделайте это по порядку.

  1. Время чтения. Если чтение представления занимает сотни миллисекунд, оно каждый раз выполняет реальную работу, и умножение этого результата на частоту чтения дает вам размер проблемы.
  2. Проверьте представления, созданные на основе представлений. Прежде чем что-либо оптимизировать, прочтите определения двумя уровнями ниже.
  3. Снимок во временную таблицу для любого многоэтапного анализа, в начале, поэтому на каждом шаге отображаются одни и те же числа, и вы можете сказать, из какого момента они взяты.
  4. Индексировать снимок если вы присоединяетесь к нему более одного раза.
  5. Сохраните определение в представлении и загрузите из него временную таблицу., поэтому логика существует один раз.
  6. Там, где движок это поддерживает, попросите материализованное представление с запланированным обновлением и убедитесь, что расписание принадлежит кому-то.

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

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

Все на одном экране

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

вещьЧто он делает
видСохраняет запрос. Ни рядов, ни места.
временная таблицаСохраняет строки, возвращенные запросом, один раз.
Чтение представленияПовторно запускает весь запрос. Здесь 467,6 мс.
Чтение временной таблицыПросто чтение. Фактически ничего.
Десять прочтений4688,8 мс против 0,2 мс.
После изменения данныхПредставление обновляется. Временная таблица этого не делает.
Это правильноПросмотр общего и всегда актуального определения. Температурный стол, чтобы он оставался неподвижным.
ОбновитьDELETE затем INSERT ... SELECT. Два заявления.
ИндексированиеТаблица температур да. Просмотр отклонен: нет строк для сортировки.
ОбъемПросмотр является постоянным и общим. Таблица Температура является частной для сеанса.
Второе соединениеВидит вид. Не видит временную таблицу.
A CTEТолько один запрос. Может быть пересчитан для каждой ссылки.
Выберите CTEТребуется один раз, внутри одного оператора.
Выберите временную таблицуНесколько заявлений, дорогие или не должны двигаться.
Выберите видОпределение, которое используют другие люди, и оно должно быть актуальным.
Материализованный видОба: сохраненные строки, общие, индексируемые, устаревшие до обновления.
Просмотры на просмотрахКаждый слой запускается повторно. Обычная причина медленного уровня отчетности.
Единственная привычка, которую следует сохранить. Сделайте снимок во временной таблице в начале любого анализа, состоящего более чем из двух шагов, и запишите время, когда вы его провели. Внутренняя согласованность ваших собственных запросов важнее, чем актуальность каждого из них по отдельности, а временная метка — это то, что превращает замороженную копию из устаревшей в констатируемый факт. Если промежуточный результат ведет себя не так, как описано на этой странице, существует общая ошибка. шлейф диагностики на предмет застревания.

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

Ссылки

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

SQL для аналитиков это 458 страниц, временные таблицы, представления и CTE по сравнению с их стоимостью и сроком службы.

SQL для аналитиков, 19 $ →
Попрактикуйтесь в выборе между тремя.

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

Откройте набор SQL →