2012-03-14 2 views
2

필자는 약 1.7m 라인의 스프레드 시트를 가지고 있으며 총 1GB이며 다양한 쿼리를 수행해야합니다. 파이썬에 가장 익숙한 첫 번째 방법은 내가 작성하려고했던 쿼리를 쉽게 수행 할 수있는 방법으로 입력 된 사전들을 함께 해킹하는 것이 었습니다. 예 : 특정 지역 번호와 나이를 가진 모든 사람들에게 접근 할 수 있어야한다면, 나는 areacode_age 2 차원 사전을 만들 것입니다. 나는 이들 중 상당수가 필요하게되어 결국 메모리 용량 (10GB 정도)이 늘어 났으며,이를 지원할만큼 충분한 RAM이 있더라도 프로세스는 여전히 느려졌다.합리적인 시간에 파이썬에서 (매우) 큰 관계형 데이터를 쿼리하고 있습니까?

이 시점에서, 나는 빨판 게임을하고있는 것처럼 보였습니다. "글쎄요, 관계형 데이터베이스가 만들어 졌죠?"라고 생각했습니다. sqlite3을 가져 와서 내 데이터를 메모리 데이터베이스로 가져 왔습니다. 나는 데이터베이스가 속도를 위해 만들어졌으며 이것이 내 문제를 해결할 것이라고 추측한다.

"SELECT (a, b, c) FROM foo WHERE date1 < = d AND date2> e AND name = f"와 같은 쿼리를 수행하는 데는 0.05 초가 걸립니다. 내 1.7m 행에 대해이 작업을 수행하려면 24 시간의 계산 시간이 필요합니다. 사전을 사용한 나의 해킹 접근법은이 특정 작업에 대해 약 3 배 더 빨랐습니다. (이 예에서는 date1과 date2를 입력 할 수 없었으므로 이름이 일치하고 날짜별로 필터링하는 모든 행을 얻었습니다.)

내 질문은 왜 이렇게 느린 지, 어떻게 빨리 만들 수 있습니까? Pythonic 접근 방식은 무엇입니까? 가능성은 내가 생각해 왔던 :

  • sqlite3를 너무 느리게, 나는 어떻게 든 최적화 ... 내 스키마 또는 내 쿼리가 더로 변경해야
  • 더 헤비급 뭔가가 필요?
  • 나는 지금까지 시도한 접근법이 완전히 잘못되어 어떤 새로운 도구가 필요하다.
  • sqlite 3에서 cursor.execute를 반복적으로 호출하면 커서를 사용하는 것보다 훨씬 느리다. 경영진. executemany는 select 문과도 호환되지 않는다는 것이 드러났습니다. 그래서 이것은 빨간 청어라고 생각합니다.

감사합니다.

+1

170 만 개의 행이 있기 때문에 170 만 번 쿼리해야한다고 말하고 있습니까? – gahooa

+0

간단한 숫자 쿼리 만 수행하고 조인 등이 필요하지 않은 경우 'pytables'를보십시오. http://www.pytables.org/moin –

답변

4

sqlite3를 너무 느립니다, 나는

첫째, sqlite3를 언젠가 빠른 MySQL을보다 더 빠르고, 더 헤비급 뭔가가 필요

둘째, 당신은 화합물을 넣어 인덱스를 사용해야합니다 (date1, date2, name)의 색인을 사용하면 작업 속도가 상당히 빨라집니다.

+0

감사합니다. 그냥 분명히하기 위해, 나는 "sqlite3은 느리다"는 사실을 진술하지 않았습니다. 그것은 내가 생각하고있는 가설적인 시나리오 중 하나 일뿐입니다. – Coquelicot

+0

업데이트 : 제안한 색인을 추가했으며 검색어 당 시간이 ~0.05에서 ~0003으로 변경되었습니다. 꽤 좋아요! 다시 한번 감사드립니다. – Coquelicot

2

