統計每日訪問量、按月匯總銷售額、區間篩選日誌等,核心需求:高效查詢時間段內的數據。
-- 查詢 2010-03-01 當天數據
SELECT COUNT(*) FROM access_log
WHERE dt >= '2010-03-01 00:00:00'
AND dt < '2010-03-02 00:00:00';
-- BETWEEN 寫法(含邊界,需注意精度)
SELECT * FROM orders
WHERE created_at BETWEEN '2023-01-01 00:00:00' AND '2023-01-31 23:59:59';
DATE(), YEAR(), MONTH() 等時間函數WHERE dt >= '...' AND dt < '...' 可走範圍索引UNIX_TIMESTAMP(datetime) -- 轉整數秒數
FROM_UNIXTIME(unixtime) -- 轉回 datetime
-- 轉換演示
SELECT UNIX_TIMESTAMP('2010-03-01 00:00:00'); -- 1267372800
SELECT FROM_UNIXTIME(1267372800); -- '2010-03-01 00:00:00'
-- 查詢:先轉換邊界值,再整數比較
SELECT COUNT(*) FROM access_log
WHERE dt >= UNIX_TIMESTAMP('2010-03-01 00:00:00')
AND dt < UNIX_TIMESTAMP('2010-03-02 00:00:00');
-- 應用層預轉換(推薦)
-- PHP: $start = strtotime('2010-03-01');
-- Java: Instant.parse("2010-03-01T00:00:00Z").getEpochSecond()
CREATE TABLE access_log (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
dt INT UNSIGNED NOT NULL COMMENT 'Unix timestamp',
...
PRIMARY KEY (id, dt)
) PARTITION BY RANGE (dt) (
PARTITION p202301 VALUES LESS THAN (1672531200),
PARTITION p202302 VALUES LESS THAN (1675209600),
PARTITION pmax VALUES LESS THAN MAXVALUE
);
查詢自動分區裁剪,僅掃描相關分區。
ALTER TABLE logs ADD year SMALLINT, ADD month TINYINT, ADD day TINYINT;
-- 生成列 (MySQL 5.7+)
ALTER TABLE logs ADD year SMALLINT AS (YEAR(dt)) STORED,
ADD month TINYINT AS (MONTH(dt)) STORED,
ADD day TINYINT AS (DAY(dt)) STORED;
-- 查詢特定月份
SELECT * FROM logs WHERE year=2023 AND month=3;
配合組合索引 INDEX(year, month, day),等值查詢極快。
-- 只查 id, dt
CREATE INDEX idx_dt_id ON access_log (dt, id);
SELECT id FROM access_log WHERE dt BETWEEN ... AND ...;
| 場景 | 推薦方案 |
|---|---|
| 中小表、需頻繁時間函數計算 | DATETIME + 範圍索引 |
| 大表、高頻區間聚合、分區/分表 | Unix Timestamp (INT) + 分區 |
| 極高寫入、時序數據 | 專用時序庫 或 MySQL 時間列拆分 |
| 跨時區應用 | 存 UTC TIMESTAMP,應用層轉換顯示 |
WHERE DATE(dt) = '2023-01-01' → 索引失效,改用範圍BETWEEN '2023-01-01' AND '2023-01-31' 漏掉 31 日非 00:00:00 的數據,用 dt >= '2023-01-01' AND dt < '2023-02-01'time_zone、連接會話 SET time_zone、應用層時區統一用 UTC 存儲