11.01.2012, 23:13 | #1 |
Administrator
|
AX 2012 Наследование таблиц. Краткое описание механизма
Добрый день! Пришлось тут в рамках подготовки к курсу 80299 What's New -Technical in Microsoft Dynamics AX 2012 for Development поисследовать AX 2012, и, поискав достаточно скудную информацию о наследовании таблиц (на русском – так вообще отсутствующую) – решил поисследовать самостоятельно – что же это за технология изнутри. Описанное ниже является исключительно моим мнением, не претендующим на истину в последней инстанции, и не являющееся заменой документации по данной функциональности.
Предназначение Данная технология хорошо предназначена для разделения одной большой таблицы по полям на несколько маленьких (подразумевается вертикальное разделение – когда часть полей из большой таблицы «уезжает» в другую). Хорошим примером ситуации, когда наследование таблиц имеет смысл применять – являются таблицы InventJournalTrans / LedgerJournalTrans – строки журналов, в которых имеются поля, специфичные только для журналов определенного типа, а для остальных данных – они являются ненужными. Примером здесь могут являться поля, относящиеся к основным средствам (для LedgerJournalTrans) или поля, относящиеся к инвентаризации (для InventJournalTrans). Принцип построения структуры таблиц в СУБД Наследование таблиц, как технология – реализована в АХ 2012 по принципу абстрагирования программиста от СУБД (как в 1С), когда разработчик задает системе некоторые принципы, а ядро реализует эти принципы в СУБД и при исполнении кода. На самом деле – эта идеология (с т.з. структуры СУБД) уже была применена в АХ 2009 в таблицах InventJournalTrans и InventJournalTrans_Tag, а также в LedgerJournalTrans и LedgerJournalTrans_Asset, LedgerJournalTrans_Project, LedgerJournalTrans_RCash, LedgerJournalTrans_RAsset, LedgerJournalTrans_RDeferrals. Все эти таблицы связаны друг с другом отношением 1:0 или 1:1 (т.е. к примеру – в таблице LedgerJournalTrans_Asset может присутствовать только одна запись для одной записи в LedgerJournalTrans или же полностью отсутствовать, если запись в LedgerJournalTrans не имеет отношения к международным Осам). Связка осуществляется по RecId. Из этого списка несколько выпадают таблицы LedgerJournalTrans_RDeferrals (здесь в одной записи – ссылки на две разных записи в LedgerJornalTrans) и InventJournalTrans_Tag (здесь связь осуществляется по JournalId + LineNum, а не RecId). Кстати говоря, эти таблицы так и остались в АХ 2012 без иерархии (т.е. не состоящие в иерархии). Таким образом, всю цепочку таблиц, участвующих в иерархии можно взять и заменить одной большой мегатаблицей, в полях которых будет много пустых данных. Поля в этой одной большой мегатаблице будут состоять из всех полей всех таблиц, участвующих в иерархии (за исключением, безусловно системных полей). Состав функционала иерархии таблиц В АХ 2012 под иерархией (наследованием) таблиц (Table Hierarchy, Table Inheritance) подразумевается: · Функционал ядра, позволяющий строить структуру таблиц, описанную выше, связи между которыми будут осуществляться по RecId родительской таблицы (в нашем примере иерархия двухуровневая и родительскими таблицами являются это LedgerJournalTrans / InventJournalTrans). Важно! RecId производной таблицы совпадает с RecId базовой, т.о. в производной таблице может быть не более одной записи, соответствующей записи в базовой (родительской) таблице. · Функционал наследования методов у производной таблицы (Derived Table) от ее родительской / базовой (Base Table) · Функционал автоматического добавления всех базовых и производных таблиц на форму, при добавлении таблицы из иерархии на форму · Функционал выбора производной таблицы на форме при создании записи (в таблицах, которые являются базовыми к добавляемой – запись создается автоматически при создании записи в таблице, прописанной в датасорсе. Задача разработчика – обеспечить возможность заполнения всех обязательных полей во всех таблицах иерархии при создании записи – иначе запись сохранена не будет). · Механизм настройки иерархии таблиц в АОТ. Запрос, генерирующийся к СУБД на форме Запрос, генерирующийся к СУБД на форме содержит в себе все таблицы из иерархии – как производные, так и базовые (т.к. везде нужно добавлять одно и тоже значение RecId). Т.о. крупная иерархия (состоящая из большого количества таблиц) может привести к большому количеству джойнов, причем связи между таблицами осуществляются по LEFT OUTER JOIN, что не добавляет скорости к выборке (по сравнению с INNER JOIN). Поддержка сортировки и фильтрации таблиц, связанных по LEFT OUTER JOIN на форме появилась в AX 2012, поэтому эти данные можно на форме фильтровать / сортировать, как будто это одна большая мегатаблица. «Академическим» примером наследования таблиц является глобальная адресная книга (DirPartyTable). Посмотрим, как это все будет выглядеть на форме. Для этого создадим простейшую форму, в которую добавим датасорс DirPartyTable И добавим грид с полями из разных таблиц: DirPartyTable.Name DirPerson.BirthMonth DirPerson.BirthYear DirPerson.BirthDay DirOrganizationBase.PhoneticName Поля, помеченные кружочком являются unretrieved, т.е. невыбираемыми (проще говоря, из-за LEFT JOIN там стоит значение NULL, т.к. запись в соответствующей таблице отсутствует). Пустые значения (без кружочка) означают наличие записи в соответствующей таблице и незаполненное поле. На скриншоте видно, что, например, для записи «Coho Receivers» в DirPartyTable отсутствует запись в таблице DirPerson, но присутствует запись в таблице DirOrganizationBase с пустым значением поля PhoneticName. Запрос, отправляемый к СУБД в этом случае выглядит так: В виде T-SQL: Если же мы вдруг решили добавить на форму таблицу из середины иерархии, к примеру OmInternalOrganization, то запрос к СУБД в этом случае будет выглядеть так: В виде T-SQL: В этом примере наглядно видно, как из запроса исчезла таблица DirPerson, т.к. она не является ни базовой ни производной к таблице OmInternalOrganization. Также обращаю внимание на появление CROSS JOIN-ов к базовым таблицам. Вопрос осмысленности добавления таблицы из середины иерархии я оставляю в стороне, т.к. цель данной статьи – показать, как это будет работать в различных вариантах исполнения. А понимание бизнес-применения наследования таблиц придет со временем. Процедура создания иерархии таблиц 1. Создать обе таблицы (базовую и производную), как элементы в АОТ без дополнительных полей. 2. Создать в базовой таблице поле типа Int64, наследованное от типа \System Documentation\Types\RelationType и назвать его InstanceRelationType (должно быть точно такое название). В этом поле будет храниться код производной таблицы (TableId). 3. На базовой таблице включить свойство SupportInheritance = Yes и выбрать в свойстве InstanceRelationType одноименное только что созданное поле. Сохранить базовую таблицу. 4. На производной таблице включить свойство SupportInheritance = Yes и выбрать в свойстве Extends базовую таблицу. Автоматически создастся Relation на базовую таблицу. Сохранить производную таблицу. Свойства созданного Relation: 5. Добавить остальные необходимые поля в базовую и производную таблицу. Версия системы Данная статья подготовлена по версии АХ 2012: Kernel version: 6.0.947.0 Application version: 6.0.947.0 Обсуждение на форуме ранее axdaily: Table inheritance Наследование таблиц в 2012, кто нибудь уже использовал ? Обновление для версии R2 и R3 В AX2012 R2 механизм наследования таблиц немного изменили. На уровне АОТ механизм остался таким же как и был, а вот на уровне СУБД - теперь вся цепочка таблиц представляет собой одну большую базовую табличку, в которой собраны все поля из производных таблиц. Т.о. в вышеописанном примере все поля из таблички DirPerson и DirOrganizationBase "переехали" в DirPartyTable. А сами таблички исчезли из общего списка таблиц (их нет в БД; в т.ч. их описания нет в SQLDictionary). В частности, теперь не стало таблички CompanyInfo, т.к. она также наследуется от DirPartyTable и, как следствие, все поля из этой таблички были перенесены в DirPartyTable. Соответственно, все запросы (в т.ч. обновления данных) к БД упростились, т.к. теперь выборка осуществляется из одной таблицы, в случае подцепления любой таблицы из иерархии в датасорс формы. Разница в выборке из производной таблицы и из базовой теперь лишь состоит в количестве полей, перечисленных в конструкции SELECT (при выборке в Х++ из производной таблицы - запрос к БД посылается к базовой таблице, но только по тем полям, которые перечислены в АОТе в производной таблице). Правда, выборка из производной таблицы дополнительно фильтруется по тем записям, которые относятся только к ней. Т.е. запрос в Х++ X++: select dirPerson Обращаю внимание на дополнительный фильтр по полю InstanceRelationType - он обеспечивает отбор только тех записей, которые должны относиться к DirPerson А запрос в Х++ X++: select dirPartyTable Данная информация справедлива для версии R2 CU1 (Ядро и приложение - 6.2.1000.156) В версии R3 (Ядро и приложение - 6.3.164.0) никаких изменений по отношению к R2 по части данной статьи не произошло
__________________
Возможно сделать все. Вопрос времени Последний раз редактировалось sukhanchik; 01.06.2014 в 13:59. |
|
|
За это сообщение автора поблагодарили: mazzy (5), AlGol (2), macklakov (9), Berty Wooster (1), BOAL (9), AK-76 (1), Владимир Максимов (5), db (10), Pustik (5), Logger (10), lev (13), TasmanianDevil (7), ziva (2), AvrDen (1), oip (5), ivas (2), Stitch_MS (3), IvanS (1), Aquarius (1), alex55 (1), S.Kuskov (15), -Dmitry- (0), jeky (2), McArrow (1), Evgeniy_R (1). |
12.01.2012, 08:34 | #2 |
Участник
|
Спасибо большое. Ужасно интересно всё то, что не известно (С)
Цитата:
А можно ли их перекрывать? Доступны ли через курсор производной таблицы поля базовой таблицы? Цитата:
Если просто в коде написать "select DirPerson;" будет ли автоматически выбран DirPartyTable? Ещё прошу подтвердить или опровергнуть следующее высказывание: Одна и таже запись базовой таблицы может быть связана с записями одновременно из нескольких прозводных таблиц одного уровня иерархии? |
|
12.01.2012, 10:49 | #3 |
Участник
|
|
|
|
За это сообщение автора поблагодарили: mazzy (2), Logger (5), TasmanianDevil (7). |
12.01.2012, 14:50 | #4 |
Мрачный тип
|
Интересная штука, но, судя по документации, реализовано с неким анально-ориентированным уклоном.
Какой-то один из трех не вписывается в картину наследования таблиц и этот отщепенец - второй пункт. От первого мы отказаться не можем, третий требуется для обеспечения связей в м-ду родителями и наследниками - остается признать, что механизм выдачи RecId в наследуемых таблицах требует некоей модификации, чтобы выполнялись первый и третий пункты. Суть такой модификации - наследование RecId из базовой таблицы при вставке в наследуемые, при этом вот что получится при вставке в таблицу потомка нижнего уровня N, если для него нужен такой же RecId, как и у базовой:
Половину этих вызовов ( всех возвратов от базовой записи) можно было бы избежать, используя всего лишь еще одно , дополнительное у к уже имеющемуся полю InstanceRelationType, служебное поле-ссылку (какой-нибудь InstanceRelationRecId) в родительских таблицах на запись в таблице-наследнике. Тогда вставка в самый нижний уровень не ждала бы вставок с верхнего уровня, а все служебные join можно было реализовать как Select Родитель Left Outer Join Потомок On Родитель.InstanceRelationType = Потомок.TableId And Родитель.InstanceRelationRecId = Потомок.RecId.
__________________
Мы летаем, кружимся, нагоняем ужасы ... |
|
|
За это сообщение автора поблагодарили: gl00mie (5). |
12.01.2012, 18:42 | #5 |
Участник
|
Цитата:
Цитата:
Сообщение от sukhanchik
2. Создать в базовой таблице поле типа Int64, наследованное от типа \System Documentation\Types\RelationType и назвать его InstanceRelationType (должно быть точно такое название). В этом поле будет храниться код производной таблицы (TableId).
3. На базовой таблице включить свойство SupportInheritance = Yes и выбрать в свойстве InstanceRelationType одноименное только что созданное поле. Сохранить базовую таблицу. Впрочем, не знаю, что это за тип RelationType. Может, в Ax2012 этот тип данных допускает хранение неких списков значений?
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
|
За это сообщение автора поблагодарили: S.Kuskov (2). |
12.01.2012, 23:19 | #6 |
Administrator
|
Добрый день! Прошу прощение за отсутствие днем – был занят – до компьютера добрался только вечером.
Итак, отвечаю: 1. Ссылку от belugin можно расширить на несколько White Paper (http://www.microsoft.com/download/en....aspx?id=20864). Все они лежат в открытом доступе. На самом деле, если ввести в поисковик фразу White Paper AX 2012 можно найти сразу несколько документов по АХ 2012. Цитата:
Об этом говорил еще gigz в своем посте 3. Зачем было сделано равенство RecId между базовой и производной таблицами я не знаю. Но факты – вещь упрямая. Запрос в БД уходит таким, как я показал на скриншотах. 4. Абстрактные таблицы (свойство у таблицы Abstract = Yes). Я о них не стал писать, т.к. в документации сказано так: Any attempt to create a record and insert it in an abstract table will result in a run-time error. (Любые попытки создать запись и вставить ее в абстрактную таблицу приведет к ошибке выполнения). Однако, записи в DirOrganizationBase живут и спокойно себе создаются из формы-примера, который я привел. В чем тогда их абстрактность – я так и не понял. 5. По поводу наследования методов. Дока говорит о том, что «Developers can access the base table method on a derived table buffer. In addition, a derived table method can override a base table method and call super() to invoke the same method on the base table buffer» (Разработчики могут получать доступ к методам на базовой таблице через курсор на производной таблице. В дополнении – метод на производной таблице может перекрыть метод на базовой таблице и вызов super() вызовет метод на базовой таблице). Цитата:
Поля базовой таблицы доступны в производной через this Цитата:
Для Query после того как в АХ 2009 добавили возможность его добавлять на форму - его поведение можно считать такое же как и у формы. Т.е. также будут выбраны все таблицы из иерархии. Более того, в обозревателе таблиц теперь показывается все. Т.е. как бы на уровне АХ все таблицы, участвующие в иерархии "склеиваются" в одну. И о том, что таблицы все же разные напоминает лишь АОТ, да СУБД. Цитата:
Сообщение от TasmanianDevil
Зачем эти лишние вызовы и ожидания? Только для выполнения странной связи по RecId с обоих сторон join'а ? Как скажется на быстродействии вставки и блокировках на SystemSequences подобный многоступенчатый механизм, гарантирующий выполнение уникальности RecId по таблице и равные RecId у связанных записей в таблицах потомков/родителей ?
Половину этих вызовов ( всех возвратов от базовой записи) можно было бы избежать, используя всего лишь еще одно , дополнительное у к уже имеющемуся полю InstanceRelationType, служебное поле-ссылку (какой-нибудь InstanceRelationRecId) в родительских таблицах на запись в таблице-наследнике. Тогда вставка в самый нижний уровень не ждала бы вставок с верхнего уровня, а все служебные join можно было реализовать как Select Родитель Left Outer Join Потомок On Родитель.InstanceRelationType = Потомок.TableId And Родитель.InstanceRelationRecId = Потомок.RecId. С другой стороны - если рассуждать с позиции, что иерархия таблиц - суть есть одна большая таблица - то в общем-то один фиг - что вставлять одну большую запись в мегатаблицу, что вставлять много маленьких записей в иерархию. Если все делать в одной транзакции. Причем, как я понимаю - условие связи 1:1 (1:0), а не 1:N между базовой и производной таблицами никто не отменял. Возможно, поэтому и возник такой непростой механизм вставки записи. Нет. Никаких списков там нет. Я ж говорю - на наследование надо смотреть исходя из гипотезы о том, что это способ вертикального разделения большой мегатаблицы на много маленьких.
__________________
Возможно сделать все. Вопрос времени Последний раз редактировалось sukhanchik; 12.01.2012 в 23:23. |
|
|
За это сообщение автора поблагодарили: S.Kuskov (5). |
13.01.2012, 00:00 | #7 |
Участник
|
Мы как-то обсуждаем детали.
А по-моему интереснее другой вопрос : 1. Зачем это сделано ? 2. Какие задачи помогает решить проще и дешевле ? 3. Не получим ли мы провал в производительности системы из-за кучи объединенных табличек ? Выгоды от наследования табличек неочевидны. |
|
13.01.2012, 02:11 | #8 |
Участник
|
Наследнование сущностей существует в любом случае. В Ax2012 сделана поддержка одной из стратегий отображения этого отношения на таблицы БД. Про достоинства и недостатки разных стратегий можно почитать, например, здесь
|
|
13.01.2012, 12:53 | #9 |
Administrator
|
Цитата:
Цитата:
Для компьютера обучающегося, на котором разворачивается виртуалка с АХ 2009 предъявляются (в документах для проведения курса) в том числе такие требования:
На деле - если виртуалке дать 2 Гб - то она просто "летает" Для компьютера обучающегося, на котором разворачивается виртуалка с АХ 2012 предъявляются в том числе такие требования:
По факту получается следующее: Если взять сейлзовую виртуалку (с партнерсорса; она состоит из одного vhd-шника) и поместить ее на выделенный жесткий диск (на котором кроме нее больше вообще ничего нет) и отдать ей 6 Гб памяти то она будет работать неторопливо. А если же на этом диске запустить вторую пустую виртуалку "вхолостую" (только с Win2008 x32) и 1 Гб оперативки - то виртуалка с АХ2012 начинает безбожно тормозить и вешаться. Увеличение оперативки скорости не добавляет. Жесткий диск 2 Тб годичной давности. Увеличение памяти для виртуалки с АХ 2012 дает плюс только при глобальной компиляции / построении перекрестных ссылок и то больше из-за SQL Server. Реальный же прирост производительности наблюдается в том случае, когда запускаешь учебную виртуалку (для курсов) на разных дисках. Она состоит из 3-х vhd-шников, 2 из которых являются разностными. Если при этом не трогая последний, 3-й диск - создать чистый 4-й (тоже разностный), и поместить 3-й и 4-й на разный физические диски - то (согласно монитору ресурсов Windows) будет усиленное чтение с 3-го диска и усиленная запись на 4-й (туда будут писаться все изменения). Увеличение рекомендуемой оперативной памяти для виртуалки особо прироста производительности не дает . Кстати, перекрестные ссылки на таким образом сконфигурированной учебной виртуалке при отданной ей 12 Гб оперативки строились у меня чуть больше 24 часов. Предварительная глобальная компиляция (иначе построение ссылок вообще уходит в даун) заняла где-то часа 3-4. Отсюда напрашивается грустный вывод. Производительность АХ 2012 (впрочем, как и ожидалось при нормализации СУБД) упирается не столько в мощности процессора / памяти - сколько в скорость дисков и операций чтения/записи.
__________________
Возможно сделать все. Вопрос времени Последний раз редактировалось sukhanchik; 13.01.2012 в 13:01. |
|
|
За это сообщение автора поблагодарили: Logger (5). |
13.01.2012, 13:17 | #10 |
Участник
|
Цитата:
Производительность АХ 2012 (впрочем, как и ожидалось при нормализации СУБД) упирается не столько в мощности процессора / памяти - сколько в скорость дисков и операций чтения/записи.
|
|
13.01.2012, 13:39 | #11 |
Administrator
|
Цитата:
Сообщение от niksen
вывод такой интересный, я конечно не упираюсь в реляционную теорию бд, но при нормализации субд разве всё начинает зависеть от скорости хардов? может я как-то не так логику понимаю, но, допустим ненормализованная бд, в ней 3 таблицы, в каждой из которых допустим 1000 записей по 30 полей в каждом, то есть перебирается 30 000 значений ячеек в сумме 1000 строк, и нормализованная, в которой будет например 15 таблиц, но полей в каждой таблице будет гораздо меньше, то есть перелопачивание данных будет меньше, разве не так?
Причина 1. Когда мы пишем Х++ - обычно мы пишем запрос типа SELECT *, т.е. заведомо выбираем ВСЕ поля - сколько бы их ни было. Т.е. если нам нужно выбрать строку накладной, код клиента и группу клиента, то при денормализации, в которой группа клиентов сидит в накладной - мы не джойним всю таблицу клиентов и производим выборку только всех полей накладной. Если же в накладной нужных нам полей нет, то мы джойним таблицу клиентов и выбираем все поля из этой таблицы - т.е. хотим мы или нет - но выбираем мы больше полей. В случае разбиения большой таблицы на маленькие - появляются дополнительные поля - связки, которые тоже подлежат выборке. Причина 2. Индексы. Сколько бы ни было полей в таблице - поиск осуществляется по индексу, а не по Вашему алгоритму (не так часто требуется получить большой набор данных - сколько требуется найти записи, удовлетворяющие некоему критерию отбора). Причина 3 (следствие). Джойны всегда работают заведомо медленнее, чем выборка из одной таблицы. Плюс LEFT JOIN на порядок тормознутее INNER JOIN. Причина 4. Данные таблицы можно дефрагментировать внутри файла. А гарантировать, что нужные таблицы при выборке будут находиться рядом друг другом в файле БД - нельзя. Т.е. джойн - это еще дополнительная работа для диска.
__________________
Возможно сделать все. Вопрос времени |
|
13.01.2012, 13:51 | #12 |
Участник
|
Цитата:
Причина 2. Индексы. Сколько бы ни было полей в таблице - поиск осуществляется по индексу, а не по Вашему алгоритму (не так часто требуется получить большой набор данных - сколько требуется найти записи, удовлетворяющие некоему критерию отбора)
|
|
13.01.2012, 14:42 | #13 |
Administrator
|
Цитата:
Сообщение от niksen
я лишь предположил. То есть как я понимаю Вас, иерархия таблиц сделана не для увеличения скорости, а для удобства и увеличения скорости разработки в целом лишь для отдельных случаев или не так? то есть в общем случае - эта иерархия многим вообще никак не нужна? или наоборот? я просто не очень пойму Вашу позицию
С моей личной т.з. иерархия таблиц не будет работать на больших объемах данных (в документации, в частности, сказано - что ее не стоит применять на транзакционных таблицах, т.е. разработчики сего механизма понимали - что на больших объемах данных - этот механизм замедлит работу системы). Т.е. с моей личной т.з. эта иерархия не стоит тех затрат, которые потратили на ее реализацию. С т.з. структуры СУБД конечно. Наследование же методов - штука полезная. Другое дело, что вполне возможно - что реализовать наследование методов можно было бы другим путем, не усложняя структуру. Например, убрать методы вообще с таблиц и добавить на таблицу ссылку на класс-обработчик методов на таблице, допустим для простоты строго с тем же названием. А в ядре бы сделать разделение - выборка бы шла по таблице, а обработка методов - по классу. В крайнем случае сделать доп. узел в АОТ что-то типа "Table Handler Classes". В 3.0 ведь создавался узел в Application Documentation и Application Developer Documentation автоматически при создании новой таблицы (даже не только таблицы). Так и тут можно было бы сие также повторить бы. И тогда бы появился и Class Declaration и классы можно было бы отнаследовать друг от друга. Конечно - там есть много спорных моментов. Но это по крайней мере не сказалось бы на производительности, а просто не ухудшило бы программирование. Можно было бы пойти и другим путем - расширить табличные Map-ы, таким образом, что можно было бы наследовать методы от них. Вполне возможно, что все это обсуждалось и был принят лучший вариант. Жизнь покажет, как это все будет востребовано. Просто на мой взгляд - если в таблице мало записей - то и делить-то ее особенной потребности нет. Ни с т.з. места на диске ни с т.з. повышения производительности. А вот задачу по обеспечению производительности больших таблиц наследование - не решает. Поэтому я пока не вижу ситуаций, когда применение наследования таблиц даст какое-либо преимущество перед одной большой таблицей или просто ручным делением таблиц с доп. полем RefRecID
__________________
Возможно сделать все. Вопрос времени |
|
|
За это сообщение автора поблагодарили: mazzy (5), Link (2). |
03.03.2013, 10:14 | #14 |
Administrator
|
Обновил информацию для версии R2 (т.к. там произошли некоторые изменения)
__________________
Возможно сделать все. Вопрос времени |
|
|
За это сообщение автора поблагодарили: mazzy (5), fed (3), S.Kuskov (10). |
03.03.2013, 10:42 | #15 |
Moderator
|
Очень, очень забавно. Версия 2012 выпускалась под флагом борьбы за нормализацию структур данных. В итоге - после столкновения с реальностью, в версии 2012R2 пришлось денормализовать те же данные до абсурдного состояния. Скрестить companyInfo и DirPartyTable - это уже денормализация за гранью добра и зла...
|
|
|
За это сообщение автора поблагодарили: mazzy (2), Logger (5). |
03.03.2013, 11:49 | #16 |
Administrator
|
Цитата:
Сообщение от fed
Очень, очень забавно. Версия 2012 выпускалась под флагом борьбы за нормализацию структур данных. В итоге - после столкновения с реальностью, в версии 2012R2 пришлось денормализовать те же данные до абсурдного состояния. Скрестить companyInfo и DirPartyTable - это уже денормализация за гранью добра и зла...
Важно другое. Фактически - этим изменением на мой взгляд похоронили саму идею иерархии таблиц. Ну т.е. в "теоретических" головах разработчиков ядра системы - можно конечно рисовать иерархию таблиц, а вот на практике, на мой взгляд - никто не будет заморачиваться с этой иерарихей, когда можно тупо создать одну большую мегатаблицу. При этом не придется заморачиваться наследованием методов (раз таблица одна, значит и методы на ней все). Т.е. автоматически исчезает потребность создавать производные таблицы, как средство размещения кода (проще все разместить на одной таблице, нежели себя обманывать и плодить псевдо-таблицу, которой нет в БД). Но в целом - я рад, что эта идея не прижилась. Уж больно (на мой взгляд) она была искусственной.
__________________
Возможно сделать все. Вопрос времени |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
03.03.2013, 12:59 | #17 |
Moderator
|
Цитата:
Сообщение от sukhanchik
Важно другое. Фактически - этим изменением на мой взгляд похоронили саму идею иерархии таблиц. Ну т.е. в "теоретических" головах разработчиков ядра системы - можно конечно рисовать иерархию таблиц, а вот на практике, на мой взгляд - никто не будет заморачиваться с этой иерарихей, когда можно тупо создать одну большую мегатаблицу. При этом не придется заморачиваться наследованием методов (раз таблица одна, значит и методы на ней все). Т.е. автоматически исчезает потребность создавать производные таблицы, как средство размещения кода (проще все разместить на одной таблице, нежели себя обманывать и плодить псевдо-таблицу, которой нет в БД). Ну и конечно, при проектировании прикладной структуры, разработчики должны понимать что каждый дополнительный уровень иерархии таблиц обходится намного дороже чем дополнительный уровень иерархии при проектировании классов. Заводить еще один уровень иерархии из за 1-2-3 аттрибутов - слишком накладно. |
|
|
За это сообщение автора поблагодарили: sukhanchik (3), S.Kuskov (2). |
03.03.2013, 13:08 | #18 |
Участник
|
Цитата:
Цитата:
не стоит привлекать злой умысел, когда достаточно простого бардака |
|
03.03.2013, 22:22 | #19 |
Роман Долгополов (RDOL)
|
Сам, увы, по нормальному с DAX2012 так и не работал, поэтому выскажусь на "общечеловескую" тематику основываясь на предыдущих сообщениях темы.
Чтобы понять что случилось надо рассмотреть возможные варианты отображения иерархий классов в таблицы БД. Применительно к DAX таблица в AOT с полями и методами это "класс", а соответствующая таблица в БД это просто "таблица" Несомненно наличие механизма отображения иерархий классов в реляционные бд вещь полезная, хоть и не жизненно необходимая Существуют три общепринятых способа такого отображения 1. Для каждого класса иерархии своя таблица в БД, содержащая только поля данного класса + прямолинейное отображение классов в таблицы, нет лишних полей, экономия пространства - чтобы получить данные конкретного класса нужен join - при измении структуры классов, перемещении полей надо следом всё это повторять в бд, т.е. физически перемещать поля между таблицами вместе с данными 2. Для каждого конкретного (неабстрактного) класса своя таблица в БД, содержащая все поля как данного класса, так и всех предков + Лишнего места (как и первый вариант) не занимает + Нет джойнов - Для построения каких либо отчетов и прочих операциях по промежуточному уровню иерархии появляется union - Так же как и в случае с первым вариантом изменения структуры классов приводят в необходимости следом изменить структуру таблиц, причем так как поля дублируются во многих таблицах, всё еще гораздо "запущеннее" - Проблемы с уникальностью ключевых полей. Так как индекс на каждой таблице свой, а constrain-ы привязаны к индексу, весьма вероятны задвоения значений ключевых полей. Т.е. БД перестает даже помогать управлять уникальностью значений и это должно быть реализовано в приложении 3. Для всей иерархии одна таблица в БД, содержащая все поля всех классов иерархии + Никаких: join, union, проблем с уникальностью, проблем с поддержкой изменений иерархии - Не оптимальное расходования места (хотя некоторые бд умеют более умно хранить дефолтные значения столбцов и места пропадает меньше) Вариант 1 теоретически красив, радует глаз и сердце архитектора и в идеальном объектом мире идеален. Джойны? так СУБД умеет джойнить. Надо тасовать данные при изменении иерархии? А для для чего еще нужны БД, если не для этого. И этот вариант как раз то что появилось в DAX2012. Всё по учебнику, всё красиво и "супер-супер". Реальный мир, как обычно, практичен и несовершенен. Тучи джойнов напрягают сервера, но не это самое страшное. А вот когда поле передвинули в иерархии и это приводит к необходимости следом переносить столбцы вместе с данными между таблицами, то это уже очень невесело для реальной жизни. Сделать такие изменения "на ходу" даже теоретически непросто и не быстро, не говоря уже о системе 24x7. Дополнительным "увеселителем" ситуации выступают всякие кубы/порталы/репортинг сервисы и прочие примкнувшие приложения, которые мало или вообще ничего не знают о метаданных DAX, а полагаются в основном на ее БД и дружно отказываются работать при изменении ее структуры. Механизм наследования таблиц сам по себе уж точно не лишнее для DAX. Поэтому решение перейти на 3 вариант, вернув одну широкую таблицу в БД, но оставить все остальное на месте вполне разумный шаг и, по сути, признание своих ошибок. И хотя бы это радует. Учебники, между тем, настоятельно рекомендуют начинать именно с третьего варианта Последний раз редактировалось db; 03.03.2013 в 22:34. |
|
|
За это сообщение автора поблагодарили: mazzy (2), gl00mie (3), S.Kuskov (5). |
04.03.2013, 11:43 | #20 |
Moderator
|
Для того чтобы реализация механизма была идеальной, надо было бы просто добавить возможность в свойствах таблицы-наследника указывать место физического хранения ее полей - в отдельной таблице или в той же таблице что и поля родителя.
|
|
Теги |
ax2012, inheritance, table inheritance, наследование таблиц, полезное |
|
|