Хэш присоединяется к столбцам Nullable

  1. Пример данных
  2. Соединение двух столов
  3. Соединение трех столов
  4. Изменение типа данных
  5. обходные
  6. Серийное исполнение
  7. Отключение оптимизированных растровых изображений
  8. Включая явный фильтр
  9. Последние мысли
  10. Подтверждения

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

Пример данных

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

С ДЕСЯТЬЮ (N) КАК (ВЫБРАТЬ 1 СОЕДИНЕНИЕ ВСЕ ВЫБРАТЬ 1 СОЮЗ ВСЕ ВЫБРАТЬ 1 СОЮЗ ВСЕ ВЫБРАТЬ 1 СОЮЗ ВСЕ ВЫБРАТЬ 1 СОЮЗ ВСЕ ВЫБРАТЬ 1 СОЮЗ ВСЕ ВЫБРАТЬ 1 СОЮЗ ВСЕ ВЫБРАТЬ 1 СОЮЗ ВСЕ ВЫБРАТЬ 1 СОЮЗ ВСЕ ВЫБРАТЬ 1) ВЫБРАТЬ ТОП (1000000 ) n = IDENTITY (int, 1, 1) INTO dbo. Номера ОТ Десять T10, Десять T100, Десять T1000, Десять T10000, Десять T100000, Десятка T1000000; ALTER TABLE dbo. Числа ADD CONSTRAINT PK_dbo_Numbers_n КЛАВИША PRIMARY CLUSTERED (n) WITH (SORT_IN_TEMPDB = ON, MAXDOP = 1, FILLFACTOR = 100);

Сам пример данных состоит из двух таблиц, T1 и T2. Оба имеют последовательный целочисленный столбец первичного ключа с именем pk и второй обнуляемый столбец с именем c1. Таблица T1 имеет 600 000 строк, где строки с четными номерами имеют то же значение для c1, что и столбец pk, а строки с нечетными номерами равны нулю. Таблица c2 имеет 32 000 строк, где столбец c1 равен NULL в каждой строке. Следующий скрипт создает и заполняет эти таблицы:

СОЗДАТЬ ТАБЛИЦУ dbo. T1 (целое число pk NOT NULL, целое число c1 NULL, CONSTRAINT PK_dbo_T1 КЛАВИША ПЕРВИЧНОГО КЛЮЧА (pk)); СОЗДАТЬ ТАБЛИЦУ dbo. T2 (целое число pk NOT NULL, целое число c1 NULL, CONSTRAINT PK_dbo_T2 КЛАВИША ПЕРВИЧНОГО КЛЮЧА (pk)); Вставить дбо. T1 С (TABLOCKX) (pk, c1) ВЫБРАТЬ N. n, случай, когда n. n% 2 = 1 ТОЛЬКО NULL ИЛИ N. И КОНЕЦ ИЗ ДБО. Числа КАК N, ГДЕ N. n между 1 и 600000; Вставить дбо. T2 С (TABLOCKX) (pk, c1) ВЫБРАТЬ N. n, NULL FROM dbo. Числа КАК N, ГДЕ N. n между 1 и 32000; ОБНОВЛЕНИЕ СТАТИСТИКИ ДБО. T1 с полным сканированием; ОБНОВЛЕНИЕ СТАТИСТИКИ ДБО. T2 с полной проверкой;

Первые десять строк образцов данных в каждой таблице выглядят так:

Соединение двух столов

Этот первый тест включает в себя объединение двух таблиц в столбце c1 (не в столбце pk) и возвращение значения pk из таблицы T1 для строк, которые объединяются:

ВЫБЕРИТЕ T1. ПК ОТ ДБО. T1 AS T1 JOIN. T2 AS T2 ON T2. с1 = т1. с1;

Запрос фактически не возвращает строк, поскольку столбец c1 равен NULL во всех строках таблицы T2, поэтому ни одна строка не может соответствовать предикату равенства. Это может показаться странным, но я уверен, что он основан на реальном производственном запросе (значительно упрощенном для упрощения обсуждения).

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

План выполнения этого простого запроса соединения имеет некоторые интересные особенности. Сначала мы рассмотрим предварительный («оценочный») план в SQL Sentry Plan Explorer :

Предупреждение на значке SELECT просто жалуется на отсутствующий индекс в таблице T1 для столбца c1 (с pk в качестве включенного столбца). Индексное предложение здесь не имеет значения.

Первый реальный интерес в этом плане - это фильтр:

Первый реальный интерес в этом плане - это фильтр:

Этот предикат IS NOT NULL не появляется в исходном запросе, хотя он подразумевается в предикате соединения, как упоминалось ранее. Интересно, что он был разбит как явный дополнительный оператор и помещен перед операцией соединения. Обратите внимание, что даже без фильтра запрос все равно будет давать правильные результаты - само соединение все равно будет отклонять пустые значения.

Фильтр любопытен и по другим причинам. Его предполагаемая стоимость равна нулю (хотя ожидается, что он будет работать на 32 000 строк), и он не был перенесен в сканирование кластерного индекса как остаточный предикат. Оптимизатор обычно очень заинтересован в этом.

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

Мы можем видеть выходные данные выбора плана на основе стоимости (до перезаписи), используя недокументированные флаги трассировки 8607 и знакомый 3604 для направления текстового вывода на консоль (вкладка сообщений в SSMS):

Дерево вывода показывает хеш-соединение, два сканирования и некоторые операторы параллелизма (обмена). В столбце c1 таблицы T2 нет отклоняющего фильтра.

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

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

Второе, и совершенно отдельное, постоптимизационное переписывание отвечает за оператор Bitmap в окончательном плане (вы могли заметить, что он также отсутствовал в выходных данных 8607):

Второе, и совершенно отдельное, постоптимизационное переписывание отвечает за оператор Bitmap в окончательном плане (вы могли заметить, что он также отсутствовал в выходных данных 8607):

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

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

Второй эффект растрового изображения можно увидеть при сканировании кластерного индекса на стороне зонда:

Второй эффект растрового изображения можно увидеть при сканировании кластерного индекса на стороне зонда:

На приведенном выше снимке экрана показано заполненное растровое изображение, проверяемое в рамках сканирования кластерного индекса по таблице T1. Так как исходный столбец является целым числом (bigint также будет работать), проверка растрового изображения помещается в механизм хранения (как указано в квалификаторе INROW), а не проверяется обработчиком запросов. В более общем смысле, битовая карта может применяться к любому оператору на стороне зонда, начиная с обмена. То, насколько далеко обработчик запросов может передать растровое изображение, зависит от типа столбца и версии SQL Server.

Чтобы завершить анализ основных характеристик этого плана выполнения, нам нужно взглянуть на план после выполнения («фактический»):

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

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

Это показывает, что все 32 000 строк из таблицы T2 были обработаны одним потоком. Чтобы понять почему, нам нужно взглянуть на свойства exchange:

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

В параллельном плане в режиме строки SQL Server достигает этого, перераспределяя оба входа, используя одну и ту же хэш-функцию в столбцах соединения. В данном случае объединение выполняется в столбце c1, поэтому входные данные распределяются по потокам путем применения хэш-функции (тип разделения: hash) к столбцу ключа объединения (c1). Проблема здесь заключается в том, что столбец c1 содержит только одно значение - нулевое - в таблице T2, поэтому всем 32 000 строк присваивается одинаковое значение хеш-функции, поскольку все они попадают в один и тот же поток.

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

Соединение трех столов

Для второго теста мы добавляем дополнительное соединение из таблицы T2 к себе на его первичный ключ:

ВЫБЕРИТЕ T1. ПК ОТ ДБО. T1 AS T1 JOIN. T2 AS T2 ON T2. с1 = т1. c1 ПРИСОЕДИНЯЙТЕСЬ к dbo. T2 AS T3 - новый! НА Т3. рк = Т2. рк;

Это не меняет логических результатов запроса, но меняет план выполнения:

Как и ожидалось, самообъединение таблицы T2 по ее первичному ключу не влияет на количество строк, соответствующих этой таблице:

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

Обращаясь к более интересному разделу предполагаемого плана, есть некоторые отличия от теста с двумя таблицами:

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

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

Объяснение этому связано со вторым отличием - битмап изменился, хотя это не очевидно из рисунка выше:

Это Opt_Bitmap, а не Bitmap. Разница в том, что это растровое изображение было введено во время оптимизации на основе затрат, а не путем переписывания в последнюю минуту. Механизм, который учитывает оптимизированные растровые изображения, связан с обработкой запросов типа «звезда». Логика объединения звезд требует как минимум трех соединенных таблиц, поэтому это объясняет, почему в примере объединения двух таблиц не было рассмотрено оптимизированное растровое изображение.

Это оптимизированное растровое изображение имеет ненулевую оценочную стоимость ЦП и напрямую влияет на общий план, выбранный оптимизатором. Его влияние на оценку мощности на стороне зонда можно увидеть у оператора Repartition Streams:

Обратите внимание, что на обмене наблюдается эффект кардинальности, даже несмотря на то, что растровое изображение в конечном итоге выталкивается полностью в механизм хранения («INROW»), как мы видели в первом тесте (но обратите внимание на ссылку Opt_Bitmap сейчас):

План после исполнения («фактический») выглядит следующим образом:

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

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

Изменение типа данных

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

ALTER TABLE dbo. T1 ALTER COLUMN c1 десятичный (9, 0) NULL; ALTER TABLE dbo. T2 ALTER COLUMN c1 десятичный (9, 0) NULL; ALTER INDEX PK_dbo_T1 ON dbo. T1 REBUILD WITH (MAXDOP = 1); ALTER INDEX PK_dbo_T2 ON dbo. T2 REBUILD WITH (MAXDOP = 1); ОБНОВЛЕНИЕ СТАТИСТИКИ ДБО. T1 с полным сканированием; ОБНОВЛЕНИЕ СТАТИСТИКИ ДБО. T2 с полной проверкой;

Повторное использование запроса на три объединения:

ВЫБЕРИТЕ T1. ПК ОТ ДБО. T1 AS T1 JOIN. T2 AS T2 ON T2. с1 = т1. c1 ПРИСОЕДИНЯЙТЕСЬ к dbo. T2 AS T3 ON T3. рк = Т2. рк;

Предполагаемый план выполнения выглядит очень знакомым:

Помимо того факта, что оптимизированное растровое изображение больше не может быть применено «INROW» механизмом хранения из-за изменения типа данных, план выполнения по существу идентичен. На снимке ниже показано изменение свойств сканирования:

К сожалению, производительность довольно сильно пострадала. Этот запрос выполняется не за 70 или 200 мс, а за 20 минут . В тесте, который дал следующий план после выполнения, время выполнения составило 22 минуты и 29 секунд:

Наиболее очевидное отличие состоит в том, что сканирование кластеризованного индекса в таблице T1 возвращает 300 000 строк даже после применения оптимизированного фильтра растровых изображений. Это имеет некоторый смысл, поскольку растровое изображение построено на строках, которые содержат только нули в столбце c1. Растровое изображение удаляет ненулевые строки из сканирования T1, оставляя только 300 000 строк с нулевыми значениями для c1. Помните, что половина строк в T1 равна нулю.

Несмотря на это, кажется странным, что объединение 32 000 строк с 300 000 строк должно занять более 20 минут. В случае, если вам интересно, одно ядро ​​процессора было привязано к 100% для всего выполнения. Объяснение этой низкой производительности и чрезмерного использования ресурсов основывается на некоторых идеях, которые мы исследовали ранее:

Например, мы уже знаем, что, несмотря на значки параллельного выполнения, все строки из T2 оказываются в одном потоке. Напомним, что параллельное хеш-соединение в режиме строки требует перераспределения в столбцах соединения (c1). Все строки из T2 имеют одинаковое значение - ноль - в столбце c1, поэтому все строки попадают в один и тот же поток. Точно так же все строки из T1, которые проходят фильтр точечного рисунка, также имеют ноль в столбце c1, поэтому они также перераспределяются в один и тот же поток. Это объясняет, почему одно ядро ​​выполняет всю работу.

