2017-10-18 7 views
1

MongoDB에서 삽입 속도가 매우 느립니다 (약 200 초/삽입). 이유가 확실하지 않습니다.PyMongo ~ 100M 레코드로 느린 데이터베이스를 삽입합니다

익명 사용자 이름 (ints), 익명화 된 메모 ID (ints) 및 댓글의 CSV 파일이 있습니다. 이 모든 것은 문자열로 읽혀 지지만 처음 두 필드는 아무런 문제없이 int로 변환 될 수 있습니다.

데이터베이스에 100M 레코드 모음이 포함되어 있으며 지금은 다른 컬렉션에 쓰여진 메모 ID로 매핑 사용자를 작성하려고합니다. 100,000 개의 댓글이 배포되는 대략 60,000 명의 사용자가 있습니다. 즉, 각 사용자에 대해 user_id = [comment_id0, ..., comment_idN]을 빌드하고 데이터베이스에 삽입하여 모든 사용자 주석을 더 빨리 가져올 수 있습니다.

def save_user_comments(dataset): 
    usrs = defaultdict(list) 
    updatebar = tqdm(total = 100000000, desc = 'Generating user-comment map', leave = False) 
    pool = mp.Pool() 

    for i, (user_id, comment_id, _) in enumerate(dataset): 
     usrs[str(user_id)].append(comment_id) 
     updatebar.update(1) 

    prev = 0 
    keys, vals = list(usrs.keys()), list(usrs.values()) 
    results = pool.map_async(write_user, zip(keys, vals)).get() 

progbar = tqdm(total = 67377, desc = 'Users Inserted', leave = False) 
def write_user(itempair): 
    usr, comments = itempair 

    db = MongoClient(host = some_ip, port = some_port).GenderSpectrum 
    table = db.user 

    if db.user.find_one({'user_id': str(usr)}): 
     progbar.update(1) 
     return 

    u_obj = {} 
    obj = db.data.find_one({'user_id': str(usr)}) 

    u_obj['comment_ids'] = comments 
    u_obj['_id'] = str(usr) 
    u_obj['is_female'] = obj['is_female'] 
    u_obj['user_id'] = str(usr) 
    db.user.insert_one(u_obj) 
    progbar.update(1) 
    return 1 

이 코드에서 느낄 수있는 유일한 점은 각 삽입에 대해 새로운 연결이 생성된다는 것입니다. 그러나 하나의 연결 (단일 및 다중 문서 삽입 모두 사용)을 사용하여 삽입 할 500 개의 문서 배치로 시도한 경우 속도가 더 느립니다. 그래서이 코드를 순차적으로 실행합니다.

누군가가 더 좋은 제안을 갖고 있습니까?

MongoDB를 버전 : v3.4.9

PyMongo 버전 : 3.5.1

파이썬 버전 : 3.5.3

OS : 삽입 자체가 가능성이 매우 빠르고 우분투 17.4

+0

벌크 삽입은 개별적인 작업에 훨씬 많은 오버 헤드가 필요하기 때문에 직렬로 실행되는 많은 'insert_one'보다 느릴 수 있다고 생각합니다. 이는 코드의 느린 부분이 MongoDB 쪽이 아니라 다른 부분에 있음을 의미합니다. 새로운 문서가 생성되는 부분 일 가능성이 있습니다. cProfile을 사용하여 프로파일 링을 시도 했습니까? –

+0

벌크 인서트는 개인에 대해 약 300 초/반복 대 200 초/반복으로 실행되었습니다. 이 중 어느 것도 나에게 의미가 없습니다. 프로파일 링을 시도했지만 의심스러워하지 않았습니다. 인덱스 생성이 도움이되었는지 확인하고 있습니다. – ZeerakW

답변

2

, 루프의 다른 부분이 느릴 가능성이 높습니다.

db.data.find_one({'user_id': str(usr)}) 

는 "데이터"컬렉션 USER_ID에 인덱스를 생성 : "USER_ID"이 인덱싱되지 않은 경우, 다음이 아마 느린 부분이다. 다음과 같이 한 번만 수행하십시오.

db.data.create_index([('user_id', 1)]) 

"find_one"이 훨씬 빠를 것입니다.

또한 각 삽입에 대해 새로운 MongoClient를 만들면 코드가 약간 느려집니다. 프로그램 기간 동안 MongoClient를 한번 작성하십시오 : "write_user"함수의 지역 변수가 아닌 전역 변수로 선언하십시오.

+0

Mongo 문서에는 명시 적으로 글로벌 클라이언트를 생성하지 말고 각 프로세스에 대해 하나씩 명시해야한다고 명시되어 있습니다. 색인 생성은 속도를 높이는 데 효과가있는 것으로 보입니다 (그렇게 할 수 있다는 것을 깨닫지 못했습니다!). 일단 확인한 후에는 색인을 업데이트 할 것입니다. – ZeerakW

+0

색인 만들기가 트릭을 만들었습니다. – ZeerakW

+0

"프로세스 당 하나의 MongoClient"가 정확합니다. 프로세스는 Python 프로그램입니다. "python myscript.py"를 실행할 때 프로세스를 생성합니다. 코드가 보여주는 것은 함수 호출 당 MongoClient를 생성하는 것입니다.이 함수 호출은 있어야하는 것보다 느려질 것입니다.MongoClient를 전역 변수로 생성하여 Python 프로그램의 지속 시간을 지속시키는 것이 좋습니다. –