联合索引和覆盖索引有很大的区别:
覆盖索引是查询的列可以直接通过索引提取,比如只查询主键的列!或者查询联合索引的所有列或者左边开始的部分列(注意有顺序的)!
而联合索引并不一定只从索引中能获取到所有的数据,这个取决于你所查询的列。比如select from table where ××××××;的方式就不太可能是覆盖索引。因此如果你查询的列能用到联合索引,且你查询的列都能通过联合索引获取,比如你只查询联合索引所在的列或者左边开始的部分列,这就相当于覆盖索引了。通常为了让查询能用到覆盖索引,就将要查询的多列数据设置成联合索引。
一个通常的建议是为WHERE条件创建索引,但这其实是片面的。索引应当为全部查询设计,而不仅仅是WHERE条件。索引确实能有效地查找数据行,但MySQL也能够使用索引获取列数据,这样根本不需要去读取一行数据。毕竟,索引的叶子节点包含了索引对应的值。当年能够读取索引就能够拿到想要的数据时为什么还去读数据行呢?当索引包含了所有查询的数据时,这个索引就称之为 覆盖索引 。
覆盖索引能够成为一个非常有力的工具并且能够显著改善性能。考虑一下不读数据只需要读取索引的情况:
在所有的场景中,最典型的就是相比查找数据行,只包含索引列的查询的代价相当低。需要注意的是,聚集索引并不是任意类型的索引。聚集索引必须存储索引数据列对应的值。哈希,空间和全文索引并没有存储这些值,因此MySQL只能使用二叉树去覆盖查询。而且,不同的存储引擎实现覆盖索引的方式不同,并且并不是全部的存储引擎都支持覆盖索引(例如Memory存储引擎当前就不支持)。
当你验证查询中索引使用了覆盖索引时,使用Explain语句时,会在Extra列中看到“Using index”。例如,在store_goods表有一个(shop_id, goods_category_id1)的多列索引。MySQL可以在查询返回数据只有这两列时使用索引:
覆盖索引查询有些细节能够停用这样的优化。MySQL查询优化器在执行查询时会判断索引是否覆盖到。假设索引覆盖了WHERE条件,但没有覆盖整个查询。如果评估结果不走覆盖索引,那么MySQL 55及以前的版本会直接获取数据行,即便是不需要这些数据,然后才会过滤掉。
让我们看一下为什么这种情况会发生,然后如何重写查询以便解决这个问题。首先查询是这样的:
这个时候的结果是不会走覆盖索引,而是普通的索引,这是因为:
有一种方式可以使用巧妙的组合索引和重写查询条件。我们可以将索引扩展到(artist, title, prod_id),然后像下面那样重写查询语句:
我们称之为“递延JOIN(deferred join)”,因为它延迟了列的访问。在第一阶段的查询中,当它在子查询中找到了匹配的行的过程中,MySQL使用了覆盖索引。虽然在整个查询中没有覆盖到,但总比没有的好。
这种优化的效果好坏取决于WHERE条件查找到了多少行数据。假设products表包含了上百万行的数据。可以对比一下这两种查询的性能对比,总的数据为100万行。
对比结果如下表。
结果的解释如下:
在大多数存储引擎中,一个索引只能够覆盖访问列是索引的一部分。然而,InnoDB实际上会做进一步的优化。想想InnoDB的的辅助索引在叶子节点中存储了主键的值。这意味着InnoDB的辅助索引实际上有了额外的列帮助InnoDB使用覆盖索引。
例如,sakilaactor表使用了InnoDB,然后在last_name有一个索引,因此这个索引能够覆盖或者主键actor_id的查询——即便这个列并不是索引的一部分。
没有区别,覆盖索引只是特定于具体select语录而言的联合索引。也就是说一个联合索引对于某个select语句,通过索引可以直接获取查询结果,而不再需要回表查询啦,就称该联合索引覆盖了这条select语句。
你的意思是通过建立足够多的索引,而不必去读行数据吗? 那就要把你的查询where 的每一个字段都要添加一个索引,是单独的字段,不要组合的字段索引。
组合索引是两个及以上的字段组合到一起,这样的话,只有where 前两个判断都到用到这个组合字段才有用,其他情况是用不到索引的。比如索引 a,b 只有where a=xx and b=xx的时候有用。
你的意思可能就是 where a=xx AND b=xx AND c=XX, 那么,要把这三个字段都要添加索引才行
索引也是需要空间的,建议最常用的查询字段建立索引就行了
引入一个面试问题:
看完以下以后再回顾,会发现迎刃而解
Mysql 可以为每一张表设置 存储引擎 这里我们只说 InnoDB 存储引擎
由于实际情况,数据页只能按照一棵 B+树 进行排序, 因此每张表只能拥有一个 聚集索引(即 主键)。
栗子:
每个叶子节点的索引行中包含了一个书签(bookmark) 该书签是用来告诉 InnoDB存储引擎哪里可以找到该索引对应的数据行或者说 行数据! 由于InnoDB存储引擎表, 是按照主键来构建的, 所以 ,该书签内其实包含或者说指向了 数据行所对应的聚集索引键
也就是说 辅助索引的 叶结点保存了 指向对应数据的 聚集索引, 可以通过该聚集索引 找到对应的数据行
辅助索引的存在并不影响数据在聚集索引中的组织,因为每张表上可以有多个辅助索引。
当通过辅助索引来寻找数据时,InnoDB 存储引擎会遍历辅助索引并通过叶级别的指针获得指向主键索引(聚集索引)的主键,然后再通过聚集索引找到一个完整的数据行。
例如:
聚集索引辅助索引关系:
: 又叫做组合索引 , 辅助索引的一种 , 和普通创建索引的方式一样,不同的是 可以同时添加多列来作为索引项;
从本质上来说,联合索引也是一课B+树
个人理解: 所谓最左原则, 是因为 存储引擎构建组合索引时 是根据最左边的那一列索引项进行排序的 ,所以使用组合索引,必须满足 条件中必须存在 最左边那一列的索引项,这样 才可以找到对应的索引,继而 去寻找对应的数据
: 又叫做 索引覆盖,InnoDB中支持覆盖索引,即 从辅助索引中就可以得到查询的记录,而不需要查询聚集索引中的记录。
比如 这里没有根据最左原则使用组合索引,但是 优化器依然进行选择
共勉,欢迎指导谢谢~
第二次回答:
问题补充:能不能具体点,新建一个索引就可以了吗
基本上可以这么说,不过你也可以修改索引。
记住:
索引其实关键目的是为了加快检索速度而建立的,所以,怎么用索引是数据库系统本身的事情,作为数据库设计或使用者,设计并创建好索引然后体验加上索引后的查询变快的感觉就行了。所以,索引怎么用就变为了“怎么创建合适的索引”
以下回答是否符合你的要求?你还有什么问题?
第一次回答:
一、索引是什么
索引是与表或视图关联的磁盘上结构,可以加快从表或视图中检索行的速度。索引包含由表或视图中的一列或多列生成的键。这些键存储在一个结构(B 树)中,使 SQL Server 可以快速有效地查找与键值关联的行。
表或视图可以包含以下类型的索引:
聚集
o 聚集索引根据数据行的键值在表或视图中排序和存储这些数据行。索引定义中包含聚集索引列。每个表只能有一个聚集索引,因为数据行本身只能按一个顺序排序。
o 只有当表包含聚集索引时,表中的数据行才按排序顺序存储。如果表具有聚集索引,则该表称为聚集表。如果表没有聚集索引,则其数据行存储在一个称为堆的无序结构中。
非聚集
o 非聚集索引具有独立于数据行的结构。非聚集索引包含非聚集索引键值,并且每个键值项都有指向包含该键值的数据行的指针。
o 从非聚集索引中的索引行指向数据行的指针称为行定位器。行定位器的结构取决于数据页是存储在堆中还是聚集表中。对于堆,行定位器是指向行的指针。对于聚集表,行定位器是聚集索引键。
o 您可以向非聚集索引的叶级添加非键列以跳过现有的索引键限制(900 字节和 16 键列),并执行完整范围内的索引查询。
聚集索引和非聚集索引都可以是唯一的。这意味着任何两行都不能有相同的索引键值。另外,索引也可以不是唯一的,即多行可以共享同一键值。
每当修改了表数据后,都会自动维护表或视图的索引。
索引和约束
对表列定义了 PRIMARY KEY 约束和 UNIQUE 约束时,会自动创建索引。例如,如果创建了表并将一个特定列标识为主键,则 数据库引擎自动对该列创建 PRIMARY KEY 约束和索引。有关详细信息,请参阅创建索引(数据库引擎)。
二、索引有什么用
与书中的索引一样,数据库中的索引使您可以快速找到表或索引视图中的特定信息。索引包含从表或视图中一个或多个列生成的键,以及映射到指定数据的存储位置的指针。通过创建设计良好的索引以支持查询,可以显著提高数据库查询和应用程序的性能。索引可以减少为返回查询结果集而必须读取的数据量。索引还可以强制表中的行具有唯一性,从而确保表数据的数据完整性。
设计良好的索引可以减少磁盘 I/O *** 作,并且消耗的系统资源也较少,从而可以提高查询性能。对于包含 SELECT、UPDATE、DELETE 或 MERGE 语句的各种查询,索引会很有用。例如,在 AdventureWorks 数据库中执行的查询 SELECT Title, HireDate FROM HumanResourcesEmployee WHERE EmployeeID = 250。执行此查询时,查询优化器评估可用于检索数据的每个方法,然后选择最有效的方法。可能采用的方法包括扫描表和扫描一个或多个索引(如果有)。
扫描表时,查询优化器读取表中的所有行,并提取满足查询条件的行。扫描表会有许多磁盘 I/O *** 作,并占用大量资源。但是,如果查询的结果集是占表中较高百分比的行,扫描表会是最为有效的方法。
查询优化器使用索引时,搜索索引键列,查找到查询所需行的存储位置,然后从该位置提取匹配行。通常,搜索索引比搜索表要快很多,因为索引与表不同,一般每行包含的列非常少,且行遵循排序顺序。
查询优化器在执行查询时通常会选择最有效的方法。但如果没有索引,则查询优化器必须扫描表。您的任务是设计并创建最适合您的环境的索引,以便查询优化器可以从多个有效的索引中选择。SQL Server 提供的数据库引擎优化顾问可以帮助分析数据库环境并选择适当的索引。
三、索引怎么用
索引其实关键目的是为了加快检索速度而建立的,所以,怎么用索引是数据库系统本身的事情,作为数据库设计或使用者,设计并创建好索引然后体验加上索引后的查询变快的感觉就行了。所以,索引怎么用就变为了“怎么创建合适的索引”,以下说明这个问题:
索引设计不佳和缺少索引是提高数据库和应用程序性能的主要障碍。设计高效的索引对于获得良好的数据库和应用程序性能极为重要。为数据库及其工作负荷选择正确的索引是一项需要在查询速度与更新所需开销之间取得平衡的复杂任务。如果索引较窄,或者说索引关键字中只有很少的几列,则需要的磁盘空间和维护开销都较少。而另一方面,宽索引可覆盖更多的查询。您可能需要试验若干不同的设计,才能找到最有效的索引。可以添加、修改和删除索引而不影响数据库架构或应用程序设计。因此,应试验多个不同的索引而无需犹豫。
SQL Server 中的查询优化器可在大多数情况下可靠地选择最高效的索引。总体索引设计策略应为查询优化器提供可供选择的多个索引,并依赖查询优化器做出正确的决定。这在多种情况下可减少分析时间并获得良好的性能。若要查看查询优化器对特定查询使用的索引,请在 SQL Server Management Studio 中的“查询”菜单上选择“包括实际的执行计划”。
不要总是将索引的使用等同于良好的性能,或者将良好的性能等同于索引的高效使用。如果只要使用索引就能获得最佳性能,那查询优化器的工作就简单了。但事实上,不正确的索引选择并不能获得最佳性能。因此,查询优化器的任务是只在索引或索引组合能提高性能时才选择它,而在索引检索有碍性能时则避免使用它。
建议的索引设计策略包括以下任务:
1 了解数据库本身的特征。例如,它是频繁修改数据的联机事务处理 (OLTP) 数据库,还是主要包含只读数据的决策支持系统 (DSS) 或数据仓库 (OLAP) 数据库?
2 了解最常用的查询的特征。例如,了解到最常用的查询联接两个或多个表将有助于决定要使用的最佳索引类型。
3 了解查询中使用的列的特征。例如,某个索引对于含有整数数据类型同时还是唯一的或非空的列是理想索引。筛选索引适用于具有定义完善的数据子集的列。
4 确定哪些索引选项可在创建或维护索引时提高性能。例如,对现有某个大型表创建聚集索引将会受益于 ONLINE 索引选项。ONLINE 选项允许在创建索引或重新生成索引时继续对基础数据执行并发活动。
5 确定索引的最佳存储位置。非聚集索引可以与基础表存储在同一个文件组中,也可以存储在不同的文件组中。索引的存储位置可通过提高磁盘 I/O 性能来提高查询性能。例如,将非聚集索引存储在表文件组所在磁盘以外的某个磁盘上的一个文件组中可以提高性能,因为可以同时读取多个磁盘。
或者,聚集索引和非聚集索引也可以使用跨越多个文件组的分区方案。在维护整个集合的完整性时,使用分区可以快速而有效地访问或管理数据子集,从而使大型表或索引更易于管理。有关详细信息,请参阅已分区表和已分区索引。在考虑分区时,应确定是否应对齐索引,即,是按实质上与表相同的方式进行分区,还是单独分区。
# 设计索引。
索引设计是一项关键任务。索引设计包括确定要使用的列,选择索引类型(例如聚集或非聚集),选择适当的索引选项,以及确定文件组或分区方案布置。
# 确定最佳的创建方法。按照以下方法创建索引:
使用 CREATE TABLE 或 ALTER TABLE 对列定义 PRIMARY KEY 或 UNIQUE 约束
SQL Server 数据库引擎自动创建唯一索引来强制 PRIMARY KEY 或 UNIQUE 约束的唯一性要求。默认情况下,创建的唯一聚集索引可以强制 PRIMARY KEY 约束,除非表中已存在聚集索引或指定了唯一的非聚集索引。默认情况下,创建的唯一非聚集索引可以强制 UNIQUE 约束,除非已明确指定唯一的聚集索引且表中不存在聚集索引。
还可以指定索引选项和索引位置、文件组或分区方案。
创建为 PRIMARY KEY 或 UNIQUE 约束的一部分的索引将自动给定与约束名称相同的名称。
使用 CREATE INDEX 语句或 SQL Server Management Studio 对象资源管理器中的“新建索引”对话框创建独立于约束的索引
必须指定索引的名称、表以及应用该索引的列。还可以指定索引选项和索引位置、文件组或分区方案。默认情况下,如果未指定聚集或唯一选项,将创建非聚集的非唯一索引。若要创建筛选索引,请使用可选的 WHERE 子句。
# 创建索引。
要考虑的一个重要因素是对空表还是对包含数据的表创建索引。对空表创建索引在创建索引时不会对性能产生任何影响,而向表中添加数据时,会对性能产生影响。
对大型表创建索引时应仔细计划,这样才不会影响数据库性能。对大型表创建索引的首选方法是先创建聚集索引,然后创建任何非聚集索引。在对现有表创建索引时,请考虑将 ONLINE 选项设置为 ON。该选项设置为 ON 时,将不持有长期表锁以继续对基础表的查询或更新。
简单的创建索引,可采用如下语句:
CREATE INDEX IX_ProductVendor_VendorID
ON PurchasingProductVendor (VendorID, VendorName);
GO
在 Web 应用程序中跨大型数据集分页记录似乎是一个简单的问题,但实际上很难扩展。两种主要的分页策略是偏移/限制和游标。
我们将首先看一下这两种方法,然后稍作修改,可以使偏移/限制非常高效。
偏移/限制分页
偏移/限制方法是迄今为止最常见的方法,它通过跳过一定数量的记录(页)并将结果限制为一页来工作。
例如,假设您的应用程序配置为每页显示 15 条记录。您的 SQL 将如下所示:
这是最常见的,因为它非常简单,易于推理,并且几乎每个框架都支持它。
除了易于实现之外,它还具有页面可直接寻址的优点。例如,如果您想直接导航到第 20 页,您可以这样做,因为该偏移量很容易计算。
但是有一个主要的缺点,它潜伏在数据库处理偏移量的方式中。偏移量告诉数据库放弃从查询中返回的前N个结果。不过数据库仍然要从磁盘上获取这些行。
如果你丢弃的是100条记录,这并不重要,但如果你丢弃的是100,000条记录,数据库就会为了丢弃这些结果而做大量的工作。
在实践中,这意味着第一个页面会快速加载,之后的每一个页面都会变得越来越慢,直到你达到一个点,网络请求可能会直接超时。
基于游标的分页
基于游标的分页弥补了偏移/限制的一些不足,同时引入了一些自己的不足。
基于游标的分页是通过存储一些关于最后呈现给用户的记录的状态,然后根据这个状态来进行下一次查询。
因此,它不是按顺序获取所有的记录并丢弃前N条,而是只获取最后一个位置N之后的记录。
如果按ID排序,SQL可能看起来像这样。
你可能已经看到了其中的好处。因为我们知道上次向用户展示的ID,我们知道下一个页面将以一个更高的ID开始。我们甚至不需要检查ID较低的行,因为我们百分之百肯定地知道那些行不需要被显示。
在上面的例子中,我特别说明了ID可能不是连续的,也就是说,可能有缺失的记录。这使得我们无法计算出哪些记录会出现在某一页面上,你必须跟踪之前那一页面上的最后一条记录是什么。
与偏移/限制分页不同,使用游标分页时,页面不能直接寻址,你只能导航到 "下一页 "或 "上一页"。
不过光标分页的好处是在任何数量的页面上都很迅速。它也很适合无限滚动,在这种情况下,页面首先不需要可以直接寻址。
Laravel文档中有一些关于偏移量和游标之间的权衡的好的背景。
>
通俗的讲就是,如果索引的列在 select 所需获得的列中(因为在 mysql 中索引是根据索引列的值进行排序的,所以索引节点中存在该列中的部分值)或者根据一次索引查询就能获得记录就不需要回表,如果 select 所需获得列中有大量的非索引列,索引就需要到表中找到相应的列的信息,这就叫回表。
InnoDB聚集索引的叶子节点存储行记录,因此, InnoDB必须要有,且只有一个聚集索引:
(1)如果表定义了主键,则PK就是聚集索引;
(2)如果表没有定义主键,则第一个非空唯一索引(not NULL unique)列是聚集索引;
(3)否则,InnoDB会创建一个隐藏的row-id作为聚集索引;
先创建一张表,sql 语句如下:
然后,我们再执行下面的 SQL 语句,插入几条测试数据。
假设,现在我们要查询出 id 为 2 的数据。那么执行 select from xttblog where ID = 2; 这条 SQL 语句就不需要回表。原因是根据主键的查询方式,则只需要搜索 ID 这棵 B+ 树。主键是唯一的,根据这个唯一的索引,MySQL 就能确定搜索的记录。
但当我们使用 k 这个索引来查询 k = 2 的记录时就要用到回表。select from xttblog where k = 2; 原因是通过 k 这个普通索引查询方式,则需要先搜索 k 索引树,然后得到主键 ID 的值为 1,再到 ID 索引树搜索一次。这个过程虽然用了索引,但实际上底层进行了两次索引查询,这个过程就称为回表。
也就是说,基于非主键索引的查询需要多扫描一棵索引树。因此,我们在应用中应该尽量使用主键查询。
我这里表里的数据量比较少,如果数据量大的话,你能很明显的看出两次查询所用的时间,很明显使用主键查询效率更高。
更多如下图:
(1)先通过普通索引定位到主键值id=5;
(2)在通过聚集索引定位到行记录;
这就是所谓的回表查询,先定位主键值,再定位行记录,它的性能较扫一遍索引树更低。
使用聚集索引(主键或第一个唯一索引)就不会回表,普通索引就会回表。
只需要在一棵索引树上就能获取SQL所需的所有列数据,无需回表,速度更快。
explain的输出结果Extra字段为Using index时,能够触发索引覆盖。
例子
第一个sql:
select id,name from user where name='shenjian';
Extra:Using index。
第二个sql:
select id,name,sex from user where name='shenjian';
能够命中name索引, 索引叶子节点存储了主键id,没有储存sex,sex字段必须回表查询才能获取到 ,不符合索引覆盖,需要再次通过id值扫描聚集索引获取sex字段,效率会降低。
Extra:Using index condition。
如果把(name)单列索引升级为联合索引(name, sex)就不同了。
可以看到:
select id,name where name='shenjian';
select id,name,sex where name='shenjian';
单列索升级为联合索引(name, sex)后,索引叶子节点存储了主键id,name,sex ,都能够命中索引覆盖,无需回表。
画外音,Extra:Using index。
场景1:全表count查询优化
原表为:
user(PK id, name, sex);
直接:
select count(name) from user;
不能利用索引覆盖。
添加索引:
alter table user add key(name);
就能够利用索引覆盖提效。
场景2:列查询回表优化
这个例子不再赘述,将单列索引(name)升级为联合索引(name, sex),即可避免回表。
场景3:分页查询
将单列索引(name)升级为联合索引(name, sex),也可以避免回表。
假设有这么个需求,查询表中“名字第一个字是张,性别男,年龄为10岁的所有记录”。那么,查询语句是这么写的:
根据前面说的“最左前缀原则”,该语句在搜索索引树的时候,只能匹配到名字第一个字是‘张’的记录(即记录ID3),接下来是怎么处理的呢?当然就是从ID3开始,逐个回表,到主键索引上找出相应的记录,再比对age和ismale这两个字段的值是否符合。
但是!MySQL 56引入了索引下推优化,可以在索引遍历过程中, 对索引中包含的字段先做判断,过滤掉不符合条件的记录,减少回表字数 。
下面图1、图2分别展示这两种情况。
图 1 中,在 (name,age) 索引里面我特意去掉了 age 的值, 这个过程 InnoDB 并不会去看 age 的值 ,只是按顺序把“name 第一个字是’张’”的记录一条条取出来回表。因此,需要回表 4 次。
图 2 跟图 1 的区别是,InnoDB 在 (name,age) 索引内部就判断了 age 是否等于 10,对于不等于 10 的记录,直接判断并跳过。在我们的这个例子中,只需要对 ID4、ID5 这两条记录回表取数据判断,就只需要回表 2 次。
如果没有索引下推优化(或称ICP优化),当进行索引查询时, 首先根据索引来查找记录,然后再根据where条件来过滤记录 ;在支持ICP优化后,MySQL会在取出索引的同时, 判断是否可以进行where条件过滤再进行索引查询 ,也就是说提前执行where的部分过滤 *** 作,在某些场景下,可以大大减少回表次数,从而提升整体性能。
以上就是关于mysql覆盖索引和联合索引的区别全部的内容,包括:mysql覆盖索引和联合索引的区别、高性能索引优化策略(五):覆盖索引性能很高,怎么回事、Mysql的覆盖索引和联合索引的区别在哪里等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)