最近幫人解決一個循環優化的問題

這兩天接個任務,幫人解決一個循環優化的問題。

和開發聯繫了一下,搞明白原來是這樣一個事。因爲數據庫比較緩慢,這些人決定把數據取到內存裏處理。兩張10w條左右的表寫了個嵌套循環...


本來聽到數據庫數據加載內存這一個說法,立刻想到是不是可以加個memcached緩存。但是一看sql,各種複雜的邏輯和多表連接,還是算了。。。

我和他說,你這個思路完全是不正確的。數據庫有問題應該explain sql看看到底慢在哪。。。加載內存這種事情應該是vfs層的緩存機制實現的麼。如果你想把數據庫都加載到內存裏處理,不相當於做一個rdbms麼,我哪有這能力。

然後我又問他,這些內存裏的數據要不要和數據源進行同步?他說,數據取出來用一下,用完就丟。。

好吧。。。看來索引什麼的也沒意義了。。


最後,只能給了他一個O(m+n)的算法。做了一個demo給他,灰常簡單的東西:

#!/usr/bin/env python
#coding:utf-8
#簡單演示data1和data2的對key的內連接。更多種的表達式解析需要對模式進行重新設計。比如可以再寫一個sql解析引擎
#想要實現的sql功能如下:
#select * from data1 where data1.value<5 and data2.value like 'a%' and data1.key=data2.key
import random
#---------------------------------------------
class Data1(object):
    '''
    第一張表的結構
    '''
    __slot__=('key','value')
    def __init__(self,key,value):
        self.key=key
        self.value=value
    def __str__(self):
        return str((self.key,self.value))
    def __repr__(self):
        return str((self.key,self,value))
class Data2(object):
    '''
    第二張表的結構
    '''
    __slot__=('key','value')
    def __init__(self,key,value):
        self.key=key
        self.value=value
    def __str__(self):
        return str((self.key,self.value))
    def __repr__(self):
        return str((self.key,self.value))
#-------------------------------------------
#where匹配的策略,每個條件變成一個工具類。設計的非常粗糙,只做算法演示用,可以用bool邏輯進行組合
class WhereStratege(object):
    @staticmethod
    def judge(data):
        pass
class Little_Then_5(WhereStratege):
    @staticmethod
    def judge(data):
        if data.value<5:
            return True
        else:
            return False
class Begin_With_A(WhereStratege):
    @staticmethod
    def judge(data):
        if data.value.startswith('a'):
            return True
        else:
            return False
       
#------------------------------------------------------
#下面是算法的基本邏輯實現。python裏面自帶hashtable作爲其基礎數據結構。.net平臺基本庫也有hashtable的實現。
#在System.Collectons命名空間下面。這些hashtable應該都是帶自動擴容的功能。因爲我不確定這個實現在大量數據
#下表現怎麼樣,不過應該是沒什麼問題的。如果發現在一定量級下hashtable性能出現明顯下降。說明這個hashtable的
#碰撞非常嚴重。很有可能是load factor過高導致的。正常情況下hashtable裏面讀寫數據的時間隨着數量增長保持在一個
#穩定的水平。偶爾會出現2、3倍的時間可能是產生了碰撞。每隔一段時間會出現一個比較慢的插入,說明hashtable正在
#進行擴容。擴容的速度隨着表的增長會越來越慢,但是每次擴容後距離下一次擴容的時間也越長。因此均攤後的hashtable
#的讀寫性能是O(1)的。
#這個demo裏面的result表示結果數組。實際操作中的可能會取兩張表的各種字段。隨便用一個struct就可以了。因爲兩張表
#中能夠匹配的數據的地址位置已經知道了。可以根據需要生成需要的結構。另外,接口設計也要進行改動。每張表一個匹配
#邏輯的數組。如果你想要同時對多個字段進行連接,如果是與關係,使用一個hashtable就可以了。如果是或關係,需要再
#建立一個hashtable。如果是多表連接,也是同樣的道理。
#需要注意的是無論是hash表還是結果緩衝區,都會比較大。需要在堆中生成而不是在線程棧裏面。python不太好表現這個。
#另外,hashtable只能用來實現等於的連接條件,無法實現偏序關係,但是我想應該不太會有偏序的,或是更奇怪的連接要求。
def connect_data(data_list1,data_list2,method1,method2):
    hashtable={}
    result=[]
    for data in data_list1:
        if method1.judge(data):
            hashtable[data.key]=data
    for data in data_list2:
        if data.key not in hashtable:
            continue
        elif method2.judge(data):
            result.append(hashtable[data.key])
    return result
#---------------------------------------------------------
#只測試了10*10的表,方便驗證程序的正確性。由於算法本身很簡單,很容易看出是O(m+n)的,demo裏就不進行性能測試了。
#第一張表的key和value是隨機的10以內的數。第二張表的key是5~14的數,value是abc字母隨機的組合。
#本來想把兩張表做成生成器,每次迭代的時候自動生成數據來節省內存空間。不過又想了一下,這不符合實際的環境。
def gen_string(length,chartable):
    '''
    在chartable字符表中隨機選擇字符生成長度爲length的字符串
    '''
    return ''.join([random.choice(chartable) for i in range(length)])
def test():
    '''
    簡單的測試用例
    '''
    keylist1=range(10)
    keylist2=range(5,15)
    valuelist1=range(10)
    valuelist2=[gen_string(3,['a','b','c']) for i in range(10)]
    random.shuffle(keylist1)
    random.shuffle(valuelist1)
    random.shuffle(keylist2)
    datalist1=map(Data1,keylist1,valuelist1)
    datalist2=map(Data2,keylist2,valuelist2)
    print '第一張表的數據:\n'
    for data in datalist1:
        print data
    print '\n第二張表的數據:\n'
    for data in datalist2:
        print data
    print '\n連接以後的數據:\n'
    r=connect_data(datalist1,datalist2,Little_Then_5,Begin_With_A)
    for data in r:
        print data
if __name__=='__main__':
    test()


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章