摘要:索引就是数据表中数据和相应的存储位置的列表,利用索引可以提高在表或视图中的查找数据的速度。
本文分享自华为云社区《数据库开发指南(六)索引和视图的使用技巧、方法与综合应用》,作者: bluetata 。
索引就是数据表中数据和相应的存储位置的列表,利用索引可以提高在表或视图中的查找数据的速度。它类似于书籍的索引,可以帮助快速定位和检索数据。在数据库中,索引是对一个或多个列的值进行排序和存储的结构,它们包含指向实际数据位置的指针。
数据库中索引主要分为两类:聚集索引和非聚集索引。SQL Server 还提供了唯一索引、索引视图、全文索引、XML 索引等等。聚集索引和非聚集索引是数据库引擎中索引的基本类型,是理解其他类型索引的基础。
聚集索引是值表中数据行的物理存储顺序和索引的存储顺序完全相同。聚集索引根据索引顺序物理地重新排列了用户插入到表中的数据,因此,每个表只能创建一个聚集索引。聚集索引经常创建在表中经常被搜索到的列或按顺序访问的列上。在默认情况下,主键约束自动创建聚集索引。
非聚集索引不改变表中数据列的物理存储位置,数据与索引分开存储,通过索引指向的地址与表中的数据发生关系。
非聚集索引没有改变表中物理行的位置,索引可以在以下情况下使用非聚集索引:
这里用一个表格简单的总结一下聚集索引和非聚集索引的区别:
除了以上索引,还有以下类型索引:
create [unique] [clustered | noclustered]
index index_name
on table_name (column_name ...)
[with fillfactor=x]
参数解释
unique 唯一索引
clustered 聚集索引
noclustered 非聚集索引
fillfactor 填充因子大小,范围在 0-100 直接,表示索引页填满的空间所占的百分比。
在 MSSQL 中,索引的命名规则的最佳实践可以有一些常见的准则,以提高可读性和维护性。这个潜在的要求不仅试用于 SQL Server 数据库,同样在其他数据库例如 MySQL、Oracle 中都同样值得注意。
下面是个人总结的一些命名规则与建议:
-- 普通索引 if (exists (select * from sys.indexes where name = 'idx_stu_name')) drop index student.idx_stu_name go create index idx_stu_name on student(name); -- 联合索引 if (exists (select * from sys.indexes where name = 'idx_uqe_clu_stu_name_age')) drop index student.idx_uqe_clu_stu_name_age go create unique clustered index idx_uqe_clu_stu_name_age on student(name, age); if (exists (select * from sys.indexes where name = 'idx_cid')) drop index student.idx_cid go if (exists (select * from sys.indexes where name = 'idx_cid')) drop index student.idx_cid go -- 非聚集索引 create nonclustered index idx_cid on student (cid) with fillFactor = 30; --填充因子 -- 聚集索引 if (exists (select * from sys.indexes where name = 'idx_sex')) drop index student.idx_sex go create clustered index idx_sex on student(sex); -- 聚集索引 if (exists (select * from sys.indexes where name = 'idx_name')) drop index student.idx_name go create unique index idx_name on student(name);
一般情况,可以选择那些对查询性能有积极影响的列进行索引创建,下面进行一定的总结:
列的选择性:选择性是指列中不同值的数量与总行数的比例。如果某列具有较高的选择性,即不同的值较多,那么为该列创建索引可能会有更好的效果。例如,在表示性别的列上创建索引可能没有太大的帮助,因为只有两个可能的值。
查询频率:观察经常用于查询条件的列。如果某个列经常用于搜索、过滤或连接操作,那么为该列创建索引可以提高查询性能。
数据表的大小:对于大型表,创建索引的影响可能更加显著。较小的表可能不需要太多的索引,因为全表扫描的开销相对较小。
数据更新频率:索引的创建和维护也会增加对数据的写操作的开销。如果某个列的数据经常发生变化,那么创建索引可能会带来一定的性能开销。
查询性能优化需求:通过分析查询执行计划,可以确定是否存在潜在的性能瓶颈,并考虑为相关的列创建索引以改善查询性能。
请注意过多的索引也可能会带来维护开销和存储成本,因此需要在权衡索引数量和性能提升之间找到平衡点。定期监控和评估索引的使用情况也是重要的,以确保索引仍然对数据库性能产生积极影响。
虽然在某些情况下创建索引可以提高查询性能,但并不是所有列都适合创建索引。以下是一些不适合创建索引的列的情况:
低选择性列:如果某个列的选择性很低,即该列的不同值较少,创建索引可能不会带来明显的性能提升。例如,对于性别这样只有几个可能值的列,创建索引可能不会有太大意义。
经常更新的列:如果某个列的值经常被修改,那么为该列创建索引可能会带来额外的维护成本和性能开销。每次更新操作都需要更新索引,这可能会影响写入性能。在这种情况下,需要仔细评估是否真的需要为该列创建索引。
过于频繁的查询列:某些列可能经常被查询,但它们的选择性较低,即不同的值较少。在这种情况下,尽管查询频率高,但为该列创建索引可能不会带来明显的性能提升,因为索引的使用效果有限。
大文本或大二进制列:对于存储大文本或大二进制数据的列,如长文本字段或图像字段,创建索引的效果通常较差。这是因为索引本身需要占用额外的存储空间,并且对于大型数据的索引操作可能变得非常耗时。
不常用的列:对于很少用于查询的列,创建索引可能没有太大意义。如果一个列很少用于查询条件或连接操作,那么为其创建索引可能只会增加额外的开销而不带来实际的性能提升。
需要注意的是,以上列举的情况只是一般性的指导原则,具体是否适合创建索引还取决于具体的数据库结构、查询模式和性能需求。在设计和创建索引时,应根据具体情况进行评估,并进行性能测试和优化以确保索引的有效性。
视图就是一个虚拟的数据表,该数据表中的数据记录是由一条查询语句的查询结果得到的。
如果你在面试的时候被问到这个问题,建议从下面这个流程来回答一下面试官。
首先介绍一下表的作用(比如表是直接存储结构化数据,可以扩展增删改之类的),之后在介绍一下视图是什么,之后从两个切入点来讲解视图的好处以及必要性,这两个切入点是:复用性和安全性,这里来简单总结一下:
讲解完上述的两个大的关键点后,也可以适当自行发挥,比如视图你可以调整表字段的显示顺序,或者字段名字等等。这些也是优点。可以适当进行讲解。
创建视图的时候,对命名视图大家一般也有默认的规则,一般情况可以使用 v_ 或 view_ + 表名(表缩写)的形式。
例如:v_student
--创建视图 if (exists (select * from sys.objects where name = 'v_student')) drop view v_student go create view v_student as select id, name, age, sex from student;
创建视图需要考虑一下准则:
下列情况必须指定视图中每列的名称:
修改视图和修改表有点类似,可以直接使用 alter 关键字进行修改,示例如下:
alter view v_student as select id, name, sex from student; alter view v_student(编号, 名称, 性别) as select id, name, sex from student go select * from v_student; select * from information_schema.views;
如果你对某一个视图有保护查询逻辑、防止修改或者查询加密的需求的时候,可以使用加密视图操作。
在 SQL Server 中 使用with encryption后,可以在创建视图时对其定义的 SQL 查询进行加密。也就是说 MSSQL 会对该视图的定义中的查询语句进行加密。这意味着其他人无法直接查看或分析该视图的查询逻辑。压根就看不到这个视图内部结构了。
-- 加密视图 if (exists (select * from sys.objects where name = 'v_student_info')) drop view v_student_info go create view v_student_info with encryption --加密 as select id, name, age from student go --view_definition is null select * from information_schema.views where table_name like 'v_student';
如何解密被加密的视图,或者修改已经被加密的视图:
一般情况一个视图被加密后,你需要修改它,那么大致有3个方法:
视图可以被更新吗?什么情况下可以被更新?
如果面试官问了这两个问题,那么他还算友好的提醒了你,如果直接问了一句话“视图可以被更新吗?”,那么我感觉有被挖坑的嫌疑。
视图可以被更新,但不是所有的情况都可以。
视图更新必须遵循以下规则: