一个简单的MySQL查询永远(超过20分钟!)

时间:2010-07-27 03:52:26

标签: sql mysql

也许你可以帮助我。我需要查询3个表以获取金融股的数据。

我们的想法是转到工具表,查找每种工具的指数,然后将该特定工具的所有价格与单独表格中的指标一起使用。

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`)
)

4 个答案:

答案 0 :(得分:5)

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

您还使用instrumentsstockdata列将instruments.name表加入stockdata.name表,这两列都是CHAR类型。使用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列的原因,请将它们设置为相同的大小并将其编入索引。

答案 1 :(得分: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

答案 2 :(得分:1)

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

答案 3 :(得分:0)

您正在查询stockdata中的非索引字段名称。创建索引或改为加入id。 (我会做后者,在工具中将名称改为id)