如何在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%'