Django脚本对接MySQL时ORM调用first()查询耗时过长问题咨询
Django对接MySQL查询卡顿问题排查解决方案
1. 优先检查数据库索引配置
这是本地SQLite正常、MySQL卡顿最常见的原因:SQLite数据量小、本地IO速度快,全表扫描也不会有明显感知,但MySQL数据量上来后全表扫描耗时会指数级上升。
你的查询基于ticker和date两个字段过滤,需要给这两个字段加联合索引才能命中快速查询:
- 检查
Stock_Csv模型的索引配置,参考示例:
class Stock_Csv(models.Model): ticker = models.CharField(max_length=32) date = models.DateField() # 其他业务字段 class Meta: # 优先加联合索引,匹配你的查询逻辑 indexes = [ models.Index(fields=['ticker', 'date']), ] # 如果ticker+date的组合是全局唯一的,直接加联合唯一约束,查询效率更高 # unique_together = ['ticker', 'date']
- 配置完成后执行
python manage.py makemigrations、python manage.py migrate同步索引到MySQL。 - 验证索引是否生效:打印查询对应的SQL语句(在
first()调用前加print(filtered_by_date.query)),登录MySQL执行EXPLAIN 你打印出的SQL语句,查看返回结果的key列是否显示你创建的联合索引,type列是否为ref及以上级别。
2. 优化查询逻辑减少数据库交互次数
你当前的写法是每次CSV行处理都发起一次独立查询,CSV行数多的话,多次请求的网络开销叠加后耗时会非常高,尤其是应用和MySQL不在同一台服务器的场景。
推荐优化方案:
- 预查询批量缓存:提前把CSV中所有涉及的
ticker和date收集起来,一次性查出所有符合条件的对象缓存到字典,循环时直接从本地字典取值:
# 第一步:提前收集CSV中所有的ticker和日期组合 ticker_date_set = set() csv_data = [] for row in your_csv_reader: name = row['ticker'] date_obj = parse_your_date(row['date']) ticker_date_set.add((name, date_obj)) csv_data.append((name, date_obj, row)) # 第二步:一次性查询所有需要的对象,存入字典缓存 tickers = [item[0] for item in ticker_date_set] dates = [item[1] for item in ticker_date_set] all_exist_objs = Stock_Csv.objects.filter(ticker__in=tickers, date__in=dates) obj_cache = {(obj.ticker, obj.date): obj for obj in all_exist_objs} # 第三步:遍历处理CSV行,直接从缓存取对象 for name, date_object, row in csv_data: current_obj = obj_cache.get((name, date_object)) # 后续业务处理逻辑
- 如果你的逻辑是存在则更新、不存在则创建,直接调用Django内置的
update_or_create方法,比手动查询再判断的效率更高:
current_obj, created = Stock_Csv.objects.update_or_create( ticker=name, date=date_object, defaults={ # 填入需要更新的字段键值对 } )
- 开启事务批量提交:把整个CSV的处理逻辑包裹在事务上下文里,避免每次写操作自动提交事务的开销:
from django.db import transaction with transaction.atomic(): # 所有CSV处理逻辑放在这个代码块内
3. 排查环境层面问题
如果上述优化完成后仍有卡顿,排查基础设施问题:
- 测试应用服务器到MySQL服务器的网络延迟,确认是否存在丢包、带宽不足的问题。
- 检查MySQL配置:
innodb_buffer_pool_size建议设置为服务器可用内存的50%~70%,太小会导致查询频繁读磁盘,性能骤降。 - 开启MySQL慢查询日志,确认卡顿是否由锁等待导致:如果慢日志中对应查询的
Lock_time远高于Query_time,需要排查是否有其他大事务占用锁资源。
内容的提问来源于stack exchange,提问作者ali.zabetpour
相关产品推荐
相关产品推荐

