2 сентября 2009 г.

“Синтетика” и методы борьбы с оной

Коллеги, приветствую всех Вас.
Я долго думал чему посвятить первый осмысленный пост в этом блоге и все-таки решил остановиться на обзоре проблемы синтетических ключей. Не стану сейчас вдаваться в подробности почему я начал именно с “синтетики”, просто оставим все как есть и примем это как должное…



Для начала небольшое отступление от основной темы поста…
Для тех кто вдруг не в курсе, QlikView имеет такое полезное (правда, не всегда) свойство как автоматическая простановка связей между таблицами, загружаемыми в документ. И делается это по самому, что ни на есть, простейшему алгоритму – по одинаковому наименованию полей. Иными словами, QlikView, всякий раз когда видит одинаковые наименования полей в разных таблицах, автоматически выстраивает связь между ними по этому самому полю. И как все уже, наверное, догадались, это поле становится ключевым. Вот и весь принцип построения связей между таблицами внутри одного документа QlikView.
На этом я позволю себе закончить с вводной частью и…

"Поехали!"
Copyright © 12 апреля 1961, Ю.А. Гагарин

Синтетические ключи возникают, когда мы загружаем в документ таблицы со сложными составными ключами(2 и более полей входят в уникальный ключ). Рассмотрим простейший пример. Необходимо загрузить 2 таблицы: Детали заказа и Отгрузки. Эти таблицы д.б. связаны по сложному ключу, состоящему из 2х полей: № Заказа(OrderID) и № Товара(ProductID). После загрузки этих 2х таблиц мы получим следующую модель данных:
synth_key

А именно, мы получили синтетический ключ “$Syn 1” и некую промежуточную таблицу с наименование “$Syn 1Table”, в которой хранятся все имеющиеся комбинации значений полей OrderID и  ProductID. Все бы ничего, т.к. по логике вещей все нормально и с этой точки зрения синтетические ключи не являются ошибкой. Однако, они очень сильно влияют на производительность документа. По идеи, если у Вас небольшие объемы данных, то Вам можно, что называется, не заморачиваться над этой проблемой. Однако, я все же советую Вам стараться всегда избавляться от этой картины в модели данных и избегать появления “синтетики” в Ваших приложениях. Если хотите можете воспринимать этот совет как некий пункт Best Practiсes при построению модели данных.
Так почему же эти ключи оказывают такое воздействие на производительность Вашего приложения? Как я уже сказал чуть выше, QlikView хранит ВСЕ возможные комбинации значений полей составного ключа, в нашем случае это значения полей OrderID и  ProductID.  Таким образом на больших объемах данных мы получаем дополнительную головную боль… Помимо этого, мы можем получить не соответствие в структуре данных, которое не всегда легко и быстро заметить. И чтобы совсем уж Вас “добить” и избавить от привычки “забивать” на эту ситуацию скажу еще об одной вещи. При наличии нескольких составных ключей (читай синтетических) в приложении QlikView, которые ко всему прочему зачастую пересекаются между собой своими составными частями или являются частями друг друга, система будет строить дополнительные синтетические ключи на основе других более мелких синтетических ключей. Во как завернул… В общем, мы добьемся того, что наше приложение даже на очень небольших объемах “встанет колом” на этапе построения связей между таблицами. Что естественно не есть гуд.
Как же от них избавляться? Есть несколько путей решения данной проблемы, о тех, что известны мне на данный момент я Вам сейчас и поведаю…
Первый способ это собственноручно создавать композитный ключ путем конкатенирования его составных частей. Пример:

Показать...


Символ тильда(“~”) используется здесь в качестве разделителя между полями составного ключа и не должен встречаться в наборе данных. Кроме того, необходимо исключить из загрузки дубликаты наименования полей путем их переименования или (как это сделано в моем примере) комментирования.
Второй способ решения это использование функции AutoNumberHash128(). Данная функция принимает в качестве параметров части композитного ключа и на основании “зашитой” хэш-функции возвращает порядковый номер каждой комбинации значений. Таким образом мы получаем более удобоваримый для человеческого восприятия ключ, который, ко всему прочему, занимает меньше памяти. В более ранних версиях QlikView (до версии 8) для этих целей использовалась функция AutoNumber(). Функция по своему применению и назначению аналогична, однако я советую избегать ее использования, т.к. она не корректно работает совместно с QVD-файлами.

11 комментариев:

  1. я часто использую третий способ - конкатенцию таблиц в одну

    ОтветитьУдалить
  2. Коллеги, а подскажите, где можно хотя бы демо-версию QlikView'ера скачать???

    ОтветитьУдалить
  3. Юлиана, например, вот тут: http://www.qlikview.com/us/explore/experience/free-download/

    ОтветитьУдалить
  4. Добрый день. А где можно посмотреть пример функции AutoNumberHash128()

    ОтветитьУдалить
  5. Приветствую, drone.
    Примеры можно посмотреть в строенном хелпе, например. Что касается конкретного случая из поста, то с использованием autonumberhash это будет выглядеть примерно так:

    AutoNumberHash128(OrderID & '~' & ProductID) as OrderShipmentKey

    ОтветитьУдалить
  6. Добрый день, Анатолий!
    во-первых с днем рождения, а во-вторых вопрос =)
    Есть ли ограничения по кол-ву "кодируемых" записей у функции AutoNumberHash128()?
    если да, то какой, если нет, то в чем отличие от функции AutoNumberHash256()?

    Спасибо!

    ОтветитьУдалить
  7. Приветствую, Александр. Спасибо за поздравления. по поводу вопроса - нет, ограничений на кол-во записей нет. А по поводу отличий, тут я честно говоря не большой помощник, но если глянуть в мануал... В первом случае используется 128-битный ключ хэширования, во втором 256-битный.

    ОтветитьУдалить
    Ответы
    1. Спасибо за ответ!
      здесь нашел еще немного по теме:
      http://community.qlikview.com/thread/67993

      Удалить
  8. JOIN (он же outer join, или вариации left, или keep) на 99% решает все проблемы. Прям в скрипте между таблиц qlik позволяет это делать. Храню, например остатки и продажи в qvd раздельно, а при загрузке джоиню в итоге получилось волшебство - удалось вснуть все факты в одну таблицу, а ней уже совать свойства объектов.

    ОтветитьУдалить
    Ответы
    1. Спасибо за комментарий. Join как и конкатенация в одну таблицу (см. 1ый комментарий) это тоже вариант. Однако, с Join надо быть аккуратным - можно легко получить задвоения в данных. Если брать ваш пример, то надо быть уверенным на 200% в том, что данные по продажам и остаткам предварительно "схлопнуты" по ключу, то есть на каждое значение ключа имеется одно значение в каждой таблице. Иначе, потом "концы" долго искать придется :)

      Удалить
    2. sparur
      Да, согласен, это принципиально. Например, если у вас продажи до чеков, то есть, товар повторяется несколько раз в разных чеках, а остатки естественно могут быть только в рамках SKU (например, кода товара). То тут только конкатенация, иначе в сводной по чеку у вас будет весь остаток по данному SKU и при агрегации в сводной остаток будет суммироваться.

      Удалить