AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: База знаний и проекты
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 04.01.2007, 23:16   #1  
Torin is offline
Torin
Участник
 
127 / 31 (2) +++
Регистрация: 10.03.2003
Адрес: Odessa, Ukraine
? Скрипт для партицирования в Юконе нужен ?
В процессе работы появился ряд артефактов. Например, скрипты для Юкона, которые создают функцию и схему партициирования по DATAAREAID и скрипт, который пробегается по всей базе и раскидывает объекты по партициям - ручками замахаться, а Аксапта не может.
В результате, производительность на мультикомпаненых базах значительно возрастает - особенно снижается влияние конткуретности.
Схема для Аксапты остается прозрачной - она даже не замечает, что то-то изменилось
Короче, кому то надо ?
Старый 05.01.2007, 02:25   #2  
raz is offline
raz
NavAx
Аватар для raz
NavAx Club
Лучший по профессии 2014
Лучший по профессии 2009
 
1,494 / 1065 (38) ++++++++
Регистрация: 22.07.2003
Адрес: МО
Чего спрашивать! Конечно выкладывай!
Старый 05.01.2007, 02:56   #3  
Torin is offline
Torin
Участник
 
127 / 31 (2) +++
Регистрация: 10.03.2003
Адрес: Odessa, Ukraine
Ага, ну вот.
Сразу, чтобы бы ввести понимание - работает только в Юконе (уровень совместимости неважен), причем Энтерпрайз версии (Или Девелопер - там где партиционирование разрешенно).
Сначала надо создать файловые группы с файлами данных (у меня DATAGROUP1, DATAGROUP2 и т.д.)
Потом функцию и схему
Код:
CREATE PARTITION FUNCTION axDataAreaPF (varchar(3))
AS RANGE LEFT FOR VALUES ('mce', 'mso', 'mea', 'mpc', 'pal', 'pgt', 'psa','pgh');
GO

CREATE PARTITION SCHEME axDataAreaPS
AS PARTITION axDataAreaPF
TO ([DATAGROUP1], [DATAGROUP2], [DATAGROUP3], [DATAGROUP4], [DATAGROUP5], [DATAGROUP6], [DATAGROUP7], [DATAGROUP8], [DATAGROUP9], [DATAGROUP10]);
GO
Где у нас 'mce', 'mso', 'mea', 'mpc', 'pal', 'pgt', 'psa','pgh' - это разные DataArea
По особенностям операторов лучьше почитать в хелпе - есть нюансы с LEFT и лишней группой в схеме.

Далее, само интересное. Этим скриптом я перебираю объекты, проверяю, что они еще не партициионированны и, собственно, do it. Скрипт можно запускать много раз - если ничего не изменилось или не было ошибок, то и делать ничего не будет.
Код:
USE AX64SP3;
SET LOCK_TIMEOUT -1;
GO

DECLARE @table_name varchar(100), @table_id int, @table_partition_type varchar(2), @table_partition_name  varchar(100)
DECLARE @index_name varchar(100), @index_type tinyint, @index_is_unique tinyint, @index_is_primary_key tinyint, @index_is_disabled tinyint, @index_allow_row_locks tinyint, @index_allow_page_locks tinyint, @index_partition_type varchar(2), @index_partition_name  varchar(100)
DECLARE @column_name varchar(100), @column_is_descending_key  tinyint, @column_first tinyint
DECLARE @SQL as nvarchar(4000)
	
DECLARE table_cursor CURSOR FOR
	select DISTINCT o.name, o.object_id, ds.type as type, ISNULL(pf.name, ds.name) as name 
	from 
		sys.partitions AS p
		INNER JOIN sys.indexes AS i ON p.object_id = i.object_id AND p.index_id = i.index_id
		INNER JOIN sys.objects AS o ON o.object_id = i.object_id
		INNER JOIN sys.data_spaces ds ON i.data_space_id=ds.data_space_id
		LEFT JOIN sys.partition_schemes ps ON i.data_space_id=ps.data_space_id
		LEFT JOIN sys.partition_functions pf ON ps.function_id = pf.function_id
	where o.type='U' and i.type=0 and SCHEMA_NAME(o.schema_id) = 'dbo'
	ORDER BY o.name

OPEN table_cursor
FETCH NEXT FROM table_cursor INTO @table_name, @table_id, @table_partition_type, @table_partition_name

