SQL Server neden bir dizini yoksaysın?


16

CustPassMasterİçinde 16 sütun olan bir tablo var , bunlardan biri CustNum varchar(8)ve bir dizin oluşturdum IX_dbo_CustPassMaster_CustNum. İfademi çalıştırdığımda SELECT:

SELECT * FROM dbo.CustPassMaster WHERE CustNum = '12345678'

Dizini tamamen yok sayar. CustDataMasterBiri daha fazla sütun (55) ile başka bir tablo var gibi bu beni şaşırttı CustNum varchar(8). IX_dbo_CustDataMaster_CustNumBu tablodaki bu sütunda ( ) bir dizin oluşturdum ve hemen hemen aynı sorguyu kullanıyorum:

SELECT * FROM dbo.CustDataMaster WHERE CustNum = '12345678'

Ve oluşturduğum endeksi kullanıyor.

Bunun arkasında belirli bir gerekçe var mı? Neden dizinini kullanıyor CustDataMaster, ama dizinini kullanmıyor CustPassMaster? Düşük sütun sayısından mı kaynaklanıyor?

İlk sorgu 66 satır döndürür. İkincisi için 1 satır döndürülür.

Ayrıca, ek not: CustPassMaster4991 kaydı ve CustDataMaster5376 kaydı vardır. Dizini görmezden gelmenin ardındaki sebep bu olabilir mi? CustPassMasterayrıca aynı CustNumdeğerlere sahip yinelenen kayıtlara da sahiptir . Bu başka bir faktör mü?

Bu iddiayı her iki sorgunun gerçek yürütme planı sonuçlarına dayandırıyorum.

İşte DDL CustPassMaster(kullanılmayan dizine sahip olan):

