content/develop/ai/search-and-query/best-practices/scalable-query-best-practices.md
{{< note >}} If you're using Redis Software or Redis Cloud, see the [best practices for scalable Redis Search]({{< relref "/operate/oss_and_stack/stack-with-enterprise/search/scalable-query-best-practices" >}}) page. {{< /note >}}
Below are some basic steps to ensure good performance of Redis Search .
FT.INFO]({{< relref "commands/ft.info" >}}) and [FT.PROFILE]({{< relref "commands/ft.profile" >}}) outputs for anomalies and/or errors.TAG]({{< relref "/develop/ai/search-and-query/indexing/field-and-type-options#tag-fields" >}}) over [NUMERIC]({{< relref "/develop/ai/search-and-query/indexing/field-and-type-options#numeric-fields" >}}) for use cases that only require matching.TAG]({{< relref "/develop/ai/search-and-query/indexing/field-and-type-options#tag-fields" >}}) over [TEXT]({{< relref "/develop/ai/search-and-query/indexing/field-and-type-options#text-fields" >}}) for use cases that don’t require full-text capabilities (pure match).SORTABLE]({{< relref "/develop/ai/search-and-query/advanced-concepts/sorting" >}}) if they are used in [SORTBY]({{< relref "/develop/ai/search-and-query/advanced-concepts/sorting#specifying-sortby" >}})
queries.DIALECT 2]({{< relref "/develop/ai/search-and-query/advanced-concepts/dialects#dialect-2" >}}).RETURN or LOAD) in the index.SORTABLE.TEXT fields to NOSTEM if the use case will support it.DIALECT 2]({{< relref "/develop/ai/search-and-query/advanced-concepts/dialects#dialect-2" >}}).CURSOR or LIMIT.LOAD *). Project only those fields that are part of the index schema.FT.PROFILE)You can analyze [FT.PROFILE]({{< relref "commands/ft.profile" >}}) output to gain insights about query execution.
The following informational items are available for analysis:
UNION and INTERSECTTIMEOUTWhen designing and querying indexes in Redis Search, certain practices can hinder performance, scalability, and maintainability. Below are some common anti-patterns to avoid:
The following examples depict an anti-pattern index schema and query, followed by corrected versions designed for scalability with Redis Search.
The following schema introduces challenges for scalability and performance:
FT.CREATE jsonidx:profiles ON JSON PREFIX 1 profiles:
SCHEMA $.tags.* as t NUMERIC SORTABLE
$.firstName as name TEXT
$.location as loc GEO
Issues:
lastName, id, and version that might be frequently queried. This results in additional operations to fetch these fields separately, reducing efficiency.SORTABLE flag for text fields: sorting operations on unsortable fields require full-text processing, which is slow.$.tags.* creates a broad index that can lead to excessive memory usage and reduced query performance.The following query is inefficient and not optimized for vertical scaling:
FT.AGGREGATE jsonidx:profiles '@t:[1299 1299]' LOAD * LIMIT 0 10
Issues:
LOAD *): retrieving all fields in the result set is inefficient and increases memory usage, especially if the documents are large.Here’s an optimized schema that adheres to best practices for vertical scaling:
FT.CREATE jsonidx:profiles ON JSON PREFIX 1 profiles:
SCHEMA $.tags.* as t NUMERIC SORTABLE
$.firstName as name TEXT NOSTEM SORTABLE
$.lastName as lastname TEXT NOSTEM SORTABLE
$.location as loc GEO SORTABLE
$.id as id TAG SORTABLE UNF
$.ver as ver TAG SORTABLE UNF
Improvements:
NOSTEM for text fields: prevents stemming on fields like firstName and lastName to allow for exact matches (e.g., "Smith" stays "Smith").lastName, id, and version, making queries more efficient by reducing the need for post-query data retrieval.TAG fields: id and ver are defined as TAG fields to support fast filtering with exact matches.SORTABLE for all relevant fields: ensures that sorting operations are efficient without requiring full-text scanning.You might be wondering why $.tags.* as t NUMERIC SORTABLE is acceptable in the improved schema and it wasn't previously.
The inclusion of $.tags.* is acceptable when:
$.tags.* for all query operations, distributing the load more evenly.$.tags.* should avoid loading unnecessary fields or returning excessively large result sets.The following query is better suited for vertical scaling:
FT.AGGREGATE jsonidx:profiles '@t:[1299 1299]'
LOAD 6 id t name lastname loc ver
LIMIT 0 10
DIALECT 2
Improvements:
LOAD clause specifies only essential fields (id, t, name, lastname, loc, ver), reducing memory and network overhead.LIMIT clause ensures the query retrieves only the first 10 results, avoiding large result sets.DIALECT 2]({{< relref "/develop/ai/search-and-query/advanced-concepts/dialects#dialect-2" >}}): enables the latest Redis Search syntax and features, ensuring compatibility with modern capabilities.