加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

postgresql – OFFSET与ROW_NUMBER()

发布时间:2020-12-13 16:43:32 所属栏目:百科 来源:网络整理
导读:我们知道,Postgresql的OFFSET要求它扫描所有的行,直到它到达你请求的位置,这使得它对于通过巨大的结果集的分页是无用的,随着OFFSET的增加越来越慢。 PG 8.4现在支持窗口功能。代替: SELECT * FROM table ORDER BY somecol LIMIT 10 OFFSET 500 你可以说
我们知道,Postgresql的OFFSET要求它扫描所有的行,直到它到达你请求的位置,这使得它对于通过巨大的结果集的分页是无用的,随着OFFSET的增加越来越慢。

PG 8.4现在支持窗口功能。代替:

SELECT * FROM table ORDER BY somecol LIMIT 10 OFFSET 500

你可以说:

SELECT * FROM (SELECT *,ROW_NUMBER() OVER (ORDER BY somecol ASC) AS rownum FROM table) AS foo
WHERE rownum > 500 AND rownum <= 510

后一种方法能帮助我们吗?或者我们必须继续使用标识列和临时表来进行大分页吗?

我构造了一个测试,它比较OFFSET,光标和ROW_NUMBER()。我对ROW_NUMBER()的印象是,无论您在结果集中的位置如何,它的速度都是一致的,是正确的。但是,这个速度比OFFSET或CURSOR的速度要慢得多,这也是我的印象,速度几乎是相同的,速度越慢,结果就越差。

结果:

offset(100,100): 0.016359
scroll(100,100): 0.018393
rownum(100,100): 15.535614

offset(100,480000): 1.761800
scroll(100,480000): 1.781913
rownum(100,480000): 15.158601

offset(100,999900): 3.670898
scroll(100,999900): 3.664517
rownum(100,999900): 14.581068

测试脚本使用sqlalchemy设置表和1000000行测试数据。然后,它使用psycopg2游标执行每个SELECT语句并使用三种不同的方法获取结果。

from sqlalchemy import *

metadata = MetaData()
engine = create_engine('postgresql://scott:tiger@localhost/test',echo=True)

t1 = Table('t1',metadata,Column('id',Integer,primary_key=True),Column('d1',String(50)),Column('d2',Column('d3',Column('d4',Column('d5',String(50))
)

if not engine.has_table('t1'):
    conn = engine.connect()
    t1.create(conn)

    # 1000000 rows
    for i in range(100):
        conn.execute(t1.insert(),[
            dict(
                ('d%d' % col,"data data data %d %d" % (col,(i * 10000) + j))
                for col in range(1,6)
            ) for j in xrange(1,10001)
        ])

import time

def timeit(fn,count,*args):
    now = time.time()
    for i in xrange(count):
        fn(*args)
    total = time.time() - now
    print "%s(%s): %f" % (fn.__name__,",".join(repr(x) for x in args),total)

# this is a raw psycopg2 connection.
conn = engine.raw_connection()

def offset(limit,offset):
    cursor = conn.cursor()
    cursor.execute("select * from t1 order by id limit %d offset %d" % (limit,offset))
    cursor.fetchall()
    cursor.close()

def rownum(limit,offset):
    cursor = conn.cursor()
    cursor.execute("select * from (select *,"
                    "row_number() over (order by id asc) as rownum from t1) as foo "
                    "where rownum>=%d and rownum<%d" % (offset,limit + offset))
    cursor.fetchall()
    cursor.close()

def scroll(limit,offset):
    cursor = conn.cursor('foo')
    cursor.execute("select * from t1 order by id")
    cursor.scroll(offset)
    cursor.fetchmany(limit)
    cursor.close()

print 

timeit(offset,10,100,100)
timeit(scroll,100)
timeit(rownum,100)

print 

timeit(offset,480000)
timeit(scroll,480000)
timeit(rownum,480000)

print 

timeit(offset,999900)
timeit(scroll,999900)
timeit(rownum,999900)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读