2012-07-05 21 views
5

Mój mysql DB stał się głodny procesora, próbując wykonać szczególnie powolne zapytanie. Kiedy robię wyjaśnienie, mysql mówi "Używanie gdzie; Używanie tymczasowego; Używanie filesort". Pomóż rozszyfrować i rozwiązać tę zagadkę.Potrzebujesz pomocy w dostrajaniu zapytania sql

Struktura Tabela:

CREATE TABLE `topsources` (
    `USER_ID` varchar(255) NOT NULL, 
    `UPDATED_TIME` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    `URL_ID` int(11) NOT NULL, 
    `SOURCE_SLUG` varchar(100) NOT NULL, 
    `FEED_PAGE_URL` varchar(255) NOT NULL, 
    `CATEGORY_SLUG` varchar(100) NOT NULL, 
    `REFERRER` varchar(2048) DEFAULT NULL, 
    PRIMARY KEY (`USER_ID`,`URL_ID`), 
    KEY `USER_ID` (`USER_ID`), 
    KEY `FEED_PAGE_URL` (`FEED_PAGE_URL`), 
    KEY `SOURCE_SLUG` (`SOURCE_SLUG`), 
    KEY `CATEGORY_SLUG` (`CATEGORY_SLUG`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8; 

Tabela ma 370K rzędy ... czasami wyższa. Poniższe zapytanie zajmuje 10 lub więcej sekund.

SELECT topsources.SOURCE_SLUG, COUNT(topsources.SOURCE_SLUG) AS VIEW_COUNT 
FROM topsources 
WHERE CATEGORY_SLUG = '/newssource' 
GROUP BY topsources.SOURCE_SLUG 
HAVING MAX(CASE WHEN topsources.USER_ID = 'xxxx' THEN 1 ELSE 0 END) = 0 
ORDER BY VIEW_COUNT DESC; 

oto inne wyjaśnienie:

+----+-------------+------------+------+---------------+---------------+---------+-------+--------+----------+----------------------------------------------+ 
| id | select_type | table  | type | possible_keys | key   | key_len | ref | rows | filtered | Extra          | 
+----+-------------+------------+------+---------------+---------------+---------+-------+--------+----------+----------------------------------------------+ 
| 1 | SIMPLE  | topsources | ref | CATEGORY_SLUG | CATEGORY_SLUG | 302  | const | 160790 | 100.00 | Using where; Using temporary; Using filesort | 
+----+-------------+------------+------+---------------+---- 

----------- + --------- + ------- + - ------- + ---------- + ------------------------------- --------------- +

Czy istnieje sposób na ulepszenie tego zapytania? Czy są jakieś ustawienia mysql, które mogą pomóc w zmniejszeniu obciążenia procesora? Mogę przydzielić więcej pamięci, która jest dostępna na moim serwerze.

+1

HAVING MAX (przypadek, gdy topsources.USER_ID = 'xxxx' TO 1 ELSE 0 END) = 0 ta część jest najbardziej problematyczna Myślę, że pozwolę sobie pomyśleć, jak to zrobić lepiej – Jester

+0

pomógłby opublikować dokładną informację z wyjaśnień. –

+0

Czy aktualizacje mają miejsce podczas uruchamiasz zapytanie? –

Odpowiedz

0

To powinno wystarczyć, jeśli czytam ten mój sql zmiana correcty

SELECT topsources.SOURCE_SLUG, COUNT(topsources.SOURCE_SLUG) AS VIEW_COUNT 
FROM topsources 
WHERE CATEGORY_SLUG = '/newssource' and 
    topsources.SOURCE_SLUG not in (
     select distinct SOURCE_SLUG 
     from topsources 
     where USER_ID = 'xxxx' 
     ) 
GROUP BY topsources.SOURCE_SLUG 
ORDER BY VIEW_COUNT DESC; 
+0

Ta kwerenda zwraca inny zestaw wyników. Nie to samo co pierwotne zapytanie. – Zero

+0

Zaktualizowano zapytanie spróbuj, pls – Jester

1

Najbardziej prawdopodobną rzeczą, aby pomóc zapytania jest indeksem na CATEGORY_SLUG, zwłaszcza jeśli trwa od wielu wartości. (To znaczy, jeśli zapytanie jest wysoce selektywne.) Zapytanie musi przeczytać całą tabelę, aby uzyskać wyniki - chociaż 10 sekund wydaje się być długim czasem.

Nie sądzę, aby klauzula HAVING wpłynęła na przetwarzanie zapytania.

Czy zapytanie trwa tak długo, jeśli uruchamiasz go dwa razy z rzędu?

+0

Istnieje już indeks na CATEGORY_SLUG. Przeczytaj powyższą tabelę. Query prawie zawsze trwa dłużej. – Zero

+0

Hmmm, ile jest tam liczbowych ślimaków? Czasami indeksy wyrządzają więcej szkód niż pożytku, zwłaszcza gdy istnieje tylko garść wartości. –

+0

Mniej niż 100 kategorii ślimaków. – Zero

0

Jeśli istnieje wiele wierszy spełniających kryteria CATEGORY_SLUG, może być trudno zrobić to szybko, ale czy jest to szybsze?

SELECT ts.SOURCE_SLUG, COUNT(ts.SOURCE_SLUG) AS VIEW_COUNT 
FROM topsources ts 
WHERE ts.CATEGORY_SLUG = '/newssource' 
    AND NOT EXISTS(SELECT 1 FROM topsources ts2 
       WHERE ts2.CATEGORY_SLUG = '/newssource' 
        AND ts.SOURCE_SLUG = TS2.SOURCE_SLUG 
        AND ts2.USER_ID = 'xxxx') 
GROUP BY ts.SOURCE_SLUG 
ORDER BY VIEW_COUNT DESC; 
+0

Zapytanie zwraca Nieznaną kolumnę "TS2.SOURCE_SLUG" w "gdzie klauzula" – Zero

+0

usuwa jego wiersz 'AND ts.SOURCE_SLUG = TS2.SOURCE_SLUG' – jared

+0

Jeśli usunę ten wiersz, to zapytanie zwraca pusty zestaw wyników – Zero

0

Zawsze trudno zoptymalizować coś, gdy nie można po prostu wyrzucić zapytań na danych siebie, ale to byłaby moja pierwsza próba gdybym robił to sam:

SELECT t.SOURCE_SLUG, COUNT(t.SOURCE_SLUG) AS VIEW_COUNT 
FROM topsources t 
LEFT JOIN (
    SELECT SOURCE_SLUG 
    FROM topsources t 
    WHERE CATEGORY_SLUG = '/newssource' 
    AND USER_ID = 'xxx' 
    GROUP BY .SOURCE_SLUG 
) x USING (SOURCE_SLUG) 
WHERE t.CATEGORY_SLUG = '/newssource' 
AND x.SOURCE_SLUG IS NULL 
GROUP BY t.SOURCE_SLUG 
ORDER BY VIEW_COUNT DESC; 
Powiązane problemy