JSON verilerini dizine ekleme

Şunlar için geçerlidir: SQL Server 2016 (13.x) ve sonraki sürümler Azure SQL VeritabanıAzure SQL Yönetilen ÖrneğiSQL database in Microsoft Fabric

JSON belgeleri üzerinde standart B-ağacı indeksleri kullanarak sorgularınızı optimize edebilirsiniz. Veritabanı dizinleri, filtre ve sıralama işlemlerinin performansını artırır. İndeksler olmadan, Database Engine her sorgulama yaptığınızda tam bir tablo taraması yapmak zorundadır.

Tavsiye

Dizinler, varchar/nvarchar veya yerel json veri türüJSON veri türündeki JSON verilerinde aynı şekilde çalışır.

Note

JSON veri tipi ve JSON dizinleri, SQL Server 2025 (17.x), Azure SQL Veritabanı, Azure SQL Yönetilen Örneği'ta (SQL Server 2025 veya Always-up-to-date güncelleştirme ilkesi ile) ve Microsoft Fabric'deki SQL veritabanında genel kullanıma sunulmuştur.

JSON verilerini nasıl depoladığınıza bağlı olarak indekslemenin iki yolu vardır:

Dizin türü Description
JSON indeksi JSON'u bir json sütununda sakladığınızda, sütunda bir JSON indeksi oluşturun. Tek bir JSON indeksi, belge içindeki değerleri aramak için JSON_PATH_EXISTS, JSON_VALUE ve JSON_CONTAINS gibi işlevleri kullanan birçok sorguyu optimize edebilir. Bu yaklaşım json veri tipi için önerilir.
Hesaplanan sütun indeksi JSON'u varchar veya nvarchar metni olarak sakladığınızda ya da tek bir JSON özelliğini güçlü tipli bir sütun olarak indekslemek istediğinizde, JSON_VALUE ile hesaplanmış bir sütun oluşturun ve o sütunda standart bir indeks oluşturun.

JSON indeksiyle bir JSON sütununu indeksle

Şunlar için geçerlidir: Azure SQL Veritabanı, Azure SQL Yönetilen Örneği, SQL Server 2025 (17.x) ve Microsoft Fabric'teki SQL veritabanı

Bir JSON dizini doğrudan bir json sütununda oluşturabilirsiniz. JSON indeksi, JSON belgesi içindeki yolları indeksler; böylece tek bir indeks, her özellik için ayrı bir hesaplanmış sütun olmadan belge üzerinde birçok aramayı optimize edebilir.

Note

JSON indeksleri SQL Server 2022 (16.x) ve önceki sürümlerde desteklenmemektedir.

Aşağıdaki örnek, bir json sütunu ve o sütunda bir JSON indeksi bulunan bir tablo oluşturur:

CREATE TABLE Orders
(
    OrderID INT IDENTITY PRIMARY KEY,
    OrderDetails JSON NOT NULL
);

CREATE JSON INDEX IX_OrderDetails
    ON Orders (OrderDetails);

JSON indeksi uygulandığında, Database Engine, JSON_VALUE, JSON_PATH_EXISTS veya JSON_CONTAINS kullanan sorguları iyileştirmek için bunu kullanabilir. Örneğin, aşağıdaki sorgu, siparişleri müşteri adına göre filtrelemek için JSON indeksini kullanabilir:

SELECT OrderID
FROM Orders
WHERE JSON_VALUE(OrderDetails, '$.Customer.Name') = N'Aaron Campbell';

Tam sözdizimi, indeks seçenekleri ve desteklenen yüklemlerin tam listesi için bkz. CREATE JSON INDEX

Hesaplanan sütunları kullanarak JSON özelliklerini dizine ekleme

JSON'u varchar veya nvarchar metni olarak depolarken veya tek bir JSON özelliğini filtreleme veya sıralama için güçlü tipli bir sütun olarak ortaya çıkarmak istediğinizde hesaplanmış bir sütun indeksi kullanın. Genellikle, sorgu sonuçlarını JSON belgelerinin bir veya daha fazla özelliğine göre filtrelemek veya sıralamak istersiniz.

