SQL 쿼리 최적화
-
22-08-2019 - |
문제
이 쿼리를 최적화하려면 어떻게 해야 합니까?
SELECT * FROM
(SELECT `item`.itemID, COUNT(`votes`.itemID) AS `votes`,
`item`.title, `item`.itemTypeID, `item`.
submitDate, `item`.deleted, `item`.ItemCat,
`item`.counter, `item`.userID, `users`.name,
TIMESTAMPDIFF(minute,`submitDate`,NOW()) AS 'timeMin' ,
`myItems`.userID as userIDFav, `myItems`.deleted as myDeleted
FROM (votes `votes` RIGHT OUTER JOIN item `item`
ON (`votes`.itemID = `item`.itemID))
INNER JOIN
users `users`
ON (`users`.userID = `item`.userID)
LEFT OUTER JOIN
myItems `myItems`
ON (`myItems`.itemID = `item`.itemID)
WHERE (`item`.deleted = 0)
GROUP BY `item`.itemID,
`votes`.itemID,
`item`.title,
`item`.itemTypeID,
`item`.submitDate,
`item`.deleted,
`item`.ItemCat,
`item`.counter,
`item`.userID,
`users`.name,
`myItems`.deleted,
`myItems`.userID
ORDER BY `item`.itemID DESC) as myTable
where myTable.userIDFav = 3 or myTable.userIDFav is null
limit 0, 20
나는 MySQL을 사용하고 있습니다
감사해요
해결책
물론 @theomega가 말했듯이 실행 계획을 살펴보십시오.
그러나 나는 또한 당신의 진술을 "정리"하는 것을 제안하고 싶습니다.(어느 것이 더 빠른지는 모르겠습니다. 이는 테이블 크기에 따라 다릅니다.) 일반적으로 저는 깔끔한 문장으로 시작하여 거기서부터 최적화를 시작하려고 합니다.그러나 일반적으로 깔끔한 문은 최적화 프로그램이 좋은 실행 계획을 세우는 것을 더 쉽게 만듭니다.
따라서 상황을 느리게 만들 수 있는 귀하의 진술에 대한 몇 가지 관찰 사항은 다음과 같습니다.
- 두 개의 외부 조인(최적자가 사용할 인덱스를 파악하기 어렵게 만듭니다)
- 그룹화
- 그룹화할 열이 많음
내가 이해하는 한 귀하의 SQL은 다음 명령문이 귀하가 수행하는 작업의 대부분을 수행해야 합니다.
SELECT `item`.itemID, `item`.title, `item`.itemTypeID, `item`.
submitDate, `item`.deleted, `item`.ItemCat,
`item`.counter, `item`.userID, `users`.name,
TIMESTAMPDIFF(minute,`submitDate`,NOW()) AS 'timeMin'
FROM (item `item` INNER JOIN users `users`
ON (`users`.userID = `item`.userID)
어디
물론 외부 조인 테이블의 정보가 누락되므로 하위 선택을 통해 필요한 열을 추가하는 것이 좋습니다.
SELECT `item`.itemID,
(SELECT count (itemID)
FROM votes v
WHERE v.itemID = 'item'.itemID) as 'votes', <etc.>
이렇게 하면 하나의 외부 조인과 그룹 기준을 제거할 수 있습니다.외부 조인은 하위 선택으로 대체되므로 "깔끔한" 문에는 좋지 않을 수 있는 절충안이 있습니다.
item과 myItems 사이의 카디널리티에 따라 동일한 작업을 수행하거나 외부 조인을 사용해야 합니다(그러나 그룹 기준을 다시 도입할 필요는 없음).
도움이 되었기를 바랍니다.
다른 팁
분석기는이 쿼리에 대해 무엇을 말합니까? 테이블에 얼마나 많은 행이 있는지에 대한 지식이 없으면 최적화를 말할 수 없습니다. 따라서 분석기를 실행하면 어떤 부품 비용이 드는지 볼 수 있습니다.
몇 가지 빠른 반 랜덤 생각 :
ItemID 및 UserID 열이 색인되어 있습니까?
쿼리 시작에 "설명"을 추가하고 실행하면 어떻게됩니까? 인덱스를 사용합니까? 그들은 합리적입니까?
전체 내부 쿼리를 실행하고 필터를 필터링해야합니까, 아니면 이동할 수 있습니까? where myTable.userIDFav = 3 or myTable.userIDFav is null
내부 쿼리에 참여 하시겠습니까?
그룹에 너무 많은 필드가있는 것 같습니다. 그중 하나는 ItemId이기 때문에 내부 선택을 사용하여 그룹화를 미리 형성하고 원하는 필드 세트를 반환하기 위해 외부 선택을 사용할 수 있다고 생각합니다.
WHERE 절을 추가 할 수 없습니다 mytable.useridfav = 3 또는 mytable.useridfav는 null입니다 에게 어디 (item
.deleted = 0)?
문안 인사
Lieven
쿼리가 구축되는 방식을 살펴보십시오. 많은 물건을 결합한 다음 출력을 20 행으로 제한합니다. 항목과 신분에 대한 외부 조인이 있어야합니다. 조건은이 두 테이블에만 적용되므로 출력을 처음 20 행으로 제한 한 다음 결합 및 집계를 제한합니다. 여기서 당신은 폐기 될 많은 작업을 수행하고 있습니다.