2010-07-27 11 views
6

Może możesz mi pomóc. Muszę zapytać o 3 tabele, aby uzyskać dane dla zasobów finansowych.Proste zapytanie MySQL trwające wiecznie (ponad 20 minut!)

Chodzi o to, aby przejść do tabeli instrumentów, znaleźć indeks dla każdego instrumentu, a następnie wprowadzić wszystkie ceny dla danego instrumentu wraz ze wskaźnikami znajdującymi się w osobnej tabeli.

Tabele stockdata i indicators to prawie 50 000 rekordów. instruments tylko 30.

To jest zapytanie, które nie działa:

SELECT 
    indicators.ddate, 
    instruments.name, 
    indicators.sma_14, 
    indicators.sma_5, 
    stockdata.close 
FROM 
indicators 
INNER JOIN instruments ON (indicators.instrument_id=instruments.id) 
INNER JOIN stockdata ON (instruments.name=stockdata.name) 

Oto EXPLAIN wynik

+----+-------------+-------------+-------+-----------------------------+---------------------+---------+------+-------------+ 
| id | select_type | table  | type | possible_keys    | key     | key_len | rows | Extra  | 
+----+-------------+-------------+-------+-----------------------------+---------------------+---------+------+-------------+ 
| 1 | SIMPLE  | instruments | index | PRIMARY,instruments_index01 | instruments_index01 |  61 | 25 | Using index | 
| 1 | SIMPLE  | indicators | ref | indicators_index01   | indicators_index01 |  5 | 973 | Using where | 
| 1 | SIMPLE  | stockdata | ref | stockdata_index01   | stockdata_index01 |  31 | 1499 | Using where | 
+----+-------------+-------------+-------+-----------------------------+---------------------+---------+------+-------------+ 

naprawdę wdzięczni za każdą pomoc można zapewnić!

Jest to schemat dla części tabel, które są zaangażowane w moje pytanie:

TABLE `indicators` (
    `id`    int AUTO_INCREMENT NOT NULL,<br> 
    `instrument_id` int, 
    `date`   date, 
    `sma_5`   float(10,3), 
    `sma_14`   float(10,3), 
    `ema_14`   float(10,3), 
    /* Keys */ 
    PRIMARY KEY (`id`) 
) 

TABLE `instruments` (
    `id`   int AUTO_INCREMENT NOT NULL, 
    `name`  char(20), 
    `country` char(50), 
    `newsquery` char(100), 
    /* Keys */ 
    PRIMARY KEY (`id`) 
) 

TABLE `stockdata` (
    `id`  int AUTO_INCREMENT NOT NULL, 
    `name`  char(10), 
    `date`  date, 
    `open`  float, 
    `high`  float, 
    `low`  float, 
    `close`  float, 
    `volume` int, 
    `adjclose` float, 
    /* Keys */ 
    PRIMARY KEY (`id`) 
) 
+0

Dlaczego są nawiasy wokół warunku łączenia? – Fosco

+0

Ile wierszy znajduje się w każdej z tabel? – sgriffinusa

+0

Witaj, tabele akcji i wskaźników to prawie 50 000 rekordów. Instrumenty tylko 30. – JordanBelf

Odpowiedz

5

Dołączasz do tabeli indicators do tabeli instruments, a kolumna indicators.instrument_id nie jest indeksowana.

Jesteś również łączenie tabeli instruments do stołu stockdata używając instruments.name i stockdata.name kolumn, z których oba są typu CHAR. Łączenie za pomocą CHAR lub VARCHAR jest zwykle znacznie wolniej niż łączenie za pomocą INT kolumny:

Using CHAR keys for joins, how much is the overhead?

Co gorsza, twoje CHAR kolumny są różne rozmiary (char(20) i char(10) odpowiednio), a oni nie są indeksowane. To naprawdę utrudnia MySQL! Aby uzyskać więcej informacji, patrz How MySQL Uses Indexes.

W idealnym przypadku należy zmienić strukturę tabeli, aby połączenie mogło zostać wykonane przy użyciu indeksowanych pól INT. Coś takiego:

