我尝试腌制Django查询对象以将其保存在Redis中。
materials = Material.objects.prefetch_related('tags_applied').prefetch_related('materialdata_set').prefetch_related('source')
materials_ids = MaterialData.objects.filter(tag_id__in=tags).values_list('material_id', flat=True)
materials = materials.filter(pk__in=materials_ids)
key_name = SAMPLES_UUID + ':' + str(redis_uuid)
redis_cl.set_key(key_name, pickle.dumps(materials.query))
redis_cl.expire(key_name, SAMPLES_TIMEOUT)
这是debug_panel的跟踪信息(我使用惰性分页):
源查询是:
SELECT“ san_material”。“ id”,“ san_material”。“ created_at”,
“ san_material”。“标题”,“ san_material”。“作者”,“ san_material”。“ url”,
“ san_material”。“ publication_datetime”,“ san_material”。“ text”,
“ san_material”。“尺寸”,“ san_material”。“ source_id”,
“ san_material”。“ material_type”,“ san_material”。“ updated_at”,
“ san_material”。“状态”,“ san_material”。“ elastic_sync”,
“ san_material”。“令牌”,“ san_material”。“检测日期时间”,
“ san_material”。“ article_title”,
“ san_material”。“ publication_datetime_article”,
“ san_material”。“ author_article”,“ san_material”。“ highlight_data” FROM
“ san_material” WHERE(“ san_material”。“ detection_datetime” BETWEEN
'2016-07-01T00:00:00 + 03:00':: timestamptz AND
'2016-07-27T10:39:00 + 03:00':: timestamptz和“ san_material”。“ id” IN
(选择U0。“ material_id”来自“ san_materialdata” U0,其中U0。“ tag_id”
IN(660)))ORDER BY“ san_material”。“ detection_datetime” DESC LIMIT 51
但这是子查询命中数据库:
从“ san_materialdata”中选择SELECT U0。“ material_id” U0在U0中。“ tag_id”
IN(660)
在这里:
/home/maxx/analize/san/utils.py in wrapper(82)
result = method_to_decorate(*args, **kwds)
/home/maxx/analize/san/views/flux.py in flux(111)
redis_cl.set_key(key_name, pickle.dumps(materials.query))
/usr/lib/python2.7/pickle.py in dumps(1393)
Pickler(file, protocol).dump(obj)
/usr/lib/python2.7/pickle.py in dump(225)
self.save(obj)
/usr/lib/python2.7/pickle.py in save(333)
self.save_reduce(obj=obj, *rv)
/usr/lib/python2.7/pickle.py in save_reduce(421)
save(state)
/usr/lib/python2.7/pickle.py in save(288)
f(self, obj) # Call unbound method with explicit self
/usr/lib/python2.7/pickle.py in save_dict(657)
self._batch_setitems(obj.iteritems())
/usr/lib/python2.7/pickle.py in _batch_setitems(675)
save(v)
/usr/lib/python2.7/pickle.py in save(333)
self.save_reduce(obj=obj, *rv)
/usr/lib/python2.7/pickle.py in save_reduce(421)
save(state)
/usr/lib/python2.7/pickle.py in save(288)
f(self, obj) # Call unbound method with explicit self
/usr/lib/python2.7/pickle.py in save_dict(657)
self._batch_setitems(obj.iteritems())
/usr/lib/python2.7/pickle.py in _batch_setitems(675)
save(v)
/usr/lib/python2.7/pickle.py in save(288)
f(self, obj) # Call unbound method with explicit self
/usr/lib/python2.7/pickle.py in save_list(604)
self._batch_appends(iter(obj))
/usr/lib/python2.7/pickle.py in _batch_appends(620)
save(x)
/usr/lib/python2.7/pickle.py in save(333)
self.save_reduce(obj=obj, *rv)
/usr/lib/python2.7/pickle.py in save_reduce(421)
save(state)
/usr/lib/python2.7/pickle.py in save(288)
f(self, obj) # Call unbound method with explicit self
/usr/lib/python2.7/pickle.py in save_dict(657)
self._batch_setitems(obj.iteritems())
/usr/lib/python2.7/pickle.py in _batch_setitems(675)
save(v)
/usr/lib/python2.7/pickle.py in save(308)
rv = reduce(self.proto)
/home/maxx/venv/analize/lib/python2.7/copy_reg.py in _reduce_ex(84)
dict = getstate()
我该如何解决?
p.s我在def _batch_setitems中测量了节省时间的参数:
('Save obj time:', 2.5215649604797363, 'arg:', 'rhs')
('Save obj time:', 2.5219039916992188, 'arg:', 'children')
('Save obj time:', 2.5219550132751465, 'arg:', 'where')
2.5秒的3倍。为什么?
最佳答案
Django查询是惰性查询,但让我解释一下您写的内容:
materials = Material.objects.prefetch_related('tags_applied'
).prefetch_related('materialdata_set').prefetch_related('source')
materials_ids = MaterialData.objects.filter(tag_id__in=tags).values_list('material_id', flat=True)
# till now materials_id is queryset, means it will not hit DB.
# as soon it execute next line of code it will hit db, because in next line you are using materials_ids.
materials = materials.filter(pk__in=materials_ids)
# So you can avoid hiting db if you are not required to use materials
key_name = SAMPLES_UUID + ':' + str(redis_uuid)
redis_cl.set_key(key_name, pickle.dumps(materials.query))
redis_cl.expire(key_name, SAMPLES_TIMEOUT)
您可以通过在Django中使用适当的联接来更正此问题:
我猜您MaterialData模型具有材料作为材料模型的外键。
materials = MaterialData.objects.filter(tag_id__in=tags).prefetch_related(
'material__tags_applied'
).prefetch_related('material__materialdata_set').prefetch_related('material__source').values(*all values realted to mateials you can put here by adding materials__ before each material field *)
# to fetch foreign key attribue you use field followed by duble underscore
key_name = SAMPLES_UUID + ':' + str(redis_uuid)
redis_cl.set_key(key_name, pickle.dumps(materials.query))
关于python - Django pickle.dumps(model.query)击中db,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38606989/