2

table_1 (1GB) と参照 (250Mb) という名前の 2 つのテーブルがあります。

参照でクロス結合をクエリすると、table_1 を更新するのに 16 時間かかります。システム ファイル EXT3 を XFS 用に変更しましたが、それでも 16 時間かかります。

更新/クロス結合クエリは次のとおりです。

  mysql> UPDATE table_1 CROSS JOIN reference ON
  -> (table_1.start >= reference.txStart AND table_1.end <= reference.txEnd)
  -> SET table_1.name = reference.name;
  Query OK, 17311434 rows affected (16 hours 36 min 48.62 sec)
  Rows matched: 17311434  Changed: 17311434  Warnings: 0

以下は、table_1 と参照の show create table です。

    CREATE TABLE `table_1` (
     `strand` char(1) DEFAULT NULL,
     `chr` varchar(10) DEFAULT NULL,
     `start` int(11) DEFAULT NULL,
     `end` int(11) DEFAULT NULL,
     `name` varchar(255) DEFAULT NULL,
     `name2` varchar(255) DEFAULT NULL,
     KEY `annot` (`start`,`end`)
   ) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;


   CREATE TABLE `reference` (
     `bin` smallint(5) unsigned NOT NULL,
     `name` varchar(255) NOT NULL,
     `chrom` varchar(255) NOT NULL,
     `strand` char(1) NOT NULL,
     `txStart` int(10) unsigned NOT NULL,
     `txEnd` int(10) unsigned NOT NULL,
     `cdsStart` int(10) unsigned NOT NULL,
     `cdsEnd` int(10) unsigned NOT NULL,
     `exonCount` int(10) unsigned NOT NULL,
     `exonStarts` longblob NOT NULL,
     `exonEnds` longblob NOT NULL,
     `score` int(11) DEFAULT NULL,
     `name2` varchar(255) NOT NULL,
     `cdsStartStat` enum('none','unk','incmpl','cmpl') NOT NULL,
     `cdsEndStat` enum('none','unk','incmpl','cmpl') NOT NULL,
     `exonFrames` longblob NOT NULL,
      KEY `chrom` (`chrom`,`bin`),
      KEY `name` (`name`),
      KEY `name2` (`name2`),
      KEY `annot` (`txStart`,`txEnd`)
   ) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
4

5 に答える 5

4

table_1.startreference.txStarttable_1.endおよびreference.txEndテーブル フィールドにインデックスを付ける必要があります。

ALTER TABLE `table_1` ADD INDEX ( `start` ) ;
ALTER TABLE `table_1` ADD INDEX ( `end` ) ;
ALTER TABLE `reference` ADD INDEX ( `txStart` ) ;
ALTER TABLE `reference` ADD INDEX ( `txEnd` ) ;
于 2011-07-04T02:42:53.737 に答える
1

交差結合はデカルト積であり、おそらく計算コストが最も高いものの 1 つです (うまくスケーリングできません)。

i = 1 から n の各テーブル T_i について、テーブル T_1 から T_n を交差させることによって生成される行の数は、各テーブルのサイズに他の各テーブルのサイズを掛けた値になります。つまり、

|T_1| * |T_2| * ... * |T_n|

各テーブルに M 行があると仮定すると、クロス結合を計算する結果のコストは次のようになります。

M_1 * M_2 ... M_n = O(M^n)

これは、結合に含まれるテーブルの数で指数関数的です。

于 2011-07-04T02:51:15.327 に答える
0

誰かがすでにいくつかのインデックスを追加するように提案しました。しかし、これら2つのインデックスで得られる最高のパフォーマンスは次のとおりです。

ALTER TABLE `test`.`time` 
    ADD INDEX `reference_start_end` (`txStart` ASC, `txEnd` ASC),
    ADD INDEX `table_1_star_end` (`start` ASC, `end` ASC);

MySQLクエリで使用されるのはそのうちの1つだけですが、MySQLはどちらがより有用であるかを自動的に決定します。

于 2011-07-06T07:41:00.993 に答える
0

UPDATEこのステートメントには 2 つの問題があります。

Endフィールドのインデックスはありません。複合インデックス ( ) は、このクエリのフィールドにannotのみ使用されます。startEmre の提案に従って、それらを追加する必要があります。

ALTER TABLE `table_1` ADD INDEX ( `end` ) ;
ALTER TABLE `reference` ADD INDEX ( `txEnd` ) ;

第 2 に、 はの行に関連するJOINtable の多くの行を検出する可能性があります (おそらく検出します) 。したがって、その一部 (またはすべて) の行が更新され、何度も更新されます。このクエリの結果をチェックして、更新された行数 ( )と同じかどうかを確認します。referencetable_1table_117311434

SELECT COUNT(*)
FROM table_1
  WHERE EXISTS
    ( SELECT *
      FROM reference
      WHERE table_1.start >= reference.txStart
        AND table_1.`end` <= reference.txEnd
    )

このクエリを作成する方法は他にもありますが、PRIMARY KEY両方のテーブルに a がないため、作成が難しくなります。で主キーを定義する場合は、主キーにtable_1置き換えidて、これを試してください。

更新: いいえ、34M 行のテーブルで試してはいけません。実行計画を確認し、最初に小さいテーブルで試してください。

UPDATE table_1 AS t1
  JOIN 
    ( SELECT t2.id
           , r.name
      FROM table_1 AS t2
        JOIN
          ( SELECT name, txStart, txEnd
            FROM reference
            GROUP BY txStart, txEnd
          ) AS r
          ON  t2.start >= r.txStart
          AND t2.`end` <= r.txEnd
      GROUP BY t2.id
    ) AS good
    ON good.id = t1.id
SET t1.name = good.name;

同等の SELECT で EXPLAIN を実行すると、クエリ プランを確認できます。

EXPLAIN
SELECT t1.id, t1.name, good.name
FROM table_1 AS t1
  JOIN 
    ( SELECT t2.id
           , r.name
      FROM table_1 AS t2
        JOIN
          ( SELECT name, txStart, txEnd
            FROM reference
            GROUP BY txStart, txEnd
          ) AS r
          ON  t2.start >= r.txStart
          AND t2.`end` <= r.txEnd
      GROUP BY t2.id
    ) AS good
    ON good.id = t1.id ;
于 2011-07-04T09:13:19.413 に答える
0

これを試して:

UPDATE table_1 SET
table_1.name = (
  select reference.name
  from reference
  where table_1.start >= reference.txStart
  and table_1.end <= reference.txEnd)
于 2011-07-04T02:45:31.193 に答える