最近遇到一个线上慢查询的问题,存在外键却没有索引,那么有啥区别呢?

你好,我是风一样的树懒,一个工作十多年的后端专家,曾就职京东、阿里等多家互联网头部企业。公众号“吴计可师”,已经更新了近百篇高质量的面试相关文章,喜欢的朋友欢迎关注点赞


最近遇到了一个线上慢查询的问题,最后确定是没有创建索引,但是很奇怪的是存在一个外键,那么外键是否能加快查询,与索引区别是什么呢?

数据库中的索引和外键是两个不同的概念,各自有不同的用途和实现方式。以下是它们的核心区别和实际应用场景:


一、定义与核心区别

维度索引(Index)外键(Foreign Key)
核心目的加速数据查询维护表间数据完整性
本质数据结构(如B+树、哈希表)数据约束(引用完整性约束)
强制关系不涉及表间关系必须关联另一表的主键或唯一键
是否可选可选创建(根据查询需求)可选约束(根据业务逻辑需求)
性能影响加速查询,但增加写操作开销保证数据一致性,但可能降低并发写入性能

二、实际应用场景

1. 索引的典型场景
  • 加速WHERE条件查询
    SELECT * FROM orders WHERE user_id = 100;  -- 在user_id字段创建索引
    
  • 优化JOIN操作
    SELECT * FROM users 
    JOIN orders ON users.id = orders.user_id;  -- 在orders.user_id创建索引
    
  • 加速排序和分组
    SELECT * FROM products ORDER BY price;  -- 在price字段创建索引
    
2. 外键的典型场景
  • 防止无效引用
    -- 订单表中的user_id必须存在于用户表
    ALTER TABLE orders 
    ADD FOREIGN KEY (user_id) REFERENCES users(id);
    
  • 级联操作
    -- 用户删除时,自动删除其所有订单
    ALTER TABLE orders 
    ADD FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
    

三、实现细节对比

1. 索引的类型
  • 普通索引(INDEX):加速查询,允许重复值。
  • 唯一索引(UNIQUE):确保列值唯一。
  • 主键索引(PRIMARY KEY):特殊的唯一索引,不允许NULL。
  • 全文索引(FULLTEXT):用于文本搜索优化。
  • 复合索引:多列组合索引(如INDEX (col1, col2))。
2. 外键的约束行为
  • ON DELETE:定义父表数据删除时的行为:
    • CASCADE:级联删除子表数据。
    • SET NULL:将子表外键设为NULL。
    • RESTRICT:阻止删除(默认)。
  • ON UPDATE:定义父表主键更新时的行为(类似ON DELETE)。

四、对数据库性能的影响

1. 索引的代价
  • 写入开销:每次INSERT/UPDATE/DELETE需要维护索引结构。
  • 存储空间:索引通常占用表数据的10%~30%空间。
  • 优化器选择:不合理的索引可能导致优化器选择低效执行计划。
2. 外键的代价
  • 锁竞争:外键约束可能引发行级锁或表级锁,影响并发。
  • 事务开销:需要检查引用完整性,增加事务处理时间。
  • 级联风险ON DELETE CASCADE可能意外删除大量数据。

五、设计时的权衡建议

1. 索引使用原则
  • 高频查询字段必加索引:WHERE、JOIN、ORDER BY涉及的列。
  • 避免过度索引:每个额外索引都会增加维护成本。
  • 复合索引列顺序:区分度高的列放在前面。
  • 监控索引使用率:定期清理未使用的索引。
2. 外键使用原则
  • 核心业务关系必加外键:如订单→用户、评论→文章。
  • 非核心关系可省略:如日志表、统计分析表。
  • 测试环境开启,生产环境慎用:某些高并发场景禁用外键,改用应用层校验。
  • 与触发器谨慎配合:避免复杂的级联逻辑难以维护。

六、常见误区澄清

1. 外键会自动创建索引吗?
  • MySQL InnoDB:自动为外键创建索引。
  • PostgreSQL不会自动创建索引,需手动添加。
  • Oracle:不自动创建,需手动管理。
2. 主键和唯一索引的区别
主键(PRIMARY KEY)唯一索引(UNIQUE)
每表只能有一个每表可以有多个
不允许NULL值允许一个NULL值(取决于数据库实现)
用于定义表的主标识仅保证列值唯一

七、实际案例解析

场景:电商系统订单管理
  • 索引设计
    -- 高频查询:按用户ID查订单
    CREATE INDEX idx_orders_user_id ON orders(user_id);
    
    -- 复合索引:按状态和时间范围查询
    CREATE INDEX idx_orders_status_time ON orders(status, create_time);
    
  • 外键设计
    -- 确保订单关联的用户存在
    ALTER TABLE orders 
    ADD FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT;
    
    -- 确保商品存在(允许商品被删除后订单保留)
    ALTER TABLE order_items 
    ADD FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE SET NULL;
    

总结

  • 索引是“加速器”:以空间换时间,优化查询性能。
  • 外键是“约束器”:以性能换安全,保障数据一致性。
  • 合理搭配使用:核心业务表建议同时使用索引和外键,非核心表根据场景取舍。

今天文章就分享到这儿,喜欢的朋友可以关注我的公众号,回复“进群”,可进免费技术交流群。博主不定时回复大家的问题。
公众号:吴计可师

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值