İki masada sersemletilebilir bir ilk harf maçı yapabilir miyim?


9
select value 
from persons p join persons2 p2 
    on left(p.lastname,1) = left(p2.lastname,1)

SQL Server. Bu SARGable'ı / çalıştırmayı daha hızlı hale getirmenin bir yolu var mı? Kişiler tablosunda sütun oluşturamıyorum, ancak kişiler2 üzerinde sütun oluşturabilirim.


3
Bu sorgunun sonucunun bir çeşit CROSS JOIN olacağını biliyor musunuz?
ypercubeᵀᴹ

1
Masalar ne kadar büyük? Her biri sadece 10 bin satır diyorsa, sonuç en az 4 milyon satır olacaktır. Böyle bir sorgunun kullanımı ne olacağını merak ediyorum.
ypercubeᵀᴹ

1
@ ypercubeᵀᴹ bulanık eşleme kullanarak bazı veri tekilleştirme işlemine ilk girdi olabilir mi?
Martin Smith

Kötü bir fikir gibi geliyor. Burada neyi başarmaya çalışıyorsunuz?
David דודו Markovitz

Bu sadece örnekti. Daha fazla tahmin var. Martin Smith doğru fikre sahip, tekilleştirme için.
lastchancexi

Yanıtlar:


9

Tablolarda LEFT(lastname, 1), her tablonun olarak tanımlanmış kalıcı bir hesaplanmış sütunu olan bir görünüm oluşturun ve sonra hesaplanan kalıcı sütun değerlerini karşılaştırın.

İşte bunun nasıl yapılacağını gösteren bir test yatağı:

CREATE TABLE dbo.Persons
(
    PersonID int NOT NULL
        CONSTRAINT PK_Persons
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , FirstName nvarchar(500) NOT NULL
    , LastName nvarchar(500) NOT NULL
);

CREATE TABLE dbo.Persons2
(
    PersonID int NOT NULL
        CONSTRAINT PK_Persons2
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , FirstName nvarchar(500) NOT NULL
    , LastName nvarchar(500) NOT NULL
);

GO
CREATE VIEW dbo.PersonsView
WITH SCHEMABINDING
AS
SELECT p1.PersonID
    , p1.FirstName
    , p1.LastName 
    , LastNameInitial = LEFT(p1.LastName, 1)
FROM dbo.Persons p1;
GO
CREATE VIEW dbo.PersonsView2
WITH SCHEMABINDING
AS
SELECT p2.PersonID
    , p2.FirstName
    , p2.LastName 
    , LastNameInitial = LEFT(p2.LastName, 1)
FROM dbo.Persons p2;
GO
CREATE UNIQUE CLUSTERED INDEX CX_PersonsView
ON dbo.PersonsView(PersonID);
CREATE NONCLUSTERED INDEX IX_PersonsView_LastNameInitial
ON dbo.PersonsView(LastNameInitial)
INCLUDE (FirstName, LastName);

CREATE UNIQUE CLUSTERED INDEX CX_PersonsView2
ON dbo.PersonsView2(PersonID);
CREATE NONCLUSTERED INDEX IX_PersonsView2_LastNameInitial
ON dbo.PersonsView2(LastNameInitial)
INCLUDE (FirstName, LastName);

CREATE STATISTICS ST_PersonsView_001
ON dbo.PersonsView(LastName);

CREATE STATISTICS ST_PersonsView2_001
ON dbo.PersonsView2(LastName);

Buraya bazı örnek veriler ekleyeceğiz:

INSERT INTO dbo.Persons(FirstName, LastName)
VALUES ('Max', 'Vernon')
    , ('Joe', 'Black');

INSERT INTO dbo.Persons2(FirstName, LastName)
VALUES ('Max', 'Vernon')
    , ('Joe', 'Black');

İşte SELECTsorgu:

SELECT *
FROM dbo.PersonsView pv1
    INNER JOIN dbo.PersonsView2 pv2 ON pv1.LastNameInitial = pv2.LastNameInitial;

Ve sonuçlar:

+ ---------- + ----------- + ---------- + --------------- - + ---------- + ----------- + ---------- + ------------- ---- +
| PersonID | Adı | Soyadı | Soyadı | PersonID | Adı | Soyadı | Soyadı |
+ ---------- + ----------- + ---------- + --------------- - + ---------- + ----------- + ---------- + ------------- ---- +
| 2 | Joe | Siyah | B | 2 | Joe | Siyah | B |
| 1 | Max | Vernon | V | 1 | Max | Vernon | V |
+ ---------- + ----------- + ---------- + --------------- - + ---------- + ----------- + ---------- + ------------- ---- +

Tablo başına sadece iki satır olan yürütme planı (kuşkusuz çok fazla satır değil!)

resim açıklamasını buraya girin


11

Eğer lastnamekolon tabloların en az birinde dizine o zaman da kullanabilirsinizLIKE

SELECT *
FROM   persons p
       INNER JOIN persons2 p2
               ON p2.lastname LIKE LEFT(p.lastname, 1) + '%' 

resim açıklamasını buraya girin

Bunun planı, benzerlerin solunda belirtilen tabloda bir arama yapabilir.

yani ON p.lastname LIKE LEFT(p2.lastname, 1) + '%'üzerinde endeksi yararlanmak mümkün olmaz persons2yukarıda kullanıldı ama olabilir üzerinde bir talep persons.

Bununla birlikte, hesaplanan bir sütunun her iki tarafta endekslenmesinin diğer cevabındaki öneri daha esnektir. İç içe bir döngüler planına gelince, her iki tablo da iç kısımda olabilir ve aynı zamanda bir sıralama gerektirmeden çok sayıda birleştirme birleştirmesine izin verir.


bu yaklaşım ne olacak ? Herhangi bir yararı varsa cevabınıza eklemek için çekinmeyin. Her iki tabloda da dizin kullanır mıydı - eğer öyleyse daha verimli olur mu?
ypercubeᵀᴹ

@ ypercubeᵀᴹ endeksleri kapsayan eğer Böyle bir plan verebilir i.stack.imgur.com/RSzcT.png . Yine de cevabımda plan üzerinde herhangi bir avantaj görmüyorum. Hala dış tablodaki tüm satırları okumaya ihtiyaç duyacağından, şimdi bir tarama yerine 26 arama yapıyor.
Martin Smith

2

3.423 satır ve 195 farklı değer içeren bir tablom var Name. Bu tabloyu P(kişi) olarak adlandıracağım ve P2(person2) oluşturmak için çoğaltacağım. Bir tamsayı kimliği sütununda benzersiz, kümelenmiş bir birincil anahtar vardır. 32 GB RAM ile Windows 10 Pro 6.3 üzerinde Microsoft SQL Server 2016 (KB3194716) Developer Edition'ı (64 bit) kullanıyorum.

Temel sorgu ile

select
    p.pid
from dbo.p
inner join dbo.p2 
    on LEFT(p.name, 1) = LEFT(p2.name, 1);

3200-3300ms'de döndürülen 1.5M satırları alıyorum (istatistikten io).

resim açıklamasını buraya girin

Böylece yeniden yazarak -

select
    p.pid
from dbo.p
where exists
(
    select 1
    from dbo.p2 
    where LEFT(p.name, 1) = LEFT(p2.name, 1)
);

Geçen süre 50-60ms'ye düşer ve plan:

resim açıklamasını buraya girin

Eşleşen algoritma nedeniyle daha az sayıda satır döndürülür (3.423). Temel plan olarak değiştirilerek aynı plan ve satır sayısı elde edilir select distinct.

Dizine alınmış, hesaplanmış sütun oluşturarak

alter table dbo.p2
add Name1 as Left(Name, 1);

create index ix1 on dbo.p2(Name1);

Geçen süre 45-50 ms'ye düşer.

resim açıklamasını buraya girin

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.