📜 ⬆️ ⬇️

New in Caché 2015.1: SQL Index on Array Property Elements

In Caché 2015.1, it became possible to include a projection for collection properties into a separate column. Thus, for SQL data access to the collection, you can use not only the child table, but simply as an additional column in which all values ​​of the collection are located. Read more about it here .
How and where it can be useful in practice, says this article.


Sometimes it is useful (especially for the EAV model) in a class to use properties-arrays and to be able to quickly search by their elements: both the key and the value.
Consider a simple example.
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 ( "Pine ^ Sibi ^ psk cedar ^" , "^" , $ c (769))

set obj = .. % New ()
set obj . entity = "Man"
do obj . attributes . SetAt (22, "Age" )
do obj . attributes . SetAt (186, "Growth" )
do obj . attributes . SetAt ( "Vasya" , "Name" )
do obj . % Save ()

set obj = .. % New ()
set obj . entity = "Tree"
do obj . attributes . SetAt (186, "Age" )
do obj . attributes . SetAt (22, "Height" )
do obj . attributes . SetAt ( "Pine" , "Family" )
do obj . attributes . SetAt ( name , "Name" )
do obj . % Save ()

/ *

; or

& sql (insert into eav (entity) select 'Person' union select 'Tree')
& sql (insert into attributes (eav, element_key, attr)
select 1, 'Age', 22 union
select 1, 'Growth', 186 union
select 1, 'Name', 'Vasya' union
select 2, 'Age', 186 union
select 2, 'Height', 22 union
select 2, 'Family', 'Pine' union
select 2, 'Name',: 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" )
}

}


After filling ( do ## class ( User.eav ). RepopulateAll () ) the following data will appear in our tables:

Eav table:
IDentity
onePerson
2Tree

Table attributes :
eavIDattrelement_key
one1 || Age22Age
one1 || NameVasyaName
one1 || Growth186Growth
22 || Age186Age
22 || Height22Height
22 || NamePine Siberian cedarName
22 || FamilyPineFamily


Global with data:
USER>zw ^User.eavD ^User.eavD=2 ^User.eavD(1)=$lb("","") ^User.eavD(1,"attributes","")=22 ^User.eavD(1,"attributes","")="" ^User.eavD(1,"attributes","")=186 ^User.eavD(2)=$lb("","") ^User.eavD(2,"attributes","")=186 ^User.eavD(2,"attributes","")=22 ^User.eavD(2,"attributes","")="́ ́ ́" ^User.eavD(2,"attributes","")="" 


Global with indexes:
 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("","") 


Now execute the following query:
 select entity from eav where attributes->attr = 22 entity   


The query fulfills, but uses a full scan, not our indexes. If you look at our tables in the SMP (System Management Portal), then we will not find idx1 and idx2 in them, although as we saw earlier, the data in them is generated.

This happens because the SQL core “sees” only those indexes on array collections that are based solely on the fields of the subtables array and necessarily contain the key, i.e. propArray (KEY). Both of our indexes contain an entity field that is not listed in the attributes sub-table.

Also, the Index idx3 On attributes (ELEMENTS) index will not be visible; since it does not contain attributes (KEYS), but the indices:
will be visible and therefore will be taken into account in queries, but they are not optimal for all types of queries.

So how can minimal efforts to achieve the visibility of indexes on the elements of the collection-array of the SQL-core?



In Caché 2015.1, it was possible to project a collection as a table field if this collection is projected into a sub-table using the methods SetCollectionProjection / GetCollectionProjection .
This feature is off by default.

In previous versions of these methods there is no, but you can try to enable this feature manually:
 %SYS>set ^%SYS("sql","sys","collection projection")=1 

After the change it is necessary to recompile the classes.

So, turn on this parameter and see what it gave us.

In SMP, our indexes are now visible, and in the eav table there is a hidden field-collection attr. However, our query still does not see idx1 / idx2 indices.

To remedy the situation, we use the already known FOR SOME% ELEMENT predicate:

 select entity from eav where for some %element(attr) (%value = 22) entity   


The query now uses the idx1 index. Few modify it:

 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  


In the last two examples, idx2 will be used instead of idx1.

Source: https://habr.com/ru/post/255203/


All Articles