Возможно ли объединение этих (длинных) запросов MySQL? - PullRequest
1 голос
/ 03 декабря 2008

Хорошо, моя дилемма заключается в следующем. У меня есть страница администратора, которую я использую, чтобы получить сводку представленных за день заявок на один из моих сайтов. На этой странице суммирования извлекаются данные из нескольких таблиц, в некоторых из которых хранятся фактические данные мультимедиа, в других - URL-адреса, идентификаторы и владельцы веб-сайта, а в другой таблице хранится ежедневная статистика для расчета коэффициентов ввода / вывода для каждого домена.

Эта страница администратора имеет основной запрос, который извлекает фактические данные мультимедиа, который выглядит следующим образом (упрощенно):

SELECT 
    content.con_catid,
    content.con_posttime,
    content.con_url,
    content.con_id,
    content.con_title,
    categories.name, 
    users.username, 
    users.user_id, 
        FROM content
        LEFT JOIN categories 
        ON (content.con_catid = categories.id) 
        LEFT JOIN users
        ON (content.con_poster = users.user_id)  
        WHERE con_status = 0 ORDER BY con_posttime

Довольно прямо вперед. Затем, это где это становится грязным. Каждый раз, когда он зацикливается на операторе mysql_fetch_array (для вывода каждого элемента содержимого), я также выполняю следующие 2 запроса:

SELECT count(con_id) as pending FROM content WHERE con_poster = '$this_userid' AND con_status = 0

SELECT count(con_id) as approved FROM content WHERE con_poster = '$this_userid' AND con_status = 2

Они получают количество ожидающих и утвержденных элементов для каждого пользователя, которому принадлежит представление (которое указано рядом с каждой отправкой.

И затем есть убийца, который добавляет много времени ко времени выполнения страницы, так как он также должен повторяться для каждой строки исходного запроса.

SELECT website_url, 
website_id, 
website_shady, 
COALESCE(sum(dstats_hits),0)+website_in_ballast as total_in, 
COALESCE(sum(dstats_hits_out),0)+website_out_ballast as total_out, 
sum(dstats_hits_out_paid) as total_paid, 
website_in_ballast, 
website_out_ballast 
  FROM websites 
    LEFT JOIN domain_stats ON (websites.website_id = domain_stats.dstats_domid) 
    WHERE website_id IN (SELECT website_id FROM websites WHERE website_userid = $this_userid)
    GROUP BY website_url

Есть ли способ объединить последние 3 запроса в первый? Потому что сейчас .... если у меня 100 элементов в очереди, то это 301 запрос (401, если вы включите подзапрос), что занимает некоторое время для генерации страницы.

Ответы [ 5 ]

0 голосов
/ 03 декабря 2008

Вот еще одна попытка превратить его в один гигантский запрос. Не знаю, как быстро это будет, хотя ...

Редактировать: ОК, третья попытка. Это должно быть довольно быстро, если вы установите правильные индексы.

SELECT 
    content.con_catid,
    content.con_posttime,
    content.con_url,
    content.con_id,
    content.con_title,
    categories.name, 
    users.username, 
    users.user_id, 
    stats1.website_url, 
    websites.website_id, 
    websites.website_shady,
    websites.website_in_ballast, 
    websites.website_out_ballast,
    (SELECT COALESCE(sum(dstats_hits),0)+website.website_in_ballast FROM domain_stats WHERE websites.website_id = domain_stats.dstats_domid) as total_in,
    (SELECT COALESCE(sum(dstats_hits_out),0)+website_out_ballast FROM domain_stats WHERE websites.website_id = domain_stats.dstats_domid) as total_out,
    (SELECT sum(dstats_hits_out_paid) FROM domain_stats WHERE websites.website_id = domain_stats.dstats_domid) as total_paid,
    (SELECT count(c2.con_id) FROM content c2 WHERE c2.con_poster = user.user_id AND con_status = 0) as pending,
    (SELECT count(c2.con_id) FROM content c2 WHERE c2.con_poster = user.user_id AND con_status = 2) as approved
FROM
    content
    LEFT JOIN categories ON (content.con_catid = categories.id) 
    LEFT JOIN users ON (content.con_poster = users.user_id)
    LEFT JOIN websites ON (website_userid=users.user_id)
WHERE
    con_status = 0
ORDER BY
    con_posttime
0 голосов
/ 03 декабря 2008

Присоединение к контенту еще раз для определенного user_id даст вам возможность подсчитать.

SELECT 
        content.con_catid,
        content.con_posttime,
        content.con_url,
        content.con_id,
        content.con_title,
        categories.name, 
        users.username, 
        users.user_id, 
        IFNULL(SUM(CASE WHEN c2.con_status = 0 THEN 1 ELSE 0 END), 0) as pending,
        IFNULL(SUM(CASE WHEN c2.con_status = 2 THEN 1 ELSE 0 END), 0) as approved
    FROM content
    LEFT JOIN categories 
       ON (content.con_catid = categories.id) 
    LEFT JOIN users
       ON (content.con_poster = users.user_id)  
    LEFT JOIN content as c2 ON users.user_id = c2.con_poster

    WHERE con_status = 0 

    GROUP BY content.con_id
    ORDER BY con_posttime

Это не проверено. Возможно, вы сможете присоединиться к контенту дважды и использовать COUNT (DISTINCT c2.con_id) как ожидающий, а COUNT (DISTINCT c3.con_id) как одобренный, если оператор CASE замедлен, то вы добавляете c2.con_status = 0 в ваше объединение пункт (для ожидающих сообщений).

IFNULL есть на тот случай, если у вас не будет никаких сообщений (что никогда не будет правдой, поскольку основная строка содержимого всегда будет существовать. Вы можете запретить текущее сообщение в предложении JOIN, если не хотите считать она.)

Для последнего запроса я бы выбрал всю информацию для всех пользователей, которых вы обрабатываете (сохраняя все идентификаторы, затем вызывайте его, используя взамен user_id IN (), или подвыбор (в зависимости от того, как вы делаете выбор).

Затем сортировка и обработка данных в коде. Это минимизирует количество запросов.

0 голосов
/ 03 декабря 2008

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

SELECT 
    col_1,
    col_2,
    col_3,
    (
        SELECT col_1
        FROM table_2
        WHERE table_2.col_2 = table_1.col_1
    ) as 'col4',
    col_5
FROM
    table_1

Совершенно законно.

0 голосов
/ 03 декабря 2008

Хм ... первый запрос просто выбирает элементы контента, в то время как другие запросы выбирают некоторую статистику о них. Первый запрос не использует никаких агрегатных функций, в то время как все остальные используют. Таким образом, я могу видеть, что вы можете присоединиться к ним только с помощью подзапросов. Это не улучшит план выполнения, но сэкономит вам пару сотен разборов запросов и генерацию набора результатов, поэтому он должен быть несколько быстрее.

Один совет, хотя - средние два запроса могут быть объединены следующим образом:

SELECT
    count(case when con_status=0 then 1 else null end) as pending,
    count(case when con_status=2 then 1 else null end) as approved
FROM
    content
WHERE
    con_poster = '$this_userid'
0 голосов
/ 03 декабря 2008

Я еще не обдумал третий дополнительный запрос, но для первых двух вы можете сделать что-то вроде:

SELECT count(con_id) as pending, con_poster FROM content 
WHERE con_status = 0
GROUP BY con_poster

и затем присоедините их к первому запросу на con_poster.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...