Caché Efficiency

I am trying to write this loop as efficient as possible.  The global has over 10 million records.

SET PIDX=""    
For
 { 
              Set PIDX=$ORDER(^[Nspace]LAB(PIDX))
              Quit:PIDX=""  
              Set Data=$GET(^[Nspace]LAB(PIDX))
              Set BBData=$P(Data,"\",6)
              If BBData'=""
              {
              If BBData'="########"
              {

Am I better off not setting the variable BBData and using If $P(Data,"\",6)'=""

Also, is there a better way to write the two If statements in one line so it only continues if it is either "" or ########

Answers

The biggest thing you want to do is use three-argument $order to collapse from two global references to one:  $ORDER(^[Nspace]LAB(PIDX),1,Data)

In regards to the question about setting BBData or other small variants like that, it may very much be data-dependent and depend on what happens later in the loop that you haven't showed us.  But generally speaking if you're going to calculate the $p more than once, you probably do want to store it in a (private) variable.

You can certainly combine multiple conditions with and and or operators (&& and ||) if that's what you're asking.  Also, constructs like $case and $select can help (in case you haven't encountered them before).

Replace full reference to a  global with one zn.

 Consider the following code:

Class Utils.Global
{

/// Do ##class(Utils.Global).Generate()
ClassMethod Generate(NS = "SAMPLES", Count = 100000000)
{
    New $namespace
    Zn NS
    Kill ^LAB
    For i=1:1:Count {
        Set ^LAB(i) = i
    }
}

/// Do ##class(Utils.Global).Test()
ClassMethod Test(NS = "SAMPLES")
{
    Set time = $p($h,",",2)
    Do ..Ref1(NS)
    Set time1 = $p($h,",",2)
    Do ..Ref2(NS)
    Set time2 = $p($h,",",2)
    Write "Full ref time ",time1-time,!,"ZN time ",time2-time1
}

ClassMethod Ref1(NS)
{
    Set PIDX=""    
    For {
        Set PIDX=$ORDER(^[NS]LAB(PIDX))
        Quit:PIDX=""  
    }
}

ClassMethod Ref2(NS)
{
    New $namespace
    Zn NS
    Set PIDX=""    
    For {
        Set PIDX=$ORDER(^LAB(PIDX))
        Quit:PIDX=""  
    }
}

}

When I run Do ##class(Utils.Global).Test() in a terminal I get the following results:

Full ref time 38
ZN time 35

even better difference on smaller loops (10000000):

Full ref time 3
ZN time 2

GitHub.

I don't think the above code proves anything.

The first time you run trough it it gets cached, so the second time is bound to be faster.
Try to run another 2 full runs and another 2 zn runs and you should see they are way closer.

Ugly as they are, naked references can significantly improve performance for repeated references to the same subscript level of a global.

Comments

Thanks for the comments.  Those changes have helped.  Here is the entire routine.  If you see anything else that would help, I'd appreciate the feedback.

uuCLASSLabBBExtract2(Nspace,rNum)
 
 
 //Temporary Global for HID number to code translation
 New $namespace
 ZN Nspace
 SET HID="" 
   FOR
{
    SET HID=$ORDER(^LBI("12H",1,HID),1,VAL)
    QUIT:HID="" 
Set VAL1=$P(VAL,"\",1)
Set ^||site(HID)=VAL1
}

 //Temporary Global for English Text Code translations
 SET TEXTCODE="" 
For
{
      Set TEXTCODE=$ORDER(^LBI(4,TEXTCODE),1,VAL2)
      Quit:TEXTCODE=""
      Set Translation =$P(VAL2,"\",1)
      Set ^||etc(TEXTCODE)=Translation
}
 
 //BB Extract
 
 SET CntIndex=0
 SET PIDX=""    
For
{
  Set PIDX=$ORDER(^LAB(PIDX),1,Data)
Quit:PIDX=""  
Set BBData=$P(Data,"\",6)
If BBData'=""
{
If BBData'="########"
{
Set Name=$P(Data,"\",1)
Set LName=$P(Name,"#",1)
Set FName=$P(Name,"#",2)
Set MIni=$P(Name,"#",3)
Set Name2=LName_","_FName_MIni

Set DOB=$P(Data,"\",2)
Set Year=$E(DOB,5,8)
Set Month=$E(DOB,1,2)
Set Day=$E(DOB,3,4)
Set DOB2=Month_"/"_Day_"/"_Year
 
 
  Set ABO=$P(BBData,"#",1)
  Set Group=$TR($P(ABO,"%",2),"!")                            //Remove "!" from Group (O!,A!)
  Set Rh=$P(ABO,"%",3)
  Set ABO2=Group_" "_Rh
 
 
  Set Units=$P(BBData,"#",2)
 
  Set Trans=$P(BBData,"#",3)
  If Trans '="" Set Trans=$ZDATE(($P(BBData,"#",3))+49307)
 
  Set AgAb=$P(BBData,"#",4)             //Need to create separation between multiple English Text Codes with "-" delimiter
  set temp =""
For codeNum=1:1:$length(AgAb,"-")           // loop through "-" pieces of AgAb
{
set code = $piece(AgAb,"-",codeNum)              // get each code
set $piece(temp," | ",codeNum) = ^||etc(code)          // put the translation into temp using "|" instead of "-"
}
set AgAb = temp                // replace contents of AgAb
 
  Set Prob=$P(BBData,"#",5)
  set temp =""
  For codeNum=1:1:$length(Prob,"-")
  {
set code = $piece(Prob,"-",codeNum)
  set $piece(temp," | ",codeNum) = ^||etc(code)
  }
set Prob = temp
 
  Set Comm=$P(BBData,"#",6)                    //Have to allow for freetext comments (ie. ;269753-;269754-HCC)
  set temp =""
  set first=""
  For codeNum=1:1:$length(Comm,"-")
  {
Set first=$E($piece(Comm,"-",codeNum),1)            //Extract first character of comment
If first=";"                                                                              //Determine if first character is ";"
{set code = $TR($piece(Comm,"-",codeNum),";")}      //Remove the ; from the comment
Else 
{set code = $piece(Comm,"-",codeNum)}               //If no ";", set to itself
  set $piece(temp," | ",codeNum) = ^||etc(code)         //setting temp to muliple pieces with translations
  }
set Comm = temp
 
  Set Attr=$P(BBData,"#",7)
  set temp =""
  For codeNum=1:1:$length(Attr,"-")
  {
set code = $piece(Attr,"-",codeNum)
  set $piece(temp," | ",codeNum) = ^||etc(code)
  }
set Attr = temp
 
  Set EXM=$P(BBData,"#",8)
 
  Set AS=$TR($P(BBData,"#",9),"%")                    //Remove "%" from beginning of code (%POS,%NEG)
 
  Set MRN=""
  For
  {
  Set MRN=$ORDER(^LAB(PIDX,0,"INT","NSP",1,MRN))
Quit:MRN=""

Set HID=""
For
{
Set HID=$ORDER(^LAB(PIDX,0,"INT","NSP",1,MRN,HID))
Quit:HID=""  
 
  IF $P(MRN,"-",2)=""          //Remove any MRNs from list that include "-" (ex. CAP-2313)
 
  {Set CntIndex=CntIndex+1
 Set ^["USER"]SQLLABBBEXTRACT(rNum,CntIndex)=$ListBuild(Name2,MRN,^||site(HID),DOB2,ABO2,AgAb,Prob,Comm,Attr,EXM,AS,Units,Trans)
}   
    }
}
}
}

 

Nothing to do with your question, but reading through your code reminds me of my years at Sunquest. :)