【问题标题】:Do indexes suck in SQL?索引会吸收 SQL 吗?
【发布时间】:2009-03-25 15:43:21
【问题描述】:

假设我有一个包含大量行的表,并且我想要索引的列之一可以有 20 个值之一。 如果我在列上放一个索引,它会很大吗?

如果是这样,为什么?如果我将数据分成 20 个表,每个表对应一个列的值,那么索引大小将是微不足道的,但索引效果是一样的。

【问题讨论】:

  • 索引效果是一样的,但是当你想要第二个索引时呢?

标签: sql indexing partitioning


【解决方案1】:

糟糕的不是索引。它会将索引放在错误的列上,这会很糟糕。

说真的,你为什么需要一个单列的表?该数据的含义是什么?它有什么用途?

还有 20 张桌子?我建议你先阅读database design,或者向我们解释你的问题的背景。

【讨论】:

  • 我见过一个数据库,其中实际实体的每个属性都有一个单独的表。原因:他们想要每个属性的版本历史和时间旅行。想象一下那个有 300 个表的数据库,其中大多数字段的类型都是“DateTime”...
  • @thijs 但您仍然需要两列,一列作为键,一列作为属性
  • 我的措辞很糟糕。我要索引一列,而不是一列。我将使用表结构的更多详细信息来编辑我的问题。
  • 单列表非常有用。考虑一个有 1,000,000 名客户的系统,其中大约 250 名在任何给定时间处于信用保留状态。您更喜欢哪一个——Customers 中的 OnCreditHold 列,还是只有 CustomerID 列和 250 行的 OnHoldCustomers 表?
【解决方案2】:

索引(或索引)并不糟糕。在过去的几十年中,许多非常聪明的人花费了大量时间来确保这一点。

但是,您的架构缺乏相同的专业知识和努力,可能确实很糟糕。

在所描述的情况下,分区相当于应用聚集索引。如果表以其他方式排序(或以任意顺序),则索引必须占用更多空间。根据平台的不同,非聚集索引的大小可能会随着行相对于索引值的排序程度的增加而减小。

YMMV.

【讨论】:

  • 好!我怀疑这种分区就像使用聚集索引。这让我想到了一个问题:使用聚集索引自己对表进行分区是否有任何价值?我认为如果我只需要添加一些代码来选择正确的插入,那么对插入的性能影响就会很小
  • 要插入的正确表。如果我使用聚集索引,会不会对性能造成更大的影响?每次插入有聚集索引的地方,数据是否必须进行大量移动 - 还是比这更智能?
  • 具有聚集索引的表(根据定义)按索引列排序。因此,插入所有值可能会产生成本。但是,使用分区表实际上可能会更糟-您必须吸吮它才能看到。也不要忘记在比较中尝试使用非聚集索引!
【解决方案3】:

简短的回答: 索引是否糟糕:是和否

更长的答案: 如果使用得当,它们不会很烂。也许您应该开始阅读索引是如何工作的、为什么它们可以工作以及为什么它们有时不工作。

良好的起点: http://www.sqlservercentral.com/articles/Indexing/

