I am running a select statement in a report that returns 30 rows in 30 mS. When I add fields to the SELECT clause that are based on a custom function, the same query takes minutes to run.
The custom function takes three parameters – all from the main query – does its own COUNT() query then returns the integer result. The query in the custom function by itself runs in a 10mS, but when run from within the custom function, it takes 300mS.
Are custom functions compiled each time they are encountered in a query? What could be the reason for the slowness? In my Oracle days (15 years ago), I was used to creating custom functions, sticking them into queries, and they would zip through their actions. Are MySQL custom functions fundamentally different?
Edit:
I have just spotted this: if the custom function takes parameters passed to it from the query it is used in, then it is very slow. If I put in hard-coded parameter values, then it is very fast.
e.g.
SELECT my_func(foo.col1, foo.col2, foo.col2)
FROM foo;
-- 120 seconds for 30 rows
SELECT my_func(1, 2, 3)
FROM foo;
-- 10 milli seconds for 30 rows
I can SELECT my_func(x, y, z), where x, y and z are any combination of values that would be passed to it in the first query example, and the database barely blinks. I’m really scratching my head on this one.
The reason I need this function is to enable me to run a report in SugarCRM. The report writing plugin (KReports) gives me access to certain entities and relationships in the database, but there are a bunch of counts that the report does not allow access to. The custom function has been created to return the counts (ten of them) for each row the main report returns, effectively giving the user a 10xN value pivot table.
The report is only returning a handful of rows each time it returns, and that is what was fooling me. Those results are grouped from the underlying data, which is much larger. The custom function is being executed (I am assuming) on the main data set before the GROUP BY is applied, and so is being called up an order of magnitude more times than I thought.
If I had full control over the generation of the SQL in this report, I would select the 30 (groups) rows in an inner query, then wrap that in an outer query to call up the custom function on that smaller data set. It looks like I am going to have to use a different reporting tool to fix this.
My answer, in summary, is that the custom function was being called up 7000 times in a query and not 300 times as I originally thought. 300 times would be fine for this report, taking about 10 seconds. 7000 times takes over 3 minutes and is no good.
The reason is that the custom function in the SELECT clause gets applied to all rows retrieved in the query before the GROUP BY clause is applied. The GROUP BY reduces the 700 rows retrieved to just 30 unique rows.
I cannot change the way the query works in the reporting tool that I am using, so will move to a new reporting tool that provides more flexibility and more control over how the SQL is constructed.