2009-08-07 12 views
5

Mam dużą tabelę (TokenFrequency), która ma miliony wierszy. Tabela TokenFrequency który jest skonstruowany tak:SQL Alternatywa dla wykonywania INNER JOIN na pojedynczej tabeli

stołowy - TokenFrequency

  • id - int, klucz podstawowy
  • źródła - int, klucz obcy
  • żeton - char
  • rachubę - int

Moim celem jest wybranie wszystkich wierszy, w których dwa źródła mają ten sam znacznik. Na przykład, jeśli mój stół wyglądał następująco:

id --- źródło --- --- żeton liczyć
1 ------ 1 --------- pies - ----- 1
2 ------ 2 --------- kot -------- 2
3 ------ 3 ----- ---- kot -------- 2
4 ------ 4 --------- świnia -------- 5
5 ---- - 5 --------- zoo ------- 1
6 ------ 5 --------- kot -------- 1
7 ------ 5 --------- świnia -------- 1

Chciałbym zapytanie SQL dać mi źródło 1, źródło 2 i sumę zliczeń. Np

źródła1 Source2 --- --- --- znacznik liczyć
---- 2 ----------- 3 --------- kot -------- 4
---- 2 ----------- 5 --------- kot -------- 3
---- 3 ----------- 5 --------- kot -------- 3
---- 4 ------- ---- 5 --------- -------- świnia 6

mam kwerendę, która wygląda tak:

SELECT F.source AS source1, S.source AS source2, F.token, 
     (F.count + S.count) AS sum 
FROM  TokenFrequency F 
INNER JOIN TokenFrequency S ON F.token = S.token 
WHERE F.source <> S.source 

Ta kwerenda działa poprawnie, ale problemy, które mam z nim są następujące:

  1. Mam tabeli TokenFrequency że ma miliony wierszy i dlatego muszą szybszą alternatywę, aby uzyskać ten wynik.
  2. Obecne zapytanie, które mam, daje duplikaty. Na przykład jego składzie:
    Source1 = 2, Source2 = 3, znacznik = kot, count = 4
    Source1 = 3, Source2 = 2, znacznik = kot, count = 4
    co nie jest zbyt wielkim problemem ale jeśli istnieje sposób na wyelimino- wanie tych i z kolei uzyskanie zwiększenia prędkości, byłoby bardzo użyteczne.

Głównym problemem, który mam, jest prędkość zapytania z bieżącym zapytaniem, to zajmuje wiele godzin. INNER JOIN na stole sam w sobie jest tym, co uważam za problem. Jestem pewien, że musi istnieć sposób na wyeliminowanie sprzężenia wewnętrznego i uzyskanie podobnych wyników przy użyciu tylko jednej instancji tabeli TokenFrequency. Drugi problem, o którym wspomniałem, może również promować wzrost prędkości w zapytaniu.

Potrzebuję sposobu na restrukturyzację tego zapytania, aby zapewnić te same wyniki w szybszy i bardziej wydajny sposób.

Dzięki.

+1

Czy możesz umieścić EXPLAIN zapytania (http://dev.mysql.com/doc/refman/5.0/en/explain.html). Pomoże to ludziom zobaczyć, jak mogą pomóc Ci zoptymalizować. –

+0

musisz podać informacje o indeksie, które kolumny itp. –

+0

Oto moje WYJAŚNIENIE z kwerendy, które początkowo wysłany. id: 1, select_type: SIMPLE, table: F & S, type: ALL, Possible_keys: NULL, Klucz: NULL, Key_len: NULL, ref: NULL, rows: 8, Extra: Using where; Korzystanie z bufora łączenia Istnieją dwa wiersze zwrócone, jedyną różnicą są dwie nazwy tabel F i S. – cruzja

Odpowiedz

2

będę potrzebował trochę więcej informacji, aby zdiagnozować problem prędkości, ale do usunięcia dups, dodać do tego gdzie:

AND F.source<S.source 
+0

Ah tak proste. To zadziałało idealnie dla wyeliminowania duplikatów. Dziękujemy – cruzja

2

Spróbuj tego:

SELECT token, GROUP_CONCAT(source), SUM(count) 
FROM TokenFrequency 
GROUP BY token; 

ten powinien działać o wiele szybciej, a także wyeliminować duplikaty. Ale źródła zostaną zwrócone na liście rozdzielanej przecinkami, więc będziesz musiał eksplodować w swojej aplikacji.

Można także spróbować tworzenia indeksu związek nad kolumnami token, source, count (w tej kolejności) i analizować z EXPLAIN aby zobaczyć, czy MySQL jest wystarczająco inteligentny, aby używać go jako covering index dla tego zapytania.


zmiana: wydaje mi się, że źle zrozumiał pytanie. Nie chcesz sumy zliczeń na token, potrzebujesz sumy zliczeń dla każdej pary źródeł dla danego tokena.

Uważam, że połączenie wewnętrzne jest najlepszym rozwiązaniem. Ważną wytyczną dla SQL jest to, że jeśli chcesz obliczyć wyrażenie w odniesieniu do dwóch różnych wierszy, musisz zrobić sprzężenie.

Jednak jedną z technik optymalizacji, o której wspomniałem powyżej, jest zastosowanie obejmującego indeks , aby wszystkie potrzebne kolumny zostały uwzględnione w strukturze danych indeksu. Korzyścią jest to, że wszystkie twoje wyszukiwania to O (log n), a zapytanie nie musi wykonywać drugiego I/O, aby odczytać fizyczny wiersz, aby uzyskać inne kolumny.

W tym przypadku powinieneś utworzyć indeks zakrywający dla kolumn token, source, count, jak wspomniałem powyżej. Spróbuj również przydzielić wystarczającą ilość pamięci podręcznej, aby indeks mógł zostać zapisany w pamięci podręcznej.

+1

+1 za właściwe podejście; ale taki indeks byłby prawie tak duży jak cały rekord, czy myślisz, że byłoby to szybsze niż indeksowanie tokena? – Javier

+0

W zależności od liczby wierszy i innych czynników specyficznych dla systemu. Jedynym sposobem, aby się upewnić, jest wypróbowanie go z * twoją * bazą danych i zmierzenie wydajności. –

+0

To jest dobre podejście, ale jedynym problemem, który stwarza, jeśli masz token, który jest w więcej niż jednym źródle, wtedy wszystkie te sprawy są dodawane razem.Na przykład w moim przykładowym przypadku token "cat" ma źródło 2,3 i 5, więc daje mi liczbę 5 zamiast dać mi 2 i 3 z liczbą 4, 3 i 5 z liczbą 3 i 2 i 5 z liczba 3. W moim prawdziwym, dużym zestawie danych znajdują się żetony, które pojawiają się w prawie każdym dokumencie, który dałby mi GROUP_CONCAT tysięcy źródeł i ich szacunek. – cruzja

1

Jeśli token nie jest indeksowany, to z pewnością powinien nim być.