У меня 2 стола. TableA заполняется импортом csv и обычно содержит от 10 до 15 тысяч строк. TableB имеет ту же структуру и теперь разросся примерно до 95 тыс. строк. Чтобы определить строки в таблице A, которых нет в таблице B, мне нужно сравнить конкатенацию 4 полей в таблице A с такой же конкатенацией в таблице B.
Приведенный ниже код работает, поскольку TableB растет, но это занимает так много времени, что его необходимо отменить, и он не завершается.
Я твердо верю, что использование связанных полей для сравнения приводит к тому, что время выполнения выходит за пределы удобства использования.
Есть ли лучший подход к проблеме?
DELETE FROM billing..whse_Temp
BULK INSERT billing..whse_Temp
FROM '/mnt/ABC/ABC.csv'
WITH
(
FORMAT='csv',
FIRSTROW=2,
FIELDTERMINATOR=',',
ROWTERMINATOR='\r\n'
)
INSERT INTO billing..whse
SELECT * FROM billing..whse_Temp S
WHERE CONCAT(S.RunTimeStamp, S.CS_Datacenter,S.Customer, S.ServerName) NOT IN
(
SELECT CONCAT(RunTimeStamp, CS_Datacenter, Customer, ServerName)
FROM billing..whse
)
Этот запрос не подлежит анализу — полезные индексы не будут использоваться, если они существуют. Перестаньте использовать внешне умные уловки.
В чем проблема с использованием обычной корреляции где не существует? Или Кроме?
Просто используйте NOT EXISTS
:
INSERT INTO billing..whse
SELECT * FROM billing..whse_temp S
WHERE NOT EXISTS
(
SELECT NULL
FROM billing..whse w
WHERE w.runtimestamp = s.runtimestamp
AND w.cs_datacenter = s.cs_datacenter
AND w.customer = s.customer
AND w.servername = s.servername
);
Соответствующий индекс для этого:
CREATE INDEX idx ON billing..whse (runtimestamp, cs_datacenter, customer, servername);
Я уверен, что есть способы сделать это с помощью команды MERGE, но я никогда ими не пользовался. Я уверен, что есть способы с EXISTS в нескольких столбцах, но лично я считаю более ясным иметь полное условие соединения, а затем просто проверять, где соединение не удалось. (то есть: нет строки с правой стороны):
INSERT INTO billing..whse
SELECT S.*
FROM billing..whse_Temp S
LEFT OUTER JOIN billing..whse W
ON S.RunTimeStamp = W.RunTimeStamp
AND S.CS_Datacenter = W.CS_Datacenter
AND S.Customer = W.Customer
AND S.ServerName = W.ServerName
WHERE W.RunTimeStamp IS NULL
Зачем вам использовать конкатенацию для смоделированного ключа? Просто так много способов, что это может пойти не так. Допустим, у вас есть клиенты
Mandi
иMandie
и серверыwok
иewok
. Возможно, если вы используетеCONCAT_WS
и разделитель, который не может появиться в данных, но тем не менее, да, поскольку таблица становится больше, это будет занимать все больше и больше времени. Уbilling..whse
нет ключа? Не могли бы вы создать такой же ключ (или хотя бы эквивалентный неуникальный кластеризованный индекс) наbilling..whse_Temp
? Тогда вы могли бы объединиться по ключам вместо этого конкатенации вуду. Также рассмотрите NOT EXISTS вместо NOT IN.