Written by

~~ retired but not tired ~~
MOD
Article Robert Cemper · 54 min ago 5m read

Hand crafted partitioningContestant

IRIS 2026.1 provided Partitioned Tables as a new option for large data sets
It's a great improvement as it offers standardization of this feature.

Though:
It was possible also before, matching requirements and leaving room for creativity.
less elegant with a bit more coding and fewer automatisms.

 

The need is obvious.

An example:
You have a PERSON table containing Customers, Employees, Partners, Suppliers, ....
The classic approach would be to index the different roles or to inherit individual 
classes from a common class.
The immediate impact: 
All records end up in the same 3 Globals for Data, Index, and Streams.
This could mean that searching for one of 37 Employees might take, on average, 
the same time as searching for one out of 277.876 Customers or of 1612 Suppliers.
Simplified:  They are inhabitants of the same pool of frogs.
Splitting their storage in separated Globals might promise improvement.

The most simple approach might be to just use 4 differently named tables
with all the related naming impact in your maintenance utilities.
Many implementations in the field work like this.

There is a more sophisticated approach

Since long this 2 Class Parameters allow a quite dynamic solution.

  • DEFAULTGLOBAL parameter is used as the default global root for 
    the values of the storage keywords DATALOCATION, IDLOCATION, 
    INDEXLOCATION and STREAMLOCATION  
    • For example, if DEFAULTGLOBAL = "^Demo.Person" 
    • this compiles as
      • DATALOCATION = ^Demo.PersonD
      • IDLOCATION = ^Demo.PersonD
      • INDEXLOCATION = ^Demo.PersonI
      • STREAMLOCATION = ^Demo.PersonS
    •  
  • MANAGEDEXTENT parameter can be set to 0 (zero) to cause the 
    Extent Manager to ignore this class. If set to 1 then the Extent Manager 
    will register globals used by the class and detect collisions.

Now we can use DEFAULTGLOBAL in combination with indirectio

  • Parameter DEFAULTGLOBAL As STRING = "@%rcc"; 

    • Assign Globals by indirection At Runtime
    • compiled as
      • <DataLocation>@%rccD</DataLocation>
      • <DefaultData>RCCDefaultData</DefaultData>
      • <IdLocation>@%rccD</IdLocation>
      • <IndexLocation>@%rccI</IndexLocation>
      • <StreamLocation>@%rccS</StreamLocation>
         
  • Parameter MANAGEDEXTENT As INTEGER = 0;
    • Allows a dynamic change of your storage Globals
    • and protects from errors during class compilation 

You just have to provide the correct names for these 3 variables before use:

  • set %rccD ="^"_%rcc_"D"
  • set %rccI ="^"_%rcc_"I"  
  • set %rccS ="^"_%rcc_"S"

Packing it in a tiny ClassMethod is not a big deal,
Projecting it as SqlProcedure makes it also available for any SQL access.

The example for Global ^Person*:

SAMPLES>write ##class(RCC).%rcc("Person")
1
SAMPLES>zwrite
 
%rccD="^PersonD"
%rccI="^PersonI"
%rccS="^PersonS"
%sqlcontext=<OBJECT REFERENCE>[2@%Library.ProcedureContext]
SAMPLES>write ##class(RCC).Populate(11)
11

SAMPLES>:sql
SQL Command Line Shell
----------------------------------------------------
The command prefix is currently set to: <<nothing>>.
Enter <command>, 'q' to quit, '?' for help.
[SQL]SAMPLES>>select * from RCC where %rcc('Person')=1
1.      select * from RCC where %rcc('Person')=1
 
| ID | city | dob | name | score |
| -- | -- | -- | -- | -- |
| 1 | Vail | 40558 | Leiberman,Sally E. | 97 |
| 2 | Chicago | 58285 | Ott,Lydia H. | 44 |
| 3 | Pueblo | 58873 | Hertz,Usha L. | 45 |
| 4 | Gansevoort | 40744 | Gomez,Heloisa O. | 53 |
| 5 | Ukiah | 34822 | Macrakis,Keith S. | 39 |
| 6 | Ukiah | 31655 | Gore,Chris N. | 9 |
| 7 | Hialeah | 39868 | Grabscheid,Amanda O. | 66 |
| 8 | Vail | 60410 | Burroughs,Greta W. | 88 |
| 9 | Tampa | 43499 | Zevon,Al W. | 15 |
| 10 | Tampa | 59787 | Feynman,Juanita Q. | 93 |
| 11 | Miami | 53081 | Zucherro,Bart R. | 42 |
 
11 Rows(s) Affected
statement prepare time(s)/globals/cmds/disk: 0.0774s/44,458/226,219/0ms
          execute time(s)/globals/cmds/disk: 0.0004s/12/1,938/0ms
                                query class: %sqlcq.SAMPLES.cls1
---------------------------------------------------------------------------
[SQL]SAMPLES>>	-

 Same session with Global ^mtemp.Work*:

SAMPLES>write ##class(RCC).%rcc("mtemp.Work")
1
SAMPLES>zw
 
%rccD="^mtemp.WorkD"
%rccI="^mtemp.WorkI"
%rccS="^mtemp.WorkS"
%sqlcontext=<OBJECT REFERENCE>[2@%Library.ProcedureContext]
SAMPLES>w ##class(RCC).Populate(5)
5

SAMPLES>:sql
SQL Command Line Shell
----------------------------------------------------
 
The command prefix is currently set to: <<nothing>>.
Enter <command>, 'q' to quit, '?' for help.
[SQL]SAMPLES>>select name,city from RCC where %rcc('mtemp.Work')=1 order by city 
2.      select name,city from RCC where %rcc('mtemp.Work')=1 order by city
 
| name | city |
| -- | -- |
| Gaboriault,Quentin O. | Bensonhurst |
| Baker,Andrew Q. | Fargo |
| Zweifelhofer,Clint T. | Miami |
| Fives,Patrick T. | Newton |
| Alton,Geoffrey I. | Pueblo |
 
5 Rows(s) Affected
statement prepare time(s)/globals/cmds/disk: 0.0596s/38,492/210,709/0ms
          execute time(s)/globals/cmds/disk: 0.0002s/6/919/0ms
                                query class: %sqlcq.SAMPLES.cls5
---------------------------------------------------------------------------
[SQL]SAMPLES>>

And the class definition:

Class User.RCC Extends (%Persistent, %Populate) [ Final ]
{
Parameter MANAGEDEXTENT As INTEGER = 0;
Parameter DEFAULTGLOBAL As STRING = "@%rcc";
Property name As %String(POPSPEC = "Name()", TRUNCATE = 1);
Property city As %String(POPSPEC = "City()", TRUNCATE = 1);
Property dob As %Date;
Property score As %Integer(POPSPEC = "Integer(0,100)");
//
Index nameIDX On name [ Data = city ];
Index cityIDX On city As SQLSTRING [ Type = index ];
Index nsIDX On (name, score);
Index ncIDX On (name, city);
Index dobIDX On dob [ Data = name ];
//
ClassMethod %rcc(%rcc = "") As %Integer [ SqlName = %rcc, SqlProc ]
{
if '$l(%rcc) set %rcc="mtemp."_$job
set %rccD="^"_%rcc_"D"  
set %rccI="^"_%rcc_"I"  
set %rccS="^"_%rcc_"S"
quit $$$OK
}
//
Storage Default
{
<Data name="RCCDefaultData">
<Value name="1">
<Value>name</Value>
</Value>
<Value name="2">
<Value>city</Value>
</Value>
<Value name="3">
<Value>dob</Value>
</Value>
<Value name="4">
<Value>score</Value>
</Value>
</Data>
<DataLocation>@%rccD</DataLocation>
<DefaultData>RCCDefaultData</DefaultData>
<IdLocation>@%rccD</IdLocation>
<IndexLocation>@%rccI</IndexLocation>
<StreamLocation>@%rccS</StreamLocation>
<Type>%Storage.Persistent</Type>
}
}

Summary:

All you need to use this approach for ISOS
;; set your access globals before use
   do ##class(RCC).%rcc("your.globalname")

For SQL use the related static WHERE condition

SELECT ........   from RCC WHERE %rcc('your.globalname')=1 ....

And this works for any valid Global reference
also for Process Private Globals, temporary Globals, Extended reference, ..
If you provide nothing, I used "mtemp."_$job