N+1查询:数据库性能的隐形杀手与终极拯救指南
title: N+1查询:数据库性能的隐形杀手与终极拯救指南


# models.py
from tortoise.models import Model
from tortoise import fields
class Author(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=50)
class Article(Model):
id = fields.IntField(pk=True)
title = fields.CharField(max_length=100)
content = fields.TextField()
author = fields.ForeignKeyField('models.Author', related_name='articles')
async def get_authors_with_articles():
authors = await Author.all()
result = []
for author in authors:
articles = await author.articles.all()
result.append({
"author": author.name,
"articles": [a.title for a in articles]
})
return result
-- 主查询
EXPLAIN
ANALYZE
SELECT "id", "name"
FROM "author";
-- 单个作者的文章查询
EXPLAIN
ANALYZE
SELECT "id", "title", "content"
FROM "article"
WHERE "author_id" = 1;
# main.py
from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise
from pydantic import BaseModel
app = FastAPI()
# Pydantic模型
class ArticleOut(BaseModel):
title: str
class AuthorOut(BaseModel):
id: int
name: str
articles: list[ArticleOut]
class Config:
orm_mode = True
# 数据库配置
DB_CONFIG = {
"connections": {"default": "postgres://user:pass@localhost/blogdb"},
"apps": {
"models": {
"models": ["models"],
"default_connection": "default",
}
}
}
# 路由端点
@app.get("/authors", response_model=list[AuthorOut])
async def get_authors():
authors = await Author.all().prefetch_related("articles")
return [
AuthorOut.from_orm(author)
for author in authors
]
# 初始化ORM
register_tortoise(
app,
config=DB_CONFIG,
generate_schemas=True,
add_exception_handlers=True,
)
EXPLAIN
ANALYZE
SELECT a.id,
a.name,
ar.id,
ar.title,
ar.content
FROM author a
LEFT JOIN article ar ON a.id = ar.author_id;
指标 | 优化前 (N=10) | 优化后 |
---|---|---|
查询次数 | 11 | 2 |
平均响应时间 (ms) | 320 | 45 |
网络往返次数 | 11 | 2 |
内存占用 (KB) | 850 | 650 |
await Author.all().prefetch_related(
"articles__comments", # 文章关联的评论
"profile" # 作者个人资料
)
await Author.all().prefetch_related(
articles=Article.all().only("title", "created_at")
)
from tortoise.functions import Count
async def get_paginated_authors(page: int, size: int):
return await Author.all().prefetch_related("articles")
.offset((page - 1) * size).limit(size)
.annotate(articles_count=Count('articles'))
pip install fastapi uvicorn tortoise-orm[asyncpg] pydantic
uvicorn main:app --reload --port 8000
curl http://localhost:8000/authors
评论
发表评论