WHILE @@FETCH_STATUS = 0
BEGIN
	IF 
		EXISTS(select [name] FROM sys.columns WHERE object_id = @table_id AND UPPER(name) = 'DATAAREAID')
		AND NOT @table_name LIKE 'SYS%'
	BEGIN
		PRINT '--' + @table_name
		IF NOT EXISTS (Select [name] FROM sys.indexes WHERE [type] = 1 AND object_id = @table_id) AND @table_partition_type = 'FG'
		BEGIN
			PRINT '----MOVE TO PARTITION'
			SELECT @SQL = 'CREATE CLUSTERED INDEX tmp_cluster ON ' +@table_name+ '(DATAAREAID) ON axDataAreaPS(DATAAREAID);'
			--PRINT @SQL
			EXEC(@SQL)
			
			SELECT @SQL = 'DROP INDEX tmp_cluster ON ' + @table_name + ';'
			--PRINT @SQL
			EXEC(@SQL)
		END

		Declare index_cursor CURSOR FOR
			Select i.name, i.type, i.is_unique,  i.is_primary_key, i.is_disabled, i.allow_row_locks, i.allow_page_locks, ds.type as type, ISNULL(pf.name, ds.name) as name 
			FROM sys.partitions AS p
				INNER JOIN sys.indexes AS i ON p.object_id = i.object_id AND p.index_id = i.index_id
				INNER JOIN sys.objects AS o ON o.object_id = i.object_id
				INNER JOIN sys.data_spaces ds ON i.data_space_id=ds.data_space_id
				LEFT JOIN sys.partition_schemes ps ON i.data_space_id=ps.data_space_id
				LEFT JOIN sys.partition_functions pf ON ps.function_id = pf.function_id
			WHERE i.object_id = @table_id and i.type>0
			Order by i.type

		OPEN index_cursor
		FETCH NEXT FROM index_cursor INTO @index_name, @index_type, @index_is_unique, @index_is_primary_key, @index_is_disabled, @index_allow_row_locks, @index_allow_page_locks, @index_partition_type, @index_partition_name

		WHILE @@FETCH_STATUS = 0
		BEGIN
			IF @index_partition_type = 'FG'
			BEGIN
				PRINT '----' + @index_name
				SELECT @SQL = 
				CASE WHEN @index_is_primary_key = 1 THEN 
					'ALTER TABLE ' + @table_name + ' DROP CONSTRAINT ' + @index_name +' WITH (ONLINE = OFF); ' 
					+  ' ALTER TABLE ' + @table_name + ' WITH NOCHECK ADD CONSTRAINT ' + @index_name + ' PRIMARY KEY ' +CASE WHEN @index_type = 1 THEN ' CLUSTERED ' ELSE ' ' END 
				ELSE
					'CREATE ' + CASE WHEN @index_type = 1 THEN 'CLUSTERED' WHEN @index_is_unique =1 THEN  'UNIQUE' ELSE '' END +' INDEX ' + @index_name + ' ON '+ @table_name
				END

				Declare column_cursor CURSOR FOR
				Select t3.[name], t2.is_descending_key 
				FROM	sys.indexes t1
						INNER JOIN sys.index_columns t2 ON t1.object_id=t2.object_id AND t1.index_id = t2.index_id
						INNER JOIN sys.columns t3 ON t1.object_id=t3.object_id AND t2.column_id = t3.column_id
				WHERE t1.[name] =@index_name and t1.object_id = @table_id
				Order by t2.index_column_id
				
				SELECT @SQL = @SQL + '('
				SELECT @column_first = 1

				OPEN column_cursor
				FETCH NEXT FROM column_cursor INTO @column_name, @column_is_descending_key
				WHILE @@FETCH_STATUS = 0
				BEGIN
					SELECT @SQL = @SQL + CASE WHEN @column_first=1 THEN '' ELSE ', ' END + @column_name + CASE WHEN @column_is_descending_key = 1 THEN ' DESC' ELSE ' ' END
					SELECT @column_first = 0
					FETCH NEXT FROM column_cursor  INTO @column_name, @column_is_descending_key
				END
				CLOSE column_cursor
				DEALLOCATE column_cursor
				SELECT @SQL = @SQL +
					CASE WHEN @index_is_primary_key = 1 THEN 
						') WITH (FILLFACTOR = 75, ONLINE = OFF) ON axDataAreaPS(DATAAREAID);'
					ELSE
						') WITH (DROP_EXISTING = ON, ONLINE = OFF) ON axDataAreaPS(DATAAREAID);'
					END
				--PRINT @SQL
				EXEC(@SQL)
			END
		FETCH NEXT FROM index_cursor INTO @index_name, @index_type, @index_is_unique, @index_is_primary_key, @index_is_disabled, @index_allow_row_locks, @index_allow_page_locks, @index_partition_type, @index_partition_name
		END
		CLOSE index_cursor
		DEALLOCATE index_cursor
	PRINT 'GO' 	
	END
	FETCH NEXT FROM table_cursor INTO @table_name, @table_id, @table_partition_type, @table_partition_name
