淺談django的db性能調(diào)優(yōu)
1 環(huán)境準(zhǔn)備
構(gòu)建一個user_demo表
from django.db import models
class UserInfo(models.Model):
# 1. 基礎(chǔ)字段
username = models.CharField(max_length=50, unique=True)
# 給 email 一個默認(rèn)空字符串,或者設(shè)為 null=True,防止遷移報錯
email = models.EmailField(default='')
# 2. 狀態(tài)字段
status = models.SmallIntegerField(default=1, help_text="0:Inactive, 1:Active, 2:Banned")
role = models.CharField(max_length=10, default='member')
# 3. 數(shù)值字段
age = models.PositiveSmallIntegerField(null=True)
balance = models.DecimalField(max_digits=19, decimal_places=4, default=0.0000)
score = models.IntegerField(default=0)
# 4. 時間字段
# 使用 auto_now_add=True 讓 Django 自動處理創(chuàng)建時間
created_at = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(null=True, blank=True)
# 5. 大文本/復(fù)雜字段
bio = models.TextField(null=True, blank=True)
# 6. JSON 字段
extras = models.JSONField(default=dict, null=True, blank=True)
class Meta:
db_table = 'user_demo'
遷移
python manage.py makemigration python manage.py migrate
2 創(chuàng)建調(diào)優(yōu)
使用bulk_create創(chuàng)建1萬條數(shù)據(jù)
import os
import sys
import random
import string
import django
# 1. 設(shè)置 Django 環(huán)境
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
django.setup()
from main.models import UserInfo
def generate_random_string(length=10):
"""生成隨機字符串"""
letters = string.ascii_lowercase
return ''.join(random.choice(letters) for i in range(length))
def create_demo_data(count=100):
print(f"開始生成 {count} 條數(shù)據(jù)...")
users = []
# 預(yù)先定義好 choices,模擬真實數(shù)據(jù)分布
ROLES = ['admin', 'editor', 'member', 'guest']
for i in range(count):
# 確保 username 唯一,這里簡單加上索引 i
username = f"user_{generate_random_string(5)}_{i}"
user = UserInfo(
username=username,
email=f"{username}@example.com",
status=random.choice([0, 1, 1, 1, 2]), # 1 的概率大一些
role=random.choice(ROLES),
age=random.randint(18, 80),
balance=random.uniform(0, 100000),
score=random.randint(0, 500000),
bio=generate_random_string(500),
extras={'preference': random.choice(['light', 'dark']), 'level': random.randint(1, 10)}
)
users.append(user)
# bulk_create 一次性插入,性能更好
UserInfo.objects.bulk_create(users)
print(f"? 成功插入 {len(users)} 條數(shù)據(jù)到 UserInfo 表。")
if __name__ == "__main__":
try:
create_demo_data(1000000)
except Exception as e:
print(f"? 發(fā)生錯誤: {e}")
創(chuàng)建成功
mysql> select count(*) from user_demo; +----------+ | count(*) | +----------+ | 10000 | +----------+ 1 row in set (0.002 sec)
構(gòu)建10萬條失敗,失敗信息為:
開始生成 1000000 條數(shù)據(jù)...
? 發(fā)生錯誤: (2013, 'Lost connection to MySQL server during query')
采取分批插入的方式來解決問題
import os
import sys
import random
import string
import django
# 1. 設(shè)置 Django 環(huán)境
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
django.setup()
from main.models import UserInfo
def generate_random_string(length=10):
"""生成隨機字符串"""
letters = string.ascii_lowercase
return ''.join(random.choice(letters) for i in range(length))
def create_demo_data(count=100):
print(f"開始生成 {count} 條數(shù)據(jù)...")
users = []
BATCH_SIZE = 5000 # 每次插入 5000 條
# 預(yù)先定義好 choices,模擬真實數(shù)據(jù)分布
ROLES = ['admin', 'editor', 'member', 'guest']
batch_data = []
for i in range(count):
# 確保 username 唯一,這里簡單加上索引 i
username = f"user_{generate_random_string(5)}_{i}"
user = UserInfo(
username=username,
email=f"{username}@example.com",
status=random.choice([0, 1, 1, 1, 2]), # 1 的概率大一些
role=random.choice(ROLES),
age=random.randint(18, 80),
balance=random.uniform(0, 100000),
score=random.randint(0, 500000),
bio=generate_random_string(500),
extras={'preference': random.choice(['light', 'dark']), 'level': random.randint(1, 10)}
)
batch_data.append(user)
# 當(dāng)積攢夠了 BATCH_SIZE,就插入一次
if len(batch_data) >= BATCH_SIZE:
UserInfo.objects.bulk_create(batch_data, batch_size=BATCH_SIZE)
print(f"已插入 {i + 1} 條...")
batch_data = [] # 清空列表
# 插入剩余的數(shù)據(jù)(如果有的話)
if batch_data:
UserInfo.objects.bulk_create(batch_data)
print(f"已插入剩余 {len(batch_data)} 條...")
print(f"? 成功插入 {len(users)} 條數(shù)據(jù)到 UserInfo 表。")
if __name__ == "__main__":
try:
create_demo_data(1000000)
except Exception as e:
print(f"? 發(fā)生錯誤: {e}")
3 查找優(yōu)化
這種查找,性能非常操作,因為本質(zhì)上是在做:SELECT * FROM table ...
from main.models import UserInfo users = UserInfo.objects.all() users_usernames = [user.username for user in users]
改成
from main.models import UserInfo
users_usernames = list(UserInfo.objects.values_list('username', flat=True))
到此這篇關(guān)于淺談django的db性能調(diào)優(yōu)的文章就介紹到這了,更多相關(guān)django db性能調(diào)優(yōu)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python數(shù)據(jù)庫操作指南之PyMysql使用詳解
利用jupyter網(wǎng)頁版本進行python函數(shù)查詢方式
vscode搭建之python?Django環(huán)境配置方式
python實現(xiàn)截取屏幕保存文件,刪除N天前截圖的例子
解決jupyter notebook打不開無反應(yīng) 瀏覽器未啟動的問題

