【问题标题】:SQLite - Fastest way to read Data from SQLite Database?SQLite - 从 SQLite 数据库读取数据的最快方法?
【发布时间】:2012-09-24 20:29:48
【问题描述】:

我有一个本地 SQLite 数据库

表格详情

-- Describe PREFIX_LIST
CREATE TABLE PREFIX_LIST(ITEM VARCHAR(25) PRIMARY KEY)

-- Describe SUFFIX_LIST
CREATE TABLE SUFFIX_LIST(ITEM VARCHAR(25) PRIMARY KEY)

-- Describe VALID_LIST
CREATE TABLE VALID_LIST (
    "PART1" TEXT,
    "PART2" TEXT,
    PRIMARY KEY(PART1, PART2)
)

现在这个列表真的很大,我需要从中保存数据。

这是我的实现。

SQLiteConnection con = null;
SQLiteCommand cmd = null;
Connect(DbPath, ref con, ref cmd);

cmd.CommandText =
    "SELECT PART1 || '@' || PART2 FROM VALID_LIST 
 WHERE NOT EXISTS 
   (SELECT * FROM PREFIX_LIST WHERE VALID_LIST.PART1 LIKE '%' || ITEM || '%') 
   AND NOT EXISTS
   (SELECT * FROM SUFFIX_LIST WHERE VALID_LIST.PART2 LIKE '%' || ITEM || '%')";

var reader = cmd.ExecuteReader();

if (reader.HasRows)
{
    string savePath;

    if (SaveTextFile(out savePath) == DialogResult.OK)
    {
        TextWriter writer = new StreamWriter(savePath);
        while (reader.Read())
        {
            writer.WriteLine(reader.GetString(0));
        }
        writer.Close();
        writer.Dispose();
    }

}

reader.Close();
reader.Dispose();
cmd.Dispose();
con.Close();
con.Dispose();

MessageBox.Show("List Saved!.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);

我需要一些更好的方法来更快地保存列表。 VALID_LIST 中的总条目数为 2639117

为上面的 SQL QUERY 保存花了 15 分钟!

如果sql查询可以优化,请lmk!

提前致谢

【问题讨论】:

  • 相关子查询 + LIKE = 巨大的性能冲击
  • @cdhowie - 我知道,但还有什么其他解决方案?我认为查询必须以某种方式进行优化!
  • 我认为没有一种简单的方法可以在不完全改变您的架构的情况下对其进行优化。
  • @cdhowie - 改变架构不是问题!我刚刚开始申请,我希望这三个列表都会变得更大!
  • 您能否提供一些示例数据,以及您希望从查询中得到什么结果?

标签: c# database sqlite query-optimization


【解决方案1】:

除非通配符附加到后缀,否则带有LIKE 的查询通常会非常慢。 LIKE '%foo' 等谓词无法通过典型的字符串索引进行索引。

但是,您可以使用其 full text search (FTS) 功能替换 sqlite 中大量使用的 LIKE

FTS3 和 FTS4 扩展模块允许用户创建特殊的 具有内置全文索引的表(以下简称“FTS 表”)。这 全文索引允许用户有效地查询数据库 包含一个或多个单词(以下称为“标记”)的所有行,即使 该表包含许多大型文档。

他们有an example,在您的用例的性能方面看起来很有希望。

CREATE VIRTUAL TABLE enrondata1 USING fts3(content TEXT);     /* FTS3 table */
CREATE TABLE enrondata2(content TEXT);                        /* Ordinary table *

SELECT count(*) FROM enrondata1 WHERE content MATCH 'linux';  /* 0.03 seconds */
SELECT count(*) FROM enrondata2 WHERE content LIKE '%linux%'; /* 22.5 seconds */

【讨论】:

  • 我认为你倒退了——前缀可以使用索引,但后缀不能。
  • @cdhowie 我同意,我指的是通配符的附加位置。我已经澄清了我的答案。
  • 我明白你现在的意思了。这有点模棱两可,谢谢澄清。
【解决方案2】:

考虑使用全文搜索。

为此,必须对 PREFIX 和 SUFFIX 中的值进行标记(它们必须是单独的单词),并且您尝试匹配的 ITEM 必须是这些值之一中的不同标记(不是一个词或两个词一起)。例如,PREFIX 和 SUFFIX 中的字符串必须是“RED BLUE GREEN”或“DOG, CAT, CAPYBARA”,ITEM 的值必须是 RED、BLUE、GREEN、DOG、CAT 或 CAPYBARA。

如果满足这些条件,您可以启用全文搜索,将这些表重新创建为全文表,并将 LIKE(和通配符)替换为 MATCH。在这种情况下,SQLite 将维护在 PREFIX 或 SUFFIX 中找到的每个 token 的索引,并且该部分的搜索将会快得多。

不幸的是,在 SQlite 中启用 FTS 涉及从设置了一个或多个编译时标志的源代码编译产品。我没有这方面的经验。

【讨论】:

  • 谢谢所有的信息!看起来我必须坚持我的解决方案 atm,即使它更慢!
  • 您的匹配项是否与单个单词匹配?如果是这样,将单词一次一个地放入它们自己的行中。您可以很快完成这项工作。
  • 对不起我的英语不好,但我想通过 sql 做的是,确保我在 valid_list.part1 中的所有项目不与 prefix_list.item 中的所有项目部分匹配
  • 不用担心。我建议如果部分值都是单独的单词,您应该在 PREFIX 和 SUFFIX 表中将它们拆分为单独的行,然后使用“=”而不是“LIKE”进行搜索。这仅适用于值是不同的单词并且您没有在“内部”单词中查找匹配项的情况。请发布所有表格中的示例值。
  • 不,抱歉,没有一个词是这样的,老实说,第 1 部分是电子邮件用户,第 2 部分是电子邮件域
【解决方案3】:

我不确定这是否是您想要的,但这将有助于加快写入过程。尝试将您从数据库中读取的字符串累积到字符串生成器中,然后写入文件。 例如,您可以读取 100k 字符串,然后一次将这 100k 写入文件。

    StringBuilder builder = new StringBuilder();
    int count = 0; //to limit the number of rows stored in string builder.
    while (reader.Read())
    {

        builder.AppendLine(reader.GetString(0));
        count++;

        //store every 100k or so rows at once. 
        //This number depends on how much RAM 
        //you can allocate towards storing the string of rows.
        //If you have 2GB of free RAM
        //this number can easily be 1 million but it always depends on the
        //size of each string stored in database.
        if(count == 100000) 
        {
           File.AppendAllText(path, builder.ToString()); //Append all rows to the file
           builder.Clear(); //clear the string for next 100k rows of data
           count = 0; //Clear the counter value
        }
        count++
    }

如果有帮助,请告诉我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-04
    • 2011-04-26
    • 1970-01-01
    相关资源
    最近更新 更多