数据库类型转换导致SQL不走索引的案例

 更新时间:2026年05月20日 10:21:35   作者:瀚高PG实验室  
在SQL中数据类型转换是基础且关键的操作,分为隐式和显式转换,隐式转换由系统自动完成,虽便捷但可能带来性能损耗、索引失效及数据准确性风险,这篇文章主要介绍了数据库类型转换导致SQL不走索引的案例,需要的朋友可以参考下

环境

系统平台:Linux x86-64 Red Hat Enterprise Linux 7

版本:4.5

文档用途

本文档主要介绍对字段添加类型转换,会导致SQL不走索引,从而影响查询性能。

详细信息

表的结构说明

表 table_varchar_id 的字段 id 是 varchar 类型,存在索引 idx_table_varchar_id 。

表 table_int_id 的字段 id 是 bigint 类型,存在索引 idx_table_int_id 。

执行计划示例

highgo=# EXPLAIN (ANALYZE, BUFFERS)
SELECT v.id as varchar_id, i.id as int_id, v.col1, i.col1
FROM table_varchar_id v
, table_int_id i
WHERE CAST(v.id AS BIGINT) = i.id
AND i.id BETWEEN 100000000000000000 AND 100000000005000000;
                                                                  QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------
 Hash Join  (cost=8.45..586.02 rows=7 width=53) (actual time=0.026..2.209 rows=5 loops=1)
   Hash Cond: ((v.id)::bigint = i.id)
   Buffers: shared hit=418
   ->  Seq Scan on table_varchar_id v  (cost=0.00..515.00 rows=10000 width=32) (actual time=0.004..0.806 rows=10000 loops=1) 
         Buffers: shared hit=415
   ->  Hash  (cost=8.38..8.38 rows=5 width=21) (actual time=0.012..0.012 rows=5 loops=1)
         Buckets: 1024  Batches: 1  Memory Usage: 9kB
         Buffers: shared hit=3
         ->  Index Scan using idx_table_int_id on table_int_id i  (cost=0.28..8.38 rows=5 width=21) (actual time=0.009..0.010 rows=5 loops=1)
               Index Cond: ((id >= '100000000000000000'::bigint) AND (id <= '100000000005000000'::bigint))
               Buffers: shared hit=3
 Planning Time: 0.117 ms
 Execution Time: 2.237 ms
(13 行记录)

上面执行计划中,查询 table_varchar_id 表时,执行了顺序扫描,没有使用 id 字段的索引,如下所示:

->  Seq Scan on table_varchar_id v  (cost=0.00..515.00 rows=10000 width=32) (actual time=0.004..0.806 rows=10000 loops=1) 
      Buffers: shared hit=415

原因

SQL语句中对 table_varchar_id 表的字段 id 添加了 CAST(v.id AS BIGINT) 类型转换,导致没有执行 id 字段的索引。

方案

方案一:修改表字段的数据类型

针对 table_varchar_id 表的字段 id ,确认业务上常用的数据类型是数值型还是字符串型,然后统一修改为相同的数据类型,示例如下:

highgo=# alter table table_varchar_id alter COLUMN id type bigint using id::bigint;  --统一使用 bigint 类型

highgo=# analyze table_varchar_id;        --收集表的统计信息,保证被修改数据类型的 id 字段的索引立即生效

数据类型修改统一后,SQL语句中的 cast 转换可以删除。

方案二:创建 cast 类型转换的索引

highgo=# create index idx_table_varchar_cast_id on table_varchar_id(cast(id as bigint));

highgo=# analyze table_varchar_id;        --收集表的统计信息,保证类型转换索引、表达式索引立即生效

注:类型转换索引、表达式索引的维护成本比较高,尤其是数据变更频繁的表,影响性能

方案三:更换为对条件值进行类型转换

SQL语句中 table_varchar_id 表的字段 id 去掉 cast 转换,表 table_int_id 的字段 id 作为条件值添加 varchar 类型的转换,修改后的SQL及执行计划

如下:

