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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 07.12.2010, 21:10   #11  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
В порядке эксперимента - автоматическое использование дыр RecId
Эх, готовил материал для сообщения в блоге (где-то уже с года полтора назад), все собирался нормально оформить и выложить, да, чувствую, если сейчас не сообщу, то для "трёшки" уже совсем никому не надо будет. Поэтому несколько сумбурно, схематично, но выкладываю. Ветка, вроде, подходящая

Честно скажу, в промышленной эксплуатации не пользовал (не припёрло), но на тестовой всё отрабатывало довольно прилично. Axapta - 3.0 SP4, СУБД - Oracle 10.

Общий смысл такой - заставить Аксапту автоматически использовать имеющиеся дыры RecId. Для этого нужно провести подготовительную работу: при помощи самописного скрипта пробежаться по всем таблицам системы и собрать информацию о неиспользованных интервалах RecId. Для Ax 3.0 (двухзвенка, без АОС) имеет смысл отбирать только непрерывные диапазоны размером не менее 25, т.е. не меньше размера кэша. Далее грузим полученные диапазоны в таблицу дыр (не аксаптовскую, просто созданную на уровне БД в той же схеме):
Код:
CREATE TABLE RECIDHOLES
(
  FROMRECID NUMBER(10),
  TORECID   NUMBER(10)
)
Для пущей убедительности добавим проверочку на размер диапазона не менее 25 упомянутых выше идентификаторов
Код:
ALTER TABLE RECIDHOLES ADD (
  CHECK (TORECID-FROMRECID+1>=25))
Ну и наконец на таблицу SystemSequences вешаем триггер BEFORE UPDATE:
Код:
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;
Всё! Аксапта начинает генерить RecId под управлением диапазонов таблицы RECIDHOLES.

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).
Теги
ax3.0, recid, дефрагментирование recid, законченный пример, полезное

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
if (record) vs if (record.RecId) kashperuk DAX: Программирование 18 27.11.2008 18:53
поля, содержащие RecId somebody DAX: Программирование 15 16.05.2008 17:50
Что лучше select RecId или select TableId Logger DAX: Программирование 9 02.06.2007 15:13
aEremenko: Дефрагментация RecID Blog bot DAX Blogs 2 06.03.2007 22:25
Два RecId у одной записи таблицы sparur DAX: Программирование 33 18.12.2006 15:56

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

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

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