2013-05-15 2 views
3

파이썬 2.7과 SQLite를 사용하고 있습니다. 수백만 행의 데이터베이스를 구축 중입니다. 가끔은 디스크에 쓰고 싶습니다. 아이디어가 있으면 성능이 향상 될 것입니다. 내 생각은 때때로 commit() 만 호출하는 것이었다. 나는 아래의 코드로 그것을 시도했다. 중간에있는 선택은 일관된 읽기를 얻는다는 것을 보여줍니다. 그러나 디스크를 보면 파일 example.db-journal이 표시됩니다. 데이터가 캐시되는 위치 여야합니다. 어떤 경우에 이것은 성능 측면에서 아무 것도 얻지 못할 것입니다. 인서트를 메모리에 모으고 디스크로 플러시 할 수있는 방법이 있습니까? 이 작업을 수행하는 더 좋은 방법이 있습니까?메모리에있는 Python SQLite 캐시

import sqlite3 
conn = sqlite3.connect('example.db') 
c = conn.cursor() 
c.execute('CREATE TABLE if not exists stocks (date text, trans text, symbol text, qty real, price real)') 

c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)") 
c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)") 
t = ('RHAT',) 
c.execute('SELECT date, symbol, trans FROM stocks WHERE symbol=?', t) 
# Here, we get 2 rows as expected. 
print c.fetchall() 
c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)") 
c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)") 
c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)") 
c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)") 
c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)") 

conn.commit() 

t = ('RHAT',) 
c.execute('SELECT date, symbol, trans FROM stocks WHERE symbol=?', t) 
# Here, we get all the rows as expected. 
print c.fetchall() 

conn.close() 

업데이트 : 나는 경우 누구의 일부 코드를 업데이 트를 줄 것이다

체격이 문제에 걸쳐 실행

여기 내 예제 코드입니다. 텍스트 파일에서 5 백만 줄을 처리 중이며 더 많은 처리를 위해 데이터를 저장할 위치가 필요했습니다. 나는 원래 모든 데이터를 메모리에 가지고 있었지만 메모리가 부족했습니다. 그래서 디스크 캐쉬를 위해 SQLite로 전환했습니다. 원래 메모리에 처리 버전은 원래 텍스트 파일에서 50,000 행당 ~ 36 초가 걸렸습니다.

측정이 끝나면 SQLite 버전의 배치 처리에 대한 첫 번째 단절은 5 만 줄에 대해 ~ 660 초가 걸렸습니다. 코멘트 (포스터 덕분에)을 바탕으로, 다음 코드를 내놓았다 :

self.conn = sqlite3.connect('myDB.db', isolation_level='Exclusive') 
self.cursor.execute('PRAGMA synchronous = 0') 
self.cursor.execute('PRAGMA journal_mode = OFF') 

또한, 내 텍스트 파일에서 처리 1000 개 선 후 커밋합니다.

if lineNum % 1000 == 0: 
    self.conn.commit() 

이렇게하면 텍스트 파일의 50,000 줄에 ~ 40 초가 소요됩니다. 그래서 전체 시간에 11 %를 더했지만 메모리는 일정합니다. 이것이 더 중요합니다.

+0

대신 redis와 같은 메모리 저장소를 사용할 수 있습니다. – Pramod

+2

정말 필요한 경우 (측정!), 메모리 내 sqlite DB (": memory :")를 사용하여 해당 내용을 디스크상의 DB로 주기적으로 덤프 할 수 있습니다. –

답변

1

첫째로, 이것이 정말로 필요합니까? 독서를 위해, OS는 파일을 어쨌든 캐시해야하며, 많이 쓰는 경우 디스크에 동기화하지 않으면 쉽게 데이터를 잃을 수 있습니다. 당신이 경우 측정, 다시 http://docs.python.org/2/library/sqlite3.html#sqlite3.Connection.iterdump

import sqlite3, os 

in_memory = sqlite3.connect(':memory:') 
# do stuff 

con = sqlite3.connect('existing_db.db') 
con.execute('drop table stocks') 
for line in in_memory.iterdump(): 
    con.execute(line) 

: 측정하고 병목로서 식별 경우

, 당신은 connect(':memory:')를 사용하여 메모리 데이터베이스를 사용하고 필요에 따라는 SQL 덤프를 반환 반복자를 얻을 수 있습니다 이게 필요해. 중요한 데이터가 충분하다면, 예를 들어 postgres와 같은 완전한 DBMS와 같이 다른 데이터 저장소를 사용하는 것에 대해 열심히 생각하십시오. 귀하의 경우에는

+0

좋습니다. 나는 측정하지 않았다. 캐싱이 당신이 다르게 지적 할 때까지는 옳은 일임이 분명하다. 위에서 작성한 코드는 내가 요청한 것처럼 보이지만 잠재적으로 느려질 수 있습니다 (즉, 메모리 내 데이터 세트를 반복합니다. 어느 쪽이든 다른 의견을 기반으로합니다.) –

+0

재미 있었어요. 내가 데이터를 중요하게 생각한다면 할 수있는 일보다 생각한 실험 ... –

1

, 당신은 때마다 당신이 INSERT 문을 실행한다는 것을 의미 자동 커밋 모드에서 DB 접속을 작성, 데이터베이스, 트랜잭션을 시작하는 문을 실행하고 커밋합니다. 따라서 귀하의 commit은 -이 경우 의미가 없습니다. See sqlite3 on python docs.

하지만 대량의 행을 삽입하는 것이 트랜잭션 내에서 이상적으로 이루어져야합니다. 이것은 연결에 모든 저널문을 저널 파일에 기록해야하지만 트랜잭션이 커밋 될 때까지 데이터베이스 파일에 쓰는 것을 지연 시킨다는 신호입니다. 실행이 I/O 작업으로 제한 되더라도 저널 파일에 기록하는 것은 심각한 성능상의 불이익이 아닙니다.