하얀설표 블로그




파이썬 왜 sqlite3를 사용하는지 이유를 알아보자.(why use sqlite with python)





( 수정됨)


코드

from time import time
import sqlite3
from decimal import Decimal
path = '{white.seolpyo.com}.db'
table = '{하얀설표 블로그}'
sq = sqlite3.connect(':memory:')
with sqlite3.connect(path) as db:
    db.backup(sq)
c = sq.cursor()
d = {}
t = time()
for i in c.execute(f'select * from {table}').fetchall():
    d[종목코드] = {
        '종목코드': 종목코드,
        '종목명': 종목명,
        '시가': 시가,
        '고가': 고가,
        '저가': 저가,
        '종가': 종가,
        '거래량': Decimal(거래량),
    }
print(time() - t)
# for k, v in d.items():
#     print(k, v)
print(f'{len(d)=}')
print(f"{d['005930']=}")
deci = Decimal('1000')
def aa():
    t = time()
    [k for k, v in d.items() if v['거래량'] > deci]
    print(time() - t)
def bb():
    t = time()
    c.execute(f'select 종목코드 from {table} where cast(거래량 as decimal) > 1000').fetchall()
    print(time() - t)
def cc():
    t = time()
    sorted([k for k, v in d.items() if v['거래량'] > deci], key=lambda x: d[x]['거래량'])
    print(time() - t)
def dd():
    t = time()
    c.execute(f'select 종목코드 from {table} where cast(거래량 as decimal) > 1000 order by cast(거래량 as decimal)').fetchall()
    print(time() - t)
def aa2():
    t = time()
    [k for k, v in d.items() if Decimal(v['종가']) > deci]
    print(time() - t)
def bb2():
    t = time()
    c.execute(f'select 종목코드 from {table} where cast(종가 as decimal) > 1000').fetchall()
    print(time() - t)
def cc2():
    t = time()
    sorted([k for k, v in d.items() if Decimal(v['종가']) > deci], key=lambda x: d[x]['거래량'])
    print(time() - t)
def dd2():
    t = time()
    c.execute(f'select 종목코드 from {table} where cast(종가 as decimal) > 1000 order by cast(거래량 as decimal)').fetchall()
    print(time() - t)
def aa3():
    t = time()
    list(filter(lambda x: d[x]['거래량'] > deci, d))
    print(time() - t)
def bb3():
    t = time()
    c.execute(f'select 종목코드 from {table} where cast(종가 as decimal) > 1000').fetchall()
    print(time() - t)
def cc3():
    t = time()
    sorted(list(filter(lambda x: d[x]['거래량'] > deci, d)), key=lambda x: d[x]['거래량'])
    print(time() - t)
def dd3():
    t = time()
    c.execute(f'select 종목코드 from {table} where cast(종가 as decimal) > 1000 order by cast(거래량 as decimal)').fetchall()
    print(time() - t)
def aaa():
    t = time()
    [k for k, v in d.items() if v['거래량'] > deci and Decimal(v['종가']) > deci]
    print(time() - t)
def bbb():
    t = time()
    c.execute(f'select 종목코드 from {table} where cast(거래량 as decimal) > 1000 and cast(종가 as decimal) > 1000').fetchall()
    print(time() - t)
def ccc():
    t = time()
    sorted([k for k, v in d.items() if v['거래량'] > deci and Decimal(v['종가']) > deci], key=lambda x: d[x]['거래량'])
    print(time() - t)
def ddd():
    t = time()
    c.execute(f'select 종목코드 from {table} where cast(거래량 as decimal) > 1000 and cast(종가 as decimal) > 1000 order by cast(거래량 as decimal)').fetchall()
    print(time() - t)
for i in [aa, bb, cc, dd,
        aa2, bb2, cc2, dd2,
        aa3, bb3, cc3, dd3,
        aaa, bbb, ccc, ddd]:
    print(i, end=' / ')
    i()

