mysql 索引长度与区分度的选择

探讨了在数据库中建立理想索引的关键因素,包括查询频率、区分度、长度及覆盖字段。通过案例分析,展示了如何在区分度与长度之间找到平衡点,以提升索引性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

理想的索引

  • 查询频繁 
  • 区分度高  
  • 长度小  
  • 尽量能覆盖常用查询字段

索引长度直接影响索引文件的大小,影响增删改的速度,并间接影响查询速度(占用内存多).

针对列中的值,从左往右截取部分,来建索引
1: 截的越短, 重复度越高,区分度越小, 索引效果越不好
2: 截的越长, 重复度越低,区分度越高, 索引效果越好,但带来的影响也越大--增删改变慢,并间影响查询速度.

所以, 我们要在  区分度 + 长度  两者上,取得一个平衡.

惯用手法: 截取不同长度,并测试其区分度

案例:

 这里准备了一张表,其表结构如下

   

索引情况如下:

在生产环境中,经常需要使用到dye_vat这个字段来查询,那么这个字段该怎么建立索引比较合理呢?

这里我们依据,字符长度和区分度来计算怎么建索引比较合理!

可以看到在这个25141条记录的表中,当字符长度为13时,区分度是最高的,但是后面也看到了,现有表dye_vat 这个字段最大长度也才13,所以我们建立索引的时候不可能以13字符长度建立索引( 就目前来看不太合理) 。

将以上数据,通过excel 分析

 

由上表可以看出,将索引长度建在8-11 是比较合理的,这里我们将索引长度选择在10,建立索引。

建立索引:

alter table dye_stock_picode add index dye_vat(dye_vat(10)); 

 

这里说下ken_len :32 是怎么来的,在utf8 下一个字符占3个字节,我们的索引dye_vat 是10个长度的,所以 3 * 10 ,加上varchar类型长度会保留1~2 字节。

在我这个案例中,索引长度选择为了10,这个案例中,辨识度普遍较低,可能是由于数据问题(数据不够多之类的),在遇到要对字符串建立索引这类问题中,一般要看业务场景,具体问题具体分析。

注:对于一般的系统应用: 区别度能达到0.1,索引的性能就可以接受。

