Sdílet prostřednictvím


Indexování dat JSON

Platí na: SQL Server 2016 (13.x) a novější verze Azure SQL DatabaseAzure SQL Managed InstanceSQL database in Microsoft Fabric

Dotazy na dokumenty JSON můžete optimalizovat pomocí standardních indexů.

Note

V SQL Serveru 2025 (17.x) můžete použít funkci CREATE JSON INDEX (Transact-SQL).

Indexy fungují stejně jako u dat JSON v varchar/nvarchar nebo nativní datového typu json.

Indexy databází zlepšují výkon operací filtrování a řazení. Bez indexů musí SQL Server při každém dotazování na data provádět úplnou kontrolu tabulek.

Note

Datový typ JSON:

  • je obecně dostupná pro Službu Azure SQL Database a Azure SQL Managed Instance pomocí zásad aktualizaceSQL Serveru 2025 nebo Always-up-to-date.
  • je ve verzi Preview pro SQL Server 2025 (17.x) a databázi SQL v prostředcích infrastruktury.

Indexování vlastností JSON pomocí počítaných sloupců

Při ukládání dat JSON na SQL Serveru obvykle chcete filtrovat nebo řadit výsledky dotazu podle jedné nebo více vlastností dokumentů JSON.

Example

V tomto příkladu předpokládejme, že tabulka AdventureWorks.SalesOrderHeader obsahuje sloupec Info, který obsahuje různé informace ve formátu JSON o prodejních objednávkách. Obsahuje například nestrukturovaná data o zákazních, prodejních osobách, dodacích a fakturačních adresách atd. Hodnoty ze sloupce Info můžete použít k filtrování prodejních objednávek pro zákazníka.

Ve výchozím nastavení použitý sloupec Info neexistuje, dá se vytvořit v AdventureWorks databázi s následujícím kódem. Následující příklady se nevztahují na AdventureWorksLT řadu ukázkových databází.

IF NOT EXISTS (SELECT *
               FROM sys.columns
               WHERE object_id = OBJECT_ID('[Sales].[SalesOrderHeader]')
                     AND name = 'Info')
    ALTER TABLE [Sales].[SalesOrderHeader]
        ADD [Info] NVARCHAR (MAX) NULL;
GO

UPDATE h
SET [Info] =
(
    SELECT [Customer.Name] = concat(p.FirstName, N' ', p.LastName), 
           [Customer.ID] = p.BusinessEntityID, 
           [Customer.Type] = p.[PersonType], 
           [Order.ID] = soh.SalesOrderID, 
           [Order.Number] = soh.SalesOrderNumber, 
           [Order.CreationData] = soh.OrderDate, 
           [Order.TotalDue] = soh.TotalDue
    FROM [Sales].SalesOrderHeader AS soh
        INNER JOIN [Sales].[Customer] AS c
            ON c.CustomerID = soh.CustomerID
        INNER JOIN [Person].[Person] AS p
            ON p.BusinessEntityID = c.CustomerID
    WHERE soh.SalesOrderID = h.SalesOrderID
    FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
)
FROM [Sales].SalesOrderHeader AS h;

Dotaz pro optimalizaci

Tady je příklad typu dotazu, který chcete optimalizovat pomocí indexu.

SELECT SalesOrderNumber,
       OrderDate,
       JSON_VALUE(Info, '$.Customer.Name') AS CustomerName
FROM Sales.SalesOrderHeader
WHERE JSON_VALUE(Info, '$.Customer.Name') = N'Aaron Campbell';

Příklad indexu

Pokud chcete zrychlit své filtry nebo klauzule ORDER BY pro vlastnost v dokumentu JSON, můžete použít stejné indexy, které už používáte v jiných sloupcích. V dokumentech JSON však nemůžete přímo odkazovat na vlastnosti.

  1. Nejprve vytvořte "virtuální sloupec", který vrátí hodnoty, které chcete použít k filtrování.
  2. Pak vytvořte index pro tento virtuální sloupec.

Následující příklad vytvoří počítaný sloupec, který lze použít k indexování. Pak vytvoří index pro nový vypočítaný sloupec. Tento příklad vytvoří sloupec, který zveřejňuje jméno zákazníka, které je uloženo v cestě $.Customer.Name v datech JSON.

ALTER TABLE Sales.SalesOrderHeader
    ADD vCustomerName AS JSON_VALUE(Info, '$.Customer.Name');

CREATE INDEX idx_soh_json_CustomerName
    ON Sales.SalesOrderHeader(vCustomerName);

Toto prohlášení vrátí následující upozornění:

Warning! The maximum key length for a nonclustered index is 1700 bytes.
The index 'vCustomerName' has maximum length of 8000 bytes.
For some combination of large values, the insert/update operation will fail.

Funkce JSON_VALUE může vracet textové hodnoty až 8 000 bajtů (například jako nvarchar(4000) typ). Hodnoty delší než 1700 bajtů se ale nedají indexovat. Pokud se pokusíte zadat hodnotu do indexovaného počítaného sloupce, který je delší než 1700 bajtů, operace jazyka pro manipulaci s daty (DML) selže.

Pokud chcete dosáhnout lepšího výkonu, zkuste přetypovat hodnotu, kterou zpřístupňujete, pomocí počítaného sloupce na nejmenší použitelný datový typ. Používejte typy int a datetime2 místo typů řetězců.

Další informace o počítaném sloupci

Vypočítaný sloupec se neuloží. Počítaný sloupec se vypočítá pouze v případech, kdy je potřeba znovu vytvořit index. Nezabírá v tabulce další prostor.

Je důležité vytvořit počítaný sloupec se stejným výrazem, který plánujete použít v dotazech – v tomto příkladu je výraz JSON_VALUE(Info, '$.Customer.Name').

