powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / Sybase ASA, ASE, IQ [игнор отключен] [закрыт для гостей] / Удаление из большой таблицы. Как?
25 сообщений из 33, страница 1 из 2
Удаление из большой таблицы. Как?
    #38857671
kostik88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Доброго времени суток.
Столкнулся с проблемой переноса данных в историческую базу.
Задача.
имеем таблицу с 300 миллионами+ записями
есть два поля, год и квартал, по которым можно определить что вырезаем, а что оставляем.
Фактически 2/3 данных нужно перенести в другую таблицу и удалить в первоначальной.

ddl таблицы которая требует обрезки

create table dbo.tbl_store (
id numeric(18, 0) identity,
year_ smallint not null,
qq_ tinyint not null,
member_id numeric(18, 0) not null,
complect_code varchar(20) not null,
chances decimal(14, 10) not null,
state tinyint DEFAULT 0 not null,
num smallint not null,
shop_del tinyint null,
constraint PKtbl_store_id PRIMARY KEY NONCLUSTERED ( id )
)
lock datarows
on 'default'
go

print 'XXmembID'
create nonclustered index XXmembID
on dbo.tbl_store (member_id)
on 'default'

print 'XXmemb_num_state'
create nonclustered index XXmemb_num_state
on dbo.tbl_store (member_id, num, state)
on 'default'

Индексы строить не вариант на полях year_ и qq_, так как происходит залочка и вообщем пользователи плачут. Программисту который такое сваял, тоже уже ничего не поможет.
Пробовал вариант с временной таблицей.
Создаю временную таблицу, ставлю SET rowcount 100 после чего закидываю в нее данные из родительской.
Данные в таблице находятся по порядку. То есть самые старые в начале и тд.
Затем полученные данные из времянки. по условию к примеру, 2012 год и 2 квартал, делаю инсерт в историческую базу в таблицу.
после этого удаляю из родительской.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
Create proc dbo.usp_cut_tbl_store_date 
@year smallint, 
@qq tinyint, 
@part int                       
--,@md smallint 
as 
/* 
DECLARE  
@year smallint, 
@qq tinyint, 
@part int ,                        
@md smallint 
 
SET @year = 2012 
SET @qq = 2 
SET @part = 1000 
--SET @md = 2014 
*/ 
 
WHILE 2=2  
    BEGIN 
        SET rowcount @part           
         
        create table #tbl_store ( 
        id  numeric(18, 0)  not null, 
        year_   smallint    not null, 
        qq_ tinyint not null, 
        member_id   numeric(18, 0)  not null, 
        complect_code   varchar(20) not null, 
        chances decimal(14, 10) not null, 
        state   tinyint DEFAULT    0        not null, 
        num smallint    not null, 
        shop_del    tinyint null, 
        constraint PKa_tbl_store_id PRIMARY KEY NONCLUSTERED ( id ) 
        ) 
 
	create nonclustered index NCI_id 
        on #tbl_store (id) 
        on 'default'

        create nonclustered index NCI_year_qq 
        on #tbl_store (year_,qq_) 
        on 'default'
 
        insert  #tbl_store  
        (id,year_,qq_,member_id,complect_code,chances,state,num,shop_del) 
        
	select  tbl_store.id, tbl_store.year_, tbl_store.qq_, tbl_store.member_id, 
		tbl_store.complect_code, tbl_store.chances, tbl_store.state, 
		tbl_store.num, tbl_store.shop_del 
	from tbl_store 
 
        IF @@rowcount =0 Break   
   
        SET ROWCOUNT 0   
 
        BEGIN TRAN 

	    INSERT M..a_tbl_store 
            (id,year_,qq_,member_id,complect_code,chances,state,num,shop_del)
 
            SELECT #tbl_store.id, #tbl_store.year_, #tbl_store.qq_,  
		   #tbl_store.member_id, #tbl_store.complect_code, 
		   #tbl_store.chances, #tbl_store.state, #tbl_store.num, 
		   #tbl_store.shop_del 
            FROM #tbl_store (index NCI_year_qq) where year_=@year and qq_=@qq
 
                IF @@error <>0 goto  lab1                                
                    DELETE tbl_store where id IN (SELECT id FROM #tbl_store (index NCI_id )) 
--                    DELETE tbl_store where id IN (SELECT id FROM #tbl_store where year_=@year and qq_=@qq) 
                IF @@error <>0 goto lab1             
        COMMIT TRAN 
--        PRINT 'Cutting Period %1!,%2!', @year ,@qq 
 
    DROP index #tbl_store.NCI_id
    DROP index #tbl_store.NCI_year_qq 
    DROP TABLE #tbl_store 
    END       
    waitfor delay "00:00:10"                        
RETURN 0 
 
lab1:                         
ROLLBACK TRAN 
RETURN -1 
go

SETUSER
go



Проблема в том что все это ну очень долго происходит, и к примеру за один квартал - это 30 лямов, выгружается около 10%, после чего закачивается место в tempdb.
Запускаю через *.bat isql.

Гуру подскажите плиз какие есть варианты решения проблемы?
Adaptive Server Enterprise/12.5.4/EBF 16791 ESD#10/P/NT (IX86)/OS 4.0/ase1254/2159/32-bit/OPT/Mon Nov 02 05:01:55 2009
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38857837
Фотография komrad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kostik88,

Задачка тривиальная, несколько вариантов решения может быть.
Из быстрых:
1) создать view1 для исторических данных
2) выгрузить её (select ... from view1) в файл1 с помощью BCP
3) создать view2 для данных, которые должны остаться в исходной таблице
4) выгрузить её (select ... from view2) в файл2 с помощью BCP
5) truncate исходной таблицы
6) удалить на ней индексы
7) залить в нее файл2 с помощью BCP
8) построить индексы обратно
9) в историческую таблицу залить файл1 с помощью BCP, удалив индексы и создав их обратно после заливки

предварительно почитать про режимы BCP :
http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc30191.1550/html/utility/X20696.htm
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38857909
kostik88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Предложение хорошее, в бытность работы с MS SQL Server я бы так и поступил, но тут меня смущает процесс постоения индексов на таблице со 100 миллионами записей. Сколько это будет по времени, и будут же залочки во время создания индексов, и пользователи жаловаться будут. А окна технологического нету :(. Но я все же попробую в тестовой среде предложенный Вами вариант.
Спасибо.
А какие есть еще варианты ?
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38857986
Фотография komrad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kostik88Предложение хорошее, в бытность работы с MS SQL Server я бы так и поступил, но тут меня смущает процесс постоения индексов на таблице со 100 миллионами записей. Сколько это будет по времени, и будут же залочки во время создания индексов, и пользователи жаловаться будут. А окна технологического нету :(. Но я все же попробую в тестовой среде предложенный Вами вариант.
Спасибо.
А какие есть еще варианты ?
На вскидку, разной степени простоты и трудозатратности:
* Базу в режим truncate log on checkpoint, удалять батчами.
* Создать рядом вторую таблицу, перелить туда нужные данные, построить индексы, после этого переименовать объекты - старую таблицу и новую поменять местами; провести рекомпиляцию связанных объектов; из переименованной перелить исторические данные в историческую таблицу.
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38858520
SQLMantis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kostik88Предложение хорошее, в бытность работы с MS SQL Server я бы так и поступил, но тут меня смущает процесс постоения индексов на таблице со 100 миллионами записей. Сколько это будет по времени, и будут же залочки во время создания индексов, и пользователи жаловаться будут. А окна технологического нету :(. Но я все же попробую в тестовой среде предложенный Вами вариант.
Спасибо.
А какие есть еще варианты ?

Привет! Все варианты, которые подразумевают прозрачный для пользователей перенос будут длительны во времени.
Поправим немного план komrad'a, тем более что во втором посте он намекает...

1) создать view1 для исторических данных
2) выгрузить её (select ... from view1) в файл1 с помощью BCP
3) в историческую таблицу залить файл1 с помощью BCP, удалив индексы и создав их обратно после заливки
4) Выбрать время минимальной загрузки (ночь, ранее утро etc) и удалять исторические данные конструкцией delete top 10000 from...
в while (@@rowcount != 0)

Да, это займет время, но прозрачно для пользователей. (не забудь включить обрезание лога по чекпоинту в базе)
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38858989
Фотография komrad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQLMantisПривет! Все варианты, которые подразумевают прозрачный для пользователей перенос будут длительны во времени.
Поправим немного план komrad'a...

с корректировкой согласен, тем более что мой вариант был схематичным

SQLMantisДа, это займет время, но прозрачно для пользователей. (не забудь включить обрезание лога по чекпоинту в базе)
решение об автоматическом обрезании лога на продакшен базе требует некоторого размышления от автора
"только трусы делают дампы" (с) начальник ;)
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38859223
kostik88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Спасибо друзья за советы!
Буду осуществлять на практике!
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38859363
Mikle83
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kostik88,

Код: sql
1.
id numeric(18, 0) identity,


Логично предположить, что дата у вас линейно зависима на Id , т.е. чем больше Id тем больше дата и не может быть двух записей с ID1 > ID2 , в которых Date2 < Date1 . По Id есть индекс.

Задача сводится к удалению по ID .

Делаете процедуру (без представлений и пр.), которая:
1. Копирует батч (X записей) в архивную таблицу по диапазону ID: ID between N1 and N2 , при этом ID < MaxID (само собой количество записей между N1 и N2 должно быть больше либо равно X для снижения количества иттераций) .
Где MaxId соответствует идентификатору записи с максимальной датой, которую можно удалить - найти этот MaxId думаю не составит труда для вас.

Архивная таблица имеет признак на каждой записи, типа HaveDeleted / WhenDeleted с индексом по этому полю.
При копировании, поле равно 0.

2. Батчем удаляете записи из основной, у которых ID соответствует записям из архивной с признаком HaveDeleted = 0 .

3. Апдейтите архивную: записи с HaveDeleted = 0 на HaveDeleted = 1 если соответствующий ID не найден в основной таблице.

С виду монстрообразная конструкция, не самая оптимальная по быстродействию, но позволит:
а) переносить данные в архив мелкими партиями по Х записей - не блокирую других пользователей.
б) удалять данные из основной таблицы партиями по Х1 записей (при этом Х <> Х1), опять же не блокируя пользователей и обеспечивая приемлемую нагрузку на сервер/лог/таблицу, учитывая все особенности вашей системы.
в) "развести" процесс копирования и удаления по времени, тем самым "разгрузив" систему. К примеру, копирование может быть "грязным" и вообще без локов (старые данные же у вас не меняются? Так ведь?). Удаление можно проводить в периоды низкой нагрузки системы, вплоть до одной записи.
г) обеспечить целостность данных - ничего не теряете в итоге.
д) растянуть процесс во времени, если система 24х7 - нет необходимости в простое.

При желании копирование и удаление могут быть разведены по двум независимым процессам - но тут надо аккуратно подходить - дабы процессы друг друга не блокировали.
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38859466
kostik88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Mikle83,
похоже воспользуюсь именно вашим советом, так как вариант с bcp отпадает, так как база куда будут помещены исторические данные, находится под репликацией и разрешено только bcp-выкачка данных.
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38859504
SQLMantis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kostik88Mikle83,
похоже воспользуюсь именно вашим советом, так как вариант с bcp отпадает, так как база куда будут помещены исторические данные, находится под репликацией и разрешено только bcp-выкачка данных.

