【问题标题】:What kind of index for orderby/where query in SQL?SQL中orderby/where查询的索引是什么样的?
【发布时间】:2014-09-10 08:39:32
【问题描述】:

我想在一个看起来像这样的 SQLite 数据库上运行查询

SELECT a,b,c,d FROM data WHERE a IN (1,2,3) ORDER BY b,c

我应该使用什么类型/顺序的索引来使 SQLite(或者以后的 MySQL)能够快速执行此操作? 如何轻松检查查询是否被索引增强(即如何解释 EXPLAIN)?如果我在索引中包含d,SQLite 会更快吗?

编辑: 以下是表格的特点:

  • 10.000.000 行
  • 60 个不同的a
  • 6.000.000 不同 b
  • 2.000 个不同的c
  • 没有限制
  • 表格是我的个人分析数据;它只写一次,然后只读

PS:有没有参考资料可以让我了解 SQLite/MySQL 何时可以使用索引?

【问题讨论】:

  • 提供的详细信息不足以为data 表选择索引结构。理想情况下,您将提供总行数、每列中不同值的数量、任何列上的唯一约束或其组合。
  • 此表的使用方式也很重要。那是 DW 或事务系统中的表吗?记录会被更新还是删除?
  • Re“是否有参考资料让我可以学习 SQLite/MySQL 何时可以使用索引”:use-the-index-luke.com

标签: sql sqlite indexing


【解决方案1】:

当且仅当IN (1,2,3) 是一个常量列表(总是相同的值),您可以像这样使用partial index

CREATE INDEX so ON data (b,c) WHERE a IN (1,2,3)

然后运行您的查询会给出这个计划 (explain query plan select...):

0|0|0|SCAN TABLE data USING INDEX so
0|0|0|EXECUTE LIST SUBQUERY 1

注意:没有ORDER BY 操作。

作为反测试,让我们删除索引并像这样替换它:

CREATE INDEX so ON data (a,b,c);

新的执行计划是:

0|0|0|SEARCH TABLE data USING INDEX so (a=?)
0|0|0|EXECUTE LIST SUBQUERY 1
0|0|0|USE TEMP B-TREE FOR ORDER BY

你现在看到排序操作了吗?

我没有生成任何有意义的测试数据(只是一个空表)来验证执行速度的提高。但我想您应该在创建索引后立即看到它。

另请注意,仅自 SQLite 3.8.0(2013-08-26 发布)起支持部分索引

【讨论】:

  • 这是一个有趣的功能。但是,IN 列表并不总是不变的。否则你会推荐什么样的索引?我试过索引b,c,a,d。 SQLite 3.7.2 上的EXPLAIN QUERY PLAN 提供order:0,from:0,detail:TABLE data WITH INDEX b_c_a_d ORDER BY。毕竟它似乎很快。现在是这样吗?是否有任何经验法则可以理解简单的EXPLAIN(产生一个长表)的复杂性?
【解决方案2】:

需要考虑的一个小问题是:如果您过滤a in (1, 2, 3),会找到多少行? 如果这是表的很大一部分,可能已经高达 15% 左右,那么使用索引甚至可能会降低性能。

将此与图书索引进行比较。假设索引是完整的,这意味着所有的词都被索引了。如果您正在寻找“and”的出现,并且您使用此索引,那么您将无法准备好从索引跳到您的文本并返回。简单地从头到尾阅读这本书,扫描“和”肯定是更快的选择。

目前尚不清楚盈亏平衡点在哪里,因为它取决于很多因素。但它比大多数人想象的要低。 (我已经提到了 15%,根据我的经验,这是一个很好的经验法则)

如果可以省略排序,则仍然可以选择使用索引。在这种情况下,树索引将包含 (b, c, a) 列。 (哈希索引在那里无济于事)。 根据数据类型和更新频率,您甚至可以考虑使用(b, c, a, d) 作为索引。 DBMS 只需要进行索引扫描,而不是表扫描。 (如果d很大,不会有太大帮助,而且会浪费很多空间;如果d更新很频繁,也可能是个坏主意,因为它会使更新的工作量增加一倍)。

物理数据库设计通常需要找到正确的折衷方案。

好的,我的很多文章在您编辑后不再适用。不过我认为答案可能会让你思考一些事情。

【讨论】:

    【解决方案3】:

    以下索引可帮助您快速获取记录 - 当然 dbms 认为使用索引比全表扫描更快。例如,如果它认为 in (1,2,3) 将获取表中 90% 的记录,它应该避免使用索引,而是简单地扫描整个表。

    CREATE INDEX idx ON data(a);
    

    以下索引可帮助您快速获取记录,甚至快速排序。同样,如果 dbms 认为使用索引是错误的,则不会使用该索引。但是使用索引的可能性更大,因为 dbms 不仅获取要访问的记录的信息,而且还会使它们已经排序。

    CREATE INDEX idx ON data(a,b,c);
    

    以下索引可帮助您快速获取记录并对其进行快速排序,甚至根本不必访问表。这里所有数据都存在于索引中,因此 dbms 没有理由不使用索引。一切都在那里:获取所需数据的标准、排序,甚至数据本身都已经存在。

    CREATE INDEX idx ON data(a,b,c,d);
    

    【讨论】:

      【解决方案4】:
      • 要过滤a in (1,2,3),您需要一个以(a, ...) 开头的索引
      • 要对b, c 进行排序,您需要一个以(b, c, ...) 开头的索引

      没有一个索引可以同时满足这两个要求。

      【讨论】:

      • 从算法的角度来看,仍然可以使用组合索引,其中第二个条件是使用索引的子树。 SQL 会这样做吗?
      • 我不知道有什么数据库平台可以做到这一点。
      • 嗯,有什么建议可能更好的索引解决方案?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-06
      • 1970-01-01
      • 2022-11-12
      • 1970-01-01
      • 2016-03-19
      • 2010-10-11
      相关资源
      最近更新 更多