Windows ESENT内部:JetPrereadKeys()的预期行为

Windows ESENT内部:JetPrereadKeys()的预期行为,windows,performance,caching,esent,extensible-storage-engine,Windows,Performance,Caching,Esent,Extensible Storage Engine,我有一个应用程序处理大量存储在ESENT中的数据(100 GB+)。该表的模式是:12字节的键和值,典型大小约为2 KiB。页面大小设置为32 KiB。我不会更改外部长值的默认1024字节大小阈值,因此我认为这些值主要存储在外部 我对改进冷缓存查找和检索性能感兴趣,因为操作是成批进行的,并且密钥是预先知道的。据我所知,()API是为了在这种情况下提高性能而设计的,但事实证明,无论是否使用此调用,我都看不到实际行为有任何变化 详情如下: 在我的例子中,jetpreradkeys()总是报告足够数

我有一个应用程序处理大量存储在ESENT中的数据(100 GB+)。该表的模式是:12字节的键和值,典型大小约为2 KiB。页面大小设置为32 KiB。我不会更改外部长值的默认1024字节大小阈值,因此我认为这些值主要存储在外部

我对改进冷缓存查找和检索性能感兴趣,因为操作是成批进行的,并且密钥是预先知道的。据我所知,()API是为了在这种情况下提高性能而设计的,但事实证明,无论是否使用此调用,我都看不到实际行为有任何变化

详情如下:

  • 在我的例子中,jetpreradkeys()总是报告足够数量的预读密钥,相当于调用API时提交的密钥数量。如文档中所述,对提交的密钥进行了适当排序

  • 我尝试了同步和异步两种方法,其中异步方法是:将预读调用发送到线程池,同时继续查找和检索当前线程上的数据

  • 通过尝试和参数的所有可用组合,我尝试了ESENT的两种可用缓存模式,即使用MMAP或专用页面缓存

  • 除了一个小的例外,我看不到有预读和没有预读时记录的I/O操作有任何区别。也就是说,我希望这个操作会导致(最好是异步)获取B树的必要内部节点。但我看到的唯一一件事是从jetpreradkeys()本身的堆栈中偶尔出现一个同步小读取。读取的大小很小,我认为它不可能预取所有需要的信息

  • 如果调试Windows Search服务,我可以中断对JetPrereadKeys()的各种调用。因此,至少有一个现实世界中调用此API的示例,可能是出于某种原因

  • 我的所有实验都是在机器重新启动后执行的,以确保数据库页面缓存为空


问题:

  • 在所描述的情况下,JetPreAdKeys()的预期行为是什么

  • 如果我使用这个API,我是否应该期望看到不同的I/O模式和更好的性能?我应该看到数据的同步或异步预读取吗

  • 是否有另一种方法可以通过暗示ESENT即将进行的批处理来提高I/O性能

  • jetprreadKeys()API会将读取同步到叶级别的父级,然后将异步IOs排队,以获取所需的键/记录所需的所有叶页面……我认为这回答了#2。如果主表记录(请注意,突发长值/LV存储在单独的树中)是浅缓存或完全缓存的,则此JetPrereadKeys()可能没有帮助。但是,如果表上的主树又大又深,那么这个API可以极大地帮助您。。。这取决于您正在检索的数据的形状和分布。您可以通过转储空间、查看树的深度以及了解“数据”页面,来了解有关表格的一些基本信息,我建议您:

    esentutl /ms Your.Db /v /fName,Depth,Internal,Data
    
    列出表名、深度、内部页面数和叶级数据页面数。主记录树将按表名列出单独的行,然后在其下方列出LVs/as“[Long Values]”

    还请注意,此预读键也不会扩展到突发LVs。。。同样,如果你立即读到一个突发LV列,不幸的是,你会被锁定在IO后面

    默认模式是ESE专门分配和控制自己的数据库缓冲区/页面缓存。JET_参数化文件缓存主要用于(通常较小)退出(或至少是JetTerm/JetDeach其数据库)并大量重新启动的客户端进程。。。所以每次退出时ESE的私有缓冲区缓存都会丢失。。。但是JET_parameterEnableFileCache是一个参数,因此如果最近退出,数据可能仍在文件缓存中。但不建议将其用于大型数据库,因为这会导致数据在ESE缓冲区缓存和NTFS/ReFS文件缓存中进行双重缓存。JET_参数化缓存增强了以前的参数,并在某种程度上改进了这种双重缓存。。。但它只能在干净/未修改的页面缓冲区上节省内存/而不是双缓冲区。对于大型DBs,将这两个参数都保留为off/false。此外,如果您不使用这些参数,则更容易测试冷性能。。。在你的应用程序退出后,只需在你的硬盘上复制一个大文件(100MB,可能是1或2GB)几次(以清除硬盘缓存),你的数据就会变冷。;-)

    现在我们已经提到了缓存。。。最后一件事——我认为可能是您的实际问题(如果不是我上面提到的“数据的形状”。。。打开perfmon并查找“数据库”和/或“数据库==>实例”perf对象(这些对象用于ESENT),查看缓存大小[数据库缓存大小”或“数据库缓存大小(MB)”],并查看可用池大小/[“数据库缓存%可用”]。。。当然,您必须取这个百分比,并根据数据库缓存大小进行计算,以获得一个想法。。。但如果这是低,这可能是你的问题。。。这是因为JetRepreAdKeys将只使用已经可用的缓冲区,所以您必须拥有一个健康/足够大的可用池。将JET_paramCacheSizeMin增大,或将JET_paramStartFlushThreshold/JET_paramStopFlushThreshold设置为使可用缓存大于总缓存大小的%。。。注意,它们被设置为与JET_paramCacheSizeMax成比例,与设置类似:

    paramCacheSizeMin = 500
    paramCacheSizeMax = 100000
    paramStartFlush.. =   1000
    paramStopFlushT.. =   2000
    
    这意味着您的开始和停止阈值分别为当前缓存大小的1%和2%