[MySQL] Optymalizacja zapytania

0

Muszę zoptymalizować te zapytanie. Nie mam już pomysłów jak to zrobić. Proszę o pomoc:

SELECT SQL_CALC_FOUND_ROWS 
	`IA`.`url` AS `URL`, 
	`IA`.`date` AS `Date`, 
	`IA`.`tags` AS `Tags`, 
	`AA`.`topic` AS `Topic`, 
	`AA`.`contents` AS `Contents`, 
	`IA`.`options` AS `Options`, 
	`AA`.`author` AS `Author` 
FROM 
	`xv_articleindex` as `IA`, 
	`xv_article` as `AA` 
WHERE 
	`IA`.`accepted` = 1 AND 
	`IA`.`category` = "/Filmy/Online/" AND 
	`IA`.`adressinsql` = `AA`.`idarticle` AND 
	`AA`.`version` = (SELECT MAX(`version`) FROM `xv_article` AS `MG` WHERE `MG`.`idarticle` = `AA`.`idarticle`) 
ORDER BY `IA`.`date` 
DESC 
LIMIT 15

Po tym zapytaniu zabijam serwer MySQL - działa wyśmienicie do 2000 rekordów. Gdy teraz mam 15 000 to wysypuje się serwer.

O to jest dostęp do mysql dla testów:
phpmyadmin: http://phpmyadmin.bordeux.net
chive: http://chive.bordeux.net/

Login: bordeux_4ptest
Hasło: 4programmers

1
  1. Zrób normalnego JOINa. To co masz teraz to iloczyn kartezjański. Jeśli w tabelach "xv_articleindex" i "xv_article" masz po 15 000 rekordów, to tworzysz tabelę tymczasową na 225 milionów wierszy.

  2. Nie wiem czy dobrze rozumiem strukturę twojej bazy ("xv_article.idatricle" to klucz podstawowy?), ale moim zdaniem podzapytanie w WHERE jest kompletnie bez sensu i jakbyś ten ostatni warunek wywalił, to dostawałbyś takie same wyniki.

1

SQL_CALC_FOUND_ROWS jest fajne, ale jednak powolne :( Sprobuj bez tego. Bedziesz musial rozdzielic zapytanie na dwa, jedno z uzyciem COUNT(*) aby obliczyc ilosc wierszy.

1
SELECT SQL_CALC_FOUND_ROWS 
        `IA`.`url` AS `URL`,
        `IA`.`date` AS `Date`,
        `IA`.`tags` AS `Tags`,
        `AA`.`topic` AS `Topic`,
        `AA`.`contents` AS `Contents`,
        `IA`.`options` AS `Options`,
        `AA`.`author` AS `Author`
FROM
        `xv_articleindex` AS `IA` INNER JOIN
        `xv_article` AS `AA` ON (`IA`.`adressinsql` = `AA`.`idarticle`) INNER JOIN
        (SELECT `idarticle`, MAX(`version`) AS `version` FROM `xv_article` GROUP BY `idarticle`) AS `MG` ON (`AA`.`idarticle`=`MG`.`idarticle`)
WHERE
        `IA`.`accepted` = 1 AND
        `IA`.`category` = "/Filmy/Online/"  AND
        `AA`.`version` = `MG`.`version`
ORDER BY `IA`.`date`
DESC
LIMIT 15 

Pozdrawiam
paweld

0

Dziękuje za wszystkie odpowiedzi. Właśnie męczyłem się z Inner Joinem, lecz problem nastał przy pobraniu najwyższej wersji. W tym momencie z całego serca chce podziękować
Pawłowi Dmitrukowi - dobra robota, masz piwo w Chorzowie.

A co do SQL_CALC_FOUND_ROWS -> też dziękuje za poradę. To jest prawda że jest to o wiele wolniejsze. Nie wiem dlaczego MySQL tego nie zoptymalizuje. Bo według logiki musi być to szybsze? Czemu? Bo jak używamy COUNT(*) .... WHERE - to znów pytamy serwer o to samo - znów musi szukać danych rekordów. Natomiast jak SQL_CALC_FOUND_ROWS -> to liczbe powinien gdzies zapisac w cache juz przy wybieraniu rekordów. Później tylko zwrócic tą liczbę. Logika nie idzie w parze z rzeczywistością.... ale to już głębsza filozofia.

Jeszcze raz dziękuje!

1 użytkowników online, w tym zalogowanych: 0, gości: 1