1

MySQL で実行しているクエリがあります。ご覧のとおり、クエリのすべての部分がインデックス付きフィールドにあります。それにもかかわらず、クエリには永遠に時間がかかります (数十分、私が待つよりも長く)。Connect テーブルは、2 つの整数と 2 つのインデックス (1 つのフィールド 1、フィールド 2、もう 1 つのフィールド 2、フィールド 1) で構成されます。ソースとターゲットは、単一のインデックス付き int フィールドを持つテーブルです。すべてのインデックスを考えると、このクエリは数秒で完了すると予想していました。1: なぜそんなに時間がかかるのか、2: 高速化する方法について何か提案はありますか?

ありがとう!

mysql> explain 
SELECT DISTINCT geneConnect.geneSymbolID FROM SNPEffectGeneConnector AS geneConnect 
  JOIN IndelSNPEffectConnector AS snpEConnect ON geneConnect.snpEffectID = snpEConnect.snpEffectID 
  JOIN InDels2 AS source ON source.id = snpEConnect.indelID 
  WHERE geneConnect.geneSymbolID NOT IN (
    SELECT geneConnect.geneSymbolID FROM SNPEffectGeneConnector AS geneConnect 
    JOIN IndelSNPEffectConnector AS snpEConnect ON geneConnect.snpEffectID = snpEConnect.snpEffectID 
    JOIN InDels3 AS target ON target.id = snpEConnect.indelID);
+----+--------------------+-------------+-------+-------------------+----------+---------+-----------------------------------------------------------------------+------+--------------------------------+
| id | select_type        | table       | type  | possible_keys     | key      | key_len | ref                                                                   | rows | Extra                          |
+----+--------------------+-------------+-------+-------------------+----------+---------+-----------------------------------------------------------------------+------+--------------------------------+
|  1 | PRIMARY            | source      | index | id                | id       | 4       | NULL                                                                  | 5771 | Using index; Using temporary   |
|  1 | PRIMARY            | snpEConnect | ref   | snpEList          | snpEList | 4       | treattablebrowser.source.id                                           |    2 | Using index                    |
|  1 | PRIMARY            | geneConnect | ref   | snpEList          | snpEList | 4       | treattablebrowser.snpEConnect.snpEffectID                             |    1 | Using where; Using index       |
|  2 | DEPENDENT SUBQUERY | geneConnect | ref   | snpEList,geneList | geneList | 4       | func                                                                  |    1 | Using index                    |
|  2 | DEPENDENT SUBQUERY | target      | index | id                | id       | 4       | NULL                                                                  | 6297 | Using index; Using join buffer |
|  2 | DEPENDENT SUBQUERY | snpEConnect | ref   | snpEList          | snpEList | 8       | treattablebrowser.target.id,treattablebrowser.geneConnect.snpEffectID |    1 | Using index                    |
+----+--------------------+-------------+-------+-------------------+----------+---------+-----------------------------------------------------------------------+------+--------------------------------+

6行セット (0.01秒)

4

4 に答える 4

3

グレッグが自分で解決した今、これは主に学術的な関心事だと思います。これらのことについての私の直感が完全に壊れる可能性があることを知ってうれしいです。私はまだこれを3つの方法で書き直すことができます。最初に私は単純化できると思いましたが、グレッグが指摘したように、単純化は機能しません。これが元のクエリよりも高速になるかどうかはわかりませんが、SQLサーバーでのテストでは異なるクエリプランが生成されます。

Select Distinct
    g1.geneSymbolID 
From
    SNPEffectGeneConnector AS g1 
        Inner Join
    IndelSNPEffectConnector AS s1 
        ON g1.snpEffectID = s1.snpEffectID 
        Inner Join
    InDels2 AS i2 ON i2.id = s1.indelID 
Where Not Exists (
    Select 'x'
        From
            SNPEffectGeneConnector As g2
                Inner Join
            IndelSNPEffectConnector AS s2 
                On g2.snpEffectID = s2.snpEffectID 
                Inner Join
            InDels3 As i3
                On i3.id = s2.indelID
        Where
            g2.geneSymbolID = g1.geneSymbolID
    );

2番目の方法については100%確信が持てませんが、ごく少量のテストデータで機能します。動作する場合は、クエリプランがはるかに短くなります(必ずしも高速ではありませんが、適切な指標です)。

Select
  geneSymbolID
