# 转载自:https://www.cnblogs.com/miaojiyao/articles/5217757.html
下面讨论一下用peewee的些许提高性能的方法。 避免N+1查询 N+1查询指的是当应用提交一次查询获取结果,然后在取得结果数据集的每一行时,应用至少再次查询一次(也可以看做是嵌套循环)。 大多数情况下,n 查询可以通过使用SQL join或子查询来避免。数据库本身可能做了嵌套循环,但是它比在你的应用代码本身里做这些n查询更高效,后者通常会导致与数据库再次潜在通讯,没有利用数据库本身关联和执行子查询时会进行切片等优化工作。 Peewee提供了几种API去减轻N+1查询的行为。再看看贯串我们这篇文档的模型,User和Tweet,这部分我们重点讲一下一些N+1场景,说明peewee怎么帮助我们避免N+1查询。 在一些场景里,N+1查询不会明显表现为显著地或可测量的性能瓶颈点。它也由你要查询的数据,使用的数据库本身,以及执行查询获取结果的潜在因素。优化前后可以测试性能,确保和你预测的变化相同。 raw执行时也会出现这种情况:
### all_res = Results.raw(sql, "2012", "2013","2014", "2015") 列出最近的tweets tweets时间轴显示最近用户的tweets。除了tweet的内容,还要显示tweet作者的用户名。N+1场景描述为: 获取最近的10条tweets
每个tweet,查询作者信息(10次查询)
通过用join选择两个表,peewee使得在一次查询里完成任务: 复制代码
query = (Tweet
.select(Tweet, User) # Note that we are selecting both models.
.join(User) # Use an INNER join because every tweet has an author.
.order_by(Tweet.id.desc()) # Get the most recent tweets.
.limit(10)) for tweet in query:
print tweet.user.username, '-', tweet.message
复制代码
没有用join时,得到tweet.user.username会触发一次查询去解析外键tweet.user从而得到相关联的user。 由于我们在User上关联并选择,peewee自动为我们解析外键。 列出所有用户和他们的tweets 你想要显示若干用户和他们所有的tweets的页面。N+1场景为: 取得些许用户。
每个用户取到他们的tweets。
虽然和上个例子相似,但是重要区别是:我们选择tweets时,每个tweet只有一个关联的用户,所以可以直接赋值到外键, 反过来不对,因为一个用户可有任意数量tweets或者没有。 Peewee提供两两种途径去避免O(n)查询: 1.首先取到用户,然后取到关联这些用户的所有tweets。一旦peewee取到tweets,将它们与合适的用户匹配。 这种方法通常很快,但是会在所选择的每个表上执行一次查询。 2.在一个查询里得到用户和tweets。用户数据将复制,所以peewee将在列举结果集时减少重复和聚合tweets。 这种方法导致有许多数据需要传输,并且要有许多python逻辑去减少行重复。 每种方案根据查询数据的大小和结构都会可能比另一种更好。 使用prefetch peewee使用子查询可以预获取数据。这种方法需要prefetch特殊API使用。Pre-fetch,像其名字本身, 用子查询去急切加载给定用户的相应的tweets。意味着我们用O(k)查询K张表而不是O(n)查询n行纪录。 下面演示我们如何得到若干用户和他们最近一周的tweets: 复制代码
week_ago = datetime.date.today() - datetime.timedelta(days=7)
users = User.select()
tweets = (Tweet
.select()
.where(
(Tweet.is_published == True) &
(Tweet.created_date >= week_ago))) # This will perform two queries.
users_with_tweets = prefetch(users, tweets) for user in users_with_tweets:
print user.username
for tweet in user.tweets_prefetch:
print ' ', tweet.message
复制代码
注意User 查询和Tweet查询都没有JOIN子句,当我们使用prefetch时不必指名join prefetch可以用于任意数量的表。可以查看API文档看其他例子。 用prefetch时应考虑的事情: 预查询的模型必须存在外键
通常它比aggregate_rows方法更高效
因为数据没有重复的所以传输的数据更少
因为不用减重复所以python逻辑更少
当你想要在最外的查询里使用LIMIT没问题,但是可能正确的实现限制子查询的返回结果大小有些困难。
使用aggregate_rows aggregeate_rows一次在内存中减少重复,选择所有的数据。它和prefetch都可以完成任意复杂的查询。 使用这个特性需要当创建查询时用到特殊的标志aggregate_rows。它告诉peewee减少那些根据JOIN的结构可能会重复的行。 因为在减少重复聚合数据时有许多计算,所以可能使用aggregate_rows可能在一些查询中会比用prefetch性能低,即使面对的是 O(n)简单的 查询时,所以你不确定使用哪种方法时测试检查你的代码。 复制代码
query = (User
.select(User, Tweet) # As in the previous example, we select both tables.
.join(Tweet, JOIN.LEFT_OUTER)
.order_by(User.username) # We need to specify an ordering here.
.aggregate_rows()) # Tell peewee to de-dupe and aggregate results. for user in query:
print user.username
for tweet in user.tweets:
print ' ', tweet.message
复制代码
复制代码
query = (User
.select(User, Tweet) # As in the previous example, we select both tables.
.join(Tweet, JOIN.LEFT_OUTER)
.order_by(User.username) # We need to specify an ordering here.
.aggregate_rows()) # Tell peewee to de-dupe and aggregate results. for user in query:
print user.username
for tweet in user.tweets:
print ' ', tweet.message

