简单连接导致使用大量行

时间:2012-08-03 04:36:45

标签: mysql

我正在尝试做我认为是两个表之间的简单连接。

CREATE TABLE t_slv
(
    symbol_id       int                     NOT NULL,
    load_id         SMALLINT,
    val                     DECIMAL(10,4)   NOT NULL,
    -- PRIMARY KEY ( symbol_id )
    unique index ( symbol_id )
);

CREATE TABLE nasd (
    symbol_id       integer                 NOT NULL, 
    load_id         SMALLINT                NOT NULL,
    openp           DECIMAL(10,4)   NOT NULL,   -- range 0.0001 - 999,999.9999
    high            DECIMAL(10,4)   NOT NULL,
    low                     DECIMAL(10,4)   NOT NULL,
    last            DECIMAL(10,4)   NOT NULL,
    volume          integer                 NOT NULL
    -- PRIMARY KEY ( symbol_id, load_id )
    -- INDEX ( load_id )
);

CREATE UNIQUE INDEX nasd_1_ix1 on nasd( symbol_id, load_id );
CREATE UNIQUE INDEX nasd_1_ix2 on nasd( load_id, symbol_id );

所以,当我这样做时:

mysql> explain                 select  nasd.load_id
  ->                         -- nasd.low
->                 from    t_slv,
->                         nasd
->                 where   t_slv.symbol_id = nasd.symbol_id
->                         and nasd.load_id >= 4700
->                         and nasd.load_id <= 4917 ;
      +----+-------------+-------+-------+-----------------------+------------+---------+--------    --------------+---------+--------------------------+
| id | select_type | table | type  | possible_keys         | key        | key_len |   ref                  | rows    | Extra                    |
+----+-------------+-------+-------+-----------------------+------------+---------+----------------------+---------+--------------------------+
|  1 | SIMPLE      | t_slv | index | symbol_id             | symbol_id  | 4       | NULL                 |       1 | Using index              |
|  1 | SIMPLE      | nasd  | ref   | nasd_1_ix1,nasd_1_ix2 | nasd_1_ix1 | 4       | prog.t_slv.symbol_id | 2069669 | Using where; Using index |
+----+-------------+-------+-------+-----------------------+------------+---------+----------------------+---------+--------------------------+

2行(0.00秒)

对不起,这很难读。

如果t_slv中只有一行,只需将其连接到nasd就可以访问超过200万行。如果我把t_slv拿出来只是从表nasd直接选择,只访问217行 - 这是有道理的,因为这是4700和4917之间有多少行。

因此,只使用一行连接到一个表会导致访问的行爆炸,即使它使用与t_slv不在连接中时相同的索引。

这对任何人都有意义吗?

现实生活中的情况实际上更糟糕 - 如果t_slv中有1000行,则select需要20分钟,这实际上使其无法运行。

即使我强制索引,我也相信我会得到相同的结果。意思是,即使它正在使用索引,它也会访问数百万行。

TIA。

1 个答案:

答案 0 :(得分:1)

Mysql认为t_slv中只有一行,所以它认为抓住那一行,从中抓取symbol_id然后使用nasd_1_ix1索引来查找所有匹配的行。它的2M行猜测关于nasd中匹配的行数是symbol_id,load_id索引不唯一的事实,因此它无法知道有多少行行在您给出的范围之间。它实际上并不会根据您的真实数据读取那么多行。

t_slv只有一行吗?如果没有,您可能希望重建该表,以便mysql了解其大小。

即使t_slv有很多行,该计划仍然可以正常运行,因为symbol_idt_slv中是唯一的,并且symbol_id上有一个以nasd开头的索引1}},所以mysql确定它永远不必两次查看一行。