【问题标题】:Does a multi-column index work for single column selects too?多列索引是否也适用于单列选择?
【发布时间】:2010-10-22 05:37:19
【问题描述】:

我有(例如)一个索引:

CREATE INDEX someIndex ON orders (customer, date);

这个索引是只加速使用客户和日期的查询,还是像这样加速单列的查询?

SELECT * FROM orders WHERE customer > 33;

我正在使用 SQLite。


如果答案是肯定的,为什么每个表可以创建多个索引?


还有一个问题:当您在查询中使用两个列时,组合索引与两个分离索引相比要快多少?

【问题讨论】:

    标签: sqlite indexing


    【解决方案1】:

    我通常使用组合索引对希望分页或“流式”请求的数据进行排序。

    假设一个客户可以下多个订单.. 并且客户 0 到 11 存在,并且每个客户有多个订单都以随机顺序插入。我想根据客户编号和日期对查询进行排序。您也应该将 id 字段排序到最后一个客户有多个相同日期的拆分集(即使这可能永远不会发生)。

    sqlite> CREATE INDEX customer_asc_date_asc_index_asc ON orders
              (customer ASC, date ASC, id ASC);
    

    获取排序查询的第 1 页(限制为 10 项):

    sqlite> SELECT id, customer, date FROM orders
              ORDER BY customer ASC, date ASC, id ASC LIMIT 10;
    
    2653|1|1303828585
    2520|1|1303828713
    2583|1|1303829785
    1828|1|1303830446
    1756|1|1303830540
    1761|1|1303831506
    2442|1|1303831705
    2523|1|1303833761
    2160|1|1303835195
    2645|1|1303837524
    

    获取下一页:

    sqlite> SELECT id, customer, date FROM orders WHERE
              (customer = 1 AND date = 1303837524 and id > 2645) OR
              (customer = 1 AND date > 1303837524) OR
              (customer > 1)
              ORDER BY customer ASC, date ASC, id ASC LIMIT 10;
    
    2515|1|1303837914
    2370|1|1303839573
    1898|1|1303840317
    1546|1|1303842312
    1889|1|1303843243
    2439|1|1303843699
    2167|1|1303849376
    1544|1|1303850494
    2247|1|1303850869
    2108|1|1303853285
    

    等等……

    当您使用查询 OFFSET 和 LIMIT 时,将索引放在适当的位置会减少服务器端索引扫描。查询时间越长,偏移量越高,驱动器越难寻找。使用这种方法可以消除这种情况。

    如果您计划稍后加入数据但每个请求只需要一组有限的数据,建议您使用此方法。如上所述加入 SUBSELECT 以减少大型表的内存开销。

    【讨论】:

    • 这也有助于消除不需要的服务器端命令时间...如果您使用 datetime(date, 'unixepoch', 'localtime') 而不是 date 作为返回列.. 它肯定会受到限制。我相信无论如何都会如此 - 取决于引擎。
    【解决方案2】:

    marc_s 对您的第一个问题有正确答案。多键索引中的第一个键可以像单键索引一样工作,但任何后续键都不会。

    至于复合索引的速度取决于您的数据以及您如何构建索引和查询,但这通常很重要。索引本质上允许 Sqlite 对字段进行二进制搜索。

    如果您运行查询,请使用您提供的示例:

    SELECT * from orders where customer > 33 && date > 99
    

    Sqlite 将首先使用对客户 > 33 的整个表进行二分搜索来获取所有结果。然后它会只对那些查找日期 > 99 的结果进行二分搜索。

    如果您对客户和日期使用两个单独的索引执行相同的查询,Sqlite 将不得不对整个表进行两次二进制搜索,首先是客户,然后是日期。

    因此,您将看到多少速度提升取决于您如何构建与查询相关的索引。理想情况下,索引和查询中的第一个字段应该是消除最可能匹配项的字段,因为这将通过大大减少第二次搜索必须做的工作量来最大程度地提高速度。

    有关更多信息,请参阅: http://www.sqlite.org/optoverview.html

    【讨论】:

    • 如果第一列是不等式表达式(例如 customer>33 ),SQLite 将不会使用索引的第二列。 (大多数数据库引擎会,很难)。
    • 如果您创建两个单独的索引,将只使用其中一个,另一个表达式将根据第一个生成的结果集进行评估。 (在 Oracle 上,它可以执行两个索引搜索并与结果集相交,如果优化是基于成本的并且满足某些条件,但这是极少数情况)。
    【解决方案3】:

    我很确定这会奏效,是的 - 它在 MS SQL Server 中仍然有效。

    但是,如果您只需要选择日期,则此索引对您没有帮助,例如一个日期范围。在这种情况下,您可能需要仅在日期上创建第二个索引,以提高这些查询的效率。

    马克

    【讨论】:

      猜你喜欢
      • 2019-08-14
      • 1970-01-01
      • 1970-01-01
      • 2022-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多