一、情況描述
我們在做后台數據列表(例如:訂單列表、會員列表、活動列表~~之類的)時候,需要的數據往往需要查詢兩張或以上的數據表,一般情況下會有兩種做法
1)聯表查詢(在這里先不考慮通過聯表方法無法查詢到想要的字段數據的情況)
2)查單表,循環處理查詢其他表的信息
二、兩種查詢方法比較
針對以上兩種情況呢,一般我們都會以為聯表查詢會比循環查詢要快,其實實際情況並不是這樣的,其實查單表,再循環查詢其他表反而更快
這是為什么呢???其實我也不知道哈哈,下面給出一些我自己的猜測(具體哪個更快,建議各位同學自己動手寫一下代碼做實驗!)
猜測:
1)如果要查詢的表數據量比較大,和其他表的關聯關系也比較復雜(查一個字段需要關聯兩張表之類的),這樣拼出來的sql語句其實是比較復雜和啰唆的;
2)聯表查詢的時候,並不像查單表一樣(假設查20條數據)直接就查詢返回20條記錄的,它內部的關聯關系比較復雜,例如訂單表的member_id關系顯示members表的uname,可能並不像我們用member_id來從members表里查詢uname一樣快捷,它要處理sql里的關聯邏輯判斷(具體是怎樣我也並不懂~~);
3)可能你會說“如果用循環來查詢,那不就要執行好多個sql語句(一條記錄查一次),mysql連接也消耗大量的資源了嗎??”;
4)其實實際上也不完全是這樣,mysql連接是要浪費的(下面會有優化方法),不過總查詢時間並不會比聯表慢。你想一下,當你面對一個很復雜,邏輯很繁瑣的問題的時候,相比於硬啃,當復雜問題分解成若干個容易處理的小問題,反而更快
5)以上都是一臉正經地胡說八道,具體性能如何,自己做實驗測試!!
三、優化循環查詢
上面說到用查單表再循環查詢其它表的方法要比聯表查詢要快,但要消耗比較多的數據庫連接,下面我們要說一下如何減少查詢次數
1)循環查詢的時候,我們一般都是通過一個id去其他表查詢我們需要的數據(例如orders表member_id查詢members表uname),每循環一次查詢一次;
2)其實你有沒有發現,每次查詢的語句都是一樣的??(例如:select uname from members where member_id='xxx'),既然是都一樣的,那么我們為什么還要每一次都重復等於等於(=)地來查詢??mysql不是還是in這個東西嗎??
3)通過上面分析,我們知道,如果是一樣的sql語句,只是查詢條件值不同的話,干嘛不用in呢??( 例如:select uname from members where member_id in ('1','2') )
4)以上面案例為例的話,其實我們先循環出所以的member_id,再用in一次性查詢所有的uname會更快,也只需要查詢一次!!!!
5)所以剩下的問題就只是怎么把查詢出來的uname再重新分配到每一條記錄中去了
6)下面是我的邏輯實現代碼, 僅供參考!!!
/** * 更高效的擴展列處理方法 * add by tujia @2016.11.07 * expression(表達式)說明 * 1)前面兩個參數是關聯表的on條件(例如:rel_id=order_id) * 2)第三個參數是你要提取的字段的名字(例如:t_payed) * 3)示例:rel_id=order_id=t_payed,member_id=member_id=login_account */ protected function nice_row_data(&$data, $sql, $expression){ $ttt = explode('=', $expression); foreach ($data as $key => $value) { $ids[] = $value[$ttt[1]]; } $ids = implode("','", $ids); $sql = sprintf($sql, $ids); $list = $this->db->select($sql); $temp = array(); foreach ($list as $key => $value) { $temp[$value[$ttt[0]]] = $value[$ttt[2]]; } foreach ($data as $key => $value) { $data[$key][$ttt[2]] = isset($temp[$value[$ttt[1]]])? $temp[$value[$ttt[1]]] : 0; } }
使用示例:
$sql = "SELECT `rel_id`,`t_payed` FROM `sdb_ectools_order_bills` ob LEFT JOIN `sdb_ectools_payments` p ON p.`payment_id` = ob.`bill_id` WHERE ob.`rel_id` IN ('%s') AND p.`status`='succ'"; $this->nice_row_data($data, $sql, 'rel_id=order_id=t_payed');
補充說明:$data 是 已經查詢出來的 單表數據