Add minutes to datetime in SQL SELECT from other column - mysql

I have an SQL query, which selects a datetime from a database. In another column called "add_minutes" are minutes I want to add to the datetime within the query. It should look like this:
SELECT * from availability WHERE ? < (datetime_start + add_minutes)
Any hints how to solve this?
Thank you!

SELECT *
FROM availability
WHERE ? < DATE_ADD(datetime_start, INTERVAL add_minutes MINUTE)
Also:
SELECT *
FROM availability
WHERE ? < ADDTIME(datetime_start, SEC_TO_TIME(add_minutes * 60))
Note that MySql is dumb, and both DATE_ADD() and ADDTIME() work with string expressions. Because of potential localization/formatting issues, converting between numbers and strings can be surprisingly expensive operations, especially if you have to do this for every column in a table.
Additionally, what we're doing here breaks any possibility of using indexes you might have on these columns. You can improve performance considerably like this:
SELECT *
FROM availability
WHERE ADDTIME(?, SEC_TO_TIME(add_minutes * -60)) < datetime_start
This inverts the interval and adds it to the source value instead. It still needs to look at every value in the add_minutes column, regardless of index, but now datetime_start is unchanged, and therefore indexes on that column can still be used.
Just for fun, here's how Sql Server does it:
SELECT *
FROM availability
WHERE DATEADD(minute, add_minutes * -1, ?) < datetime_start
Sql Server is less dumb about it's DATEADD() function. Everything here is numeric; there are no messy conversions between strings and numbers or dates. Sql Server also supports computed columns with indexes. So you could include an column in the table defined as DATEADD(minute, add_minutes, datetime_start), and have an index on that column. IIRC, MySql also supports computed columns, but does not support indexes on those columns.

Related

My Query is too slow

My query that I made is too slow. It takes more than one minute. How can I quickly create a query?
Can you help me?
select * from nss_sikdan_ok where od_id in(
select od_id from nss_order od
join nss_cart ct on od.on_uid=ct.on_uid
where ct.ct_status in('cart','sell')) and (DATE_FORMAT(today_end_date,'%Y-%m-%d')='2017-05-05') and today_end='1' limit 0,1
There are few things you can do to optimize this query.
On the query side:
Avoid calling functions on potentially indexed columns - as it won't allow MySQL to use the index on that column. The following condition:
DATE_FORMAT(today_end_date,'%Y-%m-%d')='2017-05-05'
Can be modified to this one, to avoid using the DATE_FORMAT function on the indexed column and instead only use functions on constant values:
today_end_date >= DATE('2017-05-05') AND today_end_date < (DATE('2017-05-05') + INTERVAL 1 DAY)
====
Do not use OFFSET values in your query - Instead of LIMIT X,Y, you can use the alternative approach for faster pagination with offset in MySQL.
===
Avoid selecting unused columns - in most cases, selecting all columns using the '*' operator will cause performance issues, as you're fetching more information than you actually need. Think about which columns you actually need in the result set and fetch them.
===
Use numeric values whenever appropriate - When comparing a numeric column to a string, you're forcing MySQL to cast the column's value for each row from a number to a string and only then perform the comparison. Therefore, in the condition today_end='1', if today_end is a numeric column, the condition should be:
today_end = 1
Instead of:
today_end = '1'
===
Also, if you can provide the schema structure, it will be possible to recommend the appropriate indexes for this situation.
By the way, I got the recommendations from this online MySQL query optimizer, so feel free to just enter your query and schema there and get indexing recommendations as well.

Why does MySQL drops my index when using DATE(`table`.`column`)

I have a MySQL innodb table with a few columns.
one of them is named "dateCreated" which is a DATETIME column and it is indexed.
My query:
SELECT
*
FROM
`table1`
WHERE
DATE(`dateCreated`) BETWEEN '2014-8-7' AND '2013-8-7'
MySQL for some reason refuses to use the index on the dateCreated column (even with USE INDEX or FORCE INDEX.
However, if I change the query to this:
SELECT
*
FROM
`table1`
WHERE
`dateCreated` BETWEEN '2014-8-7' AND '2013-8-7'
note the DATE(...) removal
MySQL uses the index just fine.
I could manage without using the DATE() function, but this is just weird to me.
I understand that maybe MySQL indexes the full date and time and when searching only a part of it, it gets confused or something. But there must be a way to use a partial date (lets say MONTH(...) or DATE(...)) and still benefit from the indexed column and avoid the full table scan.
Any thoughts..?
Thanks.
As you have observed once you apply a function to that field you destroy access to the index. So,
It will help if you don't use between. The rationale for applying the function to the data is so you can get the data to match the parameters. There are just 2 parameter dates and several hundred? thousand? million? rows of data. Why not reverse this, change the parameters to suit the data? (making it a "sargable" predicate)
SELECT
*
FROM
`table1`
WHERE
( `dateCreated` >= '2013-08-07' AND `dateCreated` < '2014-08-07' )
;
Note 2013-08-07 is used first, and this needs to be true if using between also. You will not get any results using between if the first date is younger than the second date.
Also note that exactly 12 months of data is contained >= '2013-08-07' AND < '2014-08-07', I presume this is what you are seeking.
Using the combination of date(dateCreated) and between would include 1 too many days as all events during '2014-08-07' would be included. If you deliberately wanted one year and 1 day then add 1 day to the higher date i.e. so it would be < '2014-08-08'

Does a query optimizer convert expressions to constants when the expression does not involve a column

I have queries that are similar to:
-- MySQL Query
SELECT * FROM table1 WHERE start_date >= CURRENT_TIMESTAMP - INTERVAL 7 DAY
-- MSSQL Query
SELECT * FROM table1 WHERE start_date >= GETDATE() - 7
Since the expression on the right hand side does not depend on the column values, should I expect the query optimizer to optimize it into a constant value such as:
SELECT * FROM table1 WHERE start_date >= '2012-04-28 14:54:31'
Or should I calculate the constants and build a query using code.
According to the documentation for MySQL's NOW() function (for which CURRENT_TIMESTAMP is a synonym):
NOW() returns a constant time that indicates the time at which the statement began to execute. (Within a stored function or trigger, NOW() returns the time at which the function or triggering statement began to execute.) This differs from the behavior for SYSDATE(), which returns the exact time at which it executes.
As such, the query optimiser will treat it as a constant, as desired. One can see this in the EXPLAIN output.
I can't speak for MSSQL, although perhaps this blog is worth a read?
You have a function on the right side, not a constant. The query must be reevaluated each time...
(do i miss a point ??)
EDIT
Like #Martin and #eggyval kindly explained i really did miss a point. The question is very clearly not about a compile time optimization, so i leave this poor, poor remark as a monument to what should happen to a jerk like me...

slow sql query - selecting data depending on date interval

I have a query that is causing me some trouble. I'm wondering if there is a better way to write this SQL;
SELECT * FROM report
WHERE blogid = 1769577
AND DATE_SUB(CURDATE(),INTERVAL 30 DAY) <= datetime
so as its faster to fetch the results.
Thanks in advance.
I don't see anything wrong with the query, but you could make sure to have indexes on the blogid and datetime columns
If your table is huge, you might consider horizontal partitioning, which can have a significant impact on performance. See http://dev.mysql.com/tech-resources/articles/performance-partitioning.html
In Oracle SQL, you can do date arithmetic through +/- operators. I don't know if it would work in MySQL, but you might as well try doing datetime >= (CURDATE() - 30).
SELECT * FROM report WHERE blogid = 1769577 AND datetime >= (curdate() - 30)
Edit: This blog entry seems to confirm my suggestion: http://mysql-tips.blogspot.com/2005/04/mysql-date-calculations.html
I suggest using the internal datediff() function instead of subtract the interval. like this:
datediff(curdate(), datetime) < 30
so the query is:
SELECT * FROM report WHERE blogid = 1769577 AND datediff(curdate(), datetime) < 30
Guess 1: your blogid is not an int column. Then you can read the MySQL manual:
Comparison of dissimilar columns may
prevent use of indexes if values
cannot be compared directly without
conversion. Suppose that a numeric
column is compared to a string column.
For a given value such as 1 in the
numeric column, it might compare equal
to any number of values in the string
column such as '1', ' 1', '00001', or
'01.e1'. This rules out use of any
indexes for the string column.
Guess 2: your blogid is not indexed.
Guess 3: the reports table is myisam. In this case when you modify data MySQL uses table level locking on the whole reports table. You say that every time a blog is viewed a new record is added. These frequent updates may cause table level locking and slow down your select queries.
Otherwise your query is fine.
Cheers!

Timestamp as int field, query performance

I'm storing timestamp as int field. And on large table it takes too long to get rows inserted at date because I'm using mysql function FROM_UNIXTIME.
SELECT * FROM table WHERE FROM_UNIXTIME(timestamp_field, '%Y-%m-%d') = '2010-04-04'
Is there any ways to speed this query? Maybe I should use query for rows using timestamp_field >= x AND timestamp_field < y?
Thank you
EDITED This query works great, but you should take care of index on timestamp_field.
SELECT * FROM table WHERE
timestamp_field >= UNIX_TIMESTAMP('2010-04-14 00:00:00')
AND timestamp_field <= UNIX_TIMESTAMP('2010-04-14 23:59:59')
Use UNIX_TIMESTAMP on the constant instead of FROM_UNIXTIME on the column:
SELECT * FROM table
WHERE timestamp_field
BETWEEN UNIX_TIMESTAMP('2010-04-14 00:00:00')
AND UNIX_TIMESTAMP('2010-04-14 23:59:59')
This can be faster because it allows the database to use an index on the column timestamp_field, if one exists. It is not possible for the database to use the index when you use a non-sargable function like FROM_UNIXTIME on the column.
If you don't have an index on timestamp_field then add one.
Once you have done this you can also try to further improve performance by selecting the columns you need instead of using SELECT *.
If you're able to, it would be faster to either store the date as a proper datetime field, or, in the code running the query, to convert the date you're after to a unix timestamp before sending it to the query.
The FROM_UNIXTIME would have to convert every record in the table before it can check it which, as you can see, has performance issues. Using a native datatype that is closest to what you're actually using in your queries, or querying with the column's data type, is the fastest way.
So, if you need to continue using an int field for your time, then yes, using < and > on a strict integer would boost performance greatly, assuming you store things to the second, rather than the timestamp that would be for midinight of that day.