說我有兩個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