728x90
반응형
지난 번에 로또번호 엑셀로 받아왔잖아요.
그거 근데 너무 빠르게 읽어오길래 놀라가지고 DB 넣는데 얼마나 걸리는지좀 봐보려고요
# forms.py
from django import forms
from .models import ExcelFile
class ExcelFileForm(forms.ModelForm):
class Meta:
model = ExcelFile
fields = ['file']
일단 엑셀 받을 폼이고요
from django.db import models
class ExcelFile(models.Model):
file = models.FileField(upload_to='excel_files/')
class Meta:
db_table = 'lotto'
class Lotto(models.Model):
uploaded_at = models.DateTimeField(auto_now_add=True)
lotto_id = models.IntegerField(null=True) # 각 로또의 ID
number_one = models.IntegerField() # 첫 번째 번호
number_two = models.IntegerField() # 두 번째 번호
number_three = models.IntegerField() # 세 번째 번호
number_four = models.IntegerField() # 네 번째 번호
number_five = models.IntegerField() # 다섯 번째 번호
number_six = models.IntegerField() # 여섯 번째 번호
def __str__(self):
return str(self.lotto_id)
class Meta:
db_table = 'lottodata'
이것은 스프링으로 치면 객체 만드는 것으로 이해를 했습니다.
아 디장고는 처음에 db가 sqlite3 입니다.
이거를 mariadb로 바꿔주셔야 해요
setting.py 에서요
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # MySQL 사용
'NAME': '', # 데이터베이스 이름
'USER': '', # 데이터베이스 사용자
'PASSWORD': '', # 데이터베이스 비밀번호
'HOST': 'localhost', # 데이터베이스 호스트 (로컬이면 'localhost')
'PORT': '3306', # MySQL 기본 포트
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"
},
}
}

참고로 로또 엑셀 데이터가 이렇게 되어있어요
num은 회차입니다. 보너스 번호는 뺐어요
방법 1. objects.bulk_create 방식
from django.shortcuts import render, redirect
import pandas as pd
import time
from .forms import ExcelFileForm
from .models import Lotto
from django.db import transaction
def upload_excel(request):
if request.method == 'POST':
form = ExcelFileForm(request.POST, request.FILES)
if form.is_valid():
# 엑셀 파일 읽기
excel = pd.read_excel(request.FILES['file'])
print(excel.head())
# 각 행을 모델 인스턴스로 변환
start_time = time.time() * 1000 # 밀리세컨드 단위
records = [
Lotto(
lotto_id=row['num'],
number_one=row['one'],
number_two=row['two'],
number_three=row['three'],
number_four=row['four'],
number_five=row['five'],
number_six=row['six']
)
for index, row in excel.iterrows()
]
Lotto.objects.bulk_create(records) # 데이터를 한 번에 삽입
total_records = Lotto.objects.count()
print(f"total count: {total_records}")
end_time = time.time() * 1000
time_taken = end_time - start_time
print(f"Time taken: {time_taken} milliseconds")
return render(request, 'upload_excel.html', {'form': form, 'data': excel.to_html()})
else:
form = ExcelFileForm()
return render(request, 'upload_excel.html', {'form': form})
- 성능 향상: 여러 데이터를 개별적으로 삽입하는 것보다 한 번에 삽입하면 데이터베이스와의 통신 횟수가 줄어들어 성능이 크게 향상. 특히 대량의 데이터를 삽입할 때 효과적.
- 트랜잭션 관리: bulk_create 메소드는 기본적으로 하나의 트랜잭션 내에서 모든 삽입 작업을 처리하므로, 삽입 도중 오류가 발생할 경우 모든 변경 사항을 롤백할 수 있어 데이터 일관성이 유지.
- 코드 가독성: 여러 개의 개별 삽입 문을 작성하는 것보다 코드가 간결하고 가독성이 높아짐.
- 오버헤드 감소: 각 개별 삽입마다 발생하는 오버헤드를 줄여주기 때문에 전체적인 효율성이 증가

대충 이정도 나와요 1000개 에 90ms ~ 150ms 정도 나오는것 같네요
그 다음은 원초적인 방법이 for문으로 집어넣어볼게요
from django.shortcuts import render
import pandas as pd
import time
from .forms import ExcelFileForm
from .models import Lotto
def upload_excel(request):
if request.method == 'POST':
form = ExcelFileForm(request.POST, request.FILES)
if form.is_valid():
# 엑셀 파일 읽기
excel = pd.read_excel(request.FILES['file'])
# 각 행을 모델 인스턴스로 변환하여 한 줄씩 DB에 저장
start_time = time.time() * 1000 # 밀리세컨드 단위
# 한 줄씩 저장
for index, row in excel.iterrows():
# Lotto 모델 인스턴스 생성
lotto = Lotto(
lotto_id=row['num'],
number_one=row['one'],
number_two=row['two'],
number_three=row['three'],
number_four=row['four'],
number_five=row['five'],
number_six=row['six']
)
# DB에 저장
lotto.save()
total_records = Lotto.objects.count()
print(f"total count: {total_records}")
end_time = time.time() * 1000
time_taken = end_time - start_time
print(f"Time taken: {time_taken} milliseconds")
return render(request, 'upload_excel.html', {'form': form, 'data': excel.to_html()})
else:
form = ExcelFileForm()
return render(request, 'upload_excel.html', {'form': form})
한 줄씩 읽어와서 DB에 저장하는 식이에요
이렇게 되면

1000개당 360 ~ 620 정도 나옵니다. 상당히 느려요
하지만 빠르다고 좋은게 아니지요
bulkcreate 는 유효성 검사를 수행하지 않고, pre_save, post_save 등의 후크롤 호출하지 않아 저장 전후 자동작업을 할 수 없습니다.
소규모 에선 save()
대규모에서는 bulk_create() 를 선호한다.
반응형
댓글