END

CLOSE table_cursor
DEALLOCATE table_cursor
Вместо EXEC можно расскомментировать PRINT - тогда результатом работы будет SQL скрипт, который можно разглядывать и выполнять по частям ручками.
AS IS, конечно
За это сообщение автора поблагодарили: George Nordic (1), kashperuk (2), Logger (1), aidsua (1), gl00mie (2), moid (1).
Старый 02.03.2007, 16:28   #4  
fomenka is offline
fomenka
Участник
 
97 / 14 (1) ++
Регистрация: 25.02.2003
Цитата:
Сообщение от Torin Посмотреть сообщение
Где у нас 'mce', 'mso', 'mea', 'mpc', 'pal', 'pgt', 'psa','pgh' - это разные DataArea
А виртуальные компании как обрабатывать? Так же?
Старый 02.03.2007, 16:31   #5  
Vadik is offline
Vadik
Модератор
Аватар для Vadik
Лучший по профессии 2017
Лучший по профессии 2015
 
3,631 / 1849 (69) ++++++++
Регистрация: 18.11.2002
Адрес: гражданин Москвы
Перенесу-ка в Полезные материалы
__________________
-ТСЯ или -ТЬСЯ ?
Старый 30.03.2011, 13:09   #6  
PavelX is offline
PavelX
MCTS
MCBMSS
 
46 / 97 (4) ++++
Регистрация: 08.09.2006
Адрес: Красноярск
Хоть тема и древняя, но все же подниму вопрос...

Может ли кто либо пояснить как при использовании данного скрипта (да и партицирования вообще) обходится проблема синхронизации таблиц Аксаптой?

Провел следующий эксперимент (AX 2009, SQL Server 2008 R2):
На таблице InventTrans настроил простенькое партицирование по полю CreatedDateTime в сиквеле. 1,2 миллиона строк разбилось на разделы за 6 минут, все хорошо. Далее при попытке синхронизировать InventTrans из Аксапты, сначала предлагается удалить созданный индекс на таблице и затем при попытке это сделать вываливается ошибка:


То есть получается что синхронизация партицированной таблицы в принципе не возможна? Или я что то делаю не так?

Есть ли у кого либо опыт по партицированию таблиц Аксапты? Поделитесь пожалуйста. Также буду признателен за любые идеи на эту тему.

Спасибо!
Миниатюры
Нажмите на изображение для увеличения
Название: error.jpg
Просмотров: 689
Размер:	54.6 Кб
ID:	6708  

Последний раз редактировалось PavelX; 30.03.2011 в 13:18. Причина: Добавил описание
Старый 30.03.2011, 13:14   #7  
egorych is offline
egorych
Участник
Самостоятельные клиенты AX
Oracle
 
761 / 154 (7) ++++++
Регистрация: 09.11.2006
Адрес: Краснодарский край
Сделал партицирование на табличке sysdatabaselog - по полю table
По остальным - ну пока не вижу смысла. Делать партиции в таблице до 10млн. строк ИМХО смысла не имеет.
Правда все это на Оракле.
За это сообщение автора поблагодарили: PavelX (2).
Старый 30.03.2011, 14:10   #8  
PavelX is offline
PavelX
MCTS
MCBMSS
 
46 / 97 (4) ++++
Регистрация: 08.09.2006
Адрес: Красноярск
Спасибо за информацию.

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

И что самое удивительное - партицирование таблицы после синхронизации Аксаптой осталось неизменным (я почему-то ожидал что оно будет снесено ). И добавление нового поля в Аксапте на партицированную таблицу и последующая синхронизация также не вызывает никаких проблем. Похоже все работает.
Старый 28.06.2012, 11:28   #9  
Damn is offline
Damn
Участник
 
436 / 154 (6) ++++++
Регистрация: 28.05.2003
Адрес: в глуши
Цитата:
Сообщение от PavelX Посмотреть сообщение
По всей видимости необходимо чтобы поле по которому производится партицирование (в моем случае InventTrans.CreatedDateTime) входило в первичный ключ этой таблицы InventTrans. Как только я его добавил - синхронизация выполнилась без ошибок.
Скорее всего не в первичный ключ, а в кластерный должно входить поле, по которому идёт секционирование.
Но у меня другой вопрос - у вас хорошо проходит реиндексация InventTrans после разбиения её по секциям ?
Я обнаружил что аксапта во время реиндексации в секционированной таблице пересоздаёт все индексы (кроме кластерного конечно) и, если раньше они хранились в одной файловой группе, то после реиндексации размазываются по нескольким файловым группам. Что приводит к тому что просто открыть таблицу в обозревателе таблиц становится практически невозможно. Я проводил тестирование на SysDatabaseLog, секционированной по CreatedDateTime. После реиндексации индекса TABLERECIDIDX таблица в обозревателе стала открываться по 30-40 минут. До реиндексации это происходило мгновенно.
Приходится в базе руками удалять индекс TABLERECIDIDX и создавать его снова, только в скрипте явно указывать в какой файловой группе он должен сидеть. При этом полностью согласен, что синхронизация таблицы проходит без ошибок. Именно синхронизация, но не реиндексация.
__________________
Дмитрий
Старый 04.07.2012, 02:15   #10  
vanokh is offline
vanokh
Участник
 
108 / 63 (3) ++++
Регистрация: 23.10.2008
Цитата:
Сообщение от Damn Посмотреть сообщение
Я проводил тестирование на SysDatabaseLog, секционированной по CreatedDateTime.
А можно подробности? Сколько записей в таблице, размеры индексов? На сколько групп разбивалось и что еще стало быстрее/медленнее?)

И кстати, индекс TABLERECIDIDX как раз и есть кластерный. Если руками реиндексировать, будет одна большая группа с кластерным индексом и несколько других, содержащих оставшиеся. Например, для таблицы в 5.5Гб будет одна группа на 5Гб с кластерным индексом и 500Мб индекс RECID, размазанный по остальным группам... Тогда смысл в разбиении, по-моему, теряется)

Или вы создавали другой кластерный индекс?

Последний раз редактировалось vanokh; 04.07.2012 в 02:40.
Старый 04.07.2012, 09:41   #11  
Damn is offline
Damn
Участник
 
436 / 154 (6) ++++++
Регистрация: 28.05.2003
Адрес: в глуши
Цитата:
Сообщение от vanokh Посмотреть сообщение
Или вы создавали другой кластерный индекс?
Точно, я создал кластерный индекс по полю CreatedDataTime, а TableRecIdIdx сделал обычным индексом, к тому же удалил из него поле CreatedDateTime. И свойство SaveDataPerCompany у таблицы выставил в No. При открытии таблицы SysDatabaseLog в обозревателе таблиц аксапта пытается отсортировать её по полям из индекса TableRecIdIdx. Вот тут-то и происходит вся загвоздка, описанная мною в предыдущем посте.
В таблице около 30 миллионов записей, разбил я её на две не сильно отличающиеся по размеру части.
Я кстати так и не понял, у вас-то таблица SysDatabaseLog секционирована ?
__________________
Дмитрий
Старый 04.07.2012, 10:16   #12  
vanokh is offline
vanokh
Участник
 
108 / 63 (3) ++++
Регистрация: 23.10.2008
Цитата:
Сообщение от Damn Посмотреть сообщение
Я кстати так и не понял, у вас-то таблица SysDatabaseLog секционирована ?
Нет) Я, честно говоря, не вижу пока что надобности в секционировании. Нормальный сервер + raid 10 отлично справляются (база около 200г). Поэтому и спрашиваю, что вам дало секционирование?)

У вас увидел только минус в виде медленной сортировки по "размазанному" индексу

Кстати, мы не пользуемся реиндексацией из аксапты - работает sql-скрипт, который перестраивает тролько "проблемные" (по уровню дефрагментированности) индексы. Там индекс перестраивается (REBUILD/REORGANIZE) на каждой секции отдельно.

Последний раз редактировалось vanokh; 04.07.2012 в 10:18.
Старый 04.07.2012, 14:05   #13  
Damn is offline
Damn
Участник
 
436 / 154 (6) ++++++
Регистрация: 28.05.2003
Адрес: в глуши
Цитата:
Сообщение от vanokh Посмотреть сообщение
Поэтому и спрашиваю, что вам дало секционирование?)

У вас увидел только минус в виде медленной сортировки по "размазанному" индексу
Так я пока ещё только тестирую эту технологию, смотрю как она работает применительно к аксапте, поэтому тоже пока вижу только минусы в виде очень ресурсоёмкой сортировки по размазанным индексам и необходимости замены реиндексации в аксапте на запуск самописного SQL-скрипта.
__________________
Дмитрий
Теги
partition, sql server, партицирование, полезное

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Как вывести из буфера html скрипт на экран? miklenew DAX: Программирование 7 31.03.2010 13:02
Нужен ли кому-нить экспорт-импорт Ax<->1C ax_probe DAX: Администрирование 18 17.03.2005 13:30
Нужен запрет на изменения данных журнала переноса после его распечатки ATimTim DAX: Программирование 4 19.01.2005 12:16
Зачем таблице нужен релэйшн на саму себя? Artild DAX: Программирование 2 21.07.2003 11:52

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

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 21:55.