我一直看到这样的答案:https://stackoverflow.com/a/21277074/4236404是如何在MySQL查询中获取月份到日期行的默认接受答案。
目前的答案:
SELECT id, created
FROM table1
WHERE MONTH(created) = MONTH(CURDATE())
AND YEAR(created) = YEAR(CURDATE())
此查询将起作用,但效率低下,MySQL将执行完整扫描以获得结果。
因此,获取月到日(MTD)查询的行的正确方法如下(我将使用PDO和PHP来演示:
//get the first day of the month
$month_first_day = date( "Y-m-01" );
//select the record where the created date is equal to or bigger than the first day of the current month.
$stmt = $pdo->prepare('SELECT id, created FROM table1 WHERE created >= :first_day_of_month');
$stmt->bindParam(':first_day_of_month', $month_first_day);
$stmt->execute();
$realm_data = $stmt->fetch();
奖金查询:
要获取今天的所有记录,请执行以下操作:
$today = date( "Y-m-d" );
$stmt = $pdo->prepare('SELECT id, created FROM table1 WHERE created >= :today');
$stmt->bindParam(':today', $today);
$stmt->execute();
$realm_data = $stmt->fetch();
要获取昨天的所有记录,请执行以下操作:
$today = date( "Y-m-d" );
$yesterday = date( "Y-m-d", time()-86400 );
$stmt = $pdo->prepare('SELECT id, created FROM table1 WHERE created >= :yesterday AND created < :today');
$stmt->bindParam(':today', $today);
$stmt->bindParam(':yesterday', $yesterday);
$stmt->execute();
$realm_data = $stmt->fetch();
要获取过去7天的所有记录,请执行以下操作:
$seven_days_ago = date('Y-m-d', strtotime('-7 days'));
$stmt = $pdo->prepare('SELECT id, created FROM table1 WHERE created >= :seven_days_ago');
$stmt->bindParam(':seven_days_ago', $seven_days_ago);
$stmt->execute();
$realm_data = $stmt->fetch();
假设/提示:
MySQL中的列设置为日期时间格式。
MySQL不允许创建基于表达式/函数的索引,有一种解决方法可以从MySQL 5.7+和generated columns进行索引。 确保将表设置为InnoDB,它可以在非存储生成的列上生成索引。
CREATE TABLE t (
d DATETIME
, dy INT AS (YEAR(d))
, dm INT AS (MONTH(d))
, INDEX(dy, dm)
) Engine = InnoDB ;
说明
EXPLAIN
SELECT
*
FROM
t
WHERE
MONTH(d) = MONTH(CURDATE())
AND
YEAR(d) = YEAR(CURDATE())
结果
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
| --- | ----------- | ----- | ---------- | ---- | ------------- | --- | ------- | --- | ---- | -------- | ----------- |
| 1 | SIMPLE | t | | ALL | dy | | | | 19 | 78.95 | Using where |
见demo
是的,我知道它说ALL
但MySQL就在这里。结果返回15条记录,该表是19条记录。
此外,您需要知道解释输出中的行输出是InnoDB引擎的预期数字关闭记录,它不是实际数字。
但是随机磁盘I.O(6ms * 15)和流的15倍(很多)比全表扫描更加昂贵,后者执行一个随机磁盘I.O(6ms * 1)并且可以一次性传输数据。
MySQL的优化器/执行是基于成本的,它根据最昂贵的随机磁盘I / O计算相对成本。
但请注意它说可能的关键dy
MySQL知道它现在可以使用索引
WHERE
MONTH(d) = MONTH(CURDATE())
AND
YEAR(d) = YEAR(CURDATE())
只有MySQL认为我不会通过阅读索引来做更多的工作。
仍在等待MySQL支持表达式/功能索引,他们可能会在稍后添加MySQL 8版本。 MySQL 8仍在继续工作并获得更新。
CREATE INDEX index_name ON table (YEAR(d));
但我认为不会很快发生,MySQL确实或多或少地使用我使用的解决方法支持它,所以它不认为他们急于实现它。
MySQL 8.0.16之前的MySQL也不支持CHECK CONSTRAINTS,他们也没有急于实现它,因为MySQL已经或多或少地使用带有CHECK OPTION的VIEW支持它给出了一个很好的例子。
编辑:
Seams我很快就会说MySQL不会很快支持那个功能表达/功能索引。
我注意到MySQL 8.0.13更新添加了表达式/功能索引。
功能关键部件
“普通”索引索引列值的列值或前缀。例如,在下表中,给定t1行的索引条目包括完整的col1值和col2值的前缀,前者包含前10个字符:
MySQL 8.0.13及更高版本支持索引表达式值而不是列或列前缀值的功能键部分。使用功能键部件可以索引未直接存储在表中的值。例子:
CREATE TABLE t1 (col1 INT, col2 INT, INDEX func_index ((ABS(col1)))); CREATE INDEX idx1 ON t1 ((col1 + col2)); CREATE INDEX idx2 ON t1 ((col1 + col2), (col1 - col2), col1); ALTER TABLE t1 ADD INDEX ((col1 * 40) DESC);
在MySQL 8.0.13+中你可以做到
CREATE INDEX index_name ON table (YEAR(created), MONTH(created));