Почему мой MySQL-запрос с использованием подвыбора зависает? - PullRequest
0 голосов
/ 21 октября 2009

Зависает следующий запрос: (хотя подзапросы выполняются отдельно)

Я не знаю, как заставить таблицу объяснения выглядеть хорошо. Если кто-нибудь скажет мне, я уберу это.

select
sum(grades.points)) as p,  
from assignments 
left join grades using (assignmentID) 
where gradeID IN 

(select grades.gradeID 
from assignments 
left join grades using (assignmentID) 
where ... grades.date <= '1255503600' AND grades.date >= '984902400' 
group by     assignmentID order by grades.date DESC);

Я думаю, что проблема в таблице первых оценок ... тип ALL с таким количеством строк, кажется, является причиной ... Все проиндексировано.

Я загрузил таблицу в виде изображения. Не удалось получить правильное форматирование: http://imgur.com/AjX34.png

Комментатор хотел полный пункт, где:

explain extended select count(assignments.assignmentID) as asscount, sum(TRIM(TRAILING '-' FROM grades.points)) as p, sum(assignments.points) as t 
from assignments left join grades using (assignmentID) 
where gradeID IN 
(select grades.gradeID from assignments left join grades using (assignmentID) left join as_types on as_types.ID = assignments.type 
where assignments.classID = '7815' 
and (assignments.type = 30170 ) 
and grades.contactID = 7141 
and grades.points REGEXP '^[-]?[0-9]+[-]?' 
and grades.points != '-' 
and grades.points != '' 
and (grades.pointsposs IS NULL or grades.pointsposs = '') 
and grades.date <= '1255503600' 
AND grades.date >= '984902400' 
group by assignmentID 
order by grades.date DESC);

Ответы [ 6 ]

2 голосов
/ 21 октября 2009

См. «Невыносимая медлительность IN»: http://www.artfulsoftware.com/infotree/queries.php#568

1 голос
/ 22 октября 2009

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

SELECT * FROM ta WHERE aid IN (SELECT subquery)

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

  • Если количество строк небольшое (скажем, менее нескольких миллионов)

Он запустит подзапрос, затем создаст хэш идентификаторов в памяти, что также делает их уникальными, что является особенностью IN ().

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

  • Если, однако, количество строк в подзапросе достаточно велико

База данных, вероятно, перепишет ее как объединение JOIN, добавив Sort + Unique к подзапросу.

Однако вы используете MySQL. В этом случае он не будет делать ничего из этого (он будет повторно выполнять подзапрос для каждой строки вашей таблицы), поэтому это займет 1000 лет. К сожалению.

1 голос
/ 21 октября 2009

Супер грязно, но: (спасибо всем за помощь)

   SELECT * 
   FROM grades
   LEFT JOIN assignments ON grades.assignmentID = assignments.assignmentID
   RIGHT JOIN (

   SELECT g.gradeID
 FROM assignments a
 LEFT JOIN grades g
 USING ( assignmentID ) 
 WHERE a.classID =  '7815'
 AND (
 a.type =30170
 )
 AND g.contactID =7141
  g.points
 REGEXP  '^[-]?[0-9]+[-]?'
 AND g.points !=  '-'
 AND g.points !=  ''
 AND (
 g.pointsposs IS NULL 
 OR g.pointsposs =  ''
 )
 AND g.date <=  '1255503600'
 AND g.date >=  '984902400'
 GROUP BY assignmentID
 ORDER BY g.date DESC
 ) AS t1 ON t1.gradeID = grades.gradeID
0 голосов
/ 21 октября 2009

Запрос немного сложен, но я подозреваю, что подзапрос вообще не нужен. Похоже, ваш запрос в основном так:

SELECT FOO()
FROM assignments LEFT JOIN grades USING (assignmentID)  
WHERE gradeID IN 
(
SELECT grades.gradeID
FROM assignments LEFT JOIN grades USING (assignmentID)  
WHERE your_conditions = TRUE
);

Но вы не делаете ничего действительно фантастического в предложении where в подзапросе. Я подозреваю, что-то более похожее на

SELECT FOO()
FROM assignments LEFT JOIN grades USING (assignmentID)  
GROUP BY groupings
WHERE your_conditions_with_some_tweaks = TRUE;

будет работать так же хорошо.

Если мне не хватает какой-то ключевой логики здесь, пожалуйста, прокомментируйте, и я отредактирую / удалю этот пост.

0 голосов
/ 21 октября 2009

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

select count(assignments.assignmentID) as asscount, sum(TRIM(TRAILING '-' FROM grades.points)) as p, sum(assignments.points) as t 
from assignments left join grades using (assignmentID) 
join
(select grades.gradeID from assignments left join grades using (assignmentID) left join as_types on as_types.ID = assignments.type 
where assignments.classID = '7815' 
and (assignments.type = 30170 ) 
and grades.contactID = 7141 
and grades.points REGEXP '^[-]?[0-9]+[-]?' 
and grades.points != '-' 
and grades.points != '' 
and (grades.pointsposs IS NULL or grades.pointsposs = '') 
and grades.date <= '1255503600' 
AND grades.date >= '984902400' 
group by assignmentID 
order by grades.date DESC) using (gradeID);
0 голосов
/ 21 октября 2009

На самом деле не хватает информации, чтобы ответить на ваш вопрос, и вы поставили ... в середине предложения where, что странно. Насколько велики таблицы и каковы индексы?

Сказав, что, если в предложении in слишком много терминов, вы можете увидеть серьезно ухудшенную производительность. Заменить использование in правым соединением .

Для начала, таблица as_types в предложении in не используется. Оставленное присоединение к нему не имеет смысла, поэтому избавьтесь от него.

Таким образом, в предложении in есть только таблица назначений и оценок из внешнего запроса. Ясно, где измененные назначения принадлежат предложению where для внешнего запроса. Вы должны переместить все единицы, где grades = what , в предложение on левого соединения для оценок.

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