ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

MySQL内置函数实战指南:高频用法与索引失效避坑解析

MySQL内置函数实战指南:高频用法与索引失效避坑解析 1. 内置函数的整体认知先搞清楚你在跟谁打交道MySQL的内置函数说白了就是数据库自己带好的一批“现成工具”你不需要自己写复杂的逻辑只要把数据丢进去它就能帮你完成字符串拼接、数值计算、日期转换、条件判断这些高频操作。日常写SQL的时候可能每个人都用过NOW()、COUNT()、IFNULL()但真到面试或者做复杂报表的时候很多人在函数选择上还是会犹豫CHAR_LENGTH和LENGTH到底有什么区别ROUND和FORMAT都能做四舍五入为什么结果不一样CASE WHEN和IF()在什么场景下不能互相替换这篇文章就是想把MySQL内置函数这件事讲透不是罗列文档而是从实际使用的角度拆开讲哪些函数最常用、哪些写法是常识但容易被忽略、哪些坑我是真实踩过的。适合刚接触SQL的初学者也适合写了好几年SQL但没系统梳理过函数的开发者和数据分析师。内置函数不是MySQL的专属概念但MySQL的函数体系在同类数据库里有很强的实际使用价值。我见过不少项目代码里写了一大堆字符串处理逻辑其实一条SQL加上SUBSTRING_INDEX加CAST就能搞定也见过报表系统因为不懂聚合函数与GROUP BY的执行顺序把统计逻辑拆到Java里循环算性能差了几十倍。搞清楚内置函数本质上是在帮自己减少不必要的代码量也让数据库少做无用功。MySQL内置函数大致可以分成几大类字符串函数、数值函数、日期时间函数、流程控制函数、聚合函数还有其他一些相对冷门的JSON函数、加密函数、信息函数。日常开发中前面五类占到了九成以上的使用场景所以下面的内容会沿着这个主线展开每个分类挑核心的讲并且把容易出错的地方一并点出来。2. 字符串函数用得最多也最容易想当然2.1 拼接、截取与长度计算的正确姿势字符串函数是所有内置函数里使用频率最高的一类。先说拼接CONCAT和CONCAT_WS是最常用的两个区别只在分隔符。CONCAT(a, b, c)得到abcCONCAT_WS(-, 2024, 01, 01)得到2024-01-01。CONCAT_WS的第一个参数是分隔符后面跟任意数量的待拼接字段如果某个字段为NULL它会直接跳过而不是拼出一个NULL这个特性在生成地址、拼接姓名时非常实用。很多人不知道CONCAT只要有一个参数为NULL整个结果就是NULL——这导致报表里经常出现某个字段空值就把整行内容带没了的情况。处理的办法是用IFNULL先兜底或者直接用CONCAT_WS。截取字符串的三个常用函数是SUBSTRING、LEFT、RIGHT。SUBSTRING(str, pos)从指定位置截到末尾SUBSTRING(str, pos, len)截取指定长度。这里有个值得注意的细节MySQL的字符串位置是从1开始的不是从0开始。LEFT(str, n)从左边取n个字符RIGHT(str, n)从右边取n个字符。至于SUBSTRING_INDEX(str, delim, count)它按分隔符截取count为正数表示从左往右数第count个分隔符之前的内容count为负数表示从右往左数。我在实际处理URL或者路径的时候非常依赖这个函数比如从/api/user/123/profile里提取用户ID一句SUBSTRING_INDEX(SUBSTRING_INDEX(url, /, 4), /, -1)就能搞定比写正则简单多了。长度计算是另一个隐藏坑点。CHAR_LENGTH返回的是字符数LENGTH返回的是字节数。只要字段里有中文、表情符号或其他多字节字符这两个函数的结果就会不一致。utf8mb4编码下一个中文字符占3个字节一个emoji占4个字节。如果你用LENGTH去判断用户输入的昵称是否超过20个字符很可能一个10个中文字的昵称就被误判为超长。所以涉及用户可见长度的判断统一用CHAR_LENGTH。2.2 替换、去空格、大小写与特殊格式处理REPLACE(str, from_str, to_str)做的是字符串替换经常用来清洗数据里的脏字符比如把电话号里的-去掉或者把\r\n替换成空。TRIM、LTRIM、RTRIM分别用来去除两侧、左侧、右侧空格。注意TRIM默认只去空格不去换行符和制表符。如果需要去掉字符串前后的特定字符可以用TRIM(BOTH , FROM str)这种扩展语法。我在导入Excel数据时经常跟这个函数打交道因为Excel里导出的数据经常带着肉眼看不见的换行和制表符先跑一遍REPLACE(REPLACE(col, \r, ), \n, )再TRIM数据瞬间干净。大小写转换的UPPER和LOWER比较简单但要留意字符集和排序规则。utf8mb4_general_ci这类不区分大小写的排序规则下字符串比较时不区分大小写所以WHERE name mysql能匹配到MySQL。如果需要强制区分可以用BINARY关键字或者把列定义成utf8mb4_bin。这块不算是函数本身的问题但跟函数的配合非常紧密——WHERE BINARY name mysql常常是排查大小写匹配问题时的关键手段。LPAD和RPAD是左填充和右填充常用于生成固定位数的编号比如订单号不足8位前面补0LPAD(order_no, 8, 0)。还有REVERSE反转字符串、SPACE生成空格串、REPEAT重复字符串这些冷门函数偶尔会在算法题或者特殊场景里发挥奇效。最后是FIND_IN_SET(str, strlist)它在第二个参数是一个逗号分隔的字符串列表时非常好用比LIKE %value%精准得多也不会误匹配。有人觉得它只能用在逗号分隔字段上算是设计不规范的无奈之选但作为只读逻辑它确实省事。3. 数值函数与类型转换别让小数精度毁掉你的报表3.1 ROUND、TRUNCATE、CEIL、FLOOR 的差异数值函数看起来简单实际上最容易在精度上翻车。ROUND(x, d)是四舍五入TRUNCATE(x, d)是直接截断CEIL向上取整FLOOR向下取整。举个例子ROUND(3.14159, 2)返回3.14TRUNCATE(3.14159, 2)返回3.14看起来一样但如果数字是3.14999ROUND结果是3.15TRUNCATE结果是3.14。报表系统里如果该用ROUND的地方用了TRUNCATE最后汇总出来的金额会少几分钱对账的时候很难查。CEIL和FLOOR没有小数位参数直接返回整数。CEIL(3.1)是4FLOOR(3.9)是3。注意CEIL对负数不是简单的“向上”因为MySQL的CEIL是朝着更大的方向取整所以CEIL(-3.1)的结果是-3而不是-4。这个细节我在分页计算总页数时遇到过CEIL(total / pageSize)对负数结果的影响不大但在一些数学计算逻辑中就很容易出问题。MOD(x, y)是取余数等价于x % y主要用于判断奇偶、周期分组等场景。ABS取绝对值POWER和SQRT分别是幂运算和平方根。RAND()生成0到1之间的随机数可以带随机种子RAND(100)配合ORDER BY能在每次查询时得到固定的随机顺序这在做抽奖或者每日推荐时很实用——只要种子不变结果就是稳定的方便复现和排查。3.2 隐式类型转换和 CAST/CONVERT数值函数不得不提类型转换。MySQL在比较不同类型的值时会做隐式转换但转换规则经常跟直觉相悖。如果phone列是VARCHAR你写WHERE phone 13800138000MySQL会尝试把字符串列转成数字来比较结果就是这一列无法使用索引全表扫描数据量大一点查询直接超时。正确写法是WHERE phone 13800138000让类型保持匹配。CAST(expr AS type)和CONVERT(expr, type)显式转换在需要精确控制类型时非常有用。比如把字符串转成日期再参与计算CAST(2024-01-01 AS DATE)或者把数值转成DECIMAL避免浮点误差CAST(3.14159 AS DECIMAL(10, 2))。用CAST时要注意把一个带小数的字符串转成整数会直接截断而不是四舍五入CAST(3.99 AS SIGNED)结果是3。如果你期望得到4要先ROUND再CAST。格式化场景里还有一个FORMAT(x, d)它返回的是带千分位分隔符的字符串比如FORMAT(1234567.891, 2)返回1,234,567.89。它本质上是“给人看”的函数不适合继续参与数值运算因为这个结果已经是字符串。这就是我说标题里“内置函数”看起来很基础但真用起来能让人栽跟头的地方。4. 日期时间函数统计SQL的绝对主角4.1 NOW()、SYSDATE()、CURRENT_TIMESTAMP 的微妙差异日期时间函数在报表统计里是绝对的主角也是坑最多的分类。最常见的是NOW()、CURRENT_TIMESTAMP、SYSDATE()这三兄弟。NOW()和CURRENT_TIMESTAMP返回的是语句开始执行的时间整条SQL不管跑多久这个时间都固定SYSDATE()返回的是函数被调用那一刻的时间一条超长SQL里如果多次调用SYSDATE()得到的结果甚至可能不同。主从复制场景下这是个隐患因为NOW()的时间是由binlog记录的SYSDATE()在MySQL 8.0.2之前可能破坏复制安全导致主库和从库数据不一致。日常开发中统一用NOW()就够了除非你确实需要“每一行获取当前真实时间”这种动态效果但这种情况极其罕见。CURDATE()返回当前日期、CURTIME()返回当前时间分别等价于DATE(NOW())和TIME(NOW())。日期加减用DATE_ADD和DATE_SUBDATE_ADD(NOW(), INTERVAL 1 DAY)表示明天此刻INTERVAL后面可以跟DAY、HOUR、MONTH、YEAR。两个日期间隔天数用DATEDIFF(end_date, start_date)它返回的是整数天数更精确的间隔用TIMESTAMPDIFF(unit, start_datetime, end_datetime)单位可以是SECOND、MINUTE、HOUR、DAY、MONTH等。注意参数顺序很多人都把DATEDIFF和TIMESTAMPDIFF的参数位置搞反查出来的结果要么是正数要么是负数排查半天。4.2 DATE_FORMAT 格式化与 STR_TO_DATE 反向解析DATE_FORMAT(date, format)是把日期按指定格式输出比如DATE_FORMAT(NOW(), %Y-%m-%d)得到2024-01-01%Y是四位年份%y是两位年份%m是两位月份%d是两位日期。除了日期还能格式化时间部分%H是24小时制%h是12小时制%i是分钟%s是秒。%W返回星期几的英文名%w返回数字星期。做报表时最常见的用法是DATE_FORMAT(create_time, %Y-%m)来统计每个月的数据量把时间粒度从秒级聚合到月级。与DATE_FORMAT相对的是STR_TO_DATE(str, format)它把字符串解析成日期配合导入外部数据时非常常用。比如STR_TO_DATE(2024/01/01 10:30:00, %Y/%m/%d %H:%i:%s)可以处理非标准日期格式。需要注意的是STR_TO_DATE对格式的匹配比较严格格式串和实际字符串不一致时返回NULL。我曾经在处理一批用户导入的日期数据时就因为月份是1而不是01用%m解析一直失败后来改成%c不补零的月份才解决。MySQL的格式符很多%c、%e这类不补零的格式符在脏数据场景中比补零的更好用。EXTRACT(unit FROM date)可以从日期中提取指定部分比如EXTRACT(YEAR FROM create_time)得到年份EXTRACT(MONTH FROM create_time)得到月份。DAYOFWEEK和WEEKDAY都可以判断星期几但返回值含义不同——DAYOFWEEK里周日是1、周一是2WEEKDAY里周一是0、周日是6。这两个函数容易搞混如果要做“周一到周五工作日判断”建议用WEEKDAY因为WEEKDAY(date) 5就是工作日逻辑更直观。LAST_DAY(date)返回该月的最后一天在计算自然月截止时间点时很好用。唯一遗憾的是MySQL没有内置DATE_TRUNC函数PostgreSQL和Doris里都有MySQL要做“按小时截断”得靠DATE_FORMAT或者FROM_UNIXTIME(UNIX_TIMESTAMP(date) - ... )这种曲线方式实现。5. 流程控制函数CASE WHEN 才是真正的主力5.1 IF、IFNULL、NULLIF 的适用场景流程控制函数里IF(expr, val1, val2)是最直觉化的一个它接收三个参数条件成立返回val1否则返回val2。写法和Java里的三元运算符很像所以很多人爱用。但IF有个缺点它只有两个分支多个条件要嵌套可读性会迅速变差。比如“成绩大于等于90显示优秀大于等于60显示及格否则显示不及格”用IF要写IF(score 90, 优秀, IF(score 60, 及格, 不及格))嵌套两层还能接受再复杂就痛苦了。IFNULL(expr1, expr2)是专门处理NULL的expr1不为NULL就返回expr1否则返回expr2。它跟COALESCE(expr1, expr2, ...)的功能有交集但COALESCE可以接受多个参数返回第一个非NULL值。在多个字段可能为NULL、需要做优先级取值时COALESCE明显更灵活。比如COALESCE(phone, email, address)表示取第一个不为空的联系方式。还有一个小细节IFNULL的返回类型跟第一个参数的类型更接近如果你写IFNULL(abc, 123)返回结果是字符串abc而不是混合类型这点在做类型判断时要留意。NULLIF(expr1, expr2)的作用是如果两个参数相等返回NULL否则返回expr1。它最常见的妙用是避免除零错误。统计占比时写SUM(x) / NULLIF(SUM(y), 0)当分母为0时除法的结果直接变成NULL而不是报错或者得到无穷大。对报表展示来说NULL可以后续处理比让SQL抛异常强太多。做数据清洗时也可以用NULLIF(col, )把空字符串转成NULL让后续聚合函数忽略这些值。5.2 CASE WHEN 的两种写法和执行顺序真正的流程控制主力是CASE WHEN它有两种写法。简单CASE表达式CASE col WHEN 1 THEN one WHEN 2 THEN two ELSE other END这里会比较col与每个WHEN后面的值是否相等。搜索CASE表达式CASE WHEN col 1 THEN big WHEN col 1 THEN one ELSE small END每个WHEN后面跟完整的条件表达式。搜索写法更灵活能处理范围判断、多字段组合判断实际使用中占比远高于简单写法。这里有个执行顺序的关键点CASE从上到下匹配一旦某个WHEN条件成立后面的WHEN就不会再执行。所以写条件时要把更具体的条件放在前面。CASE WHEN在SELECT里可以做字段逻辑转换在ORDER BY里可以做自定义排序规则。最常见的自定义排序需求是“按指定状态顺序排序”比如把状态为completed的放最前面pending其次failed最后写法是ORDER BY CASE status WHEN completed THEN 1 WHEN pending THEN 2 ELSE 3 END。这个技巧在报表展示时很管用因为单纯按字母序或时间序往往不符合业务希望的展示节奏。需要注意CASE WHEN的THEN后面返回的类型要保持一致如果有的分支返回字符串、有的分支返回数字MySQL会做隐式转换结果可能变成你完全没想到的内容。之前遇到过某段代码里CASE WHEN type 1 THEN value ELSE - END当value是数字时-会被转成0展示整列数据看起来全是数字排查了很久才发现是类型不统一导致的。6. 聚合函数与分组统计从 COUNT(*) 到 WITH ROLLUP6.1 COUNT、SUM、AVG、MAX、MIN 的隐藏语义聚合函数是用来做统计汇总的核心工具也是面试必考题。COUNT(*)统计的是所有行数包括NULL值行COUNT(1)跟COUNT(*)在MySQL中性能基本一致统计的都是行数COUNT(col)统计的是该列非NULL值的个数。这个区别在数据质量检查时特别有用比如SELECT COUNT(*) - COUNT(email) AS missing_email就可以算出邮箱为空的行数。SUM(col)只对非NULL值求和如果整列都是NULLSUM返回NULL而不是0所以很多时候要配合IFNULL(SUM(col), 0)一起用。AVG(col)同样忽略NULL但要注意AVG对参与计算的行的处理一个常见误区是AVG不会因为你某个字段是0就自动排除它0是有效值会被算进平均值里。MAX和MIN适用于数值、字符串、日期多种类型。日期可以用MAX(create_time)取最新时间字符串按排序规则取最大或最小。函数本身没什么花头真正容易出错的是它们在GROUP BY分组下的表现——SELECT user_id, MAX(score)只能保证每个分组里最大score的值但如果你同时想要该用户其他字段写成SELECT user_id, MAX(score), name是不严谨的因为name可能来自分组内任意一行MySQL默认不会报错但结果并不是你想要的那一行。MySQL 5.7以后默认开启了ONLY_FULL_GROUP_BY模式这种SQL在实际执行时报错但这个报错恰恰是提醒你聚合查询里的非聚合字段必须出现在GROUP BY子句中或者用聚合函数包起来。如果需要“分组内最大分数对应的整条记录”正确做法是用窗口函数ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY score DESC)然后取排名为1的行这在MySQL 8.0里非常方便。6.2 GROUP_CONCAT 和 WITH ROLLUP 的进阶用法GROUP_CONCAT(col)能把分组内的多个值拼接成一个字符串默认用逗号分隔。比如SELECT dept_id, GROUP_CONCAT(user_name) FROM employee GROUP BY dept_id就能把每个部门的所有员工名字拼在一起。默认长度限制是1024字节数据多的时候会被静默截断我之前就在报表里发现员工名单少了一截排查了半天才发现需要调大group_concat_max_len参数。这个参数可以会话级设置比如SET SESSION group_concat_max_len 10240;也可以在连接串里配置。GROUP_CONCAT还可以指定排序GROUP_CONCAT(user_name ORDER BY user_id ASC)这样拼出来的顺序就受控制了。WITH ROLLUP是分组汇总的进阶功能它在分组结果后面自动加一行总计。比如SELECT dept_id, COUNT(*) FROM employee GROUP BY dept_id WITH ROLLUP最后一行dept_id为NULLCOUNT(*)是所有部门的总数。这个小功能在做月报汇总时很有用可以一次SQL拿到分组明细和总计两套数据。但在MySQL 8.0之前的版本里WITH ROLLUP没法跟ORDER BY一起用官方文档会提示给WITH ROLLUP加LIMIT时结果可能不符合预期。MySQL 8.0还引入了GROUPING()函数它能区分出WITH ROLLUP生成的行避免把NULL值的正常分组行跟汇总行混在一起。如果你还在用8.0之前的版本并且项目里出现了奇怪的分组汇总数据先检查是不是WITH ROLLUP的锅。6.3 分组过滤 HAVING 与 WHERE 的执行顺序分组统计还有一个绕不开的话题WHERE和HAVING的执行顺序不同。WHERE是在分组之前过滤原始行HAVING是在分组之后过滤分组结果。比如你要统计“2024年每个用户的订单总额”先WHERE create_time 2024-01-01 AND create_time 2025-01-01再GROUP BY user_id这个条件属于行级过滤写在WHERE里性能更好。如果你要过滤的是“订单总额超过5000的用户”这属于分组结果的条件必须写在HAVING里写成GROUP BY user_id HAVING SUM(amount) 5000。这两者的混淆是SQL初学者最常犯的错误。如果把用户过滤条件写在HAVING里虽然结果有时碰巧一样但性能就差很大因为HAVING是在聚合完成后才做筛除聚合过程依然要处理所有行。一个常见的性能优化就是能放到WHERE的条件绝不放HAVING。另一个关于别名的细节WHERE子句里不能直接使用SELECT中定义的列别名因为WHERE在SELECT计算别名之前执行ORDER BY和HAVING里可以使用别名。所以SELECT DATE_FORMAT(create_time, %Y-%m) AS month, COUNT(*) AS cnt FROM orders GROUP BY month是可以正常工作的但WHERE cnt 10会报错。我在刚开始写SQL时经常因为这个报错而困惑后来理解了执行顺序才明白SQL不是先SELECT再WHERE的线性执行它有自己的逻辑顺序。7. 函数使用中的性能陷阱与排查实录7.1 函数导致索引失效一个常见但容易被忽视的大坑内置函数用得好能提升效率用得不对反而会拖垮性能。最典型的问题是在索引列上使用函数导致索引失效。比如你有一个create_time字段类型是DATETIME并且建了索引。你写WHERE DATE(create_time) 2024-01-01来查某一天的数据MySQL无法对这个查询使用索引因为DATE(create_time)的结果对所有行来说都是一个“新的值”索引无法直接定位。如果你改成WHERE create_time 2024-01-01 00:00:00 AND create_time 2024-01-02 00:00:00这就能用上索引了而且范围查询的扫描范围也很精确。我在一次慢查询优化里把一个每天跑一次的任务从30秒降到了0.2秒就是做了这样的等价改写——函数本身不是问题问题在于你让函数作用于索引列。类似的还有WHERE YEAR(create_time) 2024同样会让索引失效。如果你频繁需要按年份过滤除了改写为范围查询更稳妥的方案是新增一个year字段并在写入时冗余存储或者在MySQL 5.7及以上版本用生成列generated column加索引让函数的结果预先计算并入库。ORDER BY里面如果对索引列使用了函数排序也无法利用索引。比如ORDER BY LOWER(name)无法使用name上的索引只能进行文件排序filesort数据量大时排序就会变慢。如果业务确实需要不区分大小写排序更优雅的方案是使用不区分大小写的排序规则而不是在ORDER BY里加函数。7.2 LIKE 与字符串函数的配合误区搜索场景里LIKE %keyword%是出了名的性能杀手因为前导通配符会让索引失效即使字段上有索引也用不上。更隐蔽的问题在于很多人为了拼接模糊查询条件喜欢在SQL里写LIKE CONCAT(%, ?, %)。如果你用的ORM是MyBatis可能会用CONCAT(%, #{keyword}, %)这种写法这在MySQL里没问题但要注意CONCAT只会拼接不会处理keyword本身自带的%或_通配符。如果用户搜索的关键词里恰好包含%那么LIKE会把它当作通配符处理匹配范围完全不受控甚至可能导致查询结果为空。严格一点的做法是在应用层先对关键词做转义把%转成\%、_转成\_再用LIKE查询。另外LIKE keyword%这种后通配写法是可以使用索引的范围扫描的效率比前通配快很多。如果你只是在做前缀匹配尽量写成这种形式。还有一种常见场景是查询JSON或逗号分隔字段用LIKE %value%去匹配如果目标值之间用逗号分隔而且值的长度和格式都相对规范那么用FIND_IN_SET代替LIKE会精准很多也不会出现“匹配到包含该子串的其他值”这种误伤。7.3 其他常见报错与排查经验汇总我在长期使用MySQL内置函数的过程中积累了一些常见问题整理成一个速查表方便遇到问题时快速定位现象可能原因解决办法GROUP_CONCAT结果被截断group_concat_max_len默认只有1024字节SET SESSION group_concat_max_len 10240;或调大全局参数两个日期相差天数算错了DATEDIFF参数位置写反前大后小得到负数确认DATEDIFF(end_date, start_date)的语义WHERE DATE(create_time) 2024-01-01很慢索引列上使用了函数索引失效改写为范围查询 ... AND ...字符串转数字后精度丢失CAST(3.99 AS SIGNED)直接截断先ROUND再CAST或使用DECIMAL类型查询结果中有意外的NULLCONCAT、SUM遇到NULL返回NULL用IFNULL或COALESCE兜底或使用CONCAT_WSCASE WHEN返回类型不一致部分分支返回数字部分返回字符串隐式转换统一分支返回类型或显式CAST主从复制数据不一致使用了SYSDATE()统一改用NOW()或CURRENT_TIMESTAMPWITH ROLLUP和ORDER BY同时使用结果异常老版本MySQL限制去掉ORDER BY或分两步查询还有一个我在实际运维中经常遇到的问题DATE_FORMAT(create_time, %Y-%m-%d %H:%i:%s)写出来之后在查询结果里看没问题但一旦参与GROUP BY或者ORDER BY排序逻辑就变得很怪。原因在于DATE_FORMAT返回的是字符串字符串排序按字典序走而2024-01-01 10:00:00和2024-01-01 9:00:00这种格式里9小于10是因为字典序第二位是9和0的比较虽然肉眼看起来时间顺序是对的但字典序对两位数和一位数并不总是友好。所以如果要做时间排序尽量保持DATETIME类型排序在最后展示层再格式化。排查这些问题的通用思路其实就几步先看执行计划EXPLAIN确认是否有索引被使用再检查字段类型和函数返回值类型是否一致接着看数据里有没有预料之外的NULL值。SQL的执行结果不符合预期时用一个最小的数据集复现比对着大表瞎猜要快得多。我个人的习惯是把一条复杂SQL里的函数一层层拆开先用SELECT单独看每个中间结果再把它们组合回去基本都能定位到具体是哪一步的数据出了问题。说到底MySQL内置函数不是一个需要背完所有API的主题你只需要牢记每个分类里最高频的那十几个函数同时理解它们背后的类型转换、NULL处理和索引使用规则就够覆盖绝大多数日常工作场景了。我梳理这篇文章的初衷也是因为发现很多写了三五年SQL的人仍然会在COUNT(*)和COUNT(col)上犯迷糊或者在索引列上大胆地套DATE_FORMAT。函数本身没有错但用的时候多想一想它吃进去的是什么类型、吐出来的是什么类型、会不会破坏索引这比强行记住几百个函数签名有用得多。
返回列表