跨多个表优化mysql查询

时间:2015-03-22 04:42:54

标签: mysql explain

我在优化连接多个表的以下查询时遇到了一些问题。

SELECT count(*) as count, `snapshot_id`, `snapshot_guid`, `image`, `subject`, `name`, `brands`.`facebook`, `brands`.`brand_id`, `brand_guid`, `date_sent`
FROM (`snapshots`)
INNER JOIN `brands` ON `snapshots`.`brand_id` = `brands`.`brand_id`
WHERE `snapshots`.`status` =  1
AND `brands`.`status` =  1
AND `brands`.`archive` =  0
GROUP BY `snapshots`.`brand_id`, `snapshots`.`subject`
ORDER BY `date_sent` desc
LIMIT 20

执行时间:4.9秒

使用EXPLAIN:

id  select_type  table       type   possible_keys                           key                   key_len    ref                                   rows Extra
1     SIMPLE         brands      ALL    PRIMARY,brand_id,status,brand_status    NULL                    NULL       NULL                                338  Using where; Using temporary; Using filesort
1     SIMPLE         snapshots   ref    brand_id,status,snapshot_brand_status   snapshot_brand_status   5          mockd_catalog.brands.brand_id,const 166  

描述品牌和快照表:

描述品牌

Field   Type    Null    Key Default Extra
brand_id    int(11) NO  PRI NULL    auto_increment
brand_guid  char(12)    NO  MUL NULL    
friendly    varchar(128)    YES     NULL    
name    varchar(128)    NO      NULL    
url varchar(2048)   YES     NULL    
logo    text    YES     NULL    
cover   text    YES     NULL    
facebook    varchar(2048)   YES     NULL    
address_1   varchar(128)    YES     NULL    
address_2   varchar(128)    YES     NULL    
city    varchar(50) YES     NULL    
state   varchar(50) YES     NULL    
postal  varchar(20) YES     NULL    
country_code    varchar(128)    YES     NULL    
date_created    datetime    YES     NULL    
date_modified   datetime    YES     NULL    
hp_snapshot tinyint(1)  NO      0   
status  tinyint(1)  YES MUL 0   
archive tinyint(1)  NO      0   

描述快照

Field   Type    Null    Key Default Extra
snapshot_id int(11) NO  PRI NULL    auto_increment
snapshot_guid   char(36)    YES MUL NULL    
brand_id    int(11) NO  MUL 0   
email   varchar(256)    NO  MUL NULL    
seed_email  varchar(256)    NO      NULL    
date_sent   datetime    NO  MUL NULL    
date_created    datetime    NO      NULL    
date_modified   datetime    YES     NULL    
content_type    varchar(10) YES     NULL    
subject varchar(256)    NO      NULL    
source  longtext    YES     NULL    
html    longtext    NO      NULL    
html_error  text    YES     NULL    
thumbnail   text    YES     NULL    
image   text    YES     NULL    
status  tinyint(1)  NO  MUL 0   
archive tinyint(1)  NO      0   
tags    text    YES     NULL    

我已经尝试了我能想到的所有内容,并且似乎无法进一步优化此查询。任何帮助表示赞赏。

瑞克