CREATE TABLE `instruments` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `name` char(20) DEFAULT NULL, 
    `country` char(50) DEFAULT NULL, 
    `newsquery` char(100) DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB; 

CREATE TABLE `indicators` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `instrument_id` int(11) DEFAULT NULL, 
    `date` date DEFAULT NULL, 
    `sma_5` float(10,3) DEFAULT NULL, 
    `sma_14` float(10,3) DEFAULT NULL, 
    `ema_14` float(10,3) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `fk_instrument_indicators` (`instrument_id`), 
    CONSTRAINT `fk_instrument_indicators` FOREIGN KEY (`instrument_id`) REFERENCES `instruments` (`id`) ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB; 

CREATE TABLE `stockdata` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `instrument_id` int(11) NOT NULL, 
    `name` char(20) DEFAULT NULL, 
    `date` date DEFAULT NULL, 
    `open` float DEFAULT NULL, 
    `high` float DEFAULT NULL, 
    `low` float DEFAULT NULL, 
    `close` float DEFAULT NULL, 
    `volume` int(11) DEFAULT NULL, 
    `adjclose` float DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `fk_instrument_stockdata` (`instrument_id`), 
    CONSTRAINT `fk_instrument_stockdata` FOREIGN KEY (`instrument_id`) REFERENCES `instruments` (`id`) ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB; 

Następnie użyj indeksowanych pól w przyłączyć:

SELECT 
    indicators.date, 
    instruments.name, 
    indicators.sma_14, 
    indicators.sma_5, 
    stockdata.close 
FROM 
indicators 
INNER JOIN instruments ON (indicators.instrument_id=instruments.id) 
INNER JOIN stockdata ON (instruments.id=stockdata.instrument_id) 

za pomocą indeksowane INT kolumny, twój dołącza będzie znacznie szybciej.Korzystanie z ograniczeń InnoDB pomoże zapewnić integralność danych.

Jeśli istnieje powód, dla którego należy dołączyć do kolumny name, należy dokonać tego samego rozmiaru i zindeksować je.

+0

dzięki Mike, spróbuję. dam ci znać – JordanBelf

1
SELECT 
    ind.ddate, 
    ins.name, 
    ind.sma_14, 
    ind.sma_5, 
    sto.close 
FROM indicators ind 
JOIN instruments ins ON ind.instrument_id = ins.instrument_id 
JOIN stockdata sto ON ins.name = sto.name 

inna opcja:

select ind.ddate, ins.name, ind.sma_14, ind.sma_5, 
    (select close from stockdata where name = ins.name limit 1) as close 
from indicators ind 
join instruments ins on ind.instrument_id = ins.instrument_id 
+0

Witaj, druga opcja działa w następujący sposób: wybierz wskaźniki: "datate", instruments.name, indicators.sma_14, indicators.sma_5, (wybierz zamknij z stockdata gdzie nazwa = instruments.name limit 1) jako zamknij od wskaźników wskaźników Dołącz instrumenty instrumentów na wskaźniki.instrument_id = instruments.id Ale nadal trwało: 44619 wierszy pobranych (29,42 s) – JordanBelf

1

Jestem podejrzliwy łączenia na stockdata. pole nazwy. Czy masz odpowiednie indeksy zdefiniowane w polu nazwy w tabeli akcji i instrumentów? Czy to możliwe, aby dołączenie do nazwy mogło zwrócić nieprawidłowe wyniki i móc dołączyć do innego pola .id?

+0

Rzecz w tym, że tabela akcji nie ma kolumny instrument_id, dlatego muszę wprowadzić w insturment tabela, aby pobrać identyfikator dokumentu dla danej nazwy, a następnie dołączyć do tabeli wskaźników. – JordanBelf

0

Pytasz na temat nazwy pola nieindeksowanego w stockdata. Utwórz indeks lub dołącz przy id. (Robiłbym to drugie, zmieniając nazwę na id w instrumentach)

Powiązane problemy