用遍历查询对象来节省datastore查询时间
2010 12 14 12:24 PM 1692次查看
分类:Google App Engine 标签:Google App Engine, Python
以前文档里曾指出遍历查询对象是个很低效的方法,所以我一直都不这样用。今天特意测试了一番,发现它原来并不低效。
from time import time
from google.appengine.ext import db
from google.appengine.api import apiproxy_stub_map
db_count = 0
def before_db(service, call, request, response):
global db_count
db_count += 1
apiproxy_stub_map.apiproxy.GetPreCallHooks().Append('before_db', before_db, 'datastore_v3')
class TestModel(db.Model):
pass
COUNT = 1000
def testIterator():
t = time()
i = 0
for e in TestModel.all():
i += 1
if i == COUNT:
return time() - t
print 'testIterator'
t = testIterator()
print t
print db_count
print t / db_count
def testCursor(size_per_fetch):
t = time()
q = TestModel.all()
for i in xrange(COUNT / size_per_fetch):
q.fetch(size_per_fetch)
q.with_cursor(q.cursor())
return time() - t
db_count = 0
print '\ntestCursor 10'
t = testCursor(10)
print t
print db_count
print t / db_count
db_count = 0
print '\ntestCursor 20'
t = testCursor(20)
print t
print db_count
print t / db_count
db_count = 0
print '\ntestCursor 50'
t = testCursor(50)
print t
print db_count
print t / db_count
结果:testIterator可以看出,迭代查询对象时,每次会fetch 20个结果,且会多一次prefetch。而同样是一次fetch 20个结果,它比使用cursor要快44%。不过更高效的方法当然是一次获取更多数据,来减少数据库访问次数。
0.57021689415
51
0.0111807234147
testCursor 10
1.20552110672
100
0.0120552110672
testCursor 20
0.821892976761
50
0.0164378595352
testCursor 50
0.533807039261
20
0.026690351963
读了SDK的源码后发现,google\appengine\api\datastore_file_stub.py中定义了“_BATCH_SIZE = 20”,并且在_Dynamic_Next方法中直接使用了这个值。
不过云端用的不是datastore_file_stub,所以只能用hook替换掉这个_Dynamic_Next方法,来使用自定义的batch size。
而调用端是用Batcher这个类来实现prefetch的,由于太复杂,暂时也没想出什么用它来代替cursor来分页的办法。
0条评论 你不来一发么↓