From
  SNPEffectGeneConnector As g
    Inner Join 
  IndelSNPEffectConnector As s
    ON g.snpEffectID = s.snpEffectID 
    Left Outer Join
  InDels2 As i2 
    On i2.id = s.indelID 
    Left Outer Join
  InDels3 As i3
    On i3.id = s.indelID
Group By
    geneSymbolID
Having
    count(i2.id) > 0 And
    count(i3.id) = 0

別のアプローチ(非記述的エイリアスに対する謝罪):

Select
    g.geneSymbolID
From
    SNPEffectGeneConnector As g
        Inner Join
    IndelSNPEffectConnector AS s
        On g.snpEffectID = s.snpEffectID 
        Inner Join (
        Select 
            i2.id,
            0 As c
        From    
            InDels2 i2
        Union All
        Select
            i3.id,
            1
        From
            InDels3 i3
    ) as i23
    on s.indelID = i23.id
Group By
    g.geneSymbolID
Having
    max(i23.c) = 0;

http://sqlfiddle.com/#!2/944e1/10

于 2012-11-05T22:09:44.210 に答える
0

問題は、すべてにインデックスがありますが、サブクエリによって返される遺伝子IDにインデックスがないことでした。インデックス付けされていない数値のコレクションに対してIN検索に参加/実行すると、パフォーマンスが非常に悪くなります。これが私が得たものです。

私の解決策は、外部JOINと内部JOINを別々に実行し、結果を2つの異なるインデックス付きテーブルにダンプしてから、2にある1のgeneIDを削除することでした。

物語の教訓:索引付けされていないもののコレクションに対して決して参加または参加しないでください。

于 2012-11-07T03:37:23.543 に答える
0
    SELECT DISTINCT geneConnect.geneSymbolID 
    FROM SNPEffectGeneConnector AS geneConnect 
      JOIN IndelSNPEffectConnector AS snpEConnect 
          ON geneConnect.snpEffectID = snpEConnect.snpEffectID 
      JOIN InDels2 AS source ON source.id = snpEConnect.indelID
      LEFT OUTER JOIN InDels3 AS target ON target.id = snpEConnect.indelID
    WHERE target.id is null

上記のクエリはあなたのクエリと同等であり、はるかに優れたパフォーマンスを提供するはずです。

于 2012-11-05T22:09:57.057 に答える
0

私の理解が正しければ、エントリが 内にあるすべてgeneSymbolIDのを見つけて、 内に一致(on ) があるが、内に同じものに対応する一致がないようにする必要があります。SNPEffectGeneConnectorIndelSNPEffectConnectorindelIDInDels2 indelIDInDels3

次に、クエリの最初の部分 (「do」部分) を実行し、さらに最後の部分を結合して、一致するすべての遺伝子を収集しますマッチングの失敗LEFT JOINを課す遺伝子シンボル テーブルを使用したAは、逆の基準に失敗し、したがって対象となるすべての遺伝子を生成します。

修正された回答

これは一致するクエリです:

SELECT DISTINCT genes.geneSymbolID
FROM ( SELECT DISTINCT geneSymbolID FROM SNPEffectGeneConnector ) AS genes
JOIN SNPEffectGeneConnector AS effectSource
    ON ( genes.geneSymbolID = effectSource.geneSymbolID)
JOIN SNPEffectGeneConnector AS effectTarget
    ON ( genes.geneSymbolID = effectTarget.geneSymbolID)
JOIN IndelSNPEffectConnector AS indelSource
    ON ( indelSource.snpEffectID = effectSource.snpEffectID )
JOIN IndelSNPEffectConnector AS indelTarget
    ON ( indelTarget.snpEffectID = effectTarget.snpEffectID ) 
     JOIN InDels2 ON ( indelSource.indelId = InDels2.id )
     JOIN InDels3 ON ( indelTarget.indelId = InDels3.id )
;

さて、このクエリでは、次のインデックスが必要になると思います。

CREATE INDEX SNPEffectGeneConnector_ndx
    ON SNPEffectGeneConnector(snpEffectID, geneSymbolID);

CREATE INDEX SNPEffectGeneConnector_ndx2
    ON SNPEffectGeneConnector(geneSymbolID);

CREATE INDEX IndelSNPEffectConnector_ndx
    ON IndelSNPEffectConnector(snpEffectID, indelID);
CREATE [UNIQUE?] INDEX InDels2_ndx ON InDels2(id); -- unless id is primary key
CREATE [UNIQUE?] INDEX InDels3_ndx ON InDels3(id); -- unless id is primary key

目的の遺伝子を取得するには:

