分析

、概述

分析stmt:

ANALYZE schema-name . table-or-index-name schema-name index-or-table-name

ANALYZE 命令收集有关表和索引的统计信息,并将收集到的信息存储在数据库的内部表中,查询优化器可以在其中访问信息并使用它来帮助做出更好的查询计划选择。如果没有给出参数,则分析所有附加的数据库。如果模式名称作为参数给出,那么将分析该数据库中的所有表和索引。如果参数是表名,则只分析该表和与该表关联的索引。如果参数是索引名称,则只分析该索引。

具有使用复杂查询的长期数据库的应用程序应考虑在关闭每个数据库连接之前运行以下命令:

PRAGMA analysis_limit=400;
PRAGMA optimize;

optimize pragma通常是空操作,但它偶尔会运行 ANALYZE,如果它看起来对查询规划器有用的话。analysis_limit pragma限制优化 pragma运行的任何 ANALYZE 命令的范围,以便它不会消耗太多 CPU 周期。可以根据需要调整常量“400”。100 到 1000 之间的值适用于大多数应用程序。

2.细节

默认实现将所有统计信息存储在名为“ sqlite_stat1 ”的单个表中如果使用 SQLITE_ENABLE_STAT4选项编译 SQLite,则会收集额外的直方图数据并将其存储在sqlite_stat4中。旧版本的 SQLite 在使用 SQLITE_ENABLE_STAT2 或 SQLITE_ENABLE_STAT3 编译时会使用sqlite_stat2sqlite_stat3 表所有最新版本的 SQLite 都会忽略 sqlite_stat2 和 sqlite_stat3 表。未来的增强可能会创建额外的内部表具有相同的名称模式,但最后一位数字大于“4”。所有这些表统称为“统计表”。

可以使用SELECT查询统计表的内容, 并可以使用DELETEINSERTUPDATE命令进行更改。从SQLite 版本 3.7.9 开始, DROP TABLE命令适用于统计表。(2011-11-01) ALTER TABLE命令不适用于统计表。更改统计表的内容时应格外小心,因为无效内容会导致 SQLite 选择低效的查询计划。一般来说,不应通过调用 ANALYZE 命令以外的任何机制修改统计表的内容。有关详细信息,请参阅“使用 SQLITE_STAT 表手动控制查询计划”。

ANALYZE 收集的统计数据不会随着数据库内容的变化而自动更新。如果数据库的内容发生重大变化,或者数据库模式发生变化,那么应该考虑重新运行 ANALYZE 命令以更新统计信息。

查询计划器在读取模式时将统计表的内容加载到内存中。因此,当应用程序直接更改统计表时,SQLite 不会立即注意到更改。应用程序可以通过运行 ANALYZE sqlite_schema强制查询计划器重新读取统计表。

3.自动运行ANALYZE

PRAGMA optimize命令将根据需要自动在各个表上运行 ANALYZE。推荐的做法是让应用程序在关闭每个数据库连接之前调用PRAGMA 优化语句。

每个 SQLite数据库连接都记录了查询规划器将从手头获得准确的 ANALYZE 结果中受益的情况。这些记录保存在内存中,并在数据库连接的整个生命周期内累积。PRAGMA optimize命令查看这些记录并仅在新的或更新的 ANALYZE 数据似乎可能有用的那些表上运行 ANALYZE。在大多数情况下, PRAGMA optimize不会运行 ANALYZE,但它偶尔会对以前从未分析过的表或自上次分析以来增长显着的表执行此操作。

由于PRAGMA 优化的操作在某种程度上是由在同一数据库连接上评估的先前查询确定的,因此建议推迟PRAGMA 优化,直到数据库连接关闭,这样才有机会积累尽可能多的使用信息尽可能。 对于长时间保持打开状态的数据库连接,设置一个计时器每隔几个小时或每隔几天运行一次PRAGMA 优化也是合理的。

需要更多控制的应用程序可以运行PRAGMA optimize(0x03)以获得 SQLite 认为适合运行的 ANALYZE 命令列表,但实际上不需要运行这些命令。如果返回的集合非空,则应用程序可以决定是否运行建议的 ANALYZE 命令,也许在提示用户指导之后。

PRAGMA optimize命令首次在SQLite 3.18.0 (2017-03-28) 中引入,对于所有先前版本的 SQLite 都是空操作。

4.大型数据库的近似分析

默认情况下,ANALYZE 对每个索引进行全面扫描。这对于大型数据库来说可能很慢。因此,从 SQLite 版本 3.32.0 (2020-05-22) 开始, 可以使用PRAGMA analysis_limit命令来限制 ANALYZE 执行的扫描量,从而帮助 ANALYZE 运行得更快,即使是在非常大的数据库文件上。我们称此运行为“近似分析”。

analysis_limit pragma的推荐使用模式如下:

PRAGMA analysis_limit=1000;

该 pragma 指示 ANALYZE 命令像往常一样开始对索引进行全面扫描。但是当访问的行数达到 1000(或 pragma 指定的任何其他限制)时,ANALYZE 命令将开始采取措施停止扫描。如果索引最左边的列在之前的 1000 步中至少发生了一次变化,那么分析会立即停止。但是,如果最左边的列始终相同,则 ANALYZE 会向前跳到具有不同最左边列的第一个条目,并在终止之前读取额外的 1000 行。

上一段中描述的分析限制影响的详细信息可能会在 SQLite 的未来版本中发生变化。但核心思想将保持不变。N 的分析限制将努力将每个索引中访问的行数限制为大约 N。

建议 N 的值介于 100 和 1000 之间。或者,要禁用分析限制,导致 ANALYZE 对每个索引进行完整扫描,请将分析限制设置为 0。为了向后兼容,分析限制的默认值为 0。

通过近似 ANALYZE 放置在 sqlite_stat1 表中的值与通过不受限制的分析计算的值并不完全相同。但它们通常足够接近。sqlite_stat1 表中的索引统计信息在任何情况下都是近似值,因此近似 ANALYZE 的结果与传统的全扫描 ANALYZE 略有不同这一事实对实际影响不大。可以构建一个病理案例,其中近似分析明显不如全扫描分析,但这种情况在现实世界的问题中很少见。

一个好的经验法则是在运行“ANALYZE”或“ PRAGMA optimize之前始终将“PRAGMA analysis_limit=N”设置为 100 到 1000 之间的 N。结果不是那么精确,但也足够精确,而且结果计算速度如此之快这一事实意味着开发人员更有可能计算它们。一个近似的 ANALYZE 比根本不运行 ANALYZE 要好。

4.1. 近似分析的局限性

sqlite_stat4 表中的内容无法通过完整扫描进行计算。因此,如果指定了非零分析限制,则不会计算 sqlite_stat4 表。