关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » MySQL »MySQL的10件事—它们也许和你预想的不一样

    MySQL的10件事—它们也许和你预想的不一样

    2010-11-12 08:54:00 出处:ITJS
    分享

    #10. 搜索一个“NULL”值 

    SELECT  *  FROM    a  WHERE   a.column = NULL 

    在SQL中,NULL什么也不等于,而且NULL也不等于NULL。这个查询不会返回任何结果的,实际上,当构建那个plan的时候,优化器会把这样的语句优化掉。

    当搜索NULL值的时候,应该使用这样的查询:

    SELECT  *  FROM    a  WHERE   a.column IS NULL 

    #9. 使用附加条件的LEFT JOIN

    SELECT  *  FROM    a  LEFT JOIN         b  ON      b.a = a.id  WHERE   b.column = 'something' 

    除了从a返回每个记录(至少一次),当没有真正匹配的记录的时候,用NULL值代替缺失的字段之外,LEFT JOIN和INNER JOIN都是一样的。

    但是,在LEFT JOIN之后才会检查WHERE条件,所以,上面这个查询在连接之后才会检查column。就像我们刚才了解到的那样,非NULL值才可以满足相等条件,所以,在a的记录中,那些在b中没有对应的条目的记录不可避免地要被过滤掉。

    从本质上来说,这个查询是一个INNER JOIN,只是效率要低一些。

    为了真正地匹配满足b.column = 'something'条件的记录(这时要返回a中的全部记录,也就是说,不过滤掉那些在b中没有对应的条目的记录),这个条件应该放在ON子句中:

    SELECT  *  FROM    a  LEFT JOIN         b  ON      b.a = a.id          AND b.column = 'something' 

    #8. 小于一个值,但是不为NULL

    我经常看到这样的查询:

    SELECT  *  FROM    b  WHERE   b.column < 'something'        AND b.column IS NOT NULL 

    实际上,这并不是一个错误:这个查询是有效的,是故意这样做的。但是,这里的IS NOT NULL是冗余的。

    如果b.column是NULL,那么无法满足b.column < 'something'这个条件,因为任何一个和NULL进行的比较都会被判定为布尔NULL,是不会通过过滤器的。

    有趣的是,这个附加的NULL检查不能和“大于”查询(例如:b.column > 'something')一起使用。

    这是因为,在MySQL中,在ORDER BY的时候,NULL会排在前面,因此,一些人错误地认为NULL比任何其他的值都要小。

    这个查询可以被简化:

    SELECT  *  FROM    b  WHERE   b.column < 'something' 

    在b.column中,不可能返回NULL

    #7. 按照NULL来进行连接

    SELECT  *  FROM    a  JOIN    b  ON      a.column = b.column 

    在两个表中,当column是nullable的时候,这个查询不会返回两个字段都是NULL的记录,原因如上所述:两个NULL并不相等。

    这个查询应该这样来写:

    SELECT  *  FROM    a  JOIN    b  ON      a.column = b.column         OR (a.column IS NULL AND b.column IS NULL) 

    MySQL的优化器会把这个查询当成一个“等值连接”,然后提供一个特殊的连接条件:ref_or_null

    #6. NOT IN和NULL值

    SELECT  a.*  FROM    a  WHERE   a.column NOT IN         (          SELECT column         FROM    b          ) 

    如果在b.column中有一个NULL值,那么这个查询是不会返回任何结果的。和其他谓词一样,IN  和 NOT IN 遇到NULL也会被判定为NULL。

    你应该使用NOT EXISTS重写这个查询:

    SELECT  a.*  FROM    a  WHERE   NOT EXISTS          (          SELECT NULL         FROM    b         WHERE   b.column = a.column        ) 

    不像IN,EXISTS总是被判定为true或false的。

    #5. 对随机的样本进行排序

    SELECT  *  FROM    a  ORDER BY         RAND(), column LIMIT 10 

    这个查询试图选出10个随机的记录,按照column来排序。

    ORDER BY会按照自然顺序来对输出结果进行排序:这就是说,当第一个表达式的值相等的时候,这些记录才会按照第二个表达式来排序。

    但是,RAND()的结果是随机的。要让RAND()的值相等是行不通的,所以,按照RAND()排序以后,再按照column来排序也是没有意义的。

    要对随机的样本记录进行排序,可以使用这个查询:

    SELECT  *  FROM    (          SELECT  *          FROM    mytable          ORDER BY                 RAND()          LIMIT 10         ) q  ORDER BY        column 

    #4. 通过一个组来选取任意的记录

    这个查询打算通过某个组(定义为grouper来)来选出一些记录

    SELECT  DISTINCT(grouper), a.*  FROM    a 

    DISTINCT不是一个函数,它是SELECT子句的一部分。它会应用到SELECT列表中的所有列,实际上,这里的括号是可以省略的。所以,这个查询可能会选出grouper中的值都相同的记录(如果在其他列中,至少有一个列的值是不同的)。

    有时,这个查询可以正常地使用( 这主要依赖于MySQL对GROUP BY的扩展):

    SELECT  a.*  FROM    a  GROUP BY         grouper 

    在某个组中返回的非聚合的列可以被任意地使用。

    首先,这似乎是一个很好的解决方案,但是,它存在着一个很严重的缺陷。它依赖于这样一个假设:虽然可以通过组来任意地获取,但是返回的所有值都要属于一条记录。

    虽然当前的实现似乎就是这样的,但是它并没有文档化,无论何时,它都有可能被改变(尤其是,当MySQL学会了在GROUP BY的后面使用index_union的时候)。所以依赖于这个行为并不安全。

    如果MySQL支持分析函数的话,这个查询可以很容易地用另一种更清晰的方式来重写。但是,如果这张表拥有一个PRIMARY KEY的话,即使不使用分析函数,也可以做到这一点:

    SELECT  a.*  FROM    (          SELECT  DISTINCT grouper          FROM    a          ) ao  JOIN    a  ON      a.id =          (          SELECT  id         FROM    a ai          WHERE   ai.grouper = ao.grouper          LIMIT 1          ) 

    #3. 通过一个组来选取第一条记录

    把前面那个查询稍微变化一下:

    SELECT  a.*  FROM    a  GROUP BY         grouper  ORDER BY         MIN(id) DESC 

    和前面那个查询不同,这个查询试图选出id值最小的记录。

    同样:无法保证通过a.*返回的非聚合的值都属于id值最小的那条记录(或者任意一条记录)

    这样做会更清晰一些:

    SELECT  a.*  FROM    (          SELECT  DISTINCT grouper         FROM    a          ) ao  JOIN    a  ON      a.id =          (          SELECT  id          FROM    a ai          WHERE   ai.grouper = ao.grouper          ORDER BY                 ai.grouper, ai.id          LIMIT 1          ) 

    这个查询和前面那个查询类似,但是使用额外的ORDER BY可以确保按id来排序的第一条记录会被返回。

    #2. IN和‘,’——值的分隔列表

    这个查询试图让column的值匹配用‘,’分隔的字符串中的任意一个值:

    SELECT  *  FROM    a  WHERE   column IN ('1, 2, 3') 

    这不会正常发挥作用的,因为在IN列表中,那个字符串并不会被展开。

    如果列column是一个VARCHAR,那么它(作为一个字符串)会和整个列表(也作为一个字符串)进行比较,当然,这不可能匹配。如果 column是某个数值类型,那么这个列表会被强制转换为那种数值类型(在最好的情况下,只有第一项会匹配)

    处理这个查询的正确方法应该是使用合适的IN列表来重写它:

    SELECT  *  FROM    a  WHERE   column IN (1, 2, 3) 

    或者,也可以使用内联:

    SELECT  *  FROM    (          SELECT  1 AS id          UNION ALL         SELECT  2 AS id          UNION ALL         SELECT  3 AS id          ) q  JOIN    a  ON      a.column = q.id 

    但是,有时这是不可能的。

    如果不想改变那个查询的参数,可以使用FIND_IN_SET:

    SELECT  *  FROM    a  WHERE   FIND_IN_SET(column, '1,2,3') 

    但是,这个函数不可以利用索引从表中检索行,会在a上执行全表扫描。

    #1. LEFT JOIN和COUNT(*)

    SELECT  a.id, COUNT(*)  FROM    a  LEFT JOIN         b  ON      b.a = a.id  GROUP BY         a.id 

    这个查询试图统计出对于a中的每条记录来说,在b中匹配的记录的数目。

    问题是,在这样一个查询中,COUNT(*)永远不会返回一个0。对于a中某条记录来说,如果没有匹配的记录,那么那条记录还是会被返回和计数。

    只有需要统计b中的记录数目的时候才应该使用COUNT。既然可以使用COUNT(*),那么我们也可以使用一个参数来调用它(忽略掉NULL),我们可以把b.a传递给它。在这个例子中,作为一个连接主键,它不可以为空,但是如果不想匹配,它也可以为空。

    原文标题:10 things in MySQL (that won’t work as expected)

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    抖音安全与信任开放日:揭秘推荐算法,告别单一标签依赖

    ultraedit编辑器打开文件时,总是提示是否转换为DOS格式,如何关闭?

    Cornell大神Kleinberg的经典教材《算法设计》是最好入门的算法教材

    从 Microsoft 下载中心安装 Windows 7 SP1 和 Windows Server 2008 R2 SP1 之前要执行的步骤

    Llama 2基于UCloud UK8S的创新应用

    火山引擎DataTester:如何使用A/B测试优化全域营销效果

    腾讯云、移动云继阿里云降价后宣布大幅度降价

    字节跳动数据平台论文被ICDE2023国际顶会收录,将通过火山引擎开放相关成果

    这个话题被围观超10000次,火山引擎VeDI如此解答

    误删库怎么办?火山引擎DataLeap“3招”守护数据安全

    IT头条

    平替CUDA!摩尔线程发布MUSA 4性能分析工具

    00:43

    三起案件揭开侵犯个人信息犯罪的黑灰产业链

    13:59

    百度三年开放2.1万实习岗,全力培育AI领域未来领袖

    00:36

    工信部:一季度,电信业务总量同比增长7.7%,业务收入累计完成4469亿元

    23:42

    Gartner:2024年全球半导体营收6559亿美元,AI助力英伟达首登榜首

    18:04

    技术热点

    iOS 8 中如何集成 Touch ID 功能

    windows7系统中鼠标滑轮键(中键)的快捷应用

    MySQL数据库的23个特别注意的安全事项

    Kruskal 最小生成树算法

    Ubuntu 14.10上安装新的字体图文教程

    Ubuntu14更新后无法进入系统卡在光标界面解怎么办?

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。