SELECT glob.geneSymbolID
    FROM ( SELECT DISTINCT geneSymbolID FROM SNPEffectGeneConnector ) AS glob
    LEFT JOIN (
SELECT DISTINCT genes.geneSymbolID
FROM ( SELECT DISTINCT geneSymbolID FROM SNPEffectGeneConnector ) AS genes
JOIN SNPEffectGeneConnector AS effectSource
    ON ( genes.geneSymbolID = effectSource.geneSymbolID)
JOIN SNPEffectGeneConnector AS effectTarget
    ON ( genes.geneSymbolID = effectTarget.geneSymbolID)
JOIN IndelSNPEffectConnector AS indelSource
    ON ( indelSource.snpEffectID = effectSource.snpEffectID )
JOIN IndelSNPEffectConnector AS indelTarget
    ON ( indelTarget.snpEffectID = effectTarget.snpEffectID ) 
     JOIN InDels2 ON ( indelSource.indelId = InDels2.id )
     JOIN InDels3 ON ( indelTarget.indelId = InDels3.id )
) AS fits ON (glob.geneSymbolID = fits.geneSymbolID)
WHERE fits.geneSymbolID IS NULL;

テスト

CREATE TABLE InDels2 ( id integer );
INSERT INTO InDels2 VALUES ( 1 );
CREATE TABLE InDels3 ( id integer );
INSERT INTO InDels3 VALUES ( 2 );
CREATE TABLE IndelSNPEffectConnector ( indelId integer, snpEffectID integer );
INSERT INTO IndelSNPEffectConnector VALUES ( 1, 55 ), ( 2, 88 );
CREATE TABLE SNPEffectGeneConnector ( geneSymbolID integer, snpEffectID integer );
INSERT INTO SNPEffectGeneConnector VALUES ( 100, 55 ), ( 100, 88 );

したがって、遺伝子 100 は 1 に接続されている 55 に接続されているため、ID2 に示されていますが、2 に接続されている 88 にも接続されているため、ID3 に接続されているため、出現してはなりません。

表示されますか?要件を理解していれば、インデルが にリストされていないinDels3、効果を引き起こす遺伝子が必要です。したがって、遺伝子 42 は、遺伝子 42 に存在しないインデル 3 にリンクされた効果 77 を引き起こし、inDels3出現する必要があります。

そう:

INSERT INTO SNPEffectGeneConnector VALUES ( 42, 55 );
INSERT INTO SNPEffectGeneConnector VALUES ( 42, 77 );
INSERT INTO IndelSNPEffectConnector VALUES ( 3, 77 );

収量

+--------------+
| geneSymbolID |
+--------------+
|           42 |
+--------------+

最初のクエリの変更を使用して、42 が有効で 100 が有効でない理由を調べることができます。

SELECT genes.geneSymbolID, effectSource.snpEffectID, effectTarget.snpEffectID, indelSource.indelId AS sourceInDel, indelTarget.indelId AS targetInDel, InDels3.id
FROM ( SELECT DISTINCT geneSymbolID FROM SNPEffectGeneConnector ) AS genes
 JOIN SNPEffectGeneConnector AS effectSource
     ON ( genes.geneSymbolID = effectSource.geneSymbolID)
 JOIN SNPEffectGeneConnector AS effectTarget
     ON ( genes.geneSymbolID = effectTarget.geneSymbolID)
 JOIN IndelSNPEffectConnector AS indelSource
     ON ( indelSource.snpEffectID = effectSource.snpEffectID )
 JOIN IndelSNPEffectConnector AS indelTarget
     ON ( indelTarget.snpEffectID = effectTarget.snpEffectID )

      JOIN InDels2 ON ( indelSource.indelId = InDels2.id )
 LEFT JOIN InDels3 ON ( indelTarget.indelId = InDels3.id );

+--------------+-------------+-------------+-------------+-------------+------+
| geneSymbolID | snpEffectID | snpEffectID | sourceInDel | targetInDel | id   |
+--------------+-------------+-------------+-------------+-------------+------+
|           42 |          55 |          55 |           1 |           1 | NULL |
|           42 |          55 |          77 |           1 |           3 | NULL |
|          100 |          55 |          55 |           1 |           1 | NULL |
|          100 |          55 |          88 |           1 |           2 |    2 |
+--------------+-------------+-------------+-------------+-------------+------+

...100 には、InDels3 の ID が null ではない行があり、ターゲット indel 2 を報告します。

于 2012-11-05T22:38:26.487 に答える