此文章是今年IBM Rational开发者大会给出一份关于Schema优化的文档,我只翻译其中对我们开发者有益的部分,请关注
1、使用VB还是使用PERL语言开发
这个问题其实很多人都有自己的偏好。IBM在这里给出的意见是跨平台只能使用PERL,这个是理所当然的。而实际很多企业应该仅适用windows端进行访问CQ,所以使用VB比PERL更好。因为PERL在windows平台中是单线程执行,效率很差,最后使用者会很痛苦。在使用web asp的时候,更需要VB,而不能使用PERL,否则将无法使用。
启动的时候CQ会将所有HOOK一次性加载下来,所以越多的代码就会造成启动越慢,且更多的消耗内存。
执行时,更多的HOOK也会造成长时间响应及表现缓慢的情况。
2、字段的Validation Hook是每个字段更新都会触发字段的验证HOOK。这个就需要进行优化了~~
如果确定要用验证HOOK,请使用FieldInfo->ValueChangedThisSetValue()方法来判断这个字段是否被修改过。(当然这里IBM给的是一个例子,后来发现这个方法只能对SetFieldValue这样的HOOK起作用,如果想知道这个动作是否触发了字段值更改,需要用ValueChangedThisAction()方法来判断,比较麻烦)
还有一种解决方式,可避免使用字段的验证HOOK。使用Base型动作的验证HOOK,因为BASE型动作的验证HOOK会被在每个动作验证HOOK之前调用,所以这个HOOK也可以保证每个动作都能验证对应的字段,当然相对开发也会复杂一些。
Schema的开发要尽量重用代码,比如多使用全局脚本解决,同时创建Session变量会给程序及机器带来很大的消耗,应该尽量减少session的新建。
3、Value_Change这个HOOK要避免循环调用,就是A变了B也跟着变,而在B的Value_Change中又要改变A,这样是不允许的,会造成程序死锁。当然CQ允许多个字段对某一字段修改,比如A变化了去修改B和C的值,而B变化了也会去修改C的值,不过这样的结果是不可预测的,不能确定是A还是B对C的结果产生影响。
4、Email Rule和Notification HOOK
Email Rule定制方便,实现简单,应该是绝大部分邮件的发起。而且在v7版已经采用了一次性带入客户端进行缓存,发送邮件。
但Email Rule无法跟踪,只能够对本记录内的字段、人员进行发送,同时Email Rule多了一次性加载时间上也是很差的。
使用Notification Hook可以在客户端进行Email触发,而且灵活性会高很多,内容、人员可由开发者定制。
看一下用Perl写的Notification Hook来替代Email Rule
Example: Send E-Mail via Notification Hook
my $owner = $entity->GetFieldStringValue(“owner”);
my $submitter = $entity->GetFieldStringValue(“submitter”);
my $id = $entity->GetFieldStringValue(“id”);
my $mailmsg= CQMailMsg::Build();
$mailmsg->AddTo($owner);
$mailmsg->SetSubject($submitter);
my $subject = “Entity “. $id . “modified.”;
$mailmsg->SetSubject($subject);
my $body = “Description: “. $entity->GetFieldStringValue(“Description”);
# add more to $body as needed
$mailmsg->SetBody($body);
$mailmsg->Deliver();
5、减少在执行过程中创建AdminSession的次数
经过测试发现,AdminSession的创建会严重影响执行速度,根据使用情况不同,大概会消耗3~42s不等。而在这一过程中,Logon的时间大概会占到95%以上,即用admin登录有40s可能在logon,而只有2s才是真正执行程序的时间。
可以使用CQ提供的DB查询功能来实现adminsession做的事,这个过程是很简短的,一般1~2s即可完成执行。
my $queryDefObj= $session->BuildQuery(“users”);
$queryDefObj->BuildField(“login_name”);
$queryDefObj->BuildField(“fullname”);
my $resultSetObj= $session->BuildResultSet($queryDefObj);
$resultSetObj->Execute();
while ($resultSetObj->MoveNext()==$CQPerlExt::CQ_SUCCESS)
push(@choices, $resultSetObj->GetColumnValue(2));
6、避免使用“Recalculate Choice List”即重新计算选项列表勾选项
这个对于List字段每次点击都会去自动获取一遍,效率相对较差。不勾选的话,即首次采集后进行缓存。
在使用过程中发现,这个缓存是有一定问题的,除非这个List跟其他字段没有关联,最好是常量列表才使用。总之此处虽然可以优化,但对于很多使用CQ的用户来说,意义不大,开发人员也应该谨慎去掉这个选择。
7、理智使用Reference_List
对于Reference_List会造成查询中关联多个表,会造成查询速度缓慢。IBM工程师建议使用DB查询来缓解这个压力。
Option 1: Use Query to avoid using Reference List
my $sqlString= “select login_namefrom users where is_active<> 0”;
my $resultSetObj= $session->BuildSQLQuery($sqlString);
$resultSetObj->Execute();
while ($resultSetObj->MoveNext() == $CQPerlExt::CQ_SUCCESS)
push(@list, $resultSetObj->GetColumnValue(1));
Option 2: Use a Reference List of User records
my $list = $entity->GetFieldChoiceList(“Owner”);
使用Reference_List在使用主键时候使用比较好,使用DB查询在使用Reference内的属性时候比较高效。
8、更好的使用CQ的Reference属性关系
有些开发人员喜欢格式化,比如获取一个项目信息,再获取一个User信息,不断的使用session.GetEntity这样的东西,其实可以很简单。
$entity->SetFieldValue("cust_name", $entity->GetFieldStringValue("project.leader.full_name"));
9、附件问题,很多大公司在使用CQ时候发现,附件问题是很严重的,造成CQ数据库庞大,造成Multisite三地同步缓慢。所以附件的控制是整个平台稳定的重要一个环节。下面介绍如何控制附件的大小。
Perl脚本
sub MaxFileSize{
my $result;
use File::stat;
my $maxFileSize= 5000000; # 5MB
# Get a list of the attachment fields in this record type...
my ($AttachmentFields) = $entity->GetAttachmentFields();
for (my($AF) = 0; $AF < $AttachmentFields->Count(); $AF++){
my ($AttachmentField) = $AttachmentFields->Item($AF);
my($Attachments) = $AttachmentField->GetAttachments();
my $numAttach= $Attachments->Count();
for (my($A) = 0; $A < $ $numAttach; $A++) {
my($Attachment) = $Attachments->Item($A);
# File size is always 0 before a first commit
if ($Attachment->GetFileSize() == 0){
$filesize= -s $Attachment->GetFileName();
if ($filesize> $maxFileSize){
return "Cannot add attachments larger than 5MB.";
}
}
}
}
return $result;
}
vb脚本:
' 其他任何动作fire时,都会触发这个动作;
' 在这里完成:限制单个附件大小为3M
Dim fso, f, s
needs_Validation = ""
set session = GetSession()
set attachFields = AttachmentFields
' 定义一个session变量,用来作为上传了附件的标志
' session.NameValue("SessionVarPIRAttach") = "否"
' session.outputdebugstring "Fix 动作的validation hook 开始: "& vbCrLf
' Iterate over the attachment fields on an Entity.
' 遍历附件类型的字段
For Each attachField In attachFields
set attaches = attachField.Attachments
' iterate over the attachment's field attachments
' 遍历附件字段中的所有附件
For Each myAttach In attaches
filename = myAttach.FileName
filesize = myAttach.FileSize
' INFO " filename is " & filename
' File size is always 0 before a first commit
' when File size is 0, the file has been added during the current action,_
' and is still on the local drive
If (filesize = 0) Then
Set fso = CreateObject("Scripting.FileSystemObject")
Set f = fso.GetFile(filename)
filesize = f.size
End if
' INFO "filename is " & filename & " size is " & filesize
If (filesize > 3000000) Then
needs_Validation = "Error: File " & filename & "单个文件大小请不要超过3M"
Exit Function
End If
Next
Next
CQ Schema还有很多可以优化之处,但并不是上面的方法都要执行,个人建议根据个人需要。对于outputdebugstring这个,尽量少,用dbwin32跟踪后尽量注释掉或者屏蔽,否则可能会造成CQ Web问题。