编辑3/22/2015 @ 10:27 am ET:

    CREATE TABLE `snapshots` (
  `snapshot_id` int(11) NOT NULL AUTO_INCREMENT,
  `snapshot_guid` char(36) DEFAULT NULL,
  `brand_id` int(11) NOT NULL DEFAULT '0',
  `email` varchar(256) NOT NULL,
  `seed_email` varchar(256) NOT NULL,
  `date_sent` datetime NOT NULL,
  `date_created` datetime NOT NULL,
  `date_modified` datetime DEFAULT NULL,
  `content_type` varchar(10) DEFAULT NULL,
  `subject` varchar(256) NOT NULL,
  `source` longtext,
  `html` longtext NOT NULL,
  `html_error` text,
  `thumbnail` text,
  `image` text,
  `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '-1= error, 0 = new, 1 = approved, 2 = review ',
  `archive` tinyint(1) NOT NULL DEFAULT '0',
  `tags` text,
  PRIMARY KEY (`snapshot_id`),
  KEY `snapshot_id` (`snapshot_id`) USING BTREE,
  KEY `brand_id` (`brand_id`),
  KEY `email` (`email`(255)),
  KEY `status` (`status`),
  KEY `snapshot_guid` (`snapshot_guid`) USING BTREE,
  KEY `subject` (`subject`(255)),
  KEY `archive` (`archive`),
  KEY `archive_status` (`archive`,`status`),
  KEY `date_sent` (`date_sent`) USING BTREE,
  KEY `recent_snapshots` (`snapshot_id`,`snapshot_guid`,`archive`,`status`,`brand_id`,`date_sent`,`subject`(255)) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=95002 DEFAULT CHARSET=utf8;

品牌表:

CREATE TABLE `brands` (
  `brand_id` int(11) NOT NULL AUTO_INCREMENT,
  `brand_guid` char(12) NOT NULL,
  `friendly` varchar(128) DEFAULT NULL,
  `name` varchar(128) NOT NULL,
  `url` varchar(2048) DEFAULT NULL,
  `logo` text,
  `cover` text,
  `facebook` varchar(2048) DEFAULT NULL,
  `address_1` varchar(128) DEFAULT NULL,
  `address_2` varchar(128) DEFAULT NULL,
  `city` varchar(50) DEFAULT NULL,
  `state` varchar(50) DEFAULT NULL,
  `postal` varchar(20) DEFAULT NULL,
  `country_code` varchar(128) DEFAULT NULL,
  `date_created` datetime DEFAULT NULL,
  `date_modified` datetime DEFAULT NULL,
  `hp_snapshot` tinyint(1) NOT NULL DEFAULT '0',
  `status` tinyint(1) DEFAULT '0',
  `archive` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`brand_id`),
  KEY `brand_guid` (`brand_guid`) USING BTREE,
  KEY `brand_id` (`brand_id`),
  KEY `status` (`status`) USING BTREE,
  KEY `archive_status` (`archive`,`status`),
  KEY `archive` (`archive`)
) ENGINE=InnoDB AUTO_INCREMENT=423 DEFAULT CHARSET=utf8;

选择语句:

SELECT 
    COUNT(*) AS count,
    `snapshot_id`,
    `snapshot_guid`,
    `image`,
    `subject`,
    `name`,
    `brands`.`facebook`,
    `brands`.`brand_id`,
    `brand_guid`,
    `date_sent`
FROM
    (`snapshots`)
        INNER JOIN
    `brands` ON `snapshots`.`brand_id` = `brands`.`brand_id`
WHERE
    `snapshots`.`archive` = 0
        AND `snapshots`.`status` = 1
        AND `brands`.`archive` = 0
        AND `brands`.`status` = 1
GROUP BY `snapshots`.`brand_id` , `snapshots`.`subject`
ORDER BY `date_sent` DESC
LIMIT 20;

说明:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  snapshots   ref brand_id,status,archive,archive_status  status  1   const   48304   Using where; Using temporary; Using filesort
1   SIMPLE  brands  eq_ref  PRIMARY,brand_id,status,archive_status,archive  PRIMARY 4   mockd_catalog.snapshots.brand_id    1   Using where

1 个答案:

答案 0 :(得分:0)

Ther有几个问题:

  • 当您在date_send中使用using hash时,order by date_sent上的键定义为brand.status
  • 您有brand.archivearchive的where子句。 brand_id, status, archive仅在组合键archive中,但由于第一列(brand_id)未在where子句中使用,因此无法使用它。仅为(status, archive)或复合subject创建索引。
  • KEY `snap_indx` (`snapshot_id`,`snapshot_guid`,`email`(255),`date_sent`,`subject`(255),`status`,`archive`) 需要一个索引。目前,其指数深埋在综合指数中。

作为一般规则,复合索引中列的顺序很重要。索引仅在使用的列是第一列时才有用。第一列越宽,它们的效果就越差。这意味着

subject

效率低,因为status及其255个字节位于archive和{{1}}之前,每个字节只有4个字节。