For the query above, the following recommendations will be helpful as part of the SQL tuning process.
You'll find 3 sections below:
The optimization process and recommendations:
- Avoid Calling Functions With Indexed Columns (query line: 20): When a function is used directly on an indexed column, the database's optimizer won’t be able to use the index. For example, if the column `day` is indexed, the index won’t be used as it’s wrapped with the function `DATEPART`. If you can’t find an alternative condition that won’t use a function call, a possible solution is to store the required value in a new indexed column.
- Avoid Calling Functions With Indexed Columns (query line: 20): When a function is used directly on an indexed column, the database's optimizer won’t be able to use the index. For example, if the column `transactionTime` is indexed, the index won’t be used as it’s wrapped with the function `DATEPART`. If you can’t find an alternative condition that won’t use a function call, a possible solution is to store the required value in a new indexed column.
- Avoid Subqueries (query line: 7): We advise against using subqueries as they are not optimized well by the optimizer. Therefore, it's recommended to join a newly created temporary table that holds the data, which also includes the relevant search index.
- Explicitly ORDER BY After GROUP BY (modified query below): By default, the database sorts all 'GROUP BY col1, col2, ...' queries as if you specified 'ORDER BY col1, col2, ...' in the query as well. If a query includes a GROUP BY clause but you want to avoid the overhead of sorting the result, you can suppress sorting by specifying 'ORDER BY NULL'.
- Index Function Calls Using Generated Columns (modified query below): When a function is used directly on an indexed column, the database's optimizer won’t be able to use the index to optimize the search. Creating and indexing a generated column (supported in MySQL 5.7) will allow MySQL to optimize the search.
The optimized query:
SELECT
a.year,
b.month,
c.day,
totalVolume
FROM
(SELECT
DATEPART(year,
DOW30.transactionTime) AS year,
DATEPART(month,
DOW30.transactionTime) AS month,
DATEPART(day,
DOW30.transactionTime) AS day,
SUM(DOW30.volume) AS totalVolume
FROM
DOW30
GROUP BY
DOW30.datepart_year_transactiontime,
DOW30.datepart_month_transactiontime,
DATEPART(day,
DOW30.transactionTime)
ORDER BY
NULL) a
ORDER BY
a.year,
b.month,
c.day