SARG kardinalite tahmini, neden tam tarama değil?


11

Neden tam tarama yok (SQL 2008 R2 ve 2012'de)?

Test verisi:

DROP TABLE dbo.TestTable
GO  
CREATE TABLE dbo.TestTable
(
   TestTableID INT IDENTITY PRIMARY KEY,
   VeryRandomText VarChar(50),
   VeryRandomText2 VarChar(50)
)
Go
Set NoCount ON
Declare @i int
Set @i = 0
While @i < 10000
Begin
   Insert Into dbo.TestTable(VeryRandomText, VeryRandomText2)
      Values(Cast(Rand()*10000000 as VarChar(50)), Cast(Rand()*10000000 as VarChar(50)));
   Set @i = @i + 1;
End
Go
CREATE Index IX_VeryRandomText On dbo.TestTable
(
    VeryRandomText
)
Go

Sorgu çalıştırıldığında:

Select * From dbo.TestTable Where VeryRandomText = N'111' -- bad

Uyarı alın (beklendiği gibi, nchar verilerini varchar sütunuyla karşılaştırdığınızda):

<PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(nvarchar(50),[DemoDatabase].[dbo].[TestTable].[VeryRandomText],0)" />

Ama sonra yürütme planını görüyorum ve görebildiğim gibi tam taramayı kullanmıyor, dizin arama yerine görebiliyorum.

resim açıklamasını buraya girin

Tabii ki, bu iyi bir şey, çünkü bu özel durumda yürütme tam taramadan çok daha hızlıdır.

Ama nasıl SQL Server bu planı yapmak için karar geldi anlayamıyorum.

Ayrıca, sunucu harmanlama sunucu düzeyinde Windows harmanlama ve SQL Server harmanlama veritabanı düzeyinde olacaksa, aynı sorguda tam taramaya neden olur.

Yanıtlar:


8

SQL Server, farklı veri türlerinin değerlerini karşılaştırırken Veri Türü Önceliği kurallarına uyun . Nvarchar, varchar'dan daha yüksek önceliğe sahip olduğundan, SQL Server değerleri karşılaştırmadan önce sütun verilerini nvarchar'a dönüştürmek zorundadır. Bu, sütuna bir işlev uygulamak anlamına gelir ve bu da sorgunun anlaşılmaz olmasını sağlar.

Ancak SQL Server, hatalarınızdan korumak için en iyisini yapar, bu nedenle Paul White tarafından dinamik aramalar ve Gizli Örtük Dönüşümler blogunda açıklanan bir tekniği kullanarak bir dizi değer aramak ve daha sonra son karşılaştırmayı yapmak Sütun değerinin yanlış pozitifleri filtrelemek için artık bir yüklemle nvarchar'a dönüştürülmesi.

Daha önce belirttiğiniz gibi, sütunun harmanlaması bir SQL harmanlaması olduğunda bu çalışmaz. Bunun nedeni, SQL harmanlamalarını Windows harmanlamalarıyla karşılaştırma makalesinde bulunabilir.

Temel olarak, bir Windows harmanlaması varchar ve nvarchar için aynı algoritmayı kullanır; burada SQL harmanlaması varchar verileri için farklı bir algoritma kullanır ve nvarchar verileri için Windows harmanlaması ile aynı algoritmayı kullanır.

Bu nedenle, bir Windows harmanlaması altında varchar'tan nvarchar'a gitmek aynı algoritmayı kullanır ve SQL Server, varchar SQL harmanlama sütun dizininden satır almak için bir nvarchar değişmezinden bir dizi değer üretebilir. Ancak, varchar sütunun harmanlama kullanılan farklı algoritma nedeniyle mümkün olmayan bir SQL harmanlama olduğunda.


Güncelleme:

Windows ve sql harmanlama kullanarak varchar sütunları için farklı sıralama düzenlerinin bir gösterimi.

SQL Keman

MS SQL Server 2014 Şema Kurulumu :

create table T(C varchar(10));

insert into T values('a-b'),('aa'),('ac');

Sorgu 1 :

select C
from T
order by C collate SQL_Latin1_General_CP1_CI_AS;

Sonuçlar :

|   C |
|-----|
| a-b |
|  aa |
|  ac |

Sorgu 2 :

select C
from T
order by C collate Latin1_General_100_CI_AS;

Sonuçlar :

|   C |
|-----|
|  aa |
| a-b |
|  ac |

0

Kümelenmemiş bir Dizinin yaprak düğümlerinin, Veri Satırını bulmak için Kümeleme Anahtarı veya RID içeren Dizin sayfalarından oluştuğunu hatırlamanız gerekir.

Reklamlara burada fıkra Eğer devlet VeryRandomText = N'111'Olmayan VeryRandomText rowid bulmak için dizini tarama verileri bulmak için en ucuz yolu, (açıkça bir kümelenmiş oluşturmak yapmasını istemedikçe olmayan kümelenmiş dizin oluşturur dizin oluşturmak) üzerinde endeksi orada kümelenmiş olduğundan ve ardından satırın verilerini getirin.

Kümelenmiş bir dizin oluşturursanız

CREATE clustered Index IX_VeryRandomText On dbo.TestTable (VeryRandomText)

veya VeryRandomText'te birincil anahtar bu dizinin taranmasını sağlar.

Çevrimiçi veya burada kitaplara bakın: http://www.sqlforge.com/w/Clustered_index,_nonclustered_index,_or_heap


Evet, ne yazdığının farkındayım. Gördüğünüz gibi, TestTableID üzerinde zaten kümelenmiş bir dizin var. Ama şey şu ki - SQL sunucusu sütun veri dağıtım istatistiklerini göremiyorsa (bu durumda olduğu gibi, tüm satır değeri veri türü dönüşümünü gerektiren veri türü uyuşmazlığı nedeniyle), bu durumda dizin aramasını değil, Kümelenmiş dizin taramasını seçmelidir .
Jānis

Kümelenmemiş dizin aramak / taramak her zaman en ucuz değildir - değerler yeterince farklı veya örtücü olmayan dizin olduğunda, bunun yerine kümelenmiş dizin taraması yapmak daha ucuz olabilir.
Jānis

@ Jānis betiğinizin dizinini
hesaba katmazsa

"Bir PRIMARY KEY kısıtlaması oluşturduğunuzda, tabloda kümelenmiş bir dizin zaten yoksa ve benzersiz bir kümelenmemiş dizin belirtmezseniz, sütun veya sütunlarda benzersiz bir kümelenmiş dizin otomatik olarak oluşturulur." msdn.microsoft.com/tr-tr/library/ms186342.aspx
Jānis
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.