如何在MySql的DATETIME字段的date部分创build一个索引

如何在DATETIME字段的date部分创build索引?

mysql> SHOW COLUMNS FROM transactionlist; +-------------------+------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------------+------------------+------+-----+---------+----------------+ | TransactionNumber | int(10) unsigned | NO | PRI | NULL | auto_increment | | WagerId | int(11) | YES | MUL | 0 | | | TranNum | int(11) | YES | MUL | 0 | | | TranDateTime | datetime | NO | | NULL | | | Amount | double | YES | | 0 | | | Action | smallint(6) | YES | | 0 | | | Uid | int(11) | YES | | 1 | | | AuthId | int(11) | YES | | 1 | | +-------------------+------------------+------+-----+---------+----------------+ 8 rows in set (0.00 sec) 

TranDateTime用于保存交易发生的date和时间

我的表有超过100万条logging和声明

 SELECT * FROM transactionlist where date(TranDateTime) = '2008-08-17' 

需要很长时间。

编辑:

看看这个博客文章“ 为什么MySQL的DATETIME可以而且应该避免 ”

如果我没有记错的话,那将会运行整个表格扫描,因为你是通过一个函数传递列的。 由于查询优化器不能真正知道函数的结果,所以MySQL会顺从地运行每一列的函数,绕过索引。

我会做什么是这样的:

 SELECT * FROM transactionlist WHERE TranDateTime BETWEEN '2008-08-17 00:00:00' AND '2008-08-18 23:59:59'; 

那应该会给你2008-08-17发生的一切,以及2008-08-18 00:00:00发生的一切。 如果这是一个问题,你可以改变第二届“2008-08-17 23:59:59”,只是得到2008-08-17。

我并不是想听起来很可爱,但一个简单的方法是添加一个只包含date部分和索引的新列。

您不能仅在date部分创build索引。 你有什么理由吗?

即使可以在date部分创build索引,优化程序也可能不会将其用于上述查询。

我想你会发现的

 SELECT * FROM transactionlist WHERE TranDateTime BETWEEN '2008-08-17' AND '2008-08-18' 

高效率,做你想做的。

我不知道mySql的具体情况,但只是索引整个date字段有什么害处呢?

然后只search:

  select * from translist where TranDateTime > '2008-08-16 23:59:59' and TranDateTime < '2008-08-18 00:00:00' 

如果索引是b树或其他合理的东西,这些应该很快find。

另一个选项(与7.5.3及更高版本相关)是基于datetime列创build生成/虚拟列,然后对其进行索引。

 CREATE TABLE `table` ( `my_datetime` datetime NOT NULL, `my_date` varchar(12) GENERATED ALWAYS AS (DATE(`my_daetime`)) STORED, KEY `my_idx` (`my_date`) ) ENGINE=InnoDB; 

Valeriy Kravchuk在MySQL网站上针对这个问题的function请求说要使用这种方法。

“与此同时,您可以使用字符列来存储DATETIME值作为string,只有前N个字符被索引。通过在MySQL 5中使用一些小心的触发器,您可以基于这个想法创build一个相当健壮的解决scheme。

你可以写一个很容易添加这个列的例程,然后用触发器保持这个列同步。 这个string列上的索引应该很快。

一个很好的解决scheme是使用时间戳,而不是date时间。 它被存储为INT并被索引足够好。 就我个人而言,我在交易表上遇到过这样的问题,它有大约百万条logging,并且很难放慢速度,最后我指出这是由不好的索引字段(date时间)造成的。 现在它运行得非常快。

datetime LIKE的东西%也不会抓住索引。

使用这个: WHERE datetime_field> = curdate();
这将抓住指数,
于今天00:00:00到今天23:59:59
完成。

什么“解释”说? (运行EXPLAIN SELECT * FROM transactionlist where date(TranDateTime)='2008-08-17')

如果由于date()函数而没有使用索引,范围查询应该快速运行:

SELECT * FROM transactionlist where TranDateTime> ='2008-08-17'AND TranDateTime <'2008-08-18'

而不是做一个基于函数的索引(如果这在MySQL中甚至可能)使你的where子句做一个范围比较。 就像是:

TranDateTime>'2008-08-17 00:00:00'和TranDateTime <'2008-08-17 11:59:59')

这让数据库使用TranDateTime上的索引(有一个,对吗?)做select。

创build一个新的字段只有dateconvert(datetime, left(date_field,10)) ,然后索引。

我不知道mySQL的具体情况,但是仅仅索引整个date字段有什么害处呢?

如果你对*树使用函数魔术,哈希,…不见了,因为获取值必须调用函数。 但是,由于您不知道未来的结果,您必须对表格进行全面扫描。

没有什么补充。

也许你的意思是像计算(计算)的指标…但迄今为止,我只在IntersystemsCaché上看到这个。 我不认为在关系数据库(AFAIK)中有这种情况。

在我看来,一个好的解决scheme是以下(更新的clintp示例):

 SELECT * FROM translist WHERE TranDateTime >= '2008-08-17 00:00:00.0000' AND TranDateTime < '2008-08-18 00:00:00.0000' 

无论您使用00:00:00.0000还是00:00在我看来都没有什么区别(我通常以这种格式使用它)。

为什么没有人build议使用LIKE? 这样做也不是吗? 它会像BETWEEN一样快吗?

 SELECT * FROM transactionlist where TranDateTime LIKE '2008-08-17%'