Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 提高SQLite反连接性能_Performance_Sqlite_Join - Fatal编程技术网

Performance 提高SQLite反连接性能

Performance 提高SQLite反连接性能,performance,sqlite,join,Performance,Sqlite,Join,查看此问题底部的更新,下面提到的查询时间意外变化的原因已被确定为sqliteman怪癖的结果 我在SQLite数据库中有以下两个表(我知道这个结构似乎毫无意义,但请容忍) 源表包含大约500000行,目标表中永远不会有多个匹配记录,实际上几乎所有源行都可能有一个匹配的目标行 我正试图执行一个相当标准的反连接来查找源中的所有记录,而目标中没有相应的行,但是我发现很难创建一个执行时间可以接受的查询 我使用的查询是: SELECT source.item_id, source.time

查看此问题底部的更新,下面提到的查询时间意外变化的原因已被确定为sqliteman怪癖的结果

我在SQLite数据库中有以下两个表(我知道这个结构似乎毫无意义,但请容忍)

源表包含大约500000行,目标表中永远不会有多个匹配记录,实际上几乎所有源行都可能有一个匹配的目标行

我正试图执行一个相当标准的反连接来查找源中的所有记录,而目标中没有相应的行,但是我发现很难创建一个执行时间可以接受的查询

我使用的查询是:

SELECT
    source.item_id,
    source.time,
    source.data
FROM source
LEFT JOIN target USING (item_id, time)
WHERE target.item_id IS NULL;
没有WHERE子句的左连接大约需要200毫秒才能完成,随着时间的增加,这将增加到5000毫秒

虽然我最初注意到消费应用程序中的查询速度很慢,但上面的计时是通过直接从sqliteman中执行语句获得的

这个看似简单的子句如此显著地增加了执行时间,有什么特别的原因吗?有什么方法可以重组这个查询来改进它吗

我也尝试过以下方法,但效果相同。(我认为底层查询计划是相同的)

非常感谢

更新 非常抱歉,这些明显的结果实际上是由于sqliteman的一个怪癖造成的

sqliteman似乎对返回到256的行数任意应用了一个限制,并将在滚动时更动态地加载。这将使大型数据集上的查询看起来比实际要快得多,这使得它在估计查询性能时是一个糟糕的选择

尽管如此,他们是否有任何明显的方法来提高此查询的性能,或者我只是达到了SQLite的能力极限?

这是您的查询的关键(任意一个):

这是尽可能有效的:

  • 源代码中的每一行都必须由
  • 目标
    中搜索匹配行
  • 可能会有一点改进。
    行可能没有排序,因此
    目标
    搜索将在索引中的随机位置进行查找。 如果我们可以强制
    扫描按索引顺序进行,那么
    目标
    查找也将按顺序进行,这使得这些索引页更有可能已经在缓存中

    如果我们不使用索引中没有的任何列,即如果我们删除
    数据
    列,SQLite将使用
    索引:

    > EXPLAIN QUERY PLAN
      SELECT source.item_id, source.time
      FROM source
      LEFT JOIN target USING (item_id, time)
      WHERE target.item_id IS NULL;
    0|0|0|SCAN TABLE source USING COVERING INDEX si
    0|1|1|SEARCH TABLE target USING COVERING INDEX ti (item_id=? AND time=?)
    
    这可能没有多大帮助。 但是,如果有帮助,并且您希望在
    源代码
    中使用其他列,您可以通过先执行联接,然后按
    行的
    rowid
    查找
    源代码
    行来实现这一点(如果结果很少,则额外的查找应该不会有任何影响):


    你到底是如何衡量执行时间的?IS NULL查询应该不会慢一些。我在问题中添加了一个注释。这些时间是使用sqliteman中的查询工具获得的。这是否实际获取了所有结果行?如果不是,则从(实际查询)中测量
    选择COUNT(*)。真诚的道歉,我应该使用其他查询工具验证执行时间,因为结果表明,更快的查询是sqliteman怪癖的结果。非常感谢。查询计划实际上没有改变,但是当结果较少时,您需要搜索更多的表行以获得前256个结果。非常感谢。我可以确认,虽然您描述的查询最初并没有更快,但随后的调用明显更快,这是我原始查询中未观察到的行为。
    
    SELECT 
        source.item_id,
        source.time,
        source.data
    FROM source
    WHERE NOT EXISTS (
        SELECT 1 FROM target
        WHERE target.item_id = source.item_id
        AND target.time = source.time
    );
    
    0|0|0|SCAN TABLE source
    0|1|1|SEARCH TABLE target USING COVERING INDEX ti (item_id=? AND time=?)
    
    > EXPLAIN QUERY PLAN
      SELECT source.item_id, source.time
      FROM source
      LEFT JOIN target USING (item_id, time)
      WHERE target.item_id IS NULL;
    0|0|0|SCAN TABLE source USING COVERING INDEX si
    0|1|1|SEARCH TABLE target USING COVERING INDEX ti (item_id=? AND time=?)
    
    SELECT *
    FROM source
    WHERE rowid IN (SELECT source.rowid
                    FROM source
                    LEFT JOIN target USING (item_id, time)
                    WHERE target.item_id IS NULL)