2014-10-01 123 views
4

我知道有很多Order By Questions與各種解決方案,但我要求的是特定於我已經在下面設置的數據結構。MySQL訂購非常慢

我有以下2個表設置:

表設置

CREATE TABLE `record` (
    `id` INT(11) NOT NULL AUTO_INCREMENT, 
    `file_group_id` INT(11) NOT NULL, 
    `status_id` INT(11) NOT NULL, 
    `title` VARCHAR(3000) NOT NULL, 
    `date_created` DATETIME NOT NULL, 
    `user_created` INT(11) NOT NULL, 
    `publish_date` DATETIME NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `IDX_RECORD_FGID` (`file_group_id`) 
); 

CREATE TABLE `record_meta_text` (
    `id` INT(11) NOT NULL AUTO_INCREMENT, 
    `record_id` INT(11) NOT NULL, 
    `column_id` INT(11) NOT NULL, 
    `value` VARCHAR(3000) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `IDX_RMT_VALUE` (`value`(800)), 
    KEY `IDX_RMT_COL_ID` (`column_id`), 
    KEY `IDX_RMT_RECORD_ID_COL_ID` (`record_id`,`column_id`,`value`(800)) 
) 

沒有訂單查詢通過

SELECT 
    r.title AS col_title, 
    rmt_2780.value AS col_2780, 
    rmt_2781.value AS col_2781, 
    rmt_18474.value AS col_18474 
FROM 
    record r 
INNER JOIN record_meta_text AS rmt_2780 ON rmt_2780.record_id = r.id AND rmt_2780.column_id = 2780 
INNER JOIN record_meta_text AS rmt_2781 ON rmt_2781.record_id = r.id AND rmt_2781.column_id = 2781 
INNER JOIN record_meta_text AS rmt_18474 ON rmt_18474.record_id = r.id AND rmt_18474.column_id = 18474 
WHERE 
    r.file_group_id = 2350 
    AND r.status_id = 1 
LIMIT 0, 50 

輸出和解釋

執行時間:0.004秒

這裏是EXPLAIN輸出:

id select_type table  type possible_keys       key      key_len ref        rows Extra   
------ ----------- --------- ------ --------------------------------------- ------------------------ ------- ---------------------------- ------ ------------- 
    1 SIMPLE  r   ref  PRIMARY,IDX_RECORD_FGID     IDX_RECORD_FGID   4  const       527895 Using where 
    1 SIMPLE  rmt_18474 ref  IDX_RMT_COL_ID,IDX_RMT_RECORD_ID_COL_ID IDX_RMT_RECORD_ID_COL_ID 8  file_cabinet_data.r.id,const  1 (NULL)  
    1 SIMPLE  rmt_2780 ref  IDX_RMT_COL_ID,IDX_RMT_RECORD_ID_COL_ID IDX_RMT_RECORD_ID_COL_ID 8  file_cabinet_data.r.id,const  1 (NULL)  
    1 SIMPLE  rmt_2781 ref  IDX_RMT_COL_ID,IDX_RMT_RECORD_ID_COL_ID IDX_RMT_RECORD_ID_COL_ID 8  file_cabinet_data.r.id,const  1 (NULL) 

查詢與順序按

SELECT 
    r.title AS col_title, 
    rmt_2780.value AS col_2780, 
    rmt_2781.value AS col_2781, 
    rmt_18474.value AS col_18474 
FROM 
    record r 
INNER JOIN record_meta_text AS rmt_2780 ON rmt_2780.record_id = r.id AND rmt_2780.column_id = 2780 
INNER JOIN record_meta_text AS rmt_2781 ON rmt_2781.record_id = r.id AND rmt_2781.column_id = 2781 
INNER JOIN record_meta_text AS rmt_18474 ON rmt_18474.record_id = r.id AND rmt_18474.column_id = 18474 
WHERE 
    r.file_group_id = 2350 
    AND r.status_id = 1 
ORDER BY col_2780 
LIMIT 0, 50 

輸出和解釋

執行時間:35.237秒

id select_type table  type possible_keys       key      key_len ref        rows Extra           
------ ----------- --------- ------ --------------------------------------- ------------------------ ------- ---------------------------- ------ ---------------------------------------------- 
    1 SIMPLE  r   ref  PRIMARY,IDX_RECORD_FGID     IDX_RECORD_FGID   4  const       527895 Using where; Using temporary; Using filesort 
    1 SIMPLE  rmt_2780 ref  IDX_RMT_COL_ID,IDX_RMT_RECORD_ID_COL_ID IDX_RMT_RECORD_ID_COL_ID 8  file_cabinet_data.r.id,const  1 (NULL)           
    1 SIMPLE  rmt_2781 ref  IDX_RMT_COL_ID,IDX_RMT_RECORD_ID_COL_ID IDX_RMT_RECORD_ID_COL_ID 8  file_cabinet_data.r.id,const  1 (NULL)           
    1 SIMPLE  rmt_18474 ref  IDX_RMT_COL_ID,IDX_RMT_RECORD_ID_COL_ID IDX_RMT_RECORD_ID_COL_ID 8  file_cabinet_data.r.id,const  1 (NULL)  

的問題及解決

所以,我的問題是,我怎麼能得到這個不是由順序採取永遠。在幾種情況下,我將通過條件以及聲明的方式來進行多重排序。 LIMIT/OFFSET用於分頁。

record表當前有1,139,119條記錄。

file_meta_text表當前有7,584,428條記錄。

我與基礎架構和查詢,但沒有添加的數據(記錄過多)一SQLFiddle:

http://sqlfiddle.com/#!2/6ffc3/1

任何幫助將不勝感激。

回答

0

我可以建議使用(因爲where子句):

KEY `IDX_RECORD_FGID` (`file_group_id`,`status_id`) 

相反的:

KEY `IDX_RECORD_FGID` (`file_group_id`) 

和(因爲完整的索引)

KEY `IDX_RMT_VALUE` (`value`) 

代替:

KEY `IDX_RMT_VALUE` (`value`(800)) 

但請記住,在900bytes之後,mysql不會進行索引,這就是order by的問題,這是一個使用未完全索引的字段的mysql操作。你確定你需要有長度爲3000的「值」字段嗎?

而且我認爲,你可以使用此清潔劑查詢相同的信息:

SELECT 
    r.title AS col_title, 
    rmt.value AS value, 
    rmt.column_id AS column 
FROM 
    record r 
INNER JOIN record_meta_text AS rmt ON rmt.record_id = r.id 
WHERE 
    rmt.column_id IN(2780,2781,18474) 
    AND 
    r.file_group_id = 2350 
    AND r.status_id = 1 
LIMIT 0, 50 
+0

我會給指數一個嘗試,讓你知道。由於排序需要如何工作,第二個查詢將不起作用。我會讓你知道的。 – CodeLikeBeaker 2014-10-01 15:46:36

+0

我添加了關於「IDX_RMT_VALUE」的筆記,我認爲這是關於您的問題的最大線索。 – AndreaPosadino 2014-10-01 15:47:32

+0

我同意,我必須在3000的值,這是填充緩衝區高於我的表中的最大長度。我也試過了文字,而且更糟。 – CodeLikeBeaker 2014-10-01 15:48:30