Руководство по обработке запросов для таблиц, оптимизированных для памятиA Guide to Query Processing for Memory-Optimized Tables

Применимо к:Applies to: даSQL ServerSQL Server (все поддерживаемые версии) yesSQL ServerSQL Server (all supported versions) ДаБаза данных SQL AzureAzure SQL DatabaseYesБаза данных SQL AzureAzure SQL DatabaseПрименимо к:Applies to: даSQL ServerSQL Server (все поддерживаемые версии) yesSQL ServerSQL Server (all supported versions) ДаБаза данных SQL AzureAzure SQL DatabaseYesБаза данных SQL AzureAzure SQL Database

В SQL ServerSQL ServerIn-Memory OLTP вводятся оптимизированные для памяти таблицы и скомпилированные в собственном коде хранимые процедуры.In-Memory OLTP introduces memory-optimized tables and natively compiled stored procedures in SQL ServerSQL Server. В данной статье приводится обзор обработки запросов для таблиц, оптимизированных для памяти, и хранимых процедур, скомпилированных в собственном коде.This article gives an overview of query processing for both memory-optimized tables and natively compiled stored procedures.

Документ поясняет процесс компиляции и выполнения запросов к таблицам, оптимизированным для памяти, включая:The document explains how queries on memory-optimized tables are compiled and executed, including:

  • канал обработки запросов в SQL ServerSQL Server для дисковых таблиц;The query processing pipeline in SQL ServerSQL Server for disk-based tables.

  • оптимизацию запросов, роль статистических данных в таблицах, оптимизированных для памяти, а также рекомендации по решению проблем, связанных с неоптимальными планами запросов;Query optimization; the role of statistics on memory-optimized tables as well as guidelines for troubleshooting bad query plans.

  • использование интерпретируемого кода Transact-SQLTransact-SQL для доступа к таблицам, оптимизированным для памяти.The use of interpreted Transact-SQLTransact-SQL to access memory-optimized tables.

  • аспекты оптимизации запросов для доступа к таблицам, оптимизированным для памяти;Considerations about query optimization for memory-optimized table access.

  • компиляция и обработка хранимых процедур, скомпилированных в собственном коде;Natively compiled stored procedure compilation and processing.

  • статистические данные, которые используются для оценки затрат оптимизатора;Statistics that are used for cost estimation by the optimizer.

  • способы исправления неоптимальных планов запросов;Ways to fix bad query plans.

Пример запросаExample Query

Следующий пример иллюстрирует концепции обработки запросов, рассматриваемые в данной статье.The following example will be used to illustrate the query processing concepts discussed in this article.

Мы рассмотрим две таблицы, Customer и Order.We consider two tables, Customer and Order. Следующий скрипт Transact-SQLTransact-SQL содержит определения для этих двух таблиц и связанных индексов (в их традиционной форме для таблиц на диске):The following Transact-SQLTransact-SQL script contains the definitions for these two tables and associated indexes, in their (traditional) disk-based form:

CREATE TABLE dbo.[Customer] (  
  CustomerID nchar (5) NOT NULL PRIMARY KEY,  
  ContactName nvarchar (30) NOT NULL   
)  
GO  
  
CREATE TABLE dbo.[Order] (  
  OrderID int NOT NULL PRIMARY KEY,  
  CustomerID nchar (5) NOT NULL,  
  OrderDate date NOT NULL  
)  
GO  
CREATE INDEX IX_CustomerID ON dbo.[Order](CustomerID)  
GO  
CREATE INDEX IX_OrderDate ON dbo.[Order](OrderDate)  
GO  

Для конструирования планов запросов, показанных в данной статье, две таблицы были заполнены примерами данных из учебной базы данных Northwind, которую можно загрузить по следующий ссылке: Образцы баз данных Northwind и pubs для SQL Server 2000.For constructing the query plans shown in this article, the two tables were populated with sample data from the Northwind sample database, which you can download from Northwind and pubs Sample Databases for SQL Server 2000.

Рассмотрим следующий запрос, который выполняет соединение таблиц Customer и Order и возвращает идентификатор заказа и связанную с ним информацию о клиенте:Consider the following query, which joins the tables Customer and Order and returns the ID of the order and the associated customer information:

SELECT o.OrderID, c.* FROM dbo.[Customer] c INNER JOIN dbo.[Order] o ON c.CustomerID = o.CustomerID  

Предполагаемый план выполнения в соответствии с отображением в SQL Server Management StudioSQL Server Management Studio следующий:The estimated execution plan as displayed by SQL Server Management StudioSQL Server Management Studio is as follows

План запроса для соединения дисковых таблиц.Query plan for join of disk-based tables.
План запроса для соединения дисковых таблиц.Query plan for join of disk-based tables.

О данном плане запроса:About this query plan:

  • строки из таблицы Customer получены из кластеризованного индекса, который представляет собой основную структуру данных и содержит все данные таблицы;The rows from the Customer table are retrieved from the clustered index, which is the primary data structure and has the full table data.

  • данные из таблицы Order получены с помощью некластеризованного индекса в столбце CustomerID.Data from the Order table is retrieved using the nonclustered index on the CustomerID column. Этот индекс содержит столбец CustomerID, который используется для соединения, и столбец первичного ключа OrderID, который возвращается пользователю.This index contains both the CustomerID column, which is used for the join, and the primary key column OrderID, which is returned to the user. Для возвращения дополнительных столбцов из таблицы Order потребуется поиск по кластеризованному индексу для таблицы Order.Returning additional columns from the Order table would require lookups in the clustered index for the Order table.

  • Логический оператор Inner Join реализован в форме физического оператора Merge Join.The logical operator Inner Join is implemented by the physical operator Merge Join. Остальные физические типы соединений — это Nested Loops и Hash Join.The other physical join types are Nested Loops and Hash Join. В операторе Merge Join используется то обстоятельство, что оба индекса отсортированы по столбцу соединения CustomerID.The Merge Join operator takes advantage of the fact that both indexes are sorted on the join column CustomerID.

Рассмотрим немного другую версию этого запроса, которая возвращает все строки из таблицы Order, а не только OrderID.Consider a slight variation on this query, which returns all rows from the Order table, not only OrderID:

SELECT o.*, c.* FROM dbo.[Customer] c INNER JOIN dbo.[Order] o ON c.CustomerID = o.CustomerID  

Предполагаемый план выполнения для этого запроса:The estimated plan for this query is:

план запроса для хэш-соединений дисковых таблиц.Query plan for a hash join of disk-based tables.
план запроса для хэш-соединений дисковых таблиц.Query plan for a hash join of disk-based tables.

В этом запросе строки из таблицы заказов получаются с помощью кластеризованного индекса.In this query, rows from the Order table are retrieved using the clustered index. Физический оператор Hash Match теперь используется для Inner Join.The Hash Match physical operator is now used for the Inner Join. Кластеризованный индекс в таблице Order не отсортирован по столбцу CustomerID, поэтому для Merge Join потребуется оператор сортировки, который повлияет на производительность запроса.The clustered index on Order is not sorted on CustomerID, and so a Merge Join would require a sort operator, which would affect performance. Обратите внимание на относительную стоимость оператора Hash Match (75 %) по сравнению с затратами оператора Merge Join в предыдущем примере (46 %).Note the relative cost of the Hash Match operator (75%) compared with the cost of the Merge Join operator in the previous example (46%). Оптимизатором также рассматривался оператор Hash Match из предыдущего примера, но оказалось, что оператор Merge Join обеспечивает лучшую производительность.The optimizer would have considered the Hash Match operator also in the previous example, but concluded that the Merge Join operator gave better performance.

SQL ServerSQL Server Обработка запросов для дисковых таблицQuery Processing for Disk-Based Tables

На следующей диаграмме показан поток обработки запросов в SQL ServerSQL Server для нерегламентированных запросов:The following diagram outlines the query processing flow in SQL ServerSQL Server for ad hoc queries:

Канал обработки запросов в SQL Server.SQL Server query processing pipeline.
Канал обработки запросов в SQL Server.SQL Server query processing pipeline.

В этом сценарии:In this scenario:

  1. Пользователь выполняет запрос.The user issues a query.

  2. Средство синтаксического анализа и алгебризатор с помощью логических операторов строят дерево запросов в соответствии с тексом Transact-SQLTransact-SQL , переданным пользователем.The parser and algebrizer construct a query tree with logical operators based on the Transact-SQLTransact-SQL text submitted by the user.

  3. Оптимизатор создает оптимизированный план запроса, содержащий физические операторы (например, соединения вложенных циклов).The optimizer creates an optimized query plan containing physical operators (for example, nested-loops join). После оптимизации план может храниться в кэше планов.After optimization, the plan may be stored in the plan cache. Это действие пропускается, если кэш планов уже содержит план для этого запроса.This step is bypassed if the plan cache already contains a plan for this query.

  4. Подсистема выполнения запросов обрабатывает интерпретацию плана запроса.The query execution engine processes an interpretation of the query plan.

  5. Для каждого оператора поиска в индексе, просмотра индекса и просмотра таблицы подсистема выполнения запрашивает строки из соответствующего индекса и табличных структур у методов доступа.For each index seek, index scan, and table scan operator, the execution engine requests rows from the respective index and table structures from Access Methods.

  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.

В первом примере запроса подсистема выполнения запрашивает у методов доступа строки в кластеризованном индексе таблицы Customer и в некластеризованном индексе таблицы Order.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.

Доступ к оптимизированным для памяти таблицам с помощью интерпретируемого кода Transact-SQLTransact-SQLInterpreted Transact-SQLTransact-SQL Access to Memory-Optimized Tables

Transact-SQLTransact-SQL также называются интерпретируемым кодом Transact-SQLTransact-SQL.ad hoc batches and stored procedures are also referred to as interpreted Transact-SQLTransact-SQL. Термин «интерпретируемый» означает, что план запроса интерпретируется подсистемой выполнения запросов для каждого оператора в плане запроса.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.

Интерпретируемый код Transact-SQLTransact-SQL можно использовать для доступа к таблицам, оптимизированных для памяти, и к дисковым таблицам.Interpreted Transact-SQLTransact-SQL can be used to access both memory-optimized and disk-based tables. На следующей диаграмме показана обработка запросов для доступа с помощью интерпретируемого кода Transact-SQLTransact-SQL к таблицам, оптимизированным для памяти.The following figure illustrates query processing for interpreted Transact-SQLTransact-SQL access to memory-optimized tables:

Канал обработки запросов для интерпретируемых инструкций tsql.Query processing pipeline for interpreted tsql.
Конвейер обработки запросов для доступа к оптимизированным для памяти таблицам с помощью интерпретируемого кода Transact-SQL.Query processing pipeline for interpreted Transact-SQL access to memory-optimized tables.

Как показано на рисунке, конвейер обработки запросов в основном остается неизменным:As illustrated by the figure, the query processing pipeline remains mostly unchanged:

  • средство синтаксического анализа и алгебризатор строят дерево запроса;The parser and algebrizer construct the query tree.

  • оптимизатор запросов создает план выполнения;The optimizer creates the execution plan.

  • подсистема выполнения запроса интерпретирует план выполнения;The query execution engine interprets the execution plan.

Основное отличие от традиционного конвейера обработки запросов (рис. 2) заключается в том, что строки для оптимизированной для памяти таблицы получаются из буферного пула при помощи методов доступа.The main difference with the traditional query processing pipeline (figure 2) is that rows for memory-optimized tables are not retrieved from the buffer pool using Access Methods. Вместо этого строки извлекаются из структур данных в памяти с помощью подсистемы In-Memory OLTP.Instead, rows are retrieved from the in-memory data structures through the In-Memory OLTP engine. Из-за различий в структурах данных оптимизатор в некоторых случаях выбирает разные планы, как показано в следующем примере.Differences in data structures cause the optimizer to pick different plans in some cases, as illustrated by the following example.

Следующий скрипт Transact-SQLTransact-SQL содержит оптимизированные для памяти версии таблиц Order и Customer, использующих хэш-индексы:The following Transact-SQLTransact-SQL script contains memory-optimized versions of the Order and Customer tables, using hash indexes:

CREATE TABLE dbo.[Customer] (  
  CustomerID nchar (5) NOT NULL PRIMARY KEY NONCLUSTERED,  
  ContactName nvarchar (30) NOT NULL   
) WITH (MEMORY_OPTIMIZED=ON)  
GO  
  
CREATE TABLE dbo.[Order] (  
  OrderID int NOT NULL PRIMARY KEY NONCLUSTERED,  
  CustomerID nchar (5) NOT NULL INDEX IX_CustomerID HASH(CustomerID) WITH (BUCKET_COUNT=100000),  
  OrderDate date NOT NULL INDEX IX_OrderDate HASH(OrderDate) WITH (BUCKET_COUNT=100000)  
) WITH (MEMORY_OPTIMIZED=ON)  
GO  

Тот же запрос, выполненный к таблицам, оптимизированным для памяти:Consider the same query executed on memory-optimized tables:

SELECT o.OrderID, c.* FROM dbo.[Customer] c INNER JOIN dbo.[Order] o ON c.CustomerID = o.CustomerID  

Предполагаемый план:The estimated plan is as follows:

План запроса для соединения таблиц, оптимизированных для памяти.Query plan for join of memory optimized tables.
План запроса для соединения таблиц, оптимизированных для памяти.Query plan for join of memory-optimized tables.

Изучите следующие отличия от плана для того же запроса к дисковым таблицам (рисунок 1):Observe the following differences with the plan for the same query on disk-based tables (figure 1):

  • Этот план для таблицы Customer содержит операцию просмотра таблицы, а не просмотра кластеризованного индекса.This plan contains a table scan rather than a clustered index scan for the table Customer:

    • Определение таблицы не содержит кластеризованный индекс.The definition of the table does not contain a clustered index.

    • Кластеризованные индексы для таблиц, оптимизированных для памяти, не поддерживаются.Clustered indexes are not supported with memory-optimized tables. Вместо этого каждая оптимизированная для памяти таблица должна содержать по крайней мере один некластеризованный индекс, а все индексы для оптимизированных в памяти таблиц могут эффективно получать все столбцы таблицы без сохранения их в индексе или ссылки на кластеризованный индекс.Instead, every memory-optimized table must have at least one nonclustered index and all indexes on memory-optimized tables can efficiently access all columns in the table without having to store them in the index or refer to a clustered index.

  • Этот план содержит оператор Hash Match , а не Merge Join.This plan contains a Hash Match rather than a Merge Join. Индексы в таблицах Order и Customer представляют собой хэш-индексы и, следовательно, не упорядочены.The indexes on both the Order and the Customer table are hash indexes, and are thus not ordered. Оператор Merge Join потребовал бы добавления операторов сортировки, которые вызвали бы снижение производительности запроса.A Merge Join would require sort operators that would decrease performance.

скомпилированные в собственном коде хранимые процедурыNatively Compiled Stored Procedures

Скомпилированные в собственном коде хранимые процедуры — это хранимые процедуры Transact-SQLTransact-SQL , скомпилированные в машинный код, а не интерпретируемые подсистемой выполнения запросов.Natively compiled stored procedures are Transact-SQLTransact-SQL stored procedures compiled to machine code, rather than interpreted by the query execution engine. Следующий скрипт создает скомпилированную в собственном коде хранимую процедуру, которая выполняет пример запроса (из раздела «Пример запроса»).The following script creates a natively compiled stored procedure that runs the example query (from the Example Query section).

CREATE PROCEDURE usp_SampleJoin  
WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER  
AS BEGIN ATOMIC WITH   
(  TRANSACTION ISOLATION LEVEL = SNAPSHOT,  
  LANGUAGE = 'english')  
  
  SELECT o.OrderID, c.CustomerID, c.ContactName   
FROM dbo.[Order] o INNER JOIN dbo.[Customer] c   
  ON c.CustomerID = o.CustomerID  
  
END  

