大家好,我是程序员牛肉。
今天在逛论坛的时候,发现了一个极其逆天的帖子:该发帖人的客户购买了一个软件,发现这个软件对应的数据库会定期检测当前的索引然后进行删除。
基于这种方式,用户的软件就会出现一些要命的慢查询拖垮整个数据库。
该发帖人第一次发现这个问题之后,采用的方法是定时任务来给数据库加索引。但是随着删除索引的频率越来越高,程序也逐步到了不可用的地步,因为随着数据量上来,频繁对索引的删除和创建也会消耗大量的性能。
这明眼人一眼就看出来了,这是等着客户掏钱优化呢。说实话我看到这个帖子的时候还是有点震惊的。
我一直以为这么抽象的事情只会存在于段子中。钱还能这么挣,还是国内的人才多啊。
而且删除数据库的用户权限应该还挺高的,导致该发帖人没有办法直接对其进行权限移除。
最后该发帖人采用的方法是套了一个中间件ProxySQL ,在这个中间件中使用了 Query Rewrite功能。
[Query Rewrite(查询重写) 是数据库中间件或数据库引擎中的一项核心功能,允许在 SQL 语句执行前,动态修改其内容或逻辑。这一功能广泛应用于数据库代理(如 ProxySQL)、数据库防火墙、ORM 框架优化工具等场景。]
具体来说,该发帖人为了解决这个问题加了这么一条语句:
INSERT INTO mysql_query_rules
(rule_id, active, match_pattern, replace_pattern)
VALUES
(1, 1, '^DROP INDEX .* ON .*$', 'select 1');
这条规则会将所有匹配 ^DROP INDEX .* ON .*$
正则表达式的 SQL 语句(即 DROP INDEX
操作)重写为 SELECT 1
,从而阻止用户或程序意外删除数据库索引。
遇上这种事情确实糟心,瓜就先吃到这里了。既然这篇是关于数据库索引的瓜,那么我们今天就来和大家讲一讲数据库索引。
请大家思考一下:如果业务代码已经保证不会写入重复数据了,那么我们在加索引的时候,是选择唯一索引还是普通索引呢?
在这里我直接给出答案:优先选择普通索引。
普通索引和唯一索引的性能差距主要体现在更新操作上。
在 InnoDB 中,二级索引(Secondary Index) 仅存储索引列和主键值,而不直接存储数据。
如果需要更新的索引页已经位于 Buffer Pool,那么 MySQL 直接修改 Buffer Pool 中的索引数据,并记录相应的 Redo Log,保证数据的可靠性。
但是,如果 二级索引页不在 Buffer Pool 中(例如由于内存限制,数据页尚未加载到内存),MySQL 并不会立即从磁盘读取数据页,而是采用 Change Buffer 技术进行优化。
InnoDB会将这些更新操作缓存在change buffer中,这样就不需要从磁盘中读入这个数据页了。在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行change buffer中与这个页有关的操作。通过这种方式就能保证这个数据逻辑的正确性。
change buffer有一个很大的优势是避免了随机IO,若目标索引页不在 Buffer Pool 中,传统方式需要从磁盘读取索引页到内存,产生随机 I/O(尤其是机械硬盘性能极差)。
而并不是所有索引都可以使用这么好的优化措施。
对于唯一索引来讲,由于要在数据库层面保证数据的唯一性,因此在插入记录的时候就就需要判断表中是否存在当前数据。那就需要把内存页读入内存中进行判断。那你都读到内存里面了,直接修改不就好了吗?
因此唯一索引的更新其实是不能使用 change buffer的。这也就意味着唯一索引的更新相比较于普通索引的更新会多很多随机I/O。
基于这种原因,我们一般在添加数据库索引的时候才会优先考虑普通索引。
那今天关于数据库索引的瓜就介绍到这里了,相信通过我的介绍,你已经大致了解了这件事情。希望我的文章可以帮到你。
你对这件事有什么想说的吗,你在工作中有遇到什么坑人操作吗?欢迎在评论区留言。