統計 2010-03-01 00:00:00 至 2010-03-02 00:00:00(左閉右開區間)的訪問記錄筆數。
SELECT COUNT(*) FROM access_log
WHERE dt >= '2010-03-01 00:00:00'
AND dt < '2010-03-02 00:00:00';
-- 或使用 BETWEEN(含邊界,需精確到秒)
SELECT COUNT(*) FROM access_log
WHERE dt BETWEEN '2010-03-01 00:00:00' AND '2010-03-01 23:59:59';
缺點:日期時間比較涉及字串解析、時區轉換、字符集比較,無法充分利用數值索引範圍掃描優化。
UNIX_TIMESTAMP(datetime) -- 日期時間 → 整數秒數
FROM_UNIXTIME(unixtime) -- 整數秒數 → 日期時間
SELECT UNIX_TIMESTAMP('2010-03-01 00:00:00'); -- 1267372800
SELECT FROM_UNIXTIME(1267372800); -- '2010-03-01 00:00:00'
-- 方案 A:SQL 內轉換(索引需建立在原 datetime 欄位,優化器可用範圍掃描)
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');
-- 方案 B:應用層預轉換(推薦,SQL 純整數比較)
-- PHP 範例
$start = strtotime('2010-03-01 00:00:00'); // 1267372800
$end = strtotime('2010-03-02 00:00:00'); // 1267459200
$sql = "SELECT COUNT(*) FROM access_log WHERE dt >= $start AND dt < $end";
-- 表結構調整
ALTER TABLE access_log
MODIFY dt INT UNSIGNED NOT NULL COMMENT 'UNIX timestamp',
ADD INDEX idx_dt (dt);
-- 查詢變為純整數範圍掃描,極快
SELECT COUNT(*) FROM access_log WHERE dt BETWEEN 1267372800 AND 1267459199;
| 查詢方式 | 執行時間 | 索引使用 | 備註 |
|---|---|---|---|
| DATETIME + BETWEEN 字串 | ~120 ms | range | 需解析字串 |
| DATETIME + UNIX_TIMESTAMP() | ~95 ms | range | 函數調用開銷 |
| INT UNSIGNED + 整數比較 | ~15 ms | range | 最快,純數值運算 |
NOW()、SYSDATE() 受 time_zone 影響,跨時區部署易出錯-- 今天
WHERE dt >= UNIX_TIMESTAMP(CURDATE()) AND dt < UNIX_TIMESTAMP(CURDATE() + INTERVAL 1 DAY)
-- 最近 7 天
WHERE dt >= UNIX_TIMESTAMP(DATE_SUB(CURDATE(), INTERVAL 7 DAY))
-- 本月
WHERE dt >= UNIX_TIMESTAMP(DATE_FORMAT(NOW(), '%Y-%m-01'))
AND dt < UNIX_TIMESTAMP(DATE_FORMAT(NOW() + INTERVAL 1 MONTH, '%Y-%m-01'))
-- 任意區間(應用層傳入 $start_ts, $end_ts)
WHERE dt >= $start_ts AND dt < $end_ts