CREATE TABLE dbo.CustPassMaster(
    [CustNum] [varchar](8) NOT NULL,
    [Username] [char](15) NOT NULL,
    [Password] [char](15) NOT NULL,
    /* more columns here */
    [VBTerminator] [varchar](1) NOT NULL
) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IX_dbo_CustPassMaster_CustNum] ON dbo.CustPassMaster
(
    [CustNum] ASC
) WITH (PAD_INDEX = OFF
    , STATISTICS_NORECOMPUTE = OFF
    , SORT_IN_TEMPDB = OFF
    , DROP_EXISTING = OFF
    , ONLINE = OFF
    , ALLOW_ROW_LOCKS = ON
    , ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

Ve DDL için CustDataMaster(alakasız alanları atladım):

CREATE TABLE dbo.CustDataMaster(
    [CustNum] [varchar](8) NOT NULL,
    /* more columns here */
    [VBTerminator] [varchar](1) NOT NULL
) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IX_dbo_CustDataMaster_CustNum] ON dbo.CustDataMaster
(
    [CustNum] ASC
)WITH (PAD_INDEX = OFF
    , STATISTICS_NORECOMPUTE = OFF
    , SORT_IN_TEMPDB = OFF
    , DROP_EXISTING = OFF
    , ONLINE = OFF
    , ALLOW_ROW_LOCKS = ON
    , ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

Bu tabloların hiçbirinde kümelenmiş bir dizin yok, yalnızca bir kümelenmemiş dizin.

Veri türlerinin depolanan veri türüyle tamamen eşleşmediğini dikkate almayın. Bu alanlar bir IBM AS / 400 DB2 veritabanının yedeğidir ve bunlar onun için uyumlu veri türleridir. (Bu yedekleme veritabanını tam olarak aynı sorgularla sorgulayabilmeli ve aynı sonuçları elde edebilmeliyim.)

Bu veriler yalnızcaSELECT ifadeler için kullanılır . Yedekleme uygulaması AS / 400'den veri kopyaladığı zamanlar dışında herhangi bir INSERT/ UPDATE/ DELETEifadesi yapmıyorum .


Kümelenmemiş'ten Kümelenmiş'e devrilme noktası hakkında bu makaleyi okumaya değer olabilir. sqlskills.com/blogs/kimberly/the-tipping-point-query-answers
Mark Sinkinson

3
Yani fark bu. İlk sorgu dizininizi kullandıysa, 65 arama gerçekleştirmesi gerekir. Bu pahalı. İkinci sorgu sadece bir tane yapmak zorundadır.
Aaron Bertrand

Yanıtlar:


18

Genellikle dizinleri doğrudan temel tabloyu kullanmaktan daha uygun buluyorsa dizinler SQL Server tarafından kullanılır.

Maliyete dayalı optimize edici, söz konusu dizini kullanmanın daha pahalı olacağını düşünüyor gibi görünüyor. Bunu yapmanın eğer yerine endeksi kullanmak görebilirsiniz SELECT *basitçe, sizi SELECT T1Col1.

Ne zaman SELECT *SQL Server anlatıyorsun tablodaki tüm sütunları dönmek için. Bu sütunları dönmek için SQL Server gerekir eşleşen satırlar için sayfalarını okumak WHEREmasanın kendisi (kümelenmiş dizin veya yığın) yapılan açıklamada kriterlerini. SQL Server büyük olasılıkla tablodan sütunların geri kalanı almak için gereken okuma miktarını düşünüyor da doğrudan tabloyu taramak anlamına gelir. Gerçek sorguyu ve sorgu tarafından kullanılan gerçek yürütme planını görmek yararlı olacaktır.


3
Öyleyse, seçtiğim sütunları sınırlamak ve bunları INCLUDEdizinin yan tümcesine dahil etmek benim için daha açık ve en uygun bir çözüm olabilir mi?
Der Kommissar

1
Bu büyük bir fark yaratabilir. Sorgu tarafından döndürülen tüm sütunları INCLUDEyan tümceye eklemek, SQL Server'ın dizini kullanmasını sağlar. Bunu söyledikten sonra, neyi optimize etmeye çalışıyorsunuz? Bana göre tablonuzun ortalama satır boyutu 100 bayt ise, o zaman 5000 satır sadece yaklaşık 500kb'dir ve herhangi bir zaman harcamaya değmeyebilir.
Max Vernon

1
Ortalama satır boyutu için 0.30KB Table1ve için 0.53KB'dir Table2. Tüm bu veriler bir AS / 400'den (IBM System i) alınır ve hiçbir şey üzerinde PK yoktur. İnsanların uygulamanın zaman zaman oldukça yavaş olduğunu söyledikten sonra bugün tüm dizinleri el ile oluşturdum.
Der Kommissar

10

Dizin kullanmak için, çünkü select *SQL Server, ilk önce nerede yan tümcesinde sahip olduğunuz değerle eşleşen dizindeki satırların her birini okumalıdır. Buna dayanarak, her satır için kümelenmiş dizin değerlerini alır ve ardından her birini kümelenmiş dizinden ayrı olarak aramak zorundadır (= anahtar arama). Değerlerin benzersiz olmadığını söylediğiniz için SQL Server, bu anahtar aramasını kaç kez yapmak zorunda olduğunu tahmin etmek için istatistikleri kullanır.

Büyük olasılıkla kümelenmemiş dizin + anahtar aramalarını taramak için maliyet tahmini, kümelenmiş dizin taraması için maliyet tahminini aşıyor ve bu nedenle dizin yok sayılıyor.

set statistics io onDizini kullanırken G / Ç maliyetinin gerçekten daha düşük olup olmadığını görmek için bir dizin ipucu kullanmayı ve sonra kullanmayı deneyebilirsiniz . Fark büyükse, güncelliğini yitirmişse istatistiklere bakabilirsiniz.

Ayrıca, SQL'iniz gerçek değerleri değil de değişkenleri kullanıyorsa, bu durum parametre koklamasından da kaynaklanabilir (= planı oluşturmak için kullanılan önceki değer tabloda çok sayıda satır vardı).


1

Nedeni bu olabilir. Optimize ediciler maliyete dayalıdır ve her yürütme yolunun sahip olduğu 'maliyete' göre hangi yolu seçeceğine karar verir. En büyük maliyet, verileri diskten belleğe almaktır. Optimize edici, hem dizini hem de verileri okumak için daha fazla zaman gerektiğini hesaplarsa, dizini atlamaya karar verebilir. Sıralar büyüdükçe daha fazla disk bloğu alırlar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.