Discussion (17)5
Log in or sign up to continue

Why would you want to do this?
the index related to %Save() is no "build" but just setting a value to the index global. 
setting an index is mostly less load than saving an object.

I assume that you want to skip one (or more) indices for specific values.
You may use an "after" trigger to manually delete an index based on some of the properties.
For this approach, you will need to change this trigger, every time you add/change a property or an index.

Hi Michael,

I'm afraid the only way is to insert the record using SQL and use the  %NOTRIGGER and %NOINDEX keywords to prevent the actions.

You can have a look at %Library.FunctionalIndex

You could do something truly horrible and disgusting with the storage definition, like:

<IndexLocation>@$Select($D(%SuppressIndexFile,0):"foo",1:"^DC.Demo.SuppressIndexFileI")</IndexLocation>

But that would be truly horrible and disgusting. (Echoing Robert Cemper's comment, knowing why would help!)

Hi Michael,

Maybe you are reproducing some application migration issue and are setting up some test data.

Purely as a "diagnostic" it seems possible to use the $SORTBEGIN and $SORTEND ObjectScript functions to effect this potentially without changing existing code.

Basically you can ringfence specific globals (normally for performance rationale) and transiently store the global writes in buffer. Then at end of "experiment", you can decide what to commit. ie: Commit the data writes but throw away the index writes.

Hope this helps.

Class TEST.Claim Extends %Persistent
{ Property PropA As %String; Property PropB As %String; Index ixdPropA On PropA; Index ixdPropB On PropB; /// Do ##class(TEST.Claim).TestWithIndex()
ClassMethod TestWithIndex()
{
^TEST.ClaimD,^TEST.ClaimI
for i=1:1:10 {
set obj=..%New()
set obj.PropA="PropA V"_i
set obj.PropB="PropB V"_i
do obj.%Save()
}
zw ^TEST.ClaimD,^TEST.ClaimI
}/// Do ##class(TEST.Claim).TestWithoutIndex()
ClassMethod TestWithoutIndex()
{
^TEST.ClaimD,^TEST.ClaimI
$SORTBEGIN(^TEST.ClaimD)  // Buffer the writes
$SORTBEGIN(^TEST.ClaimI)  // Buffer the writes
for i=1:1:10 {
set obj=..%New()
set obj.PropA="PropA V"_i
set obj.PropB="PropB V"_i
do obj.%Save()
}
$SORTEND(^TEST.ClaimD,1)  // Keep data
$SORTEND(^TEST.ClaimI,0)   // Throw Indexes away
zw ^TEST.ClaimD,^TEST.ClaimI
} Storage Default
{
<Data name="ClaimDefaultData">
<Value name="1">
<Value>%%CLASSNAME</Value>
</Value>
<Value name="2">
<Value>PropA</Value>
</Value>
<Value name="3">
<Value>PropB</Value>
</Value>
</Data>
<DataLocation>^TEST.ClaimD</DataLocation>
<DefaultData>ClaimDefaultData</DefaultData>
<IdLocation>^TEST.ClaimD</IdLocation>
<IndexLocation>^TEST.ClaimI</IndexLocation>
<StreamLocation>^TEST.ClaimS</StreamLocation>
<Type>%Storage.Persistent</Type>
} }
 
Kind regards,

Alex

Update: For clarification the $Sortbegin on the ^*D global was simply to demonstrate different possible outcomes. The actual solution only required to discard the index ( ^*I) updates.
 

Yet another majestic thing about ObjectScript. Wicked cool.

I fail to imagine how to do this with ePy  devil

@Alex Woodhead Why are you using $sortbegin on the ^D global? Just to show it's possible in this demo? Or are you recommending that general approach? It seems to me that the solution to the original question would be allowing the data to save normally (not using $sortbegin on the ^D global), and using $sortbegin on the ^I global and discarding those updates.
@Michael Fortunato Please tell us the reason for wanting to do this. It can't be that you want the index to be permanently out of sync with the data. Perhaps it's for performance for many inserts? If so, switching to a SQL approach with %NOINDEX (as @David Satorres suggested) is a good idea.

Hi @Joel Solon 
Yes the $Sortbegin on the ^*D global was simply to demonstrate different possible outcomes. You are right the solution only requires to discard the index ( ^*I) updates.
I will update my above reply.

To elaborate:

1) I wanted to use the object interface because it handles multi table inserts when my %Persistent object has properties that are also %Persistent. 

2) I wanted to prevent indices from being updated on %Save so that my bulk inserts would be faster. I can then defer the building of my indices after my bulk insert is done. I was aware of %NOINDEX but because of point 1) I was hoping to take an oop approach. 

Thanks Michael.

You could code it the oop way, and use $sortbegin on all the index globals for your multiple tables, which means you'd have to know or look up what the index global names are (since they're not always ^D and ^I anymore), and test 1000000 inserts (main table and referenced tables) with the index build deferred to the end, and time it to see how long it takes. 

And then code it the sql way, inserting the same data into the multiple tables using %NOINDEX, and calling %BuildIndices() on all the classes at the end, and time it to see how long that takes. The sql way is supposed to be faster...

I understand your answer (#2) the way as this is a one time job. The simplest and quickest way to do this is:

- disable all indices (comment them out),
- compile the class or classes
- do the bulk insert
- enable all indices (by removing comment markers)
- compile the class or classes
- rebuild the indices

Class My.Class
{
    /*  disable all indices
    index1 someindex1 on someprop1;
    index2 someindex2 on someprop2;
    */
}

Following this discussion since beginning I'm wondering about the variant I've learned.
my personal approach would be.
#1)
have an exact copy of your class also pointing to the same storage
remove all index definitions from that clone class
run your bulkload
#2)
if you don't want to have the same storage
just eliminate the index definitions in the copy
clean its storage and run your bulk load
finally, merge the resulting globals

#' .)
It's not pure OO,
but writing to storage is never OO with Caché or IRIS