Performance 如何为我的用户提供大型应用程序的迷你版

Performance 如何为我的用户提供大型应用程序的迷你版,performance,lotus-notes,lotus-domino,database-replication,Performance,Lotus Notes,Lotus Domino,Database Replication,我的用户对我们拥有的大型LotusNotes应用程序(而不是web)的糟糕性能感到非常失望。它目前为10Gb,有大约500000个文档,并包含readers字段 我想做的是创建应用程序的迷你版本,因为大多数用户只对过去几年的文档感兴趣 此时无法存档或移动大型应用程序,因此我正在考虑提供一个新的迷你副本,并进行选择性复制,仅包括今年的文档 我的问题是,应用程序的完整版本需要在所有服务器上,这意味着我将在同一台服务器上使用相同的副本id获得完整版本和迷你版本,这似乎有点可怕 有更好的方法吗?我见过很

我的用户对我们拥有的大型LotusNotes应用程序(而不是web)的糟糕性能感到非常失望。它目前为10Gb,有大约500000个文档,并包含readers字段

我想做的是创建应用程序的迷你版本,因为大多数用户只对过去几年的文档感兴趣

此时无法存档或移动大型应用程序,因此我正在考虑提供一个新的迷你副本,并进行选择性复制,仅包括今年的文档

我的问题是,应用程序的完整版本需要在所有服务器上,这意味着我将在同一台服务器上使用相同的副本id获得完整版本和迷你版本,这似乎有点可怕


有更好的方法吗?

我见过很多不同的方法来解决这个问题,从简单到过度设计。可悲的是,我想我已经设计出了一些超越工程的方法。幸运的是,我学到了一些教训。以下是我认为技术含量最低的方法:

您首先要做的是制作数据库的纯设计副本。我叫它productiondocs.ntf。我将原始文件称为alldocs.nsf

将两个代理添加到productiondocs.ntf,并确保它们受到设计刷新/替换的保护。调用第一个代理“synch”,并将其设置为在新文档或修改过的文档上运行,然后编写代码,将新文档/修改过的文档复制到alldocs.nsf中。确保选中isValid以防止在此代理的主循环中处理已删除的文档。将第二个代理称为“清除”。编写代码以检查日期(创建日期、修改日期或文档中的数据字段,具体取决于您要实施的规则)并删除超过一年的文档

现在,您可以使用选择性复制,但只需一次。制作alldocs.nsf的选择性副本,仅包含一年的文档,并将其命名为yeardocs.nsf。然后制作yeardocs.nsf的非复制副本,并将其命名为production.nsf。最后,使用production.ntf替换production.nsf的设计。再次检查代理是否存在,以及是否针对设计刷新/替换操作对其进行了保护。(某些版本的designer搞砸了!)根据需要安排同步运行,并安排清除每天或每周运行。将production.nsf复制到所有服务器,并将用户移动到production.nsf


(注意:您可以反过来做,在清除现有数据库后将用户保留在现有数据库中;但老实说,我认为从一个全新的NSF开始,您将获得额外的性能提升,所以这就是我以我的方式编写它的原因。)

我看到了许多解决此问题的不同方法,从简单到过度设计。可悲的是,我想我已经设计出了一些超越工程的方法。幸运的是,我学到了一些教训。以下是我认为技术含量最低的方法:

您首先要做的是制作数据库的纯设计副本。我叫它productiondocs.ntf。我将原始文件称为alldocs.nsf

将两个代理添加到productiondocs.ntf,并确保它们受到设计刷新/替换的保护。调用第一个代理“synch”,并将其设置为在新文档或修改过的文档上运行,然后编写代码,将新文档/修改过的文档复制到alldocs.nsf中。确保选中isValid以防止在此代理的主循环中处理已删除的文档。将第二个代理称为“清除”。编写代码以检查日期(创建日期、修改日期或文档中的数据字段,具体取决于您要实施的规则)并删除超过一年的文档

现在,您可以使用选择性复制,但只需一次。制作alldocs.nsf的选择性副本,仅包含一年的文档,并将其命名为yeardocs.nsf。然后制作yeardocs.nsf的非复制副本,并将其命名为production.nsf。最后,使用production.ntf替换production.nsf的设计。再次检查代理是否存在,以及是否针对设计刷新/替换操作对其进行了保护。(某些版本的designer搞砸了!)根据需要安排同步运行,并安排清除每天或每周运行。将production.nsf复制到所有服务器,并将用户移动到production.nsf


(注意:您可以反过来做,在清除现有数据库后将用户保留在现有数据库中;但老实说,我认为从一个全新的NSF开始,您将获得额外的性能提升,这就是为什么我这样写的原因。)

我非常喜欢Richard的解决方案,但我最近实现了一个到目前为止我喜欢的衍生方案。基本上,将每个文档中的任何元数据放入一个单独的数据库,该数据库是您的“索引”,当他们打开索引文档时,它会在alldocs.nsf中打开文档(并关闭索引文档)

为此,请在alldocs.nsf中编写一个代理,在修改或保存文档时创建索引文档。它应该只复制要用于索引的字段(元数据)。从my将事件复制到Main代理执行此操作的示例代码(不包括它调用的子例程或函数):

Sub Initialize
Dim session As New NotesSession
Dim maindb As NotesDatabase ' Main SIR
Dim mainincidents As NotesView ' view in Main SIR
Dim maindoc As NotesDocument ' document in Main SIR
Dim projectdoc, nextprojectdoc As NotesDocument ' document in this database
Dim ndc As NotesDocumentCollection ' unprocessed documents in this database
Dim fieldItem As NotesItem
Dim reportnumber, value, formtype As Variant
Dim fieldsToCopy (10) As String 
Dim reason As String

On Error GoTo errorhandler 

Call StartAgentLogging ( session )

Set thisdb = session.Currentdatabase

' find all unstamped documents
Set ndc = thisdb.Unprocesseddocuments

If ndc.Count = 0 Then
    Call agentLog.LogAction ( "No incidents to process" )
    Exit Sub
End If

maindbfilepath = DetermineKeyword("MAINSIR")
Set maindb = session.Getdatabase("","")
Call maindb.Open("", maindbfilepath)

If Not maindb.Isopen Then
    reason = "Main Security database could not be found at " & maindbfilepath
    Call agentLog.LogAction ( reason )
    MessageBox reason, 16, "Error"
    Exit Sub
End If

Set mainincidents = maindb.Getview("(Incidents for Upload)")
Set projectdoc = ndc.Getfirstdocument()
fieldsToCopy (0) = "ReportType"
fieldsToCopy (1) = "ReportNumber"
fieldsToCopy (2) = "ReportDate"
fieldsToCopy (3) = "IncidentDate"
fieldsToCopy (4) = "ProjectName"
fieldsToCopy (5) = "ProjectCountry"
fieldsToCopy (6) = "ProjectLocation"
fieldsToCopy (7) = "ReporterName"
fieldsToCopy (8) = "ReporterPhone"
fieldsToCopy (9) = "ReporterEmail"
fieldsToCopy (10) = "Appointment"

While Not projectdoc Is Nothing
    formtype = projectdoc.GetItemValue ("Form")
    If formtype(0) = "Incident" Then
        ' check to see if that exists in the main SIR
        reportnumber = projectdoc.GetItemValue("ReportNumber")
        Call agentLog.LogAction ( "Checking " & reportnumber(0) )
        Set maindoc = mainincidents.GetDocumentByKey(reportnumber(0), True)
        Call agentLog.LogAction ( "Accessing " & reportnumber(0) )

        If maindoc Is Nothing Then
            Call agentLog.LogAction ( "Main does not contain " & reportnumber(0) & " creating new document." )
            ' if not, create new document
            Set maindoc = maindb.Createdocument()
            maindoc.Form = "Incident"

            ForAll fieldname In fieldsToCopy
                Call agentLog.LogAction ( "Field name: " & fieldname ) 
                Set fieldItem = projectdoc.Getfirstitem(fieldname)
                Call maindoc.Copyitem(fieldItem, fieldname)
            End ForAll

            Call maindoc.Save(True, False)
            Call CreateNotice ( maindoc )
        Else
            Call agentLog.LogAction ( "Main contains " & reportnumber(0) & " updating document." )
            ' if it does, update data
            ForAll fieldname In fieldsToCopy
                Call agentLog.LogAction ( "Field name: " & fieldname ) 
                value = projectdoc.GetItemValue(fieldname)
                Call maindoc.ReplaceItemValue(fieldname, value(0))
            End ForAll
        End If

        'Path and filename
        Call maindoc.Replaceitemvalue("Path", thisdb.Filepath)
        Call maindoc.Save(True, False)
        Call agentLog.LogAction ( "Saved " & reportnumber(0) )
    Else
        Call agentLog.LogAction ( "Project form is " & projectdoc.Form(0) )
    End If

    ' stamp document as processed
    Set nextprojectdoc = ndc.GetNextDocument(projectdoc)
    Call session.Updateprocesseddoc(projectdoc)
    Set projectdoc = nextprojectdoc
Wend 

exiting:
    Exit Sub
errorhandler:' report all errors in a messagebox
    reason = "Error #" & CStr (Err) & " (" & Error & ") when creating incident in Main database, on line " & CStr (Erl)
    Call agentLog.LogAction ( reason )
    MessageBox reason, 16, "Error" 
    Resume exiting
End Sub
然后,需要将代码添加到索引数据库中索引表单的onLoad事件中。我把我的放在了一个叫ToolsRunMacro的特工那里,但你可以直接放进去。这是我的打开项目副本代理

Sub Initialize
' this button opens the incident report in the project database
Dim ws As New NotesUIWorkspace
Dim session As New NotesSession
Dim reportdb As NotesDatabase
Dim view As NotesView
Dim uidoc As NotesUIDocument
Dim thisdoc, reportdoc As NotesDocument
Dim filepath, reportnumber As Variant
Dim baseurl, opener, unid As String

Call StartAgentLogging ( session )
Set thisdb = session.Currentdatabase

Set uidoc = ws.CurrentDocument
Set thisdoc = uidoc.Document
filepath = thisdoc.GetItemValue ( "Path" )
reportnumber = thisdoc.GetItemValue ( "ReportNumber" )

Set reportdb = session.GetDatabase (thisdb.Server, filepath (0), False )
If reportdb Is Nothing Then
    MessageBox ( "Could not find Project Security Incident Report database" & Chr$(10) & thisdb.Server & "\" & filepath(0) )
    Call agentLog.LogAction ( "Could not find Project Security Incident Report database" & Chr$(10) & thisdb.Server & "\" & filepath(0) )
    Exit Sub
End If
If Not reportdb.Isopen Then
    Call reportdb.Open(thisdb.Server, filepath (0)) 
End If
Set view = reportdb.GetView ( "Incidents" )
Set reportdoc = view.GetDocumentByKey ( reportnumber(0) )
If reportdoc Is Nothing Then
    MessageBox ( "Could not find Report #" & reportnumber(0) )
    Call agentLog.LogAction ( "Could not find Report #" & reportnumber(0) )
    Exit Sub
End If

Call uidoc.Close
unid = reportdoc.UniversalID
baseurl = reportdb.NotesURL
opener = Left$ ( baseurl, InStr ( baseurl, "?" ) -1 ) & "/Incidents/" & unid & "?OpenDocument"
Call ws.URLOpen ( opener )
Call agentLog.LogAction ( "Opened Report #" & reportnumber(0) )
End Sub
现在,您可以将索引数据库限制为仅包含最近一年的文档,或者查看当所有文档都在其中时它是如何工作的。这在很大程度上取决于您需要在视图中提供多少数据

在我的情况下,索引数据库包含来自许多数据库的文档的索引文档,并充当“完整数据”数据库的中心访问点。它还在测试中,所以我不确定它会有多好