为了获得最佳性能,datetime 字符串列上需要有一个合适的索引。我将建议(不一定推荐)一种方法,以避免某些其他查询模式的潜在性能问题。
我建议的方法是使用多个查询,每个查询返回包含新年份值的单行。 (我假设只有几个不同的年份值,并且给定年份有很多行。)
假设我现有的年份列表包含 2011、2013 和 2014 年。
下面描述了我将运行的查询序列,在我运行的查询中使用现有值作为谓词。基本思想是我只需要在给定的年份中找到一行...无需读取 所有 行。
我需要现有的年份列表才能排序。我会从最低值开始,然后运行一个查询来获取该年之前的最早日期。我想要一个最有效地利用索引的查询,以及 Sqllite 中可用的优化。
我现有列表中最早的年份值是“2011”。我会把它推到查询中......我的第一个镜头是这样的:
select dt from t where dt < '2011-01-01'
order by dt limit 1
如果我不追回,我知道 2011 年是最早的一年。
如果我确实得到了回报,我知道这是一个“新”的一年。我会将前四个字符作为年份,并将其添加到我的列表中。我会将那个年份的值与 2011 年进行比较,如果差值大于 1,我会检查下一个最低年份。
例如,如果该查询返回以“2008”开头的日期,则我运行的下一个查询将检查日期时间最短的行,该行在 2008 年之后但在 2011 年之前的一年。
select dt from t where dt < '2011-01-01'
and dt >= datetime('2008-01-01','+1 years')
order by dt limit 1
如果我没有返回一行,我知道 2011 年之前没有更多的“新”年份值。我的下一个查询将使用 2011 作为下限,并将现有列表中的下一年值作为上限绑定,然后再次重复相同的查询。
如果我确实找回了行,日期时间从 2009 年开始。我会将 2009 年添加到我的列表中,我的下一个查询与上面的查询完全相同,但用 2009 年代替 2008 年...
select dt from t where dt < '2011-01-01'
and dt >= datetime('2009-01-01','+1 years')
order by dt limit 1
再一次,如果我没有吵架,那么我知道 2011 年之前没有新的年份了。
所以,现在 2011 年是我的下限,而我现有列表中的下一年是上限。因此,再次进行相同的查询,仅更改年份文字...
select dt from t where dt < '2013-01-01'
and dt >= datetime('2011-01-01','+1 years')
order by dt limit 1
如果我得到一个连续的,那就是新的一年添加到我的列表中。这是我下一个查询的新下限。如果没有行,那么我最后一个查询的上限就是新的下限。
为了优化模式,我会跳过运行我知道不会返回行的查询。当我的列表中已经有 2013 年和 2014 年时,我的查询将采用这种模式...
select dt from t where dt < '2014-01-01'
and dt >= datetime('2013-01-01','+1 years')
order by dt limit 1
但我们知道没有满足这两个条件的行。一行的dt值不能小于2014大于等于2014,这是不可能的条件,所以我们可以跳过执行。
当我到达列表中的最后一个值时,我将删除上限条件...我不在乎下一个查询返回 2015、2017 还是 2032...无论最近一年之后的最低年份我的列表中有年份。
select dt from t where
dt >= datetime('2014-01-01','+1 years')
order by dt limit 1
如果我得到了一个回报,将那一年添加到列表中,并将其用作我的下一个下限。并重复,直到我没有得到任何回报。
这确实会运行多个查询,但它们应该非常有效。在 Hugh Jass 表上,这些可能是您可以运行以查找新年值的最有效查询。
当我们需要运行大量查询时,当我们需要检查很多“差距”时,这种模式就会崩溃。
这种模式的最坏情况是数百个现有年份值以奇数结尾。每年的值之间存在差距,我们必须检查它们之间的每个差距。
但这种模式的最佳情况是一长串连续年份值。如果没有找到新的年份值,我们最多会运行 两个 查询。一个用于检查较早的年份(未找到),另一个用于检查较晚的年份(未找到)。
同样,这种方法的性能绝对取决于在 dt 上是否有适当的索引,以及有效利用该索引的查询计划。