如何确定必须在数据库表中索引哪些字段

时间:2016-05-12 05:31:40

标签: mysql sql database indexing

说明

我有一张没有主键的表(或者甚至没有复合键)。

该表用于存储食品店的时段(营业时间和可用时间的食物供应时间)。我们将表格称为“business_hours”,主要字段如下所示。

  • shop_id
  • day(0 - 6,表示周日至周六)
  • 类型(开放,交付)
  • START_TIME
  • END_TIME

例如,如果商店A在周一上午9点​​至下午1点和下午5点至晚上10点开放,则此场景的business_hours表中将有两条记录。

-----------------------------------------------
| shop_id | day | type | start_time | end_time
-----------------------------------------------
| 1000    | 1   | open | 09:00:00   | 13:00:00
-----------------------------------------------
| 1000    | 1   | open | 17:00:00   | 22:00:00
-----------------------------------------------

当我查询这个表时,我将始终将shop_id用作where子句中的第一个条件。

前:

SELECT COUNT(*) FROM business_hours WHERE shop_id = 1000 AND day = 1 AND type = 'open' AND start_time <= '13.29.00' AND end_time > '13.29.00';

问题

为“shop_id”应用索引是足够的或“日”&amp; “type”字段也应编入索引?

如果你能解释索引的确如何运作,也会更好。

5 个答案:

答案 0 :(得分:1)

是的,您要在此列上创建聚簇索引(shop_id,day,type)。我创建了一个如上所述的索引:

Create clustered index Ix on business_hours (shop_id,day,type)

使用此索引,您的选择查询如上所述:

SELECT COUNT(*) FROM business_hours with (index (Ix)) WHERE shop_id = 1000 AND day = 1 AND type = 'open' AND start_time <= '13.29.00' AND end_time > '13.29.00';

你得到的结果很快,但是有一个主键而不是创建的表 聚集索引并创建非聚集索引

答案 1 :(得分:1)

如果您不更新记录然后使用聚集索引,则取决于您的可用性 在

<div class="popup">
        <h2>Here i am</h2>
        <a class="close" href="#">×</a>
</div>

因为聚簇索引沿着B树遍历并将整行存储在节点本身上,所以搜索速度很快。但是更新记录是内存成本有效的,因为它将整行从内存中移出,为同一记录创建新条目。

OR ELSE

如果您正在更新记录,那么非聚集索引。

如果您创建仓库,则使用列存储索引

为了更好地理解你可以转到这些链接

http://kodeweave.sourceforge.net/editor/#8d7733f82faf240e0edcb6739c5d1a1a

http://www.programmerinterview.com/index.php/database-sql/clustered-vs-non-clustered-index/

http://www.patrickkeisler.com/2014/04/what-is-non-clustered-columnstore-index.html

请回复。

答案 2 :(得分:1)

这取决于您应指定的几个因素:

  1. 数据增长的速度
  2. 行中估计的表格大小是多少
  3. 将针对该表运行哪些查询
  4. 您希望查询运行的速度有多快
  5. 更多的是思考:一些服务每小时会有数千个新记录插入,旧记录将每晚存档,并且每晚都会从该表创建报告。在这种情况下,您可能不希望创建多个索引,因为它们会降低插入速度。

    另一方面,如果您的表会增长并且变化缓慢并且许多用户将针对它运行查询,则需要使用适当的索引来加速查询。

    如果可以,请尝试创建大多数查询可以从中受益的群集唯一主键。如果您拥有构成某个时间轴的数据,并且大多数查询将使用日期时间条件(例如from - to)获取数据范围,则最好在聚簇索引中包含datetime - 您将获得最快的查询性能。

    所以这样的事情会为你提到的选择给你最好的表现。 (但您不能为一个商店存储重复的营业时间并输入)

    CREATE TABLE Business_hours
    ( shop_id INT NOT NULL 
    , day INT NOT NULL
    --- other columns
    , CONSTRAINT Business_hours_PK
        PRIMARY KEY (shop_id, day, type, start_time, end_time)     -- your clustered index
    ) 
    

    只需在SELECT中使用的字段(所有字段或其中一些最常用的字段)创建索引,也会加快查询速度:

    CREATE INDEX BusinessHours_IX ON business_hours (shop_id,day,type, start_time, end_time);
    

    群集和非群集之间的区别在于群集索引会影响存储在磁盘上的db记录的顺序。

    您可以使用EXPLAIN在数据库中查找缺失的索引,请参阅this answer

    更多细节this blog

