2013-08-20 20 views
1

我有一个InnoDB表,加上-9百万条记录。UNION DISTINCT比OR还快900万条记录?

我曾经有过这样的

SELECT 
    my_primary_key 
FROM 
    my_table 
WHERE 
    col1 = 1 AND 
    col2 = 2 AND 
    (col3 = 'aaa' OR col4 = 'bbb' OR col5 = 'ccc') 

我的表结构的查询:

CREATE TABLE IF NOT EXISTS `my_table` (
    `my_primary_key` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
    `col1` tinyint(1) unsigned NOT NULL DEFAULT '0', 
    `col2` tinyint(1) unsigned NOT NULL DEFAULT '0', 
    `col3` varchar(255) NOT NULL, 
    `col4` varchar(255) NOT NULL, 
    `col5` varchar(255) NOT NULL, 
    PRIMARY KEY (`my_primary_key`), 
    KEY `col1` (`col1`), 
    KEY `col2` (`col2`), 
    KEY `col3` (`col3`), 
    KEY `col4` (`col4`), 
    KEY `col5` (`col5`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

基于我的朋友的建议,我试图把它变成

SELECT my_primary_key FROM my_table WHERE col1 = 1 AND col2 = 2 AND col3 = 'aaa' 
UNION DISTINCT 
SELECT my_primary_key FROM my_table WHERE col1 = 1 AND col2 = 2 AND col4 = 'bbb' 
UNION DISTINCT 
SELECT my_primary_key FROM my_table WHERE col1 = 1 AND col2 = 2 AND col5 = 'ccc' 

但当我试图看到正在运行的查询时,我发现“时间”仍然很高(在8-20秒之间)

SHOW FULL PROCESSLIST 

我在正确的路径上使用UNION DISTINCT?或者还有其他更快的方式来执行我的查询?

谢谢。

+0

很难说不知道索引选择性是多少,通常你不会索引TINYINT列,因为它的选择性很低。但是如果列col1和col2具有更高的选择性,那么可以在其上创建一个聚合索引,以便您可以使用交付的表和JOIN来过滤掉不匹配的结果。 –

回答

0

我认为or通常是最快的。但是,它似乎需要全表扫描。您可以尝试(col1, col2, col3, col4, col5, my_primary_key)上的复合索引,这可能会被用来代替扫描。

如果每个子句都可以使用索引并且返回的行数相对较少,那么union distinct会更快。因此,请尝试使用以下索引运行它:

mytable(col1, col2, col3, my_primary_key) 
mytable(col1, col2, col4, my_primary_key) 
mytable(col1, col2, col5, my_primary_key) 

在您的优化中,您试图避免全表扫描。 union distinct可能通过正确的索引来实现。

+0

谢谢你的解释。但是,如果我想添加一些索引,但是我正面临另一个问题,上次尝试时,需要很长时间才能添加一些索引(也许是因为我有很多数据)。你有什么建议如何快速改变表结构? – Xrvel

+0

在有900万条记录的InnoDB表上修改表可能需要一段时间,但是它会根据您正在更改的索引而依赖于InnoDB引擎版本。新的InnoDB引擎版本支持称为快速索引创建的功能,该版本的mysql版本> 5.5应该是默认支持该功能的版本。 –