MYSQL: как найти записи, соответствующие MIN () из дорогостоящей функции - PullRequest
1 голос
/ 15 октября 2011

Я выполняю сложный и дорогостоящий запрос, чтобы найти значения MIN () функции, сгруппированной по другому атрибуту.Но мне не просто нужно значение, мне нужна запись, которая его производит + значение.

Мой текущий псевдопросмотр выглядит примерно так:

SELECT MIN(COSTLY_FUNCTION(a.att1,a.att2,$v1,$v2)) FROM (prefiltering) as a GROUP BY a.group_att;

но я хочу a.*и MIN(COSTLY_FUNCTION(a.att1,a.att2,$v1,$v2)) как мой результат.

Единственный способ, которым я могу придумать, - использовать этого уродливого зверя:

SELECT a1.*, COSTLY_FUNCTION(a1.att1,a1.att2,$v1,$v2)
FROM (prefiltering) as a1 
WHERE COSTLY_FUNCTION(a1.att1,a1.att2,$v1,$v2) = 
  (SELECT MIN(COSTLY_FUNCTION(a.att1,a.att2,$v1,$v2)) FROM (prefiltering) as a GROUP BY a.group_att) 

Но теперь я выполняю prefiltering_query 2 раза и мне нужно запуститьдорогая функция в два раза.Это смешно, и я надеюсь, что я делаю что-то серьезно неправильно.

Возможное решение?:

Только сейчас я понимаю, что могу создать временную таблицу, содержащую:

(SELECT a1.*, COSTLY_FUNCTION(a1.att1,a1.att2,$v1,$v2) as complex FROM (prefiltering) as a1)

, а затем запустите MIN () как подзапрос и сравните его при значительно сниженной стоимости.Это путь?

Ответы [ 2 ]

1 голос
/ 15 октября 2011

Проблема с решением для временных таблиц заключается в том, что я не вижу способа избежать использования дважды в одном и том же запросе .

Однако, если вы готовы использоватьфактическая постоянная таблица (возможно, с ENGINE = MEMORY), она должна работать.Вы также можете переместить подзапрос в предложение FROM, где оно может быть более эффективным:

CREATE TABLE temptable ENGINE = MEMORY
  SELECT a1.*,
    COSTLY_FUNCTION(a1.att1,a1.att2,$v1,$v2) AS complex
  FROM prefiltering AS a1;

CREATE INDEX group_att_complex USING BTREE
  ON temptable (group_att, complex);

SELECT a2.*
FROM temptable AS a2
  NATURAL JOIN (
    SELECT group_att, MIN(complex) AS complex
    FROM temptable GROUP BY group_att
  ) AS a3;

DROP TABLE temptable;

(Вы можете попробовать его и без индекса, но я подозреваю, что с ним это будет быстрее.)

Редактировать: Конечно, если одна временная таблица не подойдет, вы всегда можете использовать две:

CREATE TEMPORARY TABLE temp1
  SELECT *, COSTLY_FUNCTION(att1,att2,$v1,$v2) AS complex
  FROM prefiltering;

CREATE INDEX group_att_complex ON temp1 (group_att, complex);

CREATE TEMPORARY TABLE temp2
  SELECT group_att, MIN(complex) AS complex
  FROM temp1 GROUP BY group_att;

SELECT temp1.* FROM temp1 NATURAL JOIN temp2;

(Опять же, вы можете попробоватьс индексом или без него, когда я запускал EXPLAIN, MySQL, похоже, вообще не хотел использовать индекс для окончательного запроса, хотя это могло быть только потому, что мой набор тестовых данных был настолько мал. вот ссылка на SQLize , если вы хотите поиграть с ним; я использовал CONCAT(), чтобы заменить вашу дорогую функцию.)

0 голосов
/ 15 октября 2011

Вы можете использовать предложение HAVING для получения столбцов в дополнение к этому значению MIN. Например:

SELECT a.*, COSTLY_FUNCTION(a.att1,a.att2,$v1,$v2) FROM (prefiltering) as a GROUP BY a.group_att HAVING MIN(COSTLY_FUNCTION(a.att1,a.att2,$v1,$v2)) = COSTLY_FUNCTION(a.att1,a.att2,$v1,$v2);
...