zoukankan      html  css  js  c++  java
  • peewee外键性能问题

    # 转载自: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
    
    
  • 相关阅读:
    JQuery -- this 和 $(this) 的区别
    js动态生成表格
    Sublime 3 如何使用列编辑模式
    新版Sublime text3注册码被移除的解决办法
    Sublime text 3 格式化HTML/css/js/json代码 插件
    mingw64 构建 Geos
    C++调用Python浅析
    linux下挂载VHD等虚拟磁盘文件
    linux 下Qt WebEngine 程序打包简单记录
    C++ UTF8和UTF16互转代码
  • 原文地址:https://www.cnblogs.com/lajiao/p/10490986.html
Copyright © 2011-2022 走看看