mysql - 优化mysql跨多个表的查询

标签 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秒

使用解释:

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    

我已经尝试了我能想到的一切,但似乎无法进一步优化这个查询。如有任何帮助,我们将不胜感激。

瑞克

编辑于 2015 年 3 月 22 日 @ 上午 10:27(东部时间):

    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

最佳答案

有几个问题:

  • 当您按 order by date_sent 使用时,date_send 上的键是使用哈希定义的。
  • 您有一个包含 brand.statusbrand.archive 的 where 子句。 archive 仅存在于组合键 brand_id, status, archive 中,但无法使用,因为 where 子句中未使用第一列 (brand_id)。仅为archive 创建索引,或创建复合(status, archive)
  • subject 需要自己的索引。目前,其指数深深地埋藏在综合指数中。

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

KEY `snap_indx` (`snapshot_id`,`snapshot_guid`,`email`(255),`date_sent`,`subject`(255),`status`,`archive`)

效率很低,因为 subject 的 255 个字节位于 statusarchive 之前,而 statusarchive 各只有 4 个字节。

关于mysql - 优化mysql跨多个表的查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29191077/

相关文章:

mysql - 插入到哪里问题(将值添加到新行)

mysql - 需要帮助通过连接优化 MySQL 查询

mysql索引问题-解释说文件排序

mysql - 最常见的工作日查询

javascript - 如何在 MySQL 值更改时播放声音

php - PHP最近的论坛不显示某些论坛

php - 前 3 个结果的 SQL 查询

mysql - 如何优化服务器中的 SQL?

optimization - 优化MySQL查询: Is it always possible to optimize a query so that it doesn't use "ALL"

mysql - 如果 MySQL 对 AND 条件使用索引,为什么或何时不对 OR 条件使用索引?