You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/current/_includes/v25.4/misc/force-index-selection.md
+4-2Lines changed: 4 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,7 +1,9 @@
1
-
By using the explicit index annotation, you can override [CockroachDB's index selection](https://www.cockroachlabs.com/blog/index-selection-cockroachdb-2/) and use a specific [index]({% link {{ page.version.version }}/indexes.md %}) when reading from a named table.
1
+
By using the explicit index annotation, you can override [CockroachDB's index selection](https://www.cockroachlabs.com/blog/index-selection-cockroachdb-2/) and use a specific [index]({% link {{ page.version.version }}/indexes.md %}) when reading from a named table. This is called an *index hint*.
2
2
3
-
{{site.data.alerts.callout_info}}
4
3
Index selection can impact [performance]({% link {{ page.version.version }}/performance-best-practices-overview.md %}), but does not change the result of a query.
4
+
5
+
{{site.data.alerts.callout_success}}
6
+
You can apply index hints without modifying the original query text. Refer to [Hint injection]({% link {{ page.version.version }}/cost-based-optimizer.md %}#hint-injection).
Copy file name to clipboardExpand all lines: src/current/v25.4/cost-based-optimizer.md
+103Lines changed: 103 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -419,6 +419,10 @@ Due to SQL's implicit `AS` syntax, you cannot specify a join hint with only the
419
419
420
420
For a join hint example, see [Use the right join type]({% link {{ page.version.version }}/apply-statement-performance-rules.md %}#rule-3-use-the-right-join-type).
421
421
422
+
{{site.data.alerts.callout_success}}
423
+
You can apply join hints without modifying the original query text. Refer to [Hint injection](#hint-injection).
424
+
{{site.data.alerts.end}}
425
+
422
426
### Supported join algorithms
423
427
424
428
-`HASH`: Forces a hash join; in other words, it disables merge and lookup joins. A hash join is always possible, even if there are no equality columns: CockroachDB treats a nested loop join without an index as a special case of a hash join, where the hash table effectively has one bucket.
@@ -457,6 +461,105 @@ To make the optimizer prefer lookup joins to merge joins when performing foreign
457
461
458
462
- You should reconsider hint usage with each new release of CockroachDB. Due to improvements in the optimizer, hints specified to work with an older version may cause decreased performance in a newer version.
459
463
464
+
## Hint injection
465
+
466
+
<span class="version-tag">New inv25.4.1:</span>*Hint injection* allows you to apply [index hints]({% link {{ page.version.version }}/table-expressions.md %}#force-index-selection) and [join hints](#join-hints) without modifying the original query text. This is useful when you cannot modify application code, need to optimize queries from ORMs or third-party applications, or want to test different hints without changing production queries.
467
+
468
+
Instead of relying on inline hints (such as`SELECT * FROM table@index_name`or`INNER HASH JOIN`), hint injection stores hints in the `system.statement_hints` table and automatically applies them to statements that match a [fingerprint]({% link {{ page.version.version }}/ui-statements-page.md %}#sql-statement-fingerprints). To inject a hint, invoke the `crdb_internal.inject_hint()` function with a SQL statement fingerprint and a matching statement with hints applied:
469
+
470
+
{% include_cached copy-clipboard.html %}
471
+
~~~ sql
472
+
SELECTcrdb_internal.inject_hint(
473
+
'{statement fingerprint}',
474
+
'{statement with hints}'
475
+
);
476
+
~~~
477
+
478
+
For example, the following invocation stores the `users_email_idx` hint in the `system.statement_hints` table:
479
+
480
+
{% include_cached copy-clipboard.html %}
481
+
~~~sql
482
+
SELECTcrdb_internal.inject_hint(
483
+
'SELECT * FROM users WHERE email = _',
484
+
'SELECT * FROM users@users_email_idx WHERE email = _'
485
+
);
486
+
~~~
487
+
488
+
{{site.data.alerts.callout_info}}
489
+
The statement with hints must have the same syntactic structure as the statement fingerprint. Constants in the second parameter are ignored, and only hints are extracted and applied.
490
+
{{site.data.alerts.end}}
491
+
492
+
The function returns a unique hint ID:
493
+
494
+
~~~
495
+
crdb_internal.inject_hint
496
+
-----------------------------
497
+
1119388019656228865
498
+
~~~
499
+
500
+
Afterward, any query matching the `SELECT * FROM users WHERE email = _` fingerprint will use the `users_email_idx` index, regardless of the `email` value.
501
+
502
+
Similarly, to force a specific join algorithm:
503
+
504
+
{% include_cached copy-clipboard.html %}
505
+
~~~sql
506
+
SELECTcrdb_internal.inject_hint(
507
+
'SELECT * FROM orders AS o INNER JOIN customers AS c ON o.customer_id = c.id',
508
+
'SELECT * FROM orders AS o INNER HASH JOIN customers AS c ON o.customer_id = c.id'
509
+
);
510
+
~~~
511
+
512
+
You can inject both index and join hints in a single statement:
513
+
514
+
{% include_cached copy-clipboard.html %}
515
+
~~~sql
516
+
SELECTcrdb_internal.inject_hint(
517
+
'SELECT * FROM orders AS o INNER JOIN customers AS c ON o.customer_id = c.id WHERE o.status = _',
518
+
'SELECT * FROM orders@orders_status_idx AS o INNER LOOKUP JOIN customers@primary AS c ON o.customer_id = c.id WHERE o.status = _'
519
+
);
520
+
~~~
521
+
522
+
Hint injection supports all inline hint types, including:
The optimizer may plan a zigzag join when there are at least **two secondary indexes on the same table** and the table is filtered in a query with at least two filters constraining different attributes to a constant. A zigzag join works by "zigzagging" back and forth between two indexes and returning only rows with matching primary keys within a specified range. For example:
0 commit comments