视图中用created_at::DATE或CAST(created_at AS DATE)会阻断索引下推,导致数据库必须物化全部数据后再过滤,使千万级查询从毫秒级退化至秒级;EXPLAIN中Filter若出现在Subquery Scan而非基表扫描层即证实失效。

视图里用 CAST 或 :: 强制转类型,不是“更安全”,而是主动堵死索引下推路径。
为什么视图定义里写 created_at::DATE 会变慢
数据库看到的是一个已计算好的列,无法把外部 WHERE created_date = '2024-01-01' 下推到基表扫描层。它只能先物化整个视图(比如千万行 timestamp 全转成 date),再过滤——中间结果体积暴增,内存和 CPU 都吃紧。
验证方法很简单:EXPLAIN 输出中如果 Filter 出现在 Subquery Scan 或 Result 节点,而不是基表的 Seq Scan / Index Scan 层,就说明已失能。
- PostgreSQL 中
created_at::DATE和CAST(created_at AS DATE)行为一致,都是隐式绑定,没有性能差别 - SQL Server 的
CONVERT(DATE, created_at)同样阻断下推,别以为加了样式参数就能绕过 - MySQL 不支持
::,但CAST(created_at AS DATE)效果一样糟
UNION ALL 各分支列类型不一致的隐式升格陷阱
两个分支一个返回 INT,一个返回 NUMERIC(10,2),数据库不会报错,而是悄悄统一升格为 NUMERIC(15,2)。这不只是精度变高——它让原本可下推的 GROUP BY、ORDER BY、JOIN 全部失效,还可能因隐式 NULL 导致行数膨胀。
检查方式:
- PostgreSQL:
SELECT pg_typeof(col) FROM (your_union_query) t; - MySQL:
SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'your_temp_view';
修复原则:显式统一类型,优先选精度低、存储小的类型(比如都 CAST(col AS INT),而非全升到 NUMERIC)。
JOIN 字段在视图里类型不匹配,比普通表更难定位
视图封装了多层逻辑,ON t1.id = t2.user_id 看似正常,但若 t1.id 是 BIGINT、t2.user_id 是 VARCHAR,每次调用视图时,数据库都在对右表每行做字符串解析——你只看到查询越来越慢,EXPLAIN 显示 type=ALL、key=NULL、Extra 含 Using where; Using join buffer。
临时缓解(仅限 PostgreSQL):ON t2.user_id::BIGINT = t1.id;SQL Server 可用 ON CAST(t2.user_id AS BIGINT) = t1.id;但 MySQL 中这类写法大概率仍无法走索引,因为 CAST 作用于字符串列本身。
真正根治方式:改表结构,把 VARCHAR 列改成 BIGINT 并清理脏数据。视图层加转换只是掩盖问题,不是解决。
最常被忽略的一点:视图不是“逻辑包装”,而是执行计划的分水岭。一旦你在视图定义里动了类型,就等于提前画好了物化边界——后续所有优化,都得在这个边界之上重新开始。

















