• 84. 从视图索引说Notes数据库(下)


    作用和代价
    上文介绍了关系型数据库里的索引。Notes数据库里的索引隐藏在视图概念里(本文的讨论仅仅针对Notes的视图索引,不包括全文索引。)。开发者创建的视图仅仅是存放在数据库里的一条设计文档。数据库引擎会根据它创建和更新索引。关系型数据库里的索引是从记录中抽取的数据排序而组成的数据结构(主要是B树),Notes视图的索引还包括未排序的列、计算值、分类、总计等等数据(数据结构仍然是B树,假设运气足够好的话,你会遇到Notes报出B-tree structure is invalid的错误)。用户在client里看到的视图就是索引的数据,再加上外观的设置。这种差别缘于两类数据库底层设计的差异。
    关系型数据库里的索引是为了查询而建的。

    SELECT NAME, JOB FROM PERSON WHERE COUNTRY='China'这样一个简单的查询语句,会由于PERSON表的COUNTRY列建有索引而大大提快速度。

    而对SELECT * FROM PERSON这样无选择的查询语句,是否有索引则没有差别。作为文档型数据库的Notes。情况略有不同。文档型数据库里作为存储数据单元的文档,与关系型数据库里相应的记录相比最大的差异就是,文档没有记录受到的所在表定义的约束,比如一条记录有多少列,列的名称和数据类型是什么,长度几何等等。

    每条文档都能够有随意数量、名称和数据类型的字段。假设说某个表里的每条记录都有一个共同的schema,那么能够说每条文档都有自己的schema。

    在有些文档型数据库里,如大热的MongoDB。文档还被归类在表示同一种实体的collection里,有相似table的含义和用途。而在Notes数据库和还有一热门CouchDB里,连这种容器都没有,全部的文档,不管内容和用途是什么。都直接处于数据库这一级别之下(CouchDB与Notes数据库的相似之处还不仅这一点,考虑到它的最初作者Damien Katz就是来自Notes开发核心团队就一点都不奇怪了)。如此一来,即使是SELECT * FROM PERSON这样查询表格内全部数据的语句,在Notes里也没有直接的相应物了。这也意味着在Notes数据库里不论什么有意义的查询(也就是按文档的id查询之外)都必须藉助于视图这一概念。


    由此可见,Notes视图索引的第一个作用是从数据库里选择某些文档,提取字段的值作为或计算列值。从而提供一个相似table的数据集合或接口。当我们在LotusScript或Java使用NotesView对象訪问当中的NotesViewEntry时,读取的就是索引。同一时候,文档的响应层次、分类、求和、平均值等功能又使得视图承担了关系型数据库里依靠SQL和其它方法实现的报表功能。


    Notes视图索引第二个作用就是便于查找文档。经常使用的NotesView.GetAllDocumentsByKey和GetDocumentByKey的实质都是在索引里找到条目,再返回相应的文档。

    用户在client展现的视图里排序、折叠展开分类以及按开头搜索,也都是利用索引完毕的。
    Notes视图索引的代价和关系型数据库里讨论的一样,都是占领存储空间和消耗计算资源。
    更新的时间
    索引是何时建立的?又是何时更新的?从上一节对索引作用的讨论可知。展现文档集合和使用户能够快速查找文档,这两个至关重要的用途都要求索引的数据是最新的,也就是与它所基于的文档的数据是一致的。在上一篇文章里,我们提到理论上更新索引在时间上有三种选择,一是与文档改动(新增、改动和删除)同一时候,二是延迟至索引被读取时才检查是否须要更新,三是定时更新。选项一保证了索引与文档始终是一致的,可是加大了文档改动时数据库的负担。

    选项二也能保证每次读取的索引是最新的。

    与选项一相比优点是。在索引被读取前,相关的文档可能已经过多次改动。

    不同用户改动不同文档,单个用户多次改动某个文档,等等各种情况都会发生。採用第一种方案时每次改动索引都须要更新,而方案二使得对索引两次被读取之间的全部改动(假设有)。仅仅需进行一次批量更新,从而降低开销。缺点是假设读取时发现索引须要更新,就添加了等待时间。第三种方案实际是对另外一种方案的补充,理念相同是批量更新,目的是降低读取索引时须要更新的次数和文档数量。
    综合以上分析可见。採用方案一时用户訪问索引的速度是最快的。代价是所需系统资源也最多。方案二和三的延迟思路。节省了系统资源,但用户有时需忍受延时。关系型数据库基本上都採用第一种方案。

    文档型数据库则选择各异。MongoDB採用方案一,CouchDB採用方案二,Notes则混合使用方案二和三。


    更新的过程
    定时更新
    我们先来看Notes视图的定时更新。

    这由server执行的Update和Updall两个任务来完毕。

    两者的执行时间都能够在notes.ini里设置,默认情况下Update持续执行,Updall则在每天凌晨两点执行一次。Update维护两个队列(queue)。一个是即时队列(immediate queue),还有一个是延迟队列(deferred queue)。

    队列里保存的是一条条某个数据库索引需更新的请求。请求的来源有几类:复制器(replicator)复制后假设某个副本的文档有变动。就会发送一条请求到队列。邮件路由器(router)将新消息派送到某个邮箱后也会发送一条请求。最频繁的则是一个用户在某个数据库里创建、改动或删除了文档,当他退出该数据库时。会发送一条请求到队列。

    复制和用户改动产生的请求都被发送到延迟队列,特殊的比如触发数据库全文索引及时更新的操作会发送一条请求到即时队列。Update每隔五秒(能够通过notes.ini的UPDATE_IDLE_TIME和UPDATE_IDLE_TIME_MS设置改动此默认值,下同)检查两个队列,对即时队列里的请求立即处理。对延迟队列里的则会比較同一个数据库的请求,最先到达的请求之后的十五分钟(Update_Suppression_Time)内全部的请求都会被忽略。这样做还是为了降低资源的消耗。十五分钟以内对某个数据库的改动仅仅会触发Update更新其索引一次。
    请求仅仅记录数据库的路径,Update在处理时先要推断对那些视图的索引进行更新。此时Notes再次显示了尽量节省资源的特性。

    首先过去七天(UPDATE_ACCESS_FREQUENCY)内未被打开过的视图被忽略。接着根据索引上次更新时间和视图的选择条件搜索近期发生更改过的而且包括在该视图中的文档。假设数量少于二十(UPDATE_NOTE_MINIMUM),也不做更新。
    Updall任务由于是在凌晨进行。Notes显得慷慨一些。它不管队列。而是检查全部数据库的全部视图,须要更新的更新,须要重建的重建。
    打开时更新
    定时更新不能保证索引被訪问时数据是最新的。仅仅能尽最大限度降低那时更新的负担。用户通过client界面或程序訪问视图时,会调用Notes API的NIFOpenCollection()函数打开索引(NIF意为Notes Indexing Facility。就是Notes索引部分的组件)。假设索引数据不是最新的。NIFOpenCollection()就会调用NIFUpdateCollection()更新索引。我们每次在client里打开一个视图时。都会发生这个过程(除非下面说明的特殊情况)。

    假设距离上次Update更新该视图索引,发生更改的文档不多,这个过程就非常快能完毕。

    而假设这期间有大量文档发生改动,甚至该视图的索引不存在,就须要等待非常长时间。

    自R7后。Notes会在单独的后台线程中进行索引更新。用户界面因而不会被卡住,用户还能进行其它操作。


    为了提高视图打开的速度,或者说最大程度地降低索引更新的次数。Notes视图里还有控制打开时是否更新的选项。


     
    各自是:1. 自己主动。初次使用后。

    2. 自己主动。3. 手动。

    4. 自己主动。最多每n小时更新一次。手动意为打开视图时索引不自己主动更新,需按F9更新。

    三种自己主动的差别在于,设为1或4时。假设一个视图未被打开过没有索引,Update和Updall执行时不会创建索引;设为2时则会;设为4时,假设索引在设置的近期n小时内被更新过,表现得就和设为3时一样。
    索引在数据库里占领的空间不可小觑,数据库里假设视图多且复杂(列多,分类和排序多)。索引占领的空间甚至会超过文档的空间。所以视图里又有丢弃索引的设置,能够设为数据库关闭后或者未被訪问超过一定天数后丢弃。假设符合设置的条件。Updall任务负责删除索引。


    所以,我们在设计视图时要……
    每一个视图包括的索引有三类:
    1.    依照NotesID排序的默认索引。
    2.    依照某列排序的索引。
    3.    父文档和子文档关系的索引。


    每添加一个列排序(包括分类),就新增一个索引。多级分类比相同数量的排序须要的计算很多其它。


    我们已经从上面的讨论看到Notes是怎样挖空心思地降低索引更新的次数,由于这是非常消耗计算资源的动作。在设计视图时,假设罔顾Notes的苦心。建一大堆用途不大的视图,又加上用户非常少使用的排序和必要性不大的分类,不但会导致Dominoserver上Update任务不堪重负。也会吞下视图打开缓慢的苦果。
    曾经我曾提到,XPages视图层和数据层分开的优点之中的一个就是使视图能够仅仅作为数据集合,不同的展示须要。比方外观、列和文档的进一步筛选都能够利用XPages的视图控件实现。为降低视图数量提供了可能,从而也就降低了索引的数量。提高了性能和可维护性。
    Notes帮助里实用的參考文章:
    Notes Help - Refreshing view indexes
    Administrator help - Indexer tasks: Update and Updall


  • 相关阅读:
    桥接模式
    单例模式
    迭代器模式
    组合模式
    备忘录模式
    适配器模式
    状态模式
    观察者模式
    golang 字符串统计
    go bytes缓冲区使用介绍 -转自https://www.cnblogs.com/--xiaoyao--/p/5122138.html
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5199761.html
Copyright © 2020-2023  润新知