答案 3 :(得分:1)

决定反对主键意味着允许以下内容:

| shop_id | day | type   | start_time | end_time
+---------+-----+--------+------------+---------
| 1000    | 1   | open   | 09:00:00   | 13:00:00
| 1000    | 1   | open   | 09:00:00   | 13:00:00
| 1000    | 1   | open   | 17:00:00   | 22:00:00
| 1000    | 1   | closed | 17:00:00   | 22:00:00

因此,您可以拥有可能导致奇怪查询结果的重复条目,甚至可以在同一时间范围内关闭商店。 (但是,我们都知道,即​​使使用主键,您仍然需要一个插入前触发器来检测范围重叠,例如12:00-15:00与13:00- 16:00,并抛出一个错误。 - 我希望有一些内置的范围检测,所以我们可以说,(shop_id, day, range(start_time, end_time))上有一个唯一的索引。)

关于您的问题:如果您的数据库构建良好,则您已在shop_id上拥有外键。只要您足够快地考虑查询,就不需要任何其他索引。

一旦您认为需要加快速度,就可以根据需要添加复合索引。这通常是慢查询的WHERE子句中所有列的索引。如果仍然不够,请添加GROUP BY子句中的列(如果有)。下一步是添加HAVING子句的列,如果有的话。接下来是ORDER BY子句的列。最后一步是在SELECT子句中添加所有列,这将为您提供覆盖索引,即查询所需的所有数据都将在索引中,因此表本身不必是再访问​​了。

但如上所述:只要您没有性能问题,就不必添加任何复合索引。

答案 4 :(得分:1)

要确定必须在数据库表中索引哪些字段,您需要观察每个查询的行为,发送到表索引是在应用程序和数据之间提供有效访问路径的方法。索引提供了访问路径,因此查询要求数据到数据库,它将知道去哪里检索数据。

这里有一些官方的Microsoft文档

群集索引 聚簇索引将实际表数据页存储在叶级,并且表数据在密钥周围进行物理排序。  一个表只能有一个聚簇索引,并且在创建此索引时,还会发生以下事件: •表格数据重新排列。 •创建新索引页面。 •重建数据库中的所有非聚簇索引。 因此,有许多磁盘I / O操作以及系统和内存资源的广泛使用。如果计划创建聚簇索引,请确保可用空间至少等于表中数据量的1.5倍。额外的可用空间确保您有足够的空间来有效地完成操作。

非聚集索引 在非聚簇索引中,叶级别的页面包含一个书签,该书签告诉SQL Server在哪里可以找到与索引中的键对应的数据行。如果表具有聚簇索引,则书签指示聚簇索引键。如果表没有聚簇索引,则书签是实际的行定位器。 创建非聚簇索引时,SQL Server会创建所需的索引页,但不会重新排列表数据。

专业人士推荐的索引方法由三个阶段组成:监控,分析,然后实现索引。这意味着您需要在运行查询时观察数据库的行为,然后努力获得最佳性能

SQL Server使用此操作来获取数据:

表扫描:读取整个堆,并且很可能将所有数据传递给辅助过滤器操作

索引扫描:读取聚簇索引或非聚簇索引的整个叶级(每一行)。索引扫描操作可能会过滤行并仅返回符合条件的行,或者它可能会将所有行传递给另一个过滤操作,具体取决于条件的复杂程度。可能会或可能不会订购数据。

索引寻求: 使用索引查找特定的行数据,并仅返回有序列表中的选定行

一旦您知道可以运行查询并使用“显示估计执行计划”选项https://msdn.microsoft.com/en-us/library/ms191194.aspx并分析性能 我建议阅读这篇文章  “SQL SERVER - 索引寻求比。索引扫描“   http://blog.sqlauthority.com/2007/03/30/sql-server-index-seek-vs-index-scan-table-scan/https://msdn.microsoft.com/en-us/library/dn673537.aspx