Как стать автором
Обновить

Комментарии 23

А почему бы в статье не указать какие именно ограничения? Про численное переполнение?
Чтоб документацию читали :-)
Численное переполнение, если начать с 1 никому не грозит.
А что сложного-то взять да указать в статье и написать остальное читайте в документации? Почему я должен лезть и открывать документацию. Почему мне предлагают перейти с одного на другое, но не говорят что именно плохого может случиться?

Да дело не в копировании документации. А просто в отношении к людям (к разработчикам). Это отношение очень отталкивает.
Ну извините, если обидел. Не хотел ничего такого.

Вы, конечно, никуда лезть не должны.

Я постарался взять минимум из справки по $Sequence — зачем делать перевод на русский язык (почти наверняка корявый), того что просто, понятно, с примерами и не слишком длинно написано по-английски.
«Как страшно жить!» — вы вообще с этой планеты?
А что смущает?
Ну, планета Земля (Грязь)…

Вас ненавязчиво подталкивают ознакомится с документацией.
И вдруг такая феерия эмоций — «Дело в отношении к людям!!!», «Это… очень отталкивает»

И это еще лето, солнце. Что же зимой то будет? Волнуюсь я за вас
Вопрос к Cache разработчикам: зачем sequence? Почему бы не улучшить increment?
Я не разработчик, но постараюсь ответить. Например потому, что $sequence только для глобалов.
Ну, это я прочитал, но вопрос «почему» остался. Почему всё таки не научить метод работать с глобалами? В Cache есть универсальные функции, которые могут работать с различными типами аргументов и всё ок. А чего бы тут так не сделать? м?
Опять же вопрос к разработчикам, вполне резонный впрочем, возможно в будущем это появится. Предпололожу, что можно написать такой хитрый макрос, какой-нибудь SmartInc, который будет разбираться по аргументу, глобал там или нет, и делать правильный выбор. Судя по тому, что вы хорошо пишете макросы, может быть и вы сможете.
не научить метод работать с глобалами?
С глобалами-то он работает прекрасно. А для работы локальными переменными $sequence не предзначначен, пока.
Я тоже не разработчик. И тоже постараюсь ответить.

У функции $Increment есть определённая спецификация (контракт), которую она выполняет. Написано много когда, который на эту спецификацию расчитывает. $Sequence работает быстрее, за счёт нарушения этой спецификация. Даже не так — это вообще другая функция, с другой спецификацией (кеширование, шаг только в 1 и только вверх и т.д), которая может быть использована для той же цели, что и $Increment.

$Increment и так улучшается, но без нарушения совместимости.
Я отвечу, так как мне важны различия между этими двумя функциями.
самое главное у $increment это гарантия последовательности нумерации, в некоторых случаях это может быть важно, если это быстрорастущая система, с мбольшим количеством добавлений в минуту/секунду (нужное подчеркнуть), и которое будет вестись неоднородно различными процессами, это неизбежно приведет к пустотам в нумерации.
Далее в совокупности с другой возможностью Caché bitmap индексами, которые для тех кто не в курсе состоят из массива битовых строк разбитых на 64000 бита, каждый бит которого должен указывать на ID объекта. Так вот представим, что объектов у нас в системе миллиарды (вполне реально) делим эти миллиарды на чанки по 64000, и рост их по несколько в день. Далее, да мы помним о том что IS озаботилась так же об оптимизации хранении бит, и то что в таком чанке несколько установленных бит в 0 будет занимать совсем немного, но неоднородность работы $sequence может свести эту оптимизацию на нет, и приведет к тому, что такой индекс может занимать достаточно много места, обычно один блок это 8192 байта, но битовая строка из 64000 бит это максимум примерно 8005 байт, что вместе со служебной информацией самого блока, не влезает в один блок, и такие данные уже разбиваются, на 2 (big blocks) итого 16384 байт на один чанк, Здесь так же упоминается и работа в ECP конфигурации, в таком случае big блоки не кешируются, приходится сразу переходить на 16к блоки.
как писал раньше, имеем 1 миллиард объектов, это получится 1000000000/64000*16384/1024/1024 > 240 Мб, хм, может где ошибся, но вроде все верно. А с такими массивами еще нужно оперировать выполняя разные логические операции.
Вот в такой ситуации $sequence противопоказан, так как давая прирост в одном месте сильно мешает в другом.
Но в целом можно найти применение данной функции в других местах.
Хороший комментарий. Одно соображение — если битмап-индексы делать не на той же OLTP базе, а на хранилище данных, вынесенном на другой сервер, то, похоже, $sec в этом случае можно использовать в обоих местах: в OLTP для быстрорастущих записей (и не использовать битмап индексы вообще) и в OLAP для нумерации фактов (например фактов DeepSee), которые создавать заново подряд, создавать все необходимые битмап и битслайс индексы и использовать их для таблицы фактов эффективно.
Нужно смотреть в каждом конкретном случае, какой будет процент дырок. Это зависит от того, как данные загружаются.

В примере из статьи, после выполнения загрузки, значение ^Person = 2007040.

То есть, узлы 2'000'001 — 2'007'040 значений не имеют, и следующий узел будет вставлен в 2'007'041

