4

我正在尝试学习如何使用 RavenDB,为此我创建了一个基本示例。似乎初始化存储和查询需要花费大量时间!

static void Main( string[] args )
{
    const bool createNewEntities = true;

    var sw = new Stopwatch();
    using( var store = new EmbeddableDocumentStore {DataDirectory = "~\\Data"} )
    {
        sw.Start();
        store.Initialize();
        sw.Stop();
        Console.WriteLine( "Initialized in {0} ms.", sw.ElapsedMilliseconds );

        if (createNewEntities)
        {
            sw.Reset();
            sw.Start();
            using( var session = store.OpenSession() )
            {
                sw.Stop();
                Console.WriteLine();
                Console.WriteLine( "Opened session in {0} ms.", sw.ElapsedMilliseconds );

                for( var i = 0; i < 10; i++ )
                {
                    var entity = new EntityA( "Entity A " + DateTime.Now.ToLongTimeString() );

                    sw.Reset();
                    sw.Start();
                    session.Store( entity );
                    sw.Stop();

                    if (i < 3)
                        Console.WriteLine( "Stored '{0}' in {1} ms.", entity.Name, sw.ElapsedMilliseconds );
                }

                sw.Reset();
                sw.Start();
                session.SaveChanges();
                sw.Stop();
                Console.WriteLine( "Saved changes in {0} ms.", sw.ElapsedMilliseconds );
            }
        }


        sw.Reset();
        sw.Start();
        using( var session = store.OpenSession() )
        {
            sw.Stop();
            Console.WriteLine();
            Console.WriteLine( "Opened EntityA session in {0} ms.", sw.ElapsedMilliseconds );

            sw.Reset();
            sw.Start();
            var entities = session.Query<EntityA>().ToArray();
            sw.Stop();
            Console.WriteLine("Queried for all {0} EntityA in {1} ms.", entities.Length, sw.ElapsedMilliseconds);
        }


        sw.Reset();
        sw.Start();
        using( var session = store.OpenSession() )
        {
            sw.Stop();
            Console.WriteLine();
            Console.WriteLine( "Opened EntityA session (again) in {0} ms.", sw.ElapsedMilliseconds );

            sw.Reset();
            sw.Start();
            var entities2 = session.Query<EntityA>().ToArray();
            sw.Stop();
            Console.WriteLine( "Queried (again) for all {0} EntityA in {1} ms.", entities2.Length, sw.ElapsedMilliseconds );
        }
    }


    Console.WriteLine();
    Console.WriteLine();
    Console.WriteLine( "Press ENTER to exit..." );
    Console.ReadLine();
}

这会产生以下输出:

在 6132 毫秒内初始化。

在 3 毫秒内打开会话。
在 129 毫秒内存储了“实体 A 08:50:14”。
在 0 毫秒内存储了“实体 A 08:50:15”。
在 0 毫秒内存储了“实体 A 08:50:15”。
在 29 毫秒内保存更改。

在 0 毫秒内打开 EntityA 会话。
在 463 毫秒内查询所有 10 个 EntityA。

在 0 毫秒内(再次)打开 EntityA 会话。
在 1 毫秒内(再次)查询所有 10 个 EntityA。

从这个粗略的例子中,我可以看到:

  • 初始化商店需要大量时间!
  • 存储第一个实体(十个)需要相当长的时间。
  • 第一次查询所有实体需要很多时间,但第二次则完全没有时间。

如何正确查询数据库中特定类型(EntityA)的所有文档?当然,RavenDB 不可能每个查询都需要索引吗?特别是对于没有任何标准的查询?

(注意:我打算使用嵌入在桌面应用程序中的 DB,其中列出所有文档用于显示 DB 的内容。)

4

1 回答 1

5

以下是三个延迟的原因:

初始化延迟
初始化文档存储确实是最昂贵的操作之一。由于您正在运行 RavenDB 的嵌入式模式,它不仅要建立与数据库的连接,而且实际上还必须启动数据库运行。在我的机器(一台 2.3Ghz i5 笔记本电脑)上,初始化需要 2516 毫秒。

如果您正在运行完整的 RavenDB 服务器(未嵌入) - 大部分延迟将是在启动服务器本身时。初始化客户端会明显更快。

这是合理的行为,考虑到IDocumentStore(无论是嵌入的还是正常的)都应该作为单例来保存。在你的应用程序中应该只有一个这样的实例,它应该在启动时创建并在关闭时处理。

第一次存储延迟
因为您没有提供Id自己的,Raven 使用它的HiLo 生成算法为您自动生成一个。这涉及从数据库中分配一个可分配的 id 块,这确实需要很少的时间。后续调用会更快,因为在块用完之前它们不必访问数据库。

如果您提供自己的Id属性并用有效标识符填充它,例如entities/1,entities/2等 - 那么它会快得多,因为您将跳过密钥生成。

查询延迟
未指定静态索引时 的第一次调用.Query<T>()将尝试创建与查询表达式匹配的动态索引。即使在获取“所有”实体时也是如此,因为它仍然必须使用Raven-Entity-Name元数据按实体类型进行过滤。 RavenDB中的集合是一个虚拟的东西,由元数据决定。这些文档实际上是一起存在的——因此除了通过元数据查询和过滤之外,没有其他方法可以获取“集合”中的所有项目。

您看到的部分延迟是正在构建的动态索引。然后对要索引的项目有延迟。请注意,如果您添加了更多项目(例如几百个),您仍然会得到大致相同的延迟,但您不会取回所有项目。该索引会因为刚刚创建而过时,Raven 只会返回其中的一小部分。在像您这样的测试中,您可能希望明确地等待非陈旧的结果。在实际应用程序中,您可能希望改为预定义静态索引。实际上,您可以通过反对静态索引来加快查询速度。延迟将移至索引创建时间而不是查询时间。

如果您想完全避免使用索引,还有另一种方法:

session.Advanced.LoadStartingWith<EntityA>("EntityAs/");

此方法不使用元数据进行过滤 - 它使用键名本身。它直接与文档存储相冲突,无需查询 - 因此速度要快得多。您将需要分页以获得大量结果 - 但无论如何您对查询有同样的担忧。但是使用这种方法,默认页面大小要小得多(25) - 所以你肯定会迟早遇到这个问题。

我希望这能回答你的担忧。如果您还有其他人,请在评论中告诉我。

于 2013-02-10T02:04:29.537 回答