Выберите количество (*) из обновления A в B Super Slow - PullRequest
2 голосов
/ 05 июля 2011

У меня есть запрос, который занимает 2 минуты для подсчета из таблицы A и обновления таблицы B результатом подсчета.

Каждый раз, когда число в столбце Start_B таблицы совпадает с диапазоном в Table_A (readstart / readend), я должен обновлять read_count в Table_B.

   id | readstart | readend | read_count
    1 | 2999997   | 3000097  | 0   
    2 | 3000097   | 3000197  | 0   
    3 | 3000497   | 3000597  | 0   
    4 | 3001597   | 3001697  | 0   
    5 | 3001897   | 3001997  | 0   
    6 | 3005397   | 3005497  | 0   
    7 | 3005997   | 3006097  | 0  
    8 | 3006397   | 3006497  | 0   
    9 | 3006797   | 3006897  | 0  
    10| 3007497   | 3007597  | 0

Вот таблица, которую я должен обновить с результатом подсчета:

    CREATE TABLE `rdc_test` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `readstart` int(11) DEFAULT NULL,
    `readend` int(11) DEFAULT NULL,
    `read_count` int(11) DEFAULT NULL,
     PRIMARY KEY (`id`),
     KEY `readstart` (`readstart`),
     KEY `readend` (`readend`)
    ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;

Вот таблица, из которой я хочу посчитать соответствующие строки:

   CREATE TABLE `1ips_chr1` (
   `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,
   `id` int(11) NOT NULL AUTO_INCREMENT,
   PRIMARY KEY (`id`),
   KEY `start` (`start`),
   KEY `end` (`end`)
  ) ENGINE=MyISAM AUTO_INCREMENT=34994289 DEFAULT CHARSET=latin1;

Я провел тест на 10 строках, результат был ужасным. 2 минуты, чтобы выбрать количество (*) и обновить 10 рядов. У меня есть около 350 000 строк в Таблице_A для обновления и 35 000 000 в таблице Table_B. Я знаю, что в среднем каждый счет должен возвращать 30 ~ 40 в результате.

Вот мой супер медленный запрос:

UPDATE rdc_test
SET rdc_test.read_count =
    ( 
        SELECT COUNT(start) as read_count 
        FROM 1ips_chr1
        WHERE 1ips_chr1.start >= rdc_test.readstart 
        AND 1ips_chr1.start <= rdc_test.readend
    )

Query OK, 10 rows affected (2 min 22.20 sec)
Rows matched: 10  Changed: 10  Warnings: 0

Ответы [ 2 ]

2 голосов
/ 05 июля 2011

Попробуйте это:

UPDATE rdc_test t1
    INNER JOIN 
    (
        SELECT r.id AS id, 
               COUNT(l.start) AS read_count
        FROM rdc_test r
            LEFT OUTER JOIN start1ips_chr1 l
                ON l.start >= r.readstart 
                AND l.start <= r.readend
        GROUP BY r.id
    ) t2
    ON t1.id = t2.id
SET t1.read_count =  t2.read_count

Редактировать:

Из-за количества данных, которые необходимо обновить, лучший способ состоит в том, чтобы воссоздать таблицу вместо выполнения обновления:

CREATE TABLE new_rdc_test AS
SELECT r.id AS id, 
       r.readstart AS readstart,
       r.readend AS readend,
       COUNT(l.start) AS read_count
FROM rdc_test r
    LEFT OUTER JOIN start1ips_chr1 l
        ON l.start >= r.readstart 
        AND l.start <= r.readend
GROUP BY r.id, r.readstart, r.readend

Этот запрос выполняется достаточно быстро?

0 голосов
/ 05 июля 2011

Попробуйте перевести COUNT(*) на уровень приложения (т. Е. Сохранить его как переменную в PHP / Java), а затем выполнить UPDATE с этим значением.MySQL не нужно будет рассчитывать это количество для каждой обновляемой вами записи.

...