Имя: Пароль:
IT
Админ
T-SQL: Как правильно удалить часть строк в таблице?
0 arsik
 
гуру
14.10.16
15:13
Составил запрос. На удаление с использованием временной таблицы. Но как этой временной таблице добавить индекс?

SET DATEFORMAT ymd
DECLARE @datevar datetime = '2016-08-01'

DECLARE @docs table(UIDs binary(16))
insert into @docs

SELECT     _IDRRef
FROM         _Document9915
WHERE     (_Date_Time >= @datevar)

UNION

SELECT   _IDRRef
FROM     _Document106
WHERE    (_Date_Time >= @datevar)


DELETE FROM _InfoReg4206
WHERE     (_Fld4207_RRRef NOT IN (select UIDs as _Fld4207_RRRef from @docs))
1 МихаилМ
 
14.10.16
15:21
забыли про смещение дат. забыли про tref (uid-ы могут совпадать ) .
2 МихаилМ
 
14.10.16
15:28
3 МихаилМ
 
14.10.16
15:30
4 arsik
 
гуру
14.10.16
15:36
(1)
>>uid-ы могут совпадать
Ну там не очень важная таблица, если пару лишних строк удалится ничего страшного нет.

>>забыли про смещение дат
В базе 0 смещение, так что ничего страшного я думаю.
5 Ёпрст
 
14.10.16
15:38
(4) посмотрите на эти даты в табличке
6 arsik
 
гуру
14.10.16
15:41
(5) Посмотрел. Я изначально просто выбрал документы, допустим за сегодня, нормально. Только сегодняшние выбрались.
7 Naf_kultura
 
14.10.16
15:44
зачем тут временная таблица вообще?
8 Ёпрст
 
14.10.16
15:47
(7) дык, модно, молодежно
9 arsik
 
гуру
14.10.16
15:48
(7) ХЗ. Так в 1С обычно принято. :) Еще индекс можно построить по временной. Вроде как быстрее должно быть.
10 Мойдодыр
 
14.10.16
15:50
для однократного применения индекс не нужен
11 Naf_kultura
 
14.10.16
15:53
DELETE FROM _InfoReg4206
WHERE     (_Fld4207_RRRef NOT IN (SELECT     _IDRRef
FROM         _Document9915
WHERE     (_Date_Time >= @datevar)

UNION ALL

SELECT   _IDRRef
FROM     _Document106
WHERE    (_Date_Time >= @datevar)
))
12 arsik
 
гуру
14.10.16
15:56
(11) UNION ALL - я так понимаю быстрее должен обрабатывать объединение?
13 arsik
 
гуру
14.10.16
15:57
(10) Спорно. Почему то во всех мануалах (по 1С) советуют использовать временные с индексами. Даже если они 1 раз используются.
14 Naf_kultura
 
14.10.16
16:04
(12) естественно
15 arsik
 
гуру
14.10.16
16:23
(14) SELECT происходит быстро, а вот DELETE - уже час шуршит.
Таблица исходная из которой нужно удалить очень большая (250 миллионов записей). Временная вышла около 3 миллионов.
Как ускорить DELETE?
16 Naf_kultura
 
14.10.16
16:25
(15) если ты почти всю ее удаляешь, то бишь оставляешь 3 из 250 миллионов, то не проще было создать другую таблицу. Туда перенести нужные данные INSERT. Старую грохнуть DROP.
Новую переименовать
17 arsik
 
гуру
14.10.16
16:35
(16) Была такая мысль но моего опыта не хватит, что бы пересоздать таблицу. Там же еще и индексы нужно создать.
18 Мойдодыр
 
14.10.16
16:37
(17) В sql менеджере - показать код создания
19 arsik
 
гуру
14.10.16
16:52
(18) Есть такое.
А как со статистикой быть? Она автоматом создается?
20 youalex
 
14.10.16
16:52
(0)
DECLARE @docs table(UIDs binary(16)) - это не временная таблица, а табличная переменная.

Непонятно, зачем она вообще:

DELETE reg
FROM _InfoReg4206 reg
JOIN _Document9915 doc ON reg._RecorderRRef = doc._IDRRef
WHERE doc._Date_Time >= @datevar
    --AND reg._RecorderTRef = 0x00000105 /*это условие луше указать, чтобы в индекс попасть, значение можно в профайлере узнать*/


И для второй таблицы доков - аналогично.
21 youalex
 
14.10.16
16:54
+ смещение дат, да.
22 youalex
 
14.10.16
16:56
+ - еще можно удалять порциями:
DELETE TOP (1000)
23 Yuri 83
 
14.10.16
17:03
(17) Тем не менее правильно товарищ в (16) говорит... Времени разобраться плюс время выполнить все равно будет меньше, чем вот так, в лоб удалять.
Можно еще просто создать копию таблицы с нужными данными (можно мастером накликать код, если сложно), затем truncate table очистит полностью исходную, потом обратно скопировать данные. Будет быстрее гораздо. Только права на truncate должны быть
24 arsik
 
гуру
14.10.16
17:18
(23) А обратно скопировать через insert? Или какой то другой ход есть?
25 youalex
 
14.10.16
17:27
(24) можно через временную:
BEGIN TRAN
BEGIN TRY
1) SELECT INTO #temp SELECT ...
2) TRUNCATE TABLE Reg
3) INSERT INTO Reg SELECT * FROM #temp
END TRY

BEGIN CATCH
    SELECT ERROR_MESSAGE()
    ROLLBACK TRAN
END CATCH

IF @@TRANCOUNT > 0 COMMIT TRAN

SELECT @@TRANCOUNT -- должно быть 0 !!
26 arsik
 
гуру
14.10.16
17:36
(25) Спасибо. То что надо. Так и сделаю.
27 youalex
 
14.10.16
17:47
(26)
1) - SELECT reg.* INTO #temp FROM _InfoReg4206 reg ...
28 arsik
 
гуру
15.10.16
14:33
(27) Спасибо большое. Все получилось. Сократилось до 7 минут.
У меня еще вопрос. После инсерта нужно переиндексацию, (перестроение, реорганизацию) индексов этой таблицы делать или sql сам все автоматом сделает?
29 МихаилМ
 
15.10.16
18:28
не нужно . автоматом
30 arsik
 
гуру
15.10.16
18:33
(29) Спасибо.
31 arsik
 
гуру
17.10.16
12:09
Оказалось все не так просто.
На тестовой базе все нормально, на рабочей ошибка:
Не удается вставить повторяющуюся строку ключа в объект "dbo._InfoReg4206" с уникальным индексом "_InfoRe4206_ByDims_RR". Повторяющееся значение ключа: (0x08, 0x00001211, 0x7f8400259098e7a911e687ce59a0abda, 0x939b003048578e5311de15178d2d668c)

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

Как заблокировать на уровне SQL таблицу на время выполнения всего скрипта?

Пример скрипта тут: http://pastebin.com/5fKkFX4e
32 Naf_kultura
 
17.10.16
12:18
(31) выгнать юзеров
33 mehfk
 
17.10.16
12:18
34 mehfk
 
17.10.16
12:19
Тебе нужен TABLOCK
35 arsik
 
гуру
17.10.16
12:29
(32) Не пойдет. Там постоянно кроме юзеров еще и автообмены. Ну и выгонять юзеров долго.

(34) У меня сначала идет TRUNCATE, потом INSERT. Между этими двумя строками может пролезть INSERT от 1С?

Правильно так?
INSERT INTO _InfoReg4206 SELECT * FROM #tmp_InfoReg4206_20161017113542 WITH (TABLOCK)
36 mehfk
 
17.10.16
12:49
INSERT INTO _InfoReg4206 WITH (TABLOCK) SELECT * FROM #tmp_InfoReg4206_20161017113542
37 Oftan_Idy
 
17.10.16
12:51
(0) Вот лезут такие грязными ручками в SQL, а потом базы падают. Начерта это делать напрямую? Почему не через платформу?
38 arsik
 
гуру
17.10.16
13:05
(37) 250 милионов записей из регистра долго удаляются.
(36) Аа. Точно. Не в тот запрос воткнул.
39 mehfk
 
17.10.16
13:06
А вообще, что удаляешь? Версии объектов?
40 arsik
 
гуру
17.10.16
13:12
(39) Не. Создали тут умельцы свой регистр. Только очистку тупую сделали. 100 т. записей в день удаляется, посредством 1С, а прирастает больше. Иногда намного больше, это когда перепроведения всякие. Сейчас накопилось 270 миллионов записей, из них актуальны только 13 миллионов.
Ошибка? Это не ошибка, это системная функция.