2017-02-23 113 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' - 看起來像一個交叉連接給我。如果真實數據看起來像樣本數據,則子查詢將生成一個50M行的臨時表。 –

+0

@PaulSpiegel'看起來像一個交叉連接到我',不,它不是交叉連接,因爲有一個'ON'子句。無論如何,使用空間可能不會成爲運行時間的問題。 OP要求爲'table_code'表的每個_row_執行_two_子查詢。至少我的方法只需要一個連接和一個子查詢。 –

+0

@TimBiegeleisen。爲什麼所有記錄reg_number和reg_date類似? –