Повышение эффективности добавления столбца с одним значением

Экспериментально и неожиданно я обнаружил, что LEFT JOINING в таблице точек намного быстрее на больших таблицах, чем простое назначение одного значения столбцу. Под таблицей я имею в виду таблицу 1x1 (1 строка и 1 столбец).

Подход 1. С помощью простого присваивающего значения я имею в виду это (медленнее):

SELECT A.*, 'Value' as NewColumn,
FROM Table1 A

Подход 2.. По левому соединению с точкой-таблицей я имею в виду это (быстрее):

WITH B AS (SELECT 'Value' as 'NewColumn')
SELECT * Table1 A
LEFT JOIN B
ON A.ID <> B.NewColumn

Теперь ядро ​​моего вопроса. Может кто-нибудь посоветует мне, как избавиться от всего предложения ON:

ON A.ID <> B.NewColumn?

Проверка условия соединения кажется ненужной тратой времени, потому что ключ таблицы A не должен равняться ключу таблицы B. Он выкидывал строки из результатов, если t1.ID имел то же значение, что и "Значение". Удаление этого условия или, возможно, изменение знака <> на =, кажется дополнительным пространством для облегчения производительности соединения.

Обновление 23 февраля 2015 г. Вопрос о баунти адресован специалистам по эффективности. Какой из подходов, упомянутых в моем вопросе и ответах, является самым быстрым. Подход 1 Простое присвоение значения, Подход 2 Левое соединение таблицы точек, Подход 3 Крест, соединяющий столик (благодаря ответу Гордона Линоффа) Подход 4 Любой другой подход, который может быть предложен в течение периода награды. Поскольку я измерил эмпирическое время выполнения запроса в секундах 3 подхода - второй подход с LEFT JOIN является самым быстрым. Затем метод CROSS JOIN, а затем, наконец, просто присвоить значение. Удивительно, как есть. Эксперт с мечом Соломона необходим для подтверждения или отрицания этого.

6 ответов

Я удивлен, что это быстрее для простого выражения, но вам, похоже, нужен cross join:

WITH B AS (SELECT 'Value' as NewColumn)
SELECT *
FROM Table1 A CROSS JOIN
 B;

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


Можете ли вы попытаться вставить в временную таблицу вместо вывода на экран:

SELECT A.*, 'Value' as NewColumn
INTO #Table1Assign
FROM Table1 A

и

WITH B AS (SELECT 'Value' as 'NewColumn')
SELECT * Table1 A
INTO #Table1Join
LEFT JOIN B
ON A.ID <> B.NewColumn

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

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


Слишком много текста для комментария, поэтому добавил это как ответ, хотя я на самом деле больше добавляю к вопросу (**)

Каким-то образом я думаю, что это будет одна из таких ситуаций. Я думаю, что это зависит от количества задействованных строк и даже больше от того, что происходит потом с данными. Он просто возвращается, используется ли он в GROUP BY или DISTINCT позже, мы далее JOIN или вычисляем с ним и т.д.

Во всяком случае, я думаю, что это интересный вопрос в том, что мне пришлось найти трудный способ, чтобы иметь десяток "параметров" в однострочной temp-таблице было быстрее, чем присвоить им до 12 переменных, Много-много лет назад код, который мне был предоставлен, выглядел как абсурдная конструкция для меня, поэтому я переписал его, чтобы вместо этого использовать @variables. Это было в хранимой процедуре + 1000 строк, которая требовала некоторой дополнительной производительности, вытесненной из нее. После довольно много рефакторинга оказалось, что он работает значительно медленнее, чем до изменения?!?!!

Я никогда не понимал, почему и в то время снова возвращался к старой версии. Мое лучшее предположение - это какая-то странная комбинация статистики параметризации-обнюхивания vs (автоматически созданная?) В рассматриваемой временной таблице; если бы кто-нибудь мог принести свет вашему вопросу, он, вероятно, также приведет к моему ответу =)

(**: Я понимаю, что SO не является форумом, поэтому я извиняюсь заранее, просто хотел услышать, что наблюдаемое поведение OP не совсем анекдотично)


Select * не использует индексы должным образом на SQL, вы всегда должны указывать свои столбцы.

Помимо этого я бы использовал

DECLARE @Value VARCHAR(30) = 'Value'
SELECT t.Id, t.C2, @Value NewColumn
FROM Table1 t


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

Каков реальный сценарий?

Внутреннее соединение будет определенно быстрее, чем левое соединение.

Как насчет этого?

Declare @t table(id int,c2 varchar(10))
INSERT INTO @T
select 1,'A' union all
select 2,'A' union all
select 3,'B' union all
select 4,'B' 
Declare @t1 table(nEWcOL varchar(10))
INSERT INTO @T1 Values('Value')
-- #Approach1
--SELECT * FROM @T outer apply
 --@t1
--Create index on both join column
 --#Approach2
SELECT * FROM @T A inner join
 @t1 b on a.c2<>b.nEWcOL
--#Approach3
Declare @value varchar(20)
Select @value= nEWcOL from @t1
select *,@value value from @t


Вы также можете попробовать с помощью CROSS APPLY:

SELECT A.*, B.*,
FROM Table1 A
CROSS APPLY(SELECT 'Value' as 'NewColumn') B

licensed under cc by-sa 3.0 with attribution.