在这里将最近学习的MySQL中索引及事务的知识进行总结。
索引是一种特殊的文件,包含着对数据表里所有记录的引用指针。可以对表中的一列或多列创建索引,并指定索引的类型,各类索引有各自的数据结构实现。
要考虑对数据库表的某列或某几列创建索引,需要考虑以下几点:
满足以上条件时,考虑对表中的这些字段创建索引,以提高查询效率。
反之,如果非条件查询列,或经常做插入、修改操作,或磁盘空间不足时,不考虑创建索引。
注意:索引本身也需要占据硬盘中的内存。
show index from 表名;
案例:查看学生表已有的索引。
show index from student;
create index 索引名 on 表名(字段名);
案例:创建班级表中,name字段的索引。
注意:创建表的索引也是一个危险操作,如果表本身很大再创建索引,可能会造成大量CPU/硬盘IO消耗,将数据库搞挂掉。但是针对表中数据过多这一点有两种解决办法:(1)你可以在刚建表时就创建索引就可以避免这个问题,但是比较考验表的设计功力。(2)如果说没有那个设计功力想要加索引也是有办法的,将数据库的服务器进行更换。首先拿一个新的服务器创建表和索引此时是空表,之后将就数据库数据导入新机器,然后将应用程序请求再接到新机器即可。第二种方式还有一个好处在于如果新机器出问题可以立刻换回旧机器避免问题扩大化,开发中的高风险操作都可以通过类似方式完成。
create index idx_classes_name on classes(name);
drop index 索引名 on 表名;
案例:删除班级表中name字段的索引。
注意:删除索引也是比较危险的操作,可能涉及大量的硬盘的IO操作把数据库搞挂掉。
drop index idx_classes_name on classes;
注意:创建主键约束(PRIMARY KEY)、唯一约束(UNIQUE)、外键约束(FOREIGN KEY)时,会自动创建 对应列的索引。这里还插个题外话,创建外键约束时,父表中被参照列需要是主键或是具有唯一性约束。
默认情况下对数据表进行条件查询操作都是遍历,引入索引就是通过希望其它数据结构加快查询速度,减少遍历表的可能。
只能查询key相等的情况,无法进行<>这样的范围查询。
红黑树可以进行范围查询,但是如果想找到下一个后继元素可能要回溯到父节点才行。这个问题可以通过线索化来解决但是会消耗存储空间。当元素变多时,红黑树高度也在不断增加,比较次数增多,数据库数据/索引都是保存在硬盘中,比较增多自然硬盘IO操作就增多了。
哈希表和红黑树这两种数据结构都不太适合给数据库使用。
B树本质上是一个N叉搜索树,每个节点存放多个元素,延伸出多个子树,同样数量的数据,数的高度因此下降。
拿着想要查询的key在节点上比较确实需要比较很多次,但是这里的比较还是比较高效的。
数据库中的索引数据结构是B+树,这里引出B树是为了后续更好理解。
B+树同样也是N叉搜索树。
上图为一个3阶B+树。
按照B+树的规则来存储数据,此时叶子节点这一层就包含数据集合全集。另外叶子节点会以类似链表这样的数据结构连接起来方便遍历表中所有数据,也很方便进行范围查询。
B+树相较B树的优点:
针对上述优点的第三点,为什么这些非叶子节点本体在硬盘中,何时会放到内存中?
典型的策略:
针对查询表索引的几种情况:
如果表中没有建立主键约束,那么数据库会根据自带的隐藏列建立默认的B+树。另外B树存在的前提是MySQL使用了innodb这个存储引擎,这是最常用的。
这里底层数据结构还是学过了B和B+树更加能理解。
在平时数据库的操作中,一般都是多个数据库的sql语句进行组合使用,比如说转账的语句可以使用两个update语句。
如果执行过程中出现意外情况,比如程序崩溃等。第一句执行完成,第二句执行失败,相当于你扣除了余额但收款人余额并不增加,这个问题就挺严重。这时就需要使用事务来确保操作是完整的、可靠的。
事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败。
在不同的环境中,都可以有事务。对应在数据库中,就是数据库事务。
上述很难做到效率和准确度同时兼顾,需要根据具体场景来选择方法。
MySQL给程序猿提供了四个隔离级别,如下图:
修改以上的隔离级别是通过修改MySQL中的配置文件来完成的。
(1)开启事务:start transaction;
(2)执行多条SQL语句
(3)回滚或提交:rollback/commit;
说明:rollback即是全部失败,commit即是全部成功。
start transaction;
-- 阿里巴巴账户减少2000
update accout set money=money-2000 where name = '阿里巴巴';
-- 四十大盗账户增加2000
update accout set money=money+2000 where name = '四十大盗';
commit;