Тут давайте остановимся, посчитаем до 10 и Вы нам расскажите по подробнее про "база находится под репликацией"
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38859552
kostik88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SQLMantis,

Подробнее, есть два сервера БД, издатель и подписчик.
4 базы на каждом, все они под репликацией.
Какие вопросики будут ?
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38859792
SQLMantis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kostik88SQLMantis,
Какие вопросики будут ?

Как реализована репликация? Какими средствами?
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38859889
kostik88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SQLMantis,
настроен RS 15.7
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38859912
SQLMantis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kostik88SQLMantis,
настроен RS 15.7

Круто :) warm standby?
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38859991
kostik88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SQLMantis,

простите? Я только несколько месяцев работаю с данной БД и репликатором.
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38860351
kostik88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SQLMantis,

простите? Я только несколько месяцев работаю с данной БД и репликатором.
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38860694
SQLMantis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kostik88SQLMantis,

простите? Я только несколько месяцев работаю с данной БД и репликатором.

Тогда, пока ничего не трогайте.
А то мы тут насоветовали много такого от чего переполняются logsegment'ы и пухнут очереди в RS.
Перво наперво нужно узнать участвует ли ваша таблица в репликации.
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38860812
Mikle83
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQLMantiskostik88SQLMantis,

простите? Я только несколько месяцев работаю с данной БД и репликатором.

Тогда, пока ничего не трогайте.
А то мы тут насоветовали много такого от чего переполняются logsegment'ы и пухнут очереди в RS.
Перво наперво нужно узнать участвует ли ваша таблица в репликации.

Ну вот. И так в топике про Sybase - скучно, так еще и потенциальную тему "упала репликация" - срубили :(



По теме - если есть репликация => +1 к варианту с процедурой. В начале указать отключение репликации на сессию.
Запуск раздельный на primary и на подписчике(ах). Возможна рассинхронизация данных между архивными таблицами и "архивных" данных в основной, но, скорее всего, это не критично для бизнес задач - надо уточнять у ваших аналитиков/бизнеса. В любом случае, никто не мешает собрать представление с UNION обоих таблиц и завязать всю отчетность на представление, если это реально критично.


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

P.S.: на архивируемую таблицу другие не ссылаются случаем?
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38860918
kostik88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Спасибо всем кто откинулся на мой вопрос!
На счет репликации, под ней все и таблицы и прочие объекты и тд.
Таблица которую буду "резать", так же под репликацией, но она статична до порезки, и в нее на момент порезки никто добавлять ничего не будет. Просто нужно что бы в этой таблице был некий период, а остальное в хистори-базу. Так что тут все ок.

На счет отключения репликации. Планирую обернуть процедуру через sp_setrepproc

Оформил я так как предложил Mikle83, завернул в процедуру.

Процедура

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
/*
--test 
usp_cut_some_table_date 30409401,304010401,100

*/
GO
print    'usp_cut_some_table_date'
SETUSER  'dbo'

go
Create proc dbo.usp_cut_some_table_date 
@min_ int,@max_ int,@step int
as 

/* 
declare @min_ int,@max_ int,@step int
 
set @min_ = 30405401
set @max_ = 30405403
set @step = 1
*/ 

WHILE 
	(Select (@min_))<@max_
BEGIN
	BEGIN TRAN 
		declare @step2 int set @step2 = (@min_+@step)
--		PRINT '%1!,%2!',@min_,@step2


		INSERT M..a_some_table 
		(id,year_,qq_,member_id,complect_code,chances,state,num,shop_del)
		
		SELECT * 
		from some_table 
		where id between @min_ and 
		(select @min_+@step) and id <= @max_

		IF @@rowcount =0 raiserror 99999 
		'There are no values in this range %1! - %2!.',@min_,@step2

		IF @@error <>0 goto  lab1                                

			DELETE 
			from some_table 
			where id between @min_ and 
			(select @min_+@step) and id <= @max_

                IF @@error <>0 goto lab1  

        COMMIT TRAN 

	if (Select (@min_))>=@max_
	BREAK
   ELSE
	set @min_=@min_+@step
	CONTINUE
END  
    waitfor delay "00:00:03"                        
RETURN 0 
 
lab1:                         
ROLLBACK TRAN 

RETURN -1 
go

SETUSER
go


...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38860959
Mikle83
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kostik88,

Код: sql
1.
2.
IF @@rowcount =0 raiserror 99999 
		'There are no values in this range %1! - %2!.',@min_,@step2



странно это... Реально есть уверенность, что у вас нет "пропусков" в идентификаторах?
Я делал что-то типа (с точностью до синтаксиса)

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
Select @Min = MinValue from the Table_WhichStore_ResultsOfExecution
Set @Max = @Min + @BatchSize
Set @RC = 0
while (@RC < @BatchSize) and (@Max < [@Max_ID]) --where @Max_ID - maximum value of the identifier at the table
begin
  Set @Max = @Max + @BatchSize/10
  select @RC = count(*) from SourceTable where ID between @Min and @Max
end


Такой подход позволял нивелировать "пропуски" в идентификаторах и переносить в каждой иттерации +/- одинаковое количество записей, делая процесс более предсказуемым.


c DELETE рисковано, на мой взгляд делать так:

Код: sql
1.
2.
3.
4.
DELETE 
			from some_table 
			where id between @min_ and 
			(select @min_+@step) and id <= @max_



Я бы удалял то, что гарантированно перенесено в архив
Код: sql
1.
2.
3.
DELETE 
			from some_table st
                            join some_table_ARCHIVE stA on st.id = stA.id and st.HasDeleted = 0



Опять же, структура HasDeleted может оказаться полезной, если объем удаляемых записей не совпадает с объемом выборки на копирование.
Если в вашем случае возможен вырожденный случай и эти два объема идентичны - крупно повезло, можно оставить и так...
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38860985
kostik88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Mikle83,

Код: sql
1.
2.
IF @@rowcount =0 raiserror 99999 
		'There are no values in this range %1! - %2!.',@min_,@step2



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

На счет остальных подсказок, еще раз сенкс. Покручу с их учетом.
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38860996
SQLMantis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Mikle83 В начале указать отключение репликации на сессию.


Хмм. Можно поподробнее, что предлагается сделать?
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38861479
Mikle83
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQLMantisMikle83 В начале указать отключение репликации на сессию.


Хмм. Можно поподробнее, что предлагается сделать?

к примеру следующий запрос в начале процедуры:
Код: sql
1.
2.
IF (has_role('replication_role',0) <> 0)
SET REPLICATION OFF 



все что будет "твориться" внутри процедуры не пойдет на реплику.
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38861482
Mikle83
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kostik88поставил только для той ситуации, если случайно будет запущенно дважды.
Плохой вариант ?
Смотря как будете Min/Max определять для передачи в процедуру.
по мимо варианта повторного запуска, возможно (особенно при последовательном переборе значений ИД),
что наткнетесь на иинтервал [Min;Max] в котором нет записей. Процедура отработает с ексепшеном.
...
Рейтинг: 0 / 0
Удаление из большой таблицы. Как?
    #38861587
kostik88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Mikle83,
на счет удаления данных, я же беру некоторое количество записей, копирую их в хистори таблицу, и тут же по этому же диапазону произвожу удаление данных.

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

На счет отключения репликации, а это процедура sp_setrepproc разве не сделает то же самое? То есть я оберну выполнение своей процедуры через эту функцию, и отдельно запущу на издателе и подписчике.
...
Рейтинг: 0 / 0
25 сообщений из 33, страница 1 из 2
Форумы / Sybase ASA, ASE, IQ [игнор отключен] [закрыт для гостей] / Удаление из большой таблицы. Как?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]