07.12.2010, 14:29 | #1 |
Участник
|
Миф об уникальности RecId?
Axapta 3.0 SP3
Добрый день. Хочу опять поднять вопрос о RecId. Дело в том, что мы столкнулись с проблемой заканчивающихся номеров RecId, т.е. мы уже давно перешли на отрицательные значения и в течение ближайших месяцев снова должны достигнуть 0. На форуме уже обсуждалась эта проблема и высказывались предположения о том, что же произойдет после того, как будет достигнто нулевой значение. При этом высказывалась мысль о том, что при создании новой записи в таблице будет искаться неиспользованное значение RecId, т.е. будут заполняться пустоты в нумерации. Было также предположение, что никакого поиска не будет, а при вставки новой записи с существующим RecId будет возникать ошибка. Я решила промоделировать эту ситуацию на тестовой базе. Сдвинула NextVal в SystemSequences на значение, близкое к нулю. Как и ожидалось, RecId снова стало принимать положительные значения. Но! стали появляться записи с уже существующими RecId. Хотелось бы услышать ваше мнение по данному вопросу. Получается, что уникальность RecId - это миф? |
|
07.12.2010, 14:37 | #2 |
Модератор
|
Миф - это идея о том, что в системе есть функциональность, которая будет искать свободные "дырки" в диапазонах выделенных значений RecId
А уникальность RecId в таблице при наличии уникального индекса по этому полю - не миф см. Как выполнять дефрагментирование RecID
__________________
-ТСЯ или -ТЬСЯ ? |
|
|
За это сообщение автора поблагодарили: Alenka (1). |
07.12.2010, 14:41 | #3 |
Участник
|
Дефрагментация стандартными способами на нашей базе невозможна из-за ее размера (около 500Гб) и потере целостности (стандартный метод не правит те ссылки на RecId, которые хранятся в таблицах).
Как же уникальность не миф, когда я получила по крайней мере 2 записи с одинаковыми RecId? |
|
07.12.2010, 14:41 | #4 |
Axapta
|
Вы все неправильно понимаете. Смотрите, для 3.0 ситуация такая. Генерация Аксаптой нового RecId проста как три копейки. Аксапта грубо говоря (опустим сейчас не значащие для нас нюансы) берет соответствующее последнее значение из номерной серии и прибавляет к нему единицу. Все, данное значение и записывается в таблицу. Разумеется, Аксапта не проверяет никакую уникальность, и не пытается найти неиспользуемый номер. Представляете, с какой бы скоростью она работала, если бы каждый раз это делала?!
Поэтому никакой гарантированной уникальности RecId в пределах всей базы нет. Проблема возникает, если в той же самой таблице, в которой мы создаем запись, уже есть запись с таким RecId Соответственно, как только у вас RecId пойдут по второму кругу, вы будете в случайные моменты времени все чаще и чаще сталкиваться с такой ошибкой. А вообще, возникающие проблемы и возможные способы решения уже обсуждались и не один раз. |
|
|
За это сообщение автора поблагодарили: Alenka (1). |
07.12.2010, 14:44 | #5 |
Модератор
|
Цитата:
Стандартный метод корректно правит ссылки в пределах одной компании там, где они оформлены корректно (с использованием правильных EDT) Делает он это неторопливо, но даже в Вашем случае за сутки отработать
__________________
-ТСЯ или -ТЬСЯ ? |
|
07.12.2010, 14:57 | #6 |
Участник
|
2 Vadik : Просто я ее уже читала раньше.
2 oip: Все правильно, я неверно понимала понятие уникальности. Ошибка при вставке и сообщение о существующей записи появляются при создании записи с существующим RecId в этой же таблице. При этом запись все-таки создается со следующим RecId. Спасибо за помощь и наставления . |
|
07.12.2010, 15:05 | #7 |
Модератор
|
Значит невнимательно читали, потому что Ваши выводы и аргументация ошибочны
Цитата:
Дефрагментация стандартными способами на нашей базе невозможна из-за ее размера (около 500Гб) и потере целостности (стандартный метод не правит те ссылки на RecId, которые хранятся в таблицах)
__________________
-ТСЯ или -ТЬСЯ ? |
|
07.12.2010, 15:35 | #8 |
Участник
|
Надо просто найти поля где хранятся ссылки на RecID и исправить EDT поля на RefRecId - тогда обновляться все будет корректно.
|
|
07.12.2010, 16:19 | #9 |
Участник
|
Согласна, целостность может и не потеряется (нельзя ручаться за правильность EDT всех полей, использующих RecId), но время, требующееся для дефрагментации такой базы, по-моему вы указали сомнительное. Хотя продолжать дискуссию на эту тему - дело неблагодарное, т.к. проверить время выполнения дефрагментации на нашей базе не представляется возможным. Но в той же ветке, что вы указали есть примеры, когда 40Гб база дефрагментировалась несколько дней. Оптимизма это не прибавляет.
|
|
07.12.2010, 16:46 | #10 |
Злыдни
|
Скорость дефрагментации RecId очень сильно зависит от производительноти сервера и скорости работы дисковой подсистемы. Лет 5 назад проводил дефрагментацию на базе размером в 25 Гигов. Сервер с двумя старенькими Xeon-ами, 4Gb оперативки и SCSI подсстемой (RAID-10) пережевал дефрагментацию за час с небольшим. При этом не должны работать пользователи и пакетники. Я думаю, что в Вашем случае все должно уложиться в один выходной день. Можете, во избежании случайных подключений, запустить дефрагментацию в двухуровневой конфигурации.
__________________
люди...считают, что если техника не ломается, то ее не нужно ремонтировать. Инженеры считают, что если она не ломается, то нуждается в совершенствовании. |
|
07.12.2010, 16:59 | #11 |
Модератор
|
Цитата:
Цитата:
.. но время, требующееся для дефрагментации такой базы, по-моему вы указали сомнительное
Цитата:
Хотя продолжать дискуссию на эту тему - дело неблагодарное, т.к. проверить время выполнения дефрагментации на нашей базе не представляется возможным
Цитата:
Но в той же ветке, что вы указали есть примеры, когда 40Гб база дефрагментировалась несколько дней. Оптимизма это не прибавляет.
__________________
-ТСЯ или -ТЬСЯ ? |
|
07.12.2010, 17:12 | #12 |
Участник
|
2 KiselevSA: Откуда такая уверенность, что линейное увеличение размеров базы приведет к линейному увеличению времени дефрагментации? Если 25Гб пересчитывалась 1 час, то это не значит, что база в 20 раз больше будет обрабатываться в 20 раз дольше.
2 Vadik: Если бы сидели на попе ровно, то вообще бы эта тема не появилась |
|
07.12.2010, 19:14 | #13 |
Модератор
|
Цитата:
- что уже сделали (попробовали, проверили) - что собираетесь делать (пробовать, проверять) - сколько компаний - есть ли виртуальные - версия СУБД Цитата:
Если 25Гб пересчитывалась 1 час
__________________
-ТСЯ или -ТЬСЯ ? |
|
07.12.2010, 19:47 | #14 |
Участник
|
Не помню, был ли где уже подобный совет, поэтому, возможно, повторюсь.
Для начала, неплохо бы было посмотреть "глазами" на значение RecId тех таблиц, где приблизились к ранее использовавшимся значениям на предмет того, не было ли массовых удалений или ручной правки значения счетчика RecId. Т.е. "глобальных" разрывов в последовательности RecId. Все таблицы смотреть не обязательно, достаточно посмотреть таблицу, в которой наиболее часто создают новые записи (например, InventTrans). Причем создаются не раз в месяц большими партиями (закрытие склада), а достаточно регулярно. Тут важен именно момент создания, а не модификации. Ну, простейший запрос вида Код: select dataAreaId, round(RecId/1000000,0), count(*) from InventTrans with (nolock) group by dataAreaId, round(RecId/1000000,0) order by 1,2 Правда, такой совет подойдет, скорее, для виртуальных компаний, где не так уж и много таблиц и относительно легко найти "дыры" в последовательности значений. Для "обычных" компаний придется писать скрипт по перебору всех таблиц (не сложно, но "муторно"), чтобы убедиться, что найденная "дыра" действительно "дыра" RecId, а не просто большая группа удаленных записей в одной..двух таблицах. PS: Ага, была озвучена эта идея http://axforum.info/forums/showthrea...992#post110992 Цитата:
По результатам телефонного митинга с John McBride (менеджер команды разработки) и Mathieu Kemenovic (глобальная служба поддержки) мне подтвердили что они ничего менять в 3.0 не будут (и даже не будут делать private hot-fix) и предоставлили набор SQL-скриптов, которые ищут большие "дырки" последовательности идентификаторов записей и используют их. Данные скрипты неавтоматические и необходимо выполнять ряд шаманских танцев с бубнами...
|
|
07.12.2010, 20:22 | #15 |
Участник
|
Возможно, у автора появился повод для перехода на новую версию?
__________________
Ivanhoe as is.. |
|
07.12.2010, 21:10 | #16 |
Moderator
|
В порядке эксперимента - автоматическое использование дыр RecId
Эх, готовил материал для сообщения в блоге (где-то уже с года полтора назад), все собирался нормально оформить и выложить, да, чувствую, если сейчас не сообщу, то для "трёшки" уже совсем никому не надо будет. Поэтому несколько сумбурно, схематично, но выкладываю. Ветка, вроде, подходящая
Честно скажу, в промышленной эксплуатации не пользовал (не припёрло), но на тестовой всё отрабатывало довольно прилично. Axapta - 3.0 SP4, СУБД - Oracle 10. Общий смысл такой - заставить Аксапту автоматически использовать имеющиеся дыры RecId. Для этого нужно провести подготовительную работу: при помощи самописного скрипта пробежаться по всем таблицам системы и собрать информацию о неиспользованных интервалах RecId. Для Ax 3.0 (двухзвенка, без АОС) имеет смысл отбирать только непрерывные диапазоны размером не менее 25, т.е. не меньше размера кэша. Далее грузим полученные диапазоны в таблицу дыр (не аксаптовскую, просто созданную на уровне БД в той же схеме): Код: CREATE TABLE RECIDHOLES ( FROMRECID NUMBER(10), TORECID NUMBER(10) ) Код: ALTER TABLE RECIDHOLES ADD ( CHECK (TORECID-FROMRECID+1>=25)) Код: CREATE OR REPLACE TRIGGER SystemSequences_TBU BEFORE UPDATE ON SYSTEMSEQUENCES REFERENCING NEW AS New OLD AS Old FOR EACH ROW WHEN ( SUBSTR(NLS_LOWER(Old.DataAreaId),1,3) = 'ppp' AND Old.Id = -1 AND Old.TabId = 0 ) DECLARE currNextVal NUMBER(10); cntBetween NUMBER(10); cntAbove NUMBER(10); minDelta NUMBER(10); b4switching NUMBER(10); holesRange RecIdHoles%ROWTYPE; BEGIN b4switching := 1118091751; -- NextVal перед переключением (передвинуть с запасом на 100-200, чтобы не схватили) minDelta := 25; -- Axapta 3.0 Cache Size currNextVal := :New.NextVal; -- значение, которое собирается вставить Аксапта -- если здесь 1, то более ничего не делаем - :New.NextVal проходит в таблицу SELECT COUNT(*) INTO cntBetween FROM RecIdHoles h WHERE currNextVal BETWEEN h.FromRecId AND h.ToRecId AND h.ToRecId - currNextVal + 1 >= minDelta; IF cntBetween = 0 THEN -- иначе попадаем сюда и устанавливаем новое значение, равное FromId следующего диапазона SELECT COUNT(*) INTO cntAbove FROM RecIdHoles h WHERE h.FromRecId > currNextVal AND h.ToRecId - h.FromRecId + 1 >= minDelta; -- на всякий случай IF cntAbove > 0 THEN -- если мы в диапазонах, охватываемых таблицей дыр RecIdHoles SELECT * INTO holesRange FROM (SELECT * FROM RecIdHoles h WHERE h.FromRecId > currNextVal AND h.ToRecId - h.FromRecId + 1 >= minDelta -- на всякий случай ORDER BY h.FromRecId) WHERE ROWNUM = 1; currNextVal := holesRange.FromRecId; ELSE -- если уже нет IF currNextVal <= b4switching THEN -- значит кончились записи в таблице дыр RecIdHoles currNextVal := b4switching; END IF; -- если currNextVal > b4switching, то уже всё поехало нормально END IF; :New.NextVal := currNextVal; END IF; EXCEPTION WHEN OTHERS THEN -- Consider logging the error and then re-raise RAISE; END SystemSequences_TBU; P.S. ОГРАНИЧЕНИЯ: 1. В текущей редакции триггер можно использовать на монотонно возрастающем участке генерации RecId, достаточно далеком от крайних значений, т.е. перевалка через максимальное значение (2G) и продолжение с минимального (-2G) текущим алгоритмом не предусмотрена. 2. У таблицы SystemSequence в Ax 3.0 имеется метод setCacheSize, позволяющий установить размер кэша иным, нежели 25. Перед использованием триггера рекомендуется проверить код приложения Аксапты на присутствие вызовов этого метода (у меня не было ни одного). При необходимости можно увеличить minDelta в триггере до значения максимального параметра этих вызовов, либо (более муторно) в триггере предусмотреть генерирование ошибки (исключения) при попытке Аксапты сделать шаг больше, чем 25. По иронии судьбы в Ax 4.0 метод setCacheSize отсутствует, но в "четверке" уже и подобный триггер не нужен Последний раз редактировалось Gustav; 08.12.2010 в 11:13. |
|
|
За это сообщение автора поблагодарили: fed (3), Vadik (1), Владимир Максимов (10), gl00mie (10), Alenka (1), Mileyko (1). |
08.12.2010, 00:17 | #17 |
Модератор
|
А код, который отыщет свободные диапазоны RecId в компании на объеме данных, сопоставимом с постановкой задачи (500Гб) - будет?
__________________
-ТСЯ или -ТЬСЯ ? |
|
08.12.2010, 00:22 | #18 |
Модератор
|
- неспортивно
- неуплаченная "дань за двенадцать лет" (поддержка) зело велика будет - перевод тройки на 2009 - челлендж покруче любой дефрагментации RecId
__________________
-ТСЯ или -ТЬСЯ ? |
|
|
За это сообщение автора поблагодарили: CDR (1). |
08.12.2010, 10:14 | #19 |
Участник
|
Цитата:
2. Про неуплаченную дань не в курсе, я что-то пропустил? =) 3. Ну, можно вообще дождаться чьего-нибудь пожелания перейти на SAP - мне кажется с т.з. сотрудников поддержки Ax это еще большее зло
__________________
Ivanhoe as is.. |
|
08.12.2010, 10:19 | #20 |
Участник
|
А нет ли в базе чего-нибудь "лишнего" ? Типа :
1. InventSettlement (Cancelled == true) 2. InventSumLogTTS (не используется сводное планирование) 3. SysDataBaseLog и прочие логи 4. SalesParmTable и подобные *Parm* 5. и т.д. Может можно почистить базу и облегчить АХ задачу по дефрагментации ? |
|
Теги |
ax3.0, recid, дефрагментирование recid, законченный пример, полезное |
|
Похожие темы | ||||
Тема | Ответов | |||
if (record) vs if (record.RecId) | 18 | |||
поля, содержащие RecId | 15 | |||
Что лучше select RecId или select TableId | 9 | |||
aEremenko: Дефрагментация RecID | 2 | |||
Два RecId у одной записи таблицы | 33 |
Опции темы | Поиск в этой теме |
Опции просмотра | |
|