그것은 같은 쿼리하고 있다고하지만 밝혀 "선택 (A, B, C) DATE1 < = D 및 날짜 2> E AND NAME = f는 foo를 FROM"0.05 초가 걸린다. 내 1.7m 행에 대해 을 수행하면 24 시간의 계산 시간이 소요됩니다. 내 해킹 사전을 사용하는 접근 방식은 특정 작업 (이 예에서는 날짜 1 과 date2를 분명히 입력 할 수 없었으므로 이름이 일치하는 모든 행을 가져오고 있었고 필터링 날짜 별).

실제로을 시도했는데 24 시간이 걸렸습니까? 처리 시간은 반드시 데이터 크기에 직접 비례하지는 않습니다.

그리고 SELECT (a, b, c) FROM foo WHERE date1<=d AND date2>e AND name=f 번을 170 만 회 실행해야한다고 제안 하시겠습니까? 한 번만 실행하면 쿼리와 일치하는 행의 전체 하위 집합이 반환됩니다.

170 만 개의 행은 작지는 않지만 로컬 컴퓨터의 메모리에있는 데이터베이스의 경우 전혀 문제가되지 않습니다. (느린 디스크 액세스가없고 네트워크 액세스가 느려지지 않습니다.)


증거가 푸딩에있다. 이것은 (대부분의 시간 ~ 1 개 천만 임의 수레를 생성에 소요됩니다.) 나를 위해 꽤 빠른

import sqlite3, random 

conn = sqlite3.connect(":memory:") 
conn.execute("CREATE TABLE numbers (a FLOAT, b FLOAT, c FLOAT, d FLOAT, e FLOAT, f FLOAT)"); 
for _ in xrange(1700000): 
    data = [ random.random() for _ in xrange(6) ]; 
    conn.execute("INSERT INTO numbers VALUES (?,?,?,?,?,?)", data) 

conn.commit() 

print "done generating random numbers" 

results = conn.execute("SELECT * FROM numbers WHERE a > 0.5 AND b < 0.5") 
accumulator = 0 
for row in results: 
    accumulator += row[0] 

print ("Sum of column `a` where a > 0.5 and b < 0.5 is %f" % accumulator) 

편집 : 당신이 정말로이 170 만 번 실행해야합니까 좋아, 그래서.

이 경우 아마도 색인이 필요합니다. 위키 백과를 인용 : 데이터베이스 인덱스 :

데이터베이스 인덱스 이 증가 저장 공간을 기록 느린의 비용으로 데이터베이스 테이블에 데이터 검색 작업의 속도를 향상시키는 데이터 구조입니다. 데이터베이스 테이블의 하나 이상의 열을 사용하여 인덱스를 생성 할 수 있으며, 빠른 무작위 검색 및 주문 된 레코드에 대한 효율적인 액세스를 모두 제공합니다.

CREATE INDEX dates_and_name ON foo(date1,date2,name)과 같은 작업을 수행 한 다음 평소대로 나머지 SELECT 문을 실행합니다. 이것을 시도하고 속도가 빨라지는지 확인하십시오.

+0

예, 170 만 회 실행해야하는 쿼리입니다. d, e 및 f의 다른 값에 대해 시간을 계산합니다. (집계 변수를 계산하려면 각 행에 대해 한 번 실행해야합니다.) 나는 그것을 전체 시간 동안 실행 시키려고하지 않았지만 처음 천 번 정도의 쿼리는 각각 0.05를 취하고 있었고 나중에 변경 될 이유는 알지 못했습니다. – Coquelicot

+0

좋아. 데이터베이스 인덱스가 필요하다고 생각합니다. 편집 된 답변을 확인하십시오. –

+0

SQL에서 집계 변수의 계산을 수행 할 수도 있습니다. 예를 들어'SELECT SUM (population) FROM countries where hemisphere = "North"는 북반구의 인구를 계산합니다. –

0

당신은 이미 가장 쉬운 방법이 될 것입니다 SQL을 이야기하고 있기 때문에 :

  1. 는 MySQL의 테이블에 모든 데이터를 넣습니다. 1.7 백만 행에 대해 잘 수행됩니다.
  2. 필요한 인덱스를 추가하고 설정을 확인한 후 run fast on big table인지 확인하십시오.
  3. 파이썬에서 액세스
  4. ...
  5. 이익!
관련 문제