繁体   English   中英

如何使用此基本内部联接避免全表扫描?

[英]How do I avoid a full table scan with this basic inner join?

我有一个表具有存储一些blob数据的表的外键。 当我在主表上使用条件对表进行内连接时,连接类型从'index'变为'ALL'。 我想避免这种情况,因为我的blob表大约是几十千兆字节。 我怎么能避免呢?

这是基本的内部联接:

EXPLAIN SELECT m.id, b.id, b.data 
        FROM metadata m, blobstore b 
        WHERE m.fkBlob = b.id;

1, 'SIMPLE', 'm', 'index', 'fk_blob', 'fk_blob', '4', '', 1, 'Using index'
1, 'SIMPLE', 'b', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'blob_index.m.fkBlob', 1, ''

在这里我在主表上添加一个条件:

EXPLAIN SELECT m.id, b.id, b.data 
        FROM metadata m, blobstore b 
        WHERE m.fkBlob = b.id AND m.start < '2009-01-01';
1, 'SIMPLE', 'b', 'ALL', 'PRIMARY', '', '', '', 1, ''
1, 'SIMPLE', 'm', 'ref', 'fk_blob,index_start', 'fk_blob', '4', 'blob_index.b.id', 1, 'Using where'

请注意,列出表的顺序已更改。 它现在在blob表上进行全表扫描,因为我已经添加了关于主表的条件。

这是架构:

 DROP TABLE IF EXISTS `blob_index`.`metadata`;
    CREATE TABLE  `blob_index`.`metadata` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `fkBlob` int(10) unsigned NOT NULL,
      `start` datetime NOT NULL,
      PRIMARY KEY (`id`),
      KEY `fk_blob` (`fkBlob`),
      KEY `index_start` (`start`),
      CONSTRAINT `fk_blob` FOREIGN KEY (`fkBlob`) REFERENCES `blobstore` (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;


    DROP TABLE IF EXISTS `blob_index`.`blobstore`;
    CREATE TABLE  `blob_index`.`blobstore` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `data` mediumblob NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

我猜你是在空表上尝试这个(因为MySQL认为它需要通过一行来进行全表扫描),这可能会影响调度程序的结果。 当您在实际桌面上执行此操作时, EXPLAIN结果可能会有所不同(实际上我的测试确实有所不同)。

优化器认为您的查询将从交换表顺序中受益(这很可能意味着统计信息不是最新的)。

您可以尝试在metadata (start, fkBlob)上添加索引metadata (start, fkBlob)

CREATE INDEX ix_metadata_start_blob ON metadata (start, fkBlob)

并在两个表上运行ANALYZE TABLE

这样, start时的索引将用于过滤将成为领先的metadata

您还可以明确强制连接的顺序:

SELECT  *
FROM    metadata m
STRAIGHT_JOIN
        blobstore b
ON      b.id = m.fkBlob
WHERE   m.start <= '2009-01-01'

,虽然通常不推荐。

如果我读了你发布的内容,它会从indexrefeq_refall

CREATE INDEX idx_metadata USING BTREE ON `metadata` (fkBlob,start);

应该马上回来。

if the index doesnot take it right use HINTS

select /* INDEX <index_name> */
blah blah blah
from ........

在第一个示例中,MySQL使用元数据fk_blob索引,因为它是覆盖索引 - 您在查询中使用的每个列都存在于索引中。 (这就是“使用索引”的含义。)该查询仍然执行完整扫描,但它通过二级索引而不是主索引扫描每一行。 一旦你使用了start,你就失去了覆盖索引,MySQL计算出使用blobstore作为驱动索引会更快。 (InnoDB的主要索引与行存储集成。)

如果您希望MySQL继续使用元数据索引作为驱动索引,请确保其上有一个对查询有用的索引。 (start,fkBlob)上的索引最适合第二个查询,但这对其他查询可能没有用。 下一个最好的索引是用(fkBlob,start)替换(fkBlob)。 您必须平衡具有太多索引(维护成本高昂)与高效查询计划。 测试,测试,测试 - 永远不要盲目相信你的开发数据库的解释。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM