業務中高頻需求:查詢「今天/昨天/最近 N 天/本月/上月」的數據。本文提供標準、高效、可索引的寫法模板。
WHERE DATE(create_time) = CURDATE()
WHERE YEAR(create_time) = 2023 AND MONTH(create_time) = 5
WHERE TO_DAYS(NOW()) - TO_DAYS(create_time) <= 7
WHERE create_time >= '2023-05-01' AND create_time < '2023-06-01'
WHERE create_time >= DATE_SUB(NOW(), INTERVAL 7 DAY)
created_at DATETIME)-- 最佳:範圍查詢,用上索引
WHERE created_at >= CURDATE()
AND created_at < CURDATE() + INTERVAL 1 DAY
-- 兼容寫法 (5.6+)
WHERE created_at >= DATE(CURDATE())
AND created_at < DATE(CURDATE() + INTERVAL 1 DAY)
WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL 1 DAY)
AND created_at < CURDATE()
WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
AND created_at < CURDATE() + INTERVAL 1 DAY
WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
AND created_at < CURDATE() + INTERVAL 1 DAY
WHERE created_at >= DATE_FORMAT(CURDATE(), '%Y-%m-01')
AND created_at < DATE_FORMAT(CURDATE() + INTERVAL 1 MONTH, '%Y-%m-01')
WHERE created_at >= DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01')
AND created_at < DATE_FORMAT(CURDATE(), '%Y-%m-01')
WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY)
AND created_at < DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY) + INTERVAL 7 DAY
WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY) - INTERVAL 7 DAY
AND created_at < DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY)
WHERE created_at >= DATE_FORMAT(CURDATE(), '%Y-01-01')
AND created_at < DATE_FORMAT(CURDATE() + INTERVAL 1 YEAR, '%Y-01-01')
WHERE created_at >= DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 YEAR), '%Y-01-01')
AND created_at < DATE_FORMAT(CURDATE(), '%Y-01-01')
-- 應用層計算好開始/結束時間,傳參數
-- 避免 SQL 內部計算,利於查詢緩存與計劃復用
-- Java 範例
LocalDateTime start = LocalDate.now().atStartOfDay();
LocalDateTime end = start.plusDays(1);
String sql = "SELECT * FROM orders WHERE created_at >= ? AND created_at < ?";
-- 確保會話時區一致
SET time_zone = '+08:00';
-- 或連線參數指定
?serverTimezone=Asia/Shanghai
-- 確保 WHERE 條件包含分區鍵,實現 Partition Pruning
EXPLAIN PARTITIONS SELECT * FROM logs
WHERE created_at >= '2023-05-01' AND created_at < '2023-06-01';
-- 僅查熱數據分區
SELECT * FROM orders_202305 WHERE created_at >= '2023-05-01';
| 函數 | 說明 | 範例結果 |
|---|---|---|
NOW() | 當前日期時間 | 2023-05-27 14:30:00 |
CURDATE() | 當前日期 | 2023-05-27 |
CURTIME() | 當前時間 | 14:30:00 |
DATE_SUB(d, INTERVAL n UNIT) | 日期減去間隔 | DATE_SUB(NOW(), INTERVAL 7 DAY) |
DATE_ADD(d, INTERVAL n UNIT) | 日期加上間隔 | DATE_ADD(NOW(), INTERVAL 1 MONTH) |
DATE_FORMAT(d, fmt) | 格式化日期 | DATE_FORMAT(NOW(), '%Y-%m-01') |
WEEKDAY(d) | 星期索引 (0=週一) | WEEKDAY('2023-05-27') = 5 (週六) |
LAST_DAY(d) | 該月最後一天 | LAST_DAY('2023-02-15') = '2023-02-28' |
EXPLAIN SELECT * FROM orders
WHERE created_at >= '2023-05-01' AND created_at < '2023-06-01';
-- type=range, key=idx_created_at, rows=預估掃描行數 (非全表)
收藏此模板庫,時間範圍查詢不再手寫、不再踩索引失效坑。