1. MySQL内置函数全面解析
作为一名长期与MySQL打交道的开发者,我发现很多刚入门的同行对内置函数的使用存在不少误区。今天我就结合自己多年的实战经验,系统梳理MySQL中最实用的内置函数,并分享一些官方文档中不会告诉你的使用技巧。
MySQL内置函数就像瑞士军刀,能极大提升我们的开发效率。但如果不了解它们的特性和适用场景,很容易踩坑。比如日期函数在不同时区的表现差异、字符串函数对多字节字符的处理方式等,都是实际开发中经常遇到的问题。
2. 日期与时间函数实战指南
2.1 基础日期时间函数
最常用的日期函数莫过于获取当前时间的几个函数:
sql复制SELECT CURRENT_DATE(); -- 2023-08-15
SELECT CURRENT_TIME(); -- 14:30:22
SELECT NOW(); -- 2023-08-15 14:30:22
重要提示:在生产环境中,我强烈建议统一使用NOW()而不是SYSDATE()。虽然它们都能返回当前时间,但NOW()在SQL执行开始时就会确定值,而SYSDATE()会在每次调用时重新获取,这可能导致主从复制时出现数据不一致。
2.2 日期计算与转换
DATE_ADD和DATE_SUB是处理日期加减的神器:
sql复制-- 3天后的日期
SELECT DATE_ADD(CURRENT_DATE(), INTERVAL 3 DAY);
-- 2个月前的日期
SELECT DATE_SUB('2023-08-15', INTERVAL 2 MONTH);
DATEDIFF计算日期差特别实用:
sql复制-- 计算两个日期相差天数
SELECT DATEDIFF('2023-12-31', '2023-08-15') AS days_remaining;
2.3 时区处理经验
处理跨时区应用时,一定要明确:
sql复制-- 转换时区
SELECT CONVERT_TZ(NOW(), '+00:00', '+08:00');
我在实际项目中踩过的坑:永远不要在应用层处理时区转换,而应该使用MySQL的时区函数。因为应用服务器的时区设置可能不一致,会导致难以排查的问题。
3. 字符串处理高级技巧
3.1 基础字符串操作
CONCAT是最常用的字符串连接函数:
sql复制SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM users;
但很多人不知道,当任何参数为NULL时,结果就是NULL。安全做法是:
sql复制SELECT CONCAT(IFNULL(first_name,''), ' ', IFNULL(last_name,'')) FROM users;
3.2 字符串搜索与截取
SUBSTRING的几种用法:
sql复制-- 从第3个字符开始截取
SELECT SUBSTRING('MySQL', 3); -- 结果: SQL
-- 从第2个字符开始截取2个字符
SELECT SUBSTRING('MySQL', 2, 2); -- 结果: yS
注意:MySQL中字符串位置从1开始计数,不是0!这是很多开发者容易混淆的地方。
3.3 字符集处理要点
处理多语言时要特别注意:
sql复制-- 获取字符串字符集
SELECT CHARSET('中文');
-- 转换字符集
SELECT CONVERT('中文' USING utf8mb4);
实际案例:我们曾遇到一个emoji存储问题,最终发现是因为没有使用utf8mb4字符集,导致表情符号无法正常存储。
4. 数值计算与转换函数
4.1 数学运算函数
ROUND、CEILING和FLOOR的区别:
sql复制SELECT
ROUND(3.1415, 2), -- 3.14
CEILING(3.14), -- 4
FLOOR(3.99); -- 3
4.2 随机数生成技巧
RAND()生成随机数:
sql复制-- 生成1-100的随机整数
SELECT FLOOR(1 + RAND() * 100);
-- 随机排序查询结果
SELECT * FROM products ORDER BY RAND() LIMIT 10;
但要注意:RAND()在大数据量时性能很差,因为它会为每行计算随机值。更好的做法是在应用层生成随机ID。
4.3 进制转换实战
处理不同进制数据:
sql复制-- 十进制转二进制
SELECT BIN(10); -- 1010
-- 十六进制转十进制
SELECT CONV('A', 16, 10); -- 10
5. 其他实用函数详解
5.1 系统信息函数
获取环境信息:
sql复制SELECT
USER(), -- 当前用户
DATABASE(), -- 当前数据库
VERSION(); -- MySQL版本
5.2 加密函数安全实践
密码加密的正确姿势:
sql复制-- 不推荐使用PASSWORD函数(已废弃)
-- 推荐使用更安全的SHA2系列函数
SELECT SHA2('mypassword', 256);
5.3 条件判断函数
IFNULL的替代方案:
sql复制-- 传统写法
SELECT IFNULL(field, 'default') FROM table;
-- 更灵活的COALESCE
SELECT COALESCE(field1, field2, 'default') FROM table;
6. 性能优化与常见陷阱
6.1 函数索引的坑
在WHERE子句中使用函数会导致索引失效:
sql复制-- 糟糕的写法(索引失效)
SELECT * FROM users WHERE DATE_FORMAT(create_time,'%Y-%m')='2023-08';
-- 优化写法(可以使用索引)
SELECT * FROM users
WHERE create_time BETWEEN '2023-08-01' AND '2023-08-31';
6.2 字符集转换开销
不必要的字符集转换会显著降低性能:
sql复制-- 低效写法
SELECT * FROM products WHERE CONVERT(name USING utf8) LIKE '%手机%';
-- 应该确保表字符集与应用需求一致
6.3 内存消耗问题
GROUP_CONCAT默认限制较小,大数据量时会截断:
sql复制-- 增加GROUP_CONCAT最大长度
SET SESSION group_concat_max_len = 1000000;
SELECT GROUP_CONCAT(product_name) FROM products;
7. 实战案例分享
7.1 用户活跃度统计
利用日期函数计算用户留存:
sql复制SELECT
user_id,
DATEDIFF(NOW(), last_login_date) AS days_inactive,
CASE
WHEN DATEDIFF(NOW(), last_login_date) <= 7 THEN '活跃'
WHEN DATEDIFF(NOW(), last_login_date) <= 30 THEN '一般'
ELSE '流失'
END AS activity_status
FROM users;
7.2 产品SKU生成器
结合字符串和数字函数生成SKU:
sql复制SELECT
CONCAT(
UPPER(SUBSTRING(category_name, 1, 3)),
'-',
LPAD(product_id, 6, '0'),
'-',
DATE_FORMAT(create_time, '%y%m')
) AS sku_code
FROM products;
7.3 安全审计日志
使用加密函数处理敏感信息:
sql复制INSERT INTO audit_log
VALUES (
UUID(),
USER(),
NOW(),
'login',
CONCAT(SUBSTRING(user_email, 1, 3), '****', SUBSTRING(user_email, INSTR(user_email, '@')))
);
8. 最佳实践总结
经过多年实战,我总结了这些MySQL函数使用原则:
- 在SQL中使用函数会带来额外开销,能不用尽量不用
- 避免在WHERE条件左侧使用函数,会导致索引失效
- 处理多语言内容时,始终明确指定字符集
- 日期时间计算要考虑时区因素
- 加密敏感数据使用SHA2等现代算法,而非MD5
- 字符串操作注意NULL值处理
- 数值计算注意精度问题,必要时使用DECIMAL类型
- 随机排序大数据集时,考虑应用层实现
最后分享一个鲜为人知的小技巧:在MySQL 8.0+中,你可以创建自定义函数来封装复杂逻辑,就像这样:
sql复制CREATE FUNCTION get_user_age(birth_date DATE)
RETURNS INT DETERMINISTIC
BEGIN
RETURN TIMESTAMPDIFF(YEAR, birth_date, CURDATE());
END;
这样就能通过SELECT get_user_age(birth_date) AS age FROM users来简化查询了。