Может показаться неоправданным, что хеш-соединение, объединяющее 32 000 строк с 300 000 строк, должно занять 20 минут, тем более что столбцы соединения с обеих сторон имеют нулевое значение и не будут объединяться в любом случае. Чтобы понять это, нам нужно подумать о том, как работает это хеш-соединение.

Входные данные сборки (32 000 строк) создают хеш-таблицу с использованием столбца соединения c1. Поскольку каждая строка на стороне сборки содержит одно и то же значение (ноль) для столбца соединения c1, это означает, что все 32 000 строк оказываются в одном и том же блоке хэша. Когда хеш-соединение переключается на проверку совпадений, каждая строка на стороне зондирования с нулевым столбцом c1 также хэшируется в один и тот же сегмент. Хеш-соединение должно затем проверить все 32 000 записей в этом сегменте на совпадение.

Проверка 300 000 рядов зондов приводит к 32 000 сравнений, выполненных 300 000 раз. Это наихудший случай для хеш-соединения: все строки на стороне компоновки хэшируются в одно и то же ведро, в результате чего получается, по сути, декартово произведение. Это объясняет длительное время выполнения и постоянную 100% загрузку процессора, поскольку хэш следует длинной цепочке сегментов хэша.

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

обходные

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

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

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

Серийное исполнение

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

ВЫБЕРИТЕ T1. pk ОТ (dbo. T2 AS T2 JOIN. DBO. T2 AS T3 ON T3. pk = T2. pk) JOIN dbo. T1 AS T1 ON T1. с1 = т2. c1 ВАРИАНТ (MAXDOP 1, FORCE ORDER);

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

Этот примерный план показывает восстановление фильтра перезаписи после оптимизации:

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

Как и следовало ожидать, эта версия запроса выполняется очень быстро - в среднем около 20 мс для меня. Мы можем добиться аналогичного эффекта без подсказки FORCE ORDER и переписывания запроса:

ВЫБЕРИТЕ T1. ПК ОТ ДБО. T1 AS T1 JOIN. T2 AS T2 ON T2. с1 = т1. c1 ПРИСОЕДИНЯЙТЕСЬ к dbo. T2 AS T3 ON T3. рк = Т2. ОПЦИЯ ПК (MAXDOP 1);

В этом случае оптимизатор выбирает другую форму плана с фильтром, расположенным непосредственно над сканированием T2:

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

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

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

ВЫБЕРИТЕ T1. ПК ОТ ДБО. T1 AS T1 JOIN. T2 AS T2 ON T2. с1 = т1. c1 ПРИСОЕДИНЯЙТЕСЬ к dbo. T2 AS T3 ON T3. рк = Т2. ПК ОПЦИЯ (QUERYTRACEON 7497, QUERYTRACEON 7498);

Результирующий план выполнения:

Битовая карта - это битовая карта перезаписи постоптимизации, а не оптимизированная битовая карта:

Обратите внимание на нулевую оценку стоимости и имя растрового изображения (а не Opt_Bitmap). без оптимизированного растрового изображения для искажения оценок затрат активируется перезапись после оптимизации с включением фильтра отклонения нуля. Этот план выполнения занимает около 70 мс .

Тот же план выполнения (с фильтром и неоптимизированным растровым изображением) также можно создать, отключив правило оптимизатора, отвечающее за создание растровых планов соединения типа «звезда» (опять же, строго недокументированное и не для реального использования):

ВЫБЕРИТЕ T1. ПК ОТ ДБО. T1 AS T1 JOIN. T2 AS T2 ON T2. с1 = т1. c1 ПРИСОЕДИНЯЙТЕСЬ к dbo. T2 AS T3 ON T3. рк = Т2. pk OPTION (QUERYRULEOFF StarJoinToHashJoinsWithBitmap);

Включая явный фильтр

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

ВЫБЕРИТЕ T1. ПК ОТ ДБО. T1 AS T1 JOIN. T2 AS T2 ON T2. с1 = т1. c1 ПРИСОЕДИНЯЙТЕСЬ к dbo. T2 AS T3 ON T3. рк = Т2. ПК ГДЕ Т2. с1 НЕ НУЛЬ; - Новый!

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

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

План после исполнения:

