SQL学习之索引(优化)

一、SQL优化背景

        在SQL中,很多时候不同的SQL代码能够得出相同结果。但是不同SQL代码执行起来的效率却大不相同,甚至差异巨大。

  1. SQL 索引(Index)用于提高数据表的查询速度。一个表可以创建多个索引,一个索引可以包含一个或者多个字段。不使用索引,数据库引擎将遍历整个表。
  2. 从本质上看,索引是根据表的一个或者多个字段生成的子表,该子表中的数据已经进行了排序。子表除了包含指定字段中的数据,还包含一个 rowid 列,用于存储当前记录在原始表中的位置。用户无法看到索引,它只是用来加快查询速度。
  3. 为了提高查询效率,便于后期维护,索引都是基于某种数据结构而创建的,比如 B+ 树、B- 树、位图等。

使用SQL索引也有一定的成本

        在表中插入、修改或者删除数据时,数据库引擎也必须维护索引,以保持索引和原始表的同步;也就是说,使用索引是有额外开销的。不适合的索引,或者过多的索引,都会降低插入、修改和删除数据的效率。 

        索引还会占用磁盘空间,增加 I/O 成本,过多的索引甚至会增加碎片。

 鉴于以上两点,使用索引时应该遵循以下几条原则:

  • 仅在被频繁检索的字段上创建索引。
  • 针对大数据量的表创建索引,而不是针对只有少量数据的表创建索引。
  • 通常来说,经常查询的记录数目少于表中总记录数据的 15% 时,可以创建索引。这个比例并不绝对,它与全表扫描速度成反比。
  • 尽量不要在有大量重复值得字段上建立索引,比如性别字段、季度字段等。

二、SQL写法优化

首先创建一个空表 

CREATE TABLE website (
    id      INT              NOT NULL  AUTO_INCREMENT,
    name    VARCHAR(20)      NOT NULL,
    url     VARCHAR(30),
    age     TINYINT UNSIGNED NOT NULL,
    alexa   INT UNSIGNED     NOT NULL,
    uv      FLOAT            DEFAULT '0',
    country CHAR(3)          NOT NULL,
    PRIMARY KEY (`id`)
)

给表中的某列字段添加索引

#添加索引
CREATE INDEX myIndex
ON website(name);
#删除索引
ALTER TABLE website
DROP INDEX myIndex;
#查看索引
SHOW INDEX FROM <表名> [ FROM <数据库名>]
  1. 子查询用EXIST代替IN

当IN的参数是子查询时,数据库首先会执行子查询,然后将结果存储在一张临时的工作表里(内联视图:内联视图是 SQL 查询中的一个概念,它允许您在查询中嵌套另一个查询作为一个临时的虚拟表),然后扫描整个视图。很多情况下这种做法都非常耗费资源。使用EXISTS的话,数据库不会生成临时的工作表。但是从代码的可读性上来看,IN要比EXISTS好。使用IN时的代码看起来更加一目了然,易于理解。因此,如果确信使用IN也能快速获取结果,就没有必要非得改成EXISTS了。

--慢
SELECT *
  FROM Class_A
 WHERE id IN (SELECT id
                FROM Class_B);

--快
SELECT *
  FROM Class_A  A
 WHERE EXISTS
        (SELECT *
          FROM Class_B  B
          WHERE A.id = B.id);

   2.   避免排序并添加索引

