Новое в Caché 2015.1: SQL-индекс по элементам свойства-массива
После заполнения (do ##class (User.eav).RepopulateAll ()) в наших таблицах окажутся следующие данные:
Таблица eav:
Class User.eav Extends %Persistent{Index idx1 On attributes (ELEMENTS) [ Data = entity ];
Index idx2 On (attributes (KEYS), attributes (ELEMENTS)) [ Data = entity ];
Property entity;
Property attributes As array Of %String (SQLTABLENAME = «attributes») [ SqlFieldName = attr ];
/// do ##class (User.eav).RepopulateAll ()ClassMethod RepopulateAll (){ do …%DeleteExtent () set name=$TR («Сосна^ сиби^рская кедро^вая»,»^»,$c (769)) set obj=…%New () set obj.entity=«Человек» do obj.attributes.SetAt (22, «Возраст») do obj.attributes.SetAt (186, «Рост») do obj.attributes.SetAt («Вася», «Имя») do obj.%Save ()
set obj=…%New () set obj.entity=«Дерево» do obj.attributes.SetAt (186, «Возраст») do obj.attributes.SetAt (22, «Высота») do obj.attributes.SetAt («Сосновые», «Семейство») do obj.attributes.SetAt (name, «Имя») do obj.%Save () /* ; или &sql (insert into eav (entity) select 'Человек' union select 'Дерево') &sql (insert into attributes (eav, element_key, attr) select 1,'Возраст',22 union select 1,'Рост',186 union select 1,'Имя','Вася' union select 2,'Возраст',186 union select 2,'Высота',22 union select 2,'Семейство','Сосновые' union select 2,'Имя',: name) */ do …Reindex ()}
/// do ##class (User.eav).Reindex ()ClassMethod Reindex (){ do …%BuildIndices (,1)
do $system.SQL.TuneTable («SQLUser.eav»,1) do $system.SQL.TuneTable («SQLUser.attributes»,1) do $system.OBJ.Compile ($classname (), «cu»)}
}
ID entity 1 Человек 2 Дерево Таблица attributes: eav ID attr element_key 1 1||Возраст 22 Возраст 1 1||Имя Вася Имя 1 1||Рост 186 Рост 2 2||Возраст 186 Возраст 2 2||Высота 22 Высота 2 2||Имя Сосна́ сиби́рская кедро́вая Имя 2 2||Семейство Сосновые Семейство Глобал с данными:
USER>zw ^User.eavI ^User.eavI («idx1»,» 186»,1)=$lb (», «Человек») ^User.eavI («idx1»,» 186»,2)=$lb (», «Дерево») ^User.eavI («idx1»,» 22»,1)=$lb (», «Человек») ^User.eavI («idx1»,» 22»,2)=$lb (», «Дерево») ^User.eavI («idx1»,» ВАСЯ»,1)=$lb (», «Человек») ^User.eavI («idx1»,» СОСНА́ СИБИ́РСКАЯ КЕДРО́ВАЯ»,2)=$lb (», «Дерево») ^User.eavI («idx1»,» СОСНОВЫЕ»,2)=$lb (», «Дерево») ^User.eavI («idx2», «Возраст»,» 186»,2)=$lb (», «Дерево») ^User.eavI («idx2», «Возраст»,» 22»,1)=$lb (», «Человек») ^User.eavI («idx2», «Высота»,» 22»,2)=$lb (», «Дерево») ^User.eavI («idx2», «Имя»,» ВАСЯ»,1)=$lb (», «Человек») ^User.eavI («idx2», «Имя»,» СОСНА́ СИБИ́РСКАЯ КЕДРО́ВАЯ»,2)=$lb (», «Дерево») ^User.eavI («idx2», «Рост»,» 186»,1)=$lb (», «Человек») ^User.eavI («idx2», «Семейство»,» СОСНОВЫЕ»,2)=$lb (», «Дерево») Глобал с индексами:
USER>zw ^User.eavI ^User.eavI («idx1»,» 186»,1)=$lb (», «Человек») ^User.eavI («idx1»,» 186»,2)=$lb (», «Дерево») ^User.eavI («idx1»,» 22»,1)=$lb (», «Человек») ^User.eavI («idx1»,» 22»,2)=$lb (», «Дерево») ^User.eavI («idx1»,» ВАСЯ»,1)=$lb (», «Человек») ^User.eavI («idx1»,» СОСНА́ СИБИ́РСКАЯ КЕДРО́ВАЯ»,2)=$lb (», «Дерево») ^User.eavI («idx1»,» СОСНОВЫЕ»,2)=$lb (», «Дерево») ^User.eavI («idx2», «Возраст»,» 186»,2)=$lb (», «Дерево») ^User.eavI («idx2», «Возраст»,» 22»,1)=$lb (», «Человек») ^User.eavI («idx2», «Высота»,» 22»,2)=$lb (», «Дерево») ^User.eavI («idx2», «Имя»,» ВАСЯ»,1)=$lb (», «Человек») ^User.eavI («idx2», «Имя»,» СОСНА́ СИБИ́РСКАЯ КЕДРО́ВАЯ»,2)=$lb (», «Дерево») ^User.eavI («idx2», «Рост»,» 186»,1)=$lb (», «Человек») ^User.eavI («idx2», «Семейство»,» СОСНОВЫЕ»,2)=$lb (», «Дерево») Теперь выполним следующий запрос:
select entity from eav where attributes→attr = 22
entity Человек Дерево Запрос отрабатывает, но использует полное сканирование, а не наши индексы. Если посмотреть в SMP (Портал управления системой) на наши таблицы, то мы в них не найдём idx1 и idx2, хотя как мы ранее видели, данные в них сгенерированы.
Это происходит потому, что SQL-ядро «видит» только те индексы по коллекциям-массивам, которые базируются исключительно на полях подтаблицы-массива и обязательно содержат ключ, т.е. propArray (KEY). Оба наших индекса содержат поле entity, которое отсутствует в подтаблице attributes.
Также не будет виден индекс Index idx3 On attributes (ELEMENTS); поскольку он не содержит attributes (KEYS), а вот индексы:
Index idx4 On (attributes (KEYS), attributes (ELEMENTS)); Index idx5 On (attributes (ELEMENTS), attributes (KEYS)); будут видны и следовательно будут учитываться при запросах, но не для всех типов запросов они оптимальны.Так как же минимальными усилиями добиться видимости индексов на элементы коллекции-массива SQL-ядром? В версии Caché 2015.1 появилась возможность проецировать коллекцию как поле таблицы, если эта коллекция проецируется в подтаблицу, используя методы SetCollectionProjection/GetCollectionProjection.По умолчанию эта возможность выключена.
В предыдущих версиях данных методов нет, но Вы можете попробовать включить эту фичу вручную:
%SYS>set ^%SYS («sql», «sys», «collection projection»)=1 После изменения обязательно необходимо перекомпилировать классы.Итак, включим этот параметр и посмотрим, что это нам дало.
В SMP теперь стали видны наши индексы, а в таблице eav появилось скрытое поле-коллекция attr. Тем не менее наш запрос по прежнему не видит индексы idx1/idx2.
Для исправления ситуации воспользуемся уже известным предикатом FOR SOME %ELEMENT:
select entity from eav where for some %element (attr) (%value = 22)
entity Человек Дерево Теперь в запросе задействован индекс idx1. Немного его видоизменим:
select entity from eav where for some %element (attr) (%value = 22 and %key= 'Возраст')
entity Человек select entity from eav where for some %element (attr) (%value = 22 and %key= 'Высота')
entity Дерево В последних двух примерах уже будет задействован индекс idx2 вместо idx1.