|
|
#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). | |
|
|
#2 |
|
Участник
|
Спасибо большое. Ужасно интересно всё то, что не известно (С)
![]() Цитата:
А можно ли их перекрывать? Доступны ли через курсор производной таблицы поля базовой таблицы? Цитата:
Если просто в коде написать "select DirPerson;" будет ли автоматически выбран DirPartyTable? Ещё прошу подтвердить или опровергнуть следующее высказывание: Одна и таже запись базовой таблицы может быть связана с записями одновременно из нескольких прозводных таблиц одного уровня иерархии? |
|
|
|
|
#3 |
|
Участник
|
|
|
|
|
| За это сообщение автора поблагодарили: mazzy (2), Logger (5), TasmanianDevil (7). | |
|
|
#4 |
|
Мрачный тип
|
Интересная штука, но, судя по документации, реализовано с неким анально-ориентированным уклоном.
Какой-то один из трех не вписывается в картину наследования таблиц и этот отщепенец - второй пункт. От первого мы отказаться не можем, третий требуется для обеспечения связей в м-ду родителями и наследниками - остается признать, что механизм выдачи RecId в наследуемых таблицах требует некоей модификации, чтобы выполнялись первый и третий пункты. Суть такой модификации - наследование RecId из базовой таблицы при вставке в наследуемые, при этом вот что получится при вставке в таблицу потомка нижнего уровня N, если для него нужен такой же RecId, как и у базовой:
Половину этих вызовов ( всех возвратов от базовой записи) можно было бы избежать, используя всего лишь еще одно , дополнительное у к уже имеющемуся полю InstanceRelationType, служебное поле-ссылку (какой-нибудь InstanceRelationRecId) в родительских таблицах на запись в таблице-наследнике. Тогда вставка в самый нижний уровень не ждала бы вставок с верхнего уровня, а все служебные join можно было реализовать как Select Родитель Left Outer Join Потомок On Родитель.InstanceRelationType = Потомок.TableId And Родитель.InstanceRelationRecId = Потомок.RecId.
__________________
Мы летаем, кружимся, нагоняем ужасы ... |
|
|
|
| За это сообщение автора поблагодарили: gl00mie (5). | |
|
|
#5 |
|
Участник
|
Цитата:
Цитата:
Сообщение от sukhanchik
2. Создать в базовой таблице поле типа Int64, наследованное от типа \System Documentation\Types\RelationType и назвать его InstanceRelationType (должно быть точно такое название). В этом поле будет храниться код производной таблицы (TableId).
3. На базовой таблице включить свойство SupportInheritance = Yes и выбрать в свойстве InstanceRelationType одноименное только что созданное поле. Сохранить базовую таблицу. Впрочем, не знаю, что это за тип RelationType. Может, в Ax2012 этот тип данных допускает хранение неких списков значений?
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
|
|
| За это сообщение автора поблагодарили: S.Kuskov (2). | |
|
|
#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). | |
|
|
#7 |
|
Участник
|
Мы как-то обсуждаем детали.
А по-моему интереснее другой вопрос : 1. Зачем это сделано ? 2. Какие задачи помогает решить проще и дешевле ? 3. Не получим ли мы провал в производительности системы из-за кучи объединенных табличек ? Выгоды от наследования табличек неочевидны. |
|
|
|
|
#8 |
|
Участник
|
Наследнование сущностей существует в любом случае. В Ax2012 сделана поддержка одной из стратегий отображения этого отношения на таблицы БД. Про достоинства и недостатки разных стратегий можно почитать, например, здесь
|
|
|
|
|
#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). | |
|
|
#10 |
|
Участник
|
Цитата:
Производительность АХ 2012 (впрочем, как и ожидалось при нормализации СУБД) упирается не столько в мощности процессора / памяти - сколько в скорость дисков и операций чтения/записи.
|
|
|
|
|
#11 |
|
Administrator
|
Цитата:
Сообщение от niksen
вывод такой интересный, я конечно не упираюсь в реляционную теорию бд, но при нормализации субд разве всё начинает зависеть от скорости хардов? может я как-то не так логику понимаю, но, допустим ненормализованная бд, в ней 3 таблицы, в каждой из которых допустим 1000 записей по 30 полей в каждом, то есть перебирается 30 000 значений ячеек в сумме 1000 строк, и нормализованная, в которой будет например 15 таблиц, но полей в каждой таблице будет гораздо меньше, то есть перелопачивание данных будет меньше, разве не так?
Причина 1. Когда мы пишем Х++ - обычно мы пишем запрос типа SELECT *, т.е. заведомо выбираем ВСЕ поля - сколько бы их ни было. Т.е. если нам нужно выбрать строку накладной, код клиента и группу клиента, то при денормализации, в которой группа клиентов сидит в накладной - мы не джойним всю таблицу клиентов и производим выборку только всех полей накладной. Если же в накладной нужных нам полей нет, то мы джойним таблицу клиентов и выбираем все поля из этой таблицы - т.е. хотим мы или нет - но выбираем мы больше полей. В случае разбиения большой таблицы на маленькие - появляются дополнительные поля - связки, которые тоже подлежат выборке. Причина 2. Индексы. Сколько бы ни было полей в таблице - поиск осуществляется по индексу, а не по Вашему алгоритму (не так часто требуется получить большой набор данных - сколько требуется найти записи, удовлетворяющие некоему критерию отбора). Причина 3 (следствие). Джойны всегда работают заведомо медленнее, чем выборка из одной таблицы. Плюс LEFT JOIN на порядок тормознутее INNER JOIN. Причина 4. Данные таблицы можно дефрагментировать внутри файла. А гарантировать, что нужные таблицы при выборке будут находиться рядом друг другом в файле БД - нельзя. Т.е. джойн - это еще дополнительная работа для диска.
__________________
Возможно сделать все. Вопрос времени |
|
|
|
|
#12 |
|
Участник
|
Цитата:
Причина 2. Индексы. Сколько бы ни было полей в таблице - поиск осуществляется по индексу, а не по Вашему алгоритму (не так часто требуется получить большой набор данных - сколько требуется найти записи, удовлетворяющие некоему критерию отбора)
|
|
|
|
|
#13 |
|
Administrator
|
Цитата:
Сообщение от niksen
я лишь предположил. То есть как я понимаю Вас, иерархия таблиц сделана не для увеличения скорости, а для удобства и увеличения скорости разработки в целом лишь для отдельных случаев или не так? то есть в общем случае - эта иерархия многим вообще никак не нужна? или наоборот? я просто не очень пойму Вашу позицию
.С моей личной т.з. иерархия таблиц не будет работать на больших объемах данных (в документации, в частности, сказано - что ее не стоит применять на транзакционных таблицах, т.е. разработчики сего механизма понимали - что на больших объемах данных - этот механизм замедлит работу системы). Т.е. с моей личной т.з. эта иерархия не стоит тех затрат, которые потратили на ее реализацию. С т.з. структуры СУБД конечно. Наследование же методов - штука полезная. Другое дело, что вполне возможно - что реализовать наследование методов можно было бы другим путем, не усложняя структуру. Например, убрать методы вообще с таблиц и добавить на таблицу ссылку на класс-обработчик методов на таблице, допустим для простоты строго с тем же названием. А в ядре бы сделать разделение - выборка бы шла по таблице, а обработка методов - по классу. В крайнем случае сделать доп. узел в АОТ что-то типа "Table Handler Classes". В 3.0 ведь создавался узел в Application Documentation и Application Developer Documentation автоматически при создании новой таблицы (даже не только таблицы). Так и тут можно было бы сие также повторить бы. И тогда бы появился и Class Declaration и классы можно было бы отнаследовать друг от друга. Конечно - там есть много спорных моментов. Но это по крайней мере не сказалось бы на производительности, а просто не ухудшило бы программирование. Можно было бы пойти и другим путем - расширить табличные Map-ы, таким образом, что можно было бы наследовать методы от них. Вполне возможно, что все это обсуждалось и был принят лучший вариант. Жизнь покажет, как это все будет востребовано. Просто на мой взгляд - если в таблице мало записей - то и делить-то ее особенной потребности нет. Ни с т.з. места на диске ни с т.з. повышения производительности. А вот задачу по обеспечению производительности больших таблиц наследование - не решает. Поэтому я пока не вижу ситуаций, когда применение наследования таблиц даст какое-либо преимущество перед одной большой таблицей или просто ручным делением таблиц с доп. полем RefRecID
__________________
Возможно сделать все. Вопрос времени |
|
|
|
| За это сообщение автора поблагодарили: mazzy (5), Link (2). | |
|
|
#14 |
|
Administrator
|
Обновил информацию для версии R2 (т.к. там произошли некоторые изменения)
__________________
Возможно сделать все. Вопрос времени |
|
|
|
| За это сообщение автора поблагодарили: mazzy (5), fed (3), S.Kuskov (10). | |
|
|
#15 |
|
Moderator
|
Очень, очень забавно. Версия 2012 выпускалась под флагом борьбы за нормализацию структур данных. В итоге - после столкновения с реальностью, в версии 2012R2 пришлось денормализовать те же данные до абсурдного состояния. Скрестить companyInfo и DirPartyTable - это уже денормализация за гранью добра и зла...
|
|
|
|
| За это сообщение автора поблагодарили: mazzy (2), Logger (5). | |
|
|
#16 |
|
Administrator
|
Цитата:
Сообщение от fed
Очень, очень забавно. Версия 2012 выпускалась под флагом борьбы за нормализацию структур данных. В итоге - после столкновения с реальностью, в версии 2012R2 пришлось денормализовать те же данные до абсурдного состояния. Скрестить companyInfo и DirPartyTable - это уже денормализация за гранью добра и зла...
Важно другое. Фактически - этим изменением на мой взгляд похоронили саму идею иерархии таблиц. Ну т.е. в "теоретических" головах разработчиков ядра системы - можно конечно рисовать иерархию таблиц, а вот на практике, на мой взгляд - никто не будет заморачиваться с этой иерарихей, когда можно тупо создать одну большую мегатаблицу. При этом не придется заморачиваться наследованием методов (раз таблица одна, значит и методы на ней все). Т.е. автоматически исчезает потребность создавать производные таблицы, как средство размещения кода (проще все разместить на одной таблице, нежели себя обманывать и плодить псевдо-таблицу, которой нет в БД). Но в целом - я рад, что эта идея не прижилась. Уж больно (на мой взгляд) она была искусственной.
__________________
Возможно сделать все. Вопрос времени |
|
|
|
| За это сообщение автора поблагодарили: mazzy (2). | |
|
|
#17 |
|
Moderator
|
Цитата:
Сообщение от sukhanchik
Важно другое. Фактически - этим изменением на мой взгляд похоронили саму идею иерархии таблиц. Ну т.е. в "теоретических" головах разработчиков ядра системы - можно конечно рисовать иерархию таблиц, а вот на практике, на мой взгляд - никто не будет заморачиваться с этой иерарихей, когда можно тупо создать одну большую мегатаблицу. При этом не придется заморачиваться наследованием методов (раз таблица одна, значит и методы на ней все). Т.е. автоматически исчезает потребность создавать производные таблицы, как средство размещения кода (проще все разместить на одной таблице, нежели себя обманывать и плодить псевдо-таблицу, которой нет в БД). Ну и конечно, при проектировании прикладной структуры, разработчики должны понимать что каждый дополнительный уровень иерархии таблиц обходится намного дороже чем дополнительный уровень иерархии при проектировании классов. Заводить еще один уровень иерархии из за 1-2-3 аттрибутов - слишком накладно. |
|
|
|
| За это сообщение автора поблагодарили: sukhanchik (3), S.Kuskov (2). | |
|
|
#18 |
|
Участник
|
Цитата:
Цитата:
![]() не стоит привлекать злой умысел, когда достаточно простого бардака |
|
|
|
|
#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). | |
|
|
#20 |
|
Moderator
|
Для того чтобы реализация механизма была идеальной, надо было бы просто добавить возможность в свойствах таблицы-наследника указывать место физического хранения ее полей - в отдельной таблице или в той же таблице что и поля родителя.
|
|
|
| Теги |
| ax2012, inheritance, table inheritance, наследование таблиц, полезное |
|
|
|