Monday, 8 October 2018

How does one create an index on the date part of DATETIME field in MySql

How do I create an index on the date part of DATETIME field?
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 is used to save the date and time of a transaction as it happens
My Table has over 1,000,000 records in it and the statement
SELECT * FROM transactionlist where date(TranDateTime) = '2008-08-17' 
takes a long time.

If I remember correctly, that will run a whole table scan because you're passing the column through a function. MySQL will obediently run the function for each and every column, bypassing the index since the query optimizer can't really know the results of the function.
What I would do is something like:
SELECT * FROM transactionlist 
WHERE TranDateTime BETWEEN '2008-08-17 00:00:00' AND '2008-08-18 23:59:59';
That should give you everything that happened on 2008-08-17, and everything that happened at exactly 2008-08-18 00:00:00. If that's a problem, you could change the second term to '2008-08-17 23:59:59' and just get 2008-08-17.



You can't create an index on just the date part. Is there a reason you have to?
Even if you could create an index on just the date part, the optimiser would probably still not use it for the above query.
I think you'll find that
SELECT * FROM transactionlist WHERE TranDateTime BETWEEN '2008-08-17' AND '2008-08-18'
Is efficient and does what you want.



I don't know about the specifics of mySql, but what's the harm in just indexing the date field in its entirety?
Then just search:
 select * from translist 
     where TranDateTime > '2008-08-16 23:59:59'
        and TranDateTime < '2008-08-18 00:00:00'
If the indexes are b-trees or something else that's reasonable, these should get found quickly.



The one and good solution that is pretty good working is to use timestamp as time, rather than datetime. It is stored as INT and being indexed good enough. Personally i encountered such problem on transactions table, that has about million records and slowed down hard, finally i pointed out that this caused by bad indexed field (datetime). Now it runs very quick.



What does 'explain' say? (run EXPLAIN SELECT * FROM transactionlist where date(TranDateTime) = '2008-08-17')
If it's not using your index because of the date() function, a range query should run fast:
SELECT * FROM transactionlist where TranDateTime >= '2008-08-17' AND TranDateTime < '2008-08-18'



Create a new fields with just the dates convert(datetime, left(date_field,10)) and then index that.



Why didn't anyone suggest using LIKE? Doesn't that do the job as well? Will it be as fast as BETWEEN?
SELECT * FROM transactionlist where TranDateTime LIKE '2008-08-17%'

0 comments:

Post a Comment