Example

Bu örnekte, AdventureWorks.SalesOrderHeader tablosunun satış siparişleri hakkında JSON biçiminde çeşitli bilgiler içeren bir Info sütunu olduğunu varsayalım. Örneğin müşteri, satış elemanı, sevkiyat ve faturalama adresleri vb. hakkında yapılandırılmamış veriler içerir. Müşterinin satış siparişlerini filtrelemek için Info sütunundaki değerleri kullanabilirsiniz.

Varsayılan olarak, kullanılan sütun Info mevcut değildir, veritabanında aşağıdaki kodla oluşturulabilir AdventureWorks . Aşağıdaki örnekler örnek veritabanları serisi için AdventureWorksLT geçerli değildir.

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 concat(p.FirstName, N' ', p.LastName) AS [Customer.Name],
            p.BusinessEntityID AS [Customer.ID],
            p.[PersonType] AS [Customer.Type],
            soh.SalesOrderID AS [Order.ID],
            soh.SalesOrderNumber AS [Order.Number],
            soh.OrderDate AS [Order.CreationDate],
            soh.TotalDue AS [Order.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;

en iyi duruma getirmek için sorgu

Aşağıda, dizin kullanarak iyileştirmek istediğiniz sorgu türüne bir örnek verilmiştır.

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

Örnek dizin

JSON belgesindeki bir özellik üzerinde filtrelerinizi veya ORDER BY yan tümcelerinizi hızlandırmak istiyorsanız, diğer sütunlarda zaten kullandığınız dizinleri kullanabilirsiniz. Ancak, JSON belgelerindeki özelliklere doğrudan referans veremezsiniz.

  1. İlk olarak, filtreleme için kullanmak istediğiniz değerleri döndüren bir "sanal sütun" oluşturun.
  2. Ardından, bu sanal sütunda bir dizin oluşturun.

Aşağıdaki örnek, dizin oluşturmak için kullanılabilecek hesaplanan bir sütun oluşturur. Ardından yeni hesaplanan sütunda bir dizin oluşturur. Bu örnek, JSON verilerindeki $.Customer.Name yolunda depolanan müşteri adını kullanıma sunan bir sütun oluşturur.

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

CREATE INDEX idx_soh_json_CustomerName
    ON Sales.SalesOrderHeader(vCustomerName);

Bu ifade aşağıdaki uyarıyı verir:

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.

JSON_VALUE işlevi 8000 bayta kadar metin değeri döndürebilir (örneğin, nvarchar(4000) türü olarak). Ancak, 1700 bayttan uzun değerler dizine alınamaz. 1700 bayttan uzun olan dizine alınmış hesaplanan sütuna değeri girmeye çalışırsanız, veri işleme dili (DML) işlemi başarısız olur.

Daha iyi performans için, hesaplanan bir sütun kullanarak ortaya çıkardığınız değeri en küçük geçerli veri türüne dönüştürmeyi deneyin. Dize türleri yerine int ve datetime2 türlerini kullanın.

Hesaplanan sütun hakkında daha fazla bilgi

Hesaplanan sütun kalıcı değildir. Hesaplanan sütun yalnızca dizinin yeniden oluşturulması gerektiğinde hesaplanır. Tabloda fazladan yer kaplamaz.

Hesaplanan sütunu sorgularınızda kullanmayı planladığınız ifadeyle oluşturmanız önemlidir; bu örnekte ifade JSON_VALUE(Info, '$.Customer.Name').

Sorgularınızı yeniden yazmanız gerekmez. Yukarıdaki örnek sorguda gösterildiği gibi JSON_VALUE işleviyle ifadeler kullanırsanız, SQL Server aynı ifadeye sahip eşdeğer bir hesaplanan sütun olduğunu görür ve mümkünse bir dizin uygular.

Bu örnek için yürütme planı

Bu örnekteki sorgunun yürütme planı aşağıda verilmiştır.

Bu örnek için yürütme planını gösteren ekran görüntüsü.

TAM tablo taraması yerine SQL Server, kümelenmemiş dizinde bir dizin araması kullanır ve belirtilen koşulları karşılayan satırları bulur. Ardından sorguda başvuruda bulunan diğer sütunları getirmek için SalesOrderHeader tablosundaki bir anahtar aramasını kullanır; bu örnekte SalesOrderNumber ve OrderDate.

Dahil edilen sütunlarla dizini daha da iyileştirin

Dizine gerekli sütunları eklerseniz, tabloda bu ek aramayı önleyebilirsiniz. Yukarıdaki CREATE INDEX örneği genişleten aşağıdaki örnekte gösterildiği gibi, bu sütunları standart eklenen sütunlar olarak ekleyebilirsiniz.

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

Bu durumda, SQL Server'ın gerek duyduğu her şey kümelenmemiş JSON dizinine dahil edildiğinden SalesOrderHeader tablodan daha fazla veri okuması gerekmez. Bu dizin türü, sorgulardaki JSON ve sütun verilerini birleştirmek ve iş yükünüz için en uygun dizinleri oluşturmak için iyi bir yoldur.

Hesaplanan sütun indeksleri karşılaştırma düzenini dikkate alır

JSON verileri üzerinde hesaplanan sütun dizinlerinin önemli bir özelliği, karşılaştırma düzenine duyarlı olmalarıdır. Hesaplanan sütunu oluştururken kullandığınız JSON_VALUE işlevinin sonucu, harmanlamasını giriş ifadesinden devralan bir metin değeridir. Bu nedenle, dizindeki değerler kaynak sütunlarda tanımlanan harmanlama kuralları kullanılarak sıralanır.

Dizinlerin harmanlama duyarlı olduğunu göstermek için aşağıdaki örnek, birincil anahtar ve JSON içeriğine sahip basit bir koleksiyon tablosu oluşturur.

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)
);

Yukarıdaki komut, json sütunu için Sırp Kiril harmanlamasını belirtir. Aşağıdaki örnek, tabloyu doldurur ve name özelliğinde bir dizin oluşturur.

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);

Yukarıdaki komutlar, vNamehesaplanan sütununda JSON $.name özelliğindeki değeri temsil eden standart bir dizin oluşturur. Sırp Kiril kod sayfasında, harflerin sırası А, Б, В, Г, Д, Ђ, Еvb. dizindeki öğelerin sırası Sırp Kiril kurallarıyla uyumludur çünkü JSON_VALUE işlevinin sonucu harmanlamasını kaynak sütundan devralır. Aşağıdaki örnek bu koleksiyonu sorgular ve sonuçları ada göre sıralar.

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

Gerçek yürütme planına bakarsanız, kümelenmemiş dizinden sıralanmış değerler kullandığını görürsünüz.

Kümelenmemiş dizinden sıralanmış değerler kullanan bir yürütme planını gösteren ekran görüntüsü.

Sorgunun bir ORDER BY yan tümcesi olsa da yürütme planı Sort işleci kullanmaz. JSON dizini Sırp Kiril kurallarına göre zaten sıralanmış durumda. Bu nedenle SQL Server, sonuçların zaten sıralandığı kümelenmemiş dizini kullanabilir.

Ancak, ORDER BY ifadesinin harmanlamasını değiştirirseniz (örneğin, COLLATE French_100_CI_AS_SC işlevinden sonra JSON_VALUE eklerseniz) farklı bir sorgu yürütme planı elde edersiniz.

Farklı bir yürütme planını gösteren ekran görüntüsü.

Dizindeki değerlerin sırası Fransızca harmanlama kurallarıyla uyumlu olmadığından SQL Server sonuçları sıralamak için dizini kullanamaz. Bu nedenle, Fransızca harmanlama kurallarını kullanarak sonuçları sıralayan bir Sıralama işleci ekler.

Microsoft videoları

Yerleşik JSON desteğine görsel bir giriş için aşağıdaki videoya bakın:

  • NoSQL ile ilişkisel dünyalar arasında bir köprü olarak JSON