由于分庫(kù)分表的原因,和開發(fā)規(guī)定了不能使用 表表JOIN 語句。因此,我們要將 JOIN 語句的轉(zhuǎn)化成使用 IN 來做。如現(xiàn)在有 表 A(a_id, c_a)c_a有普通索引,表 B(b_id, c_a) 這兩個(gè)表要關(guān)聯(lián), 應(yīng)該轉(zhuǎn)化為以下步驟處理:
先查詢B中的 a_idSELECT c_a FROM B WHERE xxx;使用 IN 查詢 A 表SELECT a_id, ... FROM A WHERE c_a IN(在 1 中查出來的 c_a)場(chǎng)景現(xiàn)在表的數(shù)據(jù)量有 800萬。
一般的使用語句是:
SELECT * FROM A WHERE c_a IN(955555, 955556, 955557, 955558, 955559);上面語句會(huì)執(zhí)行的很快,知道使用 explain 的都明白這樣一般都是會(huì)使用索引的,并且是所有范圍掃描。
MySQL不會(huì)從 1 開始 掃描 800萬,而是從555555 掃描到 555559(只要掃描5行數(shù)據(jù))。
在一般情況下是沒有什么問題的。但是如果 IN 里面的數(shù)據(jù)是不連續(xù)的就有很大問題了。
創(chuàng)建表結(jié)構(gòu)語句CREATE TABLE t( id INT unsigned NOT NULL AUTO_INCREMENT, cid INT unsigned NOT NULL DEFAULT 0, c1 VARCHAR(50) NOT NULL DEFAULT '', c2 VARCHAR(50) NOT NULL DEFAULT '', c3 VARCHAR(50) NOT NULL DEFAULT '', c4 VARCHAR(50) NOT NULL DEFAULT '', c5 VARCHAR(50) NOT NULL DEFAULT '', c6 VARCHAR(50) NOT NULL DEFAULT '', PRIMARY KEY(id), INDEX idx$cid(cid)); INSERT INTO t VALUES( NULL, FLOOR(RAND() * 1000000), REPEAT('a', 50), REPEAT('a', 50), REPEAT('a', 50), REPEAT('a', 50), REPEAT('a', 50), REPEAT('a', 50)); -- 重復(fù)執(zhí)行INSERT INTO tSELECT NULL, FLOOR(RAND() * 1000000), c1, c2, c3, c4, c5, c6FROM t;下面是具體的實(shí)驗(yàn)過程使用IN查詢連續(xù)的數(shù)SELECT *FROM tWHERE cid IN(955555, 955556, 955557, 955558, 955559);+---------+--------+-----------------------------------| id | cid | c1 +---------+--------+-----------------------------------| 319330 | 955555 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| 1885293 | 955555 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| ......| 8733757 | 955559 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| 8796305 | 955559 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+---------+--------+-----------------------------------41 rows in set (0.15 sec)使用IN查詢不連續(xù)的數(shù)SELECT *FROM tWHERE cid IN(1, 5000, 50000, 500000, 955559);+---------+--------+-----------------------------------| id | cid | c1 +---------+--------+-----------------------------------| 1 | 341702 | 1 | aaaaaaaaaaaaaaaaaaaaaaaaa| 1 | 1045176 | 1 | aaaaaaaaaaaaaaaaaaaaaaaaa......| 955559 | 8733757 | 955559 | aaaaaaaaaaaaaaaaaaaaaaaaa| 955559 | 8796305 | 955559 | aaaaaaaaaaaaaaaaaaaaaaaaa+--------+---------+--------+--------------------------41 rows in set (4.34 sec)使用UNION優(yōu)化SELECT *FROM ( SELECT 1 AS cid UNION ALL SELECT 5000 UNION ALL SELECT 50000 UNION ALL SELECT 500000 UNION ALL SELECT 955559) AS tmp, tWHERE tmp.cid = t.cid;+---------+--------+-----------------------------------| id | cid | c1 +---------+--------+-----------------------------------| 1 | 341702 | 1 | aaaaaaaaaaaaaaaaaaaaaaaaa| 1 | 1045176 | 1 | aaaaaaaaaaaaaaaaaaaaaaaaa......| 955559 | 8733757 | 955559 | aaaaaaaaaaaaaaaaaaaaaaaaa| 955559 | 8796305 | 955559 | aaaaaaaaaaaaaaaaaaaaaaaaa+--------+---------+--------+--------------------------41 rows in set (0.01 sec)從上面可以看出上面使用UNION的方法生成一個(gè)臨時(shí)表作為關(guān)聯(lián)的主表。
拓展要是MySQL有只帶的一個(gè)行轉(zhuǎn)列的函數(shù)那就完美了。這樣我們就可以不用使用UNION了。
SELECT 1, 5000, 50000, 500000, 955559;+---+------+-------+--------+--------+| 1 | 5000 | 50000 | 500000 | 955559 |+---+------+-------+--------+--------+| 1 | 5000 | 50000 | 500000 | 955559 |+---+------+-------+--------+--------+1 row in set (0.00 sec) 變成以下SELECT row_to_col(1, 5000, 50000, 500000, 955559);+--------+| id |+--------+| 1 || 5000 || 50000 || 500000 || 955559 |+--------+要是能像上面就太棒了簡(jiǎn)直。
本文
免費(fèi)提供最新linux技術(shù)教程書籍,為開源技術(shù)愛好者努力做得更多更好:http://www.linuxprobe.com/
新聞熱點(diǎn)
疑難解答
圖片精選