Dotazy nemusíte přepisovat. Pokud používáte výrazy s funkcí JSON_VALUE, jak je znázorněno v předchozím ukázkovém dotazu, SQL Server zjistí, že existuje ekvivalentní počítaný sloupec se stejným výrazem a pokud je to možné, použije index.

Plán provádění pro tento příklad

Tady je plán provádění dotazu v tomto příkladu.

snímek obrazovky znázorňující plán provádění pro tento příklad

Místo úplné kontroly tabulek sql Server použije vyhledávání indexu do neclusterovaného indexu a najde řádky, které splňují zadané podmínky. Potom pomocí klíčového vyhledávání v tabulce SalesOrderHeader načte další sloupce, na které odkazuje dotaz – v tomto příkladu SalesOrderNumber a OrderDate.

Optimalizace indexu dále pomocí zahrnutých sloupců

Pokud do indexu přidáte požadované sloupce, můžete se vyhnout tomuto dodatečnému vyhledávání v tabulce. Tyto sloupce můžete přidat jako standardní zahrnuté sloupce, jak je znázorněno v následujícím příkladu, který rozšiřuje předchozí CREATE INDEX příklad.

CREATE INDEX idx_soh_json_CustomerName
    ON Sales.SalesOrderHeader(vCustomerName)
    INCLUDE(SalesOrderNumber, OrderDate);

V tomto případě SQL Server nemusí číst další data z SalesOrderHeader tabulky, protože vše, co potřebuje, je součástí neclusterovaného indexu JSON. Tento typ indexu je vhodný způsob, jak kombinovat data JSON a sloupce v dotazech a vytvářet optimální indexy pro vaši úlohu.

Indexy JSON jsou indexy pracující s kolací.

Důležitou funkcí indexů nad daty JSON je, že indexy jsou ohleduplné ke kolaci. Výsledek funkce JSON_VALUE, kterou použijete při tvorbě počítaného sloupce, je textová hodnota, která přebírá řazení z původního výrazu. Hodnoty v indexu jsou proto seřazené pomocí pravidel kolace definovaných ve zdrojových sloupcích.

Abychom ukázali, že indexy zohledňují řazení, následující příklad vytvoří jednoduchou tabulku kolekcí s primárním klíčem a obsahem JSON.

CREATE TABLE JsonCollection
(
    id INT IDENTITY CONSTRAINT PK_JSON_ID PRIMARY KEY,
    [json] NVARCHAR (MAX) COLLATE SERBIAN_CYRILLIC_100_CI_AI
        CONSTRAINT [Content should be formatted as JSON] CHECK (ISJSON(json) > 0)
);

Předchozí příkaz určuje srbské cyrilické řazení pro sloupec json. Následující příklad naplní tabulku a vytvoří index na vlastnosti 'název'.

INSERT INTO JsonCollection
VALUES
    (N'{"name":"Иво","surname":"Андрић"}'),
    (N'{"name":"Андрија","surname":"Герић"}'),
    (N'{"name":"Владе","surname":"Дивац"}'),
    (N'{"name":"Новак","surname":"Ђоковић"}'),
    (N'{"name":"Предраг","surname":"Стојаковић"}'),
    (N'{"name":"Михајло","surname":"Пупин"}'),
    (N'{"name":"Борислав","surname":"Станковић"}'),
    (N'{"name":"Владимир","surname":"Грбић"}'),
    (N'{"name":"Жарко","surname":"Паспаљ"}'),
    (N'{"name":"Дејан","surname":"Бодирога"}'),
    (N'{"name":"Ђорђе","surname":"Вајферт"}'),
    (N'{"name":"Горан","surname":"Бреговић"}'),
    (N'{"name":"Милутин","surname":"Миланковић"}'),
    (N'{"name":"Никола","surname":"Тесла"}');
GO

ALTER TABLE JsonCollection
    ADD vName AS JSON_VALUE(json, '$.name');

CREATE INDEX idx_name
    ON JsonCollection(vName);

Předchozí příkazy vytvoří standardní index vypočítaného sloupce vName, který představuje hodnotu z vlastnosti $.name JSON. Na znakové stránce srbské cyrilice je pořadí písmen А, Б, В, Г, Д, Ђ, Е, atd. Pořadí položek v indexu je v souladu s pravidly Srbské Cyriliky, protože výsledek funkce JSON_VALUE dědí kolaci ze zdrojového sloupce. Následující příklad dotazuje tuto kolekci a seřadí výsledky podle názvu.

SELECT JSON_VALUE(json, '$.name'),
       *
FROM JsonCollection
ORDER BY JSON_VALUE(json, '$.name');

Pokud se podíváte na skutečný plán provádění, uvidíte, že používá seřazené hodnoty z neclusterovaného indexu.

Snímek obrazovky znázorňující plán provádění, který používá seřazené hodnoty z neclusterovaného indexu

I když dotaz obsahuje klauzuli ORDER BY, plán provádění nepoužívá operátor Sort. Index JSON je již seřazený podle pravidel srbštiny cyrilice. Sql Server proto může použít neclusterovaný index, ve kterém jsou výsledky již seřazené.

Pokud ale změníte kolaci výrazu ORDER BY – například když za funkci COLLATE French_100_CI_AS_SC přidáte JSON_VALUE – získáte jiný plán provádění dotazů.

snímek obrazovky s jiným plánem provádění

Vzhledem k tomu, že pořadí hodnot v indexu nevyhovuje francouzským pravidlům kolace, SQL Server nemůže index použít k seřazení výsledků. Proto přidá operátor třídění, který seřadí výsledky podle pravidel francouzské kolace.

Microsoft videa

Vizuální úvod k integrované podpoře JSON najdete v následujícím videu: