优化特定查询mysql

时间:2014-02-17 12:47:10

标签: mysql performance optimization

所以我一直在寻找解决方案和阅读书籍,而且还没能弄明白,问题很简单,我有2张桌子。在一张桌子上,我有两个字段:

table_1:“染色体”和“位置”都是整数。

table_2:“染色体”“开始”和“结束”,都是整数。

我想要一个查询,它返回table_1中table_2开头和结尾之间的所有行。查询如下所示:

SELECT 
    table_1 . *
FROM
    table_1,
    table_2
WHERE
    table_1.chromosome = table_2.chromosome
        AND table_1.position > table_2.start
        AND table_1.position < table_1.end;

所以这个查询工作正常,但我的表是数百万行(7092713)和(215909)尊重。我将染色体,pos和染色体编入索引,开始,结束。奇怪的是,如果我逐个执行查询(perl DBI,为table_2的每一行执行一个语句),运行速度要快得多。不知道我搞砸了哪里。 任何帮助将不胜感激。

Jorge Kageyama

2 个答案:

答案 0 :(得分:1)

为了清楚起见,我们首先使用标准JOIN语法重新构建查询。该查询是等效的,但更容易阅读。

SELECT table_1 . *
  FROM table_1 
  JOIN table_2 ON (     table_1.chromosome = table_2.chromosome
                    AND table_1.position > table_2.start
                    AND table_1.position < table_1.end)

其次,在搜索大表(或任何表格)时,它很聪明,以避免*条款中的SELECT。使用*拒绝向优化器提供有关您在结果集中需要或不需要执行的操作的有用数据。那么让我们说吧

SELECT table_1.chromosome, table_1.position

用于SELECT。

因此,很明显,您的结果集和您的联接需要从较大的表中获得染色体和位置,而不需要其他内容。尝试在该表上创建复合BTREE索引,如下所示。

CREATE INDEX ON table_1(chromosome,position) USING BTREE

同样,尝试在table_2上创建索引,如下所示。

CREATE INDEX ON table_2(chromosome,start, end) USING BTREE

这些被称为覆盖索引。它们包含足够的列,可以从索引中满足查询,而不必退回到原始表。

BTREE索引(顺便提一下)是固有的排序。 table_1中的适当记录可以通过以(染色体,开始)和(染色体,结束)开头的索引上的范围扫描找到。

第三,您可能会在结果集中从table_1获得大量的组合爆炸。对于与ON()子句匹配的两个表中的每个行组合,您将获得一行。很难知道在不了解您的数据的情况下是否会出现这种情况。

您可以尝试使用

减少组合爆炸
SELECT DISTINCT table_1.chromosome, table_1.position

试一试。如果您还没有到达任何地方,可能有另外一个问题,包括完整的表格定义和EXPLAIN的结果会有所帮助。

答案 1 :(得分:0)

有趣的问题。如果不了解“位置”中包含的数量,我仍然会以这种方式接近它:

通常从table_1(具有7.0mm实体)选择位置,以便生成的表是较少量数据的bin。例如,假设“位置”数量是2-9的一组离散整数。从table_1中选择position等于2,然后从table_2中选择“start”小于2且“end”大于2.迭代此查询选择8次更新带有结果的新table_3。

我在这里假设table_2在染色体上是唯一的,而table_1不是。因此,您最终得到的染色体可能在同一范围内有多个位置(染色体有一个范围,但可以出现在该范围内的任何位置)。那么,您也无法判断结果连接表的大小,但它可能非常大,因为table_1中的每个7mm实体都可以在table_2的所有范围内。

迭代可以让你“成长”你的结果,同时在实验中观察每个点的质量,然后再进行整个循环。

以下是我想到的查询(未经测试)的想法:

SELECT table_1.chromosome, table_1.position, table_2.start, table_2.end
FROM 
(SELECT table_1.chromosome, table_1.position
  from table_1 where table_1.position = 2)
JOIN
(SELECT table_2.chromosome, table_2.start, table_2.end
  from table_2 where table_2.start < 2 AND table_2.end > 2)
ON
table_1.chromosome = table_2.chromosome
祝你好运,我希望你找到答案!