V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
lux182
V2EX  ›  程序员

应该使用 select * 吗?

  •  
  •   lux182 · 2020-08-04 11:09:47 +08:00 · 8732 次点击
    这是一个创建于 1566 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在使用同样索引,同样需要回表查询的情况下,应该使用

    1. select * 还是 2. select 字段,字段,...

    我能想到的使用后者的优点可能就是节省那么一点点带宽,

    缺点是极大的影响开发效率和维护难度,并且 mapper 文件难看,难懂

    72 条回复    2020-08-06 09:23:11 +08:00
    chenset
        1
    chenset  
       2020-08-04 11:14:38 +08:00
    1.特别需要注意性能与并发或者大 text 字段的时候就列出字段

    2.其他情况直接*

    两者不误
    clf
        2
    clf  
       2020-08-04 11:18:42 +08:00
    现在大部分 select 操作应该都是 orm 框架帮我们处理了?

    对于少数的自己写的查询,我一般都是 select 字段,字段,字段 这样对应自己定义的对象来处理。(反正都是用 navicat 的查询构造器来写的,勾选一下参数的事情,不需要特别麻烦。
    lux182
        3
    lux182  
    OP
       2020-08-04 11:19:01 +08:00
    @chenset 同意,现在市面上好多不分青红皂白都建议列举所有字段
    lux182
        4
    lux182  
    OP
       2020-08-04 11:22:33 +08:00
    @lychs1998 我感觉最近几年项目用 orm 反而少了。用工具构造查询是挺方便,缺点就是每次修改数据库就要在代码里 review 一遍。而且字段列举很多让人看的不舒服
    piecehealth
        5
    piecehealth  
       2020-08-04 11:23:06 +08:00
    遇到过一次玄幻的事,用的 PostgreSQL 9+,select 字段...(字段不全是索引列) 跟 select * 用的索引不一样( pg 没法指定索引),select * 用的是效率高的索引。
    cruii
        6
    cruii  
       2020-08-04 11:24:27 +08:00
    我觉得把字段写清楚更好看,能让别人清楚的知道,你想拿哪些数据。
    CrazyEight
        7
    CrazyEight  
       2020-08-04 11:24:53 +08:00
    select *用不到索引覆盖,而且字段过多会占用更多的 joinBuffer 会导致表连接变慢
    lux182
        8
    lux182  
    OP
       2020-08-04 11:29:26 +08:00
    @piecehealth select * 会有索引优化器选择合适的索引吧?
    lux182
        9
    lux182  
    OP
       2020-08-04 11:33:39 +08:00
    @cruii 当字段只有 3 、5 个时候比较清楚,当字段 10 多个以上时候,我觉得不如我直接看 model,还有注释呢
    lux182
        10
    lux182  
    OP
       2020-08-04 11:35:34 +08:00
    @CrazyEight 已经说明了不考虑覆盖索引,实际情况覆盖索引使用的字段也很少,基本不超过 3 个。joinBuffer 这个触及知识盲点
    Vegetable
        11
    Vegetable  
       2020-08-04 11:36:14 +08:00
    不推荐 select * ,不是因为性能问题,而是你没法控制 * 代表了什么,你的代码有可能会依赖数据库结构而不自知。
    lux182
        12
    lux182  
    OP
       2020-08-04 11:40:06 +08:00
    @Vegetable 可以举个例子吗?
    xuanbg
        13
    xuanbg  
       2020-08-04 11:41:12 +08:00
    一般都是*,特殊情况列出字段
    InkAndBanner
        14
    InkAndBanner  
       2020-08-04 11:43:31 +08:00
    还是写清楚更好 用啥拿啥
    lux182
        15
    lux182  
    OP
       2020-08-04 11:44:27 +08:00
    @xuanbg 我也是这样用的。接触的传统型公司反而是列出字段的居多,比如恒生,他们会用工具生成一系列 mapper,service,里面各种条件表达式。说实话还不如自己写
    stabc
        16
    stabc  
       2020-08-04 11:48:03 +08:00
    我一般是排除比较大的字段,但是 SQL 语句目前没法简单的排除字段
    ragnaroks
        17
    ragnaroks  
       2020-08-04 11:48:48 +08:00
    手动查询用"*",代码里面指定字段,因为有自动步枪
    yuanbo6
        18
    yuanbo6  
       2020-08-04 11:49:34 +08:00
    前一阵看了一个文章说还是推荐带字段,原因太长我给忘了……
    yc8332
        19
    yc8332  
       2020-08-04 11:49:47 +08:00
    这个要看吧。。如果没差几个字段,又不是大字段。。无所谓
    superrichman
        20
    superrichman  
       2020-08-04 11:50:05 +08:00 via iPhone
    在我这里你敢用 select *会被打死的 /doge
    meeop
        21
    meeop  
       2020-08-04 11:50:12 +08:00
    我的原则是在性能不是问题时注重开发效率,性能有问题在考虑优化
    绝大多数场景性能都不是问题,所以放心用 select * 除非是有 orm 帮你生成
    Jackeriss
        23
    Jackeriss  
       2020-08-04 12:45:10 +08:00 via iPhone
    *能不用就不用,就像 import *一样,谁知道你的*里有什么?
    Jooooooooo
        24
    Jooooooooo  
       2020-08-04 12:57:33 +08:00
    如果是真的要捞出全部字段就用

    数据库对 * 有专门的优化
    vindac
        25
    vindac  
       2020-08-04 13:22:30 +08:00
    额,我们又上百个字段的表从其中取五六十个,都是 select *
    lolizeppelin
        26
    lolizeppelin  
       2020-08-04 13:39:01 +08:00
    不说其他的 一旦你数据库表字段有增加,所有对这个表 select*的代码部分都要改

    如果只是写点小东西, 无所谓
    lux182
        27
    lux182  
    OP
       2020-08-04 13:44:56 +08:00
    @superrichman 所以啊,你的原因是?
    VictorJing94
        28
    VictorJing94  
       2020-08-04 13:46:14 +08:00
    不应该,虽然我经常用,数据库栏位变动会导致*到的数据不可控
    lux182
        29
    lux182  
    OP
       2020-08-04 13:50:17 +08:00
    @lolizeppelin 字段增加,增加 model 字段不就可以吗?
    lux182
        30
    lux182  
    OP
       2020-08-04 13:51:32 +08:00
    @VictorJing94 这里可控是为了什么?作为底层 service 在对外暴漏的时候还有一层转换的啊
    lolizeppelin
        31
    lolizeppelin  
       2020-08-04 13:58:32 +08:00
    @lux182

    新字段不在最后一行的时候,你 model 全乱

    遇到需要热更需要先升级数据库,再慢慢升级程序的时候,你 select*咋搞
    lolizeppelin
        32
    lolizeppelin  
       2020-08-04 14:03:18 +08:00
    @lux182

    如果你只想抬杠,或者就是要说 select*好,那么你赢了

    如果不是,我建议你多看看大型项目,好好理解下那些看上去多余的做法
    很多做法在小项目里是不需要的,大型项目周期长迭代多,很多看上去东西都是为了解决版本迭代更新兼容

    你随手写点东西,压根就不用考虑迭代更新兼容,甚至不用考虑单元测试
    自然很多做法就是多余的,禁止 select*就是基础中的基础
    wuketidai
        33
    wuketidai  
       2020-08-04 14:05:18 +08:00
    显示优于隐式
    brader
        34
    brader  
       2020-08-04 14:06:18 +08:00
    @lux182 字段增加,增加 model 字段不就可以吗?
    我想你对这里有个狭隘的误会,不同语言中,是有不同表现的,对于一些语言,数据库增加字段,是不需要去代码的 model 增加字段的。
    admol
        35
    admol  
       2020-08-04 14:14:38 +08:00   ❤️ 4
    想象一个场景, 你有一个接口, 每秒有非常多用户的来请求, 你后面的逻辑涉及到数据库语句写的是 select * ; 平时这可能没有任何问题, 但是有一天产品需求发生变化, 你的数据库需要添加一个字段, 并且这个字段需要返回, 请问你应该怎样来开发这个功能并上线?
    先上数据库 DML 语句还是先上你的代码?
    如果先上数据库, 你线上代码还是老的, 还没有那个新的字段, 代码全是 select * , 而你与之对应的 model 肯定是没有这个字段, 如何与它映射? 是否会报错? java 的 mybatis 至少会.
    如果先上代码, 加入你有 10 台服务器呢, 代码上线, 请求进来之后全是找不到新字段.

    如果之前你这个表涉及的 SQL 语句全部都是指定字段 select c1,c2,c3 from table , 那你就可以放心大胆的先让 DBA 给你添加表字段, 然后慢慢上线你的服务, 这部分至少不会有什么问题
    hello826
        36
    hello826  
       2020-08-04 14:14:54 +08:00
    那为啥阿里的 java 开发手册,第五章 Mysql 数据库,第三小节 sql 语句
    [强制] 不要使用 count(列名)或 count(常量)来替代 count(*),count(*)是 SQL92 定义的标
    准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。
    这个 mysql 实战也是推荐使用 count(*)
    hello826
        37
    hello826  
       2020-08-04 14:15:18 +08:00
    dddd1919
        38
    dddd1919  
       2020-08-04 14:17:14 +08:00
    如果需要所有字段,区别不大。
    如果只需要部分列的话最好显示声明要返回的字段,省带宽性能更好使用稳定。
    显示声明字段还有个好处就是如果字段全部在索引中,可以直接从索引返回结果
    wangritian
        39
    wangritian  
       2020-08-04 14:22:29 +08:00
    开发时间特别紧用*,否则好好写
    MeteorCat
        40
    MeteorCat  
       2020-08-04 14:26:09 +08:00 via Android
    大表筛选不要用,小表筛选可以用;开发阶段尽量用*,正式验收尽量不要用*;
    有时候项目需求文档很多版本,这样加个*直接获取比较方便
    panhongx
        41
    panhongx  
       2020-08-04 14:28:30 +08:00
    @hello826 你好像审错题了
    gz911122
        42
    gz911122  
       2020-08-04 14:33:32 +08:00
    @lolizeppelin 跟顺序有什么关系啊?
    lux182
        43
    lux182  
    OP
       2020-08-04 14:52:22 +08:00
    @lolizeppelin
    @gz911122 没遇到影响顺序的场景
    lux182
        44
    lux182  
    OP
       2020-08-04 14:58:39 +08:00   ❤️ 1
    @lolizeppelin
    ”新字段不在最后一行的时候,你 model 全乱“ ,这点我一直没遇到过,你的场景是什么啊,用的什么框架?
    ”遇到需要热更需要先升级数据库,再慢慢升级程序的时候,你 select*咋搞” ,这种情况也是比较常见的,我们也经常先更新数据库,后上程序的。所以还是不知道你的场景。
    所以你说的这几点没有说服力。
    lux182
        45
    lux182  
    OP
       2020-08-04 14:59:54 +08:00
    @brader 不是语言的问题,而是框架设计问题。我看过一些 python 程序员喜欢直接拿数据库 map 结果返回前端
    lux182
        46
    lux182  
    OP
       2020-08-04 15:09:25 +08:00   ❤️ 2
    @admol “如果先上数据库, 你线上代码还是老的, 还没有那个新的字段, 代码全是 select * , 而你与之对应的 model 肯定是没有这个字段, 如何与它映射? 是否会报错? java 的 mybatis 至少会.”
    我使用过程中,这种情形很多,mybatis 不会报错的
    lolizeppelin
        47
    lolizeppelin  
       2020-08-04 15:11:09 +08:00
    @lux182
    那我知道了
    框架里 map 字段,压根就不需要你关心是 select*还是 select 字段
    wakzz
        48
    wakzz  
       2020-08-04 15:18:19 +08:00
    单单考虑业务的问题,也不建议用 select *,因为一旦业务变更数据库新增字段,就会导致线上程序 sql 映射错误,不好向前兼容。
    gz911122
        49
    gz911122  
       2020-08-04 16:47:47 +08:00
    @wakzz 新增字段无影响吧?
    为什么会导致映射错误呢?
    VictorJing94
        50
    VictorJing94  
       2020-08-04 17:03:00 +08:00
    @lux182 楼下说清楚了.......应该不需要我再重复了吧
    useben
        51
    useben  
       2020-08-04 17:07:27 +08:00
    看查询的索引类型, 不同不同处理
    wangbudong
        52
    wangbudong  
       2020-08-04 19:09:18 +08:00
    没有性能问题的情况下,也就是不会导致 io 阻塞的情况都可以用 select * ,至于说啥迭代,数据库和 entity 的关系处理好了,只需要改 entity 和数据库,不用 orm 也可以
    1069401249
        53
    1069401249  
       2020-08-04 19:20:34 +08:00
    谁用 select *我直接打死,占 io 内存,大列表的时候 select*有几次导致内存爆掉了
    akira
        54
    akira  
       2020-08-04 19:52:24 +08:00
    小项目随便你怎么写都行。 稍微有点量的项目 还是别用 select *了,回头逐个地方修改还是挺麻烦的
    realpg
        55
    realpg  
       2020-08-04 21:07:15 +08:00
    结合实际,没有一杆子打死。
    性能,吞吐,负载综合考虑。
    CEBBCAT
        56
    CEBBCAT  
       2020-08-04 21:08:57 +08:00 via Android
    谢邀,Golang 选手,SQL 手写
    DelayNoMay
        57
    DelayNoMay  
       2020-08-04 21:11:03 +08:00
    用 * 的话,数据库新增一个字段就报 scan error 了
    blockmin
        58
    blockmin  
       2020-08-04 21:16:17 +08:00
    测试的时候数据都是几亿条,用 select * 的话下游团队会砍死我们的
    crclz
        59
    crclz  
       2020-08-04 21:40:09 +08:00
    事务类的操作,用 ORM,例如 SpringDataJpa 的 repository
    查询类的操作,用 select*,外加 ModelMapper ( java )或者 AutoMapper ( c#)之类的工具.

    对于大字段,请将表拆分。
    woshipanghu
        60
    woshipanghu  
       2020-08-04 21:55:59 +08:00
    说实话 你写的严谨一点那是不用*
    实际开发的时候用*没什么问题 不要有敏感字段暴露出去就行
    大部分项目不会因为加了*或没加*产生太大的影响
    读写多的几张表自然会想着去优化
    CrazyMoon
        61
    CrazyMoon  
       2020-08-04 21:57:59 +08:00
    这要看相关代码的动态能力。
    另外如果是列数据库,基本不能用它。
    stevenkang
        62
    stevenkang  
       2020-08-04 22:08:47 +08:00
    个人项目:select * —— 毕竟增减字段方便,自己的需求自己明白,只要快就行。
    公司项目:select 字段 —— 毕竟产品不来需求,字段绝笔不会去改,改起来费时间慢点就慢点,只要稳就行。
    tairan2006
        63
    tairan2006  
       2020-08-04 22:20:55 +08:00
    单表查询一般都是 orm,join 的时候你跟我说你用 select *?

    不过做动态 sql 的时候只能用*,因为连表名都是动态传进来的。
    chihiro2014
        64
    chihiro2014  
       2020-08-05 02:00:15 +08:00
    其实可以去看看 CMU 数据库系统这块的 SQL 优化和索引部分
    https://www.bilibili.com/video/av85655193
    saberlong
        65
    saberlong  
       2020-08-05 08:40:58 +08:00 via Android
    代码上没碰到问题是因为用 orm 之类有映射功能的。原始的方式是和查询列顺序有关的。直接写*会导致这部分业务逻辑错误。写明列则只需修改需要增加列的地方。一个人了解所有项目是不可能的,允许随意使用*。那么发布时,可能就碰到惊喜。
    hxy91819
        66
    hxy91819  
       2020-08-05 09:03:00 +08:00
    在关注性能的业务场景下,任何情况都严禁使用。
    lux182
        67
    lux182  
    OP
       2020-08-05 10:42:38 +08:00
    @1069401249 上面还有一个也这样说,"把 xxx 打死",我想你是做领导做久了吧。
    okjb
        68
    okjb  
       2020-08-05 12:00:23 +08:00 via Android
    跟使用场景有关。我自己私人查数据爱用检索全部字段。业务场景就检索特定字段。又说了一堆废话
    no1xsyzy
        69
    no1xsyzy  
       2020-08-05 12:48:55 +08:00
    @tairan2006 #63 join 也可以 select a.*, b.* 来着
    如果有重名不记得是报错还是自动重命名了
    no1xsyzy
        70
    no1xsyzy  
       2020-08-05 13:12:01 +08:00
    @lolizeppelin #31 你 model 不读字段名的吗?
    稍微瞄了眼 SQL92 没看到哪指明 <select list> 的顺序在结果中必须被保持。
    wolong
        71
    wolong  
       2020-08-05 23:50:27 +08:00
    先 select *一把梭,后期出现性能问题了再优化成 select 字段 1, 字段 2
    tairan2006
        72
    tairan2006  
       2020-08-06 09:23:11 +08:00
    @no1xsyzy mysql 会报错,有歧义
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3008 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 38ms · UTC 13:41 · PVG 21:41 · LAX 05:41 · JFK 08:41
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.