表的字段明明有index的,但为什么用不上呢? |
|
今天在搞维护的时候,客户说有个功能太慢了,要求改善一下。 |
主要逻辑的sql如下: |
SELECT |
(SELECT user_name |
FROM user |
WHERE user_id = (SELECT value |
FROM data |
WHERE id = history.id |
AND code = 'counselor_id' |
) |
) AS "指导者名 " |
… //其他项目 |
FROM user_history history |
|
user_history表:用户履历信息,大概有 10万条左右 |
user表:用户信息,大概有 3万条左右 |
data表:用户每个履历的具体信息,每个履历有几十条数据。还有其他很多数据,总的大概几千万条。 |
|
index(索引)情况如下: |
user用户的表: user_id字段 |
data表:id,code |
|
咋一看sql写的也没有问题 ,索引按理 说 也是能 够 用上的。但 为 什么 执 行的 时 候特 别 慢呢,差不多要一个小 时 才能 执 行完。 |
|
没办法只能看Postgresql的执行计划分析了,一看大吃一惊。居然没有user的user_id没有用上索引。速度慢的原因是找到了。 |
那究竟是什么原因呢?所谓有果必有因,就是说肯定是哪个地方肯定有问题。 |
仔细比较两个表的字段,发现了一个可能的原因。就是user表的user_id是char(10),而data表的value是text类型。 |
发现了这个可疑点后,就改写sql,让条件的类型保持一致。 |
修改前sql: WHERE user_id = (SELECT value |
修改后sql: WHERE user_id = (SELECT value::char(10) |
修改后查看 执行计划,乖乖好了,用上了index了。执行时间就1分钟多一点,客户是相当高兴哦。呵呵 |
|
也 许 有的人会修改 为 :WHERE user_id::text = (SELECT value。 这 种改法效率是不高的,因 为 先要去做user_id字段 的 转 型 动 作,做了无用功。 |
|
从这 个例子我 们 可以得到启示: |
①数据设计的时候,同样意义的字段的话,类型必须保持一致。 |
②有很多场合由于功能的关系,类型是不一致的,如果这个时候出现效率问题,可以在 sql把数据少的一方的 类型转换成数据多的一方的类型。 |