Обратите внимание, что Merge Join завершает работу после чтения одной строки с ее верхнего входа, а затем не может найти строку на своем нижнем входе из-за эффекта предиката, который мы добавили. Сканирование кластеризованного индекса таблицы T1 никогда не выполняется вообще, поскольку объединение Nested Loops никогда не получает строки на своем входном входе. Эта окончательная форма запроса выполняется за одну или две миллисекунды.

Последние мысли

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

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

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

На данный момент лучший вариант, похоже, знает об этой потенциальной проблеме производительности с хэш-соединениями в пустых столбцах, а также добавлять явные отклоняющие нулевые предикаты (с комментарием!), Чтобы при необходимости создать эффективный план выполнения. Использование подсказки MAXDOP 1 может также выявить альтернативный план с присутствующим контрольным фильтром.

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

Подтверждения

Я хочу поблагодарить SQL_Sasquatch ( @sqL_handLe ) за его разрешение ответить на его оригинальная статья с техническим анализом. Используемые здесь примеры данных в значительной степени основаны на этой статье.

Я также хочу поблагодарить Роба Фарли ( блог | щебет ) за наши технические обсуждения в течение многих лет, особенно в январе 2015 года, где мы обсуждали последствия дополнительных нулевых отклоняющих предикатов для равных объединений. Роб писал о смежных темах несколько раз, в том числе в Обратные предикаты - смотри в обе стороны, прежде чем пересечься ,

Похожие

3 типа результатов SEO
Если у вас есть бизнес, вам нужно, чтобы о нем знали люди, а с интернетом это сделать проще, чем когда-либо! Социальные сети и маркетинг по электронной почте являются удивительными инструментами в вашем распоряжении, но одна из ваших целей номер один должна попасть в список поисковых систем. Прежде чем нанять компанию SEO или попытайтесь сделать SEO самостоятельно, убедитесь, что вы знаете различные доступные
Ценность внутреннего SEO
За последнее десятилетие SEO превратилось в сложную область, затрагивающую UX, контент-маркетинг и даже веб-разработку. В то же время, широкий спектр организаций в настоящее время полностью используют Интернет; тем не менее, они часто не рассматривают возможность привлечения специалистов по SEO. Основываясь на разговорах с коллегами, все сводится к тому, что организациям не хватает приверженности C-suite и / или
Оптимизировать SEO изображений на Wordpress
Изображения выдвинуты При создании или редактировании статьи, нажимая на небольшую пиктограмму справа от «Отправить / вставить», вы можете добавлять различные медиафайлы, включая традиционные иллюстрации контента, как показано ниже.
6.4. Пометьте подписанные изображения с помощью и
Вы находитесь в: добро пожаловать > AcceDe Web records > Руководство по доступности HTML, CSS и JavaScript > 6. Изображения и значки > 6.4. Помечать подписанные изображения тегами <figure role
17.4 Изменение уровня моря - Физическая геология
Изменение уровня моря было характерной чертой Земли на протяжении миллиардов лет, и оно имеет важные последствия для прибрежных процессов, а также для эрозионных и осадочных особенностей. Существует три основных механизма изменения уровня моря, как описано ниже. Эустатические изменения уровня моря - это глобальные изменения уровня моря, связанные либо с изменениями объема ледникового льда на суше, либо с изменениями формы морского дна, вызванными тектоническими
Импорт данных из других плагинов WordPress SEO
Импорт данных из ваших ранее использованных плагинов SEO может быть раздражающим и занимать много времени. Вот почему мы встроили простую функцию импорта в BAVOKO SEO Tools, которая позволяет мгновенно интегрировать существующие записи из плагинов SEO, которые вы использовали до сих пор. BAVOKO SEO Tools уже может импортировать данные из следующих плагинов: Все в одном SEO SEO SEO Squirrly добавить метатеги Headspace2 Platinum SEO SEO Ultimate Yoast SEO WP Meta SEO
Время для другого обновления алгоритма Google
Похоже, это снова. В прошлую среду Google объявил, что запускает очередное обновление основного алгоритма. Как и в случае со всеми их обновлениями, не было предоставлено никакой информации о том, что именно изменилось или как это повлияет на результаты поиска. В этом объявление в твиттере Google буквально ретвитнул их ответ, когда в апреле было выпущено обновление ядра. Таким образом, с этим не было никакой новой
утилита seourlkeywordgen
Когда вы устанавливаете функцию поисковой оптимизации для создания более коротких URL, дружественных к SEO, WebSphere Commerce нужны ключевые слова SEO для страниц товаров и категорий магазина. Утилита seourlkeywordgen создает эти ключевые слова SEO на основе имени объекта. Утилита seourlkeywordgen запускает запрос, который ищет CATGROUP стол и
Как одна статья в Medium собрала $ 60 000: пример из практики
После нескольких часов встреч, когда мои глаза покраснели от бессонницы, они внезапно поразили меня. Мне не нужен совет, торгуемый так называемыми "специалистами по маркетингу". Вам не нужно быть влиятельным / консультантом ICO, чтобы достичь этого Органический охват длинного хвоста недооценен Вам не нужно быть действительно хорошим в этом
Как предотвратить отображение данных DMOZ в ваших фрагментах в результатах поиска?
Мелани Валь - январь 2012 Последнее сообщение Google для веб-мастеров в Центральном блоге под названием Лучшие заголовки страниц в результатах поиска охватывает основы того, как генерируются заголовки и описания страниц (так называемые фрагменты). Несколько вещей, на которые стоит обратить
SEO изображений: все, что вам нужно знать • Houndstooth Media Group
Мы говорили о как сделать Google счастливым в предыдущем посте. Сегодня мы углубляемся в SEO изображений. Что вы можете сделать, чтобы ваши изображения появлялись в результатах

