Почему мой запрос MySQL с использованием подзапроса зависает?

StackOverflow https://stackoverflow.com/questions/1601935

  •  05-07-2019
  •  | 
  •  

Вопрос

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

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

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

Комментатор хотел получить полное предложениеwhere:

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);
Это было полезно?

Решение

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

SELECT * FROM ta WHERE aid IN (SELECT subquery)

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

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

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

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

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

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

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

Другие советы

Смотрите " Невыносимую медлительность IN " ;: http://www.artfulsoftware.com/infotree/queries.php#568

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

   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

Если ваш подзапрос работает нормально, когда он выполняется отдельно, попробуйте использовать 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);

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

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

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

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

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

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;

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top