Скомпилированные в собственном коде хранимые процедуры компилируются при создании, а интерпретируемые хранимые процедуры компилируются в ходе первого выполнения.Natively compiled stored procedures are compiled at create time, whereas interpreted stored procedures are compiled at first execution time. (Частично компиляция, в частности, синтаксический анализ и алгебризация, выполняется при создании.(A portion of the compilation, particularly parsing and algebrization, take place at create. Однако для интерпретируемых хранимых процедур оптимизация планов запросов происходит при первом выполнении.) Процесс повторной компиляции имеет аналогичную логику.However, for interpreted stored procedures, optimization of the query plans takes place at first execution.) The recompilation logic is similar. При первом выполнении процедуры после перезапуска сервера выполняется перекомпиляция скомпилированных в собственном коде хранимых процедур.Natively compiled stored procedures are recompiled on first execution of the procedure if the server is restarted. Интерпретируемые хранимые процедуры повторно компилируются, если в кэше планов отсутствует план запроса.Interpreted stored procedures are recompiled if the plan is no longer in the plan cache. В следующей таблице объединены случаи компиляции и повторной компиляции для скомпилированных в собственном коде и интерпретируемых хранимых процедур.The following table summarizes compilation and recompilation cases for both natively compiled and interpreted stored procedures:

Тип компиляцииCompilation type Скомпилированные в собственном кодеNatively compiled Доступ к оптимизированным для памяти таблицам с помощью интерпретируемого кодаInterpreted
Первичная компиляцияInitial compilation При создании.At create time. При первом выполнении.At first execution.
Автоматическая повторная компиляцияAutomatic recompilation При первом выполнении процедуры после перезапуска базы данных или сервера.Upon first execution of the procedure after a database or server restart. При перезапуске сервера.On server restart. Либо при вытеснении из кэша планов, обычно вследствие изменений схемы или статистических данных или нагрузки на память.Or, eviction from the plan cache, usually based on schema or stats changes, or memory pressure.
Повторная компиляция вручнуюManual recompilation Используйте sp_recompile.Use sp_recompile. Используйте sp_recompile.Use sp_recompile. Можно вручную удалить план из кэша при помощи инструкции DBCC FREEPROCCACHE.You can manually evict the plan from the cache, for example through DBCC FREEPROCCACHE. Можно также создать хранимую процедуру с параметром WITH RECOMPILE; такая хранимая процедура будет повторно компилироваться при каждом выполнении.You can also create the stored procedure WITH RECOMPILE and the stored procedure will be recompiled at every execution.

Компиляция и обработка запросовCompilation and Query Processing

На следующей диаграмме показан процесс компиляции для скомпилированных в собственном коде хранимых процедур:The following diagram illustrates the compilation process for natively compiled stored procedures:

Компиляция хранимых процедур в собственном коде.Native compilation of stored procedures.
Компиляция хранимых процедур в собственном коде.Native compilation of stored procedures.

Описание процессаThe process is described as,

  1. Пользователь выполняет инструкцию CREATE PROCEDURE в отношении SQL ServerSQL Server.The user issues a CREATE PROCEDURE statement to SQL ServerSQL Server.

  2. Средство синтаксического анализа и алгебризатор создают поток обработки для процедуры, а также запрашивают деревья для запросов Transact-SQLTransact-SQL в хранимой процедуре.The parser and algebrizer create the processing flow for the procedure, as well as query trees for the Transact-SQLTransact-SQL queries in the stored procedure.

  3. Оптимизатор запросов создает оптимизированные планы выполнения запросов для всех запросов в данной хранимой процедуре.The optimizer creates optimized query execution plans for all the queries in the stored procedure.

  4. Компилятор In-Memory OLTP принимает поток обработки с внедренными оптимизированными планами запросов и создает библиотеку DLL, которая содержит машинный код для выполнения хранимой процедуры.The In-Memory OLTP compiler takes the processing flow with the embedded optimized query plans and generates a DLL that contains the machine code for executing the stored procedure.

  5. Созданная библиотека DDL загружается в память.The generated DLL is loaded into memory.

Вызов хранимой процедуры, скомпилированной в собственном коде, транслируется в вызов функции из библиотеки DLL.Invocation of a natively compiled stored procedure translates to calling a function in the DLL.