在SQL语言中,除了ORDER BY子句会进行显示排序外,还有很多语句默认也会在暗中进行排序,如果排序字段没有添加索引,会导致查询性能很慢。SQL中会进行排序的代表性的运算有下面这些。对这些语句添加索引会加快查询和排序。

  • GROUP BY子句
  • ORDER BY子句
  • 聚合函数(SUM、COUNT、AVG、MAX、MIN)
  • DISTINCT
  • 集合运算符(UNION、INTERSECT、EXCEPT)
  • 窗口函数(RANK、ROW_NUMBER等

3.集合运算优化

SQL中有UNION、INTERSECT、EXCEPT三个集合运算符。在默认的使用方式下,这些运算符会为了排除掉重复数据而进行排序。

  1. UNION 运算符用于将两个或多个 SELECT 语句的结果集合并成一个结果集,同时去除重复的行。

  2. INTERSECT 运算符用于获取两个 SELECT 语句的结果集的交集,即同时存在于两个结果集中的行。

  3. EXCEPT 运算符用于获取第一个 SELECT 语句的结果集中存在,但是在第二个 SELECT 语句的结果集中不存在的行。注意:和 UNION、INTERSECT 一样,EXCEPT 运算符也要求各个 SELECT 语句的列数量和类型一致或兼容。

三、SQL索引优化

        在SQL中使用索引可以提高查询性能和加快数据检索的速度。索引是一种数据结构,它允许数据库管理系统快速定位和访问特定值或数据范围。

  1. 索引优点
  1. 快速数据检索:使用索引可以减少数据库执行的I/O操作次数,从而加快数据检索的速度。通过在索引上执行查询操作,数据库可以快速定位到包含目标数据的位置,而不必扫描整个表。

  2. 加速排序和连接操作:索引可以优化排序和连接操作。通过在排序列上创建索引,数据库可以快速对结果进行排序。而在连接操作中,索引可以快速定位连接所需的数据,提高连接的效率。

  3. 提高查询性能:通过使用索引,数据库可以避免全表扫描,并且可以更有效地执行过滤和搜索操作。特别是对于含有大量数据的表或复杂查询,索引可以显著减少查询的执行时间。

  4. 减少存储空间需求:索引仅存储列的值和指向存储实际数据的指针。因此,相比于完整存储所有数据的表,索引需要较少的存储空间。这对于大型数据库和有限的存储资源非常有益。

  5. 强制唯一性约束:通过在列上创建唯一索引,可以强制数据库中的数据唯一性。这可以防止重复数据的插入,维护数据的一致性和完整性。

     2.索引缺点

 值得注意的是,索引并不是万能的。它们需要占用存储空间,并会在数据插入、更新和删除时产生额外的开销。

  1. 占用存储空间:索引需要额外的存储空间来存储索引数据结构和索引列的值。对于大型表和包含多个索引的数据库,这可能会显著增加存储需求。

  2. 增加数据插入、更新和删除的开销:当对包含索引的表执行数据插入、更新和删除操作时,索引需要进行维护操作。这可能会导致额外的开销和性能下降,尤其是对于频繁修改的表。

  3. 频繁更新的列性能下降:如果索引列的值频繁地被修改,那么索引维护操作会更加频繁,可能导致性能下降。此外,某些类型的索引(如聚集索引)可能会导致页面分裂,影响数据的连续性和查询性能。

  4. 不适用于所有查询:索引通常适用于频繁进行查找、排序和连接的列,但并非所有查询都能从索引中受益。在某些情况下,数据库优化器可能选择不使用索引,而是执行全表扫描。

  5. 高维数据和复杂查询的限制:对于高维数据和复杂查询,传统的索引可能无法提供良好的性能。例如,在多维数据集上执行复杂的查询和聚合操作时,可能需要使用专门的索引技术(如多维索引或倒排索引)。

  6. 需要维护和管理:索引需要定期进行维护和管理,以确保其有效性和性能。这包括索引重建、重新组织和统计信息更新等操作。

四、SQL索引的类型建立 

聚簇索引和非聚簇索引

聚簇索引:按照数据的物理顺序进行排序的索引,在一个表中只能有一个聚簇索引,因此他                    决定了数据在磁盘上的存储方式。当使用聚簇索引进行查询时,相邻的数据通常                    会在磁盘上存储在一起,这有助于提高查询性能。缺点:当数据经常被更新时,                    可能会导致页面分裂,降低性能。

非聚簇索引:是独立于数据物理排序的索引,一个表可以有多个非聚簇索引。非聚簇索引通                    常包含索引键的值以及指向对应数据行的指针。当使用非聚簇索引进行查询时,                    数据库引擎会根据索引找到对应的数据行。非聚簇索引适用于频繁更新的表,不                    会导致页面分裂。

总结:聚簇索引适用于需要经常查询范围数据的表。非聚簇索引适用于需要快速查找具体记录的表。具体使用哪种索引类型要根据实际情况进行选择。

主键索引也是聚簇索引,非主键索引都是非聚簇索引。除格式信息外,两种索引的非叶子节点都是只存索引数据的。

聚簇索引的叶子节点一般情况下存的是这条数据的所有字段信息。所以我们 select * from table where id = 1 的时候,都是要去叶子节点拿数据的。

非聚簇索引的叶子节点存的是这条数据所对应的主键和索引列信息。

你可能感兴趣的:(sql,学习,数据库)