应该使用 select * 吗? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
lux182
V2EX    程序员

应该使用 select * 吗?

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

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

    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  
    PRO
       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     Solana     945 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 22:50 PVG 06:50 LAX 14:50 JFK 17:50
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86