Выполнение хранимых процедур, скомпилированных в собственном коде.Execution of natively compiled stored procedures.
Выполнение хранимых процедур, скомпилированных в собственном коде.Execution of natively compiled stored procedures.

Описание вызова хранимой процедуры, скомпилированной в собственном коде:Invocation of a natively compiled stored procedure is described as follows:

  1. Пользователь выполняет инструкцию EXEC usp_myproc.The user issues an EXEC usp_myproc statement.

  2. Средство синтаксического анализа извлекает имя и параметры хранимой процедуры.The parser extracts the name and stored procedure parameters.

    Если инструкция подготовлена, например, с помощью sp_prep_exec, анализатору не придется извлекать имя процедуры и параметры во время выполнения.If the statement was prepared, for example using sp_prep_exec, the parser does not need to extract the procedure name and parameters at execution time.

  3. Среда выполнения In-Memory OLTP находит точки входа библиотеки DLL для хранимой процедуры.The In-Memory OLTP runtime locates the DLL entry point for the stored procedure.

  4. Машинный код в DLL выполняется, и результаты возвращаются клиенту.The machine code in the DLL is executed and the results of are returned to the client.

Пробное сохранение параметровParameter sniffing

Интерпретируемые хранимые процедуры Transact-SQLTransact-SQL компилируются во время первого выполнения в отличие от хранимых процедур, скомпилированных в собственном коде, которые компилируются при создании.Interpreted Transact-SQLTransact-SQL stored procedures are compiled at first execution, in contrast to natively compiled stored procedures, which are compiled at create time. Если интерпретируемые хранимые процедуры компилируются при вызове, значения параметров, указанные для этого вызова, используются оптимизатором для создания плана выполнения.When interpreted stored procedures are compiled at invocation, the values of the parameters supplied for this invocation are used by the optimizer when generating the execution plan. Такое использование параметров в процессе компиляции называется пробным сохранением параметров.This use of parameters during compilation is called parameter sniffing.

Пробное сохранение параметров не используется для компиляции хранимых процедур, скомпилированных в собственном коде.Parameter sniffing is not used for compiling natively compiled stored procedures. Предполагается, что у всех параметров хранимой процедуры значения UNKNOWN (неизвестны).All parameters to the stored procedure are considered to have UNKNOWN values. Как и интерпретируемые хранимые процедуры, скомпилированные в собственном коде хранимые процедуры также поддерживают указание OPTIMIZE FOR .Like interpreted stored procedures, natively compiled stored procedures also support the OPTIMIZE FOR hint. Дополнительные сведения см. в разделе Указания запросов (Transact-SQL).For more information, see Query Hints (Transact-SQL).

Получение плана выполнения запроса для скомпилированных в собственном коде хранимых процедурRetrieving a Query Execution Plan for Natively Compiled Stored Procedures

План выполнения запроса для скомпилированной в собственном коде хранимой процедуры можно получить с помощью предполагаемого плана выполнения в среде Среда Management StudioManagement Studioили с помощью параметра SHOWPLAN_XML в Transact-SQLTransact-SQL.The query execution plan for a natively compiled stored procedure can be retrieved using Estimated Execution Plan in Среда Management StudioManagement Studio, or using the SHOWPLAN_XML option in Transact-SQLTransact-SQL. Пример:For example:

SET SHOWPLAN_XML ON  
GO  
EXEC dbo.usp_myproc  
GO  
SET SHOWPLAN_XML OFF  
GO  

План выполнения, созданный с помощью оптимизатора запросов, состоит из дерева с операторами запроса на узлах и конечных узлах дерева.The execution plan generated by the query optimizer consists of a tree with query operators on the nodes and leaves of the tree. Структура дерева определяет механизм взаимодействия (поток строк от одного оператора к другому) между операторами.The structure of the tree determines the interaction (the flow of rows from one operator to another) between the operators. В графическом представлении SQL Server Management StudioSQL Server Management Studioизображен поток справа налево.In the graphical view of SQL Server Management StudioSQL Server Management Studio, the flow is from right to left. Например, план запроса в диаграмме 1 содержит два оператора просмотра индекса, которые передают строки оператору соединения слиянием.For example, the query plan in figure 1 contains two index scan operators, which supplies rows to a merge join operator. Оператор соединения слиянием merge join передает строки оператору выбора select.The merge join operator supplies rows to a select operator. Наконец, оператор Select возвращает строки клиенту.The select operator, finally, returns the rows to the client.

