Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: USING TEMPORARY
Forum PHP.pl > Forum > Bazy danych > MySQL
ktuvok
Czy ktoś może mi powiedzieć, jakie są zasady tworzenia przez MySQL tabel
tymczasowych przy wykonywaniu zapytań SELECT?

Spotykam się niejednokrotnie, że analiza zapytania (EXPLAIN SELECT ...)
ujawnia w kolumnie EXTRA wartość "USING TEMPORARY". Podejrzewam, że ma to
negatywny wpływ na wydajność.

Zapytanie mam takie:
  1. EXPLAIN SELECT
  2. Oddzialy.NazwaOddzialu,
  3. SUM(IF(DATE_FORMAT(Transakcje.DataWpisania,'%Y-%m-%d') = CURRENT_DATE,1,0))
  4. AS IloscTransakcjiWpisanych
  5. FROM Transakcje, Uzytkownicy, Oddzialy
  6. WHERE Transakcje.KtoWpisal = Uzytkownicy.IDUzyt AND Oddzialy.IDOddzialu = Uzytkownicy.IDOddzialu
  7. GROUP BY Oddzialy.IDOddzialu

a więc zupełnie proste... Ten IF jest nie do uniknięcia - zapytanie ma
zwracać sumę i ilość transakcji różnych typów, w powyższym przykładzie
pozostawiłem jedynie jedną kolumnę. Tak czy owak nawet powyższe zapytanie
generuje "USING TEMPORARY" dla tabeli Transakcje. Indeksy są na wszystkich
złączeniach, a mimo to MySQL nie korzysta z indeksu "KtoWpisal". Dlaczego?

MySQL 4.0.18

Pozdrawiam,
Krzysiek
DeyV
Przy grupowaniu - zawsze wykorzystywane jest temporary, jednak zazwyzaj nie odbija się to w zbyt drastyczny sposób na wydajności.

Natomiast co do index - jeśli możesz - udostępnij strukturę interesującego nas fragmentu bazy z przykładowymi danymi (najlepiej podając plik do pobania, a nie wklejając ją tu)
ktuvok
Oczywiście, ale niestety nie dysponuję serwerem dostępnym dla juzerów spoza firmy. Strukturę bazy w zakresie, który może być istotny, wklejam więc poniżej:

  1. CREATE TABLE `Transakcje` (
  2. `IDTransakcji` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  3. `Status` enum('N','E','B','Z','O','G','U','R') NOT NULL DEFAULT 'N',
  4. `Rodzaj` enum('S','KH','KBH','PH','KK') NOT NULL DEFAULT 'S',
  5. `Kwota` double(10,2) NOT NULL DEFAULT '0.00',
  6. `Waluta` enum('PLN','EUR','CHF') NOT NULL DEFAULT 'PLN',
  7. `KtoWpisal` int(11) UNSIGNED NOT NULL DEFAULT '0',
  8. `DataWpisania` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  9. PRIMARY KEY (`IDTransakcji`),
  10. KEY `IDTransakcji` (`IDTransakcji`),
  11. KEY `KtoWpisal` (`KtoWpisal`),
  12. KEY `Status` (`Status`)
  13. ) TYPE=MyISAM;
  14.  
  15. INSERT INTO `Transakcje` VALUES (1511,'E','S',2153.44,'PLN',1, '2004-10-06
  16. 16:25:16');
  17.  
  18. CREATE TABLE `Uzytkownicy` (
  19. `IDUzyt` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  20. `ImieINazwisko` varchar(60) NOT NULL DEFAULT '',
  21. `IDOddzialu` int(11) UNSIGNED NOT NULL DEFAULT '0',
  22. PRIMARY KEY (`IDUzyt`),
  23. KEY `IDOddzialu` (`IDOddzialu`)
  24. ) TYPE=MyISAM;
  25.  
  26. INSERT INTO `` VALUES (1, 'Janko Walski', 20);
  27.  
  28. CREATE TABLE `Oddzialy` (
  29. `IDOddzialu` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  30. `Nip` varchar(13) NOT NULL DEFAULT '',
  31. `Nazwa` varchar(60) NOT NULL DEFAULT '',
  32. PRIMARY KEY (`IDOddzialu`),
  33. KEY `IDOddzialu` (`IDOddzialu`),
  34. KEY `Nip` (`Nip`)
  35. ) TYPE=MyISAM;
  36.  
  37. INSERT INTO `Oddzialy` VALUES (1, '123-456-78-90, 'Oddział Pierwszy z Brzegu');


Będę wdzięczny za pomoc w rozwiązaniu problemu, "pałuję" się już z nim dłuższy czas i nie mam pomysłu co dalej.

Dziękuję i pozdrawiam,
Krzysiek
DeyV
Moja propozycja
  1. SELECT Oddzialy.Nazwa, SUM(
  2. IF (
  3. DATE_FORMAT( Transakcje.DataWpisania, '%Y-%m-%d' ) = CURRENT_DATE, 1, 0 )
  4. ) AS ilosc
  5. FROM Oddzialy LEFT JOIN Uzytkownicy ON ( Oddzialy.IDOddzialu = Uzytkownicy.IDOddzialu )
  6. LEFT JOIN Transakcje ON ( Uzytkownicy.IDUzyt = Transakcje.KtoWpisal )
  7. GROUP BY Oddzialy.IDOddzialu
ktuvok
Zastosowałem się do Twojej propozycji. Ciekawe...

Oczywiście kolejność skanowania tabel jest inna. Teraz pierwsza przeszukiwana jest tabela Oddzialy. Ale bez użycia indeksu IDOddzialu - dlaczego?

Tego indeksu nie ma nawet w kolumnie POSSIBLE_KEYS...

Liczba przeskanowanych rekordów jest dokładnie ta sama co poprzednio. Wygląda na to, że specjalnego przyrostu wydajności nie osiągnąłem. Ale czy ktoś potrafi wytłumaczyć, dlaczego pierwsza ze skanowanych tabel (niezależnie na którą wypadnie) zawsze przeszukiwana jest bez wykorzystania indeksu?

Pozdrawiam,
Krzysiek
DeyV
1. nie ma sensu tworzyć dodatkowego indeksu IDOddzialu skoro kolumna ta jest kluczem głownym (primary) Kolumna taka jest domyślnie indeksowana.

2. Nie wiem dlaczego nie wymienia żadnego indesku w possible_keys ale wydaje mi się, że najprostrzą i najprawdziwszą odpowiedzią jest taka, że nie potrzebuje żadnego indexu.
Bo sam powiedz - do trzego miałby go używać, jeśli po tej pierwszej tabeli nie ma nawet sortowania?

3. Liczba przeskanowanych rekordów.
Ta mogłaby się zmienić dopiero wtedy, gdybyśmy ograniczyli ilość rekodów dołączanych. Można by to zrobić przy pomocy np. dodania warunku związanego z datą (znajdującego sie teraz w select) do JOIN transakcje i być moze zmodyfikowanie wykorzystywanego przez date indexu,
Pisałeś jednak, że z pewnych względów nie możesz modyfikować tej struktury, więc nie tworzyłem takiego zapytania.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.