數據列表(聯表查詢)優化


一、情況描述

我們在做后台數據列表(例如:訂單列表、會員列表、活動列表~~之類的)時候,需要的數據往往需要查詢兩張或以上的數據表,一般情況下會有兩種做法

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 是 已經查詢出來的 單表數據

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM