LotusScript Versions of DBLookup and DBColumn Using Evaluate
I was looking through Jamie Magee’s slides from a 2008 ILUG presentation to review the performance tips he showed us at IamLUG2009. When reading slide #6 I found an interesting tidbit: “When only reading data from documents – @DBLookup and @DBColumn is fastest.” I assumed he meant through an Evaluate statement.
Could this be true? I always considered it a best practice to avoid the Evaluate statement. Then I found an article on ibm.com from 1998 called “Simplifying your LotusScript with the Evaluate statement.” The article is a great synopsis of the Evaluate statement and it confirmed Jamie’s opinion.
Here’s their view:
The reason the Evaluate is faster is because the @DbLookup gets values from a view index, without having to loop through and access each document. In contrast, pulling values using GetAllDocumentsByKey requires you to loop through and access each document.
That’s great but writing Evaluate strings for DBLookup and DBColumn calls isn’t exactly fun. So… I decided to wrap the calls in a handy class.
To call the code is pretty easy:
use "libLSViewTools"
Dim tools as New LSViewTools
dim result as variant
'** function call is DBlookup(server As String,database As String,
'** view As String,key As String,pickMe As Variant,exactMatch As Boolean) As Variant
result = tools.DBLookup("myserver","mydatabase.nsf","myview","myfield",true)
print result(0)
result = tools.DBColumn("myserver","mydatabase.nsf","myview",1)
print result(0)
The parameter “pickme” in the dblookup function is a variant because I allow a number (column) or string (field name) to be sent (just like @DBLookup).
The lss file can be downloaded here: libLSViewTools.lss
The full code is here for your perusal:
'libLSViewTools:
'***** libLSViewTools
'* Library with on class LSViewTools.
'* Class LSViewTools currently has two functions: DBlookup and DBColumn. Refer to the the Notes help
'* for a description of the formula equivalents
Option Public
Option Declare
%INCLUDE "lsconst.lss"
Class LSViewTools
Private boolPrintErrors As Boolean
Private boolThrowErrors As Boolean
Sub New()
boolPrintErrors = True
boolThrowErrors= False
End Sub
Property Set printErrors As Boolean
boolPrintErrors = printErrors
End Property
Property Set throwErrors As Boolean
boolThrowErrors = throwErrors
End Property
Function DBlookup(server As String,database As String,view As String,key As String,pickMe As Variant,exactMatch As Boolean) As Variant
Dim session As New NotesSession
Dim evalBuilder As String
Dim exactMatchStr As String
Dim result As Variant
On Error Goto error_proc
' Start Validation
If view = "" Then
Error 7000, "View cannot be null"
End If
If Typename(pickme) <> "STRING" And Typename(pickme) <> "INTEGER" Then
Error 7001, "5th Parameter must be type string or integer."
End If
If server <> "" And database = "" Then
Error 7003, "Database cannot be null if the server is specified"
End If
If exactMatch = False Then
exactMatchStr = ";[PARTIALMATCH]"
Else
exactMatchStr = ""
End If
If server = "" And database <> "" Then
server = session.CurrentDatabase.Server
End If
If Typename(pickme) = "STRING" Then
evalBuilder = {@DbLookup("";@Name([CN];"}+ server + {"):"} + database + {";"} + view + {";"} + key + {";"} + pickme + {"} + exactMatchStr + {);}
Else
evalBuilder = {@DbLookup("";@Name([CN];"}+ server + {"):"} + database + {";"} + view + {";"} + key + {";} + pickme + exactMatchStr + {);}
End If
result = Evaluate(evalBuilder)
If Isarray(result) Then
dblookup = result
Else
dblookup = Evaluate("NULL")
End If
Exit Function
error_proc:
If boolPrintErrors Then
Print "LSViewTools " + Cstr(Getthreadinfo(LSI_THREAD_PROC)) + " Error: " + Cstr(Err) + " " + Error + ""
End If
If boolThrowErrors Then
Error 7554, "LSViewTools " + Cstr(Getthreadinfo(LSI_THREAD_PROC)) + " Error: " + Cstr(Err) + " " + Error + ""
End If
DBLookup = Evaluate("NULL")
Exit Function
End Function
Function DBColumn(server As String,database As String,view As String,column As Integer) As Variant
Dim session As New NotesSession
Dim evalBuilder As String
Dim exactMatchStr As String
Dim result As Variant
On Error Goto error_proc
' Start Validation
If view = "" Then
Error 7000, "View cannot be null"
End If
If server <> "" And database = "" Then
Error 7003, "Database cannot be null if the server is specified"
End If
If server = "" And database <> "" Then
server = session.CurrentDatabase.Server
End If
evalBuilder = {@DbColumn("";@Name([CN];"}+ server + {"):"} + database + {";"} + view + {";} + Cstr(column) + {);}
result = Evaluate(evalBuilder)
If Isarray(result) Then
If Cstr(result(0)) = "1.#INF" Then
Error 7010, "DBColumn returned too many values"
End If
dbColumn = result
Else
dbColumn = Evaluate("NULL")
End If
Exit Function
error_proc:
If boolPrintErrors Then
Print "LSViewTools " + Cstr(Getthreadinfo(LSI_THREAD_PROC)) + " Error: " + Cstr(Err) + " " + Error + ""
End If
If boolThrowErrors Then
Error 7555, "LSViewTools " + Cstr(Getthreadinfo(LSI_THREAD_PROC)) + " Error: " + Cstr(Err) + " " + Error + ""
End If
DbColumn = Evaluate("NULL")
Exit Function
End Function
End Class
There are 3 Comments to "LotusScript Versions of DBLookup and DBColumn Using Evaluate"
Can’t speak for Jamie’s presentation, but the statement “The reason the Evaluate is faster is because the @DbLookup gets values from a view index, without having to loop through and access each document” predates the GetAllEntriesByKey method, which achieves exactly that. But because GetAllEntriesByKey allows key arrays, and the ability to selectively reach into the resulting document, it’s vastly superior to Evaluate(@dbLookup).
None of these, of course, is as fast as .getDocumentByUNID() in 99.99% of cases.
If you’re after a single key in a categorised view, creating a view navigator and looping through that is far quicker than creating a document collection (and maintains sort order). On one complicated agent I saw a 300% speed increase by switching from a collection to a nav.
@Paul – I have only played with view navigators to make it easier to traverse categories and totals. I never thought of using it to get data like getalldocumentsbyview.
@Nathan – While I agree that having the ability to access the document is great… sometimes you really just need a quick list (hence the reason Notes built @DBLookup).
I haven’t speed tested anything either. I just wanted an easier wrapper to play with the idea.