【问题标题】:SQL Server table optimal indexingSQL Server 表优化索引
【发布时间】:2017-02-26 02:34:02
【问题描述】:

我有一个非常具体的问题,这是工作面试测试的一部分。

我有这张桌子:

CREATE TABLE Teszt
(
    Id              INT NOT NULL
   , Name           NVARCHAR(100)
   , [Description]  NVARCHAR(MAX)
   , Value          DECIMAL(20,4)
   , IsEnabled      BIT
)

这些选择:

SELECT Name 
FROM Teszt 
WHERE Id = 10

SELECT Id, Value 
FROM Teszt 
WHERE IsEnabled = 1

SELECT [Description] 
FROM Teszt 
WHERE Name LIKE '%alma%'

SELECT [Description] 
FROM Teszt 
WHERE Value > 1000 AND IsEnabled = 1

SELECT Id, Name 
FROM Teszt 
WHERE IsEnabled = 1

问题是,我应该在这张表的哪个位置放置索引以优化上述查询的性能。没有提供有关该表的其他信息,因此我的答案将包含索引的一般赞成/反对论点,但我不确定上述查询。

我对使用索引优化这些特定查询的想法:

Id 应该有一个索引,看起来像主键,它是 where 子句的一部分;

在 Value 列上创建一个也很好,作为这里 where 子句的一部分;

现在对我来说变得模糊了。对于 Name 列,仅基于上述查询,我​​可能不应该创建一个,因为它与 LIKE 一起使用,这违背了索引的目的,对吗?

我试图阅读有关索引位列(表中的 isEnabled 列)的所有内容,但我不能说这对我来说更清楚,因为参数范围很广。我应该在上面创建一个索引吗?应该过滤吗?它应该是单独索引的一部分,还是只是其他列的一部分?

同样,这都是理论上的,所以没有关于表格大小或使用情况的信息。

提前感谢您的任何回答!

问候, 汤姆

【问题讨论】:

  • 除了Idnullable之外的所有列吗?
  • 我猜是的 :)

标签: sql sql-server indexing


【解决方案1】:

通常不建议在位列上建立索引。以下讨论不仅适用于位列,还适用于任何低基数值。在英语中,“low-cardinality”表示该列仅采用少数几个值。

原因很简单。位列具有三个值(如果包含 NULL)。这意味着列上的典型选择将返回大约三分之一的行。三分之一的行意味着您将(通常)访问每个数据页。如果是这样,您不妨进行全表扫描。

那么,让我们明确地问一个问题:位索引上的索引什么时候有用或合适?

首先,如果您一直在寻找IsEnabled = 1,并且例如启用了 0.001% 的行,则上述参数不起作用。这是一个高度选择性的查询,索引可能会有所帮助。注意:在这种情况下,索引对IsEnabled = 0 没有帮助。

其次,上述论点支持位值上的聚集索引。如果这些值是聚集的,那么即使是 30% 的选择性也意味着您只读取了 30% 的行。缺点是更新值意味着将记录从一个数据页移动到另一个数据页(有点昂贵的操作)。

第三,位列可以建设性地成为更大索引的一部分。对于位在前的聚集索引尤其如此。例如,对于第四个查询,有人可能会争辩说(IsEnabled, Value, Description) 上的聚集索引将是最佳索引。

但老实说,我不喜欢玩弄聚集索引。我更喜欢主键是聚集索引。我承认,对于一组狭窄的查询,性能提升可能令人印象深刻——如果这是您的用例,那么请使用它们(访问启用的行可能是使用它们的一个很好的理由)。但是,聚集索引只能使用一次,而主键是优化joins 的最佳通用选项。

【讨论】:

  • 非常感谢戈登!
  • 注意:不能使用(max) 长度列创建聚集索引。
  • 再次感谢戈登!只是一些后续问题。在具有 1 值的行中,索引值的百分比是多少?你提到了 0.001%,但这对我来说似乎是一个极端。您能否详细说明此处关于访问数据页的查询优化器行为?我可以说它不会执行全表扫描的行的百分比是多少?对不起,如果我的问题很天真,我以前从来没有挖过这么低的。另外,你同意我在原帖中的其他意见吗?再次感谢!
  • @TamásPásztor 。 . .如果您想了解索引,请阅读有关添加索引的不同数据库(例如 MySQL、SQL Server 和 Postgres)的文档。它们在索引中的工作方式非常相似。然后,在不同的列和查询上使用不同的索引。如果您没有一组数据,使用 SQL 和 Excel 进行数据分析的配套页面有适合此类调查的数据。
