Impacted versions:

8, 9, 10, master

Steps to reproduce:

Run `odoo shell --log-level=debug_sql` on a database where accounting is installed with demo data.

```
>>> AML = env['account.move.line']
>>> AML.search([('tax_ids.amount', '=', 15)])
```

You get the following trace of 4 sql statements:

The first one is ok:
```sql
SELECT "account_tax".id FROM "account_tax" WHERE (("account_tax"."active" = %s)  AND  ("account_tax"."amount" = %s)) ORDER BY "account_tax"."sequence"  
```

The second one can be improved and is discussed in https://github.com/odoo/odoo/pull/16066, it's not the point of this issue.
```sql
SELECT "account_move_line_id" FROM "account_move_line_account_tax_rel" WHERE "account_tax_id" IN %s
```

Then it does the same query twice with apparently no good reason (at least none I understand).
```sql
SELECT "account_move_line".id FROM "account_move_line" WHERE ("account_move_line"."id" in (%s)) ORDER BY "account_move_line"."date" DESC,"account_move_line"."id" DESC 
SELECT "account_move_line".id FROM "account_move_line" WHERE ("account_move_line"."id" in (%s)) ORDER BY "account_move_line"."date" DESC,"account_move_line"."id" DESC 
```

The problem has its source [here](https://github.com/odoo/odoo/blob/b8ce0db8e105ed3c9ab4aefe8bce5028764694f4/odoo/osv/expression.py#L879): at first glance I'd say lines 879 and 880 could be replaced with

```leaf.leaf = (path[0], 'in', right_ids)```
openerp/osv/expression.py
"""Returns a normalized version of ``domain_expr``, where all implicit '&' operators
       have been made explicit. One property of normalized domain expressions is that they
       can be easily combined together as if they were single domain components.
    """
    assert isinstance(domain, (list, tuple)), "Domains to normalize must have a 'domain' form: a list or tuple of domain components"
    if not domain:
        return TRUE_DOMAIN
     = []
    expected = 1                            # 
    op_arity = {NOT_OPERATOR: 1, AND_OPERATOR: 2, OR_OPERATOR: 2}
    for token in domain:
        if expected == 0:                   # 
            [0:0] = [AND_OPERATOR]             # 
            expected = 1
        .append(token)
        if isinstance(token, (list, tuple)):  # 
            expected -= 1
        else:
            expected += op_arity.get(token, 0) - 1
    assert expected == 0, 'This domain is syntactically not correct: %s' % (domain)
    return 
def combine(operator, unit, zero, domains):