说我有两个MyISAM表:MySQL的:优化连接查询
tab_big: id1, id2, id_a, ord (5 billion records)
tab_small: id1, id2, id_b (1 billion records)
CREATE TABLE IF NOT EXISTS `tab_big` (
`id_a` int(10) unsigned NOT NULL,
`id1` int(10) unsigned NOT NULL,
`id2` int(10) unsigned NOT NULL,
`ord` int(10) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`id_a`,`id1`,`id2`),
KEY `id1` (`id1`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `tab_small` (
`id_b` int(10) unsigned NOT NULL,
`id1` int(10) unsigned NOT NULL,
`id2` int(10) unsigned NOT NULL,
PRIMARY KEY (`id_b`,`id1`,`id2`),
KEY `id_b` (`id_b`),
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
所有字段是INT。在这两个表中,三个id字段(分别是id1,id2,id_a和id1,id2,id_b)的组合是唯一的,所以我为这两个字段创建了一个主键。
我需要获取从第一表,其中ID_A的唯一值的高效的查询:
- ID_B在第二表的表是一个给定值(缩小它下降到约10k的条目)
- id1/id2组合在两个表中都是相同的
- 第一个表中的id_a与tab_small子集中的id1,id2字段中的任一个不相同(如由id_b字段缩小);经过一番小小的调整后,似乎在php中生成列表(大约200个ids)并将其作为文本提供比添加另一个JOIN更好)。
我认为这不是非常缓存,因为两个表都一直在改变(添加行)。
我当前的查询是非常简单的:
SELECT tab_big.id_a FROM tab_big, tab_small
WHERE tab_small.id_b = '$constant'
AND tab_big.id1 = tab_small.id1 AND tab_big.id2 = tab_small.id2
AND tab_big.id_a NOT IN ({comma delimited list of 200 ids})
GROUP BY tab_big.id_a
ORDER BY SUM(tab_big.ord) DESC
LIMIT 10
它的工作原理,但不够快,无法真正使用它。可以用它做什么?
EXPLAIN说它首先从tab_big获取一个远程查询,然后将其应用于tab_small(编辑:下面添加)。我不知道为什么(EXPLAIN说查询使用主键),但添加tab_big.id1索引似乎有所帮助。另外,试图用STRAIGHT_JOIN来反过来,首先从(小)tab_small中选择一个10k子集,然后使用它在(更大的)tab_big中进行搜索,结果会比默认的结果差得多(编辑:用一个小数据集I现在需要进行测试;对于生产数据,它显然是相反的,EXPLAIN看起来像第二个)。
+----+-------------+-----------+--------+-----------------+---------+---------+-------------------------------------------+---------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+--------+-----------------+---------+---------+-------------------------------------------+---------+----------------------------------------------+
| 1 | SIMPLE | tab_big | range | PRIMARY,id1 | PRIMARY | 4 | NULL | 1374793 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | tab_small | eq_ref | PRIMARY,id_b | PRIMARY | 12 | const,db.tab_big.id1,db.tab_big.id2 | 1 | Using index |
+----+-------------+-----------+--------+-----------------+---------+---------+-------------------------------------------+---------+----------------------------------------------+
在更大的数据集EXPLAIN可能会看起来更像这个(虽然无视“行”的价值观 - 它是从一个较小的数据集拍摄):
+----+-------------+-----------+------+---------------------+---------+---------+------------------+-------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------------+---------+---------+------------------+-------+----------------------------------------------+
| 1 | SIMPLE | tab_small | ref | PRIMARY,id_b,id1 | PRIMARY | 4 | const | 259 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | tab_big | ref | PRIMARY,id1 | id1 | 4 | db.tab_small.id1 | 25692 | Using where |
+----+-------------+-----------+------+---------------------+---------+---------+------------------+-------+----------------------------------------------+
有什么想法?
你可以摆脱NOT IN并把它写成IN吗?这通常有助于解决性能问题。 – 2009-10-09 03:39:07
不,不幸的是,我只知道我不想找的东西。 :/ – Mike 2009-10-09 03:41:20
你可以在SQL中发布表结构吗? – wenbert 2009-10-09 04:02:37