MySQL常用函数详解:从字符串到聚合,避开隐式转换与索引失效陷阱

发布时间:2026/10/21 23:21:45

MySQL常用函数详解:从字符串到聚合,避开隐式转换与索引失效陷阱 干过几年后端开发的人写 SQL 时谁没跟 MySQL 函数打过交道。字符串截取、日期格式化、空值处理、条件判断这些都是日常报表统计、数据清洗、接口查询里躲不开的基础操作。但“会用”和“用得稳”是两码事很多线上慢查询、结果集莫名不对的问题往往就出在某个函数的使用姿势上。这篇文章我把 MySQL 里常用的几类函数系统梳理一遍从语法细节到实际场景再到容易踩的坑一次性说清楚。先说清楚这篇文章的定位不堆文档不列全量函数手册只挑工作中真正高频、且容易出问题的那些。内容建议收藏适合刚入门 SQL 的开发者建立函数知识框架也适合有经验的人查漏补缺——尤其是日期函数和隐式转换这两块我见过太多老手在这上面翻车。1. 字符串函数用的最多坑也最多字符串处理是 SQL 里最频繁的操作之一。数据清洗、字段拼接、模糊匹配、敏感信息脱敏哪哪都有字符串函数的身影。但这类函数有个共同特点看着简单边界情况特别多一不小心就截错位置、拼错格式。1.1 拼接函数CONCAT 与 CONCAT_WS 的取舍先聊拼接。CONCAT(str1, str2, ...)是最基础的拼接函数可以把多个字符串参数连成一个。比如用户表里分开存了姓和名要拼成完整姓名一条 SQL 就搞定SELECT CONCAT(last_name, first_name) AS full_name FROM user;这里有个关键细节CONCAT只要有一个参数为 NULL整个结果就是 NULL。这在做地址拼接、备注拼接时特别容易踩雷。比如拼用户完整地址省、市、区、详细地址四个字段里只要有一个为空整个字段就全空这显然不是业务想要的效果。所以实际项目中我更推荐CONCAT_WS(separator, str1, str2, ...)它的第一个参数是分隔符后面的参数为 NULL 时会自动跳过而不是让整个结果变 NULLSELECT CONCAT_WS(-, province, city, district, detail) AS full_address FROM user_address;这样就算某个字段为空拼接结果里最多是少了一段不会整体失效。另外注意CONCAT_WS里的分隔符如果写成 NULL结果仍然是 NULL这个和CONCAT的规则一致别忽略。1.2 截取函数SUBSTRING、SUBSTRING_INDEX 与 LEFT/RIGHT截取类函数在报表开发里使用频率极高。SUBSTRING(str, pos, len)有三个参数从指定位置截取指定长度的字符。注意 MySQL 的字符位置是从 1 开始算的这一点和很多编程语言从 0 开始不同容易混淆。SELECT SUBSTRING(MySQL 实战手册, 7, 2); -- 结果实战 SELECT SUBSTRING(MySQL 实战手册, -4, 2); -- 结果手册负数为从尾部倒着数SUBSTRING_INDEX(str, delim, count)则是按分隔符截取这个函数在处理路径、IP、邮箱这类结构化字符串时特别好用。比如要取邮箱的 前面的部分SELECT SUBSTRING_INDEX(zhangsanexample.com, , 1); -- 结果zhangsancount 为负数时从右边开始数SUBSTRING_INDEX(a/b/c/d, /, -2)结果是c/d。这个特性在做路径解析、URL 参数提取时很实用。LEFT(str, len)和RIGHT(str, len)更直观一个从左取一个从右取。做手机号脱敏时常用SELECT CONCAT(LEFT(phone, 3), ****, RIGHT(phone, 4)) AS masked_phone FROM user;1.3 大小写转换与填充LOWER、UPPER、LPAD、RPAD大小写转换比较简单LOWER(str)转小写UPPER(str)转大写。常用于用户输入的标准化处理比如用户名统一转小写后再比对。填充函数LPAD(str, len, padstr)和RPAD(str, len, padstr)则常用于格式化编号、补零操作。比如订单号需要固定 8 位不足的左侧补零SELECT LPAD(order_id, 8, 0) AS order_no FROM orders; -- 假设 order_id 为 123结果为 00000123这类函数在生成对账文件、导出报表时特别常用。需要注意的是填充结果的总长度如果小于原字符串长度函数会从左往右截断原字符串而不是不处理。比如LPAD(abcdef, 4, 0)结果是abcd不是0abc。1.4 查找替换类函数LOCATE、REPLACE、TRIM 家族LOCATE(substr, str)返回子串第一次出现的位置找不到返回 0。这个函数配合SUBSTRING可以灵活截取。比如从一段日志文本中提取某个标记后的内容。REPLACE(str, from_str, to_str)是替换函数做数据清洗时经常用到比如把字符串里的逗号全替换掉SELECT REPLACE(amount_str, ,, ) AS clean_amount FROM raw_data;TRIM家族有三个成员TRIM(str)去掉首尾空格LTRIM只去左边空格RTRIM只去右边空格。还有一个高级用法指定去掉特定字符SELECT TRIM(BOTH x FROM xxxMySQLxxx); -- 结果MySQL SELECT TRIM(LEADING 0 FROM 000123); -- 结果123LEADING表示只去掉开头的指定字符TRAILING表示只去掉结尾的BOTH表示两边都去。这个功能在做数据标准化时特别有用比如清理用户输入的电话号码里的特殊符号。补充说明字符串函数里还有一个LENGTH(str)值得注意它返回的是字节数不是字符数。在 UTF-8 编码下一个中文字符占 3 个字节。判断“字符串长度”时如果用了LENGTH算出来的结果可能和直觉不符应该用CHAR_LENGTH(str)才是字符数。这个细节在分页、截断处理时很关键。2. 数值函数计算精度与格式化陷阱数值函数在日常计算、统计汇总、金额处理中用的非常多。但这一类函数往往被低估难度尤其是在精度处理上稍不注意就会产生金额偏差。2.1 ROUND、TRUNCATE 与 CEIL、FLOORROUND(x, d)是四舍五入函数。这个函数有个经典问题ROUND(2.5)在某些数据库里结果是 2因为采用的是“四舍六入五成双”的银行家算法。但在 MySQL 里ROUND(2.5)的结果是 3是标准的四舍五入。跨数据库迁移时这个差异得留心。SELECT ROUND(123.4567, 2); -- 结果123.46 SELECT ROUND(123.4567, 0); -- 结果123 SELECT ROUND(123.4567, -2); -- 结果100负数表示保留到小数点前TRUNCATE(x, d)是直接截断不做四舍五入。做金额处理时如果业务要求“只舍不入”就应该用TRUNCATE而不是ROUND。SELECT TRUNCATE(123.4567, 2); -- 结果123.45CEIL(x)向上取整FLOOR(x)向下取整。分页计算总页数时常用CEILSELECT CEIL(COUNT(*) / 20) AS total_pages FROM orders;2.2 绝对值、取模与随机数ABS(x)返回绝对值这个在计算差异、误差分析时很常有用。MOD(x, y)取模运算判断奇偶、分表逻辑时常用SELECT MOD(7, 2); -- 结果1 SELECT MOD(10, 3); -- 结果1RAND()返回 0 到 1 之间的随机浮点数。取随机记录时常用SELECT * FROM user ORDER BY RAND() LIMIT 10;这里提醒一下ORDER BY RAND()在大表上性能极差因为它会对每一行都计算一个随机数再排序如果表数据量超过几十万这个查询会非常慢。有随机取数需求时更建议用主键随机偏移的方式比如先随机取一个 ID 范围再查询。2.3 FORMAT 格式化数字FORMAT(x, d)把数字格式化为带千分位分隔符的字符串d 为小数位数。导出报表、展示金额时常用SELECT FORMAT(1234567.891, 2); -- 结果1,234,567.89注意这个函数返回的是字符串类型不要拿去做数值运算。另外 FORMAT 的三位分隔符是写死的逗号不同国家的数字格式要求不同就不能直接用这个函数了。数值函数的精度选择在日常统计里要提前想明白。比如统计订单金额平均值AVG(amount)默认返回的结果可能带很多位小数这时候结合ROUND(AVG(amount), 2)一起用比较稳妥。但要注意能做聚合函数嵌套的场景有限ROUND这种普通函数可以包在聚合函数外面这是合法的写法。3. 日期时间函数最容易被低估的一类日期时间函数是 SQL 里最容易出问题的一类没有之一。最大的原因在于日期格式的多样性、时区问题、时间戳与日期字符串的隐式转换每一个都可能让结果和预期不符。3.1 获取当前日期时间NOW、CURDATE、CURTIME、SYSDATE这四个函数都用于获取当前时间但细节有区别SELECT NOW(); -- 当前日期和时间语句开始执行时的时间 SELECT CURDATE(); -- 当前日期无时间部分 SELECT CURTIME(); -- 当前时间无日期部分 SELECT SYSDATE(); -- 当前日期和时间函数执行时的时间核心区别在于NOW()返回的是语句开始执行时的时间无论这条语句里调用多少次NOW()结果都一样而SYSDATE()返回的是函数实际执行那一刻的时间在同一个长事务里多次调用SYSDATE()可能得到不同时间。所以在存储过程、触发器这类长事务场景中尽量别用SYSDATE()否则可能因为时间不一致导致逻辑混乱。3.2 DATE_FORMAT 与 STR_TO_DATE格式化与反格式化DATE_FORMAT(date, format)是日期格式化的核心函数把日期类型按照指定格式转成字符串。常用格式符格式符含义示例%Y四位年份2024%y两位年份24%m两位月份07%d两位日期05%H24 小时制14%i分钟注意是 i 不是 m30%s秒25%W星期英文全称Monday%w星期数字0周日1最常见的报表统计场景按天分组统计订单量SELECT DATE_FORMAT(create_time, %Y-%m-%d) AS day, COUNT(*) AS cnt FROM orders WHERE create_time 2024-01-01 AND create_time 2024-02-01 GROUP BY day;这里有个细节%m表示月份%i表示分钟这两个格式符容易搞混。很多人写分钟时习惯用%m结果输出的永远都是月份排查半天才发现问题。STR_TO_DATE(str, format)是反方向操作把字符串解析为日期类型。这在导入外部数据、处理接口返回的时间字符串时很常用SELECT STR_TO_DATE(2024-07-05 14:30:00, %Y-%m-%d %H:%i:%s); -- 结果2024-07-05 14:30:00 的 DATE 类型值3.3 日期计算DATE_ADD、DATE_SUB、DATEDIFF、TIMESTAMPDIFF日期计算在业务中的使用频率很高。查询近 30 天的数据、计算用户年龄、统计两个事件之间相隔的天数都需要日期计算函数。DATE_ADD(date, INTERVAL expr unit)和DATE_SUB(date, INTERVAL expr unit)是在日期上增加或减少一段间隔SELECT DATE_ADD(2024-07-05, INTERVAL 3 DAY); -- 结果2024-07-08 SELECT DATE_ADD(2024-07-05, INTERVAL 2 MONTH); -- 结果2024-09-05 SELECT DATE_SUB(2024-07-05, INTERVAL 1 WEEK); -- 结果2024-06-28查询近 7 天的订单很多人习惯这么写SELECT * FROM orders WHERE create_time DATE_SUB(NOW(), INTERVAL 7 DAY);DATEDIFF(expr1, expr2)返回两个日期相差的天数结果是 expr1 减去 expr2SELECT DATEDIFF(2024-07-05, 2024-06-27); -- 结果8TIMESTAMPDIFF(unit, datetime_expr1, datetime_expr2)返回两个日期时间相差的指定单位数支持SECOND、MINUTE、HOUR、DAY、WEEK、MONTH、YEARSELECT TIMESTAMPDIFF(SECOND, 2024-07-05 10:00:00, 2024-07-05 10:05:30); -- 结果330 SELECT TIMESTAMPDIFF(MONTH, 2023-01-15, 2024-07-05); -- 结果17计算用户年龄的常见做法就是用TIMESTAMPDIFF(YEAR, birth_date, CURDATE())。DATE_ADD/DATE_SUB与直接加减INTERVAL可以互换比如DATE_ADD(date, INTERVAL 1 DAY)等价于date INTERVAL 1 DAY。3.4 提取日期部分YEAR、MONTH、DAY、WEEKDAY从日期中提取年、月、日、星期是统计报表里的基本功SELECT YEAR(2024-07-05) AS year, MONTH(2024-07-05) AS month, DAY(2024-07-05) AS day; -- 结果2024、7、5WEEKDAY(date)返回一周中的第几天0 表示周一1 表示周二。DAYOFWEEK(date)则返回 1 表示周日。两个函数的标准不一样做周统计时到底用哪个取决于业务里一周从哪天开始算。还有一个每月最后一天的概念LAST_DAY(date)直接返回该日期所在月份的最后一天SELECT LAST_DAY(2024-02-10); -- 结果2024-02-29闰年3.5 unix_timestamp 与 from_unixtime很多系统的时间字段存的是时间戳做报表时得先转成可读时间。FROM_UNIXTIME(timestamp)将秒级时间戳转成日期时间格式SELECT FROM_UNIXTIME(1719556800); -- 结果2024-06-28 06:40:00取决于时区UNIX_TIMESTAMP(date)则相反把日期时间转为秒级时间戳SELECT UNIX_TIMESTAMP(2024-07-05 12:00:00);这里特别容易踩的坑是UNIX_TIMESTAMP()的默认时区是数据库的 session 时区。如果数据库时区设置不对转出来的时间戳和预期可能差了好几个小时。排查时间戳相关问题时先看数据库时区设置SHOW VARIABLES LIKE time_zone;如果业务要求按东八区处理需要在连接或会话层面设置好时区否则所有时间转换都是错的。这个坑是隐性的数据入库、出报表都会受影响。4. 流程控制与空值处理逻辑分寸要拿捏好这一类函数在业务逻辑处理中用的非常多根据条件返回不同的值处理 NULL 数据避免结果集出现大量 NULL 影响统计。这也是 SQL 从单纯的数据查询走向复杂逻辑处理的分水岭。4.1 IF 与 CASE WHEN两种条件分支方式IF(expr, v1, v2)是最简单的条件判断expr 为真返回 v1否则返回 v2。适合简单的二选一场景SELECT name, IF(age 18, 成年, 未成年) AS status FROM user;当分支多于两个时CASE WHEN更合适表达能力更强可读性也更好SELECT name, CASE WHEN score 90 THEN 优秀 WHEN score 60 THEN 合格 ELSE 不合格 END AS grade FROM exam;CASE还有第二种写法直接匹配值SELECT status, CASE status WHEN 1 THEN 待支付 WHEN 2 THEN 已支付 WHEN 3 THEN 已退款 ELSE 未知 END AS status_text FROM orders;这两种写法有一个细节区别值匹配写法在比较值之前会自动做类型转换而带条件的写法不会。如果你在条件里直接用字符串和数字比较可能因为隐式类型转换导致索引失效。后面我会专门用一节讲隐式转换的坑。4.2 IFNULL 与 COALESCE空值处理的两种思路IFNULL(expr1, expr2)是 MySQL 里处理 NULL 的常用函数如果 expr1 不为 NULL返回 expr1否则返回 expr2。这在统计、展示时非常常用SELECT IFNULL(nickname, 未设置昵称) FROM user;COALESCE(value1, value2, ...)功能更强可以传入多个参数返回第一个不为 NULL 的值SELECT COALESCE(real_name, nickname, 匿名用户) FROM user;这个函数在展示用户名称时特别实用如果设置了实名展示实名否则展示昵称都没有就显示匿名用户。使用IFNULL时有一个常见误区IFNULL的参数类型需要一致如果不一致MySQL 会自动进行类型转换而这个转换在某些场景下会产生不可预期的结果。比如IFNULL(amount, 0)中 amount 是 DECIMAL 类型0 是字符串类型MySQL 会把字符串转成数字但如果字符串无法被转换可能导致结果异常。重要提示IFNULL和COALESCE都不会修改底层数据只是在查询结果层面把 NULL 替换成指定值。如果统计时用SUM(IFNULL(amount, 0))和SUM(amount)结果其实是一样的因为 NULL 在聚合函数里会被自动忽略。但用COUNT(IFNULL(column, 0))则会影响计数行为COUNT(column)只统计非 NULL 行而COUNT(IFNULL(column, 0))会把 NULL 行也算进去。这个差异在做多表关联、LEFT JOIN 统计时很容易踩坑。4.3 NULLIF 与空值比较NULLIF(expr1, expr2)的逻辑是如果两个表达式相等返回 NULL否则返回 expr1。这个函数在避免除零错误时很有用SELECT amount / NULLIF(total, 0) AS ratio FROM sales;当 total 为 0 时NULLIF 返回 NULL除以 NULL 的结果为 NULL不会报错。这样比值结果不会出现“除零异常”而是返回一个安全的空值。4.4 流程控制函数的实际应用场景流程控制函数在复杂报表里几乎是必需品。比如统计各省份订单量和销售额同时标记哪些省份销售额为 NULL没有订单这时候可以结合IF和聚合函数使用SELECT province, COUNT(order_id) AS order_cnt, SUM(IFNULL(order_amount, 0)) AS total_amount, IF(COUNT(order_id) 0, 无订单, 有订单) AS flag FROM orders GROUP BY province;这种写法在经营分析报表、数据看板里非常常见。掌握好流程控制函数写出来的 SQL 能灵活应对各种业务分支。5. 聚合函数数据统计的基本盘聚合函数是对一组值进行计算并返回单一结果的函数。只要涉及统计报表、数据分析就一定离不开聚合函数。但聚合函数的“坑”很多很多人都没搞明白。5.1 COUNT 系列COUNT(*)、COUNT(1)、COUNT(列)COUNT(*)统计行数包括 NULL 行。COUNT(1)也是统计行数和COUNT(*)在绝大多数场景下性能几乎无差别。COUNT(column_name)只统计该列非 NULL 的行数。SELECT COUNT(*) AS total_rows FROM orders; SELECT COUNT(pay_time) AS paid_orders FROM orders;第二句的结果是已经支付完成的订单数没支付的订单表里 pay_time 为 NULL不会被计入。这个写法在统计支付转化率时特别实用SELECT COUNT(*) AS total_orders, COUNT(pay_time) AS paid_orders, ROUND(COUNT(pay_time) / COUNT(*) * 100, 2) AS payment_rate FROM orders;千万不要用COUNT(列名)去代替COUNT(*)统计总行数除非你明确知道要跳过 NULL 值。这是新手最常犯的错误统计结果莫名变少排查半天才发现是 NULL 值被跳过了。5.2 SUM、AVG 与 NULL 的关系SUM(column)是求和函数。NULL 值在 SUM 中会被忽略不会影响结果。但如果是业务里金额字段为 NULL求和时相当于跳过这一行这和把它当作 0 参与求和结果是等价的。AVG(column)是求平均值。同样忽略 NULL 值。这里有一个非常经典的坑平均值计算的分母是“非 NULL 行数”不是总行数。SELECT AVG(amount) FROM orders; -- 假设有 5 个订单其中 1 个订单 amount 为 NULL -- 结果是 4 个非 NULL 订单的平均值而不是 5 个订单把 NULL 当作 0 求平均如果业务希望把 NULL 当作 0 参与平均需要自行处理SELECT AVG(IFNULL(amount, 0)) FROM orders;这个差异在绩效统计、完成率计算中影响巨大。比如统计 5 个人的完成金额1 个人没数据直接AVG(amount)会把分母变成 4 而不是 5算出来的平均完成额虚高业务方拿着这个数据做决策就会出问题。5.3 MIN、MAX 的隐藏用途MIN(column)和MAX(column)不只是求最小值和最大值——它们在查询极值时还能配合 GROUP BY 使用SELECT customer_id, MAX(order_amount) AS max_amount FROM orders GROUP BY customer_id;还可以用来查找最早、最晚的时间SELECT MIN(create_time) AS first_order_time, MAX(create_time) AS latest_order_time FROM orders;一个比较偏门的用法是MAX也可以作用于字符串按照字典序取最大。这在某些需要特殊排序场景下能派上用场但不能代替常规的排序逻辑只适合简单场景。5.4 GROUP BY 搭配 HAVING 的过滤逻辑聚合函数常和GROUP BY一起出现HAVING用来过滤分组后的结果。这里必须注意WHERE和HAVING的执行顺序SELECT customer_id, COUNT(*) AS order_cnt, SUM(amount) AS total_amount FROM orders WHERE status paid GROUP BY customer_id HAVING COUNT(*) 3;WHERE在分组前过滤数据HAVING在分组后过滤分组数据。所以“取已支付订单中下单次数超过 3 次的用户”这个需求必须把 status 条件放在 WHERE 里先过滤再分组如果放在 HAVING 里虽然也能过滤但性能会更差因为所有数据都参与了分组操作。补充一点使用GROUP BY时SELECT 的列要么出现在聚合函数里要么出现在GROUP BY里。MySQL 有一个ONLY_FULL_GROUP_BY模式开启后会在语法层严格检查这一规则。新版 MySQL 默认开启所以习惯写“宽松模式” SQL 的人升级后可能会遇到报错。5.5 GROUP_CONCAT分组拼接的利器GROUP_CONCAT(column)可以把分组内的多个值拼成一个字符串这在做一对多数据的汇总展示时非常好用SELECT customer_id, GROUP_CONCAT(order_id ORDER BY create_time DESC SEPARATOR ,) AS order_ids FROM orders GROUP BY customer_id;它支持排序和自定义分隔符。默认最大长度限制是 1024 字节如果拼接结果太长会被截断。需要调整可以用SET SESSION group_concat_max_len 102400;这个函数在做标签聚合、分类汇总、生成下拉选项数据源时都很实用。6. 函数使用中的性能隐患与实战建议前面讲了很多函数的功能和写法实际开发中还有一个绕不开的问题性能。谋个函数写得再顺眼如果让索引失效数据量一大就是灾难。6.1 在 WHERE 条件中对列使用函数索引就废了这是 MySQL 开发中最高频的性能坑之一。比如查询某天的订单SELECT * FROM orders WHERE DATE(create_time) 2024-07-05;这个写法很自然但它会让 create_time 上的索引完全失效。因为DATE(create_time)是对索引列做了函数运算MySQL 无法直接使用索引进行范围扫描只能全表扫描逐行计算函数值再比对。正确的做法是改成范围查询SELECT * FROM orders WHERE create_time 2024-07-05 00:00:00 AND create_time 2024-07-06 00:00:00;这样 create_time 的索引就能被用上。不只是日期函数任何对索引列做运算的写法都要警惕WHERE YEAR(column) 2024、WHERE LENGTH(column) 5、WHERE CONCAT(column, x) abc这些都会让索引失效。6.2 隐式类型转换函数结果和列类型不一致隐式类型转换是另一个高发问题。比如手机号字段是 VARCHAR 类型查询时条件写成数字SELECT * FROM user WHERE phone 13800138000;MySQL 会把字符串列自动转换为数字再进行比较如果列上有索引转换后索引同样失效。更严重的是比较结果可能出错比如字符串13800138000abc在转换时会被截断成13800138000导致匹配到不该匹配的记录。避免隐式转换的原则很简单字段是什么类型条件就写什么类型。字符串列就加引号数字列就写数字不要嫌麻烦。6.3 函数索引与虚拟列MySQL 的进阶解法有些场景确实避免不了对列做函数计算MySQL 8.0 提供了函数索引Functional Index来解决这个痛点CREATE INDEX idx_create_date ON orders ((DATE(create_time)));创建函数索引后WHERE DATE(create_time) 2024-07-05这条查询就能走索引了。这是 MySQL 8.0 的新特性5.7 及以下版本不支持。如果必须用 5.7更通用的做法是增加冗余字段在写入时维护一个日期列比如 create_date专门给这类查询使用。6.4 函数使用规范建议结合踩过的坑我整理了几条日常开发中比较实用的规范查询条件里避免对索引列使用任何函数优先改写成范围查询或等值查询。字符串和数字比较时确认字段类型保持条件类型与字段类型一致。日期区间查询用和组合不要用BETWEEN配合DATE()函数。聚合统计时明确 NULL 的业务含义决定是否需要用IFNULL替代。高频调用的 SQL 里尽量避免使用ORDER BY RAND()这类消耗极大的函数组合。6.5 我踩过的一个印象最深的坑有次排查一个线上报表的慢查询一条按天统计的 SQL 执行了快 10 秒。原始写法是SELECT DATE_FORMAT(create_time, %Y-%m-%d) AS day, COUNT(*) AS cnt FROM orders WHERE DATE(create_time) DATE_SUB(CURDATE(), INTERVAL 30 DAY) GROUP BY day;一眼看过去就有两个问题WHERE里对 create_time 用了DATE()导致索引失效更糟糕的是DATE_SUB(CURDATE(), INTERVAL 30 DAY)是一个确定的值这个还能接受但前面的DATE(create_time)就是典型的“索引杀手”。改成SELECT DATE_FORMAT(create_time, %Y-%m-%d) AS day, COUNT(*) AS cnt FROM orders WHERE create_time DATE_SUB(CURDATE(), INTERVAL 30 DAY) GROUP BY day;执行时间直接从近 10 秒降到了 0.2 秒以内。因为 create_time 索引被利用起来做范围扫描了而DATE_FORMAT在SELECT列表里的使用不影响索引。这个改动几乎零成本收益却是几十倍的。所以写 SQL 时有一个条件反射看到 WHERE 里的列被函数包着立刻改掉。这个习惯养成后能省掉大量性能排查时间。最后说一点个人体会。MySQL 函数看起来零散功能好像都很简单但真正影响工作效率的往往不是记不住函数名而是不知道每个函数在什么场景下会产生什么样的副作用。字符串函数的 NULL 传播、日期函数的时区依赖、聚合函数的 NULL 跳行规则、WHERE 条件里的隐式转换——这些细节平时不踩一次坑很难有直觉反应。建议写代码时带着“业务语义”去看函数多问一句这个函数在边界情况下表现是否还是我想要的慢慢地这些细节就会变成肌肉记忆写出来的 SQL 才能既正确又平稳。
延伸阅读

