简体   繁体   中英

MySQL Order By Very Slow

I understand there are a lot of Order By Questions with various solutions, but what I'm asking for is specific to the data structure that I have setup below.

I have the following 2 tables setup:

Table Setup

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))
)

Query without Order By

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

Output and Explain

Execution Time: .004 seconds

Here is the EXPLAIN output:

    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) 

Query with Order By

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 

Output and Explain

Execution Time: 35.237 seconds

    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)      

Question and Solution

So, my question is, how can I get this to not take forever with the order by. I will have in several cases multiple order by conditions, as well as where statements. The LIMIT/OFFSET is for paging.

The record table currently has 1,139,119 records.

The file_meta_text table currently has 7,584,428 records.

I have a SQLFiddle with the base schema and query, but no data added (too many records):

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

Any help would be greatly appreciated.

Can I suggest to use (because of the where clause):

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

Instead of:

KEY `IDX_RECORD_FGID` (`file_group_id`)

And (because of complete indexing)

 KEY  `IDX_RMT_VALUE` (`value`)

Instead of:

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

But remember that after the 900bytes mysql doesn't index, that is the problem about order by, that is a mysql action that use a field not completely indexed. Are you sure you need to have the "value" field with length 3000?

And I think that you can have the same information using this cleaner query:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM