【问题标题】:Unable to optimise MySQL query further: what am I missing?无法进一步优化 MySQL 查询:我错过了什么?
【发布时间】:2012-12-20 07:37:06
【问题描述】:

我有一个似乎无法进一步优化的查询(关于执行时间)。这是一个简单的查询,索引到位,我尝试配置 InnoDB 设置......但似乎没有任何帮助。

表格

查询是三个表 trk、auf 和 paf 之间的 JOIN。

  • trk : 临时表保存 id 代表曲目。
  • auf :表示与曲目关联的音频文件的表。
  • paf : 保存已发布音频文件 id 的表。充当“过滤器”。
// 'trk' table  
CREATE TEMPORARY TABLE auf_713340 (  
  `id` char(36),   
  PRIMARY KEY (id)  
) ENGINE=MEMORY);  

// 'auf' table  
CREATE TABLE `file` (  
 `id` char(36) NOT NULL,  
 `track_id` char(36) NOT NULL,  
 `type` varchar(3) DEFAULT NULL,  
 `quality` int(1) DEFAULT '0',  
 `size` int(20) DEFAULT '0',  
 `duration` float DEFAULT '0',  
 `bitrate` int(6) DEFAULT '0',  
 `samplerate` int(5) DEFAULT '0',  
 `tagwritten` datetime DEFAULT NULL,  
 `tagwriteattempts` int(3) NOT NULL DEFAULT '0',  
 `audiodataread` datetime DEFAULT NULL,  
 `audiodatareadattempts` int(3) NOT NULL DEFAULT '0',  
 `converted` datetime DEFAULT NULL,  
 `convertattempts` int(3) NOT NULL DEFAULT '0',  
 `waveformgenerated` datetime DEFAULT NULL,  
 `waveformgenerationattempts` int(3) NOT NULL DEFAULT '0',  
 `flag` int(1) NOT NULL DEFAULT '0',  
 `status` int(1) NOT NULL DEFAULT '0',  
 `updated` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',  
 PRIMARY KEY (`id`),  
 KEY `FK_file_track` (`track_id`),  
 KEY `file_size` (`size`),  
 KEY `file_type` (`type`),  
 KEY `file_quality` (`quality`),  
 CONSTRAINT `file_ibfk_1` FOREIGN KEY (`track_id`) REFERENCES `track` (`id`)  
) ENGINE=InnoDB DEFAULT CHARSET=utf8

// 'paf' table  
CREATE TABLE `publishedfile` (  
  `file_id` varchar(36) NOT NULL,  
  `data` varchar(255) DEFAULT NULL,  
  `file_updated` datetime NOT NULL,  
  PRIMARY KEY (`file_id`)  
) ENGINE=InnoDB DEFAULT CHARSET=utf8  

查询通常需要 1500 毫秒到 2500 毫秒来执行,trk 表中有 50 到 100 个 id。auf 表保存大约 110 万行,paf 表保存大约 900.000 行。

MySQL 服务器在 4GB Rackspace 云服务器实例上运行。

查询

SELECT auf.*
FROM auf_713340 trk
INNER JOIN file auf
  ON auf.track_id = trk.id
INNER JOIN publishedfile paf
  ON auf.id = paf.file_id

带有解释的查询

id select_type table type   possible_keys         key           key_len ref                                 rows Extra
1  SIMPLE      trk   ALL    NULL                  NULL NULL     NULL                                        60  
1  SIMPLE      auf   ref    PRIMARY,FK_file_track FK_file_track 108     func                                1   Using where
1  SIMPLE      paf   eq_ref PRIMARY               PRIMARY       110     trackerdatabase_development.auf.id  1   Using where; Using index

InnoDB 配置

[mysqld]

# The size of memory used to cache table data and indexes. The larger 
# this value is, the less I/O is needed to access data in tables. 
# Default value is 8MB. Recommendations point towards 70% - 80% of 
# available system memory.
innodb_buffer_pool_size=2850M

# Recommendations point towards using O_DIRECT to avoid double buffering.
# innodb_flush_method=O_DIRECT

# Recommendations point towards using 256M.
# @see http://www.mysqlperformanceblog.com/2006/07/03/choosing-proper-innodb_log_file_size/
innodb_log_file_size=256M

# The size in bytes of the buffer that InnoDB uses to write to the log files
# on disk. Recommendations point towards using 4MB.
innodb_log_buffer_size=4M

# The size of the buffer used for MyISAM index blocks.
key_buffer_size=128M

现在,问题是;我该怎么做才能使查询更好地执行?毕竟,有问题的表并没有那么大,而且索引已经到位..?

【问题讨论】:

  • 发布表格的定义 (SHOW CREATE TABLE)。
  • 为什么列出 func 作为auf 的参考?您在发布的 SQL 中进行了直接比较。
  • @ypercube:添加了 SHOW CREATE 语句。
  • @scragar : 不确定...可能是因为 'trk' 表是临时 MEMORY 表吗?我选择了这条路径,而不是在 50 - 100 个 id 上执行 WHERE IN 条件。
  • 由于您的字符集是 utf8,因此声明为 CHAR(36) 的键列实际上占用了 108 个字节。这就是解释显示 key_len 为 108 的原因。因此,“auf”表的大小可能大 3 倍。尝试将所有这些 id 列更改为 BINARY(36)。

标签: mysql performance innodb


【解决方案1】:

在 auf 表中将 id 字段设为 int(11) 并使其自动递增。所有 >11 的 int 字段长度,将它们编辑为 11。

谢谢 里帕萨哈

【讨论】:

  • 感谢您的意见,但说起来容易做起来难。有多个应用程序取决于 id 是 UUID (char) - 这意味着此更改将需要更改整个应用程序。
  • 感谢您的信息。主键将始终是唯一的。所以 INT 是主键的最佳类型。如果 id CHAR(36) 依赖于您的应用程序,那么您可以将此 id 设为 id_depend CHAR(36) 和 id INT(11)。这两个字段可能会解决您的问题。
  • 是的,可能……但我不得不承认我更感兴趣的是研究性能改进而不是重新设计。
【解决方案2】:

试试这个:

SELECT auf.* 
FROM file auf 
WHERE EXISTS 
      ( SELECT *
        FROM auf_713340 trk 
        WHERE auf.track_id = trk.id 
      )
  AND EXISTS
      ( SELECT *
        FROM publishedfile paf
        WHERE auf.id = paf.file_id
      ) ;

我还将测试和比较使用 InnoDB 引擎定义的临时表或将(主)索引作为BTREE 索引的效率。内存表默认有HASH索引,如果我没记错的话不是Btree。

【讨论】:

    猜你喜欢
    • 2016-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-02
    • 1970-01-01
    • 2012-07-20
    • 1970-01-01
    • 2011-11-24
    相关资源
    最近更新 更多