Комментарии

Теперь вы можете задаться вопросом: «Является ли хранение аналитических данных в моей базе данных WordPress хорошей идеей?
Теперь вы можете задаться вопросом: «Является ли хранение аналитических данных в моей базе данных WordPress хорошей идеей?». Это хороший вопрос. Послушайте, я не разработчик, поэтому я не хочу давать здесь однозначный ответ. Но, по словам команды Slimstat, для хранения 10 000 записей требуется всего 10 МБ, что не кажется мне ужасным, если учесть, что ваш сайт не получает 100 000 посещений в месяц. Для
Мы можем даже найти исследования, такие как это , которые показывают эффект поисковых запросов типа «Во сколько суперкубок?
Теперь вы можете задаться вопросом: «Является ли хранение аналитических данных в моей базе данных WordPress хорошей идеей?». Это хороший вопрос. Послушайте, я не разработчик, поэтому я не хочу давать здесь однозначный ответ. Но, по словам команды Slimstat, для хранения 10 000 записей требуется всего 10 МБ, что не кажется мне ужасным, если учесть, что ваш сайт не получает 100 000 посещений в месяц. Для
Какие свойства фрагмента для какого типа?
Какие свойства фрагмента для какого типа? Формы представления богатых фрагментов разнообразны. Существуют разные свойства в зависимости от типа информации. Но не каждая часть информации имеет смысл с использованием богатых фрагментов: в зависимости от того, для какого типа информации должны создаваться обогащенные фрагменты, важно учитывать, какая информация предоставляет пользователям наибольшую ценность. Следует отметить, что тип информации может иметь несколько свойств, которые могут применяться
Пример?
Пример? Вы отель в Портофино. Их много, времени пользователей при поиске идеального места для их отпуска очень мало и огромное предложение. Если вы попытаетесь позиционировать себя в отеле Portofino, вы увидите 19 тысяч результатов. Прибавляя специфичность к вашему позиционированию, с одной стороны вы столкнетесь с гораздо меньшими результатами, с другой - вы лучше достигнете своей ниши, которая уже решила, чего хочет. Отель Портофино 5-звездочный
Более описательный первый пример или второй?
Мы возьмем тривиальный пример? Давайте возьмем музыку . С помощью инструмента анализа ключевых слов общий давайте посмотрим объем исследования и результаты. 165 000, а также 1,5 миллиарда результатов. Конкуренция становится жесткой, не так ли? Если мы немного «растянем» хвосты в поисках рок-музыки , мы найдем объем поиска 4400 и 38,1 миллиона результатов, что неплохо.
Пример: в SEO-анализе после успешного перезапуска вы обнаружите серьезные проблемы, которые не могут быть решены в краткосрочной перспективе - что сейчас?
Пример: в SEO-анализе после успешного перезапуска вы обнаружите серьезные проблемы, которые не могут быть решены в краткосрочной перспективе - что сейчас? Одной из возможностей будет откат - восстановить сайт до перезапуска. Технически откат не является проблемой, но с точки зрения SEO, как правило, нет, потому что требуется много изменений - особенно исправление перенаправлений. Если вам нужно серьезно подумать об откате, вы должны включить SEO как можно скорее, потому что раньше, чем позже.
1. Слово «логин» является сильным показателем того, какого типа намерения веб-поисковика?
1. Слово «логин» является сильным показателем того, какого типа намерения веб-поисковика? навигационный информационный транзакционный коммерческий Все вышеперечисленное 2. Если веб-поисковик вводит ключевое слово «фото Бенджамина Франклина» (без кавычек) в поле поиска, этот тип запроса классифицируется как: навигационный информационный транзакционный
Хотите получить больше советов по организации кампании такого типа?
Хотите получить больше советов по организации кампании такого типа? Не стесняйтесь обращаться к нам. Что такое трендовая тема? «Актуальная тема» - это тема или тема, которая создает новости в течение определенного периода, например, «Черная пятница» или «Корпоративный день». Первоначально «Темы тенденций» были запущены в 1992 году Бельгийской ассоциацией газетных издателей, которая распространяла новости через рекламные объявления в газетах.
Не уверены, стоит ли выделять последние или избранные сообщения?
Не уверены, стоит ли выделять последние или избранные сообщения? Запустите A / B-тест и посмотрите, какие виджеты читают посетители. Не уверены, что ваши избранные сообщения нуждаются в миниатюре? Попробуй без и посчитай клики. Независимо от того, хотите ли вы увеличить время, которое читатели проводят на вашем сайте, или узнать, как быстро вы можете отправить их в свой магазин, A / B-тестирование - лучший способ убедиться, что ваши виджеты работают на вас. A / B-тестирование может быть
Есть ли на вашем сайте страница, где вы публикуете последние скидки и купоны или говорите о бесплатной доставке?
Есть ли на вашем сайте страница, где вы публикуете последние скидки и купоны или говорите о бесплатной доставке? Если нет, вам следует рассмотреть вопрос о создании кампании с промо-кодом, целевой страницы и ссылок из всей навигации сайта (или, по крайней мере, нижнего колонтитула). По моему опыту, Google хочет дать рейтинг страницы купона бренда над RetailMeNots мира. Если вы создадите полуприличную промо или кодовую страницу купона, скорее всего, ваш сайт займет первое место
Но кто на самом деле проверял их влияние в последние годы?
Но кто на самом деле проверял их влияние в последние годы? Здесь я был бы очень признателен за ссылки на тесты. Дискуссии по оценке ссылок с 2012 года Inside Search внес вклад в качество страницы в 2012 году, и ссылки также были проблемой: Оценка ссылки. Мы часто используем характеристики ссылок, чтобы помочь нам разобраться в теме связанной страницы. Мы изменили способ оценки ссылок; в частности, мы отключаем метод анализа ссылок, который мы использовали

Теперь вы можете задаться вопросом: «Является ли хранение аналитических данных в моей базе данных WordPress хорошей идеей?
Теперь вы можете задаться вопросом: «Является ли хранение аналитических данных в моей базе данных WordPress хорошей идеей?
Какие свойства фрагмента для какого типа?
Пример?
Мы возьмем тривиальный пример?
Конкуренция становится жесткой, не так ли?
Пример: в SEO-анализе после успешного перезапуска вы обнаружите серьезные проблемы, которые не могут быть решены в краткосрочной перспективе - что сейчас?
Пример: в SEO-анализе после успешного перезапуска вы обнаружите серьезные проблемы, которые не могут быть решены в краткосрочной перспективе - что сейчас?
1. Слово «логин» является сильным показателем того, какого типа намерения веб-поисковика?
1. Слово «логин» является сильным показателем того, какого типа намерения веб-поисковика?