7'040 / 2'000'000 = 0,00352 = 0.352%

С другой стороны, если сохранение каждого объекта влечёт обновление многих индексов, то, возможно, $Increment не узкое место, и заменять его смысла нет.
Спасибо за статью, но мотивы разработчиков для введения новой функции и для меня остались неясны…
Соглашусь с jxcoder, вполне можно было бы добавить в $Increment кэширование, аналогичное $Sequence, не нарушая её спецификации: нигде ведь не сказано, что при параллельно работающих N процессах, обновляющих один глобал (как в вашем примере), значения id должны распределяться приблизительно равномерно. С приращениями > 1 этот кэш также отлично бы справился. «Дырки» в глобале, которые неизбежно будут получаться, тоже не проблема: они могут быть и сейчас при аварийном завершении процессов/откате транзакций. То, что $I() работает и с глобальными, и с локальными переменными, а $Sequence() — нет, и вовсе «гнилая отговорка»: $I() и сейчас по-разному работает в обоих случаях, очевидно, что каждый случай обслуживает отдельная ветка кода.
Пожалуйста, Алексей. Всё равно не очень понятно.

Пусть в программе написано
set id = $Increment(^a)

За счёт чего здесь может происходить кеширование? Ведь функция $Increment должна увеличить значение ^a на 1.

Работать с локальными переменными функции $Sequence, по-моему мнению нет никакой необходимости (как и функции $Increment), ведь внутри одного процесса конкурентного доступа нет, и set a = $Increment(a) это то же самое, что и set a = $Get(a) + 1.

Разброс Id можно, конечно, сделать и без $Sequence. В данном случае это побочный эффект.
Ведь функция $Increment должна увеличить значение ^a на 1
Равенство id == ^a гарантируется только в момент присваивания, не так ли? Нигде не обещается, что уже в следующую секунду не налетят «100500 процессов» и не увеличат ^a ещё на 100500.
Про локальные переменные упомянул только потому, что вы указали на неспособность работать с ними $seq как на важное отличие от $i. Нет необходимости — да, согласен, но возможность есть, как и во многих других $-функциях, скорее всего, для сохранения полноты языка.
Выделять разброс Id в какое-то отдельное аномальное явление не стоит — это жизнь, т.к. любой программист, использующий
tstart set id=$i(^a),^a(id)=«что-нибудь» tcommit
не должен полагаться на отсутствие дыр в индексации ^a. Что принципиально изменится, если этих дыр станет немного больше?
Вы и сами в заголовке статьи пишете «а вы уже поменяли?». Что понимается под заменой? Могу ли взять и поменять по контексту /$i(^/ на /$seq(^/, если знаю, что никогда не пользуюсь двухаргументной формой $i()?
Если да, то спецификации функций совместимы.
Если нет, объясните, почему.
Ведь функция $Increment должна увеличить значение ^a на 1

Равенство id == ^a гарантируется только в момент присваивания, не так ли? Нигде не обещается, что уже в следующую секунду не налетят «100500 процессов» и не увеличат ^a ещё на 100500.


Я имел в виду, что спецификация $Increment(^a) — это увеличить значение глобала ^a ровно на 1. У $Sequence такого ограничения нет.

В общем случае, одноаргументный $Increment нельзя заменить на $Sequence? Радикальный пример:
 for i=1:1:20 {
     set a = $Increment(^a)
     write "^a=",^a,!
     if i#10=0 {
         kill ^a
     }
 }


В некоторых популярных случаях одноаргументный $Increment можно заменить на $Sequence. В общем случае — нет.

Если вы используете $Increment исключительно для генерации Id, как в примере статьи, то я не знаю причин, чтобы не заменить его на $Sequence (что, конечно же, не значит, что их нет).
Спасибо за разъяснение.
Если вы используете $Increment исключительно для генерации Id, как в примере статьи, то я не знаю причин, чтобы не заменить его на $Sequence (что, конечно же, не значит, что их нет).
Сухой остаток: InterSystems вводит в язык новую фичу и предлагает на неё переходить, не формулируя чётко критерии, когда это возможно.
Немного успокаивает, что, на вскидку, пострадает лишь искусственный код типа вашего последнего примера (не всё ли равно, что было в вершине глобала, если его всё равно кильнули?), но где гарантия, что нет более тонких слачаев? Именно это и настораживает. Одно дело — писание чего-то нового, другое дело — поддержка и развитие сотен тысяч строк существующего кода, ответственность перед коллегами и клиентами, и т.д.
Я могу в начале статьи вставить дисклаймер, что статья частная позиция автора и ни в коей мере не позиция фирмы и так далее и тому подобное. Я хотел рассказать о новой интересной функции. Это вполне удалось. Что с ней делать или не делать — решать вам, как разработчику.

«не формулируя чётко критерии, когда это возможно»
Достаточно чётко, что делает функция $Sequence описано в документации.

Можно ли в ваших сценариях использования менять $Increment на $Sequence решать вам. Правильно, что вас настораживает. Нельзя автоматом менять А на Б в сотне тысяч строк кода.
Я последовал своему совету и почитал-таки документацию про $Sequence. Можно эту функцию использовать с локальными переменным.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий