Chapter 15 - Odoo 15 Development Book

Prefetch Patterns

At the point when you access information from a record-set, it makes a queries in the data set. In the event that you have a record-set with different records, getting records on it can make a framework slow in light of the various SQL queries. In this recipe, we will investigate how you can utilize the prefetching example to address this issue. By following the prefetching design, you can decrease the quantity of inquiries required, which will further develop execution and make your framework quicker.

Investigate the accompanying code; it is a typical process technique. In this strategy, self is a recordset of numerous records. At the point when you emphasize straightforwardly on the recordset, prefetching works perfectly:

# Correct prefetching
def compute_method(self):
   for rec in self:
       print(rec.name)

Be that as it may, at times, prefetching turns out to be more complicated, for example, while getting information with the browse strategy. In the accompanying model, we browse records individually in the for loop. This won't utilize prefetching effectively and it will execute more queries than expected:

# Incorrect prefetching
def some_action(self):
   record_ids = []
   self.env.cr.execute("some query to fetch record id")
   for rec in self.env.cr.fetchall():
       record = self.env['sale.order'].browse(rec[0])
       print(record.name)

Instead of passing individual IDs to the browse method we can retrieve the IDs to a variable and pass at once. Then you can perform the operations on this recordset. Along these lines, you won't lose the prefetching element and information will be brought in a solitary SQL queries.

# Correct prefetching
def some_action(self):
   record_ids = []
   self.env.cr.execute("some query to fetch record id")
   record_ids = [rec[0] for rec in self.env.cr.fetchall()]
   recordset = self.env['sale.order'].browse(record_ids)
   for record in recordset:
       print(record.name)

At the point when you are working with different recordsets, prefetching lessens the quantity of SQL queries. It does this by getting each of the information without a moment's delay. Ordinarily, prefetching works consequently in Odoo, yet you lose this component in specific conditions, for example, when you split records as portrayed in the accompanying model:

records = [rec for rec in record_ids if rec.id not in [111, 222, 444, 555]]

The above code given will part the recordset into parts, thus you can't exploit prefetching.

Utilizing prefetching accurately can altogether work on the presentation of the Object-Relational Mapping (ORM). We should investigate how prefetching functions in the engine. At the point when you emphasize on a recordset through a for loop and access the worth of a field in the first iteration, Rather than bringing information for the ongoing record in the iteration, prefetching will get the information for the records as a whole. The rationale behind this is that on the off chance that you are getting to a field in a for circle, you are probably going to bring that information for the following record in the iterations too. In the main emphasis of the for loop, prefetching will get the information for all of the recordsets and keep it in the cache. In the following iteration of the for loop, information will be served from this cache, rather than making another SQL query. This will decrease the inquiry count from O(n) to O(1).

We should assume the recordset has 10 records. At the point when you are in the first loop and access the name field of the record, it will get the information for every one of the 10 records. This isn't just the situation for the name field; it will likewise bring every one of the fields for those 10 records. In the ensuing following iteration, the information will be served from the store. This will decrease the quantity of questions from 10 to 1:

self.env.cr.execute("select id from sale_order limit 10")
record = self.env['sale.order'].browse(record_ids)
for rec in record:
   print(rec.name) # Prefetch name of all 10 records in the first loop
   print(rec.attention) # Prefetch attention of all 10 records in the first loop

Note that the prefetching will get the worth of the entirety of the fields (with the exception of the *2many fields) regardless of whether those fields are not utilized in that frame of mind of the for loop. This is on the grounds that the additional sections just minorly affect execution contrasted with the additional questions for every segment.

Once in a while, prefetched fields could decrease execution. In these cases, you can handicap prefetching by passing False into the prefetch_fields setting, as follows: recordset.with_context(prefetch_fields=False). The prefetch component utilizes the environment cache to store and recover record values. This implies that once the records are gotten from the information base, all ensuing calls for fields will be served from the environment cache. You can get to the environment cache utilizing the env.cache trait. To nullify the cache, you can utilize the invalidate_cache() strategy for the environment.

On the off chance that you split recordsets, the ORM will create a new recordset with a new prefetch setting. Performing procedure on such recordsets will just prefetch the information for the separate records. Assuming you need to prefetch every one of the records after prefetch, you can do this by passing the prefetch record IDs to the with_prefetch() technique. In the accompanying model, we split the recordset into two sections. Here, we passed a typical prefetch setting in both recordsets, so when you get the information from one of them, the ORM will bring the information for the other and put the information in the cache for sometime later:

self.env.cr.execute("select id from sale_order limit 10")
record_ids = [rec[0] for rec in self.env.cr.fetchall()]
recordset = self.env['sale.order'].browse(record_ids)
recordset1 = recordset[:5]
for rec in recordset1:
   print(rec.name)  # Prefetch name of all 5 records in the first loop
   print(rec.attention)  # Prefetch attention of all 5 records in the first loop
recordset2 = recordset[5:].with_prefetch(recordset._ids)
for rec in recordset1:
   print(rec.name)  # Prefetch name of all 10 records in the first loop
   print(rec.attention)  # Prefetch attention of all 10 records in the first loop

In the above code recordsset1 prefetch only 5 records in the recordset while recordset2 prefetch all the records in the recordset. The prefetch setting isn't restricted to parting recordsets. You can likewise utilize the with_prefetch() strategy to have a typical prefetch setting between various recordsets. This implies that when you bring information from one record, it will get information for any remaining recordsets as well.

whatsapp
location

Calicut

Cybrosys Technologies Pvt. Ltd.
Neospace, Kinfra Techno Park
Kakkancherry, Calicut
Kerala, India - 673635

location

Kochi

Cybrosys Technologies Pvt. Ltd.
1st Floor, Thapasya Building,
Infopark, Kakkanad,
Kochi, India - 682030.

location

Bangalore

Cybrosys Techno Solutions
The Estate, 8th Floor,
Dickenson Road,
Bangalore, India - 560042

Send Us A Message