开篇介绍
关于 Lookup 的缓存其实在之前的一篇文章中已经提到了 微软BI 之SSIS 系列 - Lookup 组件的使用与它的几种缓存模式 - Full Cache, Partial Cache, NO Cache 但是还是可能遗漏的部分内容,因此在这里重新总结并补充一下。这是第一篇,还是从理论的角度来讨论 Lookup 缓存的问题;后面有空还会再写一篇,从后台 SQL 执行的情况来理解 Lookup 的工作过程。
并且关于 Lookup 缓存还有其它比较有意思的话题,比如我的这些帖子,大家都可以关联起来看看:
我们还是从 OLE DB Connection Manager 下的这三种缓存模式来讨论:Full Cache 完全缓存,Partial Cache 部分缓存,NO Cache 不缓存
在下面示例中, FF_SRC_INTERNET_SALES 是文件数据输入源,LKP_SALES_ORDER_NUMBER 是 Lookup 组件。
Full Cache 完全缓存
完全缓存 - Lookup 的默认缓存。
第一步:在这种模式下,在数据流预执行 Pre-Execute 即执行之前就会将查询发送给数据库服务器并将数据查询后返回,并缓存到 SSIS 运行时内存中。之后,右侧数据库中的数据即 Lookup 中配置的视图或表 【T032_SALESORDER】中的数据发生任何变化跟缓存中的数据是没有任何关系的。
第二步:数据流此时才开始执行,缓存中已经含有数据了,这时来自于 FF_SRC_INTERNET_SALES中数据就会通过之前配置好的匹配规则使用列 SalesOrderNumber 和 列SalesOrderLineNumber 的值到缓存中查找有没有匹配的 SalesOrderNumber 和 SalesOrderLineNumber。
第三步:如果在缓存中匹配到了相应的数据,那么上图中 Available Input Column (即文件源中的列) 和 Available Lookup Column (即缓存中的列 - 视图或表 T032_SALESORDER 中的列) 中被打勾的列 (此示例中无勾选上的选项) 共同形成一个输出列组:Available Input Column + Available Lookup Column 选中的列向下输出,输出的名称默认叫做 Lookup Match Output。
第四步:如果在缓存中找不到相应的数据,那么根据不匹配的规则(这里选择的是 Redirect rows to no match output)将 Available Input Columns 中的数据作为不匹配数据往下输出,输出名称叫做 Lookup No Match Output。注意:错误数据的内容就不是 Available Input Columns 中的数据了。
那么上面的几个步骤就是在 OLE DB Connection 下的 Lookup 的完全缓存模式与查找输出的流程。
主要特点
- 数据流启动之前(甚至更早,在包执行之前)完成数据查询与缓存动作,查询结果集缓存起来。
- 消耗内存大,增加了数据流启动的时间。
- 在数据流执行的时候非常快,源数据直接和缓存数据做比较,不用再次查询数据库。
- 缓存数据源中的数据变更将也不再影响到缓存中的数据。
- 如果缓存的数据容量超过了内存的大小,那么会出现内存不足报错 Out Of Memory,因为缓存不会主动把数据写入到磁盘上。
何时使用完全缓存 Full Cache
- 引用数据集中的数据量无论大小,只要不超过内存大小,特别当数据源的数据和引用数据集匹配程度高的时候,一次缓存可以反复使用。
- 数据库服务器不在本地,或者数据库服务器压力很大,为了减少反复的连接反复的查询对数据库服务器造成更大的压力。
使用完全缓存 Full Cache 中的关键点
- 数据全部缓存在内存中,如果内存不够并不会将超出部分的数据缓存到磁盘上,而是直接报错 - Run out of memory。
- 由于数据集缓存在内存中,所以在使用 Lookup 的时候不应该直接使用表对象,而应该通过写 SELECT 语句来减少不必要的列输出并且可以加上 WHERE 条件来限定一下数据集的大小,简而言之缓存的数据应该只包含有用的数据。
- 数据一旦缓存,那么在数据流执行过程中就不会再去检测之前源数据是否发生改变或者更新等等,除非数据流重新启动执行。
Partial Cache 部分缓存
第一步:部分缓存模式下,在数据流执行之初 Lookup 缓存还是空的。当 Lookup 组件开始读入 FF_SRC_INTERNET_SALES 数据源中的列时,此时因为需要对比才开始检查缓存中是否有匹配的值。
第二步:缓存中如果有,则直接可以作为匹配输出向下输出了。
第三步:缓存中如果没有,这时就会发送查询到数据库中进行查询(查询语句可以配置参数)。如果在数据库中查找了就会将这个已查到的内容缓存在匹配缓存区中,以供下次使用,这次还是匹配输出。
第四步:如果缓存中没有,查询数据库后也没有,根据配置可以将此条在缓存中没有在数据库中也没有的数据按照配置放在不匹配缓存区以供下次做不匹配检查。因为都查找不到,因此这次是不匹配输出。
特点
- 数据流启动之前,缓存为空,数据流启动时间要比完全缓存的情况下要快。
- Lookup 的时候会慢,因为总要检查缓存,如果有的话就直接用,如果没有的话就需要查询数据库,每次查询都是一次开销。如果数据量比较大的话,这种频繁的查询对数据库服务器压力会比较大。所以从 FF_SRC_INTERNET_SALES 到 LKP_SALES_ORDER_NUMBER 数据流的传递明显要慢,传递一批等一会,因为此时 LKP_SALES_ORDER_NUMBER 需要到数据库中去查数据。即时当 FF_SRC_INTERNET_SALES 数据抽取完毕之后,下面的三个控件还要执行半天。
- 可以在 Advanced Options 中设置最大缓存(32位模式和64位模式两种选择),一旦缓存中的实际数据大小超过这个最大值的话,就会自动清理那些对比中较少使用的行以便为新的数据腾出空间。
- 可以在 Advanced Options 中设置不匹配缓存区所占缓存区的比例,这样在一条源数据在匹配缓存中查询不到,在数据库中也查询不到的情形下,这条数据的关键比较列就会存入不匹配缓存区。下次来的数据如果还在匹配缓存区中找不到的时候,就会先看看不匹配缓存区中是否存在,这样就会减少对数据库的反复查询的几率。如果数据源中的数据与 Lookup 引用集中的数据匹配率很低,可以适当的提高不匹配缓存区的比例。
- 当某次查询数据库时发生 Lookup 引用数据表中的数据发生了变化,此时不匹配缓存区将会默认禁用。应该当 Lookup 引用数据表数据相对稳定没有再发生变化的时候,不匹配缓存区将会重新分配。
什么时候使用 Partial Cache 部分缓存
- 数据源中的数据比较少的时候,这样查询的次数就小。
- 引用数据集中的数据很大,内存无法支持的时候。
- 引用数据集源表的数据发生变化,需要在查询匹配过程中也能知晓的情况下。
- 当需要使用参数化查询来限制引用集的大小的时候可以考虑使用 Partial Cache。
使用 Partial Cache 部分缓存要注意的地方
- 注意缓存区的大小分配尽量足够大,上图中 25MB 实在大小。
- 合理的使用不匹配缓存区,不匹配程度高的时候提高不匹配缓存区的占比。
No Cache 不缓存
无缓存模式下,每次匹配查询都会去数据库查一次。这种缓存模式下,数据量不大并且内存比较紧张的情况下才会使用,当然它对内存的消耗也相对最小,但效率也最低。
总结
就我个人而言,目前对 Lookup 的使用配置情况基本上都默认选择 Full Cache 模式,因为现在内存的支持完全不是什么大问题。一个 10 W 的输入 Lookup 一个 1 W 多的引用集基本上在完全缓存模式下几秒就可以解决掉;如果换成 Partial Cache 或者 No Cache 至少超过 60秒或者更多。所以,在实际开发中基本上可以保持默认选择 Full Cache 就可以达到一个最优效率的使用,除非内存紧张才会在缓存分配比率上做文章。
跟这篇文章相关的文章还有