2010-07-27 62 views
6

也许你可以帮助我。我需要查询3个表格才能获取财务股票的数据。一个简单的MySQL查询需要永久(超过20分钟!)

这个想法是去仪器表,找到每个仪器的索引,然后将该特定仪器的所有价格与独立表上的指标结合在一起。

stockdataindicators都差不多有50.000条记录。 instruments只是30

这是不正常的查询:

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) 

这里是EXPLAIN结果

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

我真的很感激任何帮助,您可以提供!

这对于参与我的问题表的部分架构:

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

为什么在连接条件周围有括号? – Fosco 2010-07-27 03:53:53

+0

涉及的每个表中有多少行? – sgriffinusa 2010-07-27 03:55:54

+0

你好,表库存数据和指标都差不多有50.000条记录。仪器只有30. – JordanBelf 2010-07-27 03:57:11

回答

5

您正在将indicators表加入instruments表,并且indicators.instrument_id列未编入索引。

您正在使用instruments.namestockdata.name列,这两者都是CHAR类型也加入instruments表到stockdata表。使用CHARVARCHAR加入通常比使用INT列加入显著慢:

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

更糟糕的是,你的CHAR列是不同的尺寸(char(20)char(10)分别),而且他们不被索引。这真的让MySQL的事情变得困难!有关更多信息,请参阅How MySQL Uses Indexes

理想情况下,您应该更改您的表格结构,以便可以使用索引INT字段执行连接。事情是这样的:

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; 

然后使用索引字段在您的加入:

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) 

使用索引INT列,您的加入会快很多。使用InnoDB约束将有助于确保数据的完整性。

如果您有必要加入name列的原因,请同时创建相同的大小并为它们编制索引。

+0

感谢迈克,我会试试看。我回头告诉你 – JordanBelf 2010-07-27 11:54:26

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 

另一种选择:

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

您好,第二个选项的工作方式如下select indicators.'date',instruments.name,indicators.sma_14,indicators.sma_5, (从stockdata选择其中name = instruments.name的限制为1)从指标指标 接近 加入仪器文书上的指标.instrument_id = instruments.id 但仍需要:44619行提取(29,42秒) – JordanBelf 2010-07-27 04:14:21

1

我怀疑参加在stockdata的。名称字段。您是否在stockdata和instruments表的名称字段中定义了正确的索引?是否有可能加入名称可能会返回无效结果,并且您可以加入另一个.id字段?

+0

事情是stockdata表没有instrument_id列,这就是为什么我需要引入仪器表从那里获得给定名称的intrument id,然后加入指标表。 – JordanBelf 2010-07-27 04:15:44

0

您正在查询stockdata中的未指定字段名称。要么创建一个索引,要么加入id。 (我会做后者,将名称更改为工具中的ID)