Denis Ledoux e2ffff1e42 [IMP] base: faster search on filters by re-ordering unique constraint
The domain used in `get_filters`, used in `get_views` is

```python
[('action_id', 'in', [action_id, False]), ('model_id', '=', model), ('user_id', 'in', [self._uid, False])]
```

Therefore filtering the filters on `action_id`, `model_id` and
`user_id`.

An index on `(action_id, model_id, user_id)` would therefore be welcome
in order to search quicker on filters.

The unique constraint `name_model_uid_unique` almost does it,
but it puts the name in first, and therefore the index is not used
when searching on the above domain.

By moving `name` to the end of the unique constraint,
the index created for this unique constraint becomes
usable for the above domain,
and it makes the SQL statement to search on filters way quicker.

Before:
```sql
EXPLAIN ANALYZE SELECT "ir_filters".id FROM "ir_filters" LEFT JOIN "ir_translation" AS "ir_filters__name" ON ("ir_filters"."id" = "ir_filters__name"."res_id" AND "ir_filters__name"."type" = 'model' AND "ir_filters__name"."name" = 'ir.filters,name' AND "ir_filters__name"."lang" = 'en_US' AND "ir_filters__name"."value" != '') WHERE (((("ir_filters"."active" = true) AND (("ir_filters"."action_id" in (225)) OR "ir_filters"."action_id" IS NULL)) AND ("ir_filters"."model_id" = 'account.move')) AND (("ir_filters"."user_id" in (2)) OR "ir_filters"."user_id" IS NULL)) AND TRUE ORDER BY  "ir_filters"."model_id" ,COALESCE("ir_filters__name"."value", "ir_filters"."name") ,"ir_filters"."id" DESC;
                                                                              QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=3500.58..3500.59 rows=1 width=56) (actual time=12.940..12.942 rows=0 loops=1)
   Sort Key: (COALESCE(ir_filters__name.value, (ir_filters.name)::text)), ir_filters.id DESC
   Sort Method: quicksort  Memory: 25kB
   ->  Nested Loop Left Join  (cost=0.00..3500.57 rows=1 width=56) (actual time=12.933..12.934 rows=0 loops=1)
         Join Filter: (ir_filters.id = ir_filters__name.res_id)
         ->  Seq Scan on ir_filters  (cost=0.00..3499.02 rows=1 width=36) (actual time=12.932..12.932 rows=0 loops=1)
               Filter: (active AND ((action_id = 225) OR (action_id IS NULL)) AND ((user_id = 2) OR (user_id IS NULL)) AND ((model_id)::text = 'account.move'::text))
               Rows Removed by Filter: 100001
         ->  Seq Scan on ir_translation ir_filters__name  (cost=0.00..1.54 rows=1 width=36) (never executed)
               Filter: ((value <> ''::text) AND ((type)::text = 'model'::text) AND ((name)::text = 'ir.filters,name'::text) AND ((lang)::text = 'en_US'::text))
 Planning Time: 0.311 ms
 Execution Time: 12.972 ms
```

After:
```sql
EXPLAIN ANALYZE SELECT "ir_filters".id FROM "ir_filters" LEFT JOIN "ir_translation" AS "ir_filters__name" ON ("ir_filters"."id" = "ir_filters__name"."res_id" AND "ir_filters__name"."type" = 'model' AND "ir_filters__name"."name" = 'ir.filters,name' AND "ir_filters__name"."lang" = 'en_US' AND "ir_filters__name"."value" != '') WHERE (((("ir_filters"."active" = true) AND (("ir_filters"."action_id" in (225)) OR "ir_filters"."action_id" IS NULL)) AND ("ir_filters"."model_id" = 'account.move')) AND (("ir_filters"."user_id" in (2)) OR "ir_filters"."user_id" IS NULL)) AND TRUE ORDER BY  "ir_filters"."model_id" ,COALESCE("ir_filters__name"."value", "ir_filters"."name") ,"ir_filters"."id" DESC;
                                                                            QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=14.44..14.44 rows=1 width=56) (actual time=0.086..0.087 rows=0 loops=1)
   Sort Key: (COALESCE(ir_filters__name.value, (ir_filters.name)::text)), ir_filters.id DESC
   Sort Method: quicksort  Memory: 25kB
   ->  Nested Loop Left Join  (cost=8.86..14.43 rows=1 width=56) (actual time=0.080..0.081 rows=0 loops=1)
         Join Filter: (ir_filters.id = ir_filters__name.res_id)
         ->  Bitmap Heap Scan on ir_filters  (cost=8.86..12.87 rows=1 width=36) (actual time=0.079..0.080 rows=0 loops=1)
               Recheck Cond: ((((model_id)::text = 'account.move'::text) AND (user_id = 2)) OR (((model_id)::text = 'account.move'::text) AND (user_id IS NULL)))
               Filter: (active AND ((action_id = 225) OR (action_id IS NULL)))
               ->  BitmapOr  (cost=8.86..8.86 rows=1 width=0) (actual time=0.078..0.079 rows=0 loops=1)
                     ->  Bitmap Index Scan on ir_filters_name_model_uid_unique  (cost=0.00..4.43 rows=1 width=0) (actual time=0.075..0.075 rows=0 loops=1)
                           Index Cond: (((model_id)::text = 'account.move'::text) AND (user_id = 2))
                     ->  Bitmap Index Scan on ir_filters_name_model_uid_unique  (cost=0.00..4.43 rows=1 width=0) (actual time=0.002..0.002 rows=0 loops=1)
                           Index Cond: (((model_id)::text = 'account.move'::text) AND (user_id IS NULL))
         ->  Seq Scan on ir_translation ir_filters__name  (cost=0.00..1.54 rows=1 width=36) (never executed)
               Filter: ((value <> ''::text) AND ((type)::text = 'model'::text) AND ((name)::text = 'ir.filters,name'::text) AND ((lang)::text = 'en_US'::text))
 Planning Time: 1.000 ms
 Execution Time: 0.121 ms
```

I take the opportunity to add the populate for `ir.filters`,
which helped me for the above analysis.

closes odoo/odoo#99657

Signed-off-by: Denis Ledoux (dle) <dle@odoo.com>
2022-09-07 11:25:52 +02:00
…
2022-08-30 08:18:53 +02:00
…
…
…
…
…
…

Build Status Tech Doc Help Nightly Builds

Odoo

Odoo is a suite of web based open source business apps.

The main Odoo Apps include an Open Source CRM, Website Builder, eCommerce, Warehouse Management, Project Management, Billing & Accounting, Point of Sale, Human Resources, Marketing, Manufacturing, ...

Odoo Apps can be used as stand-alone applications, but they also integrate seamlessly so you get a full-featured Open Source ERP when you install several Apps.

Getting started with Odoo

For a standard installation please follow the Setup instructions from the documentation.

To learn the software, we recommend the Odoo eLearning, or Scale-up, the business game. Developers can start with the developer tutorials

S
Description
No description provided
Readme LGPL-3.0
3.4 GiB
Languages
Python 49.6%
JavaScript 47.8%
SCSS 2%
CSS 0.3%
HTML 0.2%