2017-02-23 3 views
4

я не могу работать, как получить этот подзапрос очень медленно, чтобы получить данные в 10k записиПростой подзапрос занимает слишком много времени, есть ли какие-либо опции?

table_code:

+--------+-----------+------------+ 
| code_id| code_name | code_date | 
+--------+-----------+------------+ 
| 1 |  A1 | 2017-02-01 | 
| 2 |  A2 | 2017-02-02 | 
| 3 |  A3 | 2017-02-03 | 
| 4 |  A4 | 2017-02-04 | 
| 5 |  A5 | 2017-02-05 | 
| 6 |  A6 | 2017-02-06 | 
| 7 |  A7 | 2017-02-07 | 
|10000 | A10000 | 2017-02-22 | 
+--------+-----------+------------+ 

table_reg:

+--------+------------+------------+ 
| reg_id | reg_number | reg_date | 
+--------+------------+------------+ 
| 1 | 1010  | 2017-02-01 | 
| 2 | 1020  | 2017-02-02 | 
| 3 | 1030  | 2017-02-03 | 
| 4 | 1040  | 2017-02-04 | 
| 5 | 1050  | 2017-02-05 | 
| 6 | 1060  | 2017-02-06 | 
| 7 | 1070  | 2017-02-07 | 
|10000 | 101010  | 2017-02-22 | 
+--------+-----------+------------+ 

Тогда я бегу:

SELECT 
a.`code_name`, 
a.`code_date`, 
(SELECT b.`reg_number` FROM `table_reg` b WHERE b.`reg_date` <= a.`code_date` ORDER BY b.`reg_date` DESC LIMIT 1) AS `reg_number`, 
(SELECT b.`reg_date` FROM `table_reg` b WHERE b.`reg_date` <= a.`code_date` ORDER BY b.`reg_date` DESC LIMIT 1) AS `reg_date` 
FROM `table_code` a 

Результат:

+-----------+------------+------------+------------+ 
| code_name | code_date | reg_number | reg_date | 
+-----------+------------+------------+------------+ 
|  A1 | 2017-02-01 | 1010  | 2017-02-01 | 
|  A2 | 2017-02-02 | 1020  | 2017-02-02 | 
|  A3 | 2017-02-03 | 1030  | 2017-02-03 | 
|  A4 | 2017-02-04 | 1040  | 2017-02-04 | 
|  A5 | 2017-02-05 | 1050  | 2017-02-05 | 
|  A6 | 2017-02-06 | 1050  | 2017-02-05 | 
|  A7 | 2017-02-07 | 1050  | 2017-02-05 | 
| A10000 | 2017-02-22 | 1050  | 2017-02-05 | 
+-----------+------------+------------|------------+ 

DDL:

CREATE TABLE `table_reg` (
    `reg_id` INTEGER(11) NOT NULL AUTO_INCREMENT, 
    `reg_number` INTEGER(11) DEFAULT NULL, 
    `reg_date` DATE DEFAULT NULL, 
    PRIMARY KEY (`reg_id`) USING BTREE, 
    KEY `table_reg_idx1` (`reg_date`) USING BTREE 
) ENGINE=InnoDB 
AUTO_INCREMENT=4 CHARACTER SET 'latin1' COLLATE 'latin1_swedish_ci' 
COMMENT='InnoDB free: 7168 kB; InnoDB free: 6144 kB'; 

CREATE TABLE `table_code` (
    `code_id` INTEGER(11) NOT NULL AUTO_INCREMENT, 
    `code_name` VARCHAR(20) COLLATE latin1_swedish_ci DEFAULT NULL, 
    `code_date` DATE DEFAULT NULL, 
    PRIMARY KEY (`code_id`) USING BTREE, 
    KEY `table_code_idx1` (`code_date`) USING BTREE 
) ENGINE=InnoDB 
AUTO_INCREMENT=8 CHARACTER SET 'latin1' COLLATE 'latin1_swedish_ci' 
COMMENT='InnoDB free: 7168 kB; InnoDB free: 6144 kB'; 

Результат работает как ожидалось, но это очень медленно с 10k записи,

Если code_date может не совпадать с reg_date_date, он с помощью reg_number последней даты.

(SELECT b.`reg_number` FROM `table_reg` b WHERE b.`reg_date` <= a.`code_date` ORDER BY b.`reg_date` DESC LIMIT 1) AS `reg_number` 

Есть ли другие варианты запроса?

Эта ссылка sqlfiddle: [http://sqlfiddle.com/#!9/f090ad/1]

Любая помощь будет оценена. Спасибо

EXPLAIN таблица результата выборки: enter image description here

+0

В ваших таблицах нет указателей. –

+0

У них PK's- должен быть проиндексирован AFAIK – RuDevel

+0

'WHERE b.reg_date <= a.code_date' - вам нужен хотя бы индекс на' b.reg_date'. –

ответ

0

Как уже сказал, ваш нынешний подход может работать с приемлемой скоростью, если добавить соответствующие индексы. Но одной альтернативой вашему текущему запросу было бы использовать подход с номером строки.

SET @row_number = 1; 

SELECT t.code_name, 
     t.code_date, 
     t.reg_number, 
     t.reg_date 
FROM 
(
    SELECT @row_number:=CASE WHEN @code_id = t1.code_id 
          THEN @row_number + 1 ELSE 1 END AS rn, 
      @code_id:=t1.code_id AS code_id, 
      t1.code_name, 
      t1.code_date, 
      t2.reg_number, 
      t2.reg_date 
    FROM table_code t1 
    INNER JOIN table_reg t2 
     ON t2.reg_date <= t1.code_date 
    ORDER BY t1.code_id, t2.reg_date DESC 
) t 
WHERE t.rn = 1 
+0

'INNER JOIN table_reg t2 ON t2.reg_date <= t1.code_date' - Похоже, что крест присоединяется ко мне. Если реальные данные выглядят как образцы данных, ваш подзапрос приведет к таблице temp 50M строк. –

+0

@PaulSpiegel 'Похоже, что крест присоединяется ко мне', нет, это не крест, потому что есть предложение' ON'. В любом случае использование пространства может быть не такой проблемой, как время работы. OP требует выполнения _two_ подзапросов для каждой _row_ таблицы 'table_code'. По крайней мере, мой подход потребует только одного соединения и одного подзапроса. –

+0

@TimBiegeleisen. Почему все записи reg_number и reg_date похожи? –

Смежные вопросы