Skip to content

Commit bfb3c53

Browse files
authored
Merge pull request #21074 from MikeRayMSFT/issue-7154
Clarify B+ tree
2 parents ebe4f97 + 51f3c5b commit bfb3c53

33 files changed

Lines changed: 132 additions & 68 deletions

File tree

docs/includes/sql-b-tree.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
author: MikeRayMSFT
3+
ms.service: sql
4+
ms.topic: include
5+
ms.date: 01/26/2022
6+
ms.author: mikeray
7+
---
8+
9+
> [!NOTE]
10+
> SQL Server documentation uses the term B-tree generally in reference to indexes. In rowstore indexes, SQL Server implements a B+ tree. This does not apply to columnstore indexes or in-memory data stores. Review [SQL Server Index Architecture and Design Guide](../relational-databases/sql-server-index-design-guide.md) for details.

docs/relational-databases/diagnose-resolve-latch-contention.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ Latch mode compatibility is listed in the following table (**Y** indicates compa
7474

7575
With the increasing presence of NUMA based multiple socket / multi-core systems, SQL Server 2005 introduced SuperLatches, also known as sublatches, which are effective only on systems with 32 or more logical processors. Superlatches improve efficiency of the SQL engine for certain usage patterns in highly concurrent OLTP workloads; for example, when certain pages have a pattern of heavy read-only shared (SH) access, but are written to rarely. An example of a page with such an access pattern is a B-tree (i.e. index) root page; the SQL engine requires that a shared latch is held on the root page when a page-split occurs at any level in the B-tree. In an insert-heavy and high-concurrency OLTP workload, the number of page splits will increase broadly in line with throughput, which can degrade performance. SuperLatches can enable increased performance for accessing shared pages where multiple concurrently running worker threads require SH latches. To accomplish this, the SQL Server Engine will dynamically promote a latch on such a page to a SuperLatch. A SuperLatch partitions a single latch into an array of sublatch structures, one sublatch per partition per CPU core, whereby the main latch becomes a proxy redirector and global state synchronization is not required for read-only latches. In doing so, the worker, which is always assigned to a specific CPU, only needs to acquire the shared (SH) sublatch assigned to the local scheduler.
7676

77+
[!INCLUDE [sql-b-tree](../includes/sql-b-tree.md)]
78+
7779
Acquisition of compatible latches, such as a shared Superlatch uses fewer resources and scales access to hot pages better than a non-partitioned shared latch because removing the global state synchronization requirement significantly improves performance by only accessing local NUMA memory. Conversely, acquiring an exclusive (EX) SuperLatch is more expensive than acquiring an EX regular latch as SQL must signal across all sublatches. When a SuperLatch is observed to use a pattern of heavy EX access, the SQL Engine can demote it after the page is discarded from the buffer pool. The following diagram depicts a normal latch and a partitioned SuperLatch:
7880

7981
![SQL Server Superlatch](./media/diagnose-resolve-latch-contention/image4.png)

docs/relational-databases/errors-events/database-engine-events-and-errors.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ ORDER BY message_id
459459
| [605](mssqlserver-605-database-engine-error.md) | 21 | Yes | Attempt to fetch logical page %S_PGID in database %d failed. It belongs to allocation unit %I64d not to %I64d. |
460460
| 606 | 21 | Yes | Metadata inconsistency. Filegroup id %ld specified for table '%.*ls' does not exist. Run DBCC CHECKDB or CHECKCATALOG. |
461461
| 608 | 16 | Yes | No catalog entry found for partition ID %I64d in database %d. The metadata is inconsistent. Run DBCC CHECKDB to check for a metadata corruption. |
462-
| 609 | 16 | No | BTree is not empty when waking up on RowsetBulk. |
462+
| 609 | 16 | No | B+ tree is not empty when waking up on RowsetBulk. |
463463
| 610 | 16 | Yes | Invalid header value from a page. Run DBCC CHECKDB to check for a data corruption. |
464464
| [611](mssqlserver-611-database-engine-error.md) | 16 | No | Cannot insert or update a row because total variable column size, including overhead, is %d bytes more than the limit. |
465465
| 613 | 21 | No | Could not find an entry for worktable rowset with partition ID %I64d in database %d. |

docs/relational-databases/import-export/prerequisites-for-minimal-logging-in-bulk-import.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ ms.author: mathoma
4848

4949
- If table is non-empty, index pages are fully logged.
5050

51-
- If the table has a clustered index and is empty, both data and index pages are minimally logged. In contrast, if a table has a btree based clustered index and is non-empty, data pages and index pages are both fully logged regardless of the recovery model. If you start with an empty table rowstore table and bulk import the data in batches, both index and data pages are minimally logged for the first batch, but from the second batch onwards, only data pages are bulk logged.
51+
- If the table has a clustered index and is empty, both data and index pages are minimally logged. In contrast, if a table has a B-tree based clustered index and is non-empty, data pages and index pages are both fully logged regardless of the recovery model. If you start with an empty table rowstore table and bulk import the data in batches, both index and data pages are minimally logged for the first batch, but from the second batch onwards, only data pages are bulk logged.
52+
53+
[!INCLUDE [sql-b-tree](../../includes/sql-b-tree.md)]
5254

5355
- For information about logging for a clustered columnstore index (CCI), see [Columnstore index data loading guidance](../indexes/columnstore-indexes-data-loading-guidance.md#plan-bulk-load-sizes-to-minimize-delta-rowgroups).
5456

docs/relational-databases/in-memory-oltp/a-guide-to-query-processing-for-memory-optimized-tables.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ SQL Server query processing pipeline.
113113
6. Access Methods retrieves the rows from the index and data pages in the buffer pool and loads pages from disk into the buffer pool as needed.
114114

115115
For the first example query, the execution engine requests rows in the clustered index on Customer and the nonclustered index on Order from Access Methods. Access Methods traverses the B-tree index structures to retrieve the requested rows. In this case all rows are retrieved as the plan calls for full index scans.
116+
117+
[!INCLUDE [sql-b-tree](../../includes/sql-b-tree.md)]
116118

117119
## Interpreted [!INCLUDE[tsql](../../includes/tsql-md.md)] Access to Memory-Optimized Tables
118120
[!INCLUDE[tsql](../../includes/tsql-md.md)] ad hoc batches and stored procedures are also referred to as interpreted [!INCLUDE[tsql](../../includes/tsql-md.md)]. Interpreted refers to the fact that the query plan is interpreted by the query execution engine for each operator in the query plan. The execution engine reads the operator and its parameters and performs the operation.

docs/relational-databases/in-memory-oltp/estimate-memory-requirements-for-memory-optimized-tables.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ Since we have three hash indexes, the memory needed for the hash indexes is 3 *
140140

141141
#### Memory for nonclustered indexes
142142

143-
Nonclustered indexes are implemented as BTrees with the inner nodes containing the index value and pointers to subsequent nodes. Leaf nodes contain the index value and a pointer to the table row in memory.
144-
143+
Nonclustered indexes are implemented as Bw-trees with the inner nodes containing the index value and pointers to subsequent nodes. Leaf nodes contain the index value and a pointer to the table row in memory.
144+
145145
Unlike hash indexes, nonclustered indexes do not have a fixed bucket size. The index grows and shrinks dynamically with the data.
146146

147147
Memory needed by nonclustered indexes can be computed as follows:

docs/relational-databases/in-memory-oltp/plan-your-adoption-of-in-memory-oltp-features-in-sql-server.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,9 @@ This section describes situations where the excellent performance of memory-opti
197197

198198
All indexes on a memory-optimized table are created and managed by the table-related statements CREATE TABLE and ALTER TABLE. You cannot target a memory-optimized table with a CREATE INDEX statement.
199199

200-
The traditional b-tree nonclustered index is often the sensible and simple choice when you first implement a memory-optimized table. Later, after you see how your application performs, you can consider swapping another index type.
200+
The traditional B-tree nonclustered index is often the sensible and simple choice when you first implement a memory-optimized table. Later, after you see how your application performs, you can consider swapping another index type.
201+
202+
[!INCLUDE [sql-b-tree](../../includes/sql-b-tree.md)]
201203

202204
Two special types of indexes need discussion in the context of a memory-optimized table: Hash indexes, and Columnstore indexes.
203205

docs/relational-databases/indexes/clustered-and-nonclustered-indexes-described.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ monikerRange: "=azuresqldb-current||>=sql-server-2016||>=sql-server-linux-2017||
2121

2222
An index is an on-disk structure associated with a table or view that speeds retrieval of rows from the table or view. An index contains keys built from one or more columns in the table or view. These keys are stored in a structure (B-tree) that enables [!INCLUDE[ssNoVersion](../../includes/ssnoversion-md.md)] to find the row or rows associated with the key values quickly and efficiently.
2323

24-
> [!NOTE]
25-
> SQL Server documentation uses the term B-tree generally in reference to indexes. In row store indexes, SQL Server implements a B+ tree. This does not apply to [columnstore](columnstore-indexes-overview.md) or in-memory data stores.
24+
[!INCLUDE [sql-b-tree](../../includes/sql-b-tree.md)]
2625

2726
A table or view can contain the following types of indexes:
2827

docs/relational-databases/indexes/columnstore-indexes-overview.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,12 @@ A clustered columnstore index is the physical storage for the entire table.
7373

7474
![Clustered columnstore index](../../relational-databases/indexes/media/sql-server-pdw-columnstore-physicalstorage.gif "Clustered Columnstore index")
7575

76-
To reduce fragmentation of the column segments and improve performance, the columnstore index might store some data temporarily into a clustered index called a *deltastore* and a btree list of IDs for deleted rows. The deltastore operations are handled behind the scenes. To return the correct query results, the clustered columnstore index combines query results from both the columnstore and the deltastore.
76+
To reduce fragmentation of the column segments and improve performance, the columnstore index might store some data temporarily into a clustered index called a *deltastore* and a B-tree list of IDs for deleted rows. The deltastore operations are handled behind the scenes. To return the correct query results, the clustered columnstore index combines query results from both the columnstore and the deltastore.
77+
78+
[!INCLUDE [sql-b-tree](../../includes/sql-b-tree.md)]
7779

7880
#### Delta rowgroup
81+
7982
A delta rowgroup is a clustered B-tree index that's used only with columnstore indexes. It improves columnstore compression and performance by storing rows until the number of rows reaches a threshold (1,048,576 rows) and are then moved into the columnstore.
8083

8184
When a delta rowgroup reaches the maximum number of rows, it transitions from an OPEN to CLOSED state. A background process named the tuple-mover checks for closed row groups. If the process finds a closed rowgroup, it compresses the delta rowgroup and stores it into the columnstore as a COMPRESSED rowgroup.
@@ -103,7 +106,7 @@ A nonclustered columnstore index enables real-time operational analytics where t
103106
Batch mode execution is a query processing method that's used to process multiple rows together. Batch mode execution is closely integrated with, and optimized around, the columnstore storage format. Batch mode execution is sometimes known as *vector-based* or *vectorized* execution. Queries on columnstore indexes use batch mode execution, which improves query performance typically by two to four times. For more information, see the [Query processing architecture guide](../query-processing-architecture-guide.md#execution-modes).
104107

105108
## <a name="benefits"></a> Why should I use a columnstore index?
106-
A columnstore index can provide a very high level of data compression, typically by 10 times, to significantly reduce your data warehouse storage cost. For analytics, a columnstore index offers an order of magnitude better performance than a btree index. Columnstore indexes are the preferred data storage format for data warehousing and analytics workloads. Starting with [!INCLUDE[sssql16-md](../../includes/sssql16-md.md)], you can use columnstore indexes for real-time analytics on your operational workload.
109+
A columnstore index can provide a very high level of data compression, typically by 10 times, to significantly reduce your data warehouse storage cost. For analytics, a columnstore index offers an order of magnitude better performance than a B-tree index. Columnstore indexes are the preferred data storage format for data warehousing and analytics workloads. Starting with [!INCLUDE[sssql16-md](../../includes/sssql16-md.md)], you can use columnstore indexes for real-time analytics on your operational workload.
107110

108111
Reasons why columnstore indexes are so fast:
109112

@@ -204,10 +207,10 @@ When you create a table with the `CREATE TABLE` statement, you can create the ta
204207
|Convert a rowstore table to a columnstore.|[CREATE COLUMNSTORE INDEX &#40;Transact-SQL&#41;](../../t-sql/statements/create-columnstore-index-transact-sql.md)|Convert an existing heap or binary tree to a columnstore. Examples show how to handle existing indexes and also the name of the index when performing this conversion.|
205208
|Convert a columnstore table to a rowstore.|[CREATE CLUSTERED INDEX &#40;Transact-SQL&#41;](../../t-sql/statements/create-columnstore-index-transact-sql.md#d-convert-a-columnstore-table-to-a-rowstore-table-with-a-clustered-index) or [Convert a columnstore table back to a rowstore heap](../../t-sql/statements/create-columnstore-index-transact-sql.md#e-convert-a-columnstore-table-back-to-a-rowstore-heap) |Usually this conversion isn't necessary, but there can be times when you need to convert. Examples show how to convert a columnstore to a heap or clustered index.|
206209
|Create a columnstore index on a rowstore table.|[CREATE COLUMNSTORE INDEX &#40;Transact-SQL&#41;](../../t-sql/statements/create-columnstore-index-transact-sql.md)|A rowstore table can have one columnstore index. Beginning with [!INCLUDE[sssql16-md](../../includes/sssql16-md.md)], the columnstore index can have a filtered condition. Examples show the basic syntax.|
207-
|Create performant indexes for operational analytics.|[Get started with columnstore for real-time operational analytics](../../relational-databases/indexes/get-started-with-columnstore-for-real-time-operational-analytics.md)|Describes how to create complementary columnstore and btree indexes, so that OLTP queries use btree indexes and analytics queries use columnstore indexes.|
208-
|Create performant columnstore indexes for data warehousing.|[Columnstore indexes for data warehousing](~/relational-databases/indexes/columnstore-indexes-data-warehouse.md)|Describes how to use btree indexes on columnstore tables to create performant data warehousing queries.|
209-
|Use a btree index to enforce a primary key constraint on a columnstore index.|[Columnstore indexes for data warehousing](~/relational-databases/indexes/columnstore-indexes-data-warehouse.md)|Shows how to combine btree and columnstore indexes to enforce primary key constraints on the columnstore index.|
210-
|Drop a columnstore index.|[DROP INDEX &#40;Transact-SQL&#41;](../../t-sql/statements/drop-index-transact-sql.md)|Dropping a columnstore index uses the standard `DROP INDEX` syntax that btree indexes use. Dropping a clustered columnstore index converts the columnstore table to a heap.|
210+
|Create performant indexes for operational analytics.|[Get started with columnstore for real-time operational analytics](../../relational-databases/indexes/get-started-with-columnstore-for-real-time-operational-analytics.md)|Describes how to create complementary columnstore and B-tree indexes, so that OLTP queries use B-tree indexes and analytics queries use columnstore indexes.|
211+
|Create performant columnstore indexes for data warehousing.|[Columnstore indexes for data warehousing](~/relational-databases/indexes/columnstore-indexes-data-warehouse.md)|Describes how to use B-tree indexes on columnstore tables to create performant data warehousing queries.|
212+
|Use a B-tree index to enforce a primary key constraint on a columnstore index.|[Columnstore indexes for data warehousing](~/relational-databases/indexes/columnstore-indexes-data-warehouse.md)|Shows how to combine B-tree and columnstore indexes to enforce primary key constraints on the columnstore index.|
213+
|Drop a columnstore index.|[DROP INDEX &#40;Transact-SQL&#41;](../../t-sql/statements/drop-index-transact-sql.md)|Dropping a columnstore index uses the standard `DROP INDEX` syntax that B-tree indexes use. Dropping a clustered columnstore index converts the columnstore table to a heap.|
211214
|Delete a row from a columnstore index.|[DELETE &#40;Transact-SQL&#41;](../../t-sql/statements/delete-transact-sql.md)|Use [DELETE &#40;Transact-SQL&#41;](../../t-sql/statements/delete-transact-sql.md) to delete a row.<br /><br /> **columnstore row**: [!INCLUDE[ssNoVersion](../../includes/ssnoversion-md.md)] marks the row as logically deleted, but doesn't reclaim the physical storage for the row until the index is rebuilt.<br /><br /> **deltastore row**: [!INCLUDE[ssNoVersion](../../includes/ssnoversion-md.md)] logically and physically deletes the row.|
212215
|Update a row in the columnstore index.|[UPDATE &#40;Transact-SQL&#41;](../../t-sql/queries/update-transact-sql.md)|Use [UPDATE &#40;Transact-SQL&#41;](../../t-sql/queries/update-transact-sql.md) to update a row.<br /><br /> **columnstore row**: [!INCLUDE[ssNoVersion](../../includes/ssnoversion-md.md)] marks the row as logically deleted and then inserts the updated row into the deltastore.<br /><br /> **deltastore row**: [!INCLUDE[ssNoVersion](../../includes/ssnoversion-md.md)] updates the row in the deltastore.|
213216
|Load data into a columnstore index.|[Columnstore indexes data loading](~/relational-databases/indexes/columnstore-indexes-data-loading-guidance.md)||

0 commit comments

Comments
 (0)