我尝试腌制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/

10-12 22:11