【讨论】:

    【解决方案4】:

    没有索引不会很糟糕,但您必须注意如何使用它们,否则它们可能会适得其反。

    第一:架构/设计
    为什么要创建一个只有一列的表?这可能使规范化迈出了一大步。数据库设计是优化性能时要考虑的最重要的事情之一

    第二:索引
    简而言之,索引将帮助数据库对您的记录执行二进制搜索。如果没有对列(或一组列)的索引,数据库通常会退回到表扫描。表扫描非常昂贵,因为它涉及枚举每条记录。

    对于索引扫描,数据库表中有多少记录并不重要。由于(平衡)二叉树搜索,记录数量翻倍只会导致一个额外的搜索步骤。

    确定表的主键,SQL 会自动在该列上放置一个聚集索引。聚集索引执行得非常好。此外,您可以在 SELECT、JOIN、WHERE、GROUP BY 和 ORDER BY 语句中经常使用的列上放置非聚集索引。请记住索引有一定的重叠,尽量不要将聚集索引包含到非聚集索引中。

    索引上的填充因子可能也很有趣。您是要针对读取(高填充因子 - 更少存储,更少 IO)或写入(低填充因子更多存储,更少重建数据库页面)优化您的表。

    第三:分区
    使用分区的原因之一是优化您的数据访问。假设您有 100 万条记录,其中 500,000 条记录不再相关,而是出于归档目的而存储。在这种情况下,您可以决定对表进行分区并将 500,000 条旧记录存储在慢速存储上,将其他 500,000 条记录存储在快速存储上。

    衡量就是了解
    了解发生了什么的最好方法是测量你的 cpu 和 io 发生了什么。 Microsoft SQL Server 有一些工具,例如 Management Studio 中的 Profiler 和执行计划,它们会告诉您查询的持续时间、读/写次数和 CPU 使用率。执行计划还将告诉您正在使用哪些或 IF 索引。令您惊讶的是,您可能会看到表扫描,尽管您没有预料到。

    【讨论】:

    • 呵呵,我不是说表格只有一列。我的意思是它有一个特别要索引的列。我已经编辑了问题以使其更清楚。
    • 优秀的答案。很详细。
    【解决方案5】:

    假设我有一个包含大量行的表,我想要索引的一列可以有 20 个值之一。如果我在列上放一个索引,它会很大吗?

    索引大小将与您的行数和索引值的长度成正比。

    索引不仅保留索引值,还保留某种指向行的指针(Oracle 中的ROWIDPostgreSQL 中的LCIDInnoDB 中的主键等)。

    如果您有 10,000 行和 1 个不同的值,您的索引中仍然会有 10,000 记录。

    如果是这样,为什么?如果我将数据分成 20 个表,每个表对应一个列的值,则索引大小将是微不足道的,但索引效果将是相同的

    在这种情况下,您将获得 20 个索引,其大小与原始索引的大小相同。

    事实上,这种技术有时用于所谓的分区索引。它有它的优点和缺点。

    【讨论】:

    • 在 Oracle 中,创建索引时使用 COMPRESS 选项可以减少索引中表示的相同索引值的多个副本的需要。但是,您仍然需要所有的 rowid。
    • 我的观点是,如果我将表划分为 20 个表,那么列中就不需要任何索引,因为我知道列的每一行都具有相同的值。
    • 如果你分区成 20 个表,你甚至不需要列
    【解决方案6】:

    标准 b-tree 索引最适合具有选择性的索引,而本示例并非如此。你没有说你正在使用什么 DBMS; Oracle 有另一种类型的索引,称为位图索引,它更适合 OLAP 环境中的低选择性索引(因为这些索引维护成本高,不适合 OLTP 环境)。

    优化器将根据统计数据决定是否认为索引有助于在最快的时间内获取数据;如果没有,优化器将不会使用它。

    分区是另一种策略。在 Oracle 中,您可以将表定义为在一组列上进行分区,并且优化器可以按照您的建议自动执行“分区消除”。

    【讨论】:

    • 仅供参考:在 MSSQL 2005 及更高版本中也可以基于列的内容进行表分区(在文件上传播数据)
    【解决方案7】:

    抱歉,我不太清楚你所说的“大”是什么意思。

    • 如果您的索引是聚集索引,则每条记录的所有数据都将位于同一叶页上,因此只要您正确编写查询,就可以为您的表创建最有效的索引。

    • 如果您的索引是非集群的,那么只有与索引相关的数据会出现在您的叶页上。然后,根据你有多少其他索引,再加上填充因子等细节,你的索引可能有效,也可能无效。一般来说,如果你的表上没有大量索引,你应该是安全的。

    • 索引的效率还取决于您所说的进入列的 20 个值的数据类型。如果这些是预定义的值,那么它们的详细信息可能应该在具有简单主键数据类型(如 Int/Number)的查找表中。然后将该列作为外键添加到您的表中,并在该列上添加索引。

    最终,您可以在列上拥有一个完美的索引。但它的最佳用途将在很大程度上取决于您编写的查询。因此,如果您的查询使用了索引,那么您就是黄金。

    【讨论】:

    • 该表有 6 亿行。大约有 5 列,除了其中一列用于选择过滤,一列是数据列。但是,为了这个问题,我们可以说有 3 列。 Col1、Col2、Col3。假设 Col1 是 PK,col2 有 20 个可能的值,而 col3 是
    • 数据列。在我看来,如果 Col2 上的索引很大,那就有问题了 - 因为我可以通过划分为 20 个表来滚动我自己的索引,每个 Col2 值 1 个。
    • 在 600M 行时,我希望您谈论的是 OLAP 表,而不是 OLTP 表。有很多行需要管理!现在,您将进入严肃的仓库数据库架构理论,该理论必须考虑数据库的许多其他因素。我很想听听你的最终决定。
    【解决方案8】:

    索引纯粹是为了性能。如果索引不能提高您感兴趣的查询的性能,那么它就很糟糕。

    至于磁盘使用情况,您必须权衡您的顾虑。不同的 SQL 提供程序构建索引的方式不同,但作为客户端,您通常相信他们会尽力而为。在您所描述的情况下,聚集索引可能在大小和性能方面都是最佳的。

    【讨论】:

    • " 如果索引不能提高您感兴趣的查询的性能,那么它很糟糕。"我不敢苟同。我同意,如果索引没有任何用途,那只是额外的开销。但目的可能比您当前正在检查的一个或多个查询要广泛得多。
    • 你说得对……我有点夸大了。发布后我想,它可能是为未来的数据场景而设计的。
    【解决方案9】:

    它足够大,可以按排序顺序保存所有行的这些值。

    假设您有 20 个不同的 4 个字符的字符串和 100 万行,那么保存这些值至少需要 400 万字节(如果 16 位 unicode 则为 8 个字节)。

    【讨论】:

    • 嗯,不一定。例如,如果页面上的所有行都具有相同的列值,则智能索引引擎可能会通过记录该事实来使用更少的空间。恕我直言,当然,我很容易错...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-09
    • 1970-01-01
    • 2013-07-11
    • 1970-01-01
    • 2015-10-11
    相关资源
    最近更新 更多