|
![]() |
#1 |
Участник
|
Очень понравилась идея от Gustav, т.к. дырок действительно очень много. При "использованных" свыше 3,5 млрд номеров RecId у нас в базе всего около 400 млн записей. И ее еще можно почистить...
Переход на новую версию - это что-то из области фантастики для нашей компании. Так что вполне вероятно никакой дефрагментации не потребуется. |
|
![]() |
#2 |
Moderator
|
Цитата:
Я набросал еще один джоб, помогающий понять степень заполненности базы по диапазонам-этапам (stages) размером в 100 млн. номеров RecId. X++: static void Job351_CountRecIdsPerStage(Args _args) { // расчет количеств RecId по этапам int i, nLines; int timeFullStart, timeFullFinish; Dictionary dictionary = new Dictionary(); TableId tableId; DictTable dictTable; Common common; int row, timeStart; int recordCount; int stage; int stageCnt = 22; int recIdPerStage = 100000000; int recIdStart = 1; int recIdEnd = recIdPerStage; int recIdCount; ; timeFullStart = timenow(); for (stage=1; stage<= stageCnt; stage++) { recIdCount = 0; for (i=1; i<= dictionary.tableCnt(); i++) { tableId = dictionary.tableCnt2Id(i); dictTable = new DictTable(tableId); print strFmt('%1 -- %2 -- %3', stage, tableId, dictTable.name()); // если в очередной таблице нет записей // то переходим к следующей try { nLines = infolog.line(); recordCount = new SysDictTable(tableId).recordCount(); } catch //может случиться, если таблица есть в репозитарии, но нет в базе { infolog.clear(nLines); recordCount = 0; } if (! recordCount) continue; common = dictTable.makeRecord(); select count(RecId) from common where common.RecId >= recIdStart && common.RecId <= recIdEnd; recIdCount += common.RecId; } info(strFmt('%1 -- %2 -- %3 -- %4', stage, recIdStart, recIdEnd, recIdCount)); if (! recIdCount) break; recIdStart = recIdEnd + 1; recIdEnd = recIdEnd + recIdPerStage; } timeFullFinish = timenow(); box::info(strfmt('Total running time: %1 sec', timeFullFinish - timeFullStart)); } Код: stage recIdStart recIdEnd recIdCount % к 100 млн. --------------------------------------------------------------- 1 1 100 000 000 8 050 727 8% 2 100 000 001 200 000 000 878 353 1% 3 200 000 001 300 000 000 1 478 347 1% 4 300 000 001 400 000 000 1 131 490 1% 5 400 000 001 500 000 000 2 195 859 2% 6 500 000 001 600 000 000 1 427 424 1% 7 600 000 001 700 000 000 1 259 705 1% 8 700 000 001 800 000 000 2 905 657 3% 9 800 000 001 900 000 000 16 803 406 17% 10 900 000 001 1 000 000 000 12 565 324 13% 11 1 000 000 001 1 100 000 000 16 741 287 17% 12 1 100 000 001 1 200 000 000 21 317 892 21% 13 1 200 000 001 1 300 000 000 11 187 373 11% 14 1 300 000 001 1 400 000 000 0 0% --------------------------------------------------------------- 97 942 844 Кстати, нашёл у себя аксесный mdb-файл на 28 млн. записей таблицы UsedRecId (см. мой пред. пост). Так вот этот файл имеет размер 1 Gb. Можно использовать это соотношение как оценочное при планировании "завоевания" этапов. Alenka, а у вас поставщик-внедренец Аксапты - не GMCS ли тоже? У них в приложении масса полезных запросов-отчетов, которые, тем не менее, RecId расходуют нещадно - за счет заполнения вспомогательных таблиц временными данными (не путать с временными таблицами). Т.е. на "совесть" этих запросов-отчетов в нашем приложении половину дыр точно можно списывать... |
|
|
За это сообщение автора поблагодарили: aidsua (1), G.Menshikh (1). |
![]() |
#3 |
Участник
|
легко. экспорт/импорт с удалением.
|
|
![]() |
#4 |
Участник
|
2 Gustav: внедряли Аксапту нам КОРУС Консалтинг.
Такое кол-во пустот в нумерации действительно возникает из-за таблиц с временными данными, жизнь которых составляет от1 дня до 2 недель. Пустота вначале тоже есть, но она составляет всего около 2 млн. |
|
|
За это сообщение автора поблагодарили: Gustav (2). |
![]() |
#5 |
Участник
|
Наконец-то нашлось время на испытание, проверку и тестирование идеи с триггером. Выяснилось, что, к сожалению, сама идея заполнения дыр, оставляя в запасе 25 номеров, "не дружит" с insert_recordset. При использовании insert_redordset значение nextVal в SystemSequence передвигается сразу на количество вставляемых записей. Поэтому необходимо держать в запасе в текущей дыре с неиспользованными RecId не 25 номеров, а неограниченное количество, что естественно невозможно.
2 Gustav: Этот случай был просто не учтен Вами или есть какое-то решение? Последний раз редактировалось Alenka; 14.01.2011 в 10:58. |
|
|
За это сообщение автора поблагодарили: Vadik (1), Gustav (3), S.Kuskov (1). |
![]() |
#6 |
Участник
|
|
|
|
За это сообщение автора поблагодарили: Vadik (1), Alenka (1). |
![]() |
#7 |
Moderator
|
Цитата:
Сообщение от Alenka
![]() Наконец-то нашлось время на испытание, проверку и тестирование идеи с триггером. Выяснилось, что, к сожалению, сама идея заполнения дыр, оставляя в запасе 25 номеров, "не дружит" с insert_recordset. При использовании insert_redordset значение nextVal в SystemSequence передвигается сразу на количество вставляемых записей. Поэтому необходимо держать в запасе в текущей дыре с неиспользованными RecId не 25 номеров, а неограниченное количество, что естественно невозможно.
2 Gustav: Этот случай был просто не учтен Вами или есть какое-то решение? Цитата:
Сообщение от Gustav
![]() 2. У таблицы SystemSequence в Ax 3.0 имеется метод setCacheSize, позволяющий установить размер кэша иным, нежели 25. Перед использованием триггера рекомендуется проверить код приложения Аксапты на присутствие вызовов этого метода (у меня не было ни одного). При необходимости можно увеличить minDelta в триггере до значения максимального параметра этих вызовов, либо (более муторно) в триггере предусмотреть генерирование ошибки (исключения) при попытке Аксапты сделать шаг больше, чем 25.
Логично? Или я выдаю желаемое за действительное? Еще раз отмечу, что в данный момент могу рассуждать только теоретически. |
|
![]() |
#8 |
Участник
|
Нет, такой анализ не поможет, т.к. проанализировать-то можно, а исправить ничего уже будет нельзя, т.к. вставляемым записям будут присваиваться RecId, начиная со старого значения. Т.е. надо было при предыдущем смещении nextVal "предусмотреть" возможность вставки с помощью insert_recordset.
|
|
![]() |
#9 |
Участник
|
Боюсь это придется делать в АХ, т.е. "прошерстить" код и делать уже там перенаправление на самую большую дырку
Можно попробовать забить на эту проблему, ну не пройдет с первого раза транзакция, так пройдет со второго ![]() Потом в АХ найдется немного мест, которые требуют уникальности RecId в разрезе нескольких таблиц, т.ч. шансы на удачный исход дополнительно повышаются ![]() |
|
|
За это сообщение автора поблагодарили: Gustav (2). |
![]() |
#10 |
Участник
|
Беда в том, что (:Old.NextVal) и является первым выделенным RecId для текущей вставки, а (:New.NextVal) очередной RecId уже для следующей вставки и изменить можно только его.
|
|
![]() |
#11 |
Moderator
|
Цитата:
Сообщение от Alenka
![]() Нет, такой анализ не поможет, т.к. проанализировать-то можно, а исправить ничего уже будет нельзя, т.к. вставляемым записям будут присваиваться RecId, начиная со старого значения. Т.е. надо было при предыдущем смещении nextVal "предусмотреть" возможность вставки с помощью insert_recordset.
Цитата:
![]() insert_recordset, желающий вставить 100 записей (вместо 25), вероятно, возьмет старый nextVal и прибавит к нему 100 и попытается сохранить в SystemSequence для последующих запросов. Что можем мы в этой ситуации? Можем увидеть, что собирается быть выполненным шаг больше 25, а также проверить существует ли свободное пространство в текущей дыре для выполнения этого шага. Если оно есть, то всё в порядке. Если его нет, то выбирать следующую подходящую дыру бесполезно, так как наш insert_recordset уже запомнил для себя 100 последовательных номеров - надо генерить ошибку (исключение). При этом можно, конечно, уже иметь на примете следующую подходящую дыру. В общем, дальнейший успех зависит от того, сможем ли мы хорошо обработать это исключение. Тогда текущая попытка увеличения nextVal будет как бы холостым шагом, а следующая после обработки исключения попытка выделения 100 номеров будет успешной. Блин, должна быть! |
|
Теги |
ax3.0, recid, дефрагментирование recid, законченный пример, полезное |
|
![]() |
||||
Тема | Ответов | |||
if (record) vs if (record.RecId) | 18 | |||
поля, содержащие RecId | 15 | |||
Что лучше select RecId или select TableId | 9 | |||
aEremenko: Дефрагментация RecID | 2 | |||
Два RecId у одной записи таблицы | 33 |
Опции темы | Поиск в этой теме |
Опции просмотра | |
|