peewee外键性能问题的更多相关文章

  1. 通过在Oracle子表外键上建立索引提高性能

    根据我的经验,导致死锁的头号原因是外键未加索引(第二号原因是表上的位图索引遭到并发更新).在以下两种情况下,Oracle在修改父表后会对子表加一个全表锁: 1)如果更新了父表的主键(倘若遵循关系数据库 ...

  2. MS SQL巡检系列——检查外键字段是否缺少索引

    前言感想:一时兴起,突然想写一个关于MS SQL的巡检系列方面的文章,因为我觉得这方面的知识分享是有价值,也是非常有意义的.一方面,很多经验不足的人,对于巡检有点茫然,不知道要从哪些方面巡检,另外一方 ...

  3. 使用Guid做主键和int做主键性能比较

    使用Guid做主键和int做主键性能比较 在数据库的设计中我们常常用Guid或int来做主键,根据所学的知识一直感觉int做主键效率要高,但没有做仔细的测试无法 说明道理.碰巧今天在数据库的优化过程中 ...

  4. MySQL外键之级联

    简介 MySQL外键起到约束作用,在数据库层面保证数据的完整性.例如使用外键的CASCADE类型,当子表(例如user_info)关联父表(例如user)时,父表更新或删除时,子表会更新或删除记录,这 ...

  5. MySQL 外键

    在MySQL中 (1)MySQL 数据表主要支持六种类型 ,分别是:BDB.HEAP.ISAM.MERGE.MYISAM.InnoBDB.这六种又分为两类,一类是”事务安全型”(transaction ...

  6. EntityFramework 外键值映射

    如果在 EF OnModelCreating 中配置了实体外键映射,也就是 SQL Server 中的 ForeignKey,那么我们在添加实体的时候,主实体的主键值会自动映射到子实体的外键值,并且这 ...

  7. 注解:【基于外键的】Hibernate双向1->1关联

    Person与Address关联:双向1->1,[基于外键的]. #主表不应该控制关联关系.(否则会导致生成额外的update语句,从而导致性能下降), #因此主表对应的实体中使用@OneToO ...

  8. MySQL的几个概念:主键,外键,索引,唯一索引

    概念: 主键(primary key) 能够唯一标识表中某一行的属性或属性组.一个表只能有一个主键,但可以有多个候选索引.主键常常与外键构成参照完整性约束,防止出现数据不一致.主键可以保证记录的唯一和 ...

  9. 基于MVC4+EasyUI的Web开发框架经验总结(9)--在Datagrid里面实现外键字段的转义操作

    我们在使用EasyUI的时候,很多情况下需要使用到表格控件datagrid,这个控件控件非常强大,使用起来很简洁,但是我在使用中,发现对于一个表里面的外键字段进行转义,并显示引用表的一些名称的操作,却 ...

随机推荐

  1. jquery计算器(改良版)

    代码: <!Doctype html> <html> <meta charset="UTF-8"> <title>计算器</t ...

  2. netem设置了网卡的流量控制,为啥发包的延迟就搞不定呢?

    为啥我用netem做了一个流量的控制 但是发送的时候,感觉真正发送数据的时候还是没有达到每一个数据包都是1s的延迟呀,这里的1s的延迟是啥意思啊? 这里的delay并不是说每个数据包都delay 5s ...

  3. Error:Unable to tunnel through proxy. Proxy returns "HTTP/1.1 400 Bad Request"

    (1) 网上下载了一个android应用:死活用不了,查了以下,原来是android studio版本不对,于是把android studio的版本从2.2 升级到3.0,后来发现没法升级,只能下载, ...

  4. EL中定义函数

    1.在java类中要定义一个static函数 2配置:在WEB-INF/*.tld的配置文件 3在JSP页面上 4使用

  5. C语言指针【转】

    一.C语言指针的概念 在计算机中,所有的数据都是存放在存储器中的.一般把存储器中的一个字节称为一个内存单元,不同的数据类型所占用的内存单元数不等,如整型量占2个单元,字符量占1个单元等,在前面已有详细 ...

  6. IOI 98 (POJ 1179)Polygon(区间DP)

    很容易想到枚举第一步切掉的边,然后再计算能够产生的最大值. 联想到区间DP,令dp[i][l][r]为第一步切掉第i条边后从第i个顶点起区间[l,r]能够生成的最大值是多少. 但是状态不好转移,因为操 ...

  7. poj 1273 && hdu 1532 Drainage Ditches (网络最大流)

    Drainage Ditches Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 53640   Accepted: 2044 ...

  8. 【刷题】BZOJ 3510 首都

    Description 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打败了B国,那么B国将永远从 ...

  9. [洛谷P3833][SHOI2012]魔法树

    题目大意:给一棵树,路径加,子树求和 题解:树剖 卡点:无 C++ Code: #include <cstdio> #include <iostream> #define ma ...

  10. 【hackerrank】Week of Code 30

    Candy Replenishing Robot Find the Minimum Number 直接模拟 Melodious password dfs输出方案 Poles 题意:有多个仓库,只能从后 ...