You experience high latency on queries that cannot be explained by high contention or a suboptimal query plan. You might also see high CPU on one or more nodes.
You may be scanning over large numbers of MVCC versions. This is similar to how a full table scan can be slow.
A transaction is unable to complete due to another concurrent or recent transaction attempting to write to the same data. This is also called lock contention.
Indicators that your application is experiencing transaction contention
Waiting transaction
These are indicators that a transaction is trying to access a row that has been “locked” by another, concurrent write transaction.
The Active Executions table on the Transactions page (CockroachDB Cloud Console or DB Console) shows transactions with Waiting in the Status column. You can sort the table by Time Spent Waiting.
This is also shown in the Transaction Executions view on the Insights page (CockroachDB Cloud Console and DB Console). Transaction executions will display the High Contention insight.
Evaluate whether you can cancel the transaction. If so, cancel it to unblock the waiting transaction.
Optimize the transaction to reduce further contention. In particular, break down larger transactions such as bulk deletes into smaller ones to have transactions hold locks for a shorter duration, and use historical reads when possible to reduce conflicts with other writes.
Take steps to minimize transaction retry errors in the first place. This means reducing transaction contention overall, and increasing the likelihood that CockroachDB can automatically retry a failed transaction.
In the Active Executions table on the Transactions page (CockroachDB Cloud Console or DB Console), look for a waiting transaction (Waiting status).
If you see many waiting transactions, a single long-running transaction may be blocking transactions that are, in turn, blocking others. In this case, sort the table by Time Spent Waiting to find the transaction that has been waiting for the longest amount of time. Unblocking this transaction may unblock the other transactions.
Click the transaction’s execution ID and view the following transaction execution details:
Last Retry Reason shows the last transaction retry error received for the transaction, if applicable.
The details of the blocking transaction, directly below the Contention Insights section. Click the blocking transaction to view its details.
Click its Session ID to open the Session Details page.
Click Cancel Statement to cancel the Most Recent Statement and thus the transaction, or click Cancel Session to cancel the session issuing the transaction.
Identify transactions and objects that experienced lock contention
To identify transactions that experienced lock contention in the past:
In the Transaction Executions view on the Insights page (CockroachDB Cloud Console and DB Console), look for a transaction with the High Contention insight. Click the transaction’s execution ID and view the transaction execution details, including the details of the blocking transaction.
Contention is often reported after it has already resolved. Therefore, preventing contention before it affects your cluster’s performance is a more effective approach:
Limit the number of affected rows by following optimizing queries (e.g., avoiding full scans, creating secondary indexes, etc.). Not only will transactions run faster, lock fewer rows, and hold locks for a shorter duration, but the chances of read invalidation when the transaction’s timestamp is pushed, due to a conflicting write, are decreased because of a smaller read set (i.e., a smaller number of rows read).
Break down larger transactions (e.g., bulk deletes) into smaller ones to have transactions hold locks for a shorter duration. For example, use common table expressions to group multiple clauses together in a single SQL statement. This will also decrease the likelihood of pushed timestamps. For instance, as the size of writes (number of rows written) decreases, the chances of the transaction’s timestamp getting bumped by concurrent reads decreases.
Use SELECT FOR UPDATE to aggressively lock rows that will later be updated in the transaction. Updates must operate on the most recent version of a row, so a concurrent write to the row will cause a retry error (RETRY_WRITE_TOO_OLD). Locking early in the transaction forces concurrent writers to block until the transaction is finished, which prevents the retry error. Note that this locks the rows for the duration of the transaction; whether this is tenable will depend on your workload. For more information, see When and why to use SELECT FOR UPDATE in CockroachDB.
When replacing values in a row, use UPSERT and specify values for all columns in the inserted rows. This will usually have the best performance under contention, compared to combinations of SELECT, INSERT, and UPDATE.
If applicable to your workload, assign column families and separate columns that are frequently read and written into separate columns. Transactions will operate on disjoint column families and reduce the likelihood of conflicts.
As a last resort, consider adjusting the closed timestamp interval using the kv.closed_timestamp.target_durationcluster setting to reduce the likelihood of long-running write transactions having their timestamps pushed. This setting should be carefully adjusted if no other mitigations are available because there can be downstream implications (e.g., historical reads, change data capture feeds, statistics collection, handling zone configurations, etc.). For example, a transaction A is forced to refresh (i.e., change its timestamp) due to hitting the maximum closed timestamp interval (closed timestamps enable Follower Reads and Change Data Capture (CDC)). This can happen when transaction A is a long-running transaction, and there is a write by another transaction to data that A has already read. For more information, see the reference entry for RETRY_SERIALIZABLE.
Use index keys with a random distribution of values, so that transactions over different rows are more likely to operate on separate data ranges. See the SQL FAQs on row IDs for suggestions.
Place parts of the records that are modified by different transactions in different tables. That is, increase normalization. However, there are benefits and drawbacks to increasing normalization.
Benefits of increasing normalization:
Can improve performance for write-heavy workloads. This is because, with increased normalization, a given business fact must be written to one place rather than to multiple places.
Allows separate transactions to modify related underlying data without causing contention.
Reduces the chance of data inconsistency, since a given business fact must be written only to one place.
Reduces or eliminates data redundancy.
Uses less disk space.
Drawbacks of increasing normalization:
Can reduce performance for read-heavy workloads. This is because increasing normalization results in more joins, and can make the SQL more complicated in other ways.
More complex data model.
In general:
Increase normalization for write-intensive and read/write-intensive transactional workloads.
Do not increase normalization for read-intensive reporting workloads.
If the application strictly requires operating on very few different index keys, consider using ALTER ... SPLIT AT so that each index key can be served by a separate group of nodes in the cluster.
If you are working with a table that must be indexed on sequential keys, consider using hash-sharded indexes. For details about the mechanics and performance improvements of hash-sharded indexes in CockroachDB, see the blog post Hash Sharded Indexes Unlock Linear Scaling for Sequential Workloads. As part of this, we recommend doing thorough performance testing with and without hash-sharded indexes to see which works best for your application.
To avoid read hot spots:
Increase data distribution, which will allow for more ranges. The hot spot exists because the data being accessed is all co-located in one range.
Increase load balancing across more nodes in the same range. Most transactional reads must go to the leaseholder in CockroachDB, which means that opportunities for load balancing over replicas are minimal.However, the following features do permit load balancing over replicas:
Not every full table scan is an indicator of poor performance. The cost-based optimizer may decide on a full table scan when other index or join scans would result in longer execution time.Examine the statements that result in full table scans and consider adding secondary indexes.In the DB Console, visit the Schema Insights tab on the Insights page and check if there are any insights to create missing indexes. These missing index recommendations are generated based on slow statement execution. A missing index may cause a statement to have a suboptimal plan. If the execution was slow, based on the insights threshold, then it’s likely the create index recommendation is valid. If the plan had a full table scan, it’s likely that it should be removed with an index.Also see Table scans best practices.
Evaluate the schema of your table to see if you can redistribute data more evenly across multiple ranges. Specifically, make sure you have followed best practices when selecting your primary key.If your application with a small dataset (for example, a dataset that contains few index key values) is experiencing resource contention, consider splitting your tables and indexes to distribute ranges across multiple nodes to reduce resource contention.
Indicators that your tables are experiencing slow writes
If the Overview dashboard in the DB Console shows high service latency when the QPS of INSERT and UPDATE statements is high, your tables are experiencing slow writes.
Secondary indexes can improve application read performance. However, there is overhead in maintaining secondary indexes that can affect your write performance. You should profile your tables periodically to determine whether an index is worth the overhead. To identify infrequently accessed indexes that could be candidates to drop, do one of the following:
In the DB Console, visit the Schema Insights tab on the Insights page and check if there are any insights to drop unused indexes.
Indicators that your tables have too many MVCC values
In the Databases page in the DB Console, the Tables view shows the percentage of live data for each table. For example:In this example, at 37.3% the vehicles table would be considered to have a low percentage of live data. In the worst cases, the percentage can be 0%.A low percentage of live data can cause statements to scan more data (MVCC values) than required, which can reduce performance.
If you aren’t sure whether SQL query performance needs to be improved, see Identify slow queries.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"CockroachDB","colors":{"primary":"#9059FF","light":"#9059FF","dark":"#9059FF"},"logo":{"light":"https://mintcdn.com/cockroachlabs/4WvUnbVuGZfqM4kW/images/CockroachLabs_Wordmark_Black.png?fit=max\u0026auto=format\u0026n=4WvUnbVuGZfqM4kW\u0026q=85\u0026s=54ccae625c9986bf1df8ddc7b2c571f0","dark":"https://mintcdn.com/cockroachlabs/4WvUnbVuGZfqM4kW/images/CockroachLabs_Wordmark_White.png?fit=max\u0026auto=format\u0026n=4WvUnbVuGZfqM4kW\u0026q=85\u0026s=0dd9b66973a1c7d3dd72aa67b6094efe","href":"https://www.cockroachlabs.com/"},"favicon":{"light":"https://mintcdn.com/cockroachlabs/2yihO7vMXnL0G_07/images/favicon.svg?fit=max\u0026auto=format\u0026n=2yihO7vMXnL0G_07\u0026q=85\u0026s=01f9aa59c9f275e1f35cd424a27d2551","dark":"https://mintcdn.com/cockroachlabs/2yihO7vMXnL0G_07/images/favicon.svg?fit=max\u0026auto=format\u0026n=2yihO7vMXnL0G_07\u0026q=85\u0026s=01f9aa59c9f275e1f35cd424a27d2551"},"api":{"examples":{"defaults":"required","languages":["curl"]}},"appearance":{"default":"light"},"navbar":{"primary":{"type":"button","label":"Get started free","href":"https://cockroachlabs.cloud/signup?referralId=cc_nav_global\u0026_ga=2.242886210.1147139380.1759903632-41552699.1759903632"}},"footer":{"socials":{"youtube":"https://www.youtube.com/@cockroachdb","x":"https://x.com/CockroachDB","linkedin":"https://www.linkedin.com/company/cockroach-labs/mycompany/verification","instagram":"https://www.instagram.com/cockroachdb"},"links":[{"header":"Product","items":[{"label":"CockroachDB","href":"https://www.cockroachlabs.com/product"},{"label":"CockroachDB Cloud","href":"https://www.cockroachlabs.com/product/cockroachcloud"},{"label":"Compare","href":"https://www.cockroachlabs.com/compare"},{"label":"Pricing","href":"https://www.cockroachlabs.com/pricing"},{"label":"Get CockroachDB","href":"https://www.cockroachlabs.com/get-started-cockroachdb"},{"label":"Sign In","href":"https://cockroachlabs.cloud/"}]},{"header":"Resources","items":[{"label":"Guides","href":"https://resources.cockroachlabs.com/guides"},{"label":"Webinars","href":"https://www.cockroachlabs.com/community/webinars"},{"label":"Videos","href":"https://www.cockroachlabs.com/resources/video"},{"label":"Architecture Overview","href":"https://www.cockroachlabs.com/docs/stable/architecture/overview"},{"label":"FAQ","href":"https://www.cockroachlabs.com/docs/stable/frequently-asked-questions"},{"label":"Security","href":"https://www.cockroachlabs.com/security"}]},{"header":"Learn \u0026 Support","items":[{"label":"Docs","href":"https://www.cockroachlabs.com/docs"},{"label":"University","href":"https://learn.cockroachlabs.com/"},{"label":"Developers","href":"https://www.cockroachlabs.com/developers"},{"label":"Forum","href":"https://forum.cockroachlabs.com/"},{"label":"Slack","href":"https://cockroa.ch/slack"},{"label":"Support Portal","href":"https://support.cockroachlabs.com/hc/en-us"},{"label":"Contact Us","href":"https://www.cockroachlabs.com/contact"}]},{"header":"Company","items":[{"label":"About","href":"https://www.cockroachlabs.com/about"},{"label":"Blog","href":"https://www.cockroachlabs.com/blog"},{"label":"Careers","href":"https://www.cockroachlabs.com/careers"},{"label":"Customers","href":"https://www.cockroachlabs.com/customers"},{"label":"News","href":"https://www.cockroachlabs.com/press"},{"label":"Privacy","href":"https://www.cockroachlabs.com/privacy"},{"label":"Terms of Use","href":"https://www.cockroachlabs.com/website-terms-of-use"}]}]},"fonts":{"heading":{"family":"Poppins"},"body":{"family":"Open Sans"}},"styling":{"eyebrows":"breadcrumbs","codeblocks":{"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}},"latex":true},"integrations":{"gtm":{"tagId":"GTM-NR8LC4"}},"errors":{"404":{"redirect":false,"title":"Page not found","description":"The page you're looking for doesn't exist. [Return to docs home](/index.html)."}},"contextual":{"options":["copy","view","chatgpt","claude","perplexity","mcp","cursor","vscode"],"display":"header"},"interaction":{"drilldown":false},"navigation":{"global":{"anchors":[{"anchor":"University","icon":"graduation-cap","href":"https://learn.cockroachlabs.com/"}]},"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"cockroachlabs","hasAudioNarration":false,"actualSubdomain":"cockroachlabs","customDomains":["docs.cockroachlabs.com"],"gitSource":{"type":"github","owner":"cockroachlabs","repo":"docs","deployBranch":"main","contentDirectory":"cockroachlabs-preview-main","isPrivate":true,"mountPath":"","label":""},"entitlements":{"AI_CHAT":{"status":"ENABLED"},"REMOVE_BRANDING":{"status":"ENABLED"},"CONTEXTUAL_FEEDBACK":{"status":"ENABLED"},"CODE_SNIPPET_FEEDBACK":{"status":"ENABLED"},"WEB_MCP":{"status":"ENABLED"},"NARRATION":{"status":"ENABLED"}},"buildId":"6af4bb21d7a808c67a4ac795","clientVersion":"0.0.4111","searchFilterCounts":[{"language":"default","tag":"CockroachDB","count":6951},{"language":"default","tag":"Docs","count":3217},{"language":"default","tag":"SQL","count":2566},{"language":"default","tag":"Statements","count":1714},{"language":"default","tag":"Self-Hosted Deployments","count":1457},{"language":"default","tag":"Reference","count":774},{"language":"default","tag":"Cloud Deployments","count":616},{"language":"default","tag":"Endpoints","count":528},{"language":"default","tag":"Cloud API Reference","count":518},{"language":"default","tag":"Get Started","count":441}],"searchSettings":{"isFiltersEnabled":true,"showContentSnippets":true,"fullPageSearch":true}},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":true,"toggles":[],"googleFontsInlined":true},"customCss":[{"filePath":"styles.css","content":":root{--inline-code-bg-light: rgb(var(--gray-200) / 0.92);--inline-code-bg-dark: rgb(255 255 255 / 0.08)}.prose :not(pre)>code{background-color:var(--inline-code-bg-light)!important}.dark .prose :not(pre)>code{background-color:var(--inline-code-bg-dark)!important}@media (min-width: 1536px){#navbar>.max-w-8xl,[class*=\"peer-[.is-not-custom]:peer-[.is-not-center]:max-w-8xl\"]{width:100%!important;max-width:none!important}}#navigation-items{display:flex;flex-direction:column}#navigation-items>ul:not(.sidebar-group){order:1;margin-top:1.5rem}.crdb-metrics-table table{table-layout:fixed!important;width:100%!important;min-width:0!important;max-width:100%!important;border-collapse:collapse}.crdb-metrics-table table td,.crdb-metrics-table table th{min-width:0!important;overflow-wrap:anywhere;word-break:break-word}.crdb-fixed-table table{table-layout:fixed!important;width:100%!important;min-width:0!important;max-width:100%!important;border-collapse:collapse}.crdb-fixed-table table td,.crdb-fixed-table table th{min-width:0!important;overflow-wrap:anywhere;word-break:break-word}.bg-cover{background-size:cover;background-repeat:no-repeat;background-position:center center}.bg-cover__bg-3-1{background-image:url(\"https://cockroach-labs-docs.imgix.net/bg-3-1.png?auto=format,compress\u0026w=1200\u0026q=40\")}.home-header{border-radius:0.5rem;margin-bottom:2rem!important;padding:2rem}.card{border:1px solid #e5e7eb;border-radius:0.75rem;background-color:white}.dark .card{background-color:#0d1117;border-color:rgba(255, 255, 255, 0.1)}.card-link{text-decoration:none!important;overflow:hidden}.card-link:hover{outline:1px solid rgba(105, 51, 255, 0.55);outline-offset:-1px}.card-link,.card-link:hover{transform:none!important;box-shadow:none!important}.card-link a,.card-link a:hover,.card-link h3,.card-link h3:hover,.card-link p,.card-link p:hover{border:0!important;text-decoration:none!important;transform:none!important}.card-link a{display:block;width:100%}.card-link h3{font-size:1rem!important;font-weight:600!important}.card-body{padding:1.5rem}.landing-column-title{margin-bottom:1rem}.overline{text-transform:uppercase;letter-spacing:0.05em}.btn-redirect{display:inline-flex;align-items:center;gap:0.5rem;padding:0.75rem 1.5rem;border:2px solid #e5e7eb;border-radius:0.5rem;text-decoration:none;transition:border-color 0.2s}.btn-redirect:hover{border-color:#6933ff}.btn-block{display:flex;width:100%;justify-content:center}.dark .btn-redirect{border-color:rgba(255, 255, 255, 0.1)}.article-section-title{font-size:1.25rem!important}.article-lists h3{font-size:0.875rem!important;font-weight:600!important;text-transform:uppercase;letter-spacing:0.05em;color:#6b7280!important}.dark .article-lists h3{color:#9ca3af!important}.article-lists ul{font-size:0.875rem}.shadow{box-shadow:0 0.5rem 1rem rgba(0, 0, 0, 0.15)}.bg-dark-wing{background-color:#152849;border-radius:0.5rem}.text-ice-temple{color:#1bf8ec!important;display:inline-flex;align-items:center;gap:0.375rem}.text-ice-temple img{display:inline-block;margin:0}.bg-dark-wing h2{font-size:clamp(1.25rem, 1rem + 1.5vw, 1.75rem)!important}@media (max-width: 576px){.card-body.bg-dark-wing{padding:1.25rem!important}}.text-decoration-none{text-decoration:none!important}.text-muted{color:#6b7280!important}.card-link .card-desc{font-size:0.9375rem!important;font-weight:400!important;line-height:1.5!important;text-align:left!important;color:#4b5563!important;width:100%;margin-top:0.5rem}.dark .card-link .card-desc{color:#9ca3af!important}.report-tag{display:inline-block;padding:0.25rem 0.75rem;border-radius:0.25rem;background-color:rgba(84, 42, 189, 0.08);color:#542abd}.dark .report-tag{background-color:rgba(84, 42, 189, 0.3);color:#b39dff}.resilience-report-img{background-image:url(\"/images/state-resilience.png\");background-size:cover;background-position:center;min-height:150px;border-radius:0.5rem}.row{display:flex!important;flex-wrap:wrap;margin-left:-0.75rem;margin-right:-0.75rem}.display-flex{display:flex!important}.col-lg-4{flex:0 0 auto;width:100%;padding-left:0.75rem;padding-right:0.75rem}@media (min-width: 992px){.col-lg-4{width:33.333333%!important}}.col-lg-3,.col-sm-6,.col-xs-12{flex:0 0 auto;width:100%!important;padding-left:0.75rem;padding-right:0.75rem}@media (min-width: 992px){.col-lg-3{width:25%!important}}@media (min-width: 576px){.col-sm-6{width:50%!important}}.col-12{width:100%!important}.col-lg-12{width:100%;padding-left:0.75rem;padding-right:0.75rem}@media (min-width: 992px){.col-lg-12{width:100%!important}}.col-md-4,.col-md-8{flex:0 0 auto;width:100%;padding-left:0.75rem;padding-right:0.75rem}@media (min-width: 768px){.col-md-4{width:33.333333%!important}.col-md-8{width:66.666667%!important}}.h-100{height:100%}.d-flex{display:flex}.flex-column{flex-direction:column}.mb-3{margin-bottom:1rem!important}.mb-5{margin-bottom:3rem!important}.pb-5{padding-bottom:3rem!important}.mb-xl-5{margin-bottom:3rem!important}.mt-auto{margin-top:auto!important}.mt-0{margin-top:0!important}.mt-2{margin-top:0.5rem!important}.mt-3{margin-top:1rem!important}.mt-5:not(.code-block){margin-top:3rem!important}.code-block.mb-8{margin-bottom:calc(var(--spacing) * 5)}.pt-5{padding-top:3rem!important}.m-0{margin:0!important}.ml-2{margin-left:0.5rem!important}.mb-0{margin-bottom:0!important}.mb-2{margin-bottom:0.5rem!important}.mb-4{margin-bottom:1.5rem!important}.p-2{padding:0.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.ml-1{margin-left:0.25rem!important}.mr-auto{margin-right:auto!important}.justify-content-center{justify-content:center!important}.align-items-center{align-items:center!important}@media (min-width: 1200px){.p-xl-5{padding:3rem!important}}.mx-0{margin-left:0!important;margin-right:0!important}.text-center{text-align:center}.text-white{color:white!important}.text-black{color:black!important}.dark .text-black{color:white!important}.container{width:100%;max-width:1200px;margin-left:auto;margin-right:auto;padding-left:1rem;padding-right:1rem}.card-header-overlap-text{position:relative}@media (min-width: 768px){.p-md-5{padding:3rem!important}}@media (min-width: 992px){.d-lg-flex{display:flex!important}.mb-lg-0{margin-bottom:0!important}}.prose table{border-collapse:collapse!important}.prose table th,.prose table td{border:1px solid rgb(var(--gray-200))!important}.dark .prose table th,.dark .prose table td{border-color:rgb(var(--gray-700) / 0.5)!important}.prose table th{padding:0.571429em;font-weight:600;vertical-align:bottom;color:var(--tw-prose-headings);text-align:left}.prose table th.center-align{text-align:center}.prose table td{padding:0.571429em;vertical-align:baseline}[data-component-part=\"accordion-description\"]{font-size:0.875rem!important}.accordion.mb-3{margin-bottom:0.25rem!important}@media (max-width: 991.98px){[id^=\"kapa-widget-container\"] button{width:36px!important;height:36px!important;min-width:36px!important;padding:0!important;font-size:0!important}[id^=\"kapa-widget-container\"] button svg{width:18px!important;height:18px!important}[id^=\"kapa-widget-container\"] button span{display:none!important}}table.crdb-fixed-table{table-layout:fixed!important;min-width:0!important;width:100%}table.crdb-fixed-table td,table.crdb-fixed-table th{min-width:0!important;overflow-wrap:break-word;word-break:normal}.sql-grammar svg .line{fill:none;stroke:#262626}.sql-grammar svg .bold-line{stroke:#0A0A0A;shape-rendering:crispEdges;stroke-width:2}.sql-grammar svg .thin-line{stroke:#0F0F0F;shape-rendering:crispEdges}.sql-grammar svg .filled{fill:#262626;stroke:none}.sql-grammar svg text.terminal{font-family:Verdana, Sans-serif;font-size:12px;fill:#0A0A0A;font-weight:bold}.sql-grammar svg text.nonterminal{font-family:Verdana, Sans-serif;font-size:12px;fill:#0055FF}.sql-grammar svg text.regexp{font-family:Verdana, Sans-serif;font-size:12px;fill:#0F0F0F}.sql-grammar svg rect,.sql-grammar svg circle,.sql-grammar svg polygon{fill:#262626;stroke:#262626}.sql-grammar svg rect.terminal{fill:#ffffff;stroke:#262626}.sql-grammar svg rect.nonterminal{fill:#FFFFFF;stroke:#262626}.sql-grammar svg rect.text{fill:none;stroke:none}.sql-grammar svg polygon.regexp{fill:#FFFFFF;stroke:#262626}.sql-grammar svg{background-color:#ffffff}.sql-grammar a[name]::before{content:'';display:block;height:80px;margin:-80px 0 0}.sql-grammar a[name]:focus{outline:0}pre[language=\"sql\"][data-crdb-prompt-stripped] code::before{content:\"> \";color:#94e2d5;user-select:none}.mark-yes{color:#008a5e;font-weight:600}.dark .mark-yes{color:#3ddc97}"},{"filePath":"collapse-nav.css","content":"html:not(.crl-nav-off) [data-layout-item=\"sidebar\"] li[data-title]:not([data-active]):not([data-crl-keep])>button+ul,html:not(.crl-nav-off) [data-layout-item=\"mobile-nav\"] li[data-title]:not([data-active]):not([data-crl-keep])>button+ul{display:none}html:not(.crl-nav-off) [data-layout-item=\"sidebar\"] li[data-title]:not([data-active]):not([data-crl-keep])>button svg,html:not(.crl-nav-off) [data-layout-item=\"mobile-nav\"] li[data-title]:not([data-active]):not([data-crl-keep])>button svg{rotate:none!important;transform:none!important}"}],"page":{"pagePath":"docs/v23.1/performance-recipes","slug":"/docs/v23.1/performance-recipes","pageMetadata":{"title":"Performance Tuning Recipes","old_description":"Identify, diagnose, and fix common performance problems","canonical":"https://docs.cockroachlabs.com/docs/stable/performance-recipes","description":null,"href":"/docs/v23.1/performance-recipes"},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,em:`em`,h5:`h5`,li:`li`,ol:`ol`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,ul:`ul`,..._provideComponents(),...props.components},{CodeBlock,Heading,OptimizedImage,Tip}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!OptimizedImage)_missingMdxReference(`OptimizedImage`,true);if(!Tip)_missingMdxReference(`Tip`,true);return _jsxs(_Fragment,{children:[_jsx(_components.p,{children:`This page provides recipes for fixing performance issues in your applications.`}),`\n`,_jsx(Heading,{level:`2`,id:`problems`,children:`Problems`}),`\n`,_jsx(_components.p,{children:`This section describes how to use CockroachDB commands and dashboards to identify performance problems in your applications.`}),`\n`,_jsxs(`table`,{children:[_jsxs(`tr`,{children:[_jsx(`th`,{children:`Observation`}),_jsx(`th`,{children:`Diagnosis`}),_jsx(`th`,{children:`Solution`})]}),_jsxs(`tr`,{children:[_jsx(`td`,{children:_jsx(`ul`,{children:_jsx(`li`,{children:`Your application takes a long time to return results.`})})}),_jsx(`td`,{children:_jsx(`ul`,{children:_jsx(`li`,{children:`Excess network latency.`})})}),_jsx(`td`,{children:_jsx(`ul`,{children:_jsxs(`li`,{children:[`Use the correct `,_jsx(_components.a,{href:`/docs/v23.1/topology-patterns`,children:`topology pattern`}),` for your cluster.`]})})})]}),_jsxs(`tr`,{children:[_jsx(`td`,{children:_jsxs(`ul`,{children:[_jsxs(`li`,{children:[`The Transactions page in the `,_jsx(_components.a,{href:`/docs/cockroachcloud/transactions-page`,children:`CockroachDB Cloud Console`}),` or `,_jsx(_components.a,{href:`/docs/v23.1/ui-transactions-page#active-executions-table`,children:`DB Console`}),` shows transactions with `,_jsx(`code`,{children:`Waiting`}),` status.`]}),_jsxs(`li`,{children:[`Your application is experiencing degraded performance with `,_jsx(`code`,{children:`SQLSTATE: 40001`}),` and a `,_jsx(_components.a,{href:`/docs/v23.1/transaction-retry-error-reference#transaction-retry-error-reference`,children:`transaction retry error`}),` message.`]}),_jsxs(`li`,{children:[`Querying the `,_jsx(_components.a,{href:`/docs/v23.1/crdb-internal#transaction_contention_events`,children:_jsx(_components.code,{children:`crdb_internal.transaction_contention_events`})}),` table indicates that your transactions have experienced contention.`]}),_jsxs(`li`,{children:[`The SQL Statement Contention graph in the `,_jsx(_components.a,{href:`/docs/cockroachcloud/metrics-sql#sql-statement-contention`,children:`CockroachDB Cloud Console`}),` or `,_jsx(_components.a,{href:`/docs/v23.1/ui-sql-dashboard#sql-statement-contention`,children:`DB Console`}),` is showing spikes over time.`]}),_jsxs(`li`,{children:[`The Transaction Restarts graph in the `,_jsx(_components.a,{href:`/docs/cockroachcloud/metrics-sql#transaction-restarts`,children:`CockroachDB Cloud Console`}),` or `,_jsx(_components.a,{href:`/docs/v23.1/ui-sql-dashboard#transaction-restarts`,children:`DB Console`}),` is showing spikes in retries over time.`]})]})}),_jsx(`td`,{children:_jsx(`ul`,{children:_jsxs(`li`,{children:[`Your application is experiencing `,_jsx(_components.a,{href:`/docs/v23.1/performance-best-practices-overview#transaction-contention`,children:`transaction contention`}),`.`]})})}),_jsx(`td`,{children:_jsx(`ul`,{children:_jsx(`li`,{children:_jsx(`a`,{href:`#transaction-contention`,children:`Reduce transaction contention.`})})})})]}),_jsxs(`tr`,{children:[_jsx(`td`,{children:_jsxs(`ul`,{children:[_jsxs(`li`,{children:[`The `,_jsx(`b`,{children:`Hot Ranges`}),` page (DB Console) displays a higher-than-expected QPS for a range.`]}),_jsxs(`li`,{children:[`The `,_jsx(`b`,{children:`Key Visualizer`}),` (DB Console) shows ranges with much higher-than-average write rates for the cluster.`]})]})}),_jsx(`td`,{children:_jsx(`ul`,{children:_jsxs(`li`,{children:[`Your cluster has `,_jsx(_components.a,{href:`/docs/v23.1/performance-best-practices-overview#hot-spots`,children:`hot spots`}),`.`]})})}),_jsx(`td`,{children:_jsx(`ul`,{children:_jsxs(`li`,{children:[_jsx(`a`,{href:`#hot-spots`,children:`Reduce hot spots`}),`.`]})})})]}),_jsxs(`tr`,{children:[_jsx(`td`,{children:_jsxs(`ul`,{children:[_jsxs(`li`,{children:[`The statement plan produced by `,_jsx(_components.a,{href:`/docs/v23.1/explain`,children:_jsx(_components.code,{children:`EXPLAIN`})}),` or `,_jsx(_components.a,{href:`/docs/v23.1/explain-analyze`,children:_jsx(_components.code,{children:`EXPLAIN ANALYZE`})}),` indicates that the statement uses a full table scan.`]}),_jsxs(`li`,{children:[`Querying the `,_jsx(`code`,{children:`crdb_internal.node_statement_statistics`}),` table indicates that you have full table scans in some statement’s plans.`]}),_jsxs(`li`,{children:[`Viewing the statement plan on the `,_jsx(_components.a,{href:`/docs/v23.1/ui-statements-page#statement-fingerprint-page`,children:`Statement Fingerprint page`}),` in the DB Console indicates that the plan contains full table scans.`]}),_jsxs(`li`,{children:[`Running the `,_jsx(_components.a,{href:`/docs/v23.1/show-full-table-scans`,children:_jsx(_components.code,{children:`SHOW FULL TABLE SCANS`})}),` statement returns results.`]}),_jsxs(`li`,{children:[`The `,_jsx(_components.a,{href:`/docs/v23.1/ui-sql-dashboard`,children:`Full Table/Index Scans graph`}),` in the DB Console is showing spikes over time.`]})]})}),_jsx(`td`,{children:_jsx(`ul`,{children:_jsx(`li`,{children:`Poor quality statement plans retrieve more rows than are required, leading to longer execution times.`})})}),_jsx(`td`,{children:_jsx(`ul`,{children:_jsx(`li`,{children:_jsx(`a`,{href:`#statements-with-full-table-scans`,children:`Use indexes to reduce full table scans.`})})})})]}),_jsxs(`tr`,{children:[_jsx(`td`,{children:_jsxs(`ul`,{children:[_jsxs(`li`,{children:[`The `,_jsx(_components.a,{href:`/docs/v23.1/ui-hardware-dashboard`,children:`Hardware metrics dashboard`}),` in the DB Console shows high resource usage per node.`]}),_jsxs(`li`,{children:[`The Problem Ranges report on the `,_jsx(_components.a,{href:`/docs/v23.1/ui-debug-pages`,children:`Advanced Debug page`}),` in the DB Console indicates a high number of queries per second on a subset of ranges or nodes.`]})]})}),_jsx(`td`,{children:_jsx(`ul`,{children:_jsx(`li`,{children:`You have resource contention.`})})}),_jsx(`td`,{children:_jsx(`ul`,{children:_jsx(`li`,{children:_jsx(`a`,{href:`#suboptimal-primary-keys`,children:`Improve primary key usage.`})})})})]}),_jsxs(`tr`,{children:[_jsx(`td`,{children:_jsx(`ul`,{children:_jsxs(`li`,{children:[`The `,_jsx(_components.a,{href:`/docs/v23.1/ui-overview-dashboard#`,children:`Overview dashboard`}),` in the DB Console shows high service latency and QPS for `,_jsx(`code`,{children:`INSERT`}),` and `,_jsx(`code`,{children:`UPDATE`}),` statements.`]})})}),_jsx(`td`,{children:_jsx(`ul`,{children:_jsx(`li`,{children:`Your tables have long write times.`})})}),_jsx(`td`,{children:_jsx(`ul`,{children:_jsx(`li`,{children:_jsx(`a`,{href:`#slow-writes`,children:`Remove unnecessary indexes.`})})})})]}),_jsxs(`tr`,{children:[_jsx(`td`,{children:_jsx(`ul`,{children:_jsx(`li`,{children:`You experience high latency on queries that cannot be explained by high contention or a suboptimal query plan. You might also see high CPU on one or more nodes.`})})}),_jsx(`td`,{children:_jsx(`ul`,{children:_jsxs(`li`,{children:[`You may be scanning over large numbers of `,_jsx(_components.a,{href:`/docs/v23.1/architecture/storage-layer#mvcc`,children:`MVCC versions`}),`. This is similar to how a full table scan can be slow.`]})})}),_jsx(`td`,{children:_jsx(`ul`,{children:_jsx(`li`,{children:_jsx(`a`,{href:`#too-many-mvcc-values`,children:`Configure CockroachDB to purge unneeded MVCC values.`})})})})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`solutions`,children:`Solutions`}),`\n`,_jsx(_components.p,{children:`This section provides solutions for common performance issues in your applications.`}),`\n`,_jsx(Heading,{level:`3`,id:`transaction-contention`,children:`Transaction contention`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`/docs/v23.1/performance-best-practices-overview#transaction-contention`,children:`Transaction contention`}),` is a state of conflict that occurs when:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`A `,_jsx(_components.a,{href:`/docs/v23.1/transactions`,children:`transaction`}),` is unable to complete due to another concurrent or recent transaction attempting to write to the same data. This is also called `,_jsx(_components.em,{children:`lock contention`}),`.`]}),`\n`,_jsxs(_components.li,{children:[`A transaction is `,_jsx(_components.a,{href:`/docs/v23.1/transactions#automatic-retries`,children:`automatically retried`}),` because it could not be placed into a `,_jsx(_components.a,{href:`/docs/v23.1/demo-serializable`,children:`serializable ordering`}),` among all of the currently-executing transactions. If the automatic retry is not possible or fails, a `,_jsx(_components.a,{href:`/docs/v23.1/transaction-retry-error-reference`,children:_jsx(_components.em,{children:`transaction retry error`})}),` is emitted to the client, requiring the client application to `,_jsx(_components.a,{href:`/docs/v23.1/transaction-retry-error-reference#client-side-retry-handling`,children:`retry the transaction`}),`.`]}),`\n`]}),`\n`,_jsx(Heading,{level:`4`,id:`indicators-that-your-application-is-experiencing-transaction-contention`,children:`Indicators that your application is experiencing transaction contention`}),`\n`,_jsx(`a`,{id:`waiting-transaction`}),`\n`,_jsx(_components.h5,{children:`Waiting transaction`}),`\n`,_jsxs(_components.p,{children:[`These are indicators that a transaction is trying to access a row that has been `,_jsx(_components.a,{href:`/docs/v23.1/architecture/transaction-layer#writing`,children:`“locked”`}),` by another, concurrent write transaction.`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`The `,_jsx(_components.strong,{children:`Active Executions`}),` table on the `,_jsx(_components.strong,{children:`Transactions`}),` page (`,_jsx(_components.a,{href:`/docs/cockroachcloud/transactions-page`,children:`CockroachDB Cloud Console`}),` or `,_jsx(_components.a,{href:`/docs/v23.1/ui-transactions-page#active-executions-table`,children:`DB Console`}),`) shows transactions with `,_jsx(_components.code,{children:`Waiting`}),` in the `,_jsx(_components.strong,{children:`Status`}),` column. You can sort the table by `,_jsx(_components.strong,{children:`Time Spent Waiting`}),`.`]}),`\n`,_jsxs(_components.li,{children:[`Querying the `,_jsx(_components.a,{href:`/docs/v23.1/crdb-internal#cluster_locks`,children:_jsx(_components.code,{children:`crdb_internal.cluster_locks`})}),` table shows transactions where `,_jsx(_components.a,{href:`/docs/v23.1/crdb-internal#cluster-locks-columns`,children:_jsx(_components.code,{children:`granted`})}),` is `,_jsx(_components.code,{children:`false`}),`.`]}),`\n`]}),`\n`,_jsx(_components.p,{children:`These are indicators that lock contention occurred in the past:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`Querying the `,_jsx(_components.a,{href:`/docs/v23.1/crdb-internal#transaction_contention_events`,children:_jsx(_components.code,{children:`crdb_internal.transaction_contention_events`})}),` table indicates that your transactions have experienced lock contention.`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`This is also shown in the `,_jsx(_components.strong,{children:`Transaction Executions`}),` view on the `,_jsx(_components.strong,{children:`Insights`}),` page (`,_jsx(_components.a,{href:`/docs/cockroachcloud/insights-page#transaction-executions-view`,children:`CockroachDB Cloud Console`}),` and `,_jsx(_components.a,{href:`/docs/v23.1/ui-insights-page#transaction-executions-view`,children:`DB Console`}),`). Transaction executions will display the `,_jsx(_components.strong,{children:`High Contention`}),` insight.`]}),`\n`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.strong,{children:`SQL Statement Contention`}),` graph (`,_jsx(_components.a,{href:`/docs/cockroachcloud/metrics-sql#sql-statement-contention`,children:`CockroachDB Cloud Console`}),` and `,_jsx(_components.a,{href:`/docs/v23.1/ui-sql-dashboard#sql-statement-contention`,children:`DB Console`}),`) is showing spikes over time.`]}),`\n`,_jsx(OptimizedImage,{src:`https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui-statement-contention.png?fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=fbc06eb98dbc6aa7f851716e6f5dda78`,alt:`SQL Statement Contention graph in DB Console`,\"data-og-width\":`1007`,width:`1007`,\"data-og-height\":`432`,height:`432`,\"data-path\":`images/common/ui-statement-contention.png`,\"data-optimize\":`true`,\"data-opv\":`3`,srcset:`https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui-statement-contention.png?w=280\u0026fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=db24ee00308996cf0be2eff5497a79b4 280w, https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui-statement-contention.png?w=560\u0026fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=900402fc90f86c4f1d3f209ead482980 560w, https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui-statement-contention.png?w=840\u0026fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=4d7dd2b6d41152955c8b24f93b96a8ba 840w, https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui-statement-contention.png?w=1100\u0026fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=c6d73a10a16b2ba2ec59e37977e1cae7 1100w, https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui-statement-contention.png?w=1650\u0026fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=7480a5fe8ed6aa7274178e8513aa87df 1650w, https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui-statement-contention.png?w=2500\u0026fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=b0b3d46517d7acbb1f7fe25a6f8bd0e9 2500w`}),`\n`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`If a long-running transaction is waiting due to `,_jsx(_components.a,{href:`/docs/v23.1/performance-best-practices-overview#transaction-contention`,children:`lock contention`}),`:`]}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`#identify-conflicting-transactions`,children:`Identify the blocking transaction`}),`.`]}),`\n`,_jsxs(_components.li,{children:[`Evaluate whether you can cancel the transaction. If so, `,_jsx(_components.a,{href:`#cancel-a-blocking-transaction`,children:`cancel it`}),` to unblock the waiting transaction.`]}),`\n`,_jsxs(_components.li,{children:[`Optimize the transaction to `,_jsx(_components.a,{href:`#reduce-transaction-contention`,children:`reduce further contention`}),`. In particular, break down larger transactions such as `,_jsx(_components.a,{href:`/docs/v23.1/bulk-delete-data`,children:`bulk deletes`}),` into smaller ones to have transactions hold locks for a shorter duration, and use `,_jsx(_components.a,{href:`/docs/v23.1/as-of-system-time`,children:`historical reads`}),` when possible to reduce conflicts with other writes.`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`If lock contention occurred in the past, you can `,_jsx(_components.a,{href:`#identify-transactions-and-objects-that-experienced-lock-contention`,children:`identify the transactions and objects that experienced lock contention`}),`.`]}),`\n`,_jsx(`a`,{id:`transaction-retry-error`}),`\n`,_jsx(_components.h5,{children:`Transaction retry error`}),`\n`,_jsxs(_components.p,{children:[`These are indicators that a transaction has failed due to `,_jsx(_components.a,{href:`/docs/v23.1/performance-best-practices-overview#transaction-contention`,children:`contention`}),`.`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`A `,_jsx(_components.a,{href:`/docs/v23.1/transaction-retry-error-reference`,children:`transaction retry error`}),` with `,_jsx(_components.code,{children:`SQLSTATE: 40001`}),`, the string `,_jsx(_components.a,{href:`/docs/v23.1/common-errors#restart-transaction`,children:_jsx(_components.code,{children:`restart transaction`})}),`, and an error code such as `,_jsx(_components.a,{href:`/docs/v23.1/transaction-retry-error-reference#retry_write_too_old`,children:_jsx(_components.code,{children:`RETRY_WRITE_TOO_OLD`})}),` or `,_jsx(_components.a,{href:`/docs/v23.1/transaction-retry-error-reference#retry_serializable`,children:_jsx(_components.code,{children:`RETRY_SERIALIZABLE`})}),`, is emitted to the client.`]}),`\n`,_jsxs(_components.li,{children:[`An event with `,_jsx(_components.code,{children:`TransactionRetryWithProtoRefreshError`}),` is emitted to the CockroachDB `,_jsx(_components.a,{href:`/docs/v23.1/logging-use-cases#example-slow-sql-query`,children:`logs`}),`.`]}),`\n`]}),`\n`,_jsx(_components.p,{children:`These are indicators that transaction retries occurred in the past:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`The `,_jsx(_components.strong,{children:`Transaction Restarts`}),` graph (`,_jsx(_components.a,{href:`/docs/cockroachcloud/metrics-sql#transaction-restarts`,children:`CockroachDB Cloud Console`}),` and `,_jsx(_components.a,{href:`/docs/v23.1/ui-sql-dashboard#transaction-restarts`,children:`DB Console`}),` is showing spikes in transaction retries over time.`]}),`\n`]}),`\n`,_jsx(_components.p,{children:`In most cases, the correct actions to take when encountering transaction retry errors are:`}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`Update your application to support `,_jsx(_components.a,{href:`/docs/v23.1/transaction-retry-error-reference#client-side-retry-handling`,children:`client-side retry handling`}),` when transaction retry errors are encountered. Follow the guidance for the `,_jsx(_components.a,{href:`/docs/v23.1/transaction-retry-error-reference#transaction-retry-error-reference`,children:`specific error type`}),`.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`Take steps to `,_jsx(_components.a,{href:`/docs/v23.1/transaction-retry-error-reference#minimize-transaction-retry-errors`,children:`minimize transaction retry errors`}),` in the first place. This means reducing transaction contention overall, and increasing the likelihood that CockroachDB can `,_jsx(_components.a,{href:`/docs/v23.1/transactions#automatic-retries`,children:`automatically retry`}),` a failed transaction.`]}),`\n`]}),`\n`]}),`\n`,_jsx(Heading,{level:`4`,id:`fix-transaction-contention-problems`,children:`Fix transaction contention problems`}),`\n`,_jsxs(_components.p,{children:[`Identify the transactions that are in conflict, and unblock them if possible. In general, take steps to `,_jsx(_components.a,{href:`#reduce-transaction-contention`,children:`reduce transaction contention`}),`.`]}),`\n`,_jsxs(_components.p,{children:[`In addition, implement `,_jsx(_components.a,{href:`/docs/v23.1/transaction-retry-error-reference#client-side-retry-handling`,children:`client-side retry handling`}),` so that your application can respond to `,_jsx(_components.a,{href:`/docs/v23.1/transaction-retry-error-reference`,children:`transaction retry errors`}),` that are emitted when CockroachDB cannot `,_jsx(_components.a,{href:`/docs/v23.1/transactions#automatic-retries`,children:`automatically retry`}),` a transaction.`]}),`\n`,_jsx(`a`,{id:`identify-conflicting-transactions`}),`\n`,_jsx(_components.h5,{children:`Identify conflicting transactions`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`In the `,_jsx(_components.strong,{children:`Active Executions`}),` table on the `,_jsx(_components.strong,{children:`Transactions`}),` page (`,_jsx(_components.a,{href:`/docs/cockroachcloud/transactions-page`,children:`CockroachDB Cloud Console`}),` or `,_jsx(_components.a,{href:`/docs/v23.1/ui-transactions-page#active-executions-table`,children:`DB Console`}),`), look for a `,_jsx(_components.strong,{children:`waiting`}),` transaction (`,_jsx(_components.code,{children:`Waiting`}),` status).`]}),`\n`]}),`\n`,_jsx(Tip,{children:_jsxs(_components.p,{children:[`If you see many waiting transactions, a single long-running transaction may be blocking transactions that are, in turn, blocking others. In this case, sort the table by `,_jsx(_components.strong,{children:`Time Spent Waiting`}),` to find the transaction that has been waiting for the longest amount of time. Unblocking this transaction may unblock the other transactions.`]})}),`\n`,_jsx(_components.p,{children:`Click the transaction’s execution ID and view the following transaction execution details:`}),`\n`,_jsx(OptimizedImage,{src:`https://mintcdn.com/cockroachlabs/wEBM45Ur1WANJGkg/images/common/waiting-transaction.png?fit=max\u0026auto=format\u0026n=wEBM45Ur1WANJGkg\u0026q=85\u0026s=c02b5adbc1569844ad38cc2687b83bd6`,alt:`Movr rides transactions`,\"data-og-width\":`3238`,width:`3238`,\"data-og-height\":`1716`,height:`1716`,\"data-path\":`images/common/waiting-transaction.png`,\"data-optimize\":`true`,\"data-opv\":`3`,srcset:`https://mintcdn.com/cockroachlabs/wEBM45Ur1WANJGkg/images/common/waiting-transaction.png?w=280\u0026fit=max\u0026auto=format\u0026n=wEBM45Ur1WANJGkg\u0026q=85\u0026s=504d7d0fa3212f63b737e5474a4dc341 280w, https://mintcdn.com/cockroachlabs/wEBM45Ur1WANJGkg/images/common/waiting-transaction.png?w=560\u0026fit=max\u0026auto=format\u0026n=wEBM45Ur1WANJGkg\u0026q=85\u0026s=4a1d7d7c46278dbc9a49c2bef67604c0 560w, https://mintcdn.com/cockroachlabs/wEBM45Ur1WANJGkg/images/common/waiting-transaction.png?w=840\u0026fit=max\u0026auto=format\u0026n=wEBM45Ur1WANJGkg\u0026q=85\u0026s=3eebe0c444a8ab7bc46a3e5dbb0af21c 840w, https://mintcdn.com/cockroachlabs/wEBM45Ur1WANJGkg/images/common/waiting-transaction.png?w=1100\u0026fit=max\u0026auto=format\u0026n=wEBM45Ur1WANJGkg\u0026q=85\u0026s=2097816ab1fefda44f2165b99f9de26e 1100w, https://mintcdn.com/cockroachlabs/wEBM45Ur1WANJGkg/images/common/waiting-transaction.png?w=1650\u0026fit=max\u0026auto=format\u0026n=wEBM45Ur1WANJGkg\u0026q=85\u0026s=681032a3b97d9d151e58e2afc99f5416 1650w, https://mintcdn.com/cockroachlabs/wEBM45Ur1WANJGkg/images/common/waiting-transaction.png?w=2500\u0026fit=max\u0026auto=format\u0026n=wEBM45Ur1WANJGkg\u0026q=85\u0026s=bdcf4aae16239e8495498a4510b789a8 2500w`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Last Retry Reason`}),` shows the last `,_jsx(_components.a,{href:`#transaction-retry-error`,children:`transaction retry error`}),` received for the transaction, if applicable.`]}),`\n`,_jsxs(_components.li,{children:[`The details of the `,_jsx(_components.strong,{children:`blocking`}),` transaction, directly below the `,_jsx(_components.strong,{children:`Contention Insights`}),` section. Click the blocking transaction to view its details.`]}),`\n`]}),`\n`,_jsx(`a`,{id:`cancel-a-blocking-transaction`}),`\n`,_jsx(_components.h5,{children:`Cancel a blocking transaction`}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[_jsxs(_components.a,{href:`#identify-conflicting-transactions`,children:[`Identify the `,_jsx(_components.strong,{children:`blocking`}),` transaction`]}),` and view its transaction execution details.`]}),`\n`,_jsxs(_components.li,{children:[`Click its `,_jsx(_components.strong,{children:`Session ID`}),` to open the `,_jsx(_components.strong,{children:`Session Details`}),` page.`,`\n`,_jsx(OptimizedImage,{src:`https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui-sessions-details-page.png?fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=457e6606ddd39d2fd5c72c873df72f02`,alt:`Sessions Details Page`,\"data-og-width\":`2164`,width:`2164`,\"data-og-height\":`2176`,height:`2176`,\"data-path\":`images/common/ui-sessions-details-page.png`,\"data-optimize\":`true`,\"data-opv\":`3`,srcset:`https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui-sessions-details-page.png?w=280\u0026fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=d4a7428a2bdab7d13c5e94e637b016d8 280w, https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui-sessions-details-page.png?w=560\u0026fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=2e78fc9964981844bec64a0e86dadfe6 560w, https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui-sessions-details-page.png?w=840\u0026fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=1155f907aba2f66345f4c0bb63b6c961 840w, https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui-sessions-details-page.png?w=1100\u0026fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=7d7fda3128a889739ca1b92d6b1cf68e 1100w, https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui-sessions-details-page.png?w=1650\u0026fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=cd663dbb8483f459749bfb09cfd574c3 1650w, https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui-sessions-details-page.png?w=2500\u0026fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=17cd7d1e2fa6f30f50b37ee83c8803b9 2500w`}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`Click `,_jsx(_components.strong,{children:`Cancel Statement`}),` to cancel the `,_jsx(_components.strong,{children:`Most Recent Statement`}),` and thus the transaction, or click `,_jsx(_components.strong,{children:`Cancel Session`}),` to cancel the session issuing the transaction.`]}),`\n`]}),`\n`,_jsx(`a`,{id:`identify-transactions-and-objects-that-experienced-lock-contention`}),`\n`,_jsx(_components.h5,{children:`Identify transactions and objects that experienced lock contention`}),`\n`,_jsxs(_components.p,{children:[`To identify transactions that experienced `,_jsx(_components.a,{href:`/docs/v23.1/performance-best-practices-overview#transaction-contention`,children:`lock contention`}),` in the past:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`In the `,_jsx(_components.strong,{children:`Transaction Executions`}),` view on the `,_jsx(_components.strong,{children:`Insights`}),` page (`,_jsx(_components.a,{href:`/docs/cockroachcloud/insights-page#transaction-executions-view`,children:`CockroachDB Cloud Console`}),` and `,_jsx(_components.a,{href:`/docs/v23.1/ui-insights-page#transaction-executions-view`,children:`DB Console`}),`), look for a transaction with the `,_jsx(_components.strong,{children:`High Contention`}),` insight. Click the transaction’s execution ID and view the transaction execution details, including the details of the blocking transaction.`]}),`\n`,_jsxs(_components.li,{children:[`Visit the `,_jsx(_components.strong,{children:`Transactions`}),` page (`,_jsx(_components.a,{href:`/docs/cockroachcloud/transactions-page`,children:`CockroachDB Cloud Console`}),` and `,_jsx(_components.a,{href:`/docs/v23.1/ui-transactions-page`,children:`DB Console`}),`) and sort transactions by `,_jsx(_components.strong,{children:`Contention Time`}),`.`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`To view tables and indexes that experienced `,_jsx(_components.a,{href:`/docs/v23.1/performance-best-practices-overview#transaction-contention`,children:`contention`}),`:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`Query the `,_jsx(_components.a,{href:`/docs/v23.1/crdb-internal#transaction_contention_events`,children:_jsx(_components.code,{children:`crdb_internal.transaction_contention_events`})}),` table to view `,_jsx(_components.a,{href:`/docs/v23.1/crdb-internal`,children:`transactions that have blocked other transactions`}),`.`]}),`\n`,_jsxs(_components.li,{children:[`Query the `,_jsx(_components.a,{href:`/docs/v23.1/crdb-internal#cluster_contended_tables`,children:_jsx(_components.code,{children:`crdb_internal.cluster_contended_tables`})}),` table to `,_jsx(_components.a,{href:`/docs/v23.1/crdb-internal#view-all-tables-that-have-experienced-contention`,children:`view all tables that have experienced contention`}),`.`]}),`\n`,_jsxs(_components.li,{children:[`Query the `,_jsx(_components.a,{href:`/docs/v23.1/crdb-internal#cluster_contended_indexes`,children:_jsx(_components.code,{children:`crdb_internal.cluster_contended_indexes`})}),` table to `,_jsx(_components.a,{href:`/docs/v23.1/crdb-internal#view-all-indexes-that-have-experienced-contention`,children:`view all indexes that have experienced contention`}),`.`]}),`\n`,_jsxs(_components.li,{children:[`Query the `,_jsx(_components.a,{href:`/docs/v23.1/crdb-internal#cluster_contention_events`,children:_jsx(_components.code,{children:`crdb_internal.cluster_contention_events`})}),` table\nto `,_jsx(_components.a,{href:`/docs/v23.1/crdb-internal`,children:`view the tables, indexes, and transactions with the most time under contention`}),`.`]}),`\n`]}),`\n`,_jsx(`a`,{id:`reduce-transaction-contention`}),`\n`,_jsx(_components.h5,{children:`Reduce transaction contention`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`/docs/v23.1/performance-best-practices-overview#transaction-contention`,children:`Contention`}),` is often reported after it has already resolved. Therefore, preventing contention before it affects your cluster’s performance is a more effective approach:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`Limit the number of affected rows by following `,_jsx(_components.a,{href:`/docs/v23.1/apply-statement-performance-rules`,children:`optimizing queries`}),` (e.g., avoiding full scans, creating secondary indexes, etc.). Not only will transactions run faster, lock fewer rows, and hold locks for a shorter duration, but the chances of `,_jsx(_components.a,{href:`/docs/v23.1/architecture/transaction-layer#read-refreshing`,children:`read invalidation`}),` when the transaction’s `,_jsx(_components.a,{href:`/docs/v23.1/architecture/transaction-layer#timestamp-cache`,children:`timestamp is pushed`}),`, due to a conflicting write, are decreased because of a smaller read set (i.e., a smaller number of rows read).`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`Break down larger transactions (e.g., `,_jsx(_components.a,{href:`/docs/v23.1/bulk-delete-data`,children:`bulk deletes`}),`) into smaller ones to have transactions hold locks for a shorter duration. For example, use `,_jsx(_components.a,{href:`/docs/v23.1/common-table-expressions`,children:`common table expressions`}),` to group multiple clauses together in a single SQL statement. This will also decrease the likelihood of `,_jsx(_components.a,{href:`/docs/v23.1/architecture/transaction-layer#timestamp-cache`,children:`pushed timestamps`}),`. For instance, as the size of writes (number of rows written) decreases, the chances of the transaction’s timestamp getting bumped by concurrent reads decreases.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`Use `,_jsx(_components.a,{href:`/docs/v23.1/select-for-update`,children:_jsx(_components.code,{children:`SELECT FOR UPDATE`})}),` to aggressively lock rows that will later be updated in the transaction. Updates must operate on the most recent version of a row, so a concurrent write to the row will cause a retry error (`,_jsx(_components.a,{href:`/docs/v23.1/transaction-retry-error-reference#retry_write_too_old`,children:_jsx(_components.code,{children:`RETRY_WRITE_TOO_OLD`})}),`). Locking early in the transaction forces concurrent writers to block until the transaction is finished, which prevents the retry error. Note that this locks the rows for the duration of the transaction; whether this is tenable will depend on your workload. For more information, see `,_jsxs(_components.a,{href:`https://www.cockroachlabs.com/blog/when-and-why-to-use-select-for-update-in-cockroachdb/`,children:[`When and why to use `,_jsx(_components.code,{children:`SELECT FOR UPDATE`}),` in CockroachDB`]}),`.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`Use historical reads (`,_jsx(_components.a,{href:`/docs/v23.1/as-of-system-time`,children:_jsx(_components.code,{children:`SELECT ... AS OF SYSTEM TIME`})}),`), preferably `,_jsx(_components.a,{href:`/docs/v23.1/follower-reads#when-to-use-bounded-staleness-reads`,children:`bounded staleness reads`}),` or `,_jsx(_components.a,{href:`/docs/v23.1/follower-reads#run-queries-that-use-exact-staleness-follower-reads`,children:`exact staleness with follower reads`}),` when possible to reduce conflicts with other writes. This reduces the likelihood of `,_jsx(_components.a,{href:`/docs/v23.1/transaction-retry-error-reference#retry_serializable`,children:_jsx(_components.code,{children:`RETRY_SERIALIZABLE`})}),` errors as fewer writes will happen at the historical timestamp. More specifically, writes’ timestamps are less likely to be pushed by historical reads as they would `,_jsx(_components.a,{href:`/docs/v23.1/architecture/transaction-layer#transaction-conflicts`,children:`when the read has a higher priority level`}),`. Note that if the `,_jsx(_components.code,{children:`AS OF SYSTEM TIME`}),` value is below the closed timestamp, the read cannot be invalidated.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`When replacing values in a row, use `,_jsx(_components.a,{href:`/docs/v23.1/upsert`,children:_jsx(_components.code,{children:`UPSERT`})}),` and specify values for all columns in the inserted rows. This will usually have the best performance under contention, compared to combinations of `,_jsx(_components.a,{href:`/docs/v23.1/select-clause`,children:_jsx(_components.code,{children:`SELECT`})}),`, `,_jsx(_components.a,{href:`/docs/v23.1/insert`,children:_jsx(_components.code,{children:`INSERT`})}),`, and `,_jsx(_components.a,{href:`/docs/v23.1/update`,children:_jsx(_components.code,{children:`UPDATE`})}),`.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`If applicable to your workload, assign `,_jsx(_components.a,{href:`/docs/v23.1/column-families#default-behavior`,children:`column families`}),` and separate columns that are frequently read and written into separate columns. Transactions will operate on disjoint column families and reduce the likelihood of conflicts.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`As a last resort, consider adjusting the `,_jsx(_components.a,{href:`/docs/v23.1/architecture/transaction-layer#closed-timestamps`,children:`closed timestamp interval`}),` using the `,_jsx(_components.code,{children:`kv.closed_timestamp.target_duration`}),` `,_jsx(_components.a,{href:`/docs/v23.1/cluster-settings`,children:`cluster setting`}),` to reduce the likelihood of long-running write transactions having their `,_jsx(_components.a,{href:`/docs/v23.1/architecture/transaction-layer#timestamp-cache`,children:`timestamps pushed`}),`. This setting should be carefully adjusted if `,_jsx(_components.strong,{children:`no other mitigations are available`}),` because there can be downstream implications (e.g., historical reads, change data capture feeds, statistics collection, handling zone configurations, etc.). For example, a transaction `,_jsx(_components.em,{children:`A`}),` is forced to refresh (i.e., change its timestamp) due to hitting the maximum `,_jsx(_components.a,{href:`/docs/v23.1/architecture/transaction-layer#closed-timestamps`,children:_jsx(_components.em,{children:`closed timestamp`})}),` interval (closed timestamps enable `,_jsx(_components.a,{href:`/docs/v23.1/follower-reads#how-stale-follower-reads-work`,children:`Follower Reads`}),` and `,_jsx(_components.a,{href:`/docs/v23.1/change-data-capture-overview`,children:`Change Data Capture (CDC)`}),`). This can happen when transaction `,_jsx(_components.em,{children:`A`}),` is a long-running transaction, and there is a write by another transaction to data that `,_jsx(_components.em,{children:`A`}),` has already read. For more information, see the reference entry for `,_jsx(_components.a,{href:`/docs/v23.1/transaction-retry-error-reference#retry_serializable`,children:_jsx(_components.code,{children:`RETRY_SERIALIZABLE`})}),`.`]}),`\n`]}),`\n`]}),`\n`,_jsx(Heading,{level:`3`,id:`hot-spots`,children:`Hot spots`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`/docs/v23.1/performance-best-practices-overview#hot-spots`,children:`Hot spots`}),` are a symptom of `,_jsx(_components.em,{children:`resource contention`}),` and can create problems as requests increase, including excessive `,_jsx(_components.a,{href:`#transaction-contention`,children:`transaction contention`}),`.`]}),`\n`,_jsx(Heading,{level:`4`,id:`indicators-that-your-cluster-has-hot-spots`,children:`Indicators that your cluster has hot spots`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`The `,_jsx(_components.strong,{children:`CPU Percent`}),` graph on the `,_jsx(_components.a,{href:`/docs/v23.1/ui-hardware-dashboard`,children:_jsx(_components.strong,{children:`Hardware`})}),` and `,_jsx(_components.a,{href:`/docs/v23.1/ui-overload-dashboard`,children:_jsx(_components.strong,{children:`Overload`})}),` dashboards (DB Console) shows spikes in CPU usage.`]}),`\n`,_jsxs(_components.li,{children:[`The `,_jsx(_components.strong,{children:`Hot Ranges`}),` list on the `,_jsxs(_components.a,{href:`/docs/v23.1/ui-hot-ranges-page`,children:[_jsx(_components.strong,{children:`Hot Ranges`}),` page`]}),` (DB Console) displays a higher-than-expected QPS for a range.`]}),`\n`,_jsxs(_components.li,{children:[`The `,_jsx(_components.a,{href:`/docs/v23.1/ui-key-visualizer`,children:_jsx(_components.strong,{children:`Key Visualizer`})}),` (DB Console) shows `,_jsx(_components.a,{href:`/docs/v23.1/ui-key-visualizer#identifying-hot-spots`,children:`ranges with much higher-than-average write rates`}),` for the cluster.`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`If you find hot spots, use the `,_jsx(_components.a,{href:`/docs/v23.1/ui-hot-ranges-page#range-report`,children:_jsx(_components.strong,{children:`Range Report`})}),` and `,_jsx(_components.a,{href:`/docs/v23.1/ui-key-visualizer`,children:_jsx(_components.strong,{children:`Key Visualizer`})}),` to identify the ranges with excessive traffic. Then take steps to `,_jsx(_components.a,{href:`#reduce-hot-spots`,children:`reduce hot spots`}),`.`]}),`\n`,_jsx(Heading,{level:`4`,id:`reduce-hot-spots`,children:`Reduce hot spots`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`Use index keys with a random distribution of values, so that transactions over different rows are more likely to operate on separate data ranges. See the `,_jsx(_components.a,{href:`/docs/v23.1/sql-faqs#how-do-i-auto-generate-unique-row-ids-in-cockroachdb`,children:`SQL FAQs`}),` on row IDs for suggestions.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`Place parts of the records that are modified by different transactions in different tables. That is, increase `,_jsx(_components.a,{href:`https://wikipedia.org/wiki/Database_normalization`,children:`normalization`}),`. However, there are benefits and drawbacks to increasing normalization.`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`\n`,_jsx(_components.p,{children:`Benefits of increasing normalization:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Can improve performance for write-heavy workloads. This is because, with increased normalization, a given business fact must be written to one place rather than to multiple places.`}),`\n`,_jsxs(_components.li,{children:[`Allows separate transactions to modify related underlying data without causing `,_jsx(_components.a,{href:`#transaction-contention`,children:`contention`}),`.`]}),`\n`,_jsx(_components.li,{children:`Reduces the chance of data inconsistency, since a given business fact must be written only to one place.`}),`\n`,_jsx(_components.li,{children:`Reduces or eliminates data redundancy.`}),`\n`,_jsx(_components.li,{children:`Uses less disk space.`}),`\n`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsx(_components.p,{children:`Drawbacks of increasing normalization:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Can reduce performance for read-heavy workloads. This is because increasing normalization results in more joins, and can make the SQL more complicated in other ways.`}),`\n`,_jsx(_components.li,{children:`More complex data model.`}),`\n`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsx(_components.p,{children:`In general:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Increase normalization for write-intensive and read/write-intensive transactional workloads.`}),`\n`,_jsx(_components.li,{children:`Do not increase normalization for read-intensive reporting workloads.`}),`\n`]}),`\n`]}),`\n`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`If the application strictly requires operating on very few different index keys, consider using `,_jsx(_components.a,{href:`/docs/v23.1/alter-table#split-at`,children:_jsx(_components.code,{children:`ALTER ... SPLIT AT`})}),` so that each index key can be served by a separate group of nodes in the cluster.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`If you are working with a table that `,_jsx(_components.strong,{children:`must`}),` be indexed on sequential keys, consider using `,_jsx(_components.a,{href:`/docs/v23.1/hash-sharded-indexes`,children:`hash-sharded indexes`}),`. For details about the mechanics and performance improvements of hash-sharded indexes in CockroachDB, see the blog post `,_jsx(_components.a,{href:`https://www.cockroachlabs.com/blog/hash-sharded-indexes-unlock-linear-scaling-for-sequential-workloads/`,children:`Hash Sharded Indexes Unlock Linear Scaling for Sequential Workloads`}),`. As part of this, we recommend doing thorough performance testing with and without hash-sharded indexes to see which works best for your application.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsx(_components.p,{children:`To avoid read hot spots:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`\n`,_jsx(_components.p,{children:`Increase data distribution, which will allow for more ranges. The hot spot exists because the data being accessed is all co-located in one range.`}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`Increase `,_jsx(_components.a,{href:`/docs/v23.1/recommended-production-settings#load-balancing`,children:`load balancing`}),` across more nodes in the same range. Most transactional reads must go to the leaseholder in CockroachDB, which means that opportunities for load balancing over replicas are minimal.`]}),`\n`,_jsx(_components.p,{children:`However, the following features do permit load balancing over replicas:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`/docs/v23.1/global-tables`,children:`Global tables`}),`.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`/docs/v23.1/follower-reads`,children:`Follower reads`}),` (both the bounded staleness and the exact staleness kinds).`]}),`\n`]}),`\n`,_jsx(_components.p,{children:`In these cases, more replicas will help, up to the number of nodes in the cluster.`}),`\n`]}),`\n`]}),`\n`]}),`\n`]}),`\n`,_jsx(Heading,{level:`3`,id:`statements-with-full-table-scans`,children:`Statements with full table scans`}),`\n`,_jsx(_components.p,{children:`Full table scans often result in poor statement performance.`}),`\n`,_jsx(Heading,{level:`4`,id:`indicators-that-your-application-has-statements-with-full-table-scans`,children:`Indicators that your application has statements with full table scans`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`\n`,_jsx(_components.p,{children:`The following query returns statements with full table scans in their statement plan:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`sql`,children:_jsx(_components.pre,{className:`shiki shiki-themes catppuccin-mocha catppuccin-mocha`,style:{backgroundColor:`#1e1e2e`,\"--shiki-dark-bg\":`#1e1e2e`,color:`#cdd6f4`,\"--shiki-dark\":`#cdd6f4`},language:`sql`,children:_jsxs(_components.code,{language:`sql`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:`SHOW FULL `}),_jsx(_components.span,{style:{color:`#CBA6F7`,\"--shiki-dark\":`#CBA6F7`},children:`TABLE`}),_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:` SCANS;`})]}),`\n`]})})}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`The following query against the `,_jsx(_components.code,{children:`crdb_internal.node_statement_statistics`}),` table returns results:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`3`,language:`sql`,children:_jsx(_components.pre,{className:`shiki shiki-themes catppuccin-mocha catppuccin-mocha`,style:{backgroundColor:`#1e1e2e`,\"--shiki-dark-bg\":`#1e1e2e`,color:`#cdd6f4`,\"--shiki-dark\":`#cdd6f4`},language:`sql`,children:_jsxs(_components.code,{language:`sql`,numberOfLines:`3`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CBA6F7`,\"--shiki-dark\":`#CBA6F7`},children:`SELECT`}),_jsx(_components.span,{style:{color:`#89B4FA`,\"--shiki-light-font-style\":`italic`,\"--shiki-dark\":`#89B4FA`,\"--shiki-dark-font-style\":`italic`},children:` count`}),_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:`(`}),_jsx(_components.span,{style:{color:`#94E2D5`,\"--shiki-dark\":`#94E2D5`},children:`*`}),_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:`) `}),_jsx(_components.span,{style:{color:`#CBA6F7`,\"--shiki-dark\":`#CBA6F7`},children:`as`}),_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:` total_full_scans`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CBA6F7`,\"--shiki-dark\":`#CBA6F7`},children:`FROM`}),_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:` crdb_internal.node_statement_statistics`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CBA6F7`,\"--shiki-dark\":`#CBA6F7`},children:`WHERE`}),_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:` full_scan `}),_jsx(_components.span,{style:{color:`#94E2D5`,\"--shiki-dark\":`#94E2D5`},children:`=`}),_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:` true;`})]}),`\n`]})})}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`Viewing the statement plan on the `,_jsxs(_components.a,{href:`/docs/v23.1/ui-statements-page#statement-fingerprint-page`,children:[_jsx(_components.strong,{children:`Statement Fingerprint`}),` page`]}),` in the DB Console indicates that the plan contains full table scans.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`The statement plans returned by the `,_jsx(_components.a,{href:`/docs/v23.1/sql-tuning-with-explain`,children:_jsx(_components.code,{children:`EXPLAIN`})}),` and `,_jsxs(_components.a,{href:`/docs/v23.1/explain-analyze`,children:[_jsx(_components.code,{children:`EXPLAIN ANALYZE`}),` commands`]}),` indicate that there are full table scans.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.a,{href:`/docs/v23.1/ui-sql-dashboard`,children:`Full Table/Index Scans graph`}),` in the DB Console is showing spikes over time.`]}),`\n`]}),`\n`]}),`\n`,_jsx(Heading,{level:`4`,id:`fix-full-table-scans-in-statements`,children:`Fix full table scans in statements`}),`\n`,_jsxs(_components.p,{children:[`Not every full table scan is an indicator of poor performance. The `,_jsx(_components.a,{href:`/docs/v23.1/cost-based-optimizer`,children:`cost-based optimizer`}),` may decide on a full table scan when other `,_jsx(_components.a,{href:`/docs/v23.1/indexes`,children:`index`}),` or `,_jsx(_components.a,{href:`/docs/v23.1/joins`,children:`join scans`}),` would result in longer execution time.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`/docs/v23.1/sql-tuning-with-explain`,children:`Examine the statements`}),` that result in full table scans and consider adding `,_jsx(_components.a,{href:`/docs/v23.1/schema-design-indexes#create-a-secondary-index`,children:`secondary indexes`}),`.`]}),`\n`,_jsxs(_components.p,{children:[`In the DB Console, visit the `,_jsxs(_components.a,{href:`/docs/v23.1/ui-insights-page#schema-insights-tab`,children:[_jsx(_components.strong,{children:`Schema Insights`}),` tab`]}),` on the `,_jsxs(_components.a,{href:`/docs/v23.1/ui-insights-page`,children:[_jsx(_components.strong,{children:`Insights`}),` page`]}),` and check if there are any insights to create missing indexes. These missing index recommendations are generated based on `,_jsx(_components.a,{href:`/docs/v23.1/ui-insights-page#detect-slow-executions`,children:`slow statement execution`}),`. A missing index may cause a statement to have a `,_jsx(_components.a,{href:`/docs/v23.1/ui-insights-page#suboptimal-plan`,children:`suboptimal plan`}),`. If the execution was slow, based on the insights threshold, then it’s likely the create index recommendation is valid. If the plan had a full table scan, it’s likely that it should be removed with an index.`]}),`\n`,_jsxs(_components.p,{children:[`Also see `,_jsx(_components.a,{href:`/docs/v23.1/performance-best-practices-overview#table-scan-best-practices`,children:`Table scans best practices`}),`.`]}),`\n`,_jsx(Heading,{level:`3`,id:`suboptimal-primary-keys`,children:`Suboptimal primary keys`}),`\n`,_jsx(Heading,{level:`4`,id:`indicators-that-your-tables-are-using-suboptimal-primary-keys`,children:`Indicators that your tables are using suboptimal primary keys`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`The `,_jsx(_components.a,{href:`/docs/v23.1/ui-hardware-dashboard`,children:`Hardware metrics dashboard`}),` in the DB Console shows high resource usage per node.`]}),`\n`,_jsxs(_components.li,{children:[`The Problem Ranges report on the `,_jsx(_components.a,{href:`/docs/v23.1/ui-debug-pages`,children:`Advanced Debug page`}),` in the DB Console indicates a high number of queries per second on a subset of ranges or nodes.`]}),`\n`]}),`\n`,_jsx(Heading,{level:`4`,id:`fix-suboptimal-primary-keys`,children:`Fix suboptimal primary keys`}),`\n`,_jsxs(_components.p,{children:[`Evaluate the schema of your table to see if you can redistribute data more evenly across multiple ranges. Specifically, make sure you have followed `,_jsx(_components.a,{href:`/docs/v23.1/schema-design-table#primary-key-best-practices`,children:`best practices when selecting your primary key`}),`.`]}),`\n`,_jsxs(_components.p,{children:[`If your application with a small dataset (for example, a dataset that contains few index key values) is experiencing resource contention, consider splitting your tables and indexes to `,_jsx(_components.a,{href:`/docs/v23.1/alter-table#split-a-table`,children:`distribute ranges across multiple nodes`}),` to reduce resource contention.`]}),`\n`,_jsx(Heading,{level:`3`,id:`slow-writes`,children:`Slow writes`}),`\n`,_jsx(Heading,{level:`4`,id:`indicators-that-your-tables-are-experiencing-slow-writes`,children:`Indicators that your tables are experiencing slow writes`}),`\n`,_jsxs(_components.p,{children:[`If the `,_jsx(_components.a,{href:`/docs/v23.1/ui-overview-dashboard`,children:`Overview dashboard`}),` in the DB Console shows high service latency when the QPS of `,_jsx(_components.code,{children:`INSERT`}),` and `,_jsx(_components.code,{children:`UPDATE`}),` statements is high, your tables are experiencing slow writes.`]}),`\n`,_jsx(Heading,{level:`4`,id:`fix-slow-writes`,children:`Fix slow writes`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`/docs/v23.1/schema-design-indexes`,children:`Secondary indexes`}),` can improve application read performance. However, there is overhead in maintaining secondary indexes that can affect your write performance. You should profile your tables periodically to determine whether an index is worth the overhead. To identify infrequently accessed indexes that could be candidates to drop, do one of the following:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`In the DB Console, visit the `,_jsxs(_components.a,{href:`/docs/v23.1/ui-insights-page#schema-insights-tab`,children:[_jsx(_components.strong,{children:`Schema Insights`}),` tab`]}),` on the `,_jsxs(_components.a,{href:`/docs/v23.1/ui-insights-page`,children:[_jsx(_components.strong,{children:`Insights`}),` page`]}),` and check if there are any insights to drop unused indexes.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`In the DB Console, visit the `,_jsxs(_components.a,{href:`/docs/v23.1/ui-databases-page`,children:[_jsx(_components.strong,{children:`Databases`}),` page`]}),` and check databases and tables for `,_jsx(_components.a,{href:`/docs/v23.1/ui-databases-page#index-recommendations`,children:_jsx(_components.strong,{children:`Index Recommendations`})}),` to drop unused indexes.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`Run a join query against the `,_jsx(_components.a,{href:`/docs/v23.1/crdb-internal#index_usage_statistics`,children:_jsx(_components.code,{children:`crdb_internal.index_usage_statistics`})}),` and `,_jsx(_components.code,{children:`crdb_internal.table_indexes`}),` tables:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`6`,language:`sql`,children:_jsx(_components.pre,{className:`shiki shiki-themes catppuccin-mocha catppuccin-mocha`,style:{backgroundColor:`#1e1e2e`,\"--shiki-dark-bg\":`#1e1e2e`,color:`#cdd6f4`,\"--shiki-dark\":`#cdd6f4`},language:`sql`,children:_jsxs(_components.code,{language:`sql`,numberOfLines:`6`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CBA6F7`,\"--shiki-dark\":`#CBA6F7`},children:`SELECT`}),_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:` ti.descriptor_name `}),_jsx(_components.span,{style:{color:`#CBA6F7`,\"--shiki-dark\":`#CBA6F7`},children:`as`}),_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:` table_name, ti.index_name, total_reads, last_read`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CBA6F7`,\"--shiki-dark\":`#CBA6F7`},children:`FROM`}),_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:` crdb_internal.index_usage_statistics `}),_jsx(_components.span,{style:{color:`#CBA6F7`,\"--shiki-dark\":`#CBA6F7`},children:`AS`}),_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:` us`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CBA6F7`,\"--shiki-dark\":`#CBA6F7`},children:`JOIN`}),_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:` crdb_internal.table_indexes ti`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CBA6F7`,\"--shiki-dark\":`#CBA6F7`},children:`ON`}),_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:` us.index_id `}),_jsx(_components.span,{style:{color:`#94E2D5`,\"--shiki-dark\":`#94E2D5`},children:`=`}),_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:` ti.index_id`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CBA6F7`,\"--shiki-dark\":`#CBA6F7`},children:`AND`}),_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:` us.table_id `}),_jsx(_components.span,{style:{color:`#94E2D5`,\"--shiki-dark\":`#94E2D5`},children:`=`}),_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:` ti.descriptor_id`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CBA6F7`,\"--shiki-dark\":`#CBA6F7`},children:`ORDER BY`}),_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:` total_reads `}),_jsx(_components.span,{style:{color:`#CBA6F7`,\"--shiki-dark\":`#CBA6F7`},children:`ASC`}),_jsx(_components.span,{style:{color:`#CDD6F4`,\"--shiki-dark\":`#CDD6F4`},children:`;`})]}),`\n`]})})}),`\n`,_jsx(CodeBlock,{numberOfLines:`13`,language:`text`,children:_jsx(_components.pre,{className:`shiki shiki-themes catppuccin-mocha catppuccin-mocha`,style:{backgroundColor:`#1e1e2e`,\"--shiki-dark-bg\":`#1e1e2e`,color:`#cdd6f4`,\"--shiki-dark\":`#cdd6f4`},language:`text`,children:_jsxs(_components.code,{language:`text`,numberOfLines:`13`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` table_name | index_name | total_reads | last_read`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`-----------------------------+-----------------------------------------------+-------------+--------------------------------`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` vehicle_location_histories | vehicle_location_histories_pkey | 1 | 2021-09-28 22:59:03.324398+00`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` rides | rides_auto_index_fk_city_ref_users | 1 | 2021-09-28 22:59:01.500962+00`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` rides | rides_auto_index_fk_vehicle_city_ref_vehicles | 1 | 2021-09-28 22:59:02.470526+00`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` user_promo_codes | user_promo_codes_pkey | 456 | 2021-09-29 00:01:17.063418+00`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` promo_codes | promo_codes_pkey | 910 | 2021-09-29 00:01:17.062319+00`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` vehicles | vehicles_pkey | 3591 | 2021-09-29 00:01:18.261658+00`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` users | users_pkey | 5401 | 2021-09-29 00:01:18.260198+00`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` rides | rides_pkey | 45658 | 2021-09-29 00:01:18.258208+00`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` vehicles | vehicles_auto_index_fk_city_ref_users | 87119 | 2021-09-29 00:01:19.071476+00`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`(9 rows)`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})})]})})}),`\n`,_jsxs(_components.p,{children:[`Use the values in the `,_jsx(_components.code,{children:`total_reads`}),` and `,_jsx(_components.code,{children:`last_read`}),` columns to identify indexes that have low usage or are stale and can be dropped.`]}),`\n`]}),`\n`]}),`\n`,_jsx(Heading,{level:`3`,id:`too-many-mvcc-values`,children:`Too many MVCC values`}),`\n`,_jsx(Heading,{level:`4`,id:`indicators-that-your-tables-have-too-many-mvcc-values`,children:`Indicators that your tables have too many MVCC values`}),`\n`,_jsxs(_components.p,{children:[`In the `,_jsx(_components.a,{href:`/docs/v23.1/ui-databases-page#tables-view`,children:`Databases`}),` page in the DB Console, the Tables view shows the percentage of live data for each table. For example:`]}),`\n`,_jsx(OptimizedImage,{src:`https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui_databases_live_data.png?fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=4c6b3d27cec170a2c3e75599a8940f91`,alt:`Table live data`,\"data-og-width\":`1114`,width:`1114`,\"data-og-height\":`626`,height:`626`,\"data-path\":`images/common/ui_databases_live_data.png`,\"data-optimize\":`true`,\"data-opv\":`3`,srcset:`https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui_databases_live_data.png?w=280\u0026fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=76ce487eb233c0e9d0e2fc5619696e50 280w, https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui_databases_live_data.png?w=560\u0026fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=5da59cc98d7f213df6c9a4a552af3eb8 560w, https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui_databases_live_data.png?w=840\u0026fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=57e1d40a38d1b8c02895dc501b988eb0 840w, https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui_databases_live_data.png?w=1100\u0026fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=b2c65c37f46bd15824f952107994119b 1100w, https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui_databases_live_data.png?w=1650\u0026fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=c65db043bd1d96aa986be434b9afc216 1650w, https://mintcdn.com/cockroachlabs/6M4oBmgCef68NEHr/images/common/ui_databases_live_data.png?w=2500\u0026fit=max\u0026auto=format\u0026n=6M4oBmgCef68NEHr\u0026q=85\u0026s=ef18611150a2cff6f58a1ea2aec5181f 2500w`}),`\n`,_jsxs(_components.p,{children:[`In this example, at `,_jsx(_components.code,{children:`37.3%`}),` the `,_jsx(_components.code,{children:`vehicles`}),` table would be considered to have a low percentage of live data. In the worst cases, the percentage can be `,_jsx(_components.code,{children:`0%`}),`.`]}),`\n`,_jsxs(_components.p,{children:[`A low percentage of live data can cause statements to scan more data (`,_jsx(_components.a,{href:`/docs/v23.1/architecture/storage-layer#mvcc`,children:`MVCC values`}),`) than required, which can reduce performance.`]}),`\n`,_jsx(Heading,{level:`4`,id:`configure-cockroachdb-to-purge-mvcc-values`,children:`Configure CockroachDB to purge MVCC values`}),`\n`,_jsxs(_components.p,{children:[`Reduce the `,_jsx(_components.a,{href:`/docs/v23.1/configure-replication-zones#gc-ttlseconds`,children:_jsx(_components.code,{children:`gc.ttlseconds`})}),` zone configuration of the table as much as possible.`]}),`\n`,_jsx(Heading,{level:`2`,id:`see-also`,children:`See also`}),`\n`,_jsxs(_components.p,{children:[`If you aren’t sure whether SQL query performance needs to be improved, see `,_jsx(_components.a,{href:`/docs/v23.1/query-behavior-troubleshooting#identify-slow-queries`,children:`Identify slow queries`}),`.`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"codeStyling":{"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}},"config":{},"pageMetadata":{"title":"Performance Tuning Recipes","old_description":"Identify, diagnose, and fix common performance problems","canonical":"https://docs.cockroachlabs.com/docs/stable/performance-recipes","description":null,"href":"/docs/v23.1/performance-recipes"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Problems","slug":"problems","depth":2,"children":[]},{"title":"Solutions","slug":"solutions","depth":2,"children":[{"title":"Transaction contention","slug":"transaction-contention","depth":3,"children":[]},{"title":"Indicators that your application is experiencing transaction contention","slug":"indicators-that-your-application-is-experiencing-transaction-contention","depth":4,"children":[]},{"title":"Fix transaction contention problems","slug":"fix-transaction-contention-problems","depth":4,"children":[]},{"title":"Hot spots","slug":"hot-spots","depth":3,"children":[]},{"title":"Indicators that your cluster has hot spots","slug":"indicators-that-your-cluster-has-hot-spots","depth":4,"children":[]},{"title":"Reduce hot spots","slug":"reduce-hot-spots","depth":4,"children":[]},{"title":"Statements with full table scans","slug":"statements-with-full-table-scans","depth":3,"children":[]},{"title":"Indicators that your application has statements with full table scans","slug":"indicators-that-your-application-has-statements-with-full-table-scans","depth":4,"children":[]},{"title":"Fix full table scans in statements","slug":"fix-full-table-scans-in-statements","depth":4,"children":[]},{"title":"Suboptimal primary keys","slug":"suboptimal-primary-keys","depth":3,"children":[]},{"title":"Indicators that your tables are using suboptimal primary keys","slug":"indicators-that-your-tables-are-using-suboptimal-primary-keys","depth":4,"children":[]},{"title":"Fix suboptimal primary keys","slug":"fix-suboptimal-primary-keys","depth":4,"children":[]},{"title":"Slow writes","slug":"slow-writes","depth":3,"children":[]},{"title":"Indicators that your tables are experiencing slow writes","slug":"indicators-that-your-tables-are-experiencing-slow-writes","depth":4,"children":[]},{"title":"Fix slow writes","slug":"fix-slow-writes","depth":4,"children":[]},{"title":"Too many MVCC values","slug":"too-many-mvcc-values","depth":3,"children":[]},{"title":"Indicators that your tables have too many MVCC values","slug":"indicators-that-your-tables-have-too-many-mvcc-values","depth":4,"children":[]},{"title":"Configure CockroachDB to purge MVCC values","slug":"configure-cockroachdb-to-purge-mvcc-values","depth":4,"children":[]}]},{"title":"See also","slug":"see-also","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":["/_mintlify/custom/cockroachlabs/4695317e415d4eba/kapa.js","/_mintlify/custom/cockroachlabs/40fb45a3cfe42c92/copy-code-prompt.js","/_mintlify/custom/cockroachlabs/3f343c9e8c40397a/collapse-nav.js"],"subdomain":"cockroachlabs","siteName":"CockroachDB","title":"Performance Tuning Recipes - CockroachDB","navMaps":{"firstHrefInVersion":{"v26.4":{"href":"/docs/stable/performance-recipes","matchLevel":1},"v26.3":{"href":"/docs/v26.3/performance-recipes","matchLevel":1,"canonicalOverride":true},"v26.2":{"href":"/docs/v26.2/performance-recipes","matchLevel":1,"canonicalOverride":true},"v26.1":{"href":"/docs/v26.1/performance-recipes","matchLevel":1,"canonicalOverride":true},"v25.4":{"href":"/docs/v25.4/performance-recipes","matchLevel":1,"canonicalOverride":true},"v25.3":{"href":"/docs/v25.3/performance-recipes","matchLevel":1,"canonicalOverride":true},"v25.2":{"href":"/docs/v25.2/performance-recipes","matchLevel":1,"canonicalOverride":true},"v25.1":{"href":"/docs/v25.1/performance-recipes","matchLevel":1,"canonicalOverride":true},"v24.3":{"href":"/docs/v24.3/performance-recipes","matchLevel":1,"canonicalOverride":true},"v24.1":{"href":"/docs/v24.1/performance-recipes","matchLevel":1,"canonicalOverride":true},"v23.2":{"href":"/docs/v23.2/performance-recipes","matchLevel":1,"canonicalOverride":true},"v23.1":{"href":"/docs/v23.1/performance-recipes","matchLevel":0}},"firstHrefInLanguage":{}},"lastModified":"2026-11-11T19:17:13.707Z","originalFileLocation":"docs/v23.1/performance-recipes.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"light\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"application-name\" content=\"CockroachDB\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/cockroachlabs/c9BlkJ0WBi2Ma7w-/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/cockroachlabs/c9BlkJ0WBi2Ma7w-/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/cockroachlabs/c9BlkJ0WBi2Ma7w-/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/cockroachlabs/c9BlkJ0WBi2Ma7w-/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/cockroachlabs/c9BlkJ0WBi2Ma7w-/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/cockroachlabs/c9BlkJ0WBi2Ma7w-/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/cockroachlabs/c9BlkJ0WBi2Ma7w-/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/cockroachlabs/c9BlkJ0WBi2Ma7w-/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/cockroachlabs/c9BlkJ0WBi2Ma7w-/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Performance Tuning Recipes - CockroachDB\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"CockroachDB\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.cockroachlabs.com/docs/stable/performance-recipes\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://cockroachlabs.mintlify.site/_mintlify/api/og/v2?division=Optimize+Performance\u0026amp;title=Performance+Tuning+Recipes\u0026amp;theme=4aeed7318cb28bd50868adb3\u0026amp;signature=7082d35f0bd82641f2dc337014ff57b534787fab36efc585ddf76133251d43f9\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Performance Tuning Recipes - CockroachDB\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://cockroachlabs.mintlify.site/_mintlify/api/og/v2?division=Optimize+Performance\u0026amp;title=Performance+Tuning+Recipes\u0026amp;theme=4aeed7318cb28bd50868adb3\u0026amp;signature=7082d35f0bd82641f2dc337014ff57b534787fab36efc585ddf76133251d43f9\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/cockroachlabs/c9BlkJ0WBi2Ma7w-/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"CockroachDB\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#9059FF\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.cockroachlabs.com/docs/stable/performance-recipes\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/docs/v23.1/performance-recipes.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.cockroachlabs.com/#organization\",\"name\":\"CockroachDB\",\"url\":\"https://docs.cockroachlabs.com\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/cockroachlabs/4WvUnbVuGZfqM4kW/images/CockroachLabs_Wordmark_Black.png?fit=max\u0026auto=format\u0026n=4WvUnbVuGZfqM4kW\u0026q=85\u0026s=54ccae625c9986bf1df8ddc7b2c571f0\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.cockroachlabs.com#website\",\"name\":\"CockroachDB\",\"url\":\"https://docs.cockroachlabs.com\",\"publisher\":{\"@id\":\"https://docs.cockroachlabs.com/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.cockroachlabs.com/docs/stable/performance-recipes#webpage\",\"url\":\"https://docs.cockroachlabs.com/docs/stable/performance-recipes\",\"name\":\"Performance Tuning Recipes\",\"dateModified\":\"2026-11-11T19:17:13.707Z\",\"isPartOf\":{\"@id\":\"https://docs.cockroachlabs.com#website\"},\"breadcrumb\":{\"@id\":\"https://docs.cockroachlabs.com/docs/stable/performance-recipes#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.cockroachlabs.com/docs/stable/performance-recipes#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Optimize Performance\",\"item\":\"https://docs.cockroachlabs.com/docs/v23.1/make-queries-fast\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Performance Tuning Recipes\",\"item\":\"https://docs.cockroachlabs.com/docs/stable/performance-recipes\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.cockroachlabs.com/docs/stable/performance-recipes#article\",\"headline\":\"Performance Tuning Recipes\",\"name\":\"Performance Tuning Recipes\",\"url\":\"https://docs.cockroachlabs.com/docs/stable/performance-recipes\",\"mainEntityOfPage\":{\"@id\":\"https://docs.cockroachlabs.com/docs/stable/performance-recipes#webpage\"},\"dateModified\":\"2026-11-11T19:17:13.707Z\",\"publisher\":{\"@id\":\"https://docs.cockroachlabs.com/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.cockroachlabs.com#website\"}}]}\u003c/script>","agentPointerHref":"/docs/v23.1/performance-recipes.md","siteName":"CockroachDB","nav":{"global":{"anchors":[{"anchor":"University","icon":"graduation-cap","href":"https://learn.cockroachlabs.com/"}]},"products":[{"product":"Cockroach Continuum Cloud","icon":"https://mintlify.s3.us-west-1.amazonaws.com/cockroachlabs/images/continuum/cockroachlabs-symbol.svg","description":"The agentic database cloud","pages":[{"title":"Cockroach Continuum Cloud","href":"/docs/continuum"}]},{"product":"CockroachDB","icon":"database","description":"Distributed SQL database","versions":[{"version":"v26.4","default":true,"tag":"Stable","pages":[{"title":"v26.4","href":"/docs/stable/performance-recipes"}]},{"version":"v26.3","pages":[{"title":"v26.3","href":"/docs/v26.3/performance-recipes"}]},{"version":"v26.2","pages":[{"title":"v26.2","href":"/docs/v26.2/performance-recipes"}]},{"version":"v26.1","pages":[{"title":"v26.1","href":"/docs/v26.1/performance-recipes"}]},{"version":"v25.4","tag":"LTS","pages":[{"title":"v25.4","href":"/docs/v25.4/performance-recipes"}]},{"version":"v25.3","tag":"Unsupported","pages":[{"title":"v25.3","href":"/docs/v25.3/performance-recipes"}]},{"version":"v25.2","tag":"LTS","pages":[{"title":"v25.2","href":"/docs/v25.2/performance-recipes"}]},{"version":"v25.1","tag":"Unsupported","pages":[{"title":"v25.1","href":"/docs/v25.1/performance-recipes"}]},{"version":"v24.3","tag":"LTS","pages":[{"title":"v24.3","href":"/docs/v24.3/performance-recipes"}]},{"version":"v24.1","tag":"LTS","pages":[{"title":"v24.1","href":"/docs/v24.1/performance-recipes"}]},{"version":"v23.2","tag":"LTS","pages":[{"title":"v23.2","href":"/docs/v23.2/performance-recipes"}]},{"version":"v23.1","tag":"Unsupported","tabs":[{"tab":"Docs","icon":"book-open","pages":[{"title":"CockroachDB Docs","sidebarTitle":"Docs Home","href":"/docs/v23.1"},{"group":"Get Started","pages":[{"group":"Install CockroachDB","pages":[{"title":"Install CockroachDB on Mac","href":"/docs/v23.1/install-cockroachdb-mac"},{"title":"Install CockroachDB on Linux","href":"/docs/v23.1/install-cockroachdb-linux"},{"title":"Install a FIPS-ready CockroachDB Runtime","href":"/docs/v23.1/fips"},{"title":"Install CockroachDB on Windows","href":"/docs/v23.1/install-cockroachdb-windows"}]},{"group":"Develop with CockroachDB","pages":[{"title":"Developer Basics","href":"/docs/v23.1/developer-basics"},{"group":"JavaScript/TypeScript","pages":[{"title":"Build a Simple CRUD Node.js App with CockroachDB and the node-postgres Driver","href":"/docs/v23.1/build-a-nodejs-app-with-cockroachdb"},{"title":"Build a Node.js App with CockroachDB and Sequelize","href":"/docs/v23.1/build-a-nodejs-app-with-cockroachdb-sequelize"},{"title":"Build a Simple CRUD Node.js App with CockroachDB and Knex.js","href":"/docs/v23.1/build-a-nodejs-app-with-cockroachdb-knexjs"},{"title":"Build a Simple CRUD Node.js App with CockroachDB and Prisma","href":"/docs/v23.1/build-a-nodejs-app-with-cockroachdb-prisma"},{"title":"Build a TypeScript App with CockroachDB and TypeORM","href":"/docs/v23.1/build-a-typescript-app-with-cockroachdb"}]},{"group":"Python","pages":[{"title":"Build a Python App with CockroachDB and Psycopg 3","href":"/docs/v23.1/build-a-python-app-with-cockroachdb-psycopg3"},{"title":"Build a Python App with CockroachDB and psycopg2","href":"/docs/v23.1/build-a-python-app-with-cockroachdb"},{"title":"Build a Simple CRUD Python App with CockroachDB and SQLAlchemy","href":"/docs/v23.1/build-a-python-app-with-cockroachdb-sqlalchemy"},{"title":"Build a Python App with CockroachDB and Django","href":"/docs/v23.1/build-a-python-app-with-cockroachdb-django"},{"title":"Build a Python App with CockroachDB and asyncpg","href":"/docs/v23.1/build-a-python-app-with-cockroachdb-asyncpg"}]},{"group":"Golang","pages":[{"title":"Build a Simple CRUD Go App with CockroachDB and the Go pgx Driver","href":"/docs/v23.1/build-a-go-app-with-cockroachdb"},{"title":"Build a Go App with CockroachDB and GORM","href":"/docs/v23.1/build-a-go-app-with-cockroachdb-gorm"},{"title":"Build a Go App with CockroachDB the Go pq Driver","href":"/docs/v23.1/build-a-go-app-with-cockroachdb-pq"},{"title":"Build a Go App with CockroachDB and upper/db","href":"/docs/v23.1/build-a-go-app-with-cockroachdb-upperdb"}]},{"group":"Java","pages":[{"title":"Build a Simple CRUD Java App with CockroachDB and JDBC","href":"/docs/v23.1/build-a-java-app-with-cockroachdb"},{"title":"Build a Java App with CockroachDB and Hibernate","href":"/docs/v23.1/build-a-java-app-with-cockroachdb-hibernate"},{"title":"Build a Java App with CockroachDB and jOOQ","href":"/docs/v23.1/build-a-java-app-with-cockroachdb-jooq"},{"title":"Build a Spring App with CockroachDB and MyBatis","href":"/docs/v23.1/build-a-spring-app-with-cockroachdb-mybatis"},{"title":"Build a Spring App with CockroachDB and JDBC","href":"/docs/v23.1/build-a-spring-app-with-cockroachdb-jdbc"},{"title":"Build a Spring App with CockroachDB and JPA","href":"/docs/v23.1/build-a-spring-app-with-cockroachdb-jpa"}]},{"group":"Ruby","pages":[{"title":"Build a Ruby App with CockroachDB and the Ruby pg Driver","href":"/docs/v23.1/build-a-ruby-app-with-cockroachdb"},{"title":"Build a Ruby App with CockroachDB and Active Record","href":"/docs/v23.1/build-a-ruby-app-with-cockroachdb-activerecord"}]},{"title":"Build a C# App with CockroachDB and the .NET Npgsql Driver","sidebarTitle":"C# (.NET)","href":"/docs/v23.1/build-a-csharp-app-with-cockroachdb"},{"title":"Build a Rust App with CockroachDB and the Rust-Postgres Driver","sidebarTitle":"Rust","href":"/docs/v23.1/build-a-rust-app-with-cockroachdb"},{"title":"Build a GraphQL Application Using Hasura","sidebarTitle":"Hasura (GraphQL)","href":"/docs/v23.1/hasura-getting-started"}]},{"group":"Standard Examples","pages":[{"title":"Create and Deploy an AWS Lambda Function Built on CockroachDB","sidebarTitle":"AWS Lambda","href":"/docs/v23.1/deploy-lambda-function"},{"title":"Deploy a CockroachDB Cloud Application with Google Cloud Run","sidebarTitle":"Google Cloud Run","href":"/docs/v23.1/deploy-app-gcr"},{"title":"Deploy a Netlify App Built on CockroachDB","sidebarTitle":"Netlify","href":"/docs/v23.1/deploy-app-netlify"},{"title":"Deploy a Web App Built on CockroachDB with Vercel","sidebarTitle":"Vercel","href":"/docs/v23.1/deploy-app-vercel"},{"title":"Serverless Function Best Practices","href":"/docs/v23.1/serverless-function-best-practices"}]},{"title":"MovR","href":"/docs/v23.1/movr"}]},{"group":"CockroachDB and AI","pages":[{"title":"CockroachDB Docs MCP Server","sidebarTitle":"Docs MCP Server","href":"/docs/v23.1/docs-mcp-integration"}]},{"group":"Feature Overview","pages":[{"group":"CockroachDB Basics","pages":[{"title":"Why CockroachDB?","href":"/docs/v23.1/why-cockroachdb"},{"title":"Replication and Rebalancing","sidebarTitle":"Replication \u0026 Rebalancing","href":"/docs/v23.1/demo-replication-and-rebalancing"},{"title":"Fault Tolerance \u0026 Recovery","href":"/docs/v23.1/demo-fault-tolerance-and-recovery"},{"title":"Serializable Transactions","href":"/docs/v23.1/demo-serializable"},{"title":"Multi-Active Availability","href":"/docs/v23.1/multi-active-availability"}]},{"group":"CockroachDB SQL","pages":[{"title":"PostgreSQL Compatibility","href":"/docs/v23.1/postgresql-compatibility"},{"title":"SQL Feature Support in CockroachDB v23.1","sidebarTitle":"SQL Features","href":"/docs/v23.1/sql-feature-support"},{"title":"SQL FAQs","href":"/docs/v23.1/sql-faqs"}]}]},{"group":"Connect to an Application","pages":[{"title":"Install a Driver or ORM Framework","href":"/docs/v23.1/install-client-drivers"},{"title":"Connect to a CockroachDB Cluster","sidebarTitle":"Connect to a Cluster","href":"/docs/v23.1/connect-to-the-database"},{"title":"Client Connection Parameters","href":"/docs/v23.1/connection-parameters"},{"title":"Connection Pooling","href":"/docs/v23.1/connection-pooling"}]},{"group":"Self-Hosted Deployments","pages":[{"title":"Production Checklist","href":"/docs/v23.1/recommended-production-settings"},{"title":"Deployment \u0026 Operations Skills Taxonomy","sidebarTitle":"Deployment and Operations Skills Taxonomy","href":"/docs/v23.1/deployment-operations-skills-taxonomy"},{"group":"Deploy Locally","pages":[{"group":"Deploy from Binary","pages":[{"title":"Deploy a Local Cluster from Binary (Secure)","href":"/docs/v23.1/secure-a-cluster"},{"title":"Deploy a Local Cluster from Binary (Insecure)","href":"/docs/v23.1/start-a-local-cluster"}]},{"title":"Deploy a Local Cluster in Docker (Insecure)","href":"/docs/v23.1/start-a-local-cluster-in-docker"},{"group":"Deploy in Kubernetes","pages":[{"title":"Deploy a Local Cluster in Kubernetes","href":"/docs/v23.1/orchestrate-a-local-cluster-with-kubernetes"},{"title":"Orchestration with Kubernetes (Insecure)","href":"/docs/v23.1/orchestrate-a-local-cluster-with-kubernetes-insecure"}]},{"title":"Simulate a Multi-Region Cluster on localhost (Insecure)","sidebarTitle":"Simulate a Multi-Region Cluster Locally","href":"/docs/v23.1/simulate-a-multi-region-cluster-on-localhost"}]},{"group":"Deploy Manually","pages":[{"title":"Manual Deployment","sidebarTitle":"Overview","href":"/docs/v23.1/manual-deployment"},{"title":"Deploy CockroachDB On-Premises","sidebarTitle":"Deploy On-Premises","href":"/docs/v23.1/deploy-cockroachdb-on-premises"},{"title":"Deploy CockroachDB On-Premises (Insecure)","href":"/docs/v23.1/deploy-cockroachdb-on-premises-insecure"},{"title":"Deploy CockroachDB on AWS EC2","sidebarTitle":"Deploy on AWS","href":"/docs/v23.1/deploy-cockroachdb-on-aws"},{"title":"Deploy CockroachDB on AWS EC2 (Insecure)","href":"/docs/v23.1/deploy-cockroachdb-on-aws-insecure"},{"title":"Deploy CockroachDB on Microsoft Azure","sidebarTitle":"Deploy on Azure","href":"/docs/v23.1/deploy-cockroachdb-on-microsoft-azure"},{"title":"Deploy CockroachDB on Microsoft Azure (Insecure)","href":"/docs/v23.1/deploy-cockroachdb-on-microsoft-azure-insecure"},{"title":"Deploy CockroachDB on Google Cloud Platform GCE","sidebarTitle":"Deploy on Google Cloud Platform GCE","href":"/docs/v23.1/deploy-cockroachdb-on-google-cloud-platform"},{"title":"Deploy CockroachDB on Google Cloud Platform GCE (Insecure)","href":"/docs/v23.1/deploy-cockroachdb-on-google-cloud-platform-insecure"},{"title":"Deploy CockroachDB on Digital Ocean","sidebarTitle":"Deploy on Digital Ocean","href":"/docs/v23.1/deploy-cockroachdb-on-digital-ocean"},{"title":"Deploy CockroachDB on Digital Ocean (Insecure)","href":"/docs/v23.1/deploy-cockroachdb-on-digital-ocean-insecure"}]},{"group":"Deploy on Kubernetes with Legacy Technologies","pages":[{"title":"Kubernetes Overview","sidebarTitle":"Overview","href":"/docs/v23.1/kubernetes-overview"},{"title":"Deploy CockroachDB in a Single Kubernetes Cluster","href":"/docs/v23.1/deploy-cockroachdb-with-kubernetes"},{"title":"Deploy CockroachDB in a Single Kubernetes Cluster (Insecure)","href":"/docs/v23.1/deploy-cockroachdb-with-kubernetes-insecure"},{"title":"Deploy CockroachDB on Red Hat OpenShift","sidebarTitle":"OpenShift Deployment","href":"/docs/v23.1/deploy-cockroachdb-with-kubernetes-openshift"},{"title":"Orchestrate CockroachDB Across Multiple Kubernetes Clusters","sidebarTitle":"Multi-Cluster Deployment","href":"/docs/v23.1/orchestrate-cockroachdb-with-kubernetes-multi-cluster"},{"group":"Operate on Kubernetes","pages":[{"title":"Pod Scheduling","href":"/docs/v23.1/schedule-cockroachdb-kubernetes"},{"title":"Resource Management","href":"/docs/v23.1/configure-cockroachdb-kubernetes"},{"title":"Certificate Management","href":"/docs/v23.1/secure-cockroachdb-kubernetes"},{"title":"Cluster Scaling","href":"/docs/v23.1/scale-cockroachdb-kubernetes"},{"title":"Cluster Monitoring","href":"/docs/v23.1/monitor-cockroachdb-kubernetes"},{"title":"Cluster Upgrades","href":"/docs/v23.1/upgrade-cockroachdb-kubernetes"},{"title":"CockroachDB Performance on Kubernetes","sidebarTitle":"Kubernetes Performance","href":"/docs/v23.1/kubernetes-performance"}]}]},{"group":"Multi-Region for Self-Hosted Deployments","pages":[{"title":"Topology Patterns Overview","href":"/docs/v23.1/topology-patterns"},{"title":"Basic Production Topology","href":"/docs/v23.1/topology-basic-production"},{"title":"Follower Reads Topology","href":"/docs/v23.1/topology-follower-reads"},{"title":"Follow-the-Workload Topology","href":"/docs/v23.1/topology-follow-the-workload"},{"title":"Regional Tables","href":"/docs/v23.1/regional-tables"},{"title":"Global Tables","href":"/docs/v23.1/global-tables"}]},{"group":"Security","pages":[{"group":"Certificates","pages":[{"title":"Use the CockroachDB CLI to provision a development cluster","href":"/docs/v23.1/manage-certs-cli"},{"title":"Manage PKI certificates with HashiCorp Vault","href":"/docs/v23.1/manage-certs-vault"},{"title":"Create Security Certificates using OpenSSL","href":"/docs/v23.1/create-security-certificates-openssl"},{"title":"Advanced Public Key Infrastructure (PKI) Certificate Scenarios","href":"/docs/v23.1/create-security-certificates-custom-ca"},{"title":"Using Online Certificate Status Protocol (OCSP) with CockroachDB","sidebarTitle":"Use Online Certificate Status Protocol (OCSP)","href":"/docs/v23.1/manage-certs-revoke-ocsp"}]},{"title":"Authenticate to CockroachDB Self-Hosted Clusters","sidebarTitle":"Authentication","href":"/docs/v23.1/authentication"},{"title":"Manage Encryption for CockroachDB Self-Hosted","sidebarTitle":"Encryption","href":"/docs/v23.1/encryption"},{"title":"Manage Cluster User Authorization","sidebarTitle":"Authorization","href":"/docs/v23.1/authorization"},{"title":"Table-based SQL Audit Logging","href":"/docs/v23.1/sql-audit-logging"},{"title":"Role-based SQL Audit Logging","href":"/docs/v23.1/role-based-audit-logging"},{"title":"GSSAPI Authentication (Enterprise)","sidebarTitle":"GSSAPI Authentication","href":"/docs/v23.1/gssapi_authentication"},{"title":"Cluster Single Sign-on (SSO) using JSON web tokens (JWTs)","sidebarTitle":"Cluster SSO using JWT","href":"/docs/v23.1/sso-sql"},{"title":"Single Sign-on (SSO) for DB Console","sidebarTitle":"DB Console SSO","href":"/docs/v23.1/sso-db-console"},{"title":"Rotate Security Certificates","href":"/docs/v23.1/rotate-certificates"},{"title":"Use HashiCorp Vault's Dynamic Secrets","sidebarTitle":"Use Hashicorp Vault's Dynamic Secrets","href":"/docs/v23.1/vault-db-secrets-tutorial"}]},{"group":"Monitoring and Alerting","pages":[{"title":"Monitoring and Alerting","sidebarTitle":"Overview","href":"/docs/v23.1/monitoring-and-alerting"},{"title":"Common Issues to Monitor","href":"/docs/v23.1/common-issues-to-monitor"},{"title":"Enable the Node Map","href":"/docs/v23.1/enable-node-map"},{"title":"Monitor CockroachDB with Prometheus","sidebarTitle":"Use Prometheus and Alertmanager","href":"/docs/v23.1/monitor-cockroachdb-with-prometheus"},{"title":"Essential Metrics for CockroachDB Self-Hosted Deployments","sidebarTitle":"Essential Metrics for CockroachDB self-hosted Deployments","href":"/docs/v23.1/essential-metrics-self-hosted"}]},{"group":"Administration","pages":[{"title":"DB Console Overview","href":"/docs/v23.1/ui-overview"},{"title":"Cluster Overview Page","href":"/docs/v23.1/ui-cluster-overview-page"},{"group":"Metrics Dashboards","pages":[{"title":"Overview Dashboard","sidebarTitle":"Overview","href":"/docs/v23.1/ui-overview-dashboard"},{"title":"Hardware Dashboard","sidebarTitle":"Hardware","href":"/docs/v23.1/ui-hardware-dashboard"},{"title":"Runtime Dashboard","sidebarTitle":"Runtime","href":"/docs/v23.1/ui-runtime-dashboard"},{"title":"SQL Dashboard","sidebarTitle":"SQL","href":"/docs/v23.1/ui-sql-dashboard"},{"title":"Storage Dashboard","sidebarTitle":"Storage","href":"/docs/v23.1/ui-storage-dashboard"},{"title":"Replication Dashboard","sidebarTitle":"Replication","href":"/docs/v23.1/ui-replication-dashboard"},{"title":"Distributed Dashboard","sidebarTitle":"Distributed","href":"/docs/v23.1/ui-distributed-dashboard"},{"title":"Queues Dashboard","sidebarTitle":"Queues","href":"/docs/v23.1/ui-queues-dashboard"},{"title":"Slow Requests Dashboard","sidebarTitle":"Slow Requests","href":"/docs/v23.1/ui-slow-requests-dashboard"},{"title":"Changefeeds Dashboard","sidebarTitle":"Changefeeds","href":"/docs/v23.1/ui-cdc-dashboard"},{"title":"Overload Dashboard","sidebarTitle":"Overload","href":"/docs/v23.1/ui-overload-dashboard"},{"title":"TTL Dashboard","sidebarTitle":"TTL","href":"/docs/v23.1/ui-ttl-dashboard"},{"title":"Custom Chart Debug Page","href":"/docs/v23.1/ui-custom-chart-debug-page"}]},{"title":"Databases Page","href":"/docs/v23.1/ui-databases-page"},{"title":"Sessions Page","href":"/docs/v23.1/ui-sessions-page"},{"title":"Statements Page","href":"/docs/v23.1/ui-statements-page"},{"title":"Transactions Page","href":"/docs/v23.1/ui-transactions-page"},{"title":"Insights Page","href":"/docs/v23.1/ui-insights-page"},{"title":"Network Latency Page","sidebarTitle":"Network Page","href":"/docs/v23.1/ui-network-latency-page"},{"title":"Jobs Page","href":"/docs/v23.1/ui-jobs-page"},{"title":"Schedules Page","href":"/docs/v23.1/ui-schedules-page"},{"title":"Advanced Debug Page","href":"/docs/v23.1/ui-debug-pages"},{"title":"Key Visualizer","href":"/docs/v23.1/ui-key-visualizer"}]},{"group":"Backups and Restores","pages":[{"title":"Backup and Restore Overview","sidebarTitle":"Overview","href":"/docs/v23.1/backup-and-restore-overview"},{"title":"Take Full and Incremental Backups","sidebarTitle":"Full and Incremental Backups","href":"/docs/v23.1/take-full-and-incremental-backups"},{"title":"Take Backups with Revision History and Restore from a Point-in-time","sidebarTitle":"Backups with Revision History and Point-in-time Restore","href":"/docs/v23.1/take-backups-with-revision-history-and-restore-from-a-point-in-time"},{"title":"Take and Restore Encrypted Backups","sidebarTitle":"Encrypted Backup and Restore","href":"/docs/v23.1/take-and-restore-encrypted-backups"},{"title":"Take Locality-restricted Backups","sidebarTitle":"Locality-restricted Backup Execution","href":"/docs/v23.1/take-locality-restricted-backups"},{"title":"Take and Restore Locality-aware Backups","sidebarTitle":"Locality-aware Backup and Restore","href":"/docs/v23.1/take-and-restore-locality-aware-backups"},{"title":"Manage a Backup Schedule","sidebarTitle":"Scheduled Backups","href":"/docs/v23.1/manage-a-backup-schedule"},{"title":"Backup Validation","href":"/docs/v23.1/backup-validation"},{"title":"Expire Past Backups","href":"/docs/v23.1/expire-past-backups"},{"title":"Backup and Restore Monitoring","href":"/docs/v23.1/backup-and-restore-monitoring"}]},{"group":"File Storage","pages":[{"title":"Use Cloud Storage","sidebarTitle":"Cloud Storage","href":"/docs/v23.1/use-cloud-storage"},{"title":"Cloud Storage Authentication","href":"/docs/v23.1/cloud-storage-authentication"},{"title":"Use Userfile Storage","sidebarTitle":"Userfile Storage","href":"/docs/v23.1/use-userfile-storage"},{"title":"Use a Local File Server","sidebarTitle":"Local File Server","href":"/docs/v23.1/use-a-local-file-server"}]},{"group":"Cluster Maintenance","pages":[{"title":"Upgrade to CockroachDB v23.1","sidebarTitle":"Upgrade CockroachDB","href":"/docs/v23.1/upgrade-cockroach-version"},{"title":"Restoring Backups Across Versions","href":"/docs/v23.1/restoring-backups-across-versions"},{"title":"Manage Long-Running Queries","href":"/docs/v23.1/manage-long-running-queries"},{"title":"Node Shutdown","href":"/docs/v23.1/node-shutdown"}]},{"group":"Logs","pages":[{"title":"Logging Overview","sidebarTitle":"Overview","href":"/docs/v23.1/logging-overview"},{"title":"Configure Logs","href":"/docs/v23.1/configure-logs"},{"title":"Logging Use Cases","href":"/docs/v23.1/logging-use-cases"},{"title":"Log SQL Activity to Datadog","href":"/docs/v23.1/log-sql-activity-to-datadog"}]},{"title":"Cluster API v2.0","sidebarTitle":"Cluster API","href":"/docs/v23.1/cluster-api"}]},{"group":"Schema Design","pages":[{"title":"Database Schemas","href":"/docs/v23.1/schema-design-overview"},{"title":"Computed Columns","href":"/docs/v23.1/computed-columns"},{"title":"Column Families","href":"/docs/v23.1/column-families"},{"title":"Scale to Multiple Regions","href":"/docs/v23.1/multiregion-scale-application"},{"group":"Indexes","pages":[{"title":"Secondary Indexes","href":"/docs/v23.1/schema-design-indexes"},{"title":"Index a Subset of Rows with Partial Indexes","sidebarTitle":"Partial Indexes","href":"/docs/v23.1/partial-indexes"},{"title":"Index Sequential Keys with Hash-sharded Indexes","sidebarTitle":"Hash-sharded Indexes","href":"/docs/v23.1/hash-sharded-indexes"},{"title":"Generalized Inverted Indexes","href":"/docs/v23.1/inverted-indexes"},{"title":"Full-Text Search","href":"/docs/v23.1/full-text-search"},{"title":"Trigram Indexes","href":"/docs/v23.1/trigram-indexes"},{"title":"Expression Indexes","href":"/docs/v23.1/expression-indexes"},{"title":"Spatial Indexes","href":"/docs/v23.1/spatial-indexes"}]},{"group":"Update a Database Schema","pages":[{"title":"Online Schema Changes","href":"/docs/v23.1/online-schema-changes"},{"title":"Migrate CockroachDB Schemas with Alembic","sidebarTitle":"Use Alembic","href":"/docs/v23.1/alembic"},{"title":"Migrate CockroachDB Schemas with Flyway","sidebarTitle":"Use Flyway","href":"/docs/v23.1/flyway"},{"title":"Migrate CockroachDB Schemas with Liquibase","sidebarTitle":"Use Liquibase","href":"/docs/v23.1/liquibase"}]}]},{"group":"Reads and Writes","pages":[{"title":"Reads and Writes in CockroachDB","sidebarTitle":"Overview","href":"/docs/v23.1/architecture/reads-and-writes-overview"},{"group":"Read Data","pages":[{"title":"Query Data","href":"/docs/v23.1/query-data"},{"title":"Reusable Views","href":"/docs/v23.1/views"},{"title":"Subqueries","href":"/docs/v23.1/subqueries"},{"title":"Temporary Tables","href":"/docs/v23.1/temporary-tables"},{"title":"Paginate Results","href":"/docs/v23.1/pagination"},{"title":"Follower Reads","href":"/docs/v23.1/follower-reads"},{"title":"AS OF SYSTEM TIME","sidebarTitle":"AS OF SYSTEM TIME","href":"/docs/v23.1/as-of-system-time"},{"title":"Query Spatial Data","href":"/docs/v23.1/query-spatial-data"}]},{"group":"Write Data","pages":[{"title":"Insert Data","href":"/docs/v23.1/insert-data"},{"title":"Update Data","href":"/docs/v23.1/update-data"},{"title":"Bulk-update Data","href":"/docs/v23.1/bulk-update-data"},{"title":"Delete Data","href":"/docs/v23.1/delete-data"},{"title":"Bulk-delete Data","href":"/docs/v23.1/bulk-delete-data"},{"title":"Batch Delete Expired Data with Row-Level TTL","href":"/docs/v23.1/row-level-ttl"}]},{"group":"Transactions","pages":[{"title":"Transactions","sidebarTitle":"Overview","href":"/docs/v23.1/transactions"},{"title":"Advanced Client-side Transaction Retries","href":"/docs/v23.1/advanced-client-side-transaction-retries"},{"title":"Life of a Distributed Transaction","href":"/docs/v23.1/architecture/life-of-a-distributed-transaction"}]},{"title":"Test Your Application Locally","href":"/docs/v23.1/local-testing"},{"url":"https://www.cockroachlabs.com/docs/tutorials/sql-playground","title":"SQL Playground","href":"/links/tutorials/sql-playground"},{"group":"Database Management Tools","pages":[{"title":"Visualize CockroachDB Schemas with DBeaver","sidebarTitle":"DBeaver GUI","href":"/docs/v23.1/dbeaver"},{"title":"Use IntelliJ IDEA with CockroachDB","sidebarTitle":"IntelliJ IDEA","href":"/docs/v23.1/intellij-idea"}]},{"title":"JSON Support","href":"/docs/v23.1/demo-json-support"}]},{"group":"Stream Data","pages":[{"title":"Change Data Capture Overview","href":"/docs/v23.1/change-data-capture-overview"},{"group":"Get Started with Changefeeds","pages":[{"title":"Create and Configure Changefeeds","href":"/docs/v23.1/create-and-configure-changefeeds"},{"group":"Changefeed Messages","pages":[{"title":"Changefeed Messages","sidebarTitle":"Overview","href":"/docs/v23.1/changefeed-messages"}]},{"title":"Changefeed Sinks","href":"/docs/v23.1/changefeed-sinks"},{"title":"Changefeed Examples","href":"/docs/v23.1/changefeed-examples"}]},{"group":"Monitor Changefeeds","pages":[{"title":"Monitor and Debug Changefeeds","sidebarTitle":"Overview","href":"/docs/v23.1/monitor-and-debug-changefeeds"}]},{"group":"Optimize Changefeeds","pages":[{"title":"Change Data Capture Queries","href":"/docs/v23.1/cdc-queries"},{"title":"Changefeeds on Tables with Column Families","href":"/docs/v23.1/changefeeds-on-tables-with-column-families"},{"title":"Export Data with Changefeeds","href":"/docs/v23.1/export-data-with-changefeeds"},{"title":"Changefeeds in Multi-Region Deployments","href":"/docs/v23.1/changefeeds-in-multi-region-deployments"}]},{"group":"Changefeed Tutorials","pages":[{"title":"Connect to a Changefeed Kafka Sink with OAuth Using Okta","href":"/docs/v23.1/connect-to-a-changefeed-kafka-sink-with-oauth-using-okta"},{"title":"Stream a Changefeed to a Confluent Cloud Kafka Cluster","href":"/docs/v23.1/stream-a-changefeed-to-a-confluent-cloud-kafka-cluster"}]},{"title":"Advanced Changefeed Configuration","href":"/docs/v23.1/advanced-changefeed-configuration"}]},{"group":"Multi-Region Capabilities","pages":[{"title":"Multi-Region Capabilities Overview","sidebarTitle":"Overview","href":"/docs/v23.1/multiregion-overview"},{"title":"Multi-Region Survival Goals","sidebarTitle":"Survival Goals","href":"/docs/v23.1/multiregion-survival-goals"},{"group":"Data Domiciling and Performance","pages":[{"title":"Table Localities","href":"/docs/v23.1/table-localities"},{"title":"Table Partitioning","href":"/docs/v23.1/partitioning"},{"title":"Data Domiciling with CockroachDB","sidebarTitle":"Data Domiciling with CockroachDB Tutorial","href":"/docs/v23.1/data-domiciling"}]},{"title":"How to Choose a Multi-Region Configuration","href":"/docs/v23.1/choosing-a-multi-region-configuration"},{"title":"Multi-Region Zone Config Extensions","href":"/docs/v23.1/zone-config-extensions"},{"group":"Multi-Region Tutorials","pages":[{"title":"Low Latency Reads and Writes in a Multi-Region Cluster","sidebarTitle":"Low Latency Reads and Writes","href":"/docs/v23.1/demo-low-latency-multi-region-deployment"},{"title":"Migrate to Multi-Region SQL","sidebarTitle":"Migrate to Multi-Region SQL with Replication Zones","href":"/docs/v23.1/migrate-to-multiregion-sql"}]}]},{"group":"Optimize Performance","pages":[{"title":"Optimize Statement Performance Overview","sidebarTitle":"Overview","href":"/docs/v23.1/make-queries-fast"},{"title":"SQL Performance Best Practices","href":"/docs/v23.1/performance-best-practices-overview"},{"title":"Indexes","href":"/docs/v23.1/indexes"},{"title":"Map SQL Activity using an Application Name","href":"/docs/v23.1/map-sql-activity-to-app"},{"title":"Cost-Based Optimizer","href":"/docs/v23.1/cost-based-optimizer"},{"title":"Vectorized Query Execution","sidebarTitle":"Vectorized Execution Engine","href":"/docs/v23.1/vectorized-execution"},{"title":"Load-Based Splitting","href":"/docs/v23.1/load-based-splitting"},{"title":"Replication Controls","href":"/docs/v23.1/configure-replication-zones"},{"title":"Admission Control","description":null,"href":"/docs/v23.1/admission-control"},{"title":"Performance Tuning Recipes","href":"/docs/v23.1/performance-recipes"},{"group":"Performance Tuning Tutorials","pages":[{"title":"Statement Tuning with EXPLAIN","sidebarTitle":"Statement Tuning with EXPLAIN","description":null,"href":"/docs/v23.1/sql-tuning-with-explain"},{"title":"Apply SQL Statement Performance Rules","href":"/docs/v23.1/apply-statement-performance-rules"}]}]},{"group":"Integrate","pages":[{"title":"Integrate CockroachDB with Satori","sidebarTitle":"Integrate with Satori","href":"/docs/v23.1/satori-integration"}]}]},{"tab":"Migrate","icon":"arrow-right-arrow-left","pages":[{"title":"Migrate","href":"/docs/molt/migration-overview"}]},{"tab":"SQL","icon":"code","pages":[{"title":"SQL","href":"/docs/v23.1/sql-statements"}]},{"tab":"Reference","icon":"book","pages":[{"title":"Reference","href":"/docs/v23.1/architecture/glossary"}]},{"tab":"Cluster API","icon":"rocket","pages":[{"title":"Cluster API","href":"/docs/api/cluster"}]},{"tab":"Troubleshoot","icon":"bug","pages":[{"title":"Troubleshoot","href":"/docs/v23.1/troubleshooting-overview"}]}]}]},{"product":"Cloud Deployments","icon":"cloud","description":"Fully managed CockroachDB","pages":[{"title":"Cloud Deployments","href":"/docs/cockroachcloud"}]},{"product":"Releases","icon":"list","description":"Version history, support policy \u0026 advisories","pages":[{"title":"Releases","href":"/docs/releases"}]}]},"basePath":"","title":"Performance Tuning Recipes - CockroachDB","buildId":"dpl_DqYu5MPb49gWBBbUGgpHQUmCHY3P","deploymentId":"dpl_DqYu5MPb49gWBBbUGgpHQUmCHY3P","dynamics":["a74be98ba7"],"chunks":["zoom-image-lightbox-DTFzvaXJ.js","lightbox-handle-r17bVUz3.js"]}