2010-07-27 8 views
6

Forse puoi aiutarmi. Ho bisogno di interrogare 3 tabelle al fine di ottenere dati per un titolo finanziario.Una query MySQL semplice che dura per sempre (più di 20 minuti!)

L'idea è di andare alla tabella degli strumenti, trovare l'indice per ogni strumento e quindi portare tutti i prezzi per quello strumento particolare insieme agli indicatori che si trovano su una tabella separata.

Le tabelle stockdata e indicators sono entrambe quasi 50.000 record. instruments appena 30.

Questa è la query che non funziona:

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) 

Ecco il risultato

SPIEGARE
+----+-------------+-------------+-------+-----------------------------+---------------------+---------+------+-------------+ 
| 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 | 
+----+-------------+-------------+-------+-----------------------------+---------------------+---------+------+-------------+ 

Apprezzo molto tutto l'aiuto che può fornire!

Questo è lo schema per le parti delle tabelle che sono coinvolti nella mia interrogazione:

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

perché ci sono parentesi intorno alla condizione di join? – Fosco

+0

Quante righe sono in ciascuna delle tabelle interessate? – sgriffinusa

+0

Salve, tabella di dati e indicatori sono entrambi quasi 50.000 record. Strumenti appena 30. – JordanBelf

risposta

5

Stai partecipando alla tabella indicators nella tabella instruments e la colonna indicators.instrument_id non è indicizzata.

Siete anche unendo la tabella instruments alla tabella stockdata utilizzando i instruments.name e stockdata.name colonne, che sono entrambi di tipo CHAR. Partecipare utilizzando CHAR o VARCHAR di solito è molto più lento che unirsi con INT colonne:

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

A peggiorare le cose, i vostri CHAR colonne sono diverse dimensioni (rispettivamente char(20) e char(10)), e non sono indicizzati. Questo rende davvero le cose difficili per MySQL! Vedere How MySQL Uses Indexes per ulteriori informazioni.

Idealmente, è necessario modificare la struttura della tabella in modo che l'unione possa essere eseguita utilizzando i campi indicizzati INT. Qualcosa di simile a questo:

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; 

quindi utilizza i campi indicizzati in join:

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) 

By utilizzando indicizzato INT colonne, i join sarà molto più veloce.L'uso dei vincoli InnoDB contribuirà a garantire l'integrità dei dati.

Se esiste un motivo per cui è necessario unirsi alla colonna name, creare entrambe le stesse dimensioni e indicizzarle.

+0

grazie Mike, farò un tentativo. faccio sapere – 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 

un'altra opzione:

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

Ciao, la seconda opzione ha funzionato come segue seleziona gli indicatori .date', instruments.name, indicators.sma_14, indicators.sma_5, (seleziona chiudi da stockdata dove name = instruments.name limit 1) da vicino dagli indicatori indicatori unire gli strumenti strumenti su indicators.instrument_id = instruments.id Ma ancora preso: 44619 righe recuperate (29,42 sec) – JordanBelf

1

io sono sospettoso di unirsi sul stockdata. nome campo. Avete gli indici giusti definiti nel campo del nome nella tabella stockdata e degli strumenti? È possibile che unirsi al nome possa restituire risultati non validi e potresti unirti a un altro campo .id?

+0

il fatto è che la tabella stockdata non ha una colonna instrument_id, ecco perché ho bisogno di inserire l'isturment tabella per ottenere l'ID dello strumento per quel nome specificato da lì e quindi unirsi alla tabella degli indicatori. – JordanBelf

0

Si sta eseguendo una query sul nome del campo non indeterminato in stockdata. O creare un indice o piuttosto unirsi su id. (Io farei il secondo, cambiando il nome in id negli strumenti)

Problemi correlati