【问题标题】:Table name length in sqlite affects performance. Why?sqlite 中的表名长度会影响性能。为什么?
【发布时间】:2013-09-03 23:35:05
【问题描述】:

我注意到表名的长度会影响创建这些表时的性能。下面是重现问题的代码示例:

#include <stdio.h>
#include <assert.h>
#include "sqlite3.h"

int main() {
  int i, sr;
  char table_query[1000];
  sqlite3* db;

  sr = sqlite3_open("test.db", &db);
  assert(sr == SQLITE_OK);

  sr = sqlite3_exec(db, "PRAGMA synchronous=OFF", NULL, NULL, NULL);
  assert(sr == SQLITE_OK);

  sr = sqlite3_exec(db, "PRAGMA journal_mode=OFF", NULL, NULL, NULL);
  assert(sr == SQLITE_OK);

  sr = sqlite3_exec(db, "PRAGMA temp_store=MEMORY", NULL, NULL, NULL);
  assert(sr == SQLITE_OK);

  sr = sqlite3_exec(db, "BEGIN EXCLUSIVE TRANSACTION;", NULL, NULL, NULL);
  assert(sr == SQLITE_OK);

  for (i = 0; i < 10000; ++i) {
  #ifdef LONG_NAMES
   sprintf(table_query, "CREATE TABLE `TABLE_%d_AKLKEKABCDEFGHIJK4C6F766520416C6C20546865205061696E204177617920496E636C204B796175202620416C626572742052656D69782020434452` (content);", i);
  #else
   sprintf(table_query, "CREATE TABLE `TABLE_%d` (content);", i);
  #endif

   sr = sqlite3_exec(db, table_query, NULL, NULL, NULL);
   assert(sr == SQLITE_OK);

  }

  sr = sqlite3_exec(db, "END TRANSACTION;", NULL, NULL, NULL);
  assert(sr == SQLITE_OK);

  sr = sqlite3_close(db);
  assert(sr == SQLITE_OK);

  return 0;
}

编译:
gcc main.c sqlite3.c -O3 -DLONG_NAMES -DNDEBUG
gcc main.c sqlite3.c -O3 -DNDEBUG

在我的机器上,当使用相对较短的表名(如TABLE_{table #})时,创建一个包含 10,000 个表的数据库大约需要 14 秒。这些表名称从 7 个字符到最多 11 个字符不等。

当使用相对较长的表名(如 TABLE_{table #}_{some unique identifying name that adds 120 or so characters})时,创建包含 10,000 个表的数据库大约需要 60 秒。

使用长表名创建数据库的时间增加了 4 倍多!

为什么会这样?这是预期的行为还是错误?

而且由于创建具有长名称的表会对性能产生负面影响,这让我想知道这样的数据库上的查询性能是否也会受到负面影响。这个SO answer 似乎相信关于 MySQL 的答案是“否”,但没有给出参考。

想法?

P.S.:我正在使用最新的合并版本的 sqlite (3.8)

【问题讨论】:

  • 120 个字符的名称的 10000 个表是实际用例吗?
  • @CL 是的。这是一个实际的用例。尽管可以将所有这些数据放入一个表中,但它使我的实现的其他方面变得非常复杂。在放弃并转向更扁平的数据库设计之前,我想了解是否可以采取一些措施来解决此表名性能问题。
  • FWIW,我必须在带有 GCC 4.4.7 的 RedHat 6.4 上添加 -pthread -ldl 才能正确链接此示例和 SQLite 3.8.0.2。使用短名称,创建一个 11MB 的 test.db 需要 10.7 秒(3 次运行),而创建一个添加了 -DLONG_NAMES 的 15MB 的 test.db 需要 27.5 秒(也运行 3 次)。

标签: c performance sqlite database-performance


【解决方案1】:

使用较长的表名,生成的空数据库文件会大 4 倍,因为较长的表名会占用架构中的更多空间。毫不奇怪,SQLite 需要 4 倍的时间来编写 4 倍的内容。

请注意,表名只存储一次。所以一旦你开始向数据库中添加内容,两者之间的相对大小差异就会减小,渐近接近 1.0。两个数据库之间大小的绝对差异应保持不变。

【讨论】:

  • “SQLite 花费 4 倍的时间来编写 4 倍的内容也就不足为奇了。” - 我不确定我是否同意这种说法。如果我将数据库设计为使用单个表并将表名描述为行,则创建数据库会快得多。快了一个数量级。我正在描述的性能问题具体与创建表有关。行中较长的条目不会像较长的表名那样影响性能。
【解决方案2】:

较长的表名在sqlite_master 系统表中占用更多空间(比较文件大小)。 当 SQLite 遍历该系统表以搜索该表(或检查新表名是否已存在)时,需要读取和比较更多数据。

但是,在查询时,SQLite 仅在第一次实际访问该模式时才从系统表中加载数据,因此查询性能不会受到太大影响。

【讨论】:

    猜你喜欢
    • 2011-08-11
    • 2011-09-13
    • 1970-01-01
    • 2014-06-23
    • 2012-05-11
    • 2010-12-05
    • 1970-01-01
    • 2020-07-23
    • 1970-01-01
    相关资源
    最近更新 更多