highgo=# EXPLAIN (ANALYZE, BUFFERS)
SELECT v.id as varchar_id, i.id as int_id, v.col1, i.col1
FROM table_varchar_id v
, table_int_id i
WHERE v.id = i.id::varchar      --i.id 字段添加 varchar 类型转换,v.id 可以执行索引扫描
AND i.id BETWEEN 100000000000000000 AND 100000000005000000;
                                                                   QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=0.57..49.97 rows=5 width=53) (actual time=0.021..0.029 rows=5 loops=1)
   Buffers: shared hit=16 read=2
   ->  Index Scan using idx_table_int_id on table_int_id i  (cost=0.28..8.38 rows=5 width=21) (actual time=0.003..0.004 rows=5 loops=1)
         Index Cond: ((id >= '100000000000000000'::bigint) AND (id <= '100000000005000000'::bigint))
         Buffers: shared hit=3
   ->  Index Scan using idx_table_varchar_id on table_varchar_id v  (cost=0.29..8.31 rows=1 width=32) (actual time=0.004..0.004 rows=1 loops=5)
         Index Cond: ((id)::text = ((i.id)::character varying)::text)
         Buffers: shared hit=13 read=2
 Planning Time: 0.123 ms
 Execution Time: 0.048 ms
(10 行记录)

总结 

到此这篇关于数据库类型转换导致SQL不走索引的文章就介绍到这了,更多相关类型转换SQL不走索引内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MySQL及SQL注入详细说明(附预防措施)

    MySQL及SQL注入详细说明(附预防措施)

    所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令,这篇文章主要介绍了MySQL及SQL注入的相关资料,需要的朋友可以参考下
    2025-11-11
  • MySQL内外连接实战详解

    MySQL内外连接实战详解

    文章详解MySQL内连接与外连接,内连接通过WHERE筛选匹配记录,外连接包括左、右连接,保留一侧全数据,包含案例与练习及LeetCode实战题目,对mysql内外连接实战案例相关知识感兴趣的朋友一起看看吧
    2025-08-08
  • MySQL中查询字段为空或者为null的方法

    MySQL中查询字段为空或者为null的方法

    这篇文章主要介绍了MySQL中查询字段为空或者为null的方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • Mysql如何通过binlog日志恢复数据详解

    Mysql如何通过binlog日志恢复数据详解

    binlog日志用于记录所有更新了数据或者已经潜在更新了数据的所有语句,下面这篇文章主要给大家介绍了关于Mysql如何通过binlog日志恢复数据的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2022-02-02
  • MySQL连接及基本信息查看命令汇总

    MySQL连接及基本信息查看命令汇总

    这篇文章主要针对MySQL连接及基本信息查看命令进行了详细汇总,感兴趣的小伙伴们可以参考一下
    2016-02-02
  • /var/log/pacct文件导致MySQL启动失败的案例分享

    /var/log/pacct文件导致MySQL启动失败的案例分享

    这篇文章主要介绍了/var/log/pacct文件导致MySQL启动失败的案例分享,这是个比较让人郁闷的问题,找不到MySQL启动失败的原因进可以按此文的方法试一试,需要的朋友可以参考下
    2015-01-01
  • MySQL中复制数据表中的数据到新表中的操作教程

    MySQL中复制数据表中的数据到新表中的操作教程

    这篇文章主要介绍了MySQL中复制数据表中的数据到新表中的操作教程,文中分为新表存在和新表不存在两种情况来讲,需要的朋友可以参考下
    2016-03-03
  • 解读MySql深分页的问题及优化方案

    解读MySql深分页的问题及优化方案

    这篇文章主要介绍了MySql深分页的问题及优化,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-06-06
  • MySQL百万级数据,怎样做分页查询

    MySQL百万级数据,怎样做分页查询

    这篇文章主要介绍了MySQL百万级数据,怎样做分页查询?今天咱们就来聊聊这个话题,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-10-10
  • mysql获取字符串长度函数(CHAR_LENGTH)

    mysql获取字符串长度函数(CHAR_LENGTH)

    本文介绍一下关于mysql获取字符串长度的方法,希望此教程对各位同学会有所帮助哦。
    2013-11-11

最新评论