결과

0.033998966217041016
len(d)=2784
d['005930']={'종목코드': '005930', '종목명': '삼성전자', '시가': '73000', '고가': '74100', '저가': '72800', '종가': '73100', '거래량': Decimal('13038939')}

<function aa at 0x00000198FCFCCF40> / 0.0
<function bb at 0x00000198FCFCD120> / 0.0029993057250976562
<function cc at 0x00000198FCFCCFE0> / 0.002000093460083008
<function dd at 0x00000198FCFCD1C0> / 0.003998994827270508

<function aa2 at 0x00000198FCFCD260> / 0.0029993057250976562
<function bb2 at 0x00000198FCFCD080> / 0.002000093460083008
<function cc2 at 0x00000198FCFCE5C0> / 0.0039997100830078125
<function dd2 at 0x00000198FCF58B80> / 0.003000020980834961

<function aa3 at 0x00000198FCFC77E0> / 0.0010001659393310547
<function bb3 at 0x00000198FCFC47C0> / 0.004000186920166016
<function cc3 at 0x00000198FCFC4C20> / 0.002000093460083008
<function dd3 at 0x00000198FCF6CB80> / 0.0029990673065185547

<function aaa at 0x00000198FCF6DB20> / 0.002000093460083008
<function bbb at 0x00000198FCF6DBC0> / 0.0019996166229248047
<function ccc at 0x00000198FCF6FF60> / 0.002000093460083008
<function ddd at 0x00000198FCF6E020> / 0.0019996166229248047

결론

단순 데이터 조회는 그냥 파이썬에서 해결하는게 더 빠를 수 있지만, 복합적인 조건을 적용하는 경우 sqlite를 사용하는게 더 빠르다.

설명

예제 코드는 정말 단순한 코드다. 각 함수별로 특정 작업을 하고, 경과 시간을 출력한다.
aa~dd는 decimal 객체를 기준으로 비교하며, aa2~dd2은 str 요소를 decimal 객체로 변환한 다음 비교한다.
aa3~dd3는 비교자(>, <, =)가 아닌 filter 함수를 사용하고, aaa~ddd는 2개의 요소를 비교한다.

작성한 코드들은 대충 다음과 같은 공통점을 갖는다.
aa => 단순 비교(list), bb => 단순 비교(sqlite), cc => 단순 비교 + 정렬(list), dd => 단순 비교 + 정렬(sqlite)

사용한 데이터는 개인적으로 가져온 주가 데이터로, 대충 종목코드, 종목명, 시가, 저가, 고가, 종가, 거래량 데이터가 있다.
데이터의 수는 코드와 결과에서 볼 수 있듯이 3천개가 약간 안된다.

다음은 각 조건별 결과를 초보자의 입장에서 대충 정리만 해둔 것이다.

aa~dd

dict의 요소를 decimal로 변환한 상태에서 비교하는 것은 sqlite를 사용하는게 더 느렸다.
파이써닉([i for i in list])한 코드를 사용하는 것은 그냥 for 루프를 사용하는 것과 큰 차이가 없다고 생각했었는데, 작업 시간이 0초가 나와서 살짝 놀랐다.

aa2~dd2

dict의  str 요소를 decimal로 변환해가며 비교하는 것은 sqlite가 미묘하게 더 빨랐다

aa3~dd3

이미 변환된 데이터를 비교하는 것은 sqlite가 더 빨랐다.
다만, filter를 사용하는 것이 그냥 루프를 돌려서 비교하는 것보다는 느렸다.

aaa~ddd

비교자를 2개 넣었다. LIST에서는 decimal로 변환된 것과 str을, sqlite에서는 2개 요소를 모두 decimal로 변환해서 비교했다.
이 작업은 sqlite가 더 빨랐는데, 흥미로운 점은 1개의 요소만 비교했을 때보다 작업이 더 빨라졌다는 것이다.



공감 : 0







white.seolpyo.com