Short: UCASE(key_col)=… is now sargable in MariaDB. One can ignore the UCASE() call here, but only for a few collations. One might expect this to work for any _ci (case-insensitive) collation, but it doesn’t. Surprisingly, LCASE() cannot be ignored even in utf8_general_ci. Long: Some months ago, we got a set of customer queries that had […]
UCASE() is now sargable in MariaDB. LCASE() can’t be. appeared first on MariaDB.org
Short: UCASE(key_col)=… is now sargable in MariaDB. One can ignore the UCASE() call here, but only for a few collations. One might expect this to work for any _ci (case-insensitive) collation, but it doesn’t. Surprisingly, LCASE() cannot be ignored even in utf8_general_ci.
Long: Some months ago, we got a set of customer queries that had comparisons like
UCASE(tbl1.key_col) = UCASE(tbl2.key_col)
The optimizer couldn’t process this condition at all, so it was computing a cross join. Also, it wasn’t able to estimate the condition selectivity, so the rest of the query plan was bad, too.
But, tbl1.key_col’s collation used a case-insensitive collation utf8mb3_general_ci, which gave an idea, perhaps
UPPER(tbl1.key_col)=something is equivalent to tbl1.key_col=something
After investigation with Alexander Barkov, we’ve discovered that this holds for utf8mb3_general_ci collation. But other case-insensitive collations have exceptions to this. For example, in Czech collation utf8mb3_czech_ci, 'CH' compares as if it was a single letter between ‘H’ and ‘I’. But 'cH' is not treated this way, which means UCASE('cH') will compare differently from 'cH'. MDEV-31494 has more details and more examples.
One would think LCASE() would be the same. It is not. Even in utf8mb3_general_ci, there are characters that compare differently from their LCASE(). The first example is the Angstrom Sign. It compares as different from letter A:
MariaDB [test]> select 'A'='Å' ;
+-----------+
| 'A'='Å' |
+-----------+
| 0 |
+-----------+The LCASE of Angstrom Sign is “Latin Small Letter A with Ring Above”, which compares as equal to letter a:
MariaDB [test]> select LCASE('A'), LCASE('Å'), LCASE('A')=LCASE('Å') ;
+------------+--------------+-------------------------+
| LCASE('A') | LCASE('Å') | LCASE('A')=LCASE('Å') |
+------------+--------------+-------------------------+
| a | å | 1 |
+------------+--------------+-------------------------+There are other similar examples. MDEV-31955 has the details.
Note that here LCASE(x)=... is true, and x= is not. If we do searches using x=... , we will miss rows for which LCASE(x)=... , so the rewrite cannot be done.
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | Making “tbl.utf8mb3_key_column=utf8mb4_expr” sargable | 0 | 7.73 | 11-10-2023 |
| 2 | Work around a MariaDB behaviour change | 0 | 10.97 | 16-10-2024 |
| 3 | Notable optimizer fixes released in February, 2024 | 0 | 7.83 | 29-02-2024 |
| 4 | Sysbench vs MariaDB on a small server: using the same charset for all versions | 0 | 8.32 | 06-04-2026 |
| 5 | New book (coming) – MariaDB for Developers | 0 | 7.06 | 31-12-2023 |
| 6 | MariaDB Server 12.3, 11.8, 11.4, 10.11, 10.6 – May 2026’s releases: thank you for your contributions | 0 | 15.78 | 10-06-2026 |
| 7 | Optimizer-related fixes in current batch of stable releases | 0 | 8.12 | 19-11-2023 |
| 8 | MariaDB 13.1 preview available | 0 | 10.04 | 20-06-2026 |
| 9 | Building MariaDB Server from the sources | 0 | 5.29 | 05-04-2024 |