【解决方案2】:

您可以从这篇文章中阅读有关如何创建索引的详细信息:https://msdn.microsoft.com/en-us/library/ms188783.aspx

正如你所说,使用索引有利有弊。

优点:选择查询会更快
缺点:插入查询会更慢

结论:如果您的表有较少的INSERT AND 大多数SELECT 操作,则添加索引。

In which Column I should consider adding index?这真是一个非常好的问题。虽然我不是数据库专家,但以下是我的观点:

  1. 在主键列上添加索引
  2. 在连接列 [inner/outer/left] 上添加索引

【讨论】:

    【解决方案3】:

    简答:IdIsEnabled (尽管在BIT 字段上的索引存在争议;并且Id 应该是主键)

    一般来说,为了优化性能,索引应该放在有WHEREJOIN的字段上。 (在后台)为了进行选择,数据库服务器会查找索引,如果没有找到,则会在内存中即时创建一个,这需要时间,因此会降低性能。

    正如 Bhuwan 所说,INSERTs 的索引是“坏的”(在设计数据库时请牢记这一点),但在示例中只有 SELECTs 是私有的。

    希望你通过了测试:)

    -尼克

    【讨论】:

      【解决方案4】:

      tldr:我可能稍后会删除它,所以不需要!


      我对这个求职面试问题的回答:“视情况而定。” ...然后我可能会在面试中花太多时间谈论这个问题有多糟糕。

      问题在于,对于“工作面试测试”来说,这只是一个糟糕的问题。我已经在这个问题上戳了两个小时,我花的时间越长,我就越生气。

      1. 在绝对没有关于表格内容的信息的情况下,我们不能保证这个表格甚至是第一范式或更好,所以我们甚至不能假设唯一不可为空的列 Id 是有效的主键。

      2. 不知道表的内容,我们甚至不知道它是否需要索引。如果它只有几行,那么整个页面将位于内存中,并且您对其运行的任何操作都将足够快。

      3. 没有基数信息,我们不知道value > 1000 是常见的还是不常见的。所有值都可能大于 1000,也可能都不大于 1000,但我们不知道。

      4. 在没有基数信息的情况下,我们不知道IsEnabled = 1 是否意味着 99% 的行,甚至 0% 的行。

      我会说,就评估索引的思考过程而言,您的思路是正确的,但诀窍在于,您是从使用该表之前的表所需的索引的经验中汲取经验的。根据以往的一般经验应用假设是可以的,但您应该始终对其进行测试。在这种情况下,盲目地应用一般做法可能是错误的。


      问题是,我应该在这张表的哪个位置放置索引以优化上述查询的性能。没有提供关于桌子的其他信息

      如果我尝试从另一个角度解决这个问题:除了这五个查询的性能之外,没有其他问题,我会应用这些索引:

      create index ixf_Name on dbo.Teszt(Name)
      include (Id)
      where id = 10;
      
      create index ixf_Value_Enabled on dbo.Teszt(Value) 
      include (Id)
      where IsEnabled = 1;
      
      create index ixf_Value_gt1k_Enabled on  dbo.Teszt(Id)
      include (description,value,IsEnabled)
      where Value > 1000 and IsEnabled = 1;
      
      create index ixf_Name_Enabled on dbo.Teszt(Id)
      include (Name, IsEnabled)
      where IsEnabled = 1;
      
      create index ixf_Name_notNull on dbo.Teszt(Name)
      include (Description)
      where Name is not null;
      


      另外,decimal(20,4) 让我很烦,因为这是您可以在它占用的 13 个字节空间中存储的最少数据量。 decimal(28,4) 具有相同的存储大小,如果它可以是 decimal(19,4),那么它将只有 9 个字节。诚然,这是一件让人恼火的傻事,尤其是考虑到桌子无论如何都会很宽,但我想我还是会指出这一点。

      【讨论】:

        猜你喜欢
        • 2011-01-18
        • 2019-05-26
        • 2014-01-09
        • 1970-01-01
        • 2016-10-12
        • 1970-01-01
        • 1970-01-01
        • 2017-04-16
        • 1970-01-01
        相关资源
        最近更新 更多