Операторы запросов в хранимых процедурах, скомпилированных в собственном кодеQuery Operators in Natively Compiled Stored Procedures

В следующей таблице перечислены операторы запросов, которые поддерживаются в хранимых процедурах, скомпилированных в собственном коде.The following table summarizes the query operators supported inside natively compiled stored procedures:

ОператорOperator Пример запросаSample query ПримечанияNotes
SELECTSELECT SELECT OrderID FROM dbo.[Order]
INSERTINSERT INSERT dbo.Customer VALUES ('abc', 'def')
UPDATEUPDATE UPDATE dbo.Customer SET ContactName='ghi' WHERE CustomerID='abc'
DELETEDELETE DELETE dbo.Customer WHERE CustomerID='abc'
Compute ScalarCompute Scalar SELECT OrderID+1 FROM dbo.[Order] Этот оператор используется как для встроенных функций, так и для преобразований типов.This operator is used both for intrinsic functions and type conversions. Не все функции и преобразования типов поддерживаются в хранимых процедурах, скомпилированных в собственном коде.Not all functions and type conversions are supported inside natively compiled stored procedures.
Соединение вложенными цикламиNested Loops Join SELECT o.OrderID, c.CustomerID FROM dbo.[Order] o INNER JOIN dbo.[Customer] c Nested Loops — единственный оператор соединения, который поддерживается в хранимых процедурах, скомпилированных в собственном коде.Nested Loops is the only join operator supported in natively compiled stored procedures. Все планы, которые содержат соединения, будут использовать оператор Nested Loops, даже если план одного и того же запроса, выполненного как интерпретируемый код Transact-SQLTransact-SQL , содержит хэш-соединение или соединение слиянием.All plans that contain joins will use the Nested Loops operator, even if the plan for same query executed as interpreted Transact-SQLTransact-SQL contains a hash or merge join.
СортировкаSort SELECT ContactName FROM dbo.Customer ORDER BY ContactName
TOPTop SELECT TOP 10 ContactName FROM dbo.Customer
Оператор Top-sortTop-sort SELECT TOP 10 ContactName FROM dbo.Customer ORDER BY ContactName Выражение TOP (количество возвращаемых строк) не может превышать 8000 строк.The TOP expression (the number of rows to be returned) cannot exceed 8,000 rows. Если в запросе есть операторы объединения и агрегирования, то строк должно быть еще меньше.Fewer if there are also join and aggregation operators in the query. Соединения и агрегатные выражения обычно уменьшают количество строк для сортировки в сравнении с количеством строк в базовых таблицах.Joins and aggregation do typically reduce the number of rows to be sorted, compared with the row count of the base tables.
Статистическое выражение потокаStream Aggregate SELECT count(CustomerID) FROM dbo.Customer Обратите внимание, что оператор Hash Match для статической обработки не поддерживается.Note that the Hash Match operator is not supported for aggregation. Поэтому все агрегаты в скомпилированных в собственном коде хранимых процедурах используют оператор Stream Aggregate, даже если план для этого же запроса в интерпретируемом Transact-SQLTransact-SQL использует оператор Hash Match.Therefore, all aggregation in natively compiled stored procedures uses the Stream Aggregate operator, even if the plan for the same query in interpreted Transact-SQLTransact-SQL uses the Hash Match operator.

Статистика столбцов и соединенияColumn Statistics and Joins

SQL ServerSQL Server ведет статистику значений в ключевых столбцах индекса, что позволяет оценить стоимость отдельных операций, таких как просмотр индекса и поиск в индексе.maintains statistics on values in index key columns to help estimate the cost of certain operations, such as index scan and index seeks. (SQL ServerSQL Server также создает статистику по ключевым столбцам вне индекса, если они создаются явно или если оптимизатор запросов создает их в ответ на запрос с предикатом.) Основной показатель в оценке стоимости — количество строк, обрабатываемых одним оператором.( SQL ServerSQL Server also creates statistics on non-index key columns if you explicitly create them or if the query optimizer creates them in response to a query with a predicate.) The main metric in cost estimation is the number of rows processed by a single operator. Обратите внимание, что для дисковых таблиц количество страниц, к которым обращается конкретный оператор, является существенным для оценки стоимости.Note that for disk-based tables, the number of pages accessed by a particular operator is significant in cost estimation. Тем не менее, поскольку количество страниц не имеет значения для таблиц, оптимизированных для памяти (оно всегда равно нулю), мы сосредоточимся на количестве строк.However, as page count is not important for memory-optimized tables (it is always zero), this discussion focuses on row count. Оценка начинается с операторов поиска в индексе и просмотра индекса в плане, а затем дополняется другими операторами, например, операторами соединения.The estimation starts with the index seek and scan operators in the plan, and is then extended to include the other operators, like the join operator. Предполагаемое количество строк, которые будет обрабатывать оператор соединения, основано на оценке базовых операторов поиска и просмотра индекса.The estimated number of rows to be processed by a join operator is based on the estimation for the underlying index, seek, and scan operators. При выполнении доступа к оптимизированным для памяти таблицам с помощью интерпретируемого Transact-SQLTransact-SQL можно рассмотреть фактический план выполнения, чтобы увидеть разницу между расчетным и фактическим числом строк для операторов в плане.For interpreted Transact-SQLTransact-SQL access to memory-optimized tables, you can observe the actual execution plan to see the difference between the estimated and actual row counts for the operators in the plan.

Например, на рисунке 1For the example in figure 1,

  • Оператор просмотра кластеризованного индекса в таблице Customer: предполагаемое количество — 91; реальное — 91;The clustered index scan on Customer has estimated 91; actual 91.
  • Просмотр некластеризованного индекса в CustomerID: предполагаемое 830, реальное 830.The nonclustered index scan on CustomerID has estimated 830; actual 830.
  • Оператор соединения слиянием: предполагаемое 815; реальное 830.The Merge Join operator has estimated 815; actual 830.

Оценки для оператора просмотра индекса являются точными.The estimates for the index scans are accurate. SQL ServerSQL Server поддерживает количество строк для дисковых таблиц.maintains the row count for disk-based tables. Оценки для всей таблицы и просмотра индекса всегда являются точными.Estimates for full table and index scans are always accurate. Оценки для соединений также достаточно точные).The estimate for the join is fairly accurate, too.

Если эти оценки изменяются, расчеты стоимости для различных вариантов плана также изменяются.If these estimates change, the cost considerations for different plan alternatives change as well. Например, если один из участников соединения имеет предполагаемое количество строк 1 или всего несколько строк, использование соединений вложенными циклами является менее дорогостоящим.For example, if one of the sides of the join has an estimated row count of 1 or just a few rows, using a nested loops joins is less expensive. Обратите внимание на следующий запрос:Consider the following query:

SELECT o.OrderID, c.* FROM dbo.[Customer] c INNER JOIN dbo.[Order] o ON c.CustomerID = o.CustomerID  

После удаления всех строк, кроме одной строки в таблице Customer, создается следующий план запроса:After deleting all rows but one in the Customer table, the following query plan is generated:

Статистика столбцов и соединения.Column statistics and joins.

Относительно этого плана запроса:Regarding this query plan:

  • Оператор Hash Match был заменен на физический оператор соединения Nested Loops.The Hash Match has been replaced with a Nested Loops physical join operator.
  • Полный просмотр индекса в IX_CustomerID заменен поиском по индексу.The full index scan on IX_CustomerID has been replaced with an index seek. В результате для полного просмотра индекса было просмотрено 5 строк вместо 830.This resulted in scanning 5 rows, instead of the 830 rows required for the full index scan.

См. также:See Also

Таблицы, оптимизированные для памятиMemory-Optimized Tables