Mysql Sub Select Query Optimization - PullRequest
       7

Mysql Sub Select Query Optimization

0 голосов
/ 18 января 2010

Я ежедневно запускаю запрос для компиляции статистики, но он кажется действительно неэффективным. Это запрос:

SELECT a.id, tstamp, label_id, (SELECT author_id FROM b WHERE b.tid = a.id ORDER BY b.tstamp DESC LIMIT 1) AS author_id
FROM a, b
WHERE (status = '2' OR status = '3') 
AND category != 6
AND a.id = b.tid
AND (b.type = 'C' OR b.type = 'R')
AND a.tstamp1 BETWEEN {$timestamp_start} AND {$timestamp_end}
ORDER BY b.tstamp DESC
LIMIT 500

Этот запрос выполняется очень медленно. Извиняюсь за дерьмовое наименование - меня попросили не раскрывать настоящие имена таблиц.

Причина, по которой существует дополнительный выбор, заключается в том, что внешний выбор получает одну строку из таблицы a и получает строку из таблицы b. Но также необходимо знать последний идентификатор author_id из таблицы b, поэтому я запускаю подвыбор, чтобы вернуть его. Я не хочу запускать другой выбор внутри цикла php - это тоже неэффективно.

Это работает правильно - мне просто нужно найти гораздо более быстрый способ получения этого набора данных.

Ответы [ 2 ]

2 голосов
/ 18 января 2010

Если b.tstamp уникален в пределах b.tid, возьмите решение OMG Ponies.

В противном случае вы можете попробовать это решение. Он сортирует весь результат по b.tstamp DESC и добавляет рейтинг за author_id. Внешний выбор занимает только строку с rank = 1, то есть с наибольшим tstamp на author_id.

SELECT id, tstamp, label_id, author_id
  FROM (SELECT id,
               tstamp,
               label_id,
               author_id,
               CASE
                 WHEN @author_id != author_id THEN @row_num := 1 
                 ELSE @row_num := @row_num + 1
               END AS rank,
               @author_id := b.author_id
          FROM a,
               b,
               (SELECT @row_num := 0, @author_id := NULL) y
          WHERE a.id = b.tid
          AND (status = '2' OR status = '3') 
          AND category != 6
          AND (b.type = 'C' OR b.type = 'R')
          AND a.tstamp1 BETWEEN {$timestamp_start} AND {$timestamp_end}
          ORDER BY b.author_id, b.tstamp DESC
  ) x
 WHERE x.rank = 1
LIMIT 500

Я не пробовал, поэтому, пожалуйста, прокомментируйте, если он не работает.

2 голосов
/ 18 января 2010

Попробуйте:

  SELECT a.id,
         b.tstamp,
         label_id,
         y.author_id
    FROM TABLE_A a
    JOIN TABLE_B b ON b.tid = a.id
    JOIN (SELECT b.tid,
                 MAX(b.tstamp) 'm_tstamp'
            FROM TABLE_B b
        GROUP BY b.tid) x ON x.tid = a.id
    JOIN (SELECT b.tid,
                 b.author_id,
                 b.tstamp
            FROM TABLE_B b
        GROUP BY b.tid) y ON y.tid = a.id
                         AND y.tstamp = x.m_tstamp
   WHERE status IN ('2', '3')
     AND b.type IN ('C', 'R')
     AND category != 6
     AND a.tstamp1 BETWEEN {$timestamp_start} AND {$timestamp_end}
ORDER BY b.tstamp DESC 
   LIMIT 500
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...