更多相关文章

2026/10/21 23:21:45

C++设计模式之解释器模式

前言 解释器模式(Interpreter Pattern)解决的是一个很具体的问题:给定一种小型的、规则明确的语言,如何用面向对象的方式表示它的语法,并对其求值。经典例子是算术表达式、布尔表达式、查询条件、简单的命令脚本。它的…

2026/10/21 23:21:45

从高频函数到索引失效:MySQL函数使用与性能优化全指南

前几天有个同事跑过来问我一件事,他们一个报表查询每天要跑十几秒,明明加了索引还是没用。我过去一看SQL,WHERE条件里写着DATE_FORMAT(create_time, %Y-%m-%d) 2025-01-01。这个写法本身没错,但它让create_time上的索引彻底失效了…

2026/10/21 23:21:45

GBase 8c gsql元命令:输出控制、对象核查与自动化

很多DBA和开发同学刚接触GBase 8c时,习惯把gsql当成一个“能执行SQL的输入框”,敲完SQL看一眼结果就完事。但真到排查慢SQL、给开发导数据、或者把几十个节点的巡检脚本串起来跑的时候,才会发现真正让gsql好用到飞起的,是那堆以反…

2026/10/22 0:01:49

rea项目极简架构实战:响应式与实时系统的设计、实现与避坑指南

1. 从“rea”这个标题说起:一个被低估的通用缩写第一次看到“rea”这个标题的时候,我脑子里蹦出来的第一反应是——这大概率又是一个被缩写玩坏的项目名。在技术圈混久了你会发现,越是短到只有三个字母的标题,背后藏的东西往往越不…

2026/10/22 0:01:49

大数据人才需求分析毕设实践:从招聘数据到可视化系统

拿到《基于大数据专业岗位招聘信息的人才需求特征分析》这个毕设题目的时候,我第一反应是:终于有个既贴热点、又好落地的方向了。但等我认真帮人搭完一遍完整流程后,发现这个题目远没有看上去那么简单——很多人把它做成了“爬了几千条招聘数…

2026/10/22 0:01:49

若依框架AI代码生成不稳定?用Agent Skill三层结构+五步法搞定

最近一段时间,我一直想把后台管理系统里那些机械重复的增删改查代码交给AI去写。框架用的是若依,按理说这类业务代码模式非常固定,应该是AI最擅长的事情。可真试下来却不是那么回事——你让AI生成一个用户管理模块,它给出的Contro…

2026/10/22 0:01:49

电商智能运营体系从0到1:架构设计、落地步骤与避坑指南

前两年我们团队接了一个电商平台的运营中台项目,目标很直白:把过去靠运营拍脑袋做的选品、定价、发券、推活动这些事,逐步用数据算法和自动化流程代替。项目名字内部就叫“电商智能运营体系”。最近有不少朋友问我当时是怎么设计的、踩过哪些…

2026/10/21 23:56:48

从零搭建可复用能力体系:skills设计、编排与避坑指南

1. 从“skills”这个词说起:它为什么值得单独拎出来聊“skills”这个词,放在任何一个行业里都不算新鲜。但如果你最近在技术社区、产品圈或者职场分享里频繁看到它被单独拿出来讨论,那大概率不是指泛泛的“技能”概念,而是指向一个…

2026/10/21 4:53:08

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/22 0:01:49

电商智能运营体系从0到1:架构设计、落地步骤与避坑指南

前两年我们团队接了一个电商平台的运营中台项目,目标很直白:把过去靠运营拍脑袋做的选品、定价、发券、推活动这些事,逐步用数据算法和自动化流程代替。项目名字内部就叫“电商智能运营体系”。最近有不少朋友问我当时是怎么设计的、踩过哪些…

2026/10/22 0:01:49

若依框架AI代码生成不稳定?用Agent Skill三层结构+五步法搞定

最近一段时间,我一直想把后台管理系统里那些机械重复的增删改查代码交给AI去写。框架用的是若依,按理说这类业务代码模式非常固定,应该是AI最擅长的事情。可真试下来却不是那么回事——你让AI生成一个用户管理模块,它给出的Contro…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