V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MySQL 5.5 Community Server
MySQL 5.6 Community Server
Percona Configuration Wizard
XtraBackup 搭建主从复制
Great Sites on MySQL
Percona
MySQL Performance Blog
Severalnines
推荐管理工具
Sequel Pro
phpMyAdmin
推荐书目
MySQL Cookbook
MySQL 相关项目
MariaDB
Drizzle
参考文档
http://mysql-python.sourceforge.net/MySQLdb.html
mostkia
V2EX  ›  MySQL

Mysql 多个字段有唯一约束,写入时如果有重复的,如何知道哪个字段重复了?

  •  
  •   mostkia · 2018-06-19 20:51:40 +08:00 · 5177 次点击
    这是一个创建于 2379 天前的主题,其中的信息可能已经有所发展或是发生改变。

    RT。。我是通过 PHP 的 pdo 方式来获取 mysql 的返回值的。其实也没什么特殊的使用场景,就是想写一个注册功能,注册时让用户知道是哪个参数重复了(比如用户名、电话、邮箱)等这些不允许重复的字段。因为默认 mysql 只会返回 23000 错误码,并不会返回具体哪一个字段重复了。

    考虑过先 select 多条件查找,发现了后返回给 php 提示用户,如果没发现有重复的内容则再使用 php 访问数据库写入,但这样就访问了数据库 2 次了,对性能不太友好,也不优雅。可能是我比较笨吧,想来想去没什么好办法。

    原谅我只是个前端,对 sql 只会简单的读写。虚心请教一下,是否有 SQL 语法可以做到。

    thread2
        1
    thread2  
       2018-06-19 21:25:02 +08:00 via Android
    用户填完“用户名、电话、邮箱”后,点击提交前,异步查询下,如果重复则提示,如果不重复则允许提交
    mostkia
        2
    mostkia  
    OP
       2018-06-19 21:45:12 +08:00
    @thread2 恩,感谢你的回答,这也是一个思路,这样的话鼠标离开输入框,激活一个 ajax 事件,后台直接 select 当前输入框参数,就能知道哪个重复了,而后台使用唯一约束让前台进行这方面的过滤也不会存在安全问题。但性能方面应该和我的方法差不多吧,区别只是一个放在前台分散验证,而我的方法是上传后在后台集中验证。如果能一次访问是不是更好呢?
    thread2
        3
    thread2  
       2018-06-19 21:47:15 +08:00 via Android
    @mostkia 用户体验稍微好点
    soho176
        4
    soho176  
       2018-06-19 22:57:19 +08:00
    这不就是每个网站 最基本的注册功能吗
    torbrowserbridge
        5
    torbrowserbridge  
       2018-06-19 22:58:43 +08:00
    获取并解析 mysql 的错误信息可实现。不过代价大了一点。
    watzds
        6
    watzds  
       2018-06-19 23:00:52 +08:00 via Android
    这有啥性能问题,注册量这么大就好了
    letitbesqzr
        7
    letitbesqzr  
       2018-06-19 23:04:32 +08:00
    我们项目是绝对不允许这些错误让 mysql 处理的,加唯一约束只是为了查询速度,事先用代码一个个的条件的判断好,有一步错误就返回,sql exception 属于是绝对意外的异常了。
    947211232
        8
    947211232  
       2018-06-19 23:12:46 +08:00
    应该有获取错误信息的函数方法的,否则真的不可思议了——根据错误信息设置你要返回前端的消息提示
    mostkia
        9
    mostkia  
    OP
       2018-06-19 23:25:48 +08:00
    @watzds @letitbesqzr 恩,也就是说,让 mysql 一个一个条件的 select 这样查找,数据库时可行的是吗?如果这样的话,假设有 3 个字段需要判断(一般都至少有 3 个,邮箱,用户名,电话等),那至少要读写数据库 4 次( 3 次判断,没问题写入 1 次),高并发情况下我觉得也太多了。。当然注册一般没那么多并发,只是对于数据库这样使用还是心存疑惑,感觉这种方法好笨...哈哈,可能是我太多虑了吧。回头写一下吧,出问题再说。。感谢所有回答的朋友了。
    msg7086
        10
    msg7086  
       2018-06-20 01:02:43 +08:00
    > 访问了数据库 2 次了,对性能不太友好

    能不能说说访问两次对性能产生了多少影响?
    msg7086
        11
    msg7086  
       2018-06-20 01:11:31 +08:00   ❤️ 1
    你看,数据库如果放在 SSD 上跑的话,1000qps 轻轻松松。假设其中有 50qps 分给注册,那你一秒钟能承受 25 个新用户注册,一天下来可以跑 100 万新注册用户,一个月就是 3 千万。

    你要有了 3 千万新用户,不买个更好点的服务器么……

    数据库优化的时候去关注这种带索引查询的性能意义很小。N+1 或者无索引查询优化才是应该关注的地方。
    mostkia
        12
    mostkia  
    OP
       2018-06-20 08:10:17 +08:00 via Android
    @msg7086 我只是觉得可能有更好的办法,毕竟新手,有时候对自己想到的办法还是不太自信,结果似乎大家都是和我一样的做法,那我也没什么问题了,直接这样老老实实一步一步判断就行了。性能问题也是我想当然的,理解肯定不及各位常年使用数据库的大佬,还是谢谢各位解答的朋友了。能百忙之中回答我的问题就很感谢了。
    q397064399
        13
    q397064399  
       2018-06-20 09:02:18 +08:00   ❤️ 1
    @mostkia #12 原谅我爆个粗口,, 扯什么鸡巴蛋的性能问题,MySQL 单表少于 5 亿,不要瞎几把谈性能问题,有空可以去研究其它的东西,内存回收 分布式系统,在代码层面上依赖数据库的报错机制本身就有问题,能在应用层干掉的 就要在应用层干掉,数据库是存储数据的,不是给你弄业务逻辑的,最烦那种写存储过程的,这种东西本来就应该是应用干的事情,职责要明确。
    liuzhedash
        14
    liuzhedash  
       2018-06-20 09:07:34 +08:00
    @mostkia #9
    胸弟,只要你正确加了索引就完全可行,乘以 10 都没问题。
    hand515
        15
    hand515  
       2018-06-20 09:47:20 +08:00
    怕网络次数多影响性能,那就用 union all 或者 OR 查询,一次提交
    watzds
        16
    watzds  
       2018-06-20 09:48:02 +08:00 via Android
    @mostkia 可以 where a =? OR b = ?
    mostkia
        17
    mostkia  
    OP
       2018-06-20 13:01:27 +08:00
    @q397064399 额。。这位兄台可能对数据库有着很深的执念啊....又难道我是发了一个不可理喻的问题?我虽然只是个前端,对于数据库设计也并不熟悉。但追求更好的写法,避免自己一个人造轮子踩坑应该没什么原罪吧。。依我的看法,不要说 5 亿数据的表了,表的优化没事先做好,数据量能超过百万还能用就很看人品了,数据库的优化应该事先做好,而不是等到出性能问题了再改表,到时候可能数据多了也不好改的,所以就请教一下而已。。。
    结贴了。结贴了,手动下沉。。一直挂在顶部,指不定等一下又碰到几个暴躁老哥呢。。 =_=
    mostkia
        18
    mostkia  
    OP
       2018-06-20 13:09:22 +08:00
    @liuzhedash 好的,谢谢,已经按照楼上几位大佬的方案写好了控制后台了。。
    msg7086
        19
    msg7086  
       2018-06-20 15:45:59 +08:00
    @mostkia 数据库优化其实不需要「事先」做好,而是应该跑起业务做压测以后再看哪些地方是性能瓶颈,然后再集中优化。你现在思考的问题属于过早优化,90%的场景下是浪费时间,剩下最多 10%碰巧被你优化上了。

    记住这句话:

    Premature optimization is the root of all evil.
    mostkia
        20
    mostkia  
    OP
       2018-06-20 16:14:58 +08:00
    @msg7086 基础的应该做好准备吧,比如加索引什么的。我查资料的时候,看到翻车的太多太多了,都是一开始写的不好,然后到处问。。唉,也是看怕了。随便从浏览器历史记录里翻出来了几个案例...
    https://bbs.csdn.net/topics/90035915
    https://bbs.csdn.net/topics/392091851?page=1
    他们的数据库 10W 条就炸了。所以按这些案例来讲,我仍旧认为初期那些基础的优化还是有些必要的。当然这不是这个帖子要讨论的主题。。这个帖子似乎讨论方向一直朝着奇怪的方向前进着。。掰都掰不回来,其实我已经在 12、18 楼接受了各位大佬的看法并已经明确放弃使用 sql 语法来写了,转而使用 php 直接做逻辑层,现在代码都写好了,但关于性能的讨论却没断过,哈哈,感觉自己是在钓鱼,也是 6 的不行。
    mostkia
        21
    mostkia  
    OP
       2018-06-20 16:46:14 +08:00
    可能也是自己的说法有问题吧,明明只是想求一个 sql 语法,但却去强调了一下性能,其实性能倒是其次,我只是觉一个一个的 select 得这个方法实在是太笨了而已,需要多次请求数据库,从而连带的做了性能方面的猜想(其实就是我不了解数 mysql 据库造成的)但到最后这帖子变成了完全的性能方面的讨论,也实在是超出了我的预期。。而回复 sql 语法的也只有 16 楼。哈哈,尴尬了。。当然各位大佬说的都是经验只谈,比我瞎猜的肯定要靠谱,我个人感觉也的确有所收获,至少以后不会再去纠结性能问题。
    msg7086
        22
    msg7086  
       2018-06-20 23:50:23 +08:00
    @mostkia 加索引随时都可以加,一般看慢查询日志就行了。
    前期加索引也不见得就是好,因为索引除了读取收益以外,还有写入开销。
    有时候你甚至会发现加了索引后比原来还慢的。
    还是要具体分析具体解决。

    至于 10 万炸,这种是因为「不懂」,而不是因为「没有加索引」。
    这种「不懂」的人,就算一开始就加上索引,性能也会一样一团糟。
    因为你的语句可能压根就用不上你点开的索引。

    至于第二个帖子,你看,那么长的 SQL,恰恰是 13 楼说的把数据库当成运算器来跑的典型案例。
    这种如果全部转换成单个查询(就是你说的访问数据库多次的方法)反而性能会好得多。

    这帖子的本质问题还是在优化,提出的问题是很值得深思和讨论的,我觉得比单单一个 SQL 语句要有价值得多。
    mostkia
        23
    mostkia  
    OP
       2018-06-21 00:16:35 +08:00
    @msg7086 也是,对于我这个程度的,能用就好,不用太纠结这些事情,毕竟接触数据库的机会也不多,慢日志和类二进制日志也完全没去了解过,哈哈。不过现在程序也写完了,跑起来也不错,也不管这破事了,有时候写代码往往会去纠结一些奇怪的地方,现在想想,不就是多几次查询嘛,怕网络性能问题集中在一起让后台查询即可。这帖子也让我对数据库在用法上有了更多了解。至少对使用上的误区有了大致的概念。
    其实我更想在项目中使用的是 MongoDB 这类非关系数据库,写法比较接近前端常用的 json,对前台更友好一些,但无奈项目使用什么程序不是我说了定的,哈哈有些遗憾。再次谢谢所有回答的朋友了,不管是批评的还是指点的。结贴吧,结贴吧。认真脸  ̄▽ ̄
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5886 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 43ms · UTC 02:02 · PVG 10:02 · LAX 18:02 · JFK 21:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.