﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
31507	Augment QuerySet.exists() optimizations to .union().exists().	Simon Charette	nobody	"The `QuerySet.exists` method performs optimization by [https://github.com/django/django/blob/67f9d076cfc1858b94f9ed6d1a5ce2327dcc8d0d/django/db/models/sql/compiler.py#L1107-L1115 clearing the select clause], [https://github.com/django/django/blob/67f9d076cfc1858b94f9ed6d1a5ce2327dcc8d0d/django/db/models/sql/query.py#L523-L535 dropping ordering, and limit the number of results to 1 if possible].

A similar optimization can be applied for combined queries when using `QuerySet.union()` as some query planers (e.g. MySQL) are not smart enough to prune changes down into combined queries.

For example, given `filtered_authors.union(other_authors).exists()` the currently generated is

{{{#!sql
SELECT 1 FROM (SELECT * FROM authors WHERE ... ORDER BY ... UNION SELECT * FROM authors WHERE ... ORDER BY ...) LIMIT 1;
}}}

But some planers won't be smart enough to realize that both `*` and `ORDER BY` are not necessary and fetch all matching rows. In order to help them we should generate the following SQL

{{{#!sql
SELECT 1 FROM (SELECT 1 FROM authors WHERE ... LIMIT 1 ... UNION SELECT 1 FROM authors WHERE ... LIMIT 1) LIMIT 1;
}}}

This can already be done manually through `filtered_authors.order_by().values(Value(1))[:1].union(other_authors.order_by().values(Value(1))[:1]).exists()` but that involves a lot of boilerplate.

Note that the optimization is only possible in this form for `union` and not for `intersection` and `difference` since they require both sets to be unaltered."	Cleanup/optimization	new	Database layer (models, ORM)	dev	Normal				Unreviewed	0	0	0	0	0	0