<think>嗯,用户这次聚焦在索引区分度这个具体技术上,看来ta正在深入优化数据库性能。之前讨论过索引的基本要求和限制,现在ta显然想解决更核心的效率问题——如何量化索引的有效性。用户引用的资料很有价值,尤其是那个区分度计算公式:$\text{区分度}=\frac{\text{count(distinctleft(字段,长度))}}{\text{count(1)}}$。这个公式把抽象概念量化了,但ta可能更需要知道具体操作阈值。让我结合不同数据库场景说明:首先区分度低于0.1的索引基本无效这个结论需要验证。在Oracle的位图索引场景中,低区分度反而有用;但用户问题明确是SQL索引,应聚焦B+树结构。根据MySQL手册,建议值确实是0.1,但要注意:-0.1是经验值,实际要考虑数据分布。比如医疗系统中的“疾病类型”字段,虽然只有10个枚举值(理论区分度0.01),但90%查询都按该字段过滤,这时仍需索引-联合索引中次要列可以放宽要求。比如订单表索引(user_id,status),status只有3个状态,但user_id先过滤后数据量小,status的低区分度影响效率[^3]用户提供的引用[2]提到索引长度区分度的平衡,这点在实践中有个经典案例:对varchar(255)的email字段,完整索引区分度0.98但占用空间大。实际用left(email,20)计算发现区分度达0.95,这时前缀索引就能节省40%空间。特别要注意的是引用[4]的案例,9秒查询很可能是索引区分度陷阱。o_id字段如果包含大量重复值(如1,2,3占全表90%),即使有索引也会全表扫描。这时应该:1.检查区分度:selectcount(distincto_id)/count(1)fromxx2.若低于0.15,考虑强制指定索引或优化IN条件最后补充个容易忽略的点:NULL值处理。当索引列含大量NULL时:-区分度计算要排除NULL:count(distinctcol)/count(col)-SQLServer的筛选索引能针对性解决:CREATEINDEX...WHEREcolISNOTNULL</think>### SQL索引区分度要求详解 #### 一、核心概念 1. **索引区分度定义** 表示索引列中唯一值占总行数的比例,计算公式: $$ \text{区分度} = \frac{\text{count(distinct 索引列)}}{\text{count(1)}} $$ - **理想值**:接近1(如主键索引区分度=1)[^1] - **最低要求**:**>0.1**(低于此值索引通常无效)[^1][^2] 2. **区分度性能关系** | 区分度范围 | 效果 | 建议 | |------------|-------------------------------|-------------------| | >0.3 | 高效索引 | 强烈推荐创建 | | 0.1~0.3 | 中等效果 | 需结合查询频率评估| | <0.1 | 基本无效,可能降低性能[^1] | 避免创建 | #### 二、具体实践要求 1. **单列索引要求** - **必须满足**:$ \text{区分度} \geq 0.1 $ - **优化方法**:对长字段(如varchar)使用**前缀索引**: ```sql -- 测试不同前缀长度区分度 SELECT COUNT(DISTINCT LEFT(email, 5))/COUNT(1) AS prefix5, -- 0.82 COUNT(DISTINCT LEFT(email, 10))/COUNT(1) AS prefix10 -- 0.98 FROM users; ``` - 选择最短且区分度>0.9的前缀创建索引[^1][^2] 2. **联合索引设计原则** - **列顺序策略**: ```sql /* 正确顺序:高区分度列在前 */ CREATE INDEX idx_brand_cat ON goods(brand_id, cat_id); -- brand_id区分度0.4 > cat_id 0.2[^3] ``` - **低区分度列处理**: - 若某列区分度<0.1,需评估是否加入联合索引 - 高频查询的低区分度列可放在索引末尾[^3] #### 三、区分度不足的风险 1. **性能陷阱** - **额外IO消耗**:低区分度索引需多次"回表查询",反而比全表扫描更慢[^1] - **优化器弃用**:如区分度0.05的`delete`字段索引被忽略,导致200万行查询耗时9秒[^4] ```sql /* 低效案例 */ SELECT COUNT(*) FROM orders WHERE delete_flag = 0 -- 区分度仅0.02(0/1两种值) AND o_id IN (1,2,3); -- 实际走全表扫描[^4] ``` 2. **空间浪费** - 低效索引占用存储空间,增加写入时的维护开销[^1] #### 四、优化策略 1. **强制使用索引**(谨慎使用) ```sql SELECT COUNT(*) FROM orders USE INDEX(idx_delete) WHERE delete_flag = 0 AND o_id IN (1,2,3); ``` 2. **覆盖索引优化** 扩展索引包含查询所需所有列,避免回表: ```sql CREATE INDEX idx_covering ON orders(delete_flag, o_id) INCLUDE (total_amount); ``` 3. **数据归档** 对历史数据(如`delete_flag=1`)定期归档,提升有效数据区分度[^4]。 --- ### 总结要求 | **场景** | **区分度要求** | **解决方案** | |------------------------|----------------------|----------------------------------| | 单列索引 | ≥0.1 | 低于阈值时不创建索引 | | 联合索引首列 | ≥0.3 | 优先选最高区分度列为首列[^3] | | 长文本字段索引 | 前缀区分度≥0.9 | 使用`LEFT(字段,N)`前缀索引[^1][^2] | | 低区分度高频查询列 | 可放宽至0.05~0.1 | 作为联合索引末尾列 | > **关键结论**:索引区分度本质是**空间时间的权衡**。高区分度加速排序但增加空间占用,需通过`COUNT(DISTINCT